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