Libinfo-173.tar.gz
[apple/libinfo.git] / netinfo.subproj / ni_glue.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Glues the library routines to the stub routines
27 * Copyright (C) 1989 by NeXT, Inc.
28 */
29 #include <libc.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <netinfo/ni.h>
33 #include <rpc/pmap_clnt.h>
34 #include <rpc/pmap_prot.h>
35 #include <rpc/xdr.h>
36 #include <net/if.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include "clib.h"
40 #include "sys_interfaces.h"
41
42 #define LOCAL_PORT 1033
43
44 #define NI_TIMEOUT_SHORT 5 /* 5 second timeout for transactions */
45 #define NI_TIMEOUT_LONG 60 /* 60 second timeout for writes */
46 #define NI_TRIES 5 /* number of retries per timeout (udp only) */
47 #define NI_SLEEPTIME 4 /* 4 second sleeptime, in case of errors */
48 #define NI_MAXSLEEPTIME 64 /* 64 second max sleep time */
49 #define NI_MAXCONNTRIES 2 /* Try to form a connection twice before sleeping */
50
51 /* Hack for determining if an IP address is a broadcast address. -GRS */
52 /* Note that addr is network byte order (big endian) - BKM */
53
54 #define IS_BROADCASTADDR(addr) (((unsigned char *) &addr)[0] == 0xFF)
55
56 #ifndef INADDR_LOOPBACK
57 #define INADDR_LOOPBACK (u_long)0x7f000001
58 #endif
59 #define debug(msg) syslog(LOG_ERR, msg)
60
61 #define clnt_debug(ni, msg) /* do nothing */
62
63 typedef struct ni_private {
64 int naddrs; /* number of addresses */
65 struct in_addr *addrs; /* addresses of servers - network byte order */
66 int whichwrite; /* which one of the above is the master */
67 ni_name *tags; /* tags of servers */
68 int pid; /* pid, to detect forks */
69 int tsock; /* tcp socket */
70 int tport; /* tcp local port name - host byte order */
71 CLIENT *tc; /* tcp client */
72 long tv_sec; /* timeout for this call */
73 long rtv_sec; /* read timeout - 0 if default */
74 long wtv_sec; /* write timeout - 0 if default */
75 int abort; /* abort on timeout? */
76 int needwrite; /* need to lock writes? */
77 int uid; /* user id */
78 ni_name passwd; /* password */
79 } ni_private;
80
81 #define NIP(ni) ((ni_private *)(ni))
82
83 static const ni_name NAME_NAME = "name";
84 static const ni_name NAME_SERVES = "serves";
85 static const ni_name NAME_MACHINES = "machines";
86 static const ni_name NAME_IP_ADDRESS = "ip_address";
87 static const ni_name NAME_MASTER = "master";
88 static const ni_name NAME_USERS = "users";
89 static const ni_name NAME_UID = "uid";
90
91 static const ni_name NAME_DOMAIN_SERVERS = "domain_servers";
92
93 typedef struct getreg_stuff {
94 nibind_getregister_res res;
95 ni_private *ni;
96 } getreg_stuff;
97
98
99 static int socket_open(struct sockaddr_in *raddr, int, int, int, int, int);
100
101
102 /*
103 * Keep track of our port, in case somebody closes our socket
104 * on us.
105 */
106 static int
107 getmyport(
108 int sock
109 )
110 {
111 struct sockaddr_in sin;
112 int sinlen;
113
114 sinlen = sizeof(sin);
115 if (getsockname(sock, (struct sockaddr *)&sin, &sinlen) == 0) {
116 if (sin.sin_port == 0) {
117 (void)bind(sock, (struct sockaddr *)&sin, sizeof(sin));
118 sinlen = sizeof(sin);
119 (void)getsockname(sock, (struct sockaddr *)&sin,
120 &sinlen);
121 }
122 return (ntohs(sin.sin_port));
123 }
124 return (-1);
125 }
126
127
128 static void
129 createauth(
130 ni_private *ni
131 )
132 {
133 if (ni->passwd != NULL && ni->tc != NULL) {
134 auth_destroy(ni->tc->cl_auth);
135 ni->tc->cl_auth = authunix_create(ni->passwd, ni->uid, 0, 0,
136 NULL);
137 }
138 }
139
140
141 static void
142 fixtimeout(
143 struct timeval *tv,
144 long sec,
145 int tries
146 )
147 {
148 tv->tv_sec = sec / tries;
149 tv->tv_usec = ((sec % tries) * 1000000) / tries;
150 }
151
152
153 static void
154 ni_settimeout(
155 ni_private *ni,
156 int timeout
157 )
158 {
159 struct timeval tv;
160
161 tv.tv_sec = timeout;
162 tv.tv_usec = 0;
163 ni->tv_sec = timeout;
164 if (ni->tc != NULL) {
165 clnt_control(ni->tc, CLSET_TIMEOUT, &tv);
166 }
167 }
168
169
170 /*
171 * Connect to a given address/tag
172 */
173 static int
174 connectit(ni_private *ni)
175 {
176 struct sockaddr_in sin;
177 int sock;
178 CLIENT *cl;
179 struct timeval tv;
180 enum clnt_stat stat;
181 nibind_getregister_res res;
182
183 sock = -1;
184 bzero(&sin, sizeof(sin));
185 sin.sin_port = 0;
186 sin.sin_family = AF_INET;
187
188 tv.tv_sec = ni->rtv_sec == 0 ? NI_TIMEOUT_SHORT : ni->rtv_sec;
189 tv.tv_usec = 0;
190
191 ni_settimeout(ni, tv.tv_sec);
192 fixtimeout(&tv, ni->tv_sec, NI_TRIES);
193
194 /*
195 * If connecting to local domain, try using the "well-known" port first.
196 */
197 if (!strcmp(ni->tags[0], "local"))
198 {
199 interface_list_t *ilist;
200
201 ilist = sys_interfaces();
202 if (sys_is_my_address(ilist, &ni->addrs[0]))
203 {
204 sin.sin_port = htons(LOCAL_PORT);
205 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
206 sock = socket_open(&sin, NI_PROG, NI_VERS, ni->tv_sec, NI_TRIES, IPPROTO_TCP);
207 }
208 sys_interfaces_release(ilist);
209 }
210
211 /*
212 * If connecting to a domain other than the local domain,
213 * or if connection to local didn't work with local's well-known port,
214 * then go through portmap & nibindd to find the port and connect.
215 */
216 if (sock < 0)
217 {
218 sin.sin_port = 0;
219 sin.sin_addr = ni->addrs[0];
220
221 sock = socket_open(&sin, NIBIND_PROG, NIBIND_VERS, ni->tv_sec, NI_TRIES, IPPROTO_UDP);
222 if (sock < 0) return (0);
223
224 cl = clntudp_create(&sin, NIBIND_PROG, NIBIND_VERS, tv, &sock);
225 if (cl == NULL)
226 {
227 close(sock);
228 return (0);
229 }
230
231 tv.tv_sec = ni->rtv_sec == 0 ? NI_TIMEOUT_SHORT : ni->rtv_sec;
232 tv.tv_usec = 0;
233
234 stat = clnt_call(cl, NIBIND_GETREGISTER, xdr_ni_name, &ni->tags[0], xdr_nibind_getregister_res, &res, tv);
235 clnt_destroy(cl);
236 close(sock);
237 if (stat != RPC_SUCCESS || res.status != NI_OK) return (0);
238
239 sin.sin_port = htons(res.nibind_getregister_res_u.addrs.tcp_port);
240 sock = socket_open(&sin, NI_PROG, NI_VERS, ni->tv_sec, NI_TRIES, IPPROTO_TCP);
241 }
242
243 if (sock < 0) return (0);
244
245 cl = clnttcp_create(&sin, NI_PROG, NI_VERS, &sock, 0, 0);
246 if (cl == NULL)
247 {
248 close(sock);
249 return (0);
250 }
251
252 clnt_control(cl, CLSET_TIMEOUT, &tv);
253 ni->tc = cl;
254 ni->tsock = sock;
255 ni->tport = getmyport(sock);
256 createauth(ni);
257 fcntl(ni->tsock, F_SETFD, 1);
258 return (1);
259 }
260
261
262 void
263 ni_setabort(
264 void *ni,
265 int abort
266 )
267 {
268 ((ni_private *)ni)->abort = abort;
269 }
270
271
272 void
273 ni_setwritetimeout(
274 void *ni,
275 int timeout
276 )
277 {
278 ((ni_private *)ni)->wtv_sec = timeout;
279 }
280
281
282 void
283 ni_setreadtimeout(
284 void *ni,
285 int timeout
286 )
287 {
288 ((ni_private *)ni)->rtv_sec = timeout;
289 }
290
291
292 void
293 ni_needwrite(
294 void *ni,
295 int needwrite
296 )
297 {
298 ((ni_private *)ni)->needwrite = needwrite;
299 }
300
301
302 /*
303 * Returns a client handle to the NetInfo server, if it's running
304 */
305 static int
306 connectlocal(ni_private *ni)
307 {
308 int printed = 0;
309
310 ni->naddrs = 1;
311 ni->addrs = (struct in_addr *)malloc(sizeof(struct in_addr));
312 ni->addrs[0].s_addr = htonl(INADDR_LOOPBACK);
313 ni->tags = (ni_name *)malloc(sizeof(ni_name));
314 ni->tags[0] = ni_name_dup("local");
315 ni->whichwrite = 0;
316
317 while (!connectit(ni))
318 {
319 if (!printed)
320 {
321 syslog(LOG_ERR, "NetInfo timeout connecting to local domain, sleeping");
322 printed++;
323 }
324
325 sleep(NI_SLEEPTIME);
326 /* wait forever */
327 }
328
329 if (printed)
330 {
331 syslog(LOG_ERR, "NetInfo connection to local domain waking");
332 }
333
334 return (1);
335 }
336
337
338 /*
339 * Destroy the client handle
340 */
341 static void
342 clnt_kill(
343 CLIENT *cl,
344 int sock,
345 int port
346 )
347 {
348 int save = 0;
349
350 if (sock >= 0 && getmyport(sock) != port) {
351 /*
352 * Somebody else has the descriptor open. Do not close it,
353 * it's not ours.
354 */
355 save++;
356 }
357 if (cl != NULL) {
358 auth_destroy(cl->cl_auth);
359 clnt_destroy(cl);
360 }
361 if (!save) {
362 /*
363 * It's ours and we can close it
364 */
365 (void)close(sock);
366 }
367 }
368
369
370 /*
371 * Reinitialize everything
372 */
373 static void
374 reinit(
375 ni_private *ni
376 )
377 {
378 if (ni->tc != NULL) {
379 clnt_kill(ni->tc, ni->tsock, ni->tport);
380 ni->tc = NULL;
381 }
382 ni->tsock = -1;
383 ni->tport = -1;
384 ni->pid = getpid();
385 }
386
387
388 /*
389 * Switch to a new server
390 */
391 static void
392 ni_switch(
393 ni_private *ni,
394 ni_index which
395 )
396 {
397 struct in_addr tmp_addr;
398 ni_name tmp_tag;
399
400 if (which == 0) {
401 return;
402 }
403 reinit(ni);
404 tmp_addr = ni->addrs[0];
405 tmp_tag = ni->tags[0];
406
407 ni->addrs[0] = ni->addrs[which];
408 ni->tags[0] = ni->tags[which];
409
410 ni->addrs[which] = tmp_addr;
411 ni->tags[which] = tmp_tag;
412
413 if (ni->whichwrite == 0) {
414 ni->whichwrite = which;
415 }
416 else if (ni->whichwrite == which) {
417 ni->whichwrite = 0;
418 }
419 }
420
421
422 /*
423 * Swap two servers' positions
424 */
425 static void
426 ni_swap(
427 ni_private *ni,
428 ni_index a,
429 ni_index b
430 )
431 {
432 struct in_addr tmp_addr;
433 ni_name tmp_tag;
434
435 if (a == b) return;
436
437 tmp_addr = ni->addrs[a];
438 tmp_tag = ni->tags[a];
439
440 ni->addrs[a] = ni->addrs[b];
441 ni->tags[a] = ni->tags[b];
442
443 ni->addrs[b] = tmp_addr;
444 ni->tags[b] = tmp_tag;
445
446 if (ni->whichwrite == a) {
447 ni->whichwrite = b;
448 }
449 else if (ni->whichwrite == b) {
450 ni->whichwrite = a;
451 }
452 }
453
454
455 /*
456 * Callback routine for multi_call
457 * XXX: should save returned port numbers
458 */
459 static bool_t
460 eachresult(
461 void *vstuff,
462 struct sockaddr_in *sin,
463 int which
464 )
465 {
466 getreg_stuff *stuff = (getreg_stuff *)vstuff;
467
468 if (stuff->res.status != NI_OK) {
469 return (FALSE);
470 }
471 ni_switch(stuff->ni, which);
472 return (TRUE);
473 }
474
475
476 /*
477 * shuffle addresses
478 */
479 static void
480 shuffle(ni_private *ni)
481 {
482 int *shuffle;
483 int i, j;
484 int rfd;
485
486 if (ni->naddrs <= 1) return;
487
488 rfd = open("/dev/random", O_RDONLY, 0);
489 shuffle = (int *)malloc(ni->naddrs * sizeof(int));
490 for (i = 0; i < ni->naddrs; i++) shuffle[i] = i;
491 for (i = 0, j = ni->naddrs; j > 0; i++, j--) {
492 unsigned int rEnt;
493 long rVal;
494 int tEnt;
495
496 /* get a random number */
497 if ((rfd < 0) ||
498 (read(rfd, &rVal, sizeof(rVal)) != sizeof(rVal))) {
499 /* if we could not read from /dev/random */
500 static int initialized = 0;
501 if (!initialized)
502 {
503 srandom(gethostid() ^ time(NULL));
504 initialized++;
505 }
506 rVal = random();
507 }
508
509 rEnt = (unsigned int)rVal % j; /* pick one of the remaining entries */
510 tEnt = shuffle[rEnt]; /* grab the random entry */
511 shuffle[rEnt] = shuffle[j-1]; /* the last entry moves to the random slot */
512 shuffle[j-1] = tEnt; /* the last slot gets the random entry */
513 ni_swap(ni, rEnt, j-1); /* and swap the actual NI addresses */
514 }
515 free(shuffle);
516 if (rfd > 0) (void)close(rfd);
517 return;
518 }
519
520
521 static int
522 rebind(
523 ni_private *ni
524 )
525 {
526 enum clnt_stat stat;
527 getreg_stuff stuff;
528 int sleeptime = NI_SLEEPTIME;
529 int printed = 0;
530 int nlocal;
531 int nnetwork;
532 interface_list_t *ilist;
533 int i;
534
535 if (ni->naddrs == 1) {
536 ni->whichwrite = 0;
537 return (1);
538 }
539
540 /*
541 * Majka - 1994.04.27
542 * re-order the servers so that:
543 * servers on the local host are at the start of the list, then
544 * servers on the local network are next, then
545 * all other servers are next
546 */
547
548 ilist = sys_interfaces();
549
550 /*
551 * shuffle addresses
552 */
553 shuffle(ni);
554
555 /*
556 * move local servers to the head of the list
557 */
558 nlocal = 0;
559 for (i = nlocal; i < ni->naddrs; i++) {
560 if (sys_is_my_address(ilist, &ni->addrs[i]))
561 {
562 ni_swap(ni, nlocal, i);
563 nlocal++;
564 }
565 }
566
567 /*
568 * move servers on this network to follow local servers
569 */
570 nnetwork = nlocal;
571 for (i = nnetwork; i < ni->naddrs; i++) {
572 if (sys_is_my_network(ilist, &ni->addrs[i]) ||
573 IS_BROADCASTADDR(ni->addrs[i].s_addr))
574 {
575 ni_swap(ni, nnetwork, i);
576 nnetwork++;
577 }
578 }
579
580 sys_interfaces_release(ilist);
581
582 stuff.ni = ni;
583 for (;;) {
584 /*
585 * call local servers first
586 */
587 if (nlocal > 0) {
588 for (i = 0; i < nlocal; i++) {
589 syslog(LOG_DEBUG, "NetInfo connect call to: %s/%s (local %d)",
590 inet_ntoa(ni->addrs[i]), ni->tags[i], i);
591 }
592 stat = multi_call(nlocal, ni->addrs,
593 NIBIND_PROG, NIBIND_VERS, NIBIND_GETREGISTER,
594 xdr_ni_name, ni->tags,
595 sizeof(ni_name),
596 xdr_nibind_getregister_res,
597 &stuff, eachresult,
598 NI_TIMEOUT_SHORT);
599 if (stat == RPC_SUCCESS) {
600 break;
601 }
602 }
603
604 /*
605 * call local servers and this network's servers
606 */
607 if (nnetwork > nlocal) {
608 for (i = 0; i < nnetwork; i++) {
609 syslog(LOG_DEBUG, "NetInfo connect call to: %s/%s (network %d)",
610 inet_ntoa(ni->addrs[i]), ni->tags[i], i);
611 }
612 stat = multi_call(nnetwork, ni->addrs,
613 NIBIND_PROG, NIBIND_VERS, NIBIND_GETREGISTER,
614 xdr_ni_name, ni->tags,
615 sizeof(ni_name),
616 xdr_nibind_getregister_res,
617 &stuff, eachresult,
618 NI_TIMEOUT_SHORT);
619 if (stat == RPC_SUCCESS) {
620 break;
621 }
622 }
623
624 /*
625 * call all servers
626 */
627 for (i = 0; i < ni->naddrs; i++) {
628 syslog(LOG_DEBUG, "NetInfo connect call to: %s/%s (world %d)",
629 inet_ntoa(ni->addrs[i]), ni->tags[i], i);
630 }
631 stat = multi_call(ni->naddrs,
632 ni->addrs, NIBIND_PROG, NIBIND_VERS,
633 NIBIND_GETREGISTER,
634 xdr_ni_name, ni->tags,
635 sizeof(ni_name),
636 xdr_nibind_getregister_res,
637 &stuff, eachresult,
638 ni->rtv_sec == 0 ? NI_TIMEOUT_SHORT : ni->rtv_sec);
639 if (stat == RPC_SUCCESS) {
640 break;
641 }
642
643 if (ni->abort) {
644 return (0);
645 }
646 if (!printed) {
647 if (ni->whichwrite >= 0) {
648 syslog(LOG_ERR,
649 "NetInfo connect timeout (domain with master %s/%s), sleeping",
650 inet_ntoa(ni->addrs[ni->whichwrite]), ni->tags[ni->whichwrite]);
651 }
652 else {
653 syslog(LOG_ERR, "NetInfo connect timeout (domain with server %s/%s), sleeping",
654 inet_ntoa(ni->addrs[0]), ni->tags[0]);
655 }
656 printed++;
657 }
658 sleep(sleeptime);
659 if (sleeptime < NI_MAXSLEEPTIME) {
660 sleeptime *= 2; /* backoff */
661 }
662 }
663
664 syslog(LOG_INFO, "NetInfo connected to %s/%s", inet_ntoa(ni->addrs[0]), ni->tags[0]);
665
666 if (printed) {
667 syslog(LOG_ERR, "NetInfo connected to %s/%s", inet_ntoa(ni->addrs[0]), ni->tags[0]);
668 }
669 return (1);
670 }
671
672
673 /*
674 * Confirm that our tcp socket is still valid
675 */
676 static int
677 confirm_tcp(
678 ni_private *ni,
679 int needwrite
680 )
681 {
682 if (ni->tsock != -1) {
683 if (getmyport(ni->tsock) == ni->tport) {
684 return (1);
685 }
686 /*
687 * Somebody closed our socket. Do not close it, it could
688 * be owned by somebody else now.
689 */
690 if (ni->tc != NULL)
691 {
692 if (ni->tc->cl_auth != NULL) auth_destroy(ni->tc->cl_auth);
693 clnt_destroy(ni->tc);
694 ni->tc = NULL;
695 }
696 }
697 if (!needwrite && !rebind(ni) && ni->abort) {
698 return (0);
699 }
700 return (connectit(ni));
701 }
702
703
704 static int
705 setmaster(
706 ni_private *ni
707 )
708 {
709 ni_id root;
710 ni_namelist nl;
711 ni_name sep;
712 ni_idlist idl;
713 ni_name master;
714 ni_index i;
715 ni_index j;
716 ni_id id;
717 struct in_addr addr;
718 int needwrite;
719
720 if (ni->naddrs == 1) {
721 /*
722 * One server - must be the master
723 */
724 ni->whichwrite = 0;
725 return (1);
726 }
727 needwrite = ni->needwrite;
728 ni->needwrite = 0;
729 if (ni_root(ni, &root) != NI_OK) {
730 ni->needwrite = needwrite;
731 return (0);
732 }
733 NI_INIT(&nl);
734 if (ni_lookupprop(ni, &root, NAME_MASTER, &nl) != NI_OK) {
735 ni->needwrite = needwrite;
736 return (0);
737 }
738 if (nl.ninl_len == 0) {
739 ni->needwrite = needwrite;
740 return (0);
741 }
742 sep = index(nl.ninl_val[0], '/');
743 if (sep == NULL) {
744 ni->needwrite = needwrite;
745 return (0);
746 }
747 *sep++ = 0;
748 master = nl.ninl_val[0];
749 NI_INIT(&idl);
750 if (ni_lookup(ni, &root, NAME_NAME, NAME_MACHINES, &idl) != NI_OK) {
751 ni->needwrite = needwrite;
752 ni_namelist_free(&nl);
753 return (0);
754 }
755 if (idl.niil_len < 1) {
756 ni->needwrite = needwrite;
757 return (0);
758 }
759 id.nii_object = idl.niil_val[0];
760 ni_idlist_free(&idl);
761 NI_INIT(&idl);
762 if (ni_lookup(ni, &id, NAME_NAME, master, &idl) != NI_OK) {
763 ni_namelist_free(&nl);
764 ni->needwrite = needwrite;
765 return (0);
766 }
767 ni_namelist_free(&nl);
768 if (idl.niil_len < 1) {
769 ni->needwrite = needwrite;
770 return (0);
771 }
772 id.nii_object = idl.niil_val[0];
773 ni_idlist_free(&idl);
774 NI_INIT(&nl);
775 if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) {
776 return (0);
777 }
778 for (i = 0; i < nl.ninl_len; i++) {
779 addr.s_addr = inet_addr(nl.ninl_val[i]);
780 for (j = 0; j < ni->naddrs; j++) {
781 if (addr.s_addr == ni->addrs[j].s_addr) {
782 ni->whichwrite = j;
783 ni_namelist_free(&nl);
784 ni->needwrite = needwrite;
785 return (1);
786 }
787 }
788 }
789 ni->needwrite = needwrite;
790 ni_namelist_free(&nl);
791 return (0);
792 }
793
794
795 static void *
796 callit(
797 ni_private *ni,
798 void *(*stub)(),
799 void *args,
800 int needwrite
801 )
802 {
803 void *resp;
804 struct rpc_err err;
805 int i;
806 int sleeptime = 0;
807 int printed = 0;
808
809 if (getpid() != ni->pid) {
810 reinit(ni);
811 }
812 if (needwrite || ni->needwrite) {
813 if (ni->whichwrite >= 0) {
814 ni_switch(ni, ni->whichwrite);
815 } else {
816 if (!setmaster(ni)) {
817 return (NULL);
818 }
819 ni_switch(ni, ni->whichwrite);
820 }
821 if (!needwrite) {
822 ni_settimeout(ni, (ni->rtv_sec == 0 ?
823 NI_TIMEOUT_SHORT : ni->rtv_sec));
824 needwrite = 1;
825 } else {
826 ni_settimeout(ni, (ni->wtv_sec == 0 ?
827 NI_TIMEOUT_LONG : ni->wtv_sec));
828 }
829 } else {
830 ni_settimeout(ni, (ni->rtv_sec == 0 ?
831 NI_TIMEOUT_SHORT : ni->rtv_sec));
832 }
833 for (;;) {
834 /*
835 * Try more than once, in case server closed connection.
836 */
837 for (i = 0; i < NI_MAXCONNTRIES; i++) {
838 if (!confirm_tcp(ni, needwrite)) {
839 break;
840 }
841 if ((resp = (*stub)(args, ni->tc)) != NULL) {
842 if (printed) {
843 syslog(LOG_ERR, "NetInfo connected to %s/%s",
844 inet_ntoa(ni->addrs[0]), ni->tags[0]);
845 }
846 return (resp);
847 }
848 if (ni->tc != NULL)
849 {
850 clnt_geterr(ni->tc, &err);
851 if (err.re_status != RPC_CANTRECV) break;
852 }
853 if (i + 1 < NI_MAXCONNTRIES) {
854 /*
855 * Server closed connection. Reinit and try
856 * again.
857 */
858 reinit(ni);
859 }
860 }
861 if (err.re_status == RPC_PROCUNAVAIL) {
862 return (NULL);
863 }
864 if (needwrite || ni->abort) {
865 /*
866 * We time out for writes or if it is explicitly
867 * requested.
868 */
869 if (ni->abort) {
870 reinit(ni);
871 }
872 syslog(LOG_ERR,
873 "NetInfo connection failed for server %s/%s",
874 inet_ntoa(ni->addrs[0]), ni->tags[0]);
875 return (NULL);
876 }
877 if (!printed) {
878 if (ni->tc != NULL) {
879 if (!(sleeptime == 0 &&
880 err.re_status == RPC_TIMEDOUT)) {
881 /*
882 * Do not print message on
883 * first timeout. It is likely
884 * we will find another server soon.
885 * Let's not needlessly alarm the
886 * poor user!
887 */
888 syslog(LOG_ERR, "%s on connection to %s/%s",
889 clnt_sperror(ni->tc,"NetInfo connection timeout"),
890 inet_ntoa(ni->addrs[0]), ni->tags[0]);
891 printed++;
892 }
893 else {
894 /* first attempt failed */
895 syslog(LOG_ERR, "%s on initial connection to %s/%s",
896 clnt_sperror(ni->tc,"NetInfo connection timeout"),
897 inet_ntoa(ni->addrs[0]), ni->tags[0]);
898 }
899 } else {
900 syslog(LOG_ERR,
901 "NetInfo connection failed for server %s/%s",
902 inet_ntoa(ni->addrs[0]), ni->tags[0]);
903 printed++;
904 }
905 }
906 if (sleeptime > 0) {
907 sleep(sleeptime);
908 if (sleeptime < NI_MAXSLEEPTIME) {
909 sleeptime *= 2; /* backoff */
910 }
911 } else {
912 /*
913 * Do not sleep on the first timeout.
914 * It is likely we will find another server quickly.
915 */
916 sleeptime = NI_SLEEPTIME;
917 }
918 reinit(ni);
919 (void)rebind(ni);
920 }
921 }
922
923
924 #define RCALLIT(a, b, c) callit((ni_private *)(a), (void *(*)())(b), \
925 (void *)c, 0)
926
927
928 #define WCALLIT(a, b, c) callit((ni_private *)(a), (void *(*)())(b), \
929 (void *)c, 1)
930
931
932 static void
933 ni_clear(
934 ni_private *ni
935 )
936 {
937 ni->needwrite = 0;
938 ni->naddrs = 0;
939 ni->addrs = NULL;
940 ni->tags = NULL;
941 ni->tc = NULL;
942 ni->tsock = -1;
943 ni->tport = -1;
944 ni->whichwrite = -1;
945 ni->passwd = NULL;
946 }
947
948
949 static void *
950 ni_alloc(
951 void
952 )
953 {
954 ni_private *ni;
955
956 ni = (ni_private *)malloc(sizeof(*ni));
957 ni->naddrs = 0;
958 ni->whichwrite = -1;
959 ni->pid = getpid();
960 ni->tsock = -1;
961 ni->tport = -1;
962 ni->tc = NULL;
963 ni->tv_sec = NI_TIMEOUT_SHORT;
964 ni->rtv_sec = 0;
965 ni->wtv_sec = 0;
966 ni->abort = 0;
967 ni->passwd = NULL;
968 ni->uid = getuid();
969 ni->needwrite = 0;
970 return ((void *)ni);
971 }
972
973
974 void *
975 _ni_dup(
976 void *ni
977 )
978 {
979 ni_private *dupni;
980 ni_index i;
981
982 dupni = (ni_private *)ni_alloc();
983 *dupni = *NIP(ni);
984 ni_clear(dupni);
985 dupni->naddrs = NIP(ni)->naddrs;
986 dupni->whichwrite = NIP(ni)->whichwrite;
987 if (dupni->naddrs > 0) {
988 dupni->addrs = ((struct in_addr *)
989 malloc(NIP(ni)->naddrs * sizeof(struct in_addr)));
990 bcopy(NIP(ni)->addrs, dupni->addrs,
991 NIP(ni)->naddrs * sizeof(struct in_addr));
992 dupni->tags = ((ni_name *)
993 malloc(NIP(ni)->naddrs * sizeof(ni_name)));
994 for (i = 0; i < NIP(ni)->naddrs; i++) {
995 dupni->tags[i] = ni_name_dup(NIP(ni)->tags[i]);
996 }
997 }
998 if (NIP(ni)->passwd != NULL) {
999 dupni->passwd = ni_name_dup(NIP(ni)->passwd);
1000 }
1001 return ((void *)dupni);
1002 }
1003
1004
1005 static int
1006 match(
1007 ni_name domain,
1008 ni_name domtag,
1009 ni_name *tag
1010 )
1011 {
1012 int len = strlen(domain);
1013 ni_name sep;
1014
1015 sep = index(domtag, '/');
1016 if (sep == NULL) {
1017 return (0);
1018 }
1019 if (strncmp(domain, domtag, len) == 0 &&
1020 domtag[len] == '/') {
1021 *tag = ni_name_dup(sep + 1);
1022 return (1);
1023 }
1024 return (0);
1025 }
1026
1027
1028 static void
1029 add_addr_tag(ni_private *ni, ni_name addrtag)
1030 {
1031 struct in_addr addr;
1032 ni_name tag;
1033 char *slash;
1034
1035 slash = strchr(addrtag, '/');
1036 if (slash == NULL) return;
1037
1038 tag = slash + 1;
1039 if (tag[0] == '\0') return;
1040
1041 *slash = '\0';
1042
1043 if (inet_aton(addrtag, &addr) == 0) return;
1044
1045 if (ni->naddrs == 0)
1046 {
1047 ni->addrs = (struct in_addr *)calloc(1, sizeof(struct in_addr));
1048 if (ni->addrs == NULL) return;
1049
1050 ni->tags = (ni_name *)calloc(1, sizeof(ni_name));
1051 if (ni->tags == NULL) return;
1052 }
1053 else
1054 {
1055 ni->addrs = (struct in_addr *)realloc(ni->addrs, ((ni->naddrs + 1) * sizeof(struct in_addr)));
1056 if (ni->addrs == NULL) return;
1057
1058 ni->tags = (ni_name *)realloc(ni->tags, ((ni->naddrs + 1) * sizeof(ni_name)));
1059 if (ni->tags == NULL) return;
1060 }
1061
1062 ni->addrs[ni->naddrs] = addr;
1063 ni->tags[ni->naddrs] = ni_name_dup(tag);
1064 ni->naddrs++;
1065 }
1066
1067 static int
1068 addaddr(void *ni, ni_index ido, ni_name tag, ni_private *target_ni)
1069 {
1070 ni_id id;
1071 ni_namelist nl;
1072 struct in_addr addr;
1073 int i;
1074
1075 id.nii_object = ido;
1076 NI_INIT(&nl);
1077 if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) return 0;
1078
1079 if (nl.ni_namelist_len == 0) return 0;
1080
1081 if (target_ni->naddrs == 0)
1082 {
1083 target_ni->addrs = (struct in_addr *)malloc(nl.ni_namelist_len * sizeof(struct in_addr));
1084 target_ni->tags = (ni_name *)malloc(nl.ni_namelist_len * sizeof(ni_name));
1085 }
1086 else
1087 {
1088 target_ni->addrs = (struct in_addr *)realloc(target_ni->addrs, ((target_ni->naddrs + nl.ni_namelist_len) * sizeof(struct in_addr)));
1089 target_ni->tags = (ni_name *)realloc(target_ni->tags, ((target_ni->naddrs + nl.ni_namelist_len) * sizeof(ni_name)));
1090 }
1091
1092 for (i = 0; i < nl.ni_namelist_len; i++)
1093 {
1094 addr.s_addr = inet_addr(nl.ni_namelist_val[i]);
1095 target_ni->addrs[target_ni->naddrs] = addr;
1096 target_ni->tags[target_ni->naddrs] = ni_name_dup(tag);
1097 target_ni->naddrs++;
1098 }
1099
1100 ni_namelist_free(&nl);
1101 return 1;
1102 }
1103
1104 static int
1105 get_daddr(ni_private *ni, ni_name dom, ni_private *target_ni)
1106 {
1107 ni_id nid;
1108 ni_idlist ids;
1109 ni_entrylist entries;
1110 ni_proplist pl;
1111 ni_index i;
1112 ni_index j;
1113 ni_name tag;
1114
1115 if (dom == NULL) return 0;
1116
1117 if (!strcmp(dom, "."))
1118 {
1119 /* check for server list */
1120 NI_INIT(&pl);
1121 if (ni_statistics(ni, &pl) == NI_OK)
1122 {
1123 i = ni_proplist_match(pl, NAME_DOMAIN_SERVERS, NULL);
1124 if (i != NI_INDEX_NULL)
1125 {
1126 if (pl.ni_proplist_val[i].nip_val.ni_namelist_len > 0)
1127 {
1128 for (j = 0; j < pl.ni_proplist_val[i].nip_val.ni_namelist_len; j++)
1129 {
1130 add_addr_tag(target_ni, pl.ni_proplist_val[i].nip_val.ni_namelist_val[j]);
1131 }
1132 ni_proplist_free(&pl);
1133 return 1;
1134 }
1135 }
1136 ni_proplist_free(&pl);
1137 }
1138 }
1139
1140 if (ni_root(ni, &nid) != NI_OK) return 0;
1141 NI_INIT(&ids);
1142 if (ni_lookup(ni, &nid, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) return 0;
1143
1144 nid.nii_object = ids.niil_val[0];
1145 ni_idlist_free(&ids);
1146
1147 NI_INIT(&entries);
1148 if (ni_list(ni, &nid, NAME_SERVES, &entries) != NI_OK) return 0;
1149
1150 for (i = 0; i < entries.niel_len; i++)
1151 {
1152 if (entries.niel_val[i].names == NULL) continue;
1153
1154 for (j = 0; j < entries.niel_val[i].names->ni_namelist_len; j++)
1155 {
1156 if (match(dom, entries.niel_val[i].names->ni_namelist_val[j], &tag))
1157 {
1158 addaddr(ni, entries.niel_val[i].id, tag, target_ni);
1159 ni_name_free(&tag);
1160 }
1161 }
1162 }
1163
1164 ni_entrylist_free(&entries);
1165 return (target_ni->naddrs > 0);
1166 }
1167
1168 static ni_status
1169 getparent(ni_private *oldni, ni_private **newni)
1170 {
1171 ni_rparent_res *resp;
1172 ni_private *ni = NULL;
1173 ni_private *dupni;
1174 int found = 0;
1175 ni_index i;
1176 struct in_addr raddr;
1177 int printed = 0;
1178 int inlist = 0;
1179
1180 while (found == 0)
1181 {
1182 /*
1183 * First, find our parent, any parent
1184 */
1185 for (;;)
1186 {
1187 resp = RCALLIT(oldni, _ni_rparent_2, NULL);
1188 if (resp == NULL) return NI_FAILED;
1189 if (resp->status != NI_NORESPONSE) break;
1190
1191 if (!printed)
1192 {
1193 syslog(LOG_ERR, "NetInfo timeout finding server for parent of %s/%s, sleeping",
1194 inet_ntoa(oldni->addrs[0]), oldni->tags[0]);
1195 printed++;
1196 }
1197
1198 sleep(NI_SLEEPTIME);
1199 }
1200
1201 if (printed)
1202 {
1203 raddr.s_addr = htonl(resp->ni_rparent_res_u.binding.addr);
1204
1205 syslog(LOG_ERR, "NetInfo %s/%s found parent %s/%s",
1206 inet_ntoa(oldni->addrs[0]), oldni->tags[0],
1207 inet_ntoa(raddr), resp->ni_rparent_res_u.binding.tag);
1208 }
1209
1210 if (resp->status != NI_OK) return (resp->status);
1211
1212 ni = ni_alloc();
1213 *ni = *oldni;
1214 ni_clear(ni);
1215 ni->naddrs = 1;
1216 ni->addrs = (struct in_addr *)malloc(sizeof(struct in_addr));
1217 ni->addrs[0].s_addr=htonl(resp->ni_rparent_res_u.binding.addr);
1218 ni->tags = (ni_name *)malloc(sizeof(ni_name));
1219 ni->tags[0] = ni_name_dup(resp->ni_rparent_res_u.binding.tag);
1220
1221 xdr_free(xdr_ni_rparent_res, resp);
1222
1223 dupni = ni;
1224 ni = ni_alloc();
1225 *ni = *dupni;
1226 ni_clear(ni);
1227 if (get_daddr(dupni, ".", ni) == 0)
1228 {
1229 if (oldni->abort == 1)
1230 {
1231 ni_free(dupni);
1232 break;
1233 }
1234 }
1235 else
1236 {
1237 /*
1238 * Make sure returned parent is head of list
1239 */
1240 for (i = 0; i < ni->naddrs; i++)
1241 {
1242 if (ni->addrs[i].s_addr == dupni->addrs[0].s_addr)
1243 {
1244 ni_switch(ni, i);
1245 inlist++;
1246 break;
1247 }
1248 }
1249
1250 /*
1251 * Reuse dupni client info
1252 */
1253 ni->tsock = dupni->tsock;
1254 ni->tport = dupni->tport;
1255 ni->tc = dupni->tc;
1256 dupni->tsock = -1;
1257 dupni->tport = -1;
1258 dupni->tc = NULL;
1259 found = 1;
1260
1261 /*
1262 * If returned parent wasn't in list, it's a rogue.
1263 * Log an error and drop the connection.
1264 */
1265 if (inlist == 0)
1266 {
1267 syslog(LOG_ERR, "Rogue NetInfo server detected: %s/%s",
1268 inet_ntoa(dupni->addrs[0]), dupni->tags[0]);
1269 reinit(ni);
1270 }
1271
1272 }
1273 ni_free(dupni);
1274 }
1275
1276 if (found)
1277 {
1278 *newni = ni;
1279 return NI_OK;
1280 }
1281
1282 if (ni != NULL) ni_free(ni);
1283 return NI_FAILED;
1284 }
1285
1286
1287 void *
1288 ni_connect(
1289 struct sockaddr_in *sin,
1290 const char *tag
1291 )
1292 {
1293 void *ni;
1294
1295 ni = ni_alloc();
1296 NIP(ni)->naddrs = 1;
1297 NIP(ni)->addrs = (struct in_addr *
1298 )malloc(sizeof(struct in_addr));
1299 NIP(ni)->addrs[0] = sin->sin_addr;
1300 NIP(ni)->tags = (ni_name *)malloc(sizeof(ni_name));
1301 NIP(ni)->tags[0] = ni_name_dup(tag);
1302 return (ni);
1303 }
1304
1305
1306 ni_status
1307 ni_addrtag(
1308 void *ni,
1309 struct sockaddr_in *addr,
1310 ni_name *tag
1311 )
1312 {
1313
1314 if (!confirm_tcp(ni, 0)) {
1315 return (NI_FAILED);
1316 }
1317 *tag = ni_name_dup(NIP(ni)->tags[0]);
1318 addr->sin_addr = NIP(ni)->addrs[0];
1319 addr->sin_port = htons(NIP(ni)->tport);
1320 addr->sin_family = AF_INET;
1321 bzero(addr->sin_zero, sizeof(addr->sin_zero));
1322 return (NI_OK);
1323 }
1324
1325
1326 void *
1327 ni_new(void *oldni, const char *domain)
1328 {
1329 ni_private *ni;
1330 ni_status status;
1331 ni_name sep, addr, tag;
1332 struct sockaddr_in sin;
1333 struct hostent *he;
1334
1335 if (domain == NULL) return NULL;
1336
1337 sep = index(domain, '@');
1338 if (sep != NULL)
1339 {
1340 tag = strncpy((char *)malloc(sep - domain + 1), domain, sep - domain);
1341 tag[sep - domain] = '\0';
1342 addr = strcpy ((char *)malloc(strlen(sep + 1)), sep + 1);
1343 sin.sin_addr.s_addr = inet_addr(addr);
1344 if (sin.sin_addr.s_addr == INADDR_NONE)
1345 {
1346 he = gethostbyname(addr);
1347 if (he == NULL)
1348 {
1349 free(addr);
1350 free(tag);
1351 return NULL;
1352 }
1353
1354 bcopy(he->h_addr_list[0], &sin.sin_addr.s_addr, he->h_length);
1355 }
1356
1357 ni = ni_connect(&sin, tag);
1358 free(addr);
1359 free(tag);
1360
1361 return (void *)ni;
1362 }
1363
1364 ni = NULL;
1365
1366 if (oldni == NULL)
1367 {
1368 ni = ni_alloc();
1369 if (connectlocal(ni) == 0)
1370 {
1371 free(ni);
1372 return NULL;
1373 }
1374
1375 if (strcmp(domain, ".") == 0) return (void *)ni;
1376
1377 if (strcmp(domain, "..") == 0)
1378 {
1379 oldni = ni;
1380 status = getparent((ni_private *)oldni, &ni);
1381 ni_free(oldni);
1382 if (status != NI_OK) return NULL;
1383 return (void *)ni;
1384 }
1385
1386 ni_free(ni);
1387 return NULL;
1388 }
1389
1390 if (strcmp(domain, "..") == 0)
1391 {
1392 status = getparent((ni_private *)oldni, &ni);
1393 if (status != NI_OK) return NULL;
1394 return (void *)ni;
1395 }
1396
1397 ni = ni_alloc();
1398 *ni = *NIP(oldni);
1399 ni_clear(ni);
1400 if (!get_daddr(oldni, (ni_name)domain, ni))
1401 {
1402 ni_free(ni);
1403 return NULL;
1404 }
1405
1406 return (void *)ni;
1407 }
1408
1409
1410 void
1411 ni_free(
1412 void *ni
1413 )
1414 {
1415 ni_index i;
1416
1417 if (NIP(ni)->tc != NULL) {
1418 clnt_kill(NIP(ni)->tc, NIP(ni)->tsock, NIP(ni)->tport);
1419 }
1420 if (NIP(ni)->naddrs > 0) {
1421 free(NIP(ni)->addrs);
1422 for (i = 0; i < NIP(ni)->naddrs; i++) {
1423 ni_name_free(&NIP(ni)->tags[i]);
1424 }
1425 free(NIP(ni)->tags);
1426 }
1427 if (NIP(ni)->passwd != NULL) {
1428 ni_name_free(&NIP(ni)->passwd);
1429 }
1430 free(ni);
1431 }
1432
1433
1434 /*
1435 * The rest of these are just wrappers that end up doing
1436 * RPC calls to the local NetInfo server.
1437 */
1438 ni_status
1439 ni_statistics(
1440 void *ni,
1441 ni_proplist *pl
1442 )
1443 {
1444 ni_proplist *resp;
1445
1446 if ((resp = (ni_proplist *)RCALLIT(ni, _ni_statistics_2, NULL))
1447 == NULL) {
1448 return (NI_FAILED);
1449 }
1450 *pl = *resp;
1451 return (NI_OK);
1452 }
1453
1454
1455 ni_status
1456 ni_root(
1457 void *ni,
1458 ni_id *id
1459 )
1460 {
1461 ni_id_res *resp;
1462
1463 if ((resp = RCALLIT(ni, _ni_root_2, id)) == NULL) {
1464 clnt_debug(ni, "_ni_root");
1465 return (NI_FAILED);
1466 }
1467 if (resp->status == NI_OK) {
1468 *id = resp->ni_id_res_u.id;
1469 }
1470 return (resp->status);
1471 }
1472
1473
1474 ni_status
1475 ni_self(
1476 void *ni,
1477 ni_id *id
1478 )
1479 {
1480 ni_id_res *resp;
1481
1482 if ((resp = RCALLIT(ni, _ni_self_2, id)) == NULL) {
1483 clnt_debug(ni, "_ni_self");
1484 return (NI_FAILED);
1485 }
1486 if (resp->status == NI_OK) {
1487 *id = resp->ni_id_res_u.id;
1488 }
1489 return (resp->status);
1490 }
1491
1492
1493 ni_status
1494 ni_parent(
1495 void *ni,
1496 ni_id *id,
1497 ni_index *parent_id_p
1498 )
1499 {
1500 ni_parent_res *resp;
1501
1502 if ((resp = RCALLIT(ni, _ni_parent_2, id)) == NULL) {
1503 clnt_debug(ni, "_ni_parent");
1504 return (NI_FAILED);
1505 }
1506 if (resp->status == NI_OK) {
1507 *parent_id_p = resp->ni_parent_res_u.stuff.object_id;
1508 *id = resp->ni_parent_res_u.stuff.self_id;
1509 }
1510 return (resp->status);
1511 }
1512
1513
1514 ni_status
1515 ni_children(
1516 void *ni,
1517 ni_id *id,
1518 ni_idlist *children
1519 )
1520 {
1521 ni_children_res *resp;
1522
1523 if ((resp = RCALLIT(ni, _ni_children_2, id)) == NULL) {
1524 clnt_debug(ni, "_ni_children");
1525 return (NI_FAILED);
1526 }
1527 if (resp->status == NI_OK) {
1528 *children = resp->ni_children_res_u.stuff.children;
1529 *id = resp->ni_children_res_u.stuff.self_id;
1530 }
1531 return (resp->status);
1532 }
1533
1534
1535 ni_status
1536 ni_create(
1537 void *ni,
1538 ni_id *parent_id,
1539 ni_proplist pl,
1540 ni_id *child_id_p,
1541 ni_index where
1542 )
1543 {
1544 ni_create_args args;
1545 ni_create_res *resp;
1546
1547 args.id = *parent_id;
1548 args.props = pl;
1549 args.where = where;
1550 args.target_id = NULL;
1551 if ((resp = WCALLIT(ni, _ni_create_2, &args)) == NULL) {
1552 clnt_debug(ni, "_ni_create");
1553 return (NI_FAILED);
1554 }
1555 if (resp->status == NI_OK) {
1556 *child_id_p = resp->ni_create_res_u.stuff.id;
1557 *parent_id = resp->ni_create_res_u.stuff.self_id;
1558 }
1559 return (resp->status);
1560 }
1561
1562
1563 ni_status
1564 ni_destroy(
1565 void *ni,
1566 ni_id *parent_id,
1567 ni_id self_id
1568 )
1569 {
1570 ni_id_res *resp;
1571 ni_destroy_args args;
1572
1573 args.parent_id = *parent_id;
1574 args.self_id = self_id;
1575 if ((resp = WCALLIT(ni, _ni_destroy_2, &args)) == NULL) {
1576 clnt_debug(ni, "_ni_destroy");
1577 return (NI_FAILED);
1578 }
1579 if (resp->status == NI_OK) {
1580 *parent_id = resp->ni_id_res_u.id;
1581 }
1582 return (resp->status);
1583 }
1584
1585
1586 ni_status
1587 ni_write(
1588 void *ni,
1589 ni_id *self_id,
1590 ni_proplist pl
1591 )
1592 {
1593 ni_proplist_stuff args;
1594 ni_id_res *resp;
1595
1596 args.id = *self_id;
1597 args.props = pl;
1598 if ((resp = WCALLIT(ni, _ni_write_2, &args)) == NULL) {
1599 clnt_debug(ni, "_ni_write");
1600 return (NI_FAILED);
1601 }
1602 if (resp->status == NI_OK) {
1603 *self_id = resp->ni_id_res_u.id;
1604 }
1605 return (resp->status);
1606 }
1607
1608
1609 ni_status
1610 ni_read(
1611 void *ni,
1612 ni_id *self_id,
1613 ni_proplist *pl
1614 )
1615 {
1616 ni_proplist_res *resp;
1617
1618 if ((resp = RCALLIT(ni, _ni_read_2, self_id)) == NULL) {
1619 clnt_debug(ni, "_ni_read");
1620 return (NI_FAILED);
1621 }
1622 if (resp->status == NI_OK) {
1623 *self_id = resp->ni_proplist_res_u.stuff.id;
1624 *pl = resp->ni_proplist_res_u.stuff.props;
1625 }
1626 return (resp->status);
1627 }
1628
1629
1630 ni_status
1631 ni_lookup(
1632 void *ni,
1633 ni_id *id,
1634 ni_name_const pname,
1635 ni_name_const pval,
1636 ni_idlist *hits
1637 )
1638 {
1639 ni_lookup_res *resp;
1640 ni_lookup_args args;
1641
1642 args.id = *id;
1643 args.key = (ni_name)pname;
1644 args.value = (ni_name)pval;
1645 if ((resp = RCALLIT(ni, _ni_lookup_2, &args)) == NULL) {
1646 clnt_debug(ni, "_ni_lookup");
1647 return (NI_FAILED);
1648 }
1649 if (resp->status == NI_OK) {
1650 *hits = resp->ni_lookup_res_u.stuff.idlist;
1651 *id = resp->ni_lookup_res_u.stuff.self_id;
1652 }
1653 return (resp->status);
1654 }
1655
1656
1657 ni_status
1658 ni_lookupread(
1659 void *ni,
1660 ni_id *id,
1661 ni_name_const pname,
1662 ni_name_const pval,
1663 ni_proplist *props
1664 )
1665 {
1666 ni_proplist_res *resp;
1667 ni_lookup_args args;
1668
1669 args.id = *id;
1670 args.key = (ni_name)pname;
1671 args.value = (ni_name)pval;
1672 if ((resp = RCALLIT(ni, _ni_lookupread_2, &args)) == NULL) {
1673 clnt_debug(ni, "_ni_lookupread");
1674 return (NI_FAILED);
1675 }
1676 if (resp->status == NI_OK) {
1677 *props = resp->ni_proplist_res_u.stuff.props;
1678 *id = resp->ni_proplist_res_u.stuff.id;
1679 }
1680 return (resp->status);
1681 }
1682
1683
1684 ni_status
1685 ni_list(
1686 void *ni,
1687 ni_id *id,
1688 ni_name_const pname,
1689 ni_entrylist *entries
1690 )
1691 {
1692 ni_list_res *resp;
1693 ni_name_args args;
1694
1695 args.id = *id;
1696 args.name = (ni_name)pname;
1697 if ((resp = RCALLIT(ni, _ni_list_2, &args)) == NULL) {
1698 clnt_debug(ni, "_ni_list");
1699 return (NI_FAILED);
1700 }
1701 if (resp->status == NI_OK) {
1702 *entries = resp->ni_list_res_u.stuff.entries;
1703 *id = resp->ni_list_res_u.stuff.self_id;
1704 }
1705 return (resp->status);
1706 }
1707
1708
1709 ni_status
1710 ni_listall(
1711 void *ni,
1712 ni_id *id,
1713 ni_proplist_list *entries
1714 )
1715 {
1716 ni_listall_res *resp;
1717
1718 if ((resp = RCALLIT(ni, _ni_listall_2, id)) == NULL) {
1719 clnt_debug(ni, "_ni_listall");
1720 return (NI_FAILED);
1721 }
1722 if (resp->status == NI_OK) {
1723 *entries = resp->ni_listall_res_u.stuff.entries;
1724 *id = resp->ni_listall_res_u.stuff.self_id;
1725 }
1726 return (resp->status);
1727 }
1728
1729
1730 ni_status
1731 ni_readprop(
1732 void *ni,
1733 ni_id *id,
1734 ni_index which,
1735 ni_namelist *propval_p
1736 )
1737 {
1738 ni_namelist_res *resp;
1739 ni_prop_args args;
1740
1741 args.id = *id;
1742 args.prop_index = which;
1743 if ((resp = RCALLIT(ni, _ni_readprop_2, &args)) == NULL) {
1744 clnt_debug(ni, "_ni_readprop");
1745 return (NI_FAILED);
1746 }
1747 if (resp->status == NI_OK) {
1748 *propval_p = resp->ni_namelist_res_u.stuff.values;
1749 *id = resp->ni_namelist_res_u.stuff.self_id;
1750 }
1751 return (resp->status);
1752 }
1753
1754
1755 ni_status
1756 ni_writeprop(
1757 void *ni,
1758 ni_id *id,
1759 ni_index which,
1760 ni_namelist propval
1761 )
1762 {
1763 ni_id_res *resp;
1764 ni_writeprop_args args;
1765
1766 args.id = *id;
1767 args.prop_index = which;
1768 args.values = propval;
1769 if ((resp = WCALLIT(ni, _ni_writeprop_2, &args)) == NULL) {
1770 clnt_debug(ni, "_ni_writeprop");
1771 return (NI_FAILED);
1772 }
1773 if (resp->status == NI_OK) {
1774 *id = resp->ni_id_res_u.id;
1775 }
1776 return (resp->status);
1777 }
1778
1779
1780 ni_status
1781 ni_listprops(
1782 void *ni,
1783 ni_id *id,
1784 ni_namelist *propnames
1785 )
1786 {
1787 ni_namelist_res *resp;
1788
1789 if ((resp = RCALLIT(ni, _ni_listprops_2, id)) == NULL) {
1790 clnt_debug(ni, "_ni_listprops");
1791 return (NI_FAILED);
1792 }
1793 if (resp->status == NI_OK) {
1794 *propnames = resp->ni_namelist_res_u.stuff.values;
1795 *id = resp->ni_namelist_res_u.stuff.self_id;
1796 }
1797 return (resp->status);
1798 }
1799
1800
1801 ni_status
1802 ni_createprop(
1803 void *ni,
1804 ni_id *id,
1805 ni_property prop,
1806 ni_index where
1807 )
1808 {
1809 ni_id_res *resp;
1810 ni_createprop_args args;
1811
1812 args.id = *id;
1813 args.prop = prop;
1814 args.where = where;
1815 if ((resp = WCALLIT(ni, _ni_createprop_2, &args)) == NULL) {
1816 clnt_debug(ni, "_ni_createprop");
1817 return (NI_FAILED);
1818 }
1819 if (resp->status == NI_OK) {
1820 *id = resp->ni_id_res_u.id;
1821 }
1822 return (resp->status);
1823 }
1824
1825
1826 ni_status
1827 ni_destroyprop(
1828 void *ni,
1829 ni_id *id,
1830 ni_index which
1831 )
1832 {
1833 ni_id_res *resp;
1834 ni_prop_args args;
1835
1836 args.id = *id;
1837 args.prop_index = which;
1838 if ((resp = WCALLIT(ni, _ni_destroyprop_2, &args)) == NULL) {
1839 clnt_debug(ni, "_ni_destroyprop");
1840 return (NI_FAILED);
1841 }
1842 if (resp->status == NI_OK) {
1843 *id = resp->ni_id_res_u.id;
1844 }
1845 return (resp->status);
1846 }
1847
1848
1849 ni_status
1850 ni_renameprop(
1851 void *ni,
1852 ni_id *id,
1853 ni_index prop_index,
1854 ni_name_const name
1855 )
1856 {
1857 ni_id_res *resp;
1858 ni_propname_args args;
1859
1860 args.id = *id;
1861 args.prop_index = prop_index;
1862 args.name = (ni_name)name;
1863 if ((resp = WCALLIT(ni, _ni_renameprop_2, &args)) == NULL) {
1864 clnt_debug(ni, "_ni_renameprop");
1865 return (NI_FAILED);
1866 }
1867 if (resp->status == NI_OK) {
1868 *id = resp->ni_id_res_u.id;
1869 }
1870 return (resp->status);
1871 }
1872
1873
1874 ni_status
1875 ni_createname(
1876 void *ni,
1877 ni_id *id,
1878 ni_index prop_index,
1879 ni_name_const name,
1880 ni_index where
1881 )
1882 {
1883 ni_id_res *resp;
1884 ni_createname_args args;
1885
1886 args.id = *id;
1887 args.prop_index = prop_index;
1888 args.name = (ni_name)name;
1889 args.where = where;
1890 if ((resp = WCALLIT(ni, _ni_createname_2, &args)) == NULL) {
1891 clnt_debug(ni, "_ni_createname");
1892 return (NI_FAILED);
1893 }
1894 if (resp->status == NI_OK) {
1895 *id = resp->ni_id_res_u.id;
1896 }
1897 return (resp->status);
1898 }
1899
1900
1901 ni_status
1902 ni_destroyname(
1903 void *ni,
1904 ni_id *id,
1905 ni_index prop_index,
1906 ni_index name_index
1907 )
1908 {
1909 ni_id_res *resp;
1910 ni_nameindex_args args;
1911
1912 args.id = *id;
1913 args.prop_index = prop_index;
1914 args.name_index = name_index;
1915 if ((resp = WCALLIT(ni, _ni_destroyname_2, &args)) == NULL) {
1916 clnt_debug(ni, "_ni_destroyname");
1917 return (NI_FAILED);
1918 }
1919 if (resp->status == NI_OK) {
1920 *id = resp->ni_id_res_u.id;
1921 }
1922 return (resp->status);
1923 }
1924
1925
1926 ni_status
1927 ni_writename(
1928 void *ni,
1929 ni_id *id,
1930 ni_index prop_index,
1931 ni_index name_index,
1932 ni_name_const name
1933 )
1934 {
1935 ni_id_res *resp;
1936 ni_writename_args args;
1937
1938 args.id = *id;
1939 args.prop_index = prop_index;
1940 args.name_index = name_index;
1941 args.name = (ni_name)name;
1942 if ((resp = WCALLIT(ni, _ni_writename_2, &args)) == NULL) {
1943 clnt_debug(ni, "_ni_writename");
1944 return (NI_FAILED);
1945 }
1946 if (resp->status == NI_OK) {
1947 *id = resp->ni_id_res_u.id;
1948 }
1949 return (resp->status);
1950 }
1951
1952
1953 ni_status
1954 ni_readname(
1955 void *ni,
1956 ni_id *id,
1957 ni_index prop_index,
1958 ni_index name_index,
1959 ni_name *name
1960 )
1961 {
1962 ni_readname_res *resp;
1963 ni_nameindex_args args;
1964
1965 args.id = *id;
1966 args.prop_index = prop_index;
1967 args.name_index = name_index;
1968 if ((resp = RCALLIT(ni, _ni_readname_2, &args)) == NULL) {
1969 clnt_debug(ni, "_ni_readname");
1970 return (NI_FAILED);
1971 }
1972 if (resp->status == NI_OK) {
1973 *id = resp->ni_readname_res_u.stuff.id;
1974 *name = resp->ni_readname_res_u.stuff.name;
1975 }
1976 return (resp->status);
1977 }
1978
1979
1980 ni_status
1981 ni_resync(
1982 void *ni
1983 )
1984 {
1985 ni_status *resp;
1986
1987 if ((resp = (ni_status *)RCALLIT(ni, _ni_resync_2, NULL)) == NULL) {
1988 return (NI_FAILED);
1989 }
1990 return (*resp);
1991 }
1992
1993
1994 ni_status
1995 ni_setuser(
1996 void *ni,
1997 ni_name_const user
1998 )
1999 {
2000 ni_id id;
2001 ni_idlist ids;
2002 ni_namelist nl;
2003 char *p;
2004
2005 if (user == NULL) {
2006 NIP(ni)->uid = getuid();
2007 return (ni_setpassword(ni, NULL));
2008 }
2009
2010 if (ni_root(ni, &id) != NI_OK) {
2011 return(NI_NOUSER);
2012 }
2013 NI_INIT(&ids);
2014 if (ni_lookup(ni, &id, NAME_NAME, NAME_USERS, &ids) != NI_OK) {
2015 return (NI_NOUSER);
2016 }
2017 id.nii_object = ids.niil_val[0];
2018 ni_idlist_free(&ids);
2019
2020 NI_INIT(&ids);
2021 if (ni_lookup(ni, &id, NAME_NAME, user, &ids) != NI_OK) {
2022 return (NI_NOUSER);
2023 }
2024 id.nii_object = ids.niil_val[0];
2025 ni_idlist_free(&ids);
2026 NI_INIT(&nl);
2027 if (ni_lookupprop(ni, &id, NAME_UID, &nl) != NI_OK) {
2028 return (NI_NOUSER);
2029 }
2030 if (nl.ninl_len == 0) {
2031 return (NI_NOUSER);
2032 }
2033 for (p = nl.ninl_val[0]; *p; p++) {
2034 if (!isdigit(*p)) {
2035 ni_namelist_free(&nl);
2036 return (NI_NOUSER);
2037 }
2038 }
2039 NIP(ni)->uid = atoi(nl.ninl_val[0]);
2040 if (NIP(ni)->passwd == NULL) {
2041 NIP(ni)->passwd = ni_name_dup("");
2042 }
2043 createauth(NIP(ni));
2044 return (NI_OK);
2045 }
2046
2047
2048 ni_status
2049 ni_setpassword(
2050 void *ni,
2051 ni_name_const passwd
2052 )
2053 {
2054 char *p;
2055
2056 if (NIP(ni)->passwd != NULL) {
2057 ni_name_free(&NIP(ni)->passwd);
2058 }
2059 if (passwd == NULL) {
2060 NIP(ni)->passwd = NULL;
2061 if (NIP(ni)->tc != NULL) {
2062 auth_destroy(NIP(ni)->tc->cl_auth);
2063 NIP(ni)->tc->cl_auth = authnone_create();
2064 }
2065 return (NI_OK);
2066 }
2067 NIP(ni)->passwd = ni_name_dup(passwd);
2068 /*
2069 * Our trivial encryption scheme
2070 */
2071 for (p = NIP(ni)->passwd; *p; p++) {
2072 *p = ~(*p);
2073 }
2074 createauth(NIP(ni));
2075 return (NI_OK);
2076 }
2077
2078
2079 extern int bindresvport(int, struct sockaddr_in *);
2080
2081
2082 /*
2083 * NeXT note:
2084 * The procedure pmap_getport_to below is derived
2085 * from Sun Microsystems RPC source code. As such the following
2086 * statement applies to it.:
2087 *
2088 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
2089 * unrestricted use provided that this legend is included on all tape
2090 * media and as a part of the software program in whole or part. Users
2091 * may copy or modify Sun RPC without charge, but are not authorized
2092 * to license or distribute it to anyone else except as part of a product or
2093 * program developed by the user.
2094 *
2095 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
2096 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
2097 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
2098 *
2099 * Sun RPC is provided with no support and without any obligation on the
2100 * part of Sun Microsystems, Inc. to assist in its use, correction,
2101 * modification or enhancement.
2102 *
2103 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2104 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2105 * OR ANY PART THEREOF.
2106 *
2107 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2108 * or profits or other special, indirect and consequential damages, even if
2109 * Sun has been advised of the possibility of such damages.
2110 *
2111 * Sun Microsystems, Inc.
2112 * 2550 Garcia Avenue
2113 * Mountain View, California 94043
2114 */
2115 /*
2116 * Client interface to pmap rpc service.
2117 *
2118 * Find the mapped port for program,version.
2119 * Calls the pmap service remotely to do the lookup.
2120 * Returns 0 if no map exists.
2121 */
2122 static u_short
2123 pmap_getport_to(address, program, version, protocol, timeout_secs, ntries)
2124 struct sockaddr_in *address;
2125 u_long program;
2126 u_long version;
2127 u_int protocol;
2128 int timeout_secs;
2129 int ntries;
2130 {
2131 u_short port = 0;
2132 int sock = -1;
2133 register CLIENT *client;
2134 struct pmap parms;
2135 struct timeval timeout;
2136
2137 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2138 if (sock < 0) {
2139 return (0);
2140 }
2141 address->sin_port = htons(PMAPPORT);
2142 timeout.tv_usec = ((timeout_secs % ntries) * 1000000) / ntries;
2143 timeout.tv_sec = (timeout_secs / ntries);
2144 client = clntudp_bufcreate(address, PMAPPROG,
2145 PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
2146 if (client != (CLIENT *)NULL) {
2147 parms.pm_prog = program;
2148 parms.pm_vers = version;
2149 parms.pm_prot = protocol;
2150 parms.pm_port = 0; /* not needed or used */
2151 timeout.tv_usec = 0;
2152 timeout.tv_sec = timeout_secs;
2153 if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms,
2154 xdr_u_short, &port, timeout) != RPC_SUCCESS){
2155 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
2156 clnt_geterr(client, &rpc_createerr.cf_error);
2157 port = 0;
2158 } else if (port == 0) {
2159 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
2160 }
2161 }
2162 if (client != NULL) {
2163 clnt_destroy(client);
2164 }
2165 (void)close(sock);
2166 address->sin_port = 0;
2167 return (port);
2168 }
2169
2170
2171 /*
2172 * Open a socket, but do not use the default portmap timeout
2173 */
2174 static int
2175 socket_open(
2176 struct sockaddr_in *raddr,
2177 int prog,
2178 int vers,
2179 int timeout,
2180 int ntries,
2181 int proto
2182 )
2183 {
2184 struct sockaddr_in bindsin;
2185 int sock;
2186 int reuse = 1;
2187
2188 memset(&bindsin, 0, sizeof(bindsin));
2189
2190 /*
2191 * If no port number given ask the pmap for one
2192 */
2193 if (raddr->sin_port == 0) {
2194 u_short port;
2195 if ((port = pmap_getport_to(raddr, prog, vers,
2196 IPPROTO_UDP, timeout,
2197 ntries)) == 0) {
2198 return (-1);
2199 }
2200 raddr->sin_port = htons(port);
2201 }
2202
2203 sock = socket(AF_INET, proto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM,
2204 proto);
2205 if (sock < 0) {
2206 return (-1);
2207 }
2208 if (-1 == bindresvport(sock, NULL) && errno == EADDRNOTAVAIL) {
2209 /* XXX - we're hitting this case way too often under load */
2210 /* fail gracefully: some address is better than none most of the time */
2211 syslog(LOG_DEBUG, "Libinfo[%s():%d] bindresvport(): %m", __func__, __LINE__);
2212 if (-1 == bind(sock, &bindsin, sizeof(bindsin))) {
2213 /* The system is really sad now if it can't give me any address... */
2214 syslog(LOG_DEBUG, "Libinfo[%s():%d] bind(): %m", __func__, __LINE__);
2215 (void)close(sock);
2216 return -1;
2217 }
2218 }
2219 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int));
2220 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
2221 if (proto == IPPROTO_TCP) {
2222 if (connect(sock, (struct sockaddr *)raddr,
2223 sizeof(*raddr)) < 0) {
2224 syslog(LOG_DEBUG, "Libinfo[%s():%d] connect(): %m", __func__, __LINE__);
2225 (void)close(sock);
2226 return (-1);
2227 }
2228 }
2229 return (sock);
2230 }