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