]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ypserv/yp_dblookup.c
typo in connect(2) error handling.
[FreeBSD/FreeBSD.git] / usr.sbin / ypserv / yp_dblookup.c
1 /*
2  * Copyright (c) 1995
3  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #ifndef lint
34 static const char rcsid[] =
35   "$FreeBSD$";
36 #endif /* not lint */
37
38 #include <db.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <limits.h>
42 #include <paths.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <sys/stat.h>
48 #include <sys/param.h>
49 #include <rpcsvc/yp.h>
50 #include "yp_extern.h"
51
52 int ypdb_debug = 0;
53 enum ypstat yp_errno = YP_TRUE;
54
55 #define PERM_SECURE (S_IRUSR|S_IWUSR)
56 HASHINFO openinfo = {
57         4096,           /* bsize */
58         32,             /* ffactor */
59         256,            /* nelem */
60         2048 * 512,     /* cachesize */
61         NULL,           /* hash */
62         0,              /* lorder */
63 };
64
65 #ifdef DB_CACHE
66 #include <sys/queue.h>
67
68 #ifndef MAXDBS
69 #define MAXDBS 20
70 #endif
71
72 static int numdbs = 0;
73
74 struct dbent {
75         DB *dbp;
76         char *name;
77         char *key;
78         int size;
79         int flags;
80 };
81
82 static TAILQ_HEAD(circlehead, circleq_entry) qhead;
83
84 struct circleq_entry {
85         struct dbent *dbptr;
86         TAILQ_ENTRY(circleq_entry) links;
87 };
88
89 /*
90  * Initialize the circular queue.
91  */
92 void
93 yp_init_dbs(void)
94 {
95         TAILQ_INIT(&qhead);
96         return;
97 }
98
99 /*
100  * Dynamically allocate an entry for the circular queue.
101  * Return a NULL pointer on failure.
102  */
103 static struct circleq_entry *
104 yp_malloc_qent(void)
105 {
106         register struct circleq_entry *q;
107
108         q = (struct circleq_entry *)malloc(sizeof(struct circleq_entry));
109         if (q == NULL) {
110                 yp_error("failed to malloc() circleq entry");
111                 return(NULL);
112         }
113         bzero((char *)q, sizeof(struct circleq_entry));
114         q->dbptr = (struct dbent *)malloc(sizeof(struct dbent));
115         if (q->dbptr == NULL) {
116                 yp_error("failed to malloc() circleq entry");
117                 free(q);
118                 return(NULL);
119         }
120         bzero((char *)q->dbptr, sizeof(struct dbent));
121
122         return(q);
123 }
124
125 /*
126  * Free a previously allocated circular queue
127  * entry.
128  */
129 static void
130 yp_free_qent(struct circleq_entry *q)
131 {
132         /*
133          * First, close the database. In theory, this is also
134          * supposed to free the resources allocated by the DB
135          * package, including the memory pointed to by q->dbptr->key.
136          * This means we don't have to free q->dbptr->key here.
137          */
138         if (q->dbptr->dbp) {
139                 (void)(q->dbptr->dbp->close)(q->dbptr->dbp);
140                 q->dbptr->dbp = NULL;
141         }
142         /*
143          * Then free the database name, which was strdup()'ed.
144          */
145         free(q->dbptr->name);
146
147         /*
148          * Free the rest of the dbent struct.
149          */
150         free(q->dbptr);
151         q->dbptr = NULL;
152
153         /*
154          * Free the circleq struct.
155          */
156         free(q);
157         q = NULL;
158
159         return;
160 }
161
162 /*
163  * Zorch a single entry in the dbent queue and release
164  * all its resources. (This always removes the last entry
165  * in the queue.)
166  */
167 static void
168 yp_flush(void)
169 {
170         register struct circleq_entry *qptr;
171
172         qptr = TAILQ_LAST(&qhead, circlehead);
173         TAILQ_REMOVE(&qhead, qptr, links);
174         yp_free_qent(qptr);
175         numdbs--;
176
177         return;
178 }
179
180 /*
181  * Close all databases, erase all database names and empty the queue.
182  */
183 void
184 yp_flush_all(void)
185 {
186         register struct circleq_entry *qptr;
187
188         while (!TAILQ_EMPTY(&qhead)) {
189                 qptr = TAILQ_FIRST(&qhead); /* save this */
190                 TAILQ_REMOVE(&qhead, qptr, links);
191                 yp_free_qent(qptr);
192         }
193         numdbs = 0;
194
195         return;
196 }
197
198 static char *inter_string = "YP_INTERDOMAIN";
199 static char *secure_string = "YP_SECURE";
200 static int inter_sz = sizeof("YP_INTERDOMAIN") - 1;
201 static int secure_sz = sizeof("YP_SECURE") - 1;
202
203 static int
204 yp_setflags(DB *dbp)
205 {
206         DBT key = { NULL, 0 }, data = { NULL, 0 };
207         int flags = 0;
208
209         key.data = inter_string;
210         key.size = inter_sz;
211
212         if (!(dbp->get)(dbp, &key, &data, 0))
213                 flags |= YP_INTERDOMAIN;
214
215         key.data = secure_string;
216         key.size = secure_sz;
217
218         if (!(dbp->get)(dbp, &key, &data, 0))
219                 flags |= YP_SECURE;
220
221         return(flags);
222 }
223
224 int
225 yp_testflag(char *map, char *domain, int flag)
226 {
227         char buf[MAXPATHLEN + 2];
228         register struct circleq_entry *qptr;
229
230         if (map == NULL || domain == NULL)
231                 return(0);
232
233         strcpy(buf, domain);
234         strcat(buf, "/");
235         strcat(buf, map);
236
237         TAILQ_FOREACH(qptr, &qhead, links) {
238                 if (!strcmp(qptr->dbptr->name, buf)) {
239                         if (qptr->dbptr->flags & flag)
240                                 return(1);
241                         else
242                                 return(0);
243                 }
244         }
245
246         if (yp_open_db_cache(domain, map, NULL, 0) == NULL)
247                 return(0);
248
249         if (TAILQ_FIRST(&qhead)->dbptr->flags & flag)
250                 return(1);
251
252         return(0);
253 }
254
255 /*
256  * Add a DB handle and database name to the cache. We only maintain
257  * fixed number of entries in the cache, so if we're asked to store
258  * a new entry when all our slots are already filled, we have to kick
259  * out the entry in the last slot to make room.
260  */
261 static int
262 yp_cache_db(DB *dbp, char *name, int size)
263 {
264         register struct circleq_entry *qptr;
265
266         if (numdbs == MAXDBS) {
267                 if (ypdb_debug)
268                         yp_error("queue overflow -- releasing last slot");
269                 yp_flush();
270         }
271
272         /*
273          * Allocate a new queue entry.
274          */
275
276         if ((qptr = yp_malloc_qent()) == NULL) {
277                 yp_error("failed to allocate a new cache entry");
278                 return(1);
279         }
280
281         qptr->dbptr->dbp = dbp;
282         qptr->dbptr->name = strdup(name);
283         qptr->dbptr->size = size;
284         qptr->dbptr->key = NULL;
285
286         qptr->dbptr->flags = yp_setflags(dbp);
287
288         TAILQ_INSERT_HEAD(&qhead, qptr, links);
289         numdbs++;
290
291         return(0);
292 }
293
294 /*
295  * Search the list for a database matching 'name.' If we find it,
296  * move it to the head of the list and return its DB handle. If
297  * not, just fail: yp_open_db_cache() will subsequently try to open
298  * the database itself and call yp_cache_db() to add it to the
299  * list.
300  *
301  * The search works like this:
302  *
303  * - The caller specifies the name of a database to locate. We try to
304  *   find an entry in our queue with a matching name.
305  *
306  * - If the caller doesn't specify a key or size, we assume that the
307  *   first entry that we encounter with a matching name is returned.
308  *   This will result in matches regardless of the key/size values
309  *   stored in the queue entry.
310  *
311  * - If the caller also specifies a key and length, we check to see
312  *   if the key and length saved in the queue entry also matches.
313  *   This lets us return a DB handle that's already positioned at the
314  *   correct location within a database.
315  *
316  * - Once we have a match, it gets migrated to the top of the queue
317  *   so that it will be easier to find if another request for
318  *   the same database comes in later.
319  */
320 static DB *
321 yp_find_db(char *name, char *key, int size)
322 {
323         register struct circleq_entry *qptr;
324
325         TAILQ_FOREACH(qptr, &qhead, links) {
326                 if (!strcmp(qptr->dbptr->name, name)) {
327                         if (size) {
328                                 if (size != qptr->dbptr->size ||
329                                    strncmp(qptr->dbptr->key, key, size))
330                                         continue;
331                         } else {
332                                 if (qptr->dbptr->size)
333                                         continue;
334                         }
335                         if (qptr != TAILQ_FIRST(&qhead)) {
336                                 TAILQ_REMOVE(&qhead, qptr, links);
337                                 TAILQ_INSERT_HEAD(&qhead, qptr, links);
338                         }
339                         return(qptr->dbptr->dbp);
340                 }
341         }
342
343         return(NULL);
344 }
345
346 /*
347  * Open a DB database and cache the handle for later use. We first
348  * check the cache to see if the required database is already open.
349  * If so, we fetch the handle from the cache. If not, we try to open
350  * the database and save the handle in the cache for later use.
351  */
352 DB *
353 yp_open_db_cache(const char *domain, const char *map, const char *key,
354     const int size)
355 {
356         DB *dbp = NULL;
357         char buf[MAXPATHLEN + 2];
358 /*
359         snprintf(buf, sizeof(buf), "%s/%s", domain, map);
360 */
361         yp_errno = YP_TRUE;
362
363         strcpy(buf, domain);
364         strcat(buf, "/");
365         strcat(buf, map);
366
367         if ((dbp = yp_find_db((char *)&buf, key, size)) != NULL) {
368                 return(dbp);
369         } else {
370                 if ((dbp = yp_open_db(domain, map)) != NULL) {
371                         if (yp_cache_db(dbp, (char *)&buf, size)) {
372                                 (void)(dbp->close)(dbp);
373                                 yp_errno = YP_YPERR;
374                                 return(NULL);
375                         }
376                 }
377         }
378
379         return (dbp);
380 }
381 #endif
382
383 /*
384  * Open a DB database.
385  */
386 DB *
387 yp_open_db(const char *domain, const char *map)
388 {
389         DB *dbp = NULL;
390         char buf[MAXPATHLEN + 2];
391
392         yp_errno = YP_TRUE;
393
394         if (map[0] == '.' || strchr(map, '/')) {
395                 yp_errno = YP_BADARGS;
396                 return (NULL);
397         }
398
399 #ifdef DB_CACHE
400         if (yp_validdomain(domain)) {
401                 yp_errno = YP_NODOM;
402                 return(NULL);
403         }
404 #endif
405         snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, domain, map);
406
407 #ifdef DB_CACHE
408 again:
409 #endif
410         dbp = dbopen(buf,O_RDONLY, PERM_SECURE, DB_HASH, NULL);
411
412         if (dbp == NULL) {
413                 switch (errno) {
414 #ifdef DB_CACHE
415                 case ENFILE:
416                         /*
417                          * We ran out of file descriptors. Nuke an
418                          * open one and try again.
419                          */
420                         yp_error("ran out of file descriptors");
421                         yp_flush();
422                         goto again;
423                         break;
424 #endif
425                 case ENOENT:
426                         yp_errno = YP_NOMAP;
427                         break;
428                 case EFTYPE:
429                         yp_errno = YP_BADDB;
430                         break;
431                 default:
432                         yp_errno = YP_YPERR;
433                         break;
434                 }
435         }
436
437         return (dbp);
438 }
439
440 /*
441  * Database access routines.
442  *
443  * - yp_get_record(): retrieve an arbitrary key/data pair given one key
444  *                 to match against.
445  *
446  * - yp_first_record(): retrieve first key/data base in a database.
447  *
448  * - yp_next_record(): retrieve key/data pair that sequentially follows
449  *                   the supplied key value in the database.
450  */
451
452 #ifdef DB_CACHE
453 int
454 yp_get_record(DB *dbp, const DBT *key, DBT *data, int allow)
455 #else
456 int
457 yp_get_record(const char *domain, const char *map,
458     const DBT *key, DBT *data, int allow)
459 #endif
460 {
461 #ifndef DB_CACHE
462         DB *dbp;
463 #endif
464         int rval = 0;
465 #ifndef DB_CACHE
466         static unsigned char buf[YPMAXRECORD];
467 #endif
468
469         if (ypdb_debug)
470                 yp_error("looking up key [%.*s]",
471                           key->size, key->data);
472
473         /*
474          * Avoid passing back magic "YP_*" entries unless
475          * the caller specifically requested them by setting
476          * the 'allow' flag.
477          */
478         if (!allow && !strncmp(key->data, "YP_", 3))
479                 return(YP_NOKEY);
480
481 #ifndef DB_CACHE
482         if ((dbp = yp_open_db(domain, map)) == NULL) {
483                 return(yp_errno);
484         }
485 #endif
486
487         if ((rval = (dbp->get)(dbp, key, data, 0)) != 0) {
488 #ifdef DB_CACHE
489                 TAILQ_FIRST(&qhead)->dbptr->size = 0;
490 #else
491                 (void)(dbp->close)(dbp);
492 #endif
493                 if (rval == 1)
494                         return(YP_NOKEY);
495                 else
496                         return(YP_BADDB);
497         }
498
499         if (ypdb_debug)
500                 yp_error("result of lookup: key: [%.*s] data: [%.*s]",
501                          key->size, key->data, data->size, data->data);
502
503 #ifdef DB_CACHE
504         if (TAILQ_FIRST(&qhead)->dbptr->size) {
505                 TAILQ_FIRST(&qhead)->dbptr->key = "";
506                 TAILQ_FIRST(&qhead)->dbptr->size = 0;
507         }
508 #else
509         bcopy((char *)data->data, (char *)&buf, data->size);
510         data->data = (void *)&buf;
511         (void)(dbp->close)(dbp);
512 #endif
513
514         return(YP_TRUE);
515 }
516
517 int
518 yp_first_record(const DB *dbp, DBT *key, DBT *data, int allow)
519 {
520         int rval;
521 #ifndef DB_CACHE
522         static unsigned char buf[YPMAXRECORD];
523 #endif
524
525         if (ypdb_debug)
526                 yp_error("retrieving first key in map");
527
528         if ((rval = (dbp->seq)(dbp,key,data,R_FIRST)) != 0) {
529 #ifdef DB_CACHE
530                 TAILQ_FIRST(&qhead)->dbptr->size = 0;
531 #endif
532                 if (rval == 1)
533                         return(YP_NOKEY);
534                 else
535                         return(YP_BADDB);
536         }
537
538         /* Avoid passing back magic "YP_*" records. */
539         while (!strncmp(key->data, "YP_", 3) && !allow) {
540                 if ((rval = (dbp->seq)(dbp,key,data,R_NEXT)) != 0) {
541 #ifdef DB_CACHE
542                         TAILQ_FIRST(&qhead)->dbptr->size = 0;
543 #endif
544                         if (rval == 1)
545                                 return(YP_NOKEY);
546                         else
547                                 return(YP_BADDB);
548                 }
549         }
550
551         if (ypdb_debug)
552                 yp_error("result of lookup: key: [%.*s] data: [%.*s]",
553                          key->size, key->data, data->size, data->data);
554
555 #ifdef DB_CACHE
556         if (TAILQ_FIRST(&qhead)->dbptr->size) {
557                 TAILQ_FIRST(&qhead)->dbptr->key = key->data;
558                 TAILQ_FIRST(&qhead)->dbptr->size = key->size;
559         }
560 #else
561         bcopy((char *)data->data, (char *)&buf, data->size);
562         data->data = (void *)&buf;
563 #endif
564
565         return(YP_TRUE);
566 }
567
568 int
569 yp_next_record(const DB *dbp, DBT *key, DBT *data, int all, int allow)
570 {
571         static DBT lkey = { NULL, 0 };
572         static DBT ldata = { NULL, 0 };
573         int rval;
574 #ifndef DB_CACHE
575         static unsigned char keybuf[YPMAXRECORD];
576         static unsigned char datbuf[YPMAXRECORD];
577 #endif
578
579         if (key == NULL || !key->size || key->data == NULL) {
580                 rval = yp_first_record(dbp,key,data,allow);
581                 if (rval == YP_NOKEY)
582                         return(YP_NOMORE);
583                 else {
584 #ifdef DB_CACHE
585                         TAILQ_FIRST(&qhead)->dbptr->key = key->data;
586                         TAILQ_FIRST(&qhead)->dbptr->size = key->size;
587 #endif
588                         return(rval);
589                 }
590         }
591
592         if (ypdb_debug)
593                 yp_error("retrieving next key, previous was: [%.*s]",
594                           key->size, key->data);
595
596         if (!all) {
597 #ifdef DB_CACHE
598                 if (TAILQ_FIRST(&qhead)->dbptr->key == NULL) {
599 #endif
600                         (dbp->seq)(dbp,&lkey,&ldata,R_FIRST);
601                         while (key->size != lkey.size ||
602                             strncmp((char *)key->data, lkey.data,
603                             (int)key->size))
604                                 if ((dbp->seq)(dbp,&lkey,&ldata,R_NEXT)) {
605 #ifdef DB_CACHE
606                                         TAILQ_FIRST(&qhead)->dbptr->size = 0;
607 #endif
608                                         return(YP_NOKEY);
609                                 }
610
611 #ifdef DB_CACHE
612                 }
613 #endif
614         }
615
616         if ((dbp->seq)(dbp,key,data,R_NEXT)) {
617 #ifdef DB_CACHE
618                 TAILQ_FIRST(&qhead)->dbptr->size = 0;
619 #endif
620                 return(YP_NOMORE);
621         }
622
623         /* Avoid passing back magic "YP_*" records. */
624         while (!strncmp(key->data, "YP_", 3) && !allow)
625                 if ((dbp->seq)(dbp,key,data,R_NEXT)) {
626 #ifdef DB_CACHE
627                 TAILQ_FIRST(&qhead)->dbptr->size = 0;
628 #endif
629                         return(YP_NOMORE);
630                 }
631
632         if (ypdb_debug)
633                 yp_error("result of lookup: key: [%.*s] data: [%.*s]",
634                          key->size, key->data, data->size, data->data);
635
636 #ifdef DB_CACHE
637         if (TAILQ_FIRST(&qhead)->dbptr->size) {
638                 TAILQ_FIRST(&qhead)->dbptr->key = key->data;
639                 TAILQ_FIRST(&qhead)->dbptr->size = key->size;
640         }
641 #else
642         bcopy((char *)key->data, (char *)&keybuf, key->size);
643         lkey.data = (void *)&keybuf;
644         lkey.size = key->size;
645         bcopy((char *)data->data, (char *)&datbuf, data->size);
646         data->data = (void *)&datbuf;
647 #endif
648
649         return(YP_TRUE);
650 }
651
652 #ifdef DB_CACHE
653 /*
654  * Database glue functions.
655  */
656
657 static DB *yp_currmap_db = NULL;
658 static int yp_allow_db = 0;
659
660 ypstat
661 yp_select_map(char *map, char *domain, keydat *key, int allow)
662 {
663         if (key == NULL)
664                 yp_currmap_db = yp_open_db_cache(domain, map, NULL, 0);
665         else
666                 yp_currmap_db = yp_open_db_cache(domain, map,
667                                                  key->keydat_val,
668                                                  key->keydat_len);
669
670         yp_allow_db = allow;
671         return(yp_errno);
672 }
673
674 ypstat
675 yp_getbykey(keydat *key, valdat *val)
676 {
677         DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
678         ypstat rval;
679
680         db_key.data = key->keydat_val;
681         db_key.size = key->keydat_len;
682
683         rval = yp_get_record(yp_currmap_db,
684                                 &db_key, &db_val, yp_allow_db);
685
686         if (rval == YP_TRUE) {
687                 val->valdat_val = db_val.data;
688                 val->valdat_len = db_val.size;
689         }
690
691         return(rval);
692 }
693
694 ypstat
695 yp_firstbykey(keydat *key, valdat *val)
696 {
697         DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
698         ypstat rval;
699
700         rval = yp_first_record(yp_currmap_db, &db_key, &db_val, yp_allow_db);
701
702         if (rval == YP_TRUE) {
703                 key->keydat_val = db_key.data;
704                 key->keydat_len = db_key.size;
705                 val->valdat_val = db_val.data;
706                 val->valdat_len = db_val.size;
707         }
708
709         return(rval);
710 }
711
712 ypstat
713 yp_nextbykey(keydat *key, valdat *val)
714 {
715         DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
716         ypstat rval;
717
718         db_key.data = key->keydat_val;
719         db_key.size = key->keydat_len;
720
721         rval = yp_next_record(yp_currmap_db, &db_key, &db_val, 0, yp_allow_db);
722
723         if (rval == YP_TRUE) {
724                 key->keydat_val = db_key.data;
725                 key->keydat_len = db_key.size;
726                 val->valdat_val = db_val.data;
727                 val->valdat_len = db_val.size;
728         }
729
730         return(rval);
731 }
732 #endif