1 /*	$NetBSD: dict_nis.c,v 1.1.1.1 2009/06/23 10:08:59 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	dict_nis 3
6 /* SUMMARY
7 /*	dictionary manager interface to NIS maps
8 /* SYNOPSIS
9 /*	#include <dict_nis.h>
10 /*
11 /*	DICT	*dict_nis_open(map, open_flags, dict_flags)
12 /*	const char *map;
13 /*	int	open_flags;
14 /*	int	dict_flags;
15 /* DESCRIPTION
16 /*	dict_nis_open() makes the specified NIS map accessible via
17 /*	the generic dictionary operations described in dict_open(3).
18 /* SEE ALSO
19 /*	dict(3) generic dictionary manager
20 /* DIAGNOSTICS
21 /*	Fatal errors: out of memory, attempt to update NIS map.
22 /* LICENSE
23 /* .ad
24 /* .fi
25 /*	The Secure Mailer license must be distributed with this software.
26 /* AUTHOR(S)
27 /*	Wietse Venema
28 /*	IBM T.J. Watson Research
29 /*	P.O. Box 704
30 /*	Yorktown Heights, NY 10598, USA
31 /*--*/
32 
33 /* System library. */
34 
35 #include "sys_defs.h"
36 #include <string.h>
37 
38 #ifdef STRCASECMP_IN_STRINGS_H
39 #include <strings.h>
40 #endif
41 
42 #ifdef HAS_NIS
43 
44 #include <rpcsvc/ypclnt.h>
45 #ifndef YPERR_BUSY
46 #define YPERR_BUSY  16
47 #endif
48 #ifndef YPERR_ACCESS
49 #define YPERR_ACCESS  15
50 #endif
51 
52 #endif
53 
54 /* Utility library. */
55 
56 #include "msg.h"
57 #include "mymalloc.h"
58 #include "vstring.h"
59 #include "stringops.h"
60 #include "dict.h"
61 #include "dict_nis.h"
62 
63 #ifdef HAS_NIS
64 
65 /* Application-specific. */
66 
67 typedef struct {
68     DICT    dict;			/* generic members */
69 } DICT_NIS;
70 
71  /*
72   * Class variables, so that multiple maps can share this info.
73   */
74 static char dict_nis_disabled[1];
75 static char *dict_nis_domain;
76 
77 /* dict_nis_init - NIS binding */
78 
79 static void dict_nis_init(void)
80 {
81     const char *myname = "dict_nis_init";
82 
83     if (yp_get_default_domain(&dict_nis_domain) != 0
84 	|| dict_nis_domain == 0 || *dict_nis_domain == 0
85 	|| strcasecmp(dict_nis_domain, "(none)") == 0) {
86 	dict_nis_domain = dict_nis_disabled;
87 	msg_warn("%s: NIS domain name not set - NIS lookups disabled", myname);
88     }
89     if (msg_verbose)
90 	msg_info("%s: NIS domain %s", myname, dict_nis_domain);
91 }
92 
93 /* dict_nis_strerror - map error number to string */
94 
95 static char *dict_nis_strerror(int err)
96 {
97 
98     /*
99      * Grr. There should be a standard function for this.
100      */
101     switch (err) {
102 	case YPERR_BADARGS:
103 	return ("args to function are bad");
104     case YPERR_RPC:
105 	return ("RPC failure - domain has been unbound");
106     case YPERR_DOMAIN:
107 	return ("can't bind to server on this domain");
108     case YPERR_MAP:
109 	return ("no such map in server's domain");
110     case YPERR_KEY:
111 	return ("no such key in map");
112     case YPERR_YPERR:
113 	return ("internal yp server or client error");
114     case YPERR_RESRC:
115 	return ("resource allocation failure");
116     case YPERR_NOMORE:
117 	return ("no more records in map database");
118     case YPERR_PMAP:
119 	return ("can't communicate with portmapper");
120     case YPERR_YPBIND:
121 	return ("can't communicate with ypbind");
122     case YPERR_YPSERV:
123 	return ("can't communicate with ypserv");
124     case YPERR_NODOM:
125 	return ("local domain name not set");
126     case YPERR_BADDB:
127 	return ("yp database is bad");
128     case YPERR_VERS:
129 	return ("yp version mismatch");
130     case YPERR_ACCESS:
131 	return ("access violation");
132     case YPERR_BUSY:
133 	return ("database busy");
134     default:
135 	return ("unknown NIS lookup error");
136     }
137 }
138 
139 /* dict_nis_lookup - find table entry */
140 
141 static const char *dict_nis_lookup(DICT *dict, const char *key)
142 {
143     DICT_NIS *dict_nis = (DICT_NIS *) dict;
144     static char *result;
145     int     result_len;
146     int     err;
147     static VSTRING *buf;
148 
149     /*
150      * Sanity check.
151      */
152     if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
153 	msg_panic("dict_nis_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
154 
155     dict_errno = 0;
156     if (dict_nis_domain == dict_nis_disabled)
157 	return (0);
158 
159     /*
160      * Optionally fold the key.
161      */
162     if (dict->flags & DICT_FLAG_FOLD_FIX) {
163 	if (dict->fold_buf == 0)
164 	    dict->fold_buf = vstring_alloc(10);
165 	vstring_strcpy(dict->fold_buf, key);
166 	key = lowercase(vstring_str(dict->fold_buf));
167     }
168 
169     /*
170      * See if this NIS map was written with one null byte appended to key and
171      * value.
172      */
173     if (dict->flags & DICT_FLAG_TRY1NULL) {
174 	err = yp_match(dict_nis_domain, dict_nis->dict.name,
175 		       (void *) key, strlen(key) + 1,
176 		       &result, &result_len);
177 	if (err == 0) {
178 	    dict->flags &= ~DICT_FLAG_TRY0NULL;
179 	    return (result);
180 	}
181     }
182 
183     /*
184      * See if this NIS map was written with no null byte appended to key and
185      * value. This should never be the case, but better play safe.
186      */
187     if (dict->flags & DICT_FLAG_TRY0NULL) {
188 	err = yp_match(dict_nis_domain, dict_nis->dict.name,
189 		       (void *) key, strlen(key),
190 		       &result, &result_len);
191 	if (err == 0) {
192 	    dict->flags &= ~DICT_FLAG_TRY1NULL;
193 	    if (buf == 0)
194 		buf = vstring_alloc(10);
195 	    vstring_strncpy(buf, result, result_len);
196 	    return (vstring_str(buf));
197 	}
198     }
199 
200     /*
201      * When the NIS lookup fails for reasons other than "key not found", keep
202      * logging warnings, and hope that someone will eventually notice the
203      * problem and fix it.
204      */
205     if (err != YPERR_KEY) {
206 	msg_warn("lookup %s, NIS domain %s, map %s: %s",
207 		 key, dict_nis_domain, dict_nis->dict.name,
208 		 dict_nis_strerror(err));
209 	dict_errno = DICT_ERR_RETRY;
210     }
211     return (0);
212 }
213 
214 /* dict_nis_close - close NIS map */
215 
216 static void dict_nis_close(DICT *dict)
217 {
218     if (dict->fold_buf)
219 	vstring_free(dict->fold_buf);
220     dict_free(dict);
221 }
222 
223 /* dict_nis_open - open NIS map */
224 
225 DICT   *dict_nis_open(const char *map, int open_flags, int dict_flags)
226 {
227     DICT_NIS *dict_nis;
228 
229     if (open_flags != O_RDONLY)
230 	msg_fatal("%s:%s map requires O_RDONLY access mode",
231 		  DICT_TYPE_NIS, map);
232 
233     dict_nis = (DICT_NIS *) dict_alloc(DICT_TYPE_NIS, map, sizeof(*dict_nis));
234     dict_nis->dict.lookup = dict_nis_lookup;
235     dict_nis->dict.close = dict_nis_close;
236     dict_nis->dict.flags = dict_flags | DICT_FLAG_FIXED;
237     if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
238 	dict_nis->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
239     if (dict_flags & DICT_FLAG_FOLD_FIX)
240 	dict_nis->dict.fold_buf = vstring_alloc(10);
241     if (dict_nis_domain == 0)
242 	dict_nis_init();
243     return (DICT_DEBUG (&dict_nis->dict));
244 }
245 
246 #endif
247