2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
25 * Glues the library routines to the stub routines
26 * Copyright (C) 1989 by NeXT, Inc.
30 #include <netinfo/ni.h>
31 #include <rpc/pmap_clnt.h>
32 #include <rpc/pmap_prot.h>
37 #include "sys_interfaces.h"
39 #define LOCAL_PORT 1033
41 #define NI_TIMEOUT_SHORT 5 /* 5 second timeout for transactions */
42 #define NI_TIMEOUT_LONG 60 /* 60 second timeout for writes */
43 #define NI_TRIES 5 /* number of retries per timeout (udp only) */
44 #define NI_SLEEPTIME 4 /* 4 second sleeptime, in case of errors */
45 #define NI_MAXSLEEPTIME 64 /* 64 second max sleep time */
46 #define NI_MAXCONNTRIES 2 /* Try to form a connection twice before sleeping */
48 /* Hack for determining if an IP address is a broadcast address. -GRS */
49 /* Note that addr is network byte order (big endian) - BKM */
51 #define IS_BROADCASTADDR(addr) (((unsigned char *) &addr)[0] == 0xFF)
53 #ifndef INADDR_LOOPBACK
54 #define INADDR_LOOPBACK (u_long)0x7f000001
56 #define debug(msg) syslog(LOG_ERR, msg)
58 #define clnt_debug(ni, msg) /* do nothing */
60 typedef struct ni_private
{
61 int naddrs
; /* number of addresses */
62 struct in_addr
*addrs
; /* addresses of servers - network byte order */
63 int whichwrite
; /* which one of the above is the master */
64 ni_name
*tags
; /* tags of servers */
65 int pid
; /* pid, to detect forks */
66 int tsock
; /* tcp socket */
67 int tport
; /* tcp local port name - host byte order */
68 CLIENT
*tc
; /* tcp client */
69 long tv_sec
; /* timeout for this call */
70 long rtv_sec
; /* read timeout - 0 if default */
71 long wtv_sec
; /* write timeout - 0 if default */
72 int abort
; /* abort on timeout? */
73 int needwrite
; /* need to lock writes? */
74 int uid
; /* user id */
75 ni_name passwd
; /* password */
78 #define NIP(ni) ((ni_private *)(ni))
80 static const ni_name NAME_NAME
= "name";
81 static const ni_name NAME_SERVES
= "serves";
82 static const ni_name NAME_MACHINES
= "machines";
83 static const ni_name NAME_IP_ADDRESS
= "ip_address";
84 static const ni_name NAME_MASTER
= "master";
85 static const ni_name NAME_USERS
= "users";
86 static const ni_name NAME_UID
= "uid";
88 typedef struct getreg_stuff
{
89 nibind_getregister_res res
;
94 static int socket_open(struct sockaddr_in
*raddr
, int, int, int, int, int);
98 * Keep track of our port, in case somebody closes our socket
106 struct sockaddr_in sin
;
109 sinlen
= sizeof(sin
);
110 if (getsockname(sock
, (struct sockaddr
*)&sin
, &sinlen
) == 0) {
111 if (sin
.sin_port
== 0) {
112 (void)bind(sock
, (struct sockaddr
*)&sin
, sizeof(sin
));
113 sinlen
= sizeof(sin
);
114 (void)getsockname(sock
, (struct sockaddr
*)&sin
,
117 return (ntohs(sin
.sin_port
));
128 if (ni
->passwd
!= NULL
&& ni
->tc
!= NULL
) {
129 auth_destroy(ni
->tc
->cl_auth
);
130 ni
->tc
->cl_auth
= authunix_create(ni
->passwd
, ni
->uid
, 0, 0,
143 tv
->tv_sec
= sec
/ tries
;
144 tv
->tv_usec
= ((sec
% tries
) * 1000000) / tries
;
158 ni
->tv_sec
= timeout
;
159 if (ni
->tc
!= NULL
) {
160 clnt_control(ni
->tc
, CLSET_TIMEOUT
, &tv
);
166 * Connect to a given address/tag
169 connectit(ni_private
*ni
)
171 struct sockaddr_in sin
;
176 nibind_getregister_res res
;
179 bzero(&sin
, sizeof(sin
));
181 sin
.sin_family
= AF_INET
;
183 tv
.tv_sec
= ni
->rtv_sec
== 0 ? NI_TIMEOUT_SHORT
: ni
->rtv_sec
;
186 ni_settimeout(ni
, tv
.tv_sec
);
187 fixtimeout(&tv
, ni
->tv_sec
, NI_TRIES
);
190 * If connecting to local domain, try using the "well-known" port first.
192 if (!strcmp(ni
->tags
[0], "local"))
194 interface_list_t
*ilist
;
196 ilist
= sys_interfaces();
197 if (sys_is_my_address(ilist
, &ni
->addrs
[0]))
199 sin
.sin_port
= htons(LOCAL_PORT
);
200 sin
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
201 sock
= socket_open(&sin
, NI_PROG
, NI_VERS
, ni
->tv_sec
, NI_TRIES
, IPPROTO_TCP
);
203 sys_interfaces_release(ilist
);
207 * If connecting to a domain other than the local domain,
208 * or if connection to local didn't work with local's well-known port,
209 * then go through portmap & nibindd to find the port and connect.
214 sin
.sin_addr
= ni
->addrs
[0];
216 sock
= socket_open(&sin
, NIBIND_PROG
, NIBIND_VERS
, ni
->tv_sec
, NI_TRIES
, IPPROTO_UDP
);
217 if (sock
< 0) return (0);
219 cl
= clntudp_create(&sin
, NIBIND_PROG
, NIBIND_VERS
, tv
, &sock
);
226 tv
.tv_sec
= ni
->rtv_sec
== 0 ? NI_TIMEOUT_SHORT
: ni
->rtv_sec
;
229 stat
= clnt_call(cl
, NIBIND_GETREGISTER
, xdr_ni_name
, &ni
->tags
[0], xdr_nibind_getregister_res
, &res
, tv
);
232 if (stat
!= RPC_SUCCESS
|| res
.status
!= NI_OK
) return (0);
234 sin
.sin_port
= htons(res
.nibind_getregister_res_u
.addrs
.tcp_port
);
235 sock
= socket_open(&sin
, NI_PROG
, NI_VERS
, ni
->tv_sec
, NI_TRIES
, IPPROTO_TCP
);
238 if (sock
< 0) return (0);
240 cl
= clnttcp_create(&sin
, NI_PROG
, NI_VERS
, &sock
, 0, 0);
247 clnt_control(cl
, CLSET_TIMEOUT
, &tv
);
250 ni
->tport
= getmyport(sock
);
252 fcntl(ni
->tsock
, F_SETFD
, 1);
263 ((ni_private
*)ni
)->abort
= abort
;
273 ((ni_private
*)ni
)->wtv_sec
= timeout
;
283 ((ni_private
*)ni
)->rtv_sec
= timeout
;
293 ((ni_private
*)ni
)->needwrite
= needwrite
;
298 * Returns a client handle to the NetInfo server, if it's running
301 connectlocal(ni_private
*ni
)
306 ni
->addrs
= (struct in_addr
*)malloc(sizeof(struct in_addr
));
307 ni
->addrs
[0].s_addr
= htonl(INADDR_LOOPBACK
);
308 ni
->tags
= (ni_name
*)malloc(sizeof(ni_name
));
309 ni
->tags
[0] = ni_name_dup("local");
312 while (!connectit(ni
))
316 syslog(LOG_ERR
, "NetInfo timeout connecting to local domain, sleeping");
326 syslog(LOG_ERR
, "NetInfo connection to local domain waking");
334 * Destroy the client handle
345 if (sock
>= 0 && getmyport(sock
) != port
) {
347 * Somebody else has the descriptor open. Do not close it,
353 auth_destroy(cl
->cl_auth
);
358 * It's ours and we can close it
366 * Reinitialize everything
373 if (ni
->tc
!= NULL
) {
374 clnt_kill(ni
->tc
, ni
->tsock
, ni
->tport
);
384 * Switch to a new server
392 struct in_addr tmp_addr
;
399 tmp_addr
= ni
->addrs
[0];
400 tmp_tag
= ni
->tags
[0];
402 ni
->addrs
[0] = ni
->addrs
[which
];
403 ni
->tags
[0] = ni
->tags
[which
];
405 ni
->addrs
[which
] = tmp_addr
;
406 ni
->tags
[which
] = tmp_tag
;
408 if (ni
->whichwrite
== 0) {
409 ni
->whichwrite
= which
;
411 else if (ni
->whichwrite
== which
) {
418 * Swap two servers' positions
427 struct in_addr tmp_addr
;
432 tmp_addr
= ni
->addrs
[a
];
433 tmp_tag
= ni
->tags
[a
];
435 ni
->addrs
[a
] = ni
->addrs
[b
];
436 ni
->tags
[a
] = ni
->tags
[b
];
438 ni
->addrs
[b
] = tmp_addr
;
439 ni
->tags
[b
] = tmp_tag
;
441 if (ni
->whichwrite
== a
) {
444 else if (ni
->whichwrite
== b
) {
451 * Callback routine for multi_call
452 * XXX: should save returned port numbers
457 struct sockaddr_in
*sin
,
461 getreg_stuff
*stuff
= (getreg_stuff
*)vstuff
;
463 if (stuff
->res
.status
!= NI_OK
) {
466 ni_switch(stuff
->ni
, which
);
475 shuffle(ni_private
*ni
)
481 if (ni
->naddrs
<= 1) return;
483 rfd
= open("/dev/random", O_RDONLY
, 0);
484 shuffle
= (int *)malloc(ni
->naddrs
* sizeof(int));
485 for (i
= 0; i
< ni
->naddrs
; i
++) shuffle
[i
] = i
;
486 for (i
= 0, j
= ni
->naddrs
; j
> 0; i
++, j
--) {
491 /* get a random number */
493 (read(rfd
, &rVal
, sizeof(rVal
)) != sizeof(rVal
))) {
494 /* if we could not read from /dev/random */
495 static int initialized
= 0;
498 srandom(gethostid() ^ time(NULL
));
504 rEnt
= (unsigned int)rVal
% j
; /* pick one of the remaining entries */
505 tEnt
= shuffle
[rEnt
]; /* grab the random entry */
506 shuffle
[rEnt
] = shuffle
[j
-1]; /* the last entry moves to the random slot */
507 shuffle
[j
-1] = tEnt
; /* the last slot gets the random entry */
508 ni_swap(ni
, rEnt
, j
-1); /* and swap the actual NI addresses */
511 if (rfd
> 0) (void)close(rfd
);
523 int sleeptime
= NI_SLEEPTIME
;
527 interface_list_t
*ilist
;
530 if (ni
->naddrs
== 1) {
537 * re-order the servers so that:
538 * servers on the local host are at the start of the list, then
539 * servers on the local network are next, then
540 * all other servers are next
543 ilist
= sys_interfaces();
551 * move local servers to the head of the list
554 for (i
= nlocal
; i
< ni
->naddrs
; i
++) {
555 if (sys_is_my_address(ilist
, &ni
->addrs
[i
]))
557 ni_swap(ni
, nlocal
, i
);
563 * move servers on this network to follow local servers
566 for (i
= nnetwork
; i
< ni
->naddrs
; i
++) {
567 if (sys_is_my_network(ilist
, &ni
->addrs
[i
]) ||
568 IS_BROADCASTADDR(ni
->addrs
[i
].s_addr
))
570 ni_swap(ni
, nnetwork
, i
);
575 sys_interfaces_release(ilist
);
580 * call local servers first
583 for (i
= 0; i
< nlocal
; i
++) {
584 syslog(LOG_DEBUG
, "NetInfo connect call to: %s/%s (local %d)",
585 inet_ntoa(ni
->addrs
[i
]), ni
->tags
[i
], i
);
587 stat
= multi_call(nlocal
, ni
->addrs
,
588 NIBIND_PROG
, NIBIND_VERS
, NIBIND_GETREGISTER
,
589 xdr_ni_name
, ni
->tags
,
591 xdr_nibind_getregister_res
,
594 if (stat
== RPC_SUCCESS
) {
600 * call local servers and this network's servers
602 if (nnetwork
> nlocal
) {
603 for (i
= 0; i
< nnetwork
; i
++) {
604 syslog(LOG_DEBUG
, "NetInfo connect call to: %s/%s (network %d)",
605 inet_ntoa(ni
->addrs
[i
]), ni
->tags
[i
], i
);
607 stat
= multi_call(nnetwork
, ni
->addrs
,
608 NIBIND_PROG
, NIBIND_VERS
, NIBIND_GETREGISTER
,
609 xdr_ni_name
, ni
->tags
,
611 xdr_nibind_getregister_res
,
614 if (stat
== RPC_SUCCESS
) {
622 for (i
= 0; i
< ni
->naddrs
; i
++) {
623 syslog(LOG_DEBUG
, "NetInfo connect call to: %s/%s (world %d)",
624 inet_ntoa(ni
->addrs
[i
]), ni
->tags
[i
], i
);
626 stat
= multi_call(ni
->naddrs
,
627 ni
->addrs
, NIBIND_PROG
, NIBIND_VERS
,
629 xdr_ni_name
, ni
->tags
,
631 xdr_nibind_getregister_res
,
633 ni
->rtv_sec
== 0 ? NI_TIMEOUT_SHORT
: ni
->rtv_sec
);
634 if (stat
== RPC_SUCCESS
) {
642 if (ni
->whichwrite
>= 0) {
644 "NetInfo connect timeout (domain with master %s/%s), sleeping",
645 inet_ntoa(ni
->addrs
[ni
->whichwrite
]), ni
->tags
[ni
->whichwrite
]);
648 syslog(LOG_ERR
, "NetInfo connect timeout (domain with server %s/%s), sleeping",
649 inet_ntoa(ni
->addrs
[0]), ni
->tags
[0]);
654 if (sleeptime
< NI_MAXSLEEPTIME
) {
655 sleeptime
*= 2; /* backoff */
659 syslog(LOG_INFO
, "NetInfo connected to %s/%s", inet_ntoa(ni
->addrs
[0]), ni
->tags
[0]);
662 syslog(LOG_ERR
, "NetInfo connected to %s/%s", inet_ntoa(ni
->addrs
[0]), ni
->tags
[0]);
669 * Confirm that our tcp socket is still valid
677 if (ni
->tsock
!= -1) {
678 if (getmyport(ni
->tsock
) == ni
->tport
) {
682 * Somebody closed our socket. Do not close it, it could
683 * be owned by somebody else now.
685 auth_destroy(ni
->tc
->cl_auth
);
686 clnt_destroy(ni
->tc
);
689 if (!needwrite
&& !rebind(ni
) && ni
->abort
) {
692 return (connectit(ni
));
712 if (ni
->naddrs
== 1) {
714 * One server - must be the master
719 needwrite
= ni
->needwrite
;
721 if (ni_root(ni
, &root
) != NI_OK
) {
722 ni
->needwrite
= needwrite
;
726 if (ni_lookupprop(ni
, &root
, NAME_MASTER
, &nl
) != NI_OK
) {
727 ni
->needwrite
= needwrite
;
730 if (nl
.ninl_len
== 0) {
731 ni
->needwrite
= needwrite
;
734 sep
= index(nl
.ninl_val
[0], '/');
736 ni
->needwrite
= needwrite
;
740 master
= nl
.ninl_val
[0];
742 if (ni_lookup(ni
, &root
, NAME_NAME
, NAME_MACHINES
, &idl
) != NI_OK
) {
743 ni
->needwrite
= needwrite
;
744 ni_namelist_free(&nl
);
747 if (idl
.niil_len
< 1) {
748 ni
->needwrite
= needwrite
;
751 id
.nii_object
= idl
.niil_val
[0];
752 ni_idlist_free(&idl
);
754 if (ni_lookup(ni
, &id
, NAME_NAME
, master
, &idl
) != NI_OK
) {
755 ni_namelist_free(&nl
);
756 ni
->needwrite
= needwrite
;
759 ni_namelist_free(&nl
);
760 if (idl
.niil_len
< 1) {
761 ni
->needwrite
= needwrite
;
764 id
.nii_object
= idl
.niil_val
[0];
765 ni_idlist_free(&idl
);
767 if (ni_lookupprop(ni
, &id
, NAME_IP_ADDRESS
, &nl
) != NI_OK
) {
770 for (i
= 0; i
< nl
.ninl_len
; i
++) {
771 addr
.s_addr
= inet_addr(nl
.ninl_val
[i
]);
772 for (j
= 0; j
< ni
->naddrs
; j
++) {
773 if (addr
.s_addr
== ni
->addrs
[j
].s_addr
) {
775 ni_namelist_free(&nl
);
776 ni
->needwrite
= needwrite
;
781 ni
->needwrite
= needwrite
;
782 ni_namelist_free(&nl
);
801 if (getpid() != ni
->pid
) {
804 if (needwrite
|| ni
->needwrite
) {
805 if (ni
->whichwrite
>= 0) {
806 ni_switch(ni
, ni
->whichwrite
);
808 if (!setmaster(ni
)) {
811 ni_switch(ni
, ni
->whichwrite
);
814 ni_settimeout(ni
, (ni
->rtv_sec
== 0 ?
815 NI_TIMEOUT_SHORT
: ni
->rtv_sec
));
818 ni_settimeout(ni
, (ni
->wtv_sec
== 0 ?
819 NI_TIMEOUT_LONG
: ni
->wtv_sec
));
822 ni_settimeout(ni
, (ni
->rtv_sec
== 0 ?
823 NI_TIMEOUT_SHORT
: ni
->rtv_sec
));
827 * Try more than once, in case server closed connection.
829 for (i
= 0; i
< NI_MAXCONNTRIES
; i
++) {
830 if (!confirm_tcp(ni
, needwrite
)) {
833 if ((resp
= (*stub
)(args
, ni
->tc
)) != NULL
) {
835 syslog(LOG_ERR
, "NetInfo connected to %s/%s",
836 inet_ntoa(ni
->addrs
[0]), ni
->tags
[0]);
840 clnt_geterr(ni
->tc
, &err
);
841 if (err
.re_status
!= RPC_CANTRECV
) {
844 if (i
+ 1 < NI_MAXCONNTRIES
) {
846 * Server closed connection. Reinit and try
852 if (err
.re_status
== RPC_PROCUNAVAIL
) {
855 if (needwrite
|| ni
->abort
) {
857 * We time out for writes or if it is explicitly
864 "NetInfo connection failed for server %s/%s",
865 inet_ntoa(ni
->addrs
[0]), ni
->tags
[0]);
869 if (ni
->tc
!= NULL
) {
870 if (!(sleeptime
== 0 &&
871 err
.re_status
== RPC_TIMEDOUT
)) {
873 * Do not print message on
874 * first timeout. It is likely
875 * we will find another server soon.
876 * Let's not needlessly alarm the
879 syslog(LOG_ERR
, "%s on connection to %s/%s",
880 clnt_sperror(ni
->tc
,"NetInfo connection timeout"),
881 inet_ntoa(ni
->addrs
[0]), ni
->tags
[0]);
885 /* first attempt failed */
886 syslog(LOG_ERR
, "%s on initial connection to %s/%s",
887 clnt_sperror(ni
->tc
,"NetInfo connection timeout"),
888 inet_ntoa(ni
->addrs
[0]), ni
->tags
[0]);
892 "NetInfo connection failed for server %s/%s",
893 inet_ntoa(ni
->addrs
[0]), ni
->tags
[0]);
899 if (sleeptime
< NI_MAXSLEEPTIME
) {
900 sleeptime
*= 2; /* backoff */
904 * Do not sleep on the first timeout.
905 * It is likely we will find another server quickly.
907 sleeptime
= NI_SLEEPTIME
;
915 #define RCALLIT(a, b, c) callit((ni_private *)(a), (void *(*)())(b), \
919 #define WCALLIT(a, b, c) callit((ni_private *)(a), (void *(*)())(b), \
947 ni
= (ni_private
*)malloc(sizeof(*ni
));
954 ni
->tv_sec
= NI_TIMEOUT_SHORT
;
973 dupni
= (ni_private
*)ni_alloc();
976 dupni
->naddrs
= NIP(ni
)->naddrs
;
977 dupni
->whichwrite
= NIP(ni
)->whichwrite
;
978 if (dupni
->naddrs
> 0) {
979 dupni
->addrs
= ((struct in_addr
*)
980 malloc(NIP(ni
)->naddrs
* sizeof(struct in_addr
)));
981 bcopy(NIP(ni
)->addrs
, dupni
->addrs
,
982 NIP(ni
)->naddrs
* sizeof(struct in_addr
));
983 dupni
->tags
= ((ni_name
*)
984 malloc(NIP(ni
)->naddrs
* sizeof(ni_name
)));
985 for (i
= 0; i
< NIP(ni
)->naddrs
; i
++) {
986 dupni
->tags
[i
] = ni_name_dup(NIP(ni
)->tags
[i
]);
989 if (NIP(ni
)->passwd
!= NULL
) {
990 dupni
->passwd
= ni_name_dup(NIP(ni
)->passwd
);
992 return ((void *)dupni
);
1003 int len
= strlen(domain
);
1006 sep
= index(domtag
, '/');
1010 if (strncmp(domain
, domtag
, len
) == 0 &&
1011 domtag
[len
] == '/') {
1012 *tag
= ni_name_dup(sep
+ 1);
1024 ni_private
*target_ni
1029 struct in_addr addr
;
1032 id
.nii_object
= ido
;
1034 if (ni_lookupprop(ni
, &id
, NAME_IP_ADDRESS
, &nl
) != NI_OK
) {
1037 if (nl
.ninl_len
== 0) {
1041 if (target_ni
->naddrs
== 0) {
1043 (struct in_addr
*)malloc(nl
.ninl_len
* sizeof(struct in_addr
));
1045 (ni_name
*)malloc(nl
.ninl_len
* sizeof(ni_name
));
1048 (struct in_addr
*)realloc(target_ni
->addrs
,
1049 ((target_ni
->naddrs
+ nl
.ninl_len
) * sizeof(struct in_addr
)));
1051 (ni_name
*)realloc(target_ni
->tags
,
1052 ((target_ni
->naddrs
+ nl
.ninl_len
) * sizeof(ni_name
)));
1055 for (i
=0; i
<nl
.ninl_len
; i
++) {
1056 addr
.s_addr
= inet_addr(nl
.ninl_val
[i
]);
1057 target_ni
->addrs
[target_ni
->naddrs
] = addr
;
1058 target_ni
->tags
[target_ni
->naddrs
] = ni_name_dup(tag
);
1059 target_ni
->naddrs
++;
1062 ni_namelist_free(&nl
);
1071 ni_private
*target_ni
1077 ni_entrylist entries
;
1082 if (ni_root(ni
, &id
) != NI_OK
) {
1087 if (ni_lookup(ni
, &id
, NAME_NAME
, NAME_MACHINES
, &ids
) != NI_OK
) {
1091 id
.nii_object
= ids
.niil_val
[0];
1092 ni_idlist_free(&ids
);
1095 if (ni_list(ni
, &id
, NAME_SERVES
, &entries
) != NI_OK
) {
1099 for (i
= 0; i
< entries
.niel_len
; i
++) {
1100 if (entries
.niel_val
[i
].names
!= NULL
) {
1101 nl
= *entries
.niel_val
[i
].names
;
1102 for (j
= 0; j
< nl
.ninl_len
; j
++) {
1103 if (match(dom
, nl
.ninl_val
[j
], &tag
)) {
1105 entries
.niel_val
[i
].id
,
1117 ni_entrylist_free(&entries
);
1118 return (target_ni
->naddrs
> 0);
1128 ni_private
*target_ni
1134 if (ni_root(ni
, &id
) != NI_OK
) {
1138 if (ni_lookup(ni
, &id
, NAME_NAME
, NAME_MACHINES
, &ids
) != NI_OK
) {
1141 id
.nii_object
= ids
.niil_val
[0];
1142 ni_idlist_free(&ids
);
1145 if (ni_lookup(ni
, &id
, NAME_NAME
, hname
, &ids
) != NI_OK
) {
1148 id
.nii_object
= ids
.niil_val
[0];
1149 ni_idlist_free(&ids
);
1150 if (!addaddr(ni
, id
.nii_object
, tag
, target_ni
)) {
1159 getparent(ni_private
*oldni
, ni_private
**newni
)
1161 ni_rparent_res
*resp
;
1166 struct in_addr raddr
;
1173 * First, find our parent, any parent
1176 resp
= RCALLIT(oldni
, _ni_rparent_2
, NULL
);
1180 if (resp
->status
!= NI_NORESPONSE
) {
1184 syslog(LOG_ERR
, "NetInfo timeout finding server for parent of %s/%s, sleeping",
1185 inet_ntoa(oldni
->addrs
[0]), oldni
->tags
[0]);
1188 sleep(NI_SLEEPTIME
);
1191 raddr
.s_addr
= htonl(resp
->ni_rparent_res_u
.binding
.addr
);
1193 syslog(LOG_ERR
, "NetInfo %s/%s found parent %s/%s",
1194 inet_ntoa(oldni
->addrs
[0]), oldni
->tags
[0],
1195 inet_ntoa(raddr
), resp
->ni_rparent_res_u
.binding
.tag
);
1197 if (resp
->status
!= NI_OK
) {
1198 return (resp
->status
);
1204 ni
->addrs
= (struct in_addr
*)malloc(sizeof(struct in_addr
));
1205 ni
->addrs
[0].s_addr
=htonl(resp
->ni_rparent_res_u
.binding
.addr
);
1206 ni
->tags
= (ni_name
*)malloc(sizeof(ni_name
));
1207 ni
->tags
[0] = ni_name_dup(resp
->ni_rparent_res_u
.binding
.tag
);
1209 xdr_free(xdr_ni_rparent_res
, resp
);
1215 if (get_daddr(dupni
, ".", ni
)) {
1218 * Now make sure returned parent is head of
1221 for (i
= 0; i
< ni
->naddrs
; i
++) {
1222 if (ni
->addrs
[i
].s_addr
==
1223 dupni
->addrs
[0].s_addr
) {
1231 * Reuse dupni client info
1233 ni
->tsock
= dupni
->tsock
;
1234 ni
->tport
= dupni
->tport
;
1242 * If returned parent wasn't in list, it's a rogue.
1243 * Log an error and drop the connection.
1246 syslog(LOG_ERR
, "Rogue NetInfo server detected: %s/%s",
1247 inet_ntoa(dupni
->addrs
[0]), dupni
->tags
[0]);
1266 struct sockaddr_in
*sin
,
1273 NIP(ni
)->naddrs
= 1;
1274 NIP(ni
)->addrs
= (struct in_addr
*
1275 )malloc(sizeof(struct in_addr
));
1276 NIP(ni
)->addrs
[0] = sin
->sin_addr
;
1277 NIP(ni
)->tags
= (ni_name
*)malloc(sizeof(ni_name
));
1278 NIP(ni
)->tags
[0] = ni_name_dup(tag
);
1286 struct sockaddr_in
*addr
,
1291 if (!confirm_tcp(ni
, 0)) {
1294 *tag
= ni_name_dup(NIP(ni
)->tags
[0]);
1295 addr
->sin_addr
= NIP(ni
)->addrs
[0];
1296 addr
->sin_port
= htons(NIP(ni
)->tport
);
1297 addr
->sin_family
= AF_INET
;
1298 bzero(addr
->sin_zero
, sizeof(addr
->sin_zero
));
1311 ni_name sep
, addr
, tag
;
1312 struct sockaddr_in sin
;
1315 if (oldni
== NULL
) {
1317 if (!connectlocal(ni
)) {
1321 if (strcmp(domain
, "..") == 0) {
1323 status
= getparent((ni_private
*)oldni
, &ni
);
1325 if (status
!= NI_OK
) {
1328 } else if ((sep
= index(domain
, '@')) != NULL
) {
1330 tag
= strncpy((char *)malloc(sep
-domain
+1), domain
, sep
-domain
);
1331 tag
[sep
-domain
] = '\0';
1332 addr
= strcpy ((char *)malloc(strlen(sep
+1)), sep
+1);
1333 sin
.sin_addr
.s_addr
= inet_addr(addr
);
1334 if (sin
.sin_addr
.s_addr
== INADDR_NONE
) {
1335 he
= gethostbyname(addr
);
1341 bcopy(he
->h_addr_list
[0], &sin
.sin_addr
.s_addr
, he
->h_length
);
1343 ni
= ni_connect(&sin
, tag
);
1346 } else if (strcmp(domain
, ".") != 0) {
1348 * nothing else makes sense
1354 if (strcmp(domain
, "..") == 0) {
1355 status
= getparent((ni_private
*)oldni
, &ni
);
1356 if (status
!= NI_OK
) {
1359 } else if ((sep
= index(domain
, '@')) != NULL
) {
1360 tag
= strncpy((char *)malloc(sep
-domain
+1), domain
, sep
-domain
);
1361 tag
[sep
-domain
] = '\0';
1362 addr
= strcpy ((char *)malloc(strlen(sep
+1)), sep
+1);
1363 sin
.sin_addr
.s_addr
= inet_addr(addr
);
1364 if (sin
.sin_addr
.s_addr
== INADDR_NONE
) {
1365 he
= gethostbyname(addr
);
1371 bcopy(he
->h_addr_list
[0], &sin
.sin_addr
.s_addr
, he
->h_length
);
1373 ni
= ni_connect(&sin
, tag
);
1380 if (!get_daddr(oldni
, (ni_name
)domain
, ni
)) {
1386 return ((void *)ni
);
1397 if (NIP(ni
)->tc
!= NULL
) {
1398 clnt_kill(NIP(ni
)->tc
, NIP(ni
)->tsock
, NIP(ni
)->tport
);
1400 if (NIP(ni
)->naddrs
> 0) {
1401 free(NIP(ni
)->addrs
);
1402 for (i
= 0; i
< NIP(ni
)->naddrs
; i
++) {
1403 ni_name_free(&NIP(ni
)->tags
[i
]);
1405 free(NIP(ni
)->tags
);
1407 if (NIP(ni
)->passwd
!= NULL
) {
1408 ni_name_free(&NIP(ni
)->passwd
);
1415 * The rest of these are just wrappers that end up doing
1416 * RPC calls to the local NetInfo server.
1426 if ((resp
= (ni_proplist
*)RCALLIT(ni
, _ni_statistics_2
, NULL
))
1443 if ((resp
= RCALLIT(ni
, _ni_root_2
, id
)) == NULL
) {
1444 clnt_debug(ni
, "_ni_root");
1447 if (resp
->status
== NI_OK
) {
1448 *id
= resp
->ni_id_res_u
.id
;
1450 return (resp
->status
);
1462 if ((resp
= RCALLIT(ni
, _ni_self_2
, id
)) == NULL
) {
1463 clnt_debug(ni
, "_ni_self");
1466 if (resp
->status
== NI_OK
) {
1467 *id
= resp
->ni_id_res_u
.id
;
1469 return (resp
->status
);
1477 ni_index
*parent_id_p
1480 ni_parent_res
*resp
;
1482 if ((resp
= RCALLIT(ni
, _ni_parent_2
, id
)) == NULL
) {
1483 clnt_debug(ni
, "_ni_parent");
1486 if (resp
->status
== NI_OK
) {
1487 *parent_id_p
= resp
->ni_parent_res_u
.stuff
.object_id
;
1488 *id
= resp
->ni_parent_res_u
.stuff
.self_id
;
1490 return (resp
->status
);
1501 ni_children_res
*resp
;
1503 if ((resp
= RCALLIT(ni
, _ni_children_2
, id
)) == NULL
) {
1504 clnt_debug(ni
, "_ni_children");
1507 if (resp
->status
== NI_OK
) {
1508 *children
= resp
->ni_children_res_u
.stuff
.children
;
1509 *id
= resp
->ni_children_res_u
.stuff
.self_id
;
1511 return (resp
->status
);
1524 ni_create_args args
;
1525 ni_create_res
*resp
;
1527 args
.id
= *parent_id
;
1530 args
.target_id
= NULL
;
1531 if ((resp
= WCALLIT(ni
, _ni_create_2
, &args
)) == NULL
) {
1532 clnt_debug(ni
, "_ni_create");
1535 if (resp
->status
== NI_OK
) {
1536 *child_id_p
= resp
->ni_create_res_u
.stuff
.id
;
1537 *parent_id
= resp
->ni_create_res_u
.stuff
.self_id
;
1539 return (resp
->status
);
1551 ni_destroy_args args
;
1553 args
.parent_id
= *parent_id
;
1554 args
.self_id
= self_id
;
1555 if ((resp
= WCALLIT(ni
, _ni_destroy_2
, &args
)) == NULL
) {
1556 clnt_debug(ni
, "_ni_destroy");
1559 if (resp
->status
== NI_OK
) {
1560 *parent_id
= resp
->ni_id_res_u
.id
;
1562 return (resp
->status
);
1573 ni_proplist_stuff args
;
1578 if ((resp
= WCALLIT(ni
, _ni_write_2
, &args
)) == NULL
) {
1579 clnt_debug(ni
, "_ni_write");
1582 if (resp
->status
== NI_OK
) {
1583 *self_id
= resp
->ni_id_res_u
.id
;
1585 return (resp
->status
);
1596 ni_proplist_res
*resp
;
1598 if ((resp
= RCALLIT(ni
, _ni_read_2
, self_id
)) == NULL
) {
1599 clnt_debug(ni
, "_ni_read");
1602 if (resp
->status
== NI_OK
) {
1603 *self_id
= resp
->ni_proplist_res_u
.stuff
.id
;
1604 *pl
= resp
->ni_proplist_res_u
.stuff
.props
;
1606 return (resp
->status
);
1614 ni_name_const pname
,
1619 ni_lookup_res
*resp
;
1620 ni_lookup_args args
;
1623 args
.key
= (ni_name
)pname
;
1624 args
.value
= (ni_name
)pval
;
1625 if ((resp
= RCALLIT(ni
, _ni_lookup_2
, &args
)) == NULL
) {
1626 clnt_debug(ni
, "_ni_lookup");
1629 if (resp
->status
== NI_OK
) {
1630 *hits
= resp
->ni_lookup_res_u
.stuff
.idlist
;
1631 *id
= resp
->ni_lookup_res_u
.stuff
.self_id
;
1633 return (resp
->status
);
1641 ni_name_const pname
,
1646 ni_proplist_res
*resp
;
1647 ni_lookup_args args
;
1650 args
.key
= (ni_name
)pname
;
1651 args
.value
= (ni_name
)pval
;
1652 if ((resp
= RCALLIT(ni
, _ni_lookupread_2
, &args
)) == NULL
) {
1653 clnt_debug(ni
, "_ni_lookupread");
1656 if (resp
->status
== NI_OK
) {
1657 *props
= resp
->ni_proplist_res_u
.stuff
.props
;
1658 *id
= resp
->ni_proplist_res_u
.stuff
.id
;
1660 return (resp
->status
);
1668 ni_name_const pname
,
1669 ni_entrylist
*entries
1676 args
.name
= (ni_name
)pname
;
1677 if ((resp
= RCALLIT(ni
, _ni_list_2
, &args
)) == NULL
) {
1678 clnt_debug(ni
, "_ni_list");
1681 if (resp
->status
== NI_OK
) {
1682 *entries
= resp
->ni_list_res_u
.stuff
.entries
;
1683 *id
= resp
->ni_list_res_u
.stuff
.self_id
;
1685 return (resp
->status
);
1693 ni_proplist_list
*entries
1696 ni_listall_res
*resp
;
1698 if ((resp
= RCALLIT(ni
, _ni_listall_2
, id
)) == NULL
) {
1699 clnt_debug(ni
, "_ni_listall");
1702 if (resp
->status
== NI_OK
) {
1703 *entries
= resp
->ni_listall_res_u
.stuff
.entries
;
1704 *id
= resp
->ni_listall_res_u
.stuff
.self_id
;
1706 return (resp
->status
);
1715 ni_namelist
*propval_p
1718 ni_namelist_res
*resp
;
1722 args
.prop_index
= which
;
1723 if ((resp
= RCALLIT(ni
, _ni_readprop_2
, &args
)) == NULL
) {
1724 clnt_debug(ni
, "_ni_readprop");
1727 if (resp
->status
== NI_OK
) {
1728 *propval_p
= resp
->ni_namelist_res_u
.stuff
.values
;
1729 *id
= resp
->ni_namelist_res_u
.stuff
.self_id
;
1731 return (resp
->status
);
1744 ni_writeprop_args args
;
1747 args
.prop_index
= which
;
1748 args
.values
= propval
;
1749 if ((resp
= WCALLIT(ni
, _ni_writeprop_2
, &args
)) == NULL
) {
1750 clnt_debug(ni
, "_ni_writeprop");
1753 if (resp
->status
== NI_OK
) {
1754 *id
= resp
->ni_id_res_u
.id
;
1756 return (resp
->status
);
1764 ni_namelist
*propnames
1767 ni_namelist_res
*resp
;
1769 if ((resp
= RCALLIT(ni
, _ni_listprops_2
, id
)) == NULL
) {
1770 clnt_debug(ni
, "_ni_listprops");
1773 if (resp
->status
== NI_OK
) {
1774 *propnames
= resp
->ni_namelist_res_u
.stuff
.values
;
1775 *id
= resp
->ni_namelist_res_u
.stuff
.self_id
;
1777 return (resp
->status
);
1790 ni_createprop_args args
;
1795 if ((resp
= WCALLIT(ni
, _ni_createprop_2
, &args
)) == NULL
) {
1796 clnt_debug(ni
, "_ni_createprop");
1799 if (resp
->status
== NI_OK
) {
1800 *id
= resp
->ni_id_res_u
.id
;
1802 return (resp
->status
);
1817 args
.prop_index
= which
;
1818 if ((resp
= WCALLIT(ni
, _ni_destroyprop_2
, &args
)) == NULL
) {
1819 clnt_debug(ni
, "_ni_destroyprop");
1822 if (resp
->status
== NI_OK
) {
1823 *id
= resp
->ni_id_res_u
.id
;
1825 return (resp
->status
);
1833 ni_index prop_index
,
1838 ni_propname_args args
;
1841 args
.prop_index
= prop_index
;
1842 args
.name
= (ni_name
)name
;
1843 if ((resp
= WCALLIT(ni
, _ni_renameprop_2
, &args
)) == NULL
) {
1844 clnt_debug(ni
, "_ni_renameprop");
1847 if (resp
->status
== NI_OK
) {
1848 *id
= resp
->ni_id_res_u
.id
;
1850 return (resp
->status
);
1858 ni_index prop_index
,
1864 ni_createname_args args
;
1867 args
.prop_index
= prop_index
;
1868 args
.name
= (ni_name
)name
;
1870 if ((resp
= WCALLIT(ni
, _ni_createname_2
, &args
)) == NULL
) {
1871 clnt_debug(ni
, "_ni_createname");
1874 if (resp
->status
== NI_OK
) {
1875 *id
= resp
->ni_id_res_u
.id
;
1877 return (resp
->status
);
1885 ni_index prop_index
,
1890 ni_nameindex_args args
;
1893 args
.prop_index
= prop_index
;
1894 args
.name_index
= name_index
;
1895 if ((resp
= WCALLIT(ni
, _ni_destroyname_2
, &args
)) == NULL
) {
1896 clnt_debug(ni
, "_ni_destroyname");
1899 if (resp
->status
== NI_OK
) {
1900 *id
= resp
->ni_id_res_u
.id
;
1902 return (resp
->status
);
1910 ni_index prop_index
,
1911 ni_index name_index
,
1916 ni_writename_args args
;
1919 args
.prop_index
= prop_index
;
1920 args
.name_index
= name_index
;
1921 args
.name
= (ni_name
)name
;
1922 if ((resp
= WCALLIT(ni
, _ni_writename_2
, &args
)) == NULL
) {
1923 clnt_debug(ni
, "_ni_writename");
1926 if (resp
->status
== NI_OK
) {
1927 *id
= resp
->ni_id_res_u
.id
;
1929 return (resp
->status
);
1937 ni_index prop_index
,
1938 ni_index name_index
,
1942 ni_readname_res
*resp
;
1943 ni_nameindex_args args
;
1946 args
.prop_index
= prop_index
;
1947 args
.name_index
= name_index
;
1948 if ((resp
= RCALLIT(ni
, _ni_readname_2
, &args
)) == NULL
) {
1949 clnt_debug(ni
, "_ni_readname");
1952 if (resp
->status
== NI_OK
) {
1953 *id
= resp
->ni_readname_res_u
.stuff
.id
;
1954 *name
= resp
->ni_readname_res_u
.stuff
.name
;
1956 return (resp
->status
);
1967 if ((resp
= (ni_status
*)RCALLIT(ni
, _ni_resync_2
, NULL
)) == NULL
) {
1986 NIP(ni
)->uid
= getuid();
1987 return (ni_setpassword(ni
, NULL
));
1990 if (ni_root(ni
, &id
) != NI_OK
) {
1994 if (ni_lookup(ni
, &id
, NAME_NAME
, NAME_USERS
, &ids
) != NI_OK
) {
1997 id
.nii_object
= ids
.niil_val
[0];
1998 ni_idlist_free(&ids
);
2001 if (ni_lookup(ni
, &id
, NAME_NAME
, user
, &ids
) != NI_OK
) {
2004 id
.nii_object
= ids
.niil_val
[0];
2005 ni_idlist_free(&ids
);
2007 if (ni_lookupprop(ni
, &id
, NAME_UID
, &nl
) != NI_OK
) {
2010 if (nl
.ninl_len
== 0) {
2013 for (p
= nl
.ninl_val
[0]; *p
; p
++) {
2015 ni_namelist_free(&nl
);
2019 NIP(ni
)->uid
= atoi(nl
.ninl_val
[0]);
2020 if (NIP(ni
)->passwd
== NULL
) {
2021 NIP(ni
)->passwd
= ni_name_dup("");
2023 createauth(NIP(ni
));
2031 ni_name_const passwd
2036 if (NIP(ni
)->passwd
!= NULL
) {
2037 ni_name_free(&NIP(ni
)->passwd
);
2039 if (passwd
== NULL
) {
2040 NIP(ni
)->passwd
= NULL
;
2041 if (NIP(ni
)->tc
!= NULL
) {
2042 auth_destroy(NIP(ni
)->tc
->cl_auth
);
2043 NIP(ni
)->tc
->cl_auth
= authnone_create();
2047 NIP(ni
)->passwd
= ni_name_dup(passwd
);
2049 * Our trivial encryption scheme
2051 for (p
= NIP(ni
)->passwd
; *p
; p
++) {
2054 createauth(NIP(ni
));
2059 extern int bindresvport(int, struct sockaddr_in
*);
2064 * The procedure pmap_getport_to below is derived
2065 * from Sun Microsystems RPC source code. As such the following
2066 * statement applies to it.:
2068 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
2069 * unrestricted use provided that this legend is included on all tape
2070 * media and as a part of the software program in whole or part. Users
2071 * may copy or modify Sun RPC without charge, but are not authorized
2072 * to license or distribute it to anyone else except as part of a product or
2073 * program developed by the user.
2075 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
2076 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
2077 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
2079 * Sun RPC is provided with no support and without any obligation on the
2080 * part of Sun Microsystems, Inc. to assist in its use, correction,
2081 * modification or enhancement.
2083 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2084 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2085 * OR ANY PART THEREOF.
2087 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2088 * or profits or other special, indirect and consequential damages, even if
2089 * Sun has been advised of the possibility of such damages.
2091 * Sun Microsystems, Inc.
2092 * 2550 Garcia Avenue
2093 * Mountain View, California 94043
2096 * Client interface to pmap rpc service.
2098 * Find the mapped port for program,version.
2099 * Calls the pmap service remotely to do the lookup.
2100 * Returns 0 if no map exists.
2103 pmap_getport_to(address
, program
, version
, protocol
, timeout_secs
, ntries
)
2104 struct sockaddr_in
*address
;
2113 register CLIENT
*client
;
2115 struct timeval timeout
;
2117 sock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2121 address
->sin_port
= htons(PMAPPORT
);
2122 timeout
.tv_usec
= ((timeout_secs
% ntries
) * 1000000) / ntries
;
2123 timeout
.tv_sec
= (timeout_secs
/ ntries
);
2124 client
= clntudp_bufcreate(address
, PMAPPROG
,
2125 PMAPVERS
, timeout
, &sock
, RPCSMALLMSGSIZE
, RPCSMALLMSGSIZE
);
2126 if (client
!= (CLIENT
*)NULL
) {
2127 parms
.pm_prog
= program
;
2128 parms
.pm_vers
= version
;
2129 parms
.pm_prot
= protocol
;
2130 parms
.pm_port
= 0; /* not needed or used */
2131 timeout
.tv_usec
= 0;
2132 timeout
.tv_sec
= timeout_secs
;
2133 if (CLNT_CALL(client
, PMAPPROC_GETPORT
, xdr_pmap
, &parms
,
2134 xdr_u_short
, &port
, timeout
) != RPC_SUCCESS
){
2135 rpc_createerr
.cf_stat
= RPC_PMAPFAILURE
;
2136 clnt_geterr(client
, &rpc_createerr
.cf_error
);
2138 } else if (port
== 0) {
2139 rpc_createerr
.cf_stat
= RPC_PROGNOTREGISTERED
;
2142 if (client
!= NULL
) {
2143 clnt_destroy(client
);
2146 address
->sin_port
= 0;
2152 * Open a socket, but do not use the default portmap timeout
2156 struct sockaddr_in
*raddr
,
2168 * If no port number given ask the pmap for one
2170 if (raddr
->sin_port
== 0) {
2172 if ((port
= pmap_getport_to(raddr
, prog
, vers
,
2173 IPPROTO_UDP
, timeout
,
2177 raddr
->sin_port
= htons(port
);
2180 sock
= socket(AF_INET
, proto
== IPPROTO_UDP
? SOCK_DGRAM
: SOCK_STREAM
,
2185 (void)bindresvport(sock
, (struct sockaddr_in
*)0);
2186 setsockopt(sock
, SOL_SOCKET
, SO_REUSEPORT
, &reuse
, sizeof(int));
2187 if (proto
== IPPROTO_TCP
) {
2188 if (connect(sock
, (struct sockaddr
*)raddr
,
2189 sizeof(*raddr
)) < 0) {