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