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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 *	ns_generic.c
24 *
25 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26 * Use is subject to license terms.
27 */
28
29/*
30 * Portions Copyright 2007-2011 Apple Inc.
31 */
32
33#pragma ident	"@(#)ns_generic.c	1.33	05/06/08 SMI"
34
35#include <stdio.h>
36#include <syslog.h>
37#include <string.h>
38#include <stdlib.h>
39#include <errno.h>
40#include <assert.h>
41#include <mntopts.h>
42#include "autofs.h"
43#include "automount.h"
44#include "auto_mntopts.h"
45
46/*
47 * Each name service is represented by a ns_info structure.
48 */
49struct ns_info {
50	char	*ns_name;		/* service name */
51	void	(*ns_init)(char **, char ***);
52					/* initialization routine */
53	int	(*ns_getmapent)(const char *, const char *, struct mapline *,
54		char **, char ***, bool_t *, bool_t);
55					/* get map entry given key */
56	int	(*ns_loadmaster)(char *, char *, char **, char ***);
57					/* load master map */
58	int	(*ns_loaddirect)(char *, char *, char *,
59		char **, char ***);	/* load direct map */
60	int	(*ns_getmapkeys)(char *, struct dir_entry **,
61		int *, int *, char **, char ***);
62					/* readdir */
63};
64
65static struct ns_info ns_info[] = {
66
67	{ "files",   init_files,  getmapent_files,
68	  loadmaster_files, loaddirect_files,
69	  getmapkeys_files },
70
71	{ "od",   init_od,  getmapent_od,
72	  loadmaster_od, loaddirect_od,
73	  getmapkeys_od },
74
75	{ NULL, NULL, NULL, NULL, NULL, NULL }
76};
77
78void
79ns_setup(char **stack, char ***stkptr)
80{
81	struct ns_info *nsp;
82
83	for (nsp = ns_info; nsp->ns_name; nsp++) {
84		nsp->ns_init(stack, stkptr);
85	}
86}
87
88int
89getmapent(key, mapname, ml, stack, stkptr, iswildcard, isrestricted)
90	const char *key, *mapname;
91	struct mapline *ml;
92	char **stack, ***stkptr;
93	bool_t *iswildcard;
94	bool_t isrestricted;
95{
96	int ns_err, err;
97	struct ns_info *nsp;
98
99	if (*mapname == '/') 		/* must be a file */
100		return (getmapent_files(key, mapname, ml, stack, stkptr,
101					iswildcard, isrestricted));
102
103	ns_err = __NSW_NOTFOUND;
104	for (nsp = ns_info; nsp->ns_name; nsp++) {
105		err = nsp->ns_getmapent(key, mapname, ml, stack, stkptr,
106						iswildcard, isrestricted);
107		if (err == __NSW_SUCCESS)
108			return (__NSW_SUCCESS);
109		if (err != __NSW_NOTFOUND)
110			ns_err = err;
111	}
112
113	return (ns_err);
114}
115
116int
117loadmaster_map(mapname, defopts, stack, stkptr)
118	char *mapname, *defopts;
119	char **stack, ***stkptr;
120{
121	int ns_err;
122	struct ns_info *nsp;
123
124	if (*mapname == '/')		/* must be a file */
125		return (loadmaster_files(mapname, defopts, stack, stkptr));
126
127	for (nsp = ns_info; nsp->ns_name; nsp++) {
128		ns_err = nsp->ns_loadmaster(mapname, defopts, stack, stkptr);
129		if (ns_err == __NSW_SUCCESS)
130			return (__NSW_SUCCESS);
131	}
132
133	return (__NSW_UNAVAIL);
134}
135
136int
137loaddirect_map(mapname, localmap, defopts, stack, stkptr)
138	char *mapname, *localmap, *defopts;
139	char **stack, ***stkptr;
140{
141	int ns_err = __NSW_SUCCESS;
142	struct ns_info *nsp;
143
144	if (*mapname == '/')		/* must be a file */
145		return (loaddirect_files(mapname, localmap, defopts,
146				stack, stkptr));
147	if (strcmp(mapname, "-static") == 0) {
148		return (loaddirect_static(localmap, defopts, stack, stkptr));
149	}
150
151	for (nsp = ns_info; nsp->ns_name; nsp++) {
152		ns_err = nsp->ns_loaddirect(mapname, localmap, defopts, stack,
153					stkptr);
154		if (ns_err == __NSW_SUCCESS)
155			return (__NSW_SUCCESS);
156	}
157
158	return (__NSW_UNAVAIL);
159}
160
161/*
162 * XXX - this assumes that gethostent() returns a pointer to
163 * thread-specific data.  It currently does....
164 */
165static int
166gethostkeys(struct dir_entry **list, int *error, int *cache_time)
167{
168	char **p;
169	struct dir_entry *last = NULL;
170	struct hostent *ent;
171	int err;
172
173	*cache_time = RDDIR_CACHE_TIME * 2;
174	*error = 0;
175	if (trace  > 1)
176		trace_prt(1, "gethostkeys called\n");
177
178	sethostent(1);
179
180	while ((ent = gethostent()) != NULL) {
181		/*
182		 * add canonical name
183		 *
184		 * A return of -1 means the name isn't valid.
185		 */
186		err = add_dir_entry(ent->h_name, NULL, NULL, list, &last);
187		if (err == -1)
188			continue;
189		if (err != 0) {
190			*error = err;
191			goto done;
192		}
193		if (ent->h_aliases == NULL)
194			goto done;	/* no aliases */
195		for (p = ent->h_aliases; *p != 0; p++) {
196			if (strcmp(*p, ent->h_name) != 0) {
197				/*
198				 * add alias only if different
199				 * from canonical name
200				 */
201				err = add_dir_entry(*p, NULL, NULL, list,
202				    &last);
203				if (err == -1)
204					continue;
205				if (err != 0) {
206					*error = err;
207					goto done;
208				}
209			}
210		}
211		assert(last != NULL);
212	}
213done:	if (*list != NULL) {
214		/*
215		 * list of entries found
216		 */
217		*error = 0;
218	}
219	endhostent();
220
221	return (__NSW_SUCCESS);
222}
223
224/*
225 * enumerate all entries in the map in the various name services.
226 */
227int
228getmapkeys(mapname, list, error, cache_time, stack, stkptr)
229	char *mapname;
230	struct dir_entry **list;
231	int *error;
232	int *cache_time;
233	char **stack, ***stkptr;
234
235{
236	int ns_err = __NSW_SUCCESS;
237	int success = 0;
238	struct ns_info *nsp;
239
240	if (*mapname == '/') 		/* must be a file */
241		return (getmapkeys_files(mapname, list, error, cache_time,
242				stack, stkptr));
243	if (strcmp(mapname, "-hosts") == 0) {
244		return (gethostkeys(list, error, cache_time));
245	}
246	if (strcmp(mapname, "-static") == 0) {
247		pr_msg("-static is a collection of direct maps");
248		return (__NSW_UNAVAIL);
249	}
250	if (strcmp(mapname, "-fstab") == 0) {
251		return (getfstabkeys(list, error, cache_time));
252	}
253
254	for (nsp = ns_info; nsp->ns_name; nsp++) {
255		ns_err = nsp->ns_getmapkeys(mapname, list, error,
256				cache_time, stack, stkptr);
257		if (*error == 0) {
258			/*
259			 * return success if listing was successful
260			 * for at least one name service
261			 */
262			success++;
263		}
264
265		/*
266		 * XXX force next name service
267		 */
268		if (ns_err != __NSW_UNAVAIL)
269			ns_err = __NSW_NOTFOUND;
270	}
271	if (success) {
272		/*
273		 * if succeeded at least once, return error=0
274		 */
275		*error = 0;
276	};
277
278	return (success ? __NSW_SUCCESS : __NSW_NOTFOUND);
279}
280