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