yplib.c revision 1.2 1 #include <sys/param.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <sys/file.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <rpc/rpc.h>
9 #include <rpc/xdr.h>
10 #include <rpcsvc/yp_prot.h>
11 #include <rpcsvc/ypclnt.h>
12
13 #ifndef BINDINGDIR
14 #define BINDINGDIR "/var/yp/binding"
15 #endif
16 #define YPMATCHCACHE
17
18 extern bool_t xdr_domainname(), xdr_ypbind_resp();
19 extern bool_t xdr_ypreq_key(), xdr_ypresp_val();
20 extern bool_t xdr_ypreq_nokey(), xdr_ypresp_key_val();
21 extern bool_t xdr_ypresp_all(), xdr_ypresp_all_seq();
22 extern bool_t xdr_ypresp_master();
23
24 int (*ypresp_allfn)();
25 void *ypresp_data;
26
27 struct dom_binding *_ypbindlist;
28 static char _yp_domain[MAXHOSTNAMELEN];
29 int _yplib_timeout = 10;
30
31 #ifdef YPMATCHCACHE
32 int _yplib_cache = 5;
33
34 static struct ypmatch_ent {
35 struct ypmatch_ent *next;
36 char *map, *key, *val;
37 int keylen, vallen;
38 time_t expire_t;
39 } *ypmc;
40
41 static void
42 ypmatch_add(map, key, keylen, val, vallen)
43 char *map, *key, *val;
44 {
45 struct ypmatch_ent *ep;
46 time_t t;
47
48 time(&t);
49
50 for(ep=ypmc; ep; ep=ep->next)
51 if(ep->expire_t < t)
52 break;
53 if(ep==NULL) {
54 ep = (struct ypmatch_ent *)malloc(sizeof *ep);
55 bzero((char *)ep, sizeof *ep);
56 if(ypmc)
57 ep->next = ypmc;
58 ypmc = ep;
59 }
60
61 if(ep->key)
62 free(ep->key);
63 if(ep->val)
64 free(ep->val);
65
66 ep->key = NULL;
67 ep->val = NULL;
68
69 ep->key = (char *)malloc(keylen);
70 if(ep->key==NULL)
71 return;
72
73 ep->val = (char *)malloc(vallen);
74 if(ep->key==NULL) {
75 free(ep->key);
76 ep->key = NULL;
77 return;
78 }
79 ep->keylen = keylen;
80 ep->vallen = vallen;
81
82 bcopy(key, ep->key, ep->keylen);
83 bcopy(val, ep->val, ep->vallen);
84
85 if(ep->map) {
86 if( strcmp(ep->map, map) ) {
87 free(ep->map);
88 ep->map = strdup(map);
89 }
90 } else {
91 ep->map = strdup(map);
92 }
93
94 ep->expire_t = t + _yplib_cache;
95 }
96
97 static bool_t
98 ypmatch_find(map, key, keylen, val, vallen)
99 char *map, *key;
100 int keylen;
101 char **val;
102 int *vallen;
103 {
104 struct ypmatch_ent *ep;
105 time_t t;
106
107 if(ypmc==NULL)
108 return 0;
109
110 time(&t);
111
112 for(ep=ypmc; ep; ep=ep->next) {
113 if(ep->keylen != keylen)
114 continue;
115 if(strcmp(ep->map, map))
116 continue;
117 if(bcmp(ep->key, key, keylen))
118 continue;
119 if(t > ep->expire_t)
120 continue;
121
122 *val = ep->val;
123 *vallen = ep->vallen;
124 return 1;
125 }
126 return 0;
127 }
128 #endif
129
130 int
131 _yp_dobind(dom, ypdb)
132 char *dom;
133 struct dom_binding **ypdb;
134 {
135 static int pid = -1;
136 char path[MAXPATHLEN];
137 struct dom_binding *ysd, *ysd2;
138 struct ypbind_resp ypbr;
139 struct timeval tv;
140 struct sockaddr_in clnt_sin;
141 int clnt_sock, fd, gpid;
142 CLIENT *client;
143 int new=0, r;
144
145 gpid = getpid();
146 if( !(pid==-1 || pid==gpid) ) {
147 ysd = _ypbindlist;
148 while(ysd) {
149 if(ysd->dom_client)
150 clnt_destroy(ysd->dom_client);
151 ysd2 = ysd->dom_pnext;
152 free(ysd);
153 ysd = ysd2;
154 }
155 _ypbindlist = NULL;
156 }
157 pid = gpid;
158
159 if(ypdb!=NULL)
160 *ypdb = NULL;
161
162 if(dom==NULL || strlen(dom)==0)
163 return YPERR_BADARGS;
164
165 for(ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
166 if( strcmp(dom, ysd->dom_domain) == 0)
167 break;
168 if(ysd==NULL) {
169 ysd = (struct dom_binding *)malloc(sizeof *ysd);
170 bzero((char *)ysd, sizeof *ysd);
171 ysd->dom_socket = -1;
172 ysd->dom_vers = 0;
173 new = 1;
174 }
175 again:
176 #ifdef BINDINGDIR
177 if(ysd->dom_vers==0) {
178 sprintf(path, "%s/%s.%d", BINDINGDIR, dom, 2);
179 if( (fd=open(path, O_RDONLY)) == -1) {
180 /* no binding file, YP is dead. */
181 if(new)
182 free(ysd);
183 return YPERR_YPBIND;
184 }
185 if( flock(fd, LOCK_EX|LOCK_NB) == -1 && errno==EWOULDBLOCK) {
186 r = read(fd, &ysd->dom_server_addr, sizeof ysd->dom_server_addr);
187 if(r != sizeof ysd->dom_server_addr) {
188 close(fd);
189 ysd->dom_vers = -1;
190 goto again;
191 }
192 ysd->dom_server_port = ysd->dom_server_addr.sin_port;
193 close(fd);
194 goto gotit;
195 } else {
196 /* no lock on binding file, YP is dead. */
197 close(fd);
198 if(new)
199 free(ysd);
200 return YPERR_YPBIND;
201 }
202 }
203 #endif
204 if(ysd->dom_vers==-1 || ysd->dom_vers==0) {
205 bzero((char *)&clnt_sin, sizeof clnt_sin);
206 clnt_sin.sin_family = AF_INET;
207 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
208
209 clnt_sock = RPC_ANYSOCK;
210 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
211 0, 0);
212 if(client==NULL) {
213 clnt_pcreateerror("clnttcp_create");
214 if(new)
215 free(ysd);
216 return YPERR_YPBIND;
217 }
218
219 tv.tv_sec = _yplib_timeout;
220 tv.tv_usec = 0;
221 r = clnt_call(client, YPBINDPROC_DOMAIN,
222 xdr_domainname, dom, xdr_ypbind_resp, &ypbr, tv);
223 if(r != RPC_SUCCESS) {
224 fprintf(stderr,
225 "YP: server for domain %s not responding, still trying\n", dom);
226 clnt_destroy(client);
227 ysd->dom_vers = -1;
228 goto again;
229 }
230 clnt_destroy(client);
231
232 bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
233 ysd->dom_server_addr.sin_family = AF_INET;
234 ysd->dom_server_addr.sin_port =
235 ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
236 ysd->dom_server_addr.sin_addr.s_addr =
237 ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr;
238 ysd->dom_server_port =
239 ypbr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
240 gotit:
241 ysd->dom_vers = YPVERS;
242 strcpy(ysd->dom_domain, dom);
243 }
244
245 tv.tv_sec = _yplib_timeout/2;
246 tv.tv_usec = 0;
247 if(ysd->dom_client)
248 clnt_destroy(ysd->dom_client);
249 ysd->dom_socket = RPC_ANYSOCK;
250 ysd->dom_client = clntudp_create(&ysd->dom_server_addr,
251 YPPROG, YPVERS, tv, &ysd->dom_socket);
252 if(ysd->dom_client==NULL) {
253 clnt_pcreateerror("clntudp_create");
254 ysd->dom_vers = -1;
255 goto again;
256 }
257 if( fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
258 perror("fcntl: F_SETFD");
259
260 if(new) {
261 ysd->dom_pnext = _ypbindlist;
262 _ypbindlist = ysd;
263 }
264
265 if(ypdb!=NULL)
266 *ypdb = ysd;
267 return 0;
268 }
269
270 static void
271 _yp_unbind(ypb)
272 struct dom_binding *ypb;
273 {
274 clnt_destroy(ypb->dom_client);
275 ypb->dom_client = NULL;
276 ypb->dom_socket = -1;
277 }
278
279 int
280 yp_bind(dom)
281 char *dom;
282 {
283 return _yp_dobind(dom, NULL);
284 }
285
286 void
287 yp_unbind(dom)
288 char *dom;
289 {
290 struct dom_binding *ypb, *ypbp;
291
292 ypbp = NULL;
293 for(ypb=_ypbindlist; ypb; ypb=ypb->dom_pnext) {
294 if( strcmp(dom, ypb->dom_domain) == 0) {
295 clnt_destroy(ypb->dom_client);
296 if(ypbp)
297 ypbp->dom_pnext = ypb->dom_pnext;
298 else
299 _ypbindlist = ypb->dom_pnext;
300 free(ypb);
301 return;
302 }
303 ypbp = ypb;
304 }
305 return;
306 }
307
308 int
309 yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen)
310 char *indomain;
311 char *inmap;
312 char *inkey;
313 int inkeylen;
314 char **outval;
315 int *outvallen;
316 {
317 struct dom_binding *ysd;
318 struct ypresp_val yprv;
319 struct timeval tv;
320 struct ypreq_key yprk;
321 int r;
322
323 *outval = NULL;
324 *outvallen = 0;
325
326 again:
327 if( _yp_dobind(indomain, &ysd) != 0)
328 return YPERR_DOMAIN;
329
330 #ifdef YPMATCHCACHE
331 if( !strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
332 inkeylen, &yprv.valdat.dptr, &yprv.valdat.dsize)) {
333 *outvallen = yprv.valdat.dsize;
334 *outval = (char *)malloc(*outvallen+1);
335 bcopy(yprv.valdat.dptr, *outval, *outvallen);
336 (*outval)[*outvallen] = '\0';
337 return 0;
338 }
339 #endif
340
341 tv.tv_sec = _yplib_timeout;
342 tv.tv_usec = 0;
343
344 yprk.domain = indomain;
345 yprk.map = inmap;
346 yprk.keydat.dptr = inkey;
347 yprk.keydat.dsize = inkeylen;
348
349 bzero((char *)&yprv, sizeof yprv);
350
351 r = clnt_call(ysd->dom_client, YPPROC_MATCH,
352 xdr_ypreq_key, &yprk, xdr_ypresp_val, &yprv, tv);
353 if(r != RPC_SUCCESS) {
354 clnt_perror(ysd->dom_client, "yp_match: clnt_call");
355 ysd->dom_vers = -1;
356 goto again;
357 }
358 if( !(r=ypprot_err(yprv.status)) ) {
359 *outvallen = yprv.valdat.dsize;
360 *outval = (char *)malloc(*outvallen+1);
361 bcopy(yprv.valdat.dptr, *outval, *outvallen);
362 (*outval)[*outvallen] = '\0';
363 #ifdef YPMATCHCACHE
364 if( strcmp(_yp_domain, indomain)==0 )
365 ypmatch_add(inmap, inkey, inkeylen, *outval, *outvallen);
366 #endif
367 }
368 xdr_free(xdr_ypresp_val, &yprv);
369 _yp_unbind(ysd);
370 return r;
371 }
372
373 int
374 yp_get_default_domain(domp)
375 char **domp;
376 {
377 *domp = NULL;
378 if(_yp_domain[0] == '\0')
379 if( getdomainname(_yp_domain, sizeof _yp_domain))
380 return YPERR_NODOM;
381 *domp = _yp_domain;
382 return 0;
383 }
384
385 int
386 yp_first(indomain, inmap, outkey, outkeylen, outval, outvallen)
387 char *indomain;
388 char *inmap;
389 char **outkey;
390 int *outkeylen;
391 char **outval;
392 int *outvallen;
393 {
394 struct ypresp_key_val yprkv;
395 struct ypreq_nokey yprnk;
396 struct dom_binding *ysd;
397 struct timeval tv;
398 int r;
399
400 *outkey = *outval = NULL;
401 *outkeylen = *outvallen = 0;
402
403 again:
404 if( _yp_dobind(indomain, &ysd) != 0)
405 return YPERR_DOMAIN;
406
407 tv.tv_sec = _yplib_timeout;
408 tv.tv_usec = 0;
409
410 yprnk.domain = indomain;
411 yprnk.map = inmap;
412 bzero((char *)&yprkv, sizeof yprkv);
413
414 r = clnt_call(ysd->dom_client, YPPROC_FIRST,
415 xdr_ypreq_nokey, &yprnk, xdr_ypresp_key_val, &yprkv, tv);
416 if(r != RPC_SUCCESS) {
417 clnt_perror(ysd->dom_client, "yp_first: clnt_call");
418 ysd->dom_vers = -1;
419 goto again;
420 }
421 if( !(r=ypprot_err(yprkv.status)) ) {
422 *outkeylen = yprkv.keydat.dsize;
423 *outkey = (char *)malloc(*outkeylen+1);
424 bcopy(yprkv.keydat.dptr, *outkey, *outkeylen);
425 (*outkey)[*outkeylen] = '\0';
426 *outvallen = yprkv.valdat.dsize;
427 *outval = (char *)malloc(*outvallen+1);
428 bcopy(yprkv.valdat.dptr, *outval, *outvallen);
429 (*outval)[*outvallen] = '\0';
430 }
431 xdr_free(xdr_ypresp_key_val, &yprkv);
432 _yp_unbind(ysd);
433 return r;
434 }
435
436 int
437 yp_next(indomain, inmap, inkey, inkeylen, outkey, outkeylen, outval, outvallen)
438 char *indomain;
439 char *inmap;
440 char *inkey;
441 int inkeylen;
442 char **outkey;
443 int *outkeylen;
444 char **outval;
445 int *outvallen;
446 {
447 struct ypresp_key_val yprkv;
448 struct ypreq_key yprk;
449 struct dom_binding *ysd;
450 struct timeval tv;
451 int r;
452
453 *outkey = *outval = NULL;
454 *outkeylen = *outvallen = 0;
455
456 again:
457 if( _yp_dobind(indomain, &ysd) != 0)
458 return YPERR_DOMAIN;
459
460 tv.tv_sec = _yplib_timeout;
461 tv.tv_usec = 0;
462
463 yprk.domain = indomain;
464 yprk.map = inmap;
465 yprk.keydat.dptr = inkey;
466 yprk.keydat.dsize = inkeylen;
467 bzero((char *)&yprkv, sizeof yprkv);
468
469 r = clnt_call(ysd->dom_client, YPPROC_NEXT,
470 xdr_ypreq_key, &yprk, xdr_ypresp_key_val, &yprkv, tv);
471 if(r != RPC_SUCCESS) {
472 clnt_perror(ysd->dom_client, "yp_next: clnt_call");
473 ysd->dom_vers = -1;
474 goto again;
475 }
476 if( !(r=ypprot_err(yprkv.status)) ) {
477 *outkeylen = yprkv.keydat.dsize;
478 *outkey = (char *)malloc(*outkeylen+1);
479 bcopy(yprkv.keydat.dptr, *outkey, *outkeylen);
480 (*outkey)[*outkeylen] = '\0';
481 *outvallen = yprkv.valdat.dsize;
482 *outval = (char *)malloc(*outvallen+1);
483 bcopy(yprkv.valdat.dptr, *outval, *outvallen);
484 (*outval)[*outvallen] = '\0';
485 }
486 xdr_free(xdr_ypresp_key_val, &yprkv);
487 _yp_unbind(ysd);
488 return r;
489 }
490
491 int
492 yp_all(indomain, inmap, incallback)
493 char *indomain;
494 char *inmap;
495 struct ypall_callback *incallback;
496 {
497 struct ypreq_nokey yprnk;
498 struct dom_binding *ysd;
499 struct timeval tv;
500 struct sockaddr_in clnt_sin;
501 CLIENT *clnt;
502 u_long status;
503 int clnt_sock;
504
505 if( _yp_dobind(indomain, &ysd) != 0)
506 return YPERR_DOMAIN;
507
508 tv.tv_sec = _yplib_timeout;
509 tv.tv_usec = 0;
510 clnt_sock = RPC_ANYSOCK;
511 clnt_sin = ysd->dom_server_addr;
512 clnt_sin.sin_port = 0;
513 clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
514 if(clnt==NULL) {
515 printf("clnttcp_create failed\n");
516 return YPERR_PMAP;
517 }
518
519 yprnk.domain = indomain;
520 yprnk.map = inmap;
521 ypresp_allfn = incallback->foreach;
522 ypresp_data = (void *)incallback->data;
523
524 (void) clnt_call(clnt, YPPROC_ALL,
525 xdr_ypreq_nokey, &yprnk, xdr_ypresp_all_seq, &status, tv);
526 clnt_destroy(clnt);
527 xdr_free(xdr_ypresp_all_seq, &status); /* NOT NEEDED */
528 _yp_unbind(ysd);
529
530 if(status != YP_FALSE)
531 return ypprot_err(status);
532 return 0;
533 }
534
535 int
536 yp_order(indomain, inmap, outorder)
537 char *indomain;
538 char *inmap;
539 int *outorder;
540 {
541 struct dom_binding *ysd;
542 struct ypresp_order ypro;
543 struct ypreq_nokey yprnk;
544 struct timeval tv;
545 int r;
546
547 again:
548 if( _yp_dobind(indomain, &ysd) != 0)
549 return YPERR_DOMAIN;
550
551 tv.tv_sec = _yplib_timeout;
552 tv.tv_usec = 0;
553
554 yprnk.domain = indomain;
555 yprnk.map = inmap;
556
557 bzero((char *)(char *)&ypro, sizeof ypro);
558
559 r = clnt_call(ysd->dom_client, YPPROC_ORDER,
560 xdr_ypreq_nokey, &yprnk, xdr_ypresp_order, &ypro, tv);
561 if(r != RPC_SUCCESS) {
562 clnt_perror(ysd->dom_client, "yp_order: clnt_call");
563 ysd->dom_vers = -1;
564 goto again;
565 }
566
567 *outorder = ypro.ordernum;
568 xdr_free(xdr_ypresp_order, &ypro);
569 _yp_unbind(ysd);
570 return ypprot_err(ypro.status);
571 }
572
573 yp_master(indomain, inmap, outname)
574 char *indomain;
575 char *inmap;
576 char **outname;
577 {
578 struct dom_binding *ysd;
579 struct ypresp_master yprm;
580 struct ypreq_nokey yprnk;
581 struct timeval tv;
582 int r;
583
584 again:
585 if( _yp_dobind(indomain, &ysd) != 0)
586 return YPERR_DOMAIN;
587
588 tv.tv_sec = _yplib_timeout;
589 tv.tv_usec = 0;
590
591 yprnk.domain = indomain;
592 yprnk.map = inmap;
593
594 bzero((char *)&yprm, sizeof yprm);
595
596 r = clnt_call(ysd->dom_client, YPPROC_MASTER,
597 xdr_ypreq_nokey, &yprnk, xdr_ypresp_master, &yprm, tv);
598 if(r != RPC_SUCCESS) {
599 clnt_perror(ysd->dom_client, "yp_master: clnt_call");
600 ysd->dom_vers = -1;
601 goto again;
602 }
603 if( !(r=ypprot_err(yprm.status)) ) {
604 *outname = (char *)strdup(yprm.master);
605 }
606 xdr_free(xdr_ypresp_master, &yprm);
607 _yp_unbind(ysd);
608 return r;
609 }
610
611 yp_maplist(indomain, outmaplist)
612 char *indomain;
613 struct ypmaplist **outmaplist;
614 {
615 struct dom_binding *ysd;
616 struct ypresp_maplist ypml;
617 struct timeval tv;
618 int r;
619
620 again:
621 if( _yp_dobind(indomain, &ysd) != 0)
622 return YPERR_DOMAIN;
623
624 tv.tv_sec = _yplib_timeout;
625 tv.tv_usec = 0;
626
627 bzero((char *)&ypml, sizeof ypml);
628
629 r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
630 xdr_domainname, indomain, xdr_ypresp_maplist, &ypml, tv);
631 if (r != RPC_SUCCESS) {
632 clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
633 ysd->dom_vers = -1;
634 goto again;
635 }
636 *outmaplist = ypml.list;
637 /* NO: xdr_free(xdr_ypresp_maplist, &ypml);*/
638 _yp_unbind(ysd);
639 return ypprot_err(ypml.status);
640 }
641
642 char *
643 yperr_string(incode)
644 int incode;
645 {
646 static char err[80];
647
648 switch(incode) {
649 case 0:
650 return "Success";
651 case YPERR_BADARGS:
652 return "Request arguments bad";
653 case YPERR_RPC:
654 return "RPC failure";
655 case YPERR_DOMAIN:
656 return "Can't bind to server which serves this domain";
657 case YPERR_MAP:
658 return "No such map in server's domain";
659 case YPERR_KEY:
660 return "No such key in map";
661 case YPERR_YPERR:
662 return "YP server error";
663 case YPERR_RESRC:
664 return "Local resource allocation failure";
665 case YPERR_NOMORE:
666 return "No more records in map database";
667 case YPERR_PMAP:
668 return "Can't communicate with portmapper";
669 case YPERR_YPBIND:
670 return "Can't communicate with ypbind";
671 case YPERR_YPSERV:
672 return "Can't communicate with ypserv";
673 case YPERR_NODOM:
674 return "Local domain name not set";
675 case YPERR_BADDB:
676 return "Server data base is bad";
677 case YPERR_VERS:
678 return "YP server version mismatch - server can't supply service.";
679 case YPERR_ACCESS:
680 return "Access violation";
681 case YPERR_BUSY:
682 return "Database is busy";
683 }
684 sprintf(err, "YP unknown error %d\n", incode);
685 return err;
686 }
687
688 int
689 ypprot_err(incode)
690 unsigned int incode;
691 {
692 switch(incode) {
693 case YP_TRUE:
694 return 0;
695 case YP_FALSE:
696 return YPERR_YPBIND;
697 case YP_NOMORE:
698 return YPERR_NOMORE;
699 case YP_NOMAP:
700 return YPERR_MAP;
701 case YP_NODOM:
702 return YPERR_NODOM;
703 case YP_NOKEY:
704 return YPERR_KEY;
705 case YP_BADOP:
706 return YPERR_YPERR;
707 case YP_BADDB:
708 return YPERR_BADDB;
709 case YP_YPERR:
710 return YPERR_YPERR;
711 case YP_BADARGS:
712 return YPERR_BADARGS;
713 case YP_VERS:
714 return YPERR_VERS;
715 }
716 return YPERR_YPERR;
717 }
718
719 int
720 _yp_check(dom)
721 char **dom;
722 {
723 int use_yp = 0;
724 char *unused;
725
726 if( _yp_domain[0]=='\0' )
727 if( yp_get_default_domain(&unused) )
728 return 0;
729
730 if(dom)
731 *dom = _yp_domain;
732
733 if( yp_bind(_yp_domain)==0 )
734 return 1;
735 return 0;
736 }
737