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