1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include <errno.h>
22: #include <fcntl.h>
23: #include <string.h>
24: #include <unistd.h>
25: #include <libintl.h>
26: #include <rpc/rpc.h>
27: #include <rpcsvc/nis.h>
28: #include <rpcsvc/yp.h>
29: #include <rpcsvc/ypclnt.h>
30: #include <rpcsvc/ypupd.h>
31: #include <sys/uio.h>
32: #include <bits/libc-lock.h>
33:
34:
35: #ifndef BINDINGDIR
36: # define BINDINGDIR "/var/yp/binding"
37: #endif
38:
39: struct dom_binding
40: {
41: struct dom_binding *dom_pnext;
42: char dom_domain[YPMAXDOMAIN + 1];
43: struct sockaddr_in dom_server_addr;
44: int dom_socket;
45: CLIENT *dom_client;
46: };
47: typedef struct dom_binding dom_binding;
48:
49: static const struct timeval RPCTIMEOUT = {25, 0};
50: static const struct timeval UDPTIMEOUT = {5, 0};
51: static int const MAXTRIES = 2;
52: static char ypdomainname[NIS_MAXNAMELEN + 1];
53: __libc_lock_define_initialized (static, ypbindlist_lock)
54: static dom_binding *ypbindlist = NULL;
55:
56:
57: static void
58: yp_bind_client_create (const char *domain, dom_binding *ysd,
59: struct ypbind_resp *ypbr)
60: {
61: ysd->dom_server_addr.sin_family = AF_INET;
62: memcpy (&ysd->dom_server_addr.sin_port,
63: ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
64: sizeof (ysd->dom_server_addr.sin_port));
65: memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
66: ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
67: sizeof (ysd->dom_server_addr.sin_addr.s_addr));
68: strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
69: ysd->dom_domain[YPMAXDOMAIN] = '\0';
70:
71: ysd->dom_socket = RPC_ANYSOCK;
72: ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
73: UDPTIMEOUT, &ysd->dom_socket);
74:
75: if (ysd->dom_client != NULL)
76: {
77:
78: if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
79: perror ("fcntl: F_SETFD");
80: }
81: }
82:
83: #if USE_BINDINGDIR
84: static void
85: yp_bind_file (const char *domain, dom_binding *ysd)
86: {
87: char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
88:
89: snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
90: int fd = open (path, O_RDONLY);
91: if (fd >= 0)
92: {
93:
94:
95:
96: struct ypbind_resp ypbr;
97:
98: if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
99: yp_bind_client_create (domain, ysd, &ypbr);
100:
101: close (fd);
102: }
103: }
104: #endif
105:
106: static int
107: yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
108: {
109: struct sockaddr_in clnt_saddr;
110: struct ypbind_resp ypbr;
111: int clnt_sock;
112: CLIENT *client;
113:
114: clnt_saddr.sin_family = AF_INET;
115: clnt_saddr.sin_port = 0;
116: clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
117: clnt_sock = RPC_ANYSOCK;
118: client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
119: &clnt_sock, 0, 0);
120: if (client == NULL)
121: return YPERR_YPBIND;
122:
123:
124:
125:
126: if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
127: {
128: clnt_destroy (client);
129: return YPERR_YPBIND;
130: }
131:
132: if (clnt_call (client, YPBINDPROC_DOMAIN,
133: (xdrproc_t) xdr_domainname, (caddr_t) &domain,
134: (xdrproc_t) xdr_ypbind_resp,
135: (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
136: {
137: clnt_destroy (client);
138: return YPERR_YPBIND;
139: }
140:
141: clnt_destroy (client);
142:
143: if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
144: {
145: fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
146: ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
147: return YPERR_DOMAIN;
148: }
149: memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
150:
151: yp_bind_client_create (domain, ysd, &ypbr);
152:
153: return YPERR_SUCCESS;
154: }
155:
156: static int
157: __yp_bind (const char *domain, dom_binding **ypdb)
158: {
159: dom_binding *ysd = NULL;
160: int is_new = 0;
161:
162: if (domain == NULL || domain[0] == '\0')
163: return YPERR_BADARGS;
164:
165: ysd = *ypdb;
166: while (ysd != NULL)
167: {
168: if (strcmp (domain, ysd->dom_domain) == 0)
169: break;
170: ysd = ysd->dom_pnext;
171: }
172:
173: if (ysd == NULL)
174: {
175: is_new = 1;
176: ysd = (dom_binding *) calloc (1, sizeof *ysd);
177: if (__builtin_expect (ysd == NULL, 0))
178: return YPERR_RESRC;
179: }
180:
181: #if USE_BINDINGDIR
182:
183: if (ysd->dom_client == NULL)
184: yp_bind_file (domain, ysd);
185: #endif
186:
187: if (ysd->dom_client == NULL)
188: {
189: int retval = yp_bind_ypbindprog (domain, ysd);
190: if (retval != YPERR_SUCCESS)
191: {
192: if (is_new)
193: free (ysd);
194: return retval;
195: }
196: }
197:
198: if (ysd->dom_client == NULL)
199: {
200: if (is_new)
201: free (ysd);
202: return YPERR_YPSERV;
203: }
204:
205: if (is_new)
206: {
207: ysd->dom_pnext = *ypdb;
208: *ypdb = ysd;
209: }
210:
211: return YPERR_SUCCESS;
212: }
213:
214: static void
215: __yp_unbind (dom_binding *ydb)
216: {
217: clnt_destroy (ydb->dom_client);
218: free (ydb);
219: }
220:
221: int
222: yp_bind (const char *indomain)
223: {
224: int status;
225:
226: __libc_lock_lock (ypbindlist_lock);
227:
228: status = __yp_bind (indomain, &ypbindlist);
229:
230: __libc_lock_unlock (ypbindlist_lock);
231:
232: return status;
233: }
234: libnsl_hidden_def (yp_bind)
235:
236: static void
237: yp_unbind_locked (const char *indomain)
238: {
239: dom_binding *ydbptr, *ydbptr2;
240:
241: ydbptr2 = NULL;
242: ydbptr = ypbindlist;
243:
244: while (ydbptr != NULL)
245: {
246: if (strcmp (ydbptr->dom_domain, indomain) == 0)
247: {
248: dom_binding *work;
249:
250: work = ydbptr;
251: if (ydbptr2 == NULL)
252: ypbindlist = ypbindlist->dom_pnext;
253: else
254: ydbptr2 = ydbptr->dom_pnext;
255: __yp_unbind (work);
256: break;
257: }
258: ydbptr2 = ydbptr;
259: ydbptr = ydbptr->dom_pnext;
260: }
261: }
262:
263: void
264: yp_unbind (const char *indomain)
265: {
266: __libc_lock_lock (ypbindlist_lock);
267:
268: yp_unbind_locked (indomain);
269:
270: __libc_lock_unlock (ypbindlist_lock);
271:
272: return;
273: }
274:
275: static int
276: __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
277: caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
278: int print_error)
279: {
280: enum clnt_stat result;
281:
282: result = clnt_call ((*ydb)->dom_client, prog,
283: xargs, req, xres, resp, RPCTIMEOUT);
284:
285: if (result != RPC_SUCCESS)
286: {
287:
288:
289: if (print_error)
290: clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
291:
292: return YPERR_RPC;
293: }
294:
295: return YPERR_SUCCESS;
296: }
297:
298: static int
299: do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
300: caddr_t req, xdrproc_t xres, caddr_t resp)
301: {
302: dom_binding *ydb;
303: int status;
304: int saved_errno = errno;
305:
306: status = YPERR_YPERR;
307:
308: __libc_lock_lock (ypbindlist_lock);
309: ydb = ypbindlist;
310: while (ydb != NULL)
311: {
312: if (strcmp (domain, ydb->dom_domain) == 0)
313: {
314: if (__yp_bind (domain, &ydb) == 0)
315: {
316:
317: status = __ypclnt_call (domain, prog, xargs, req, xres,
318: resp, &ydb, 0);
319: if (status == YPERR_SUCCESS)
320: {
321: __libc_lock_unlock (ypbindlist_lock);
322: __set_errno (saved_errno);
323: return status;
324: }
325: }
326:
327:
328: yp_unbind_locked (domain);
329:
330: break;
331: }
332: ydb = ydb->dom_pnext;
333: }
334: __libc_lock_unlock (ypbindlist_lock);
335:
336:
337:
338: ydb = NULL;
339: if (__yp_bind (domain, &ydb) == 0)
340: {
341: status = __ypclnt_call (domain, prog, xargs, req, xres,
342: resp, &ydb, 1);
343: __yp_unbind (ydb);
344: }
345:
346: #if USE_BINDINGDIR
347:
348:
349: if (status != YPERR_SUCCESS)
350: {
351: ydb = calloc (1, sizeof (dom_binding));
352: if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
353: {
354: status = __ypclnt_call (domain, prog, xargs, req, xres,
355: resp, &ydb, 1);
356: __yp_unbind (ydb);
357: }
358: else
359: free (ydb);
360: }
361: #endif
362:
363: __set_errno (saved_errno);
364:
365: return status;
366: }
367:
368:
369: static int
370: do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
371: caddr_t req, xdrproc_t xres, caddr_t resp)
372: {
373: int status = do_ypcall (domain, prog, xargs, req, xres, resp);
374: if (status == YPERR_SUCCESS)
375:
376:
377:
378:
379: status = ypprot_err (((struct ypresp_val *) resp)->stat);
380: return status;
381: }
382:
383:
384: __libc_lock_define_initialized (static, domainname_lock)
385:
386: int
387: yp_get_default_domain (char **outdomain)
388: {
389: int result = YPERR_SUCCESS;;
390: *outdomain = NULL;
391:
392: __libc_lock_lock (domainname_lock);
393:
394: if (ypdomainname[0] == '\0')
395: {
396: if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
397: result = YPERR_NODOM;
398: else if (strcmp (ypdomainname, "(none)") == 0)
399: {
400:
401: ypdomainname[0] = '\0';
402: result = YPERR_NODOM;
403: }
404: else
405: *outdomain = ypdomainname;
406: }
407: else
408: *outdomain = ypdomainname;
409:
410: __libc_lock_unlock (domainname_lock);
411:
412: return result;
413: }
414: libnsl_hidden_def (yp_get_default_domain)
415:
416: int
417: __yp_check (char **domain)
418: {
419: char *unused;
420:
421: if (ypdomainname[0] == '\0')
422: if (yp_get_default_domain (&unused))
423: return 0;
424:
425: if (domain)
426: *domain = ypdomainname;
427:
428: if (yp_bind (ypdomainname) == 0)
429: return 1;
430: return 0;
431: }
432:
433: int
434: yp_match (const char *indomain, const char *inmap, const char *inkey,
435: const int inkeylen, char **outval, int *outvallen)
436: {
437: ypreq_key req;
438: ypresp_val resp;
439: enum clnt_stat result;
440:
441: if (indomain == NULL || indomain[0] == '\0' ||
442: inmap == NULL || inmap[0] == '\0' ||
443: inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
444: return YPERR_BADARGS;
445:
446: req.domain = (char *) indomain;
447: req.map = (char *) inmap;
448: req.key.keydat_val = (char *) inkey;
449: req.key.keydat_len = inkeylen;
450:
451: *outval = NULL;
452: *outvallen = 0;
453: memset (&resp, '\0', sizeof (resp));
454:
455: result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
456: (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
457: (caddr_t) &resp);
458:
459: if (result != YPERR_SUCCESS)
460: return result;
461:
462: *outvallen = resp.val.valdat_len;
463: *outval = malloc (*outvallen + 1);
464: int status = YPERR_RESRC;
465: if (__builtin_expect (*outval != NULL, 1))
466: {
467: memcpy (*outval, resp.val.valdat_val, *outvallen);
468: (*outval)[*outvallen] = '\0';
469: status = YPERR_SUCCESS;
470: }
471:
472: xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
473:
474: return status;
475: }
476:
477: int
478: yp_first (const char *indomain, const char *inmap, char **outkey,
479: int *outkeylen, char **outval, int *outvallen)
480: {
481: ypreq_nokey req;
482: ypresp_key_val resp;
483: enum clnt_stat result;
484:
485: if (indomain == NULL || indomain[0] == '\0' ||
486: inmap == NULL || inmap[0] == '\0')
487: return YPERR_BADARGS;
488:
489: req.domain = (char *) indomain;
490: req.map = (char *) inmap;
491:
492: *outkey = *outval = NULL;
493: *outkeylen = *outvallen = 0;
494: memset (&resp, '\0', sizeof (resp));
495:
496: result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
497: (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
498: (caddr_t) &resp);
499:
500: if (result != RPC_SUCCESS)
501: return YPERR_RPC;
502: if (resp.stat != YP_TRUE)
503: return ypprot_err (resp.stat);
504:
505: int status;
506: if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
507: && (*outval = malloc (resp.val.valdat_len
508: + 1)) != NULL, 1))
509: {
510: *outkeylen = resp.key.keydat_len;
511: memcpy (*outkey, resp.key.keydat_val, *outkeylen);
512: (*outkey)[*outkeylen] = '\0';
513:
514: *outvallen = resp.val.valdat_len;
515: memcpy (*outval, resp.val.valdat_val, *outvallen);
516: (*outval)[*outvallen] = '\0';
517:
518: status = YPERR_SUCCESS;
519: }
520: else
521: {
522: free (*outkey);
523: status = YPERR_RESRC;
524: }
525:
526: xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
527:
528: return status;
529: }
530:
531: int
532: yp_next (const char *indomain, const char *inmap, const char *inkey,
533: const int inkeylen, char **outkey, int *outkeylen, char **outval,
534: int *outvallen)
535: {
536: ypreq_key req;
537: ypresp_key_val resp;
538: enum clnt_stat result;
539:
540: if (indomain == NULL || indomain[0] == '\0' ||
541: inmap == NULL || inmap[0] == '\0' ||
542: inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
543: return YPERR_BADARGS;
544:
545: req.domain = (char *) indomain;
546: req.map = (char *) inmap;
547: req.key.keydat_val = (char *) inkey;
548: req.key.keydat_len = inkeylen;
549:
550: *outkey = *outval = NULL;
551: *outkeylen = *outvallen = 0;
552: memset (&resp, '\0', sizeof (resp));
553:
554: result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
555: (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
556: (caddr_t) &resp);
557:
558: if (result != YPERR_SUCCESS)
559: return result;
560:
561: int status;
562: if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
563: && (*outval = malloc (resp.val.valdat_len
564: + 1)) != NULL, 1))
565: {
566: *outkeylen = resp.key.keydat_len;
567: memcpy (*outkey, resp.key.keydat_val, *outkeylen);
568: (*outkey)[*outkeylen] = '\0';
569:
570: *outvallen = resp.val.valdat_len;
571: memcpy (*outval, resp.val.valdat_val, *outvallen);
572: (*outval)[*outvallen] = '\0';
573:
574: status = YPERR_SUCCESS;
575: }
576: else
577: {
578: free (*outkey);
579: status = YPERR_RESRC;
580: }
581:
582: xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
583:
584: return status;
585: }
586:
587: int
588: yp_master (const char *indomain, const char *inmap, char **outname)
589: {
590: ypreq_nokey req;
591: ypresp_master resp;
592: enum clnt_stat result;
593:
594: if (indomain == NULL || indomain[0] == '\0' ||
595: inmap == NULL || inmap[0] == '\0')
596: return YPERR_BADARGS;
597:
598: req.domain = (char *) indomain;
599: req.map = (char *) inmap;