1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  *	ns_generic.c
23  *
24  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #include <stdio.h>
29 #include <syslog.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <nsswitch.h>
33 #include <sys/param.h>
34 #include <netdb.h>
35 #include <errno.h>
36 #include <assert.h>
37 #include <rpc/rpc.h>
38 #include <rpcsvc/nfs_prot.h>
39 #include "automount.h"
40 
41 /*
42  * Each name service is represented by a ns_info structure.
43  */
44 struct ns_info {
45 	char	*ns_name;		/* service name */
46 	void	(*ns_init)();		/* initialization routine */
47 	int	(*ns_getmapent)();	/* get map entry given key */
48 	int	(*ns_loadmaster)();	/* load master map */
49 	int	(*ns_loaddirect)();	/* load direct map */
50 	int	(*ns_getmapkeys)();	/* readdir */
51 };
52 
53 static struct ns_info ns_info[] = {
54 
55 	"files",   init_files,  getmapent_files,
56 	loadmaster_files, loaddirect_files,
57 	getmapkeys_files,
58 
59 	"ldap",   init_ldap,  getmapent_ldap,
60 	loadmaster_ldap, loaddirect_ldap,
61 	getmapkeys_ldap,
62 
63 	"nis",	   init_nis,	getmapent_nis,
64 	loadmaster_nis,   loaddirect_nis,
65 	getmapkeys_nis,
66 
67 	NULL, NULL, NULL, NULL, NULL, NULL, NULL
68 };
69 
70 static struct ns_info *get_next_ns(struct __nsw_lookup **, int);
71 
72 void
ns_setup(char ** stack,char *** stkptr)73 ns_setup(char **stack, char ***stkptr)
74 {
75 	struct ns_info *nsp;
76 
77 	for (nsp = ns_info; nsp->ns_name; nsp++) {
78 		nsp->ns_init(stack, stkptr);
79 	}
80 }
81 
82 static struct ns_info *
get_next_ns(curr_ns,curr_nserr)83 get_next_ns(curr_ns, curr_nserr)
84 	struct __nsw_lookup **curr_ns;
85 	int curr_nserr;
86 {
87 	static struct __nsw_switchconfig *conf = NULL;
88 	enum __nsw_parse_err pserr;
89 	struct __nsw_lookup *lkp;
90 	struct ns_info *nsp;
91 
92 	if (conf == NULL) {
93 		/* __nsw_getconfig() is protected by a lock */
94 		conf = __nsw_getconfig("automount", &pserr);
95 		if (conf == NULL) {
96 			return (NULL);
97 		}
98 	}
99 
100 	if (*curr_ns == NULL)
101 		/* first time */
102 		lkp = conf->lookups;
103 	else {
104 		lkp = *curr_ns;
105 		/* __NSW_ACTION is MT-Safe */
106 		if (__NSW_ACTION(lkp, curr_nserr) == __NSW_RETURN)
107 			return (NULL);
108 		lkp = lkp->next;
109 	}
110 
111 	for (; lkp; lkp = lkp->next) {
112 		for (nsp = ns_info; nsp->ns_name; nsp++) {
113 			if (strcmp(lkp->service_name, nsp->ns_name) == 0) {
114 				*curr_ns = lkp;
115 				return (nsp);
116 			}
117 		}
118 		/*
119 		 * Note: if we get here then we've found
120 		 * an unsupported name service.
121 		 */
122 	}
123 
124 	return (NULL);
125 }
126 
127 int
getmapent(key,mapname,ml,stack,stkptr,iswildcard,isrestricted)128 getmapent(key, mapname, ml, stack, stkptr, iswildcard, isrestricted)
129 	char *key, *mapname;
130 	struct mapline *ml;
131 	char **stack, ***stkptr;
132 	bool_t *iswildcard;
133 	bool_t isrestricted;
134 {
135 	struct __nsw_lookup *curr_ns = NULL;
136 	int ns_err = __NSW_SUCCESS;
137 	struct ns_info *nsp;
138 
139 	if (strcmp(mapname, "-hosts") == 0) {
140 		(void) strcpy(ml->linebuf, "-hosts");
141 		return (__NSW_SUCCESS);
142 	}
143 
144 	if (*mapname == '/') 		/* must be a file */
145 		return (getmapent_files(key, mapname, ml, stack, stkptr,
146 					iswildcard, isrestricted));
147 
148 	while ((nsp = get_next_ns(&curr_ns, ns_err)) != NULL) {
149 		ns_err = nsp->ns_getmapent(key, mapname, ml, stack, stkptr,
150 						iswildcard, isrestricted);
151 		if (ns_err == __NSW_SUCCESS)
152 			return (__NSW_SUCCESS);
153 	}
154 
155 	return (__NSW_UNAVAIL);
156 }
157 
158 int
loadmaster_map(mapname,defopts,stack,stkptr)159 loadmaster_map(mapname, defopts, stack, stkptr)
160 	char *mapname, *defopts;
161 	char **stack, ***stkptr;
162 {
163 	struct __nsw_lookup *curr_ns = NULL;
164 	int ns_err = __NSW_SUCCESS;
165 	struct ns_info *nsp;
166 
167 	if (*mapname == '/')		/* must be a file */
168 		return (loadmaster_files(mapname, defopts, stack, stkptr));
169 
170 	while ((nsp = get_next_ns(&curr_ns, ns_err)) != NULL) {
171 		ns_err = nsp->ns_loadmaster(mapname, defopts, stack, stkptr);
172 		if (ns_err == __NSW_SUCCESS)
173 			return (__NSW_SUCCESS);
174 	}
175 
176 	return (__NSW_UNAVAIL);
177 }
178 
179 int
loaddirect_map(mapname,localmap,defopts,stack,stkptr)180 loaddirect_map(mapname, localmap, defopts, stack, stkptr)
181 	char *mapname, *localmap, *defopts;
182 	char **stack, ***stkptr;
183 {
184 	struct __nsw_lookup *curr_ns = NULL;
185 	int ns_err = __NSW_SUCCESS;
186 	struct ns_info *nsp;
187 
188 	if (*mapname == '/')		/* must be a file */
189 		return (loaddirect_files(mapname, localmap, defopts,
190 				stack, stkptr));
191 
192 	while ((nsp = get_next_ns(&curr_ns, ns_err)) != NULL) {
193 		ns_err = nsp->ns_loaddirect(mapname, localmap, defopts, stack,
194 					stkptr);
195 		if (ns_err == __NSW_SUCCESS)
196 			return (__NSW_SUCCESS);
197 	}
198 
199 	return (__NSW_UNAVAIL);
200 }
201 
202 int
gethostkeys(mapname,list,error,cache_time)203 gethostkeys(mapname, list, error, cache_time)
204 	char *mapname;
205 	struct dir_entry **list;
206 	int *error;
207 	int *cache_time;
208 {
209 	char *buffer, **p;
210 	int bufferlen = 1000;
211 	struct dir_entry *last = NULL;
212 	struct hostent ent;
213 
214 #ifdef lint
215 	mapname = mapname;
216 #endif
217 
218 	*cache_time = RDDIR_CACHE_TIME * 2;
219 	*error = 0;
220 	if (trace  > 1)
221 		trace_prt(1, "gethostkeys called\n");
222 
223 	if (sethostent(1)) {
224 		syslog(LOG_ERR, "gethostkeys: sethostent failed");
225 		*error = EIO;
226 		return (__NSW_UNAVAIL);
227 	}
228 
229 	buffer = (char *)malloc(bufferlen);
230 	if (buffer == NULL) {
231 		syslog(LOG_ERR, "gethostkeys: malloc of buffer failed");
232 		*error = ENOMEM;
233 		return (__NSW_UNAVAIL);
234 	}
235 
236 	while (gethostent_r(&ent, buffer, bufferlen, error)) {
237 		/*
238 		 * add canonical name
239 		 */
240 		if (add_dir_entry(ent.h_name, list, &last)) {
241 			*error = ENOMEM;
242 			goto done;
243 		}
244 		if (ent.h_aliases == NULL)
245 			goto done;	/* no aliases */
246 		for (p = ent.h_aliases; *p != 0; p++) {
247 			if (strcmp(*p, ent.h_name) != 0) {
248 				/*
249 				 * add alias only if different
250 				 * from canonical name
251 				 */
252 				if (add_dir_entry(*p, list, &last)) {
253 					*error = ENOMEM;
254 					goto done;
255 				}
256 			}
257 		}
258 		assert(last != NULL);
259 	}
260 done:	if (*list != NULL) {
261 		/*
262 		 * list of entries found
263 		 */
264 		*error = 0;
265 	}
266 	endhostent();
267 
268 	return (__NSW_SUCCESS);
269 }
270 
271 /*
272  * enumerate all entries in the map in the various name services.
273  */
274 int
getmapkeys(mapname,list,error,cache_time,stack,stkptr,uid)275 getmapkeys(mapname, list, error, cache_time, stack, stkptr, uid)
276 	char *mapname;
277 	struct dir_entry **list;
278 	int *error;
279 	int *cache_time;
280 	char **stack, ***stkptr;
281 	uid_t uid;
282 
283 {
284 	struct __nsw_lookup *curr_ns = NULL;
285 	int ns_err = __NSW_SUCCESS;
286 	int success = 0;
287 	struct ns_info *nsp;
288 
289 	if (*mapname == '/') 		/* must be a file */
290 		return (getmapkeys_files(mapname, list, error, cache_time,
291 				stack, stkptr));
292 	if (strcmp(mapname, "-hosts") == 0) {
293 		return (gethostkeys(mapname, list, error, cache_time));
294 	}
295 
296 	while ((nsp = get_next_ns(&curr_ns, ns_err)) != NULL) {
297 		ns_err = nsp->ns_getmapkeys(mapname, list, error,
298 				cache_time, stack, stkptr);
299 		if (*error == 0) {
300 			/*
301 			 * return success if listing was successful
302 			 * for at least one name service
303 			 */
304 			success++;
305 		}
306 
307 		/*
308 		 * XXX force next name service
309 		 */
310 		if (ns_err != __NSW_UNAVAIL)
311 			ns_err = __NSW_NOTFOUND;
312 	}
313 	if (success) {
314 		/*
315 		 * if succeeded at least once, return error=0
316 		 */
317 		*error = 0;
318 	};
319 
320 	return (success ? __NSW_SUCCESS : __NSW_NOTFOUND);
321 }
322