xref: /titanic_41/usr/src/head/nss_common.h (revision 1d4b38e0077763e7c9b20768eacb841957e787bc)
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  * Copyright (c) 1992-1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 /*
28  *
29  * NOTE:  The interfaces documented in this file may change in a minor
30  *	  release.  It is intended that in the future a stronger committment
31  *	  will be made to these interface definitions which will guarantee
32  *	  them across minor releases.
33  */
34 
35 #ifndef _NSS_COMMON_H
36 #define	_NSS_COMMON_H
37 
38 #pragma ident	"%Z%%M%	%I%	%E% SMI"
39 
40 #include <synch.h>
41 
42 #ifdef	__cplusplus
43 extern "C" {
44 #endif
45 
46 /*
47  * The name-service switch
48  * -----------------------
49  *
50  * From nsswitch.conf(4):
51  *
52  *	    The operating system uses a number of ``databases'' of information
53  *	    about hosts, users (passwd/shadow), groups and so forth.  Data for
54  *	    these can come from a variety of ``sources'':  host-names and
55  *	    -addresses, for example, may be found in /etc/hosts, NIS, NIS+ or
56  *	    DNS.  One or more sources may be used for each database;  the
57  *	    sources and their lookup order are specified in the
58  *	    /etc/nsswitch.conf file.
59  *
60  * The implementation of this consists of:
61  *
62  *    -	a ``frontend'' for each database, which provides a programming
63  *	interface for that database [for example, the "passwd" frontend
64  *	consists of getpwnam_r(), getpwuid_r(), getpwent_r(), setpwent(),
65  *	endpwent(), and the old MT-unsafe routines getpwnam() and getpwuid()]
66  *	and is implemented by calls to...
67  *
68  *    -	the common core of the switch (``switch engine'');  it determines
69  *	which sources to use and invokes...
70  *
71  *    -	A ``backend'' for each useful <database, source> pair.  Each backend
72  *	consists of whatever private data it needs and a set of functions
73  *	that the switch engine may invoke on behalf of the frontend
74  *	[e.g. the "nis" backend for "passwd" provides routines to lookup
75  *	by name and by uid, as well as set/get/end iterator routines].
76  *	The set of functions, and their expected arguments and results,
77  *	constitutes a (database-specific) interface between a frontend and
78  *	all its backends.  The switch engine knows as little as possible
79  *	about these interfaces.
80  *
81  *	(The term ``backend'' is used ambiguously;  it may also refer to a
82  *	particular instantiation of a backend, or to the set of all backends
83  *	for a particular source, e.g. "the nis backend").
84  *
85  * This header file defines the interface between the switch engine and the
86  * frontends and backends.  Interfaces between specific frontends and
87  * backends are defined elsewhere;  many are in <nss_dbdefs.h>.
88  *
89  *
90  * Switch-engine outline
91  * ---------------------
92  *
93  * Frontends may call the following routines in the switch engine:
94  *
95  *	nss_search() does getXXXbyYYY,	e.g. getpwnam_r(), getpwuid_r()
96  *	nss_getent() does getXXXent,	e.g. getpwent_r()
97  *	nss_setent() does setXXXent,	e.g. setpwent()
98  *	nss_endent() does endXXXent,	e.g. endpwent()
99  *	nss_delete() releases resources, in the style of endpwent().
100  *
101  * A getpwnam_r() call might proceed thus (with many details omitted):
102  *
103  *	(1)  getpwnam_r	fills in (getpwnam-specific) argument/result struct,
104  *			calls nss_search(),
105  *	(2)  nss_search	looks up configuration info, gets "passwd: files nis",
106  *	(3)  nss_search	decides to try first source ("files"),
107  *	 (a) nss_search	locates code for <"passwd", "files"> backend,
108  *	 (b) nss_search	creates instance of backend,
109  *	 (c) nss_search	calls get-by-name routine in backend,
110  *	 (d) backend	searches /etc/passwd, doesn't find the name,
111  *			returns "not found" status to nss_search,
112  *	(4)  nss_search	examines status and config info, decides to try
113  *			next source ("nis"),
114  *	 (a) nss_search	locates code for <"passwd", "nis"> backend,
115  *	 (b) nss_search	creates instance of backend,
116  *	 (c) nss_search	calls get-by-name routine in backend,
117  *	 (d) backend	searches passwd.byname, finds the desired entry,
118  *			fills in the result part of the getpwnam-specific
119  *			struct, returns "success" status to nss_search,
120  *	(5)  nss_search	examines status and config info, decides to return
121  *			to caller,
122  *	(6)  getpwnam_r	extracts result from getpwnam-specific struct,
123  *			returns to caller.
124  *
125  *
126  * Data structures
127  * ---------------
128  *
129  * Both databases and sources are represented by case-sensitive strings
130  * (the same strings that appear in the configuration file).
131  *
132  * The switch engine maintains a per-frontend data structure so that the
133  * results of steps (2), (a) and (b) can be cached.  The frontend holds a
134  * handle (nss_db_root_t) to this structure and passes it in to the
135  * nss_*() routines.
136  *
137  * The nss_setent(), nss_getent() and nss_endent() routines introduce another
138  * variety of state (the current position in the enumeration process).
139  * Within a single source, this information is maintained by private data
140  * in the backend instance -- but, in the presence of multiple sources, the
141  * switch engine must keep track of the current backend instance [e.g either
142  * <"passwd", "files"> or <"passwd", "nis"> instances].  The switch engine
143  * has a separate per-enumeration data structure for this;  again, the
144  * frontend holds a handle (nss_getent_t) and passes it in, along with the
145  * nss_db_root_t handle, to nss_setent(), nss_getent() and nss_endent().
146  *
147  *
148  * Multithreading
149  * --------------
150  *
151  * The switch engine takes care of locking;  frontends should be written to
152  * be reentrant, and a backend instance may assume that all calls to it are
153  * serialized.
154  *
155  * If multiple threads simultaneously want to use a particular backend, the
156  * switch engine creates multiple backend instances (up to some limit
157  * specified by the frontend).  Backends must of course lock any state that
158  * is shared between instances, and must serialize calls to any MT-unsafe
159  * code.
160  *
161  * The switch engine has no notion of per-thread state.
162  *
163  * Frontends can use the nss_getent_t handle to define the scope of the
164  * enumeration (set/get/endXXXent) state:  a static handle gives global state
165  * (which is what Posix has specified for the getXXXent_r routines), handles
166  * in Thread-Specific Data give per-thread state, and handles on the stack
167  * give per-invocation state.
168  */
169 
170 
171 /*
172  * Backend instances
173  * -----------------
174  *
175  * As far as the switch engine is concerned, an instance of a backend is a
176  * struct whose first two members are:
177  *    -	A pointer to a vector of function pointers, one for each
178  *	database-specific function,
179  *    -	The length of the vector (an int), used for bounds-checking.
180  * There are four well-known function slots in the vector:
181  *	[0] is a destructor for the backend instance,
182  *	[1] is the endXXXent routine,
183  *	[2] is the setXXXent routine,
184  *	[3] is the getXXXent routine.
185  * Any other slots are database-specific getXXXbyYYY routines;  the frontend
186  * specifies a slot-number to nss_search().
187  *
188  * The functions take two arguments:
189  *    -	a pointer to the backend instance (like a C++ "this" pointer)
190  *    -	a single (void *) pointer to the database-specific argument/result
191  *	structure (the contents are opaque to the switch engine).
192  * The four well-known functions ignore the (void *) pointer.
193  *
194  * Backend routines return one of five status codes to the switch engine:
195  * SUCCESS, UNAVAIL, NOTFOUND, TRYAGAIN (these are the same codes that may
196  * be specified in the config information;  see nsswitch.conf(4)), or
197  * NSS_NISSERVDNS_TRYAGAIN (should only be used by the NIS backend for
198  * NIS server in DNS forwarding mode to indicate DNS server non-response).
199  */
200 
201 typedef enum {
202 	NSS_SUCCESS,
203 	NSS_NOTFOUND,
204 	NSS_UNAVAIL,
205 	NSS_TRYAGAIN,
206 	NSS_NISSERVDNS_TRYAGAIN
207 } nss_status_t;
208 
209 struct nss_backend;
210 
211 #if defined(__STDC__)
212 typedef nss_status_t (*nss_backend_op_t)(struct nss_backend *, void *args);
213 #else
214 typedef nss_status_t (*nss_backend_op_t)();
215 #endif
216 
217 struct nss_backend {
218 	nss_backend_op_t	*ops;
219 	int			n_ops;
220 };
221 typedef struct nss_backend	nss_backend_t;
222 typedef int			nss_dbop_t;
223 
224 #define	NSS_DBOP_DESTRUCTOR	0
225 #define	NSS_DBOP_ENDENT		1
226 #define	NSS_DBOP_SETENT		2
227 #define	NSS_DBOP_GETENT		3
228 #define	NSS_DBOP_next_iter	(NSS_DBOP_GETENT + 1)
229 #define	NSS_DBOP_next_noiter	(NSS_DBOP_DESTRUCTOR + 1)
230 #define	NSS_DBOP_next_ipv6_iter	(NSS_DBOP_GETENT + 3)
231 
232 #define	NSS_LOOKUP_DBOP(instp, n)					    \
233 		(((n) >= 0 && (n) < (instp)->n_ops) ? (instp)->ops[n] : 0)
234 
235 #define	NSS_INVOKE_DBOP(instp, n, argp)					    (\
236 		((n) >= 0 && (n) < (instp)->n_ops && (instp)->ops[n] != 0) \
237 		? (*(instp)->ops[n])(instp, argp)			    \
238 		: NSS_UNAVAIL)
239 
240 /*
241  * Locating and instantiating backends
242  * -----------------------------------
243  *
244  * To perform step (a), the switch consults a list of backend-finder routines,
245  * passing a <database, source> pair.
246  *
247  * There is a standard backend-finder;  frontends may augment or replace this
248  * in order to, say, indicate that some backends are "compiled in" with the
249  * frontend.
250  *
251  * Backend-finders return a pointer to a constructor function for the backend.
252  * (or NULL if they can't find the backend).  The switch engine caches these
253  * function pointers;  when it needs to perform step (b), it calls the
254  * constructor function, which returns a pointer to a new instance of the
255  * backend, properly initialized (or returns NULL).
256  */
257 
258 #if defined(__STDC__)
259 typedef	nss_backend_t * 	(*nss_backend_constr_t)(const char *db_name,
260 							const char *src_name,
261 /* Hook for (unimplemented) args in nsswitch.conf */	const char *cfg_args);
262 #else
263 typedef	nss_backend_t * 	(*nss_backend_constr_t)();
264 #endif
265 
266 struct nss_backend_finder {
267 #if defined(__STDC__)
268 	nss_backend_constr_t	(*lookup)
269 		(void *lkp_priv, const char *, const char *, void **del_privp);
270 	void			(*delete)
271 		(void *del_priv, nss_backend_constr_t);
272 #else
273 	nss_backend_constr_t	(*lookup)();
274 	void			(*delete)();
275 #endif
276 	struct nss_backend_finder *next;
277 	void			*lookup_priv;
278 };
279 
280 typedef struct nss_backend_finder nss_backend_finder_t;
281 
282 extern nss_backend_finder_t	*nss_default_finders;
283 
284 /*
285  * Frontend parameters
286  * -------------------
287  *
288  * The frontend must tell the switch engine:
289  *    -	the database name,
290  *    -	the compiled-in default configuration entry.
291  * It may also override default values for:
292  *    -	the database name to use when looking up the configuration
293  *	information (e.g. "shadow" uses the config entry for "passwd"),
294  *    -	a limit on the number of instances of each backend that are
295  *	simultaneously active,
296  *    - a limit on the number of instances of each backend that are
297  *	simultaneously dormant (waiting for new requests),
298  *    -	a flag that tells the switch engine to use the default configuration
299  *	entry and ignore any other config entry for this database,
300  *    -	backend-finders (see above)
301  *    - a cleanup routine that should be called when these parameters are
302  *	about to be deleted.
303  *
304  * In order to do this, the frontend includes a pointer to an initialization
305  * function (nss_db_initf_t) in every nss_*() call.  When necessary (normally
306  * just on the first invocation), the switch engine allocates a parameter
307  * structure (nss_db_params_t), fills in the default values, then calls
308  * the initialization function, which should update the parameter structure
309  * as necessary.
310  *
311  * (This might look more natural if we put nss_db_initf_t in nss_db_root_t,
312  * or abolished nss_db_initf_t and put nss_db_params_t in nss_db_root_t.
313  * It's done the way it is for shared-library efficiency, namely:
314  *	- keep the unshared data (nss_db_root_t) to a minimum,
315  *	- keep the symbol lookups and relocations to a minimum.
316  * In particular this means that non-null pointers, e.g. strings and
317  * function pointers, in global data are a bad thing).
318  */
319 
320 enum nss_dbp_flags {
321 	NSS_USE_DEFAULT_CONFIG	= 0x1
322 };
323 
324 struct nss_db_params {
325 	const char 		*name;		/* Mandatory: database name */
326 	const char		*config_name;	/* config-file database name */
327 	const char		*default_config; /* Mandatory: default config */
328 	unsigned		max_active_per_src;
329 	unsigned		max_dormant_per_src;
330 	enum nss_dbp_flags	flags;
331 	nss_backend_finder_t	*finders;
332 	void			*private;	/* Not used by switch */
333 	void			(*cleanup)(struct nss_db_params *);
334 };
335 
336 typedef struct nss_db_params nss_db_params_t;
337 
338 #if defined(__STDC__)
339 typedef void (*nss_db_initf_t)(nss_db_params_t *);
340 #else
341 typedef void (*nss_db_initf_t)();
342 #endif
343 
344 /*
345  * These structures are defined inside the implementation of the switch
346  * engine;  the interface just holds pointers to them.
347  */
348 struct nss_db_state;
349 struct nss_getent_context;
350 
351 /*
352  * Finally, the two handles that frontends hold:
353  */
354 
355 struct nss_db_root {
356 	struct nss_db_state	*s;
357 	mutex_t			lock;
358 };
359 typedef struct nss_db_root nss_db_root_t;
360 #define	NSS_DB_ROOT_INIT		{ 0, DEFAULTMUTEX }
361 #define	DEFINE_NSS_DB_ROOT(name)	nss_db_root_t name = NSS_DB_ROOT_INIT
362 
363 
364 typedef struct {
365 	struct nss_getent_context *ctx;
366 	mutex_t			lock;
367 } nss_getent_t;
368 
369 #define	NSS_GETENT_INIT			{ 0, DEFAULTMUTEX }
370 #define	DEFINE_NSS_GETENT(name)		nss_getent_t name = NSS_GETENT_INIT
371 
372 #if defined(__STDC__)
373 extern nss_status_t nss_search(nss_db_root_t *, nss_db_initf_t,
374 			int search_fnum, void *search_args);
375 extern nss_status_t nss_getent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *,
376 			void *getent_args);
377 extern void nss_setent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *);
378 
379 extern void nss_endent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *);
380 					/* ^^ superfluous but consistent */
381 extern void nss_delete(nss_db_root_t *);
382 #else
383 extern nss_status_t nss_search();
384 extern nss_status_t nss_getent();
385 extern void nss_setent();
386 extern void nss_endent();
387 extern void nss_delete();
388 #endif
389 
390 #ifdef	__cplusplus
391 }
392 #endif
393 
394 #endif /* _NSS_COMMON_H */
395