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