]> git.saurik.com Git - apple/libinfo.git/blob - netinfo.subproj/ni_glue.c
Libinfo-89.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 <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 NI_INIT(&nl);
726 if (ni_lookupprop(ni, &root, NAME_MASTER, &nl) != NI_OK) {
727 ni->needwrite = needwrite;
728 return (0);
729 }
730 if (nl.ninl_len == 0) {
731 ni->needwrite = needwrite;
732 return (0);
733 }
734 sep = index(nl.ninl_val[0], '/');
735 if (sep == NULL) {
736 ni->needwrite = needwrite;
737 return (0);
738 }
739 *sep++ = 0;
740 master = nl.ninl_val[0];
741 NI_INIT(&idl);
742 if (ni_lookup(ni, &root, NAME_NAME, NAME_MACHINES, &idl) != NI_OK) {
743 ni->needwrite = needwrite;
744 ni_namelist_free(&nl);
745 return (0);
746 }
747 if (idl.niil_len < 1) {
748 ni->needwrite = needwrite;
749 return (0);
750 }
751 id.nii_object = idl.niil_val[0];
752 ni_idlist_free(&idl);
753 NI_INIT(&idl);
754 if (ni_lookup(ni, &id, NAME_NAME, master, &idl) != NI_OK) {
755 ni_namelist_free(&nl);
756 ni->needwrite = needwrite;
757 return (0);
758 }
759 ni_namelist_free(&nl);
760 if (idl.niil_len < 1) {
761 ni->needwrite = needwrite;
762 return (0);
763 }
764 id.nii_object = idl.niil_val[0];
765 ni_idlist_free(&idl);
766 NI_INIT(&nl);
767 if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) {
768 return (0);
769 }
770 for (i = 0; i < nl.ninl_len; i++) {
771 addr.s_addr = inet_addr(nl.ninl_val[i]);
772 for (j = 0; j < ni->naddrs; j++) {
773 if (addr.s_addr == ni->addrs[j].s_addr) {
774 ni->whichwrite = j;
775 ni_namelist_free(&nl);
776 ni->needwrite = needwrite;
777 return (1);
778 }
779 }
780 }
781 ni->needwrite = needwrite;
782 ni_namelist_free(&nl);
783 return (0);
784 }
785
786
787 static void *
788 callit(
789 ni_private *ni,
790 void *(*stub)(),
791 void *args,
792 int needwrite
793 )
794 {
795 void *resp;
796 struct rpc_err err;
797 int i;
798 int sleeptime = 0;
799 int printed = 0;
800
801 if (getpid() != ni->pid) {
802 reinit(ni);
803 }
804 if (needwrite || ni->needwrite) {
805 if (ni->whichwrite >= 0) {
806 ni_switch(ni, ni->whichwrite);
807 } else {
808 if (!setmaster(ni)) {
809 return (NULL);
810 }
811 ni_switch(ni, ni->whichwrite);
812 }
813 if (!needwrite) {
814 ni_settimeout(ni, (ni->rtv_sec == 0 ?
815 NI_TIMEOUT_SHORT : ni->rtv_sec));
816 needwrite = 1;
817 } else {
818 ni_settimeout(ni, (ni->wtv_sec == 0 ?
819 NI_TIMEOUT_LONG : ni->wtv_sec));
820 }
821 } else {
822 ni_settimeout(ni, (ni->rtv_sec == 0 ?
823 NI_TIMEOUT_SHORT : ni->rtv_sec));
824 }
825 for (;;) {
826 /*
827 * Try more than once, in case server closed connection.
828 */
829 for (i = 0; i < NI_MAXCONNTRIES; i++) {
830 if (!confirm_tcp(ni, needwrite)) {
831 break;
832 }
833 if ((resp = (*stub)(args, ni->tc)) != NULL) {
834 if (printed) {
835 syslog(LOG_ERR, "NetInfo connected to %s/%s",
836 inet_ntoa(ni->addrs[0]), ni->tags[0]);
837 }
838 return (resp);
839 }
840 clnt_geterr(ni->tc, &err);
841 if (err.re_status != RPC_CANTRECV) {
842 break;
843 }
844 if (i + 1 < NI_MAXCONNTRIES) {
845 /*
846 * Server closed connection. Reinit and try
847 * again.
848 */
849 reinit(ni);
850 }
851 }
852 if (err.re_status == RPC_PROCUNAVAIL) {
853 return (NULL);
854 }
855 if (needwrite || ni->abort) {
856 /*
857 * We time out for writes or if it is explicitly
858 * requested.
859 */
860 if (ni->abort) {
861 reinit(ni);
862 }
863 syslog(LOG_ERR,
864 "NetInfo connection failed for server %s/%s",
865 inet_ntoa(ni->addrs[0]), ni->tags[0]);
866 return (NULL);
867 }
868 if (!printed) {
869 if (ni->tc != NULL) {
870 if (!(sleeptime == 0 &&
871 err.re_status == RPC_TIMEDOUT)) {
872 /*
873 * Do not print message on
874 * first timeout. It is likely
875 * we will find another server soon.
876 * Let's not needlessly alarm the
877 * poor user!
878 */
879 syslog(LOG_ERR, "%s on connection to %s/%s",
880 clnt_sperror(ni->tc,"NetInfo connection timeout"),
881 inet_ntoa(ni->addrs[0]), ni->tags[0]);
882 printed++;
883 }
884 else {
885 /* first attempt failed */
886 syslog(LOG_ERR, "%s on initial connection to %s/%s",
887 clnt_sperror(ni->tc,"NetInfo connection timeout"),
888 inet_ntoa(ni->addrs[0]), ni->tags[0]);
889 }
890 } else {
891 syslog(LOG_ERR,
892 "NetInfo connection failed for server %s/%s",
893 inet_ntoa(ni->addrs[0]), ni->tags[0]);
894 printed++;
895 }
896 }
897 if (sleeptime > 0) {
898 sleep(sleeptime);
899 if (sleeptime < NI_MAXSLEEPTIME) {
900 sleeptime *= 2; /* backoff */
901 }
902 } else {
903 /*
904 * Do not sleep on the first timeout.
905 * It is likely we will find another server quickly.
906 */
907 sleeptime = NI_SLEEPTIME;
908 }
909 reinit(ni);
910 (void)rebind(ni);
911 }
912 }
913
914
915 #define RCALLIT(a, b, c) callit((ni_private *)(a), (void *(*)())(b), \
916 (void *)c, 0)
917
918
919 #define WCALLIT(a, b, c) callit((ni_private *)(a), (void *(*)())(b), \
920 (void *)c, 1)
921
922
923 static void
924 ni_clear(
925 ni_private *ni
926 )
927 {
928 ni->needwrite = 0;
929 ni->naddrs = 0;
930 ni->addrs = NULL;
931 ni->tags = NULL;
932 ni->tc = NULL;
933 ni->tsock = -1;
934 ni->tport = -1;
935 ni->whichwrite = -1;
936 ni->passwd = NULL;
937 }
938
939
940 static void *
941 ni_alloc(
942 void
943 )
944 {
945 ni_private *ni;
946
947 ni = (ni_private *)malloc(sizeof(*ni));
948 ni->naddrs = 0;
949 ni->whichwrite = -1;
950 ni->pid = getpid();
951 ni->tsock = -1;
952 ni->tport = -1;
953 ni->tc = NULL;
954 ni->tv_sec = NI_TIMEOUT_SHORT;
955 ni->rtv_sec = 0;
956 ni->wtv_sec = 0;
957 ni->abort = 0;
958 ni->passwd = NULL;
959 ni->uid = getuid();
960 ni->needwrite = 0;
961 return ((void *)ni);
962 }
963
964
965 void *
966 _ni_dup(
967 void *ni
968 )
969 {
970 ni_private *dupni;
971 ni_index i;
972
973 dupni = (ni_private *)ni_alloc();
974 *dupni = *NIP(ni);
975 ni_clear(dupni);
976 dupni->naddrs = NIP(ni)->naddrs;
977 dupni->whichwrite = NIP(ni)->whichwrite;
978 if (dupni->naddrs > 0) {
979 dupni->addrs = ((struct in_addr *)
980 malloc(NIP(ni)->naddrs * sizeof(struct in_addr)));
981 bcopy(NIP(ni)->addrs, dupni->addrs,
982 NIP(ni)->naddrs * sizeof(struct in_addr));
983 dupni->tags = ((ni_name *)
984 malloc(NIP(ni)->naddrs * sizeof(ni_name)));
985 for (i = 0; i < NIP(ni)->naddrs; i++) {
986 dupni->tags[i] = ni_name_dup(NIP(ni)->tags[i]);
987 }
988 }
989 if (NIP(ni)->passwd != NULL) {
990 dupni->passwd = ni_name_dup(NIP(ni)->passwd);
991 }
992 return ((void *)dupni);
993 }
994
995
996 static int
997 match(
998 ni_name domain,
999 ni_name domtag,
1000 ni_name *tag
1001 )
1002 {
1003 int len = strlen(domain);
1004 ni_name sep;
1005
1006 sep = index(domtag, '/');
1007 if (sep == NULL) {
1008 return (0);
1009 }
1010 if (strncmp(domain, domtag, len) == 0 &&
1011 domtag[len] == '/') {
1012 *tag = ni_name_dup(sep + 1);
1013 return (1);
1014 }
1015 return (0);
1016 }
1017
1018
1019 static int
1020 addaddr(
1021 void *ni,
1022 ni_index ido,
1023 ni_name tag,
1024 ni_private *target_ni
1025 )
1026 {
1027 ni_id id;
1028 ni_namelist nl;
1029 struct in_addr addr;
1030 int i;
1031
1032 id.nii_object = ido;
1033 NI_INIT(&nl);
1034 if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) {
1035 return (0);
1036 }
1037 if (nl.ninl_len == 0) {
1038 return(0);
1039 }
1040
1041 if (target_ni->naddrs == 0) {
1042 target_ni->addrs =
1043 (struct in_addr *)malloc(nl.ninl_len * sizeof(struct in_addr));
1044 target_ni->tags =
1045 (ni_name *)malloc(nl.ninl_len * sizeof(ni_name));
1046 } else {
1047 target_ni->addrs =
1048 (struct in_addr *)realloc(target_ni->addrs,
1049 ((target_ni->naddrs + nl.ninl_len) * sizeof(struct in_addr)));
1050 target_ni->tags =
1051 (ni_name *)realloc(target_ni->tags,
1052 ((target_ni->naddrs + nl.ninl_len) * sizeof(ni_name)));
1053 }
1054
1055 for (i=0; i<nl.ninl_len; i++) {
1056 addr.s_addr = inet_addr(nl.ninl_val[i]);
1057 target_ni->addrs[target_ni->naddrs] = addr;
1058 target_ni->tags[target_ni->naddrs] = ni_name_dup(tag);
1059 target_ni->naddrs++;
1060 }
1061
1062 ni_namelist_free(&nl);
1063 return (1);
1064 }
1065
1066
1067 static int
1068 get_daddr(
1069 ni_private *ni,
1070 ni_name dom,
1071 ni_private *target_ni
1072 )
1073 {
1074 ni_id id;
1075 ni_idlist ids;
1076 ni_namelist nl;
1077 ni_entrylist entries;
1078 ni_index i;
1079 ni_index j;
1080 ni_name tag;
1081
1082 if (ni_root(ni, &id) != NI_OK) {
1083 return(0);
1084 }
1085
1086 NI_INIT(&ids);
1087 if (ni_lookup(ni, &id, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) {
1088 return (0);
1089 }
1090
1091 id.nii_object = ids.niil_val[0];
1092 ni_idlist_free(&ids);
1093
1094 NI_INIT(&entries);
1095 if (ni_list(ni, &id, NAME_SERVES, &entries) != NI_OK) {
1096 return (0);
1097 }
1098
1099 for (i = 0; i < entries.niel_len; i++) {
1100 if (entries.niel_val[i].names != NULL) {
1101 nl = *entries.niel_val[i].names;
1102 for (j = 0; j < nl.ninl_len; j++) {
1103 if (match(dom, nl.ninl_val[j], &tag)) {
1104 if (addaddr(ni,
1105 entries.niel_val[i].id,
1106 tag,
1107 target_ni)) {
1108 ni_name_free(&tag);
1109 break;
1110 }
1111 ni_name_free(&tag);
1112 }
1113 }
1114 }
1115
1116 }
1117 ni_entrylist_free(&entries);
1118 return (target_ni->naddrs > 0);
1119 }
1120
1121
1122 #ifdef notdef
1123 static int
1124 get_haddr(
1125 ni_private *ni,
1126 ni_name hname,
1127 ni_name tag,
1128 ni_private *target_ni
1129 )
1130 {
1131 ni_id id;
1132 ni_idlist ids;
1133
1134 if (ni_root(ni, &id) != NI_OK) {
1135 return(0);
1136 }
1137 NI_INIT(&ids);
1138 if (ni_lookup(ni, &id, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) {
1139 return (0);
1140 }
1141 id.nii_object = ids.niil_val[0];
1142 ni_idlist_free(&ids);
1143
1144 NI_INIT(&ids);
1145 if (ni_lookup(ni, &id, NAME_NAME, hname, &ids) != NI_OK) {
1146 return (0);
1147 }
1148 id.nii_object = ids.niil_val[0];
1149 ni_idlist_free(&ids);
1150 if (!addaddr(ni, id.nii_object, tag, target_ni)) {
1151 return (0);
1152 }
1153 return (1);
1154 }
1155 #endif
1156
1157
1158 static ni_status
1159 getparent(ni_private *oldni, ni_private **newni)
1160 {
1161 ni_rparent_res *resp;
1162 ni_private *ni;
1163 ni_private *dupni;
1164 int found;
1165 ni_index i;
1166 struct in_addr raddr;
1167 int printed = 0;
1168 int inlist = 0;
1169
1170 found = 0;
1171 while (!found) {
1172 /*
1173 * First, find our parent, any parent
1174 */
1175 for (;;) {
1176 resp = RCALLIT(oldni, _ni_rparent_2, NULL);
1177 if (resp == NULL) {
1178 return (NI_FAILED);
1179 }
1180 if (resp->status != NI_NORESPONSE) {
1181 break;
1182 }
1183 if (!printed) {
1184 syslog(LOG_ERR, "NetInfo timeout finding server for parent of %s/%s, sleeping",
1185 inet_ntoa(oldni->addrs[0]), oldni->tags[0]);
1186 printed++;
1187 }
1188 sleep(NI_SLEEPTIME);
1189 }
1190 if (printed) {
1191 raddr.s_addr = htonl(resp->ni_rparent_res_u.binding.addr);
1192
1193 syslog(LOG_ERR, "NetInfo %s/%s found parent %s/%s",
1194 inet_ntoa(oldni->addrs[0]), oldni->tags[0],
1195 inet_ntoa(raddr), resp->ni_rparent_res_u.binding.tag);
1196 }
1197 if (resp->status != NI_OK) {
1198 return (resp->status);
1199 }
1200 ni = ni_alloc();
1201 *ni = *oldni;
1202 ni_clear(ni);
1203 ni->naddrs = 1;
1204 ni->addrs = (struct in_addr *)malloc(sizeof(struct in_addr));
1205 ni->addrs[0].s_addr=htonl(resp->ni_rparent_res_u.binding.addr);
1206 ni->tags = (ni_name *)malloc(sizeof(ni_name));
1207 ni->tags[0] = ni_name_dup(resp->ni_rparent_res_u.binding.tag);
1208
1209 xdr_free(xdr_ni_rparent_res, resp);
1210
1211 dupni = ni;
1212 ni = ni_alloc();
1213 *ni = *dupni;
1214 ni_clear(ni);
1215 if (get_daddr(dupni, ".", ni)) {
1216
1217 /*
1218 * Now make sure returned parent is head of
1219 * list
1220 */
1221 for (i = 0; i < ni->naddrs; i++) {
1222 if (ni->addrs[i].s_addr ==
1223 dupni->addrs[0].s_addr) {
1224 ni_switch(ni, i);
1225 inlist++;
1226 break;
1227 }
1228 }
1229
1230 /*
1231 * Reuse dupni client info
1232 */
1233 ni->tsock = dupni->tsock;
1234 ni->tport = dupni->tport;
1235 ni->tc = dupni->tc;
1236 dupni->tsock = -1;
1237 dupni->tport = -1;
1238 dupni->tc = NULL;
1239 found++;
1240
1241 /*
1242 * If returned parent wasn't in list, it's a rogue.
1243 * Log an error and drop the connection.
1244 */
1245 if (inlist == 0) {
1246 syslog(LOG_ERR, "Rogue NetInfo server detected: %s/%s",
1247 inet_ntoa(dupni->addrs[0]), dupni->tags[0]);
1248 reinit(ni);
1249 }
1250
1251 }
1252 ni_free(dupni);
1253 }
1254 if (found) {
1255 *newni = ni;
1256 return (NI_OK);
1257 } else {
1258 ni_free(ni);
1259 return (NI_FAILED);
1260 }
1261 }
1262
1263
1264 void *
1265 ni_connect(
1266 struct sockaddr_in *sin,
1267 const char *tag
1268 )
1269 {
1270 void *ni;
1271
1272 ni = ni_alloc();
1273 NIP(ni)->naddrs = 1;
1274 NIP(ni)->addrs = (struct in_addr *
1275 )malloc(sizeof(struct in_addr));
1276 NIP(ni)->addrs[0] = sin->sin_addr;
1277 NIP(ni)->tags = (ni_name *)malloc(sizeof(ni_name));
1278 NIP(ni)->tags[0] = ni_name_dup(tag);
1279 return (ni);
1280 }
1281
1282
1283 ni_status
1284 ni_addrtag(
1285 void *ni,
1286 struct sockaddr_in *addr,
1287 ni_name *tag
1288 )
1289 {
1290
1291 if (!confirm_tcp(ni, 0)) {
1292 return (NI_FAILED);
1293 }
1294 *tag = ni_name_dup(NIP(ni)->tags[0]);
1295 addr->sin_addr = NIP(ni)->addrs[0];
1296 addr->sin_port = htons(NIP(ni)->tport);
1297 addr->sin_family = AF_INET;
1298 bzero(addr->sin_zero, sizeof(addr->sin_zero));
1299 return (NI_OK);
1300 }
1301
1302
1303 void *
1304 ni_new(
1305 void *oldni,
1306 const char *domain
1307 )
1308 {
1309 ni_private *ni;
1310 ni_status status;
1311 ni_name sep, addr, tag;
1312 struct sockaddr_in sin;
1313 struct hostent *he;
1314
1315 if (oldni == NULL) {
1316 ni = ni_alloc();
1317 if (!connectlocal(ni)) {
1318 free(ni);
1319 return (NULL);
1320 }
1321 if (strcmp(domain, "..") == 0) {
1322 oldni = ni;
1323 status = getparent((ni_private *)oldni, &ni);
1324 ni_free(oldni);
1325 if (status != NI_OK) {
1326 return (NULL);
1327 }
1328 } else if ((sep = index(domain, '@')) != NULL) {
1329 free(ni);
1330 tag = strncpy((char *)malloc(sep-domain+1), domain, sep-domain);
1331 tag[sep-domain] = '\0';
1332 addr = strcpy ((char *)malloc(strlen(sep+1)), sep+1);
1333 sin.sin_addr.s_addr = inet_addr(addr);
1334 if (sin.sin_addr.s_addr == INADDR_NONE) {
1335 he = gethostbyname(addr);
1336 if (he == NULL) {
1337 free(addr);
1338 free(tag);
1339 return (NULL);
1340 }
1341 bcopy(he->h_addr_list[0], &sin.sin_addr.s_addr, he->h_length);
1342 }
1343 ni = ni_connect(&sin, tag);
1344 free(addr);
1345 free(tag);
1346 } else if (strcmp(domain, ".") != 0) {
1347 /*
1348 * nothing else makes sense
1349 */
1350 free(ni);
1351 return (NULL);
1352 }
1353 } else {
1354 if (strcmp(domain, "..") == 0) {
1355 status = getparent((ni_private *)oldni, &ni);
1356 if (status != NI_OK) {
1357 return (NULL);
1358 }
1359 } else if ((sep = index(domain, '@')) != NULL) {
1360 tag = strncpy((char *)malloc(sep-domain+1), domain, sep-domain);
1361 tag[sep-domain] = '\0';
1362 addr = strcpy ((char *)malloc(strlen(sep+1)), sep+1);
1363 sin.sin_addr.s_addr = inet_addr(addr);
1364 if (sin.sin_addr.s_addr == INADDR_NONE) {
1365 he = gethostbyname(addr);
1366 if (he == NULL) {
1367 free(addr);
1368 free(tag);
1369 return (NULL);
1370 }
1371 bcopy(he->h_addr_list[0], &sin.sin_addr.s_addr, he->h_length);
1372 }
1373 ni = ni_connect(&sin, tag);
1374 free(addr);
1375 free(tag);
1376 } else {
1377 ni = ni_alloc();
1378 *ni = *NIP(oldni);
1379 ni_clear(ni);
1380 if (!get_daddr(oldni, (ni_name)domain, ni)) {
1381 ni_free(ni);
1382 ni = NULL;
1383 }
1384 }
1385 }
1386 return ((void *)ni);
1387 }
1388
1389
1390 void
1391 ni_free(
1392 void *ni
1393 )
1394 {
1395 ni_index i;
1396
1397 if (NIP(ni)->tc != NULL) {
1398 clnt_kill(NIP(ni)->tc, NIP(ni)->tsock, NIP(ni)->tport);
1399 }
1400 if (NIP(ni)->naddrs > 0) {
1401 free(NIP(ni)->addrs);
1402 for (i = 0; i < NIP(ni)->naddrs; i++) {
1403 ni_name_free(&NIP(ni)->tags[i]);
1404 }
1405 free(NIP(ni)->tags);
1406 }
1407 if (NIP(ni)->passwd != NULL) {
1408 ni_name_free(&NIP(ni)->passwd);
1409 }
1410 free(ni);
1411 }
1412
1413
1414 /*
1415 * The rest of these are just wrappers that end up doing
1416 * RPC calls to the local NetInfo server.
1417 */
1418 ni_status
1419 ni_statistics(
1420 void *ni,
1421 ni_proplist *pl
1422 )
1423 {
1424 ni_proplist *resp;
1425
1426 if ((resp = (ni_proplist *)RCALLIT(ni, _ni_statistics_2, NULL))
1427 == NULL) {
1428 return (NI_FAILED);
1429 }
1430 *pl = *resp;
1431 return (NI_OK);
1432 }
1433
1434
1435 ni_status
1436 ni_root(
1437 void *ni,
1438 ni_id *id
1439 )
1440 {
1441 ni_id_res *resp;
1442
1443 if ((resp = RCALLIT(ni, _ni_root_2, id)) == NULL) {
1444 clnt_debug(ni, "_ni_root");
1445 return (NI_FAILED);
1446 }
1447 if (resp->status == NI_OK) {
1448 *id = resp->ni_id_res_u.id;
1449 }
1450 return (resp->status);
1451 }
1452
1453
1454 ni_status
1455 ni_self(
1456 void *ni,
1457 ni_id *id
1458 )
1459 {
1460 ni_id_res *resp;
1461
1462 if ((resp = RCALLIT(ni, _ni_self_2, id)) == NULL) {
1463 clnt_debug(ni, "_ni_self");
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_parent(
1475 void *ni,
1476 ni_id *id,
1477 ni_index *parent_id_p
1478 )
1479 {
1480 ni_parent_res *resp;
1481
1482 if ((resp = RCALLIT(ni, _ni_parent_2, id)) == NULL) {
1483 clnt_debug(ni, "_ni_parent");
1484 return (NI_FAILED);
1485 }
1486 if (resp->status == NI_OK) {
1487 *parent_id_p = resp->ni_parent_res_u.stuff.object_id;
1488 *id = resp->ni_parent_res_u.stuff.self_id;
1489 }
1490 return (resp->status);
1491 }
1492
1493
1494 ni_status
1495 ni_children(
1496 void *ni,
1497 ni_id *id,
1498 ni_idlist *children
1499 )
1500 {
1501 ni_children_res *resp;
1502
1503 if ((resp = RCALLIT(ni, _ni_children_2, id)) == NULL) {
1504 clnt_debug(ni, "_ni_children");
1505 return (NI_FAILED);
1506 }
1507 if (resp->status == NI_OK) {
1508 *children = resp->ni_children_res_u.stuff.children;
1509 *id = resp->ni_children_res_u.stuff.self_id;
1510 }
1511 return (resp->status);
1512 }
1513
1514
1515 ni_status
1516 ni_create(
1517 void *ni,
1518 ni_id *parent_id,
1519 ni_proplist pl,
1520 ni_id *child_id_p,
1521 ni_index where
1522 )
1523 {
1524 ni_create_args args;
1525 ni_create_res *resp;
1526
1527 args.id = *parent_id;
1528 args.props = pl;
1529 args.where = where;
1530 args.target_id = NULL;
1531 if ((resp = WCALLIT(ni, _ni_create_2, &args)) == NULL) {
1532 clnt_debug(ni, "_ni_create");
1533 return (NI_FAILED);
1534 }
1535 if (resp->status == NI_OK) {
1536 *child_id_p = resp->ni_create_res_u.stuff.id;
1537 *parent_id = resp->ni_create_res_u.stuff.self_id;
1538 }
1539 return (resp->status);
1540 }
1541
1542
1543 ni_status
1544 ni_destroy(
1545 void *ni,
1546 ni_id *parent_id,
1547 ni_id self_id
1548 )
1549 {
1550 ni_id_res *resp;
1551 ni_destroy_args args;
1552
1553 args.parent_id = *parent_id;
1554 args.self_id = self_id;
1555 if ((resp = WCALLIT(ni, _ni_destroy_2, &args)) == NULL) {
1556 clnt_debug(ni, "_ni_destroy");
1557 return (NI_FAILED);
1558 }
1559 if (resp->status == NI_OK) {
1560 *parent_id = resp->ni_id_res_u.id;
1561 }
1562 return (resp->status);
1563 }
1564
1565
1566 ni_status
1567 ni_write(
1568 void *ni,
1569 ni_id *self_id,
1570 ni_proplist pl
1571 )
1572 {
1573 ni_proplist_stuff args;
1574 ni_id_res *resp;
1575
1576 args.id = *self_id;
1577 args.props = pl;
1578 if ((resp = WCALLIT(ni, _ni_write_2, &args)) == NULL) {
1579 clnt_debug(ni, "_ni_write");
1580 return (NI_FAILED);
1581 }
1582 if (resp->status == NI_OK) {
1583 *self_id = resp->ni_id_res_u.id;
1584 }
1585 return (resp->status);
1586 }
1587
1588
1589 ni_status
1590 ni_read(
1591 void *ni,
1592 ni_id *self_id,
1593 ni_proplist *pl
1594 )
1595 {
1596 ni_proplist_res *resp;
1597
1598 if ((resp = RCALLIT(ni, _ni_read_2, self_id)) == NULL) {
1599 clnt_debug(ni, "_ni_read");
1600 return (NI_FAILED);
1601 }
1602 if (resp->status == NI_OK) {
1603 *self_id = resp->ni_proplist_res_u.stuff.id;
1604 *pl = resp->ni_proplist_res_u.stuff.props;
1605 }
1606 return (resp->status);
1607 }
1608
1609
1610 ni_status
1611 ni_lookup(
1612 void *ni,
1613 ni_id *id,
1614 ni_name_const pname,
1615 ni_name_const pval,
1616 ni_idlist *hits
1617 )
1618 {
1619 ni_lookup_res *resp;
1620 ni_lookup_args args;
1621
1622 args.id = *id;
1623 args.key = (ni_name)pname;
1624 args.value = (ni_name)pval;
1625 if ((resp = RCALLIT(ni, _ni_lookup_2, &args)) == NULL) {
1626 clnt_debug(ni, "_ni_lookup");
1627 return (NI_FAILED);
1628 }
1629 if (resp->status == NI_OK) {
1630 *hits = resp->ni_lookup_res_u.stuff.idlist;
1631 *id = resp->ni_lookup_res_u.stuff.self_id;
1632 }
1633 return (resp->status);
1634 }
1635
1636
1637 ni_status
1638 ni_lookupread(
1639 void *ni,
1640 ni_id *id,
1641 ni_name_const pname,
1642 ni_name_const pval,
1643 ni_proplist *props
1644 )
1645 {
1646 ni_proplist_res *resp;
1647 ni_lookup_args args;
1648
1649 args.id = *id;
1650 args.key = (ni_name)pname;
1651 args.value = (ni_name)pval;
1652 if ((resp = RCALLIT(ni, _ni_lookupread_2, &args)) == NULL) {
1653 clnt_debug(ni, "_ni_lookupread");
1654 return (NI_FAILED);
1655 }
1656 if (resp->status == NI_OK) {
1657 *props = resp->ni_proplist_res_u.stuff.props;
1658 *id = resp->ni_proplist_res_u.stuff.id;
1659 }
1660 return (resp->status);
1661 }
1662
1663
1664 ni_status
1665 ni_list(
1666 void *ni,
1667 ni_id *id,
1668 ni_name_const pname,
1669 ni_entrylist *entries
1670 )
1671 {
1672 ni_list_res *resp;
1673 ni_name_args args;
1674
1675 args.id = *id;
1676 args.name = (ni_name)pname;
1677 if ((resp = RCALLIT(ni, _ni_list_2, &args)) == NULL) {
1678 clnt_debug(ni, "_ni_list");
1679 return (NI_FAILED);
1680 }
1681 if (resp->status == NI_OK) {
1682 *entries = resp->ni_list_res_u.stuff.entries;
1683 *id = resp->ni_list_res_u.stuff.self_id;
1684 }
1685 return (resp->status);
1686 }
1687
1688
1689 ni_status
1690 ni_listall(
1691 void *ni,
1692 ni_id *id,
1693 ni_proplist_list *entries
1694 )
1695 {
1696 ni_listall_res *resp;
1697
1698 if ((resp = RCALLIT(ni, _ni_listall_2, id)) == NULL) {
1699 clnt_debug(ni, "_ni_listall");
1700 return (NI_FAILED);
1701 }
1702 if (resp->status == NI_OK) {
1703 *entries = resp->ni_listall_res_u.stuff.entries;
1704 *id = resp->ni_listall_res_u.stuff.self_id;
1705 }
1706 return (resp->status);
1707 }
1708
1709
1710 ni_status
1711 ni_readprop(
1712 void *ni,
1713 ni_id *id,
1714 ni_index which,
1715 ni_namelist *propval_p
1716 )
1717 {
1718 ni_namelist_res *resp;
1719 ni_prop_args args;
1720
1721 args.id = *id;
1722 args.prop_index = which;
1723 if ((resp = RCALLIT(ni, _ni_readprop_2, &args)) == NULL) {
1724 clnt_debug(ni, "_ni_readprop");
1725 return (NI_FAILED);
1726 }
1727 if (resp->status == NI_OK) {
1728 *propval_p = resp->ni_namelist_res_u.stuff.values;
1729 *id = resp->ni_namelist_res_u.stuff.self_id;
1730 }
1731 return (resp->status);
1732 }
1733
1734
1735 ni_status
1736 ni_writeprop(
1737 void *ni,
1738 ni_id *id,
1739 ni_index which,
1740 ni_namelist propval
1741 )
1742 {
1743 ni_id_res *resp;
1744 ni_writeprop_args args;
1745
1746 args.id = *id;
1747 args.prop_index = which;
1748 args.values = propval;
1749 if ((resp = WCALLIT(ni, _ni_writeprop_2, &args)) == NULL) {
1750 clnt_debug(ni, "_ni_writeprop");
1751 return (NI_FAILED);
1752 }
1753 if (resp->status == NI_OK) {
1754 *id = resp->ni_id_res_u.id;
1755 }
1756 return (resp->status);
1757 }
1758
1759
1760 ni_status
1761 ni_listprops(
1762 void *ni,
1763 ni_id *id,
1764 ni_namelist *propnames
1765 )
1766 {
1767 ni_namelist_res *resp;
1768
1769 if ((resp = RCALLIT(ni, _ni_listprops_2, id)) == NULL) {
1770 clnt_debug(ni, "_ni_listprops");
1771 return (NI_FAILED);
1772 }
1773 if (resp->status == NI_OK) {
1774 *propnames = resp->ni_namelist_res_u.stuff.values;
1775 *id = resp->ni_namelist_res_u.stuff.self_id;
1776 }
1777 return (resp->status);
1778 }
1779
1780
1781 ni_status
1782 ni_createprop(
1783 void *ni,
1784 ni_id *id,
1785 ni_property prop,
1786 ni_index where
1787 )
1788 {
1789 ni_id_res *resp;
1790 ni_createprop_args args;
1791
1792 args.id = *id;
1793 args.prop = prop;
1794 args.where = where;
1795 if ((resp = WCALLIT(ni, _ni_createprop_2, &args)) == NULL) {
1796 clnt_debug(ni, "_ni_createprop");
1797 return (NI_FAILED);
1798 }
1799 if (resp->status == NI_OK) {
1800 *id = resp->ni_id_res_u.id;
1801 }
1802 return (resp->status);
1803 }
1804
1805
1806 ni_status
1807 ni_destroyprop(
1808 void *ni,
1809 ni_id *id,
1810 ni_index which
1811 )
1812 {
1813 ni_id_res *resp;
1814 ni_prop_args args;
1815
1816 args.id = *id;
1817 args.prop_index = which;
1818 if ((resp = WCALLIT(ni, _ni_destroyprop_2, &args)) == NULL) {
1819 clnt_debug(ni, "_ni_destroyprop");
1820 return (NI_FAILED);
1821 }
1822 if (resp->status == NI_OK) {
1823 *id = resp->ni_id_res_u.id;
1824 }
1825 return (resp->status);
1826 }
1827
1828
1829 ni_status
1830 ni_renameprop(
1831 void *ni,
1832 ni_id *id,
1833 ni_index prop_index,
1834 ni_name_const name
1835 )
1836 {
1837 ni_id_res *resp;
1838 ni_propname_args args;
1839
1840 args.id = *id;
1841 args.prop_index = prop_index;
1842 args.name = (ni_name)name;
1843 if ((resp = WCALLIT(ni, _ni_renameprop_2, &args)) == NULL) {
1844 clnt_debug(ni, "_ni_renameprop");
1845 return (NI_FAILED);
1846 }
1847 if (resp->status == NI_OK) {
1848 *id = resp->ni_id_res_u.id;
1849 }
1850 return (resp->status);
1851 }
1852
1853
1854 ni_status
1855 ni_createname(
1856 void *ni,
1857 ni_id *id,
1858 ni_index prop_index,
1859 ni_name_const name,
1860 ni_index where
1861 )
1862 {
1863 ni_id_res *resp;
1864 ni_createname_args args;
1865
1866 args.id = *id;
1867 args.prop_index = prop_index;
1868 args.name = (ni_name)name;
1869 args.where = where;
1870 if ((resp = WCALLIT(ni, _ni_createname_2, &args)) == NULL) {
1871 clnt_debug(ni, "_ni_createname");
1872 return (NI_FAILED);
1873 }
1874 if (resp->status == NI_OK) {
1875 *id = resp->ni_id_res_u.id;
1876 }
1877 return (resp->status);
1878 }
1879
1880
1881 ni_status
1882 ni_destroyname(
1883 void *ni,
1884 ni_id *id,
1885 ni_index prop_index,
1886 ni_index name_index
1887 )
1888 {
1889 ni_id_res *resp;
1890 ni_nameindex_args args;
1891
1892 args.id = *id;
1893 args.prop_index = prop_index;
1894 args.name_index = name_index;
1895 if ((resp = WCALLIT(ni, _ni_destroyname_2, &args)) == NULL) {
1896 clnt_debug(ni, "_ni_destroyname");
1897 return (NI_FAILED);
1898 }
1899 if (resp->status == NI_OK) {
1900 *id = resp->ni_id_res_u.id;
1901 }
1902 return (resp->status);
1903 }
1904
1905
1906 ni_status
1907 ni_writename(
1908 void *ni,
1909 ni_id *id,
1910 ni_index prop_index,
1911 ni_index name_index,
1912 ni_name_const name
1913 )
1914 {
1915 ni_id_res *resp;
1916 ni_writename_args args;
1917
1918 args.id = *id;
1919 args.prop_index = prop_index;
1920 args.name_index = name_index;
1921 args.name = (ni_name)name;
1922 if ((resp = WCALLIT(ni, _ni_writename_2, &args)) == NULL) {
1923 clnt_debug(ni, "_ni_writename");
1924 return (NI_FAILED);
1925 }
1926 if (resp->status == NI_OK) {
1927 *id = resp->ni_id_res_u.id;
1928 }
1929 return (resp->status);
1930 }
1931
1932
1933 ni_status
1934 ni_readname(
1935 void *ni,
1936 ni_id *id,
1937 ni_index prop_index,
1938 ni_index name_index,
1939 ni_name *name
1940 )
1941 {
1942 ni_readname_res *resp;
1943 ni_nameindex_args args;
1944
1945 args.id = *id;
1946 args.prop_index = prop_index;
1947 args.name_index = name_index;
1948 if ((resp = RCALLIT(ni, _ni_readname_2, &args)) == NULL) {
1949 clnt_debug(ni, "_ni_readname");
1950 return (NI_FAILED);
1951 }
1952 if (resp->status == NI_OK) {
1953 *id = resp->ni_readname_res_u.stuff.id;
1954 *name = resp->ni_readname_res_u.stuff.name;
1955 }
1956 return (resp->status);
1957 }
1958
1959
1960 ni_status
1961 ni_resync(
1962 void *ni
1963 )
1964 {
1965 ni_status *resp;
1966
1967 if ((resp = (ni_status *)RCALLIT(ni, _ni_resync_2, NULL)) == NULL) {
1968 return (NI_FAILED);
1969 }
1970 return (*resp);
1971 }
1972
1973
1974 ni_status
1975 ni_setuser(
1976 void *ni,
1977 ni_name_const user
1978 )
1979 {
1980 ni_id id;
1981 ni_idlist ids;
1982 ni_namelist nl;
1983 char *p;
1984
1985 if (user == NULL) {
1986 NIP(ni)->uid = getuid();
1987 return (ni_setpassword(ni, NULL));
1988 }
1989
1990 if (ni_root(ni, &id) != NI_OK) {
1991 return(NI_NOUSER);
1992 }
1993 NI_INIT(&ids);
1994 if (ni_lookup(ni, &id, NAME_NAME, NAME_USERS, &ids) != NI_OK) {
1995 return (NI_NOUSER);
1996 }
1997 id.nii_object = ids.niil_val[0];
1998 ni_idlist_free(&ids);
1999
2000 NI_INIT(&ids);
2001 if (ni_lookup(ni, &id, NAME_NAME, user, &ids) != NI_OK) {
2002 return (NI_NOUSER);
2003 }
2004 id.nii_object = ids.niil_val[0];
2005 ni_idlist_free(&ids);
2006 NI_INIT(&nl);
2007 if (ni_lookupprop(ni, &id, NAME_UID, &nl) != NI_OK) {
2008 return (NI_NOUSER);
2009 }
2010 if (nl.ninl_len == 0) {
2011 return (NI_NOUSER);
2012 }
2013 for (p = nl.ninl_val[0]; *p; p++) {
2014 if (!isdigit(*p)) {
2015 ni_namelist_free(&nl);
2016 return (NI_NOUSER);
2017 }
2018 }
2019 NIP(ni)->uid = atoi(nl.ninl_val[0]);
2020 if (NIP(ni)->passwd == NULL) {
2021 NIP(ni)->passwd = ni_name_dup("");
2022 }
2023 createauth(NIP(ni));
2024 return (NI_OK);
2025 }
2026
2027
2028 ni_status
2029 ni_setpassword(
2030 void *ni,
2031 ni_name_const passwd
2032 )
2033 {
2034 char *p;
2035
2036 if (NIP(ni)->passwd != NULL) {
2037 ni_name_free(&NIP(ni)->passwd);
2038 }
2039 if (passwd == NULL) {
2040 NIP(ni)->passwd = NULL;
2041 if (NIP(ni)->tc != NULL) {
2042 auth_destroy(NIP(ni)->tc->cl_auth);
2043 NIP(ni)->tc->cl_auth = authnone_create();
2044 }
2045 return (NI_OK);
2046 }
2047 NIP(ni)->passwd = ni_name_dup(passwd);
2048 /*
2049 * Our trivial encryption scheme
2050 */
2051 for (p = NIP(ni)->passwd; *p; p++) {
2052 *p = ~(*p);
2053 }
2054 createauth(NIP(ni));
2055 return (NI_OK);
2056 }
2057
2058
2059 extern int bindresvport(int, struct sockaddr_in *);
2060
2061
2062 /*
2063 * NeXT note:
2064 * The procedure pmap_getport_to below is derived
2065 * from Sun Microsystems RPC source code. As such the following
2066 * statement applies to it.:
2067 *
2068 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
2069 * unrestricted use provided that this legend is included on all tape
2070 * media and as a part of the software program in whole or part. Users
2071 * may copy or modify Sun RPC without charge, but are not authorized
2072 * to license or distribute it to anyone else except as part of a product or
2073 * program developed by the user.
2074 *
2075 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
2076 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
2077 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
2078 *
2079 * Sun RPC is provided with no support and without any obligation on the
2080 * part of Sun Microsystems, Inc. to assist in its use, correction,
2081 * modification or enhancement.
2082 *
2083 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2084 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2085 * OR ANY PART THEREOF.
2086 *
2087 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2088 * or profits or other special, indirect and consequential damages, even if
2089 * Sun has been advised of the possibility of such damages.
2090 *
2091 * Sun Microsystems, Inc.
2092 * 2550 Garcia Avenue
2093 * Mountain View, California 94043
2094 */
2095 /*
2096 * Client interface to pmap rpc service.
2097 *
2098 * Find the mapped port for program,version.
2099 * Calls the pmap service remotely to do the lookup.
2100 * Returns 0 if no map exists.
2101 */
2102 static u_short
2103 pmap_getport_to(address, program, version, protocol, timeout_secs, ntries)
2104 struct sockaddr_in *address;
2105 u_long program;
2106 u_long version;
2107 u_int protocol;
2108 int timeout_secs;
2109 int ntries;
2110 {
2111 u_short port = 0;
2112 int sock = -1;
2113 register CLIENT *client;
2114 struct pmap parms;
2115 struct timeval timeout;
2116
2117 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2118 if (sock < 0) {
2119 return (0);
2120 }
2121 address->sin_port = htons(PMAPPORT);
2122 timeout.tv_usec = ((timeout_secs % ntries) * 1000000) / ntries;
2123 timeout.tv_sec = (timeout_secs / ntries);
2124 client = clntudp_bufcreate(address, PMAPPROG,
2125 PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
2126 if (client != (CLIENT *)NULL) {
2127 parms.pm_prog = program;
2128 parms.pm_vers = version;
2129 parms.pm_prot = protocol;
2130 parms.pm_port = 0; /* not needed or used */
2131 timeout.tv_usec = 0;
2132 timeout.tv_sec = timeout_secs;
2133 if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms,
2134 xdr_u_short, &port, timeout) != RPC_SUCCESS){
2135 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
2136 clnt_geterr(client, &rpc_createerr.cf_error);
2137 port = 0;
2138 } else if (port == 0) {
2139 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
2140 }
2141 }
2142 if (client != NULL) {
2143 clnt_destroy(client);
2144 }
2145 (void)close(sock);
2146 address->sin_port = 0;
2147 return (port);
2148 }
2149
2150
2151 /*
2152 * Open a socket, but do not use the default portmap timeout
2153 */
2154 static int
2155 socket_open(
2156 struct sockaddr_in *raddr,
2157 int prog,
2158 int vers,
2159 int timeout,
2160 int ntries,
2161 int proto
2162 )
2163 {
2164 int sock;
2165 int reuse = 1;
2166
2167 /*
2168 * If no port number given ask the pmap for one
2169 */
2170 if (raddr->sin_port == 0) {
2171 u_short port;
2172 if ((port = pmap_getport_to(raddr, prog, vers,
2173 IPPROTO_UDP, timeout,
2174 ntries)) == 0) {
2175 return (-1);
2176 }
2177 raddr->sin_port = htons(port);
2178 }
2179
2180 sock = socket(AF_INET, proto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM,
2181 proto);
2182 if (sock < 0) {
2183 return (-1);
2184 }
2185 (void)bindresvport(sock, (struct sockaddr_in *)0);
2186 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int));
2187 if (proto == IPPROTO_TCP) {
2188 if (connect(sock, (struct sockaddr *)raddr,
2189 sizeof(*raddr)) < 0) {
2190 (void)close(sock);
2191 return (-1);
2192 }
2193 }
2194 return (sock);
2195 }