xref: /illumos-gate/usr/src/head/nss_common.h (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  *
28  * NOTE:  The interfaces documented in this file may change in a minor
29  *	  release.  It is intended that in the future a stronger committment
30  *	  will be made to these interface definitions which will guarantee
31  *	  them across minor releases.
32  */
33 
34 #ifndef _NSS_COMMON_H
35 #define	_NSS_COMMON_H
36 
37 #pragma ident	"%Z%%M%	%I%	%E% SMI"
38 
39 #include <synch.h>
40 
41 #ifdef	__cplusplus
42 extern "C" {
43 #endif
44 
45 /*
46  * The name-service switch
47  * -----------------------
48  *
49  * From nsswitch.conf(4):
50  *
51  *	    The operating system uses a number of "databases" of information
52  *	    about hosts, users (passwd/shadow), groups and so forth.  Data for
53  *	    these can come from a variety of "sources":  host-names and
54  *	    -addresses, for example, may be found in /etc/hosts, NIS, NIS+ or
55  *	    DNS.  One or more sources may be used for each database;  the
56  *	    sources and their lookup order are specified in the
57  *	    /etc/nsswitch.conf file.
58  *
59  * The implementation of this consists of:
60  *
61  *    -	a "frontend" for each database, which provides a programming
62  *	interface for that database [for example, the "passwd" frontend
63  *	consists of getpwnam_r(), getpwuid_r(), getpwent_r(), setpwent(),
64  *	endpwent(), and the old MT-unsafe routines getpwnam() and getpwuid()]
65  *	and is implemented by calls to...
66  *
67  *    -	the common core of the switch (called the "switch" or "policy" engine);
68  *	that determines what sources to use and when to invoke them.  This
69  *	component works in conjunction with the name service switch (nscd).
70  *	Usually nscd is the policy engine for an application lookup.
71  *
72  *    - Old style backend interfaces follow this pointer to function interface:
73  *
74  *     	A "backend" exists for useful <database, source> pairs.  Each backend
75  *	consists of whatever private data it needs and a set of functions
76  *	that the switch engine may invoke on behalf of the frontend
77  *	[e.g. the "nis" backend for "passwd" provides routines to lookup
78  *	by name and by uid, as well as set/get/end iterator routines].
79  *	The set of functions, and their expected arguments and results,
80  *	constitutes a (database-specific) interface between a frontend and
81  *	all its backends.  The switch engine knows as little as possible
82  *	about these interfaces.
83  *
84  *	(The term "backend" is used ambiguously;  it may also refer to a
85  *	particular instantiation of a backend, or to the set of all backends
86  *	for a particular source, e.g. "the nis backend").
87  *
88  * This header file defines the interface between the switch engine and the
89  * frontends and backends.  Interfaces between specific frontends and
90  * backends are defined elsewhere;  many are in <nss_dbdefs.h>.
91  * Most of these definitions are in the form of pointer to function
92  * indicies used to call specific backend APIs.
93  *
94  *
95  * Switch-engine outline
96  * ---------------------
97  *
98  * Frontends may call the following routines in the switch engine:
99  *
100  *	nss_search() does getXXXbyYYY,	e.g. getpwnam_r(), getpwuid_r()
101  *	nss_getent() does getXXXent,	e.g. getpwent_r()
102  *	nss_setent() does setXXXent,	e.g. setpwent()
103  *	nss_endent() does endXXXent,	e.g. endpwent()
104  *	nss_delete() releases resources, in the style of endpwent().
105  *
106  * A getpwnam_r() call might proceed thus (with many details omitted):
107  *
108  *	(1)  getpwnam_r	fills in (getpwnam-specific) argument/result struct,
109  *			calls nss_search(),
110  *	(2)  nss_search queries the name service cache for an existing
111  *			result via a call to _nsc_search().  if the cache
112  *			(nscd) has a definitive answer skip to step 7
113  *	(3)  nss_search	looks up configuration info, gets "passwd: files nis",
114  *	(4)  nss_search	decides to try first source ("files"),
115  *	 (a) nss_search	locates code for <"passwd", "files"> backend,
116  *	 (b) nss_search	creates instance of backend,
117  *	 (c) nss_search	calls get-by-name routine in backend,
118  *			through a function pointer interface,
119  *	 (d) backend	searches /etc/passwd, doesn't find the name,
120  *			returns "not found" status to nss_search,
121  *	(5)  nss_search	examines status and config info, decides to try
122  *			next source ("nis"),
123  *	 (a) nss_search	locates code for <"passwd", "nis"> backend,
124  *	 (b) nss_search	creates instance of backend,
125  *	 (c) nss_search	calls get-by-name routine in backend,
126  *			through a function pointer interface,
127  *	 (d) backend	searches passwd.byname, finds the desired entry,
128  *			fills in the result part of the getpwnam-specific
129  *			struct, returns "success" status to nss_search,
130  *	(6)  nss_search	examines status and config info, decides to return
131  *			to caller,
132  *	(7)  getpwnam_r	extracts result from getpwnam-specific struct,
133  *			returns to caller.
134  *
135  *
136  * Data structures
137  * ---------------
138  *
139  * Both databases and sources are represented by case-sensitive strings
140  * (the same strings that appear in the configuration file).
141  *
142  * The switch engine maintains a per-frontend data structure so that the
143  * results of steps (2), (a) and (b) can be cached.  The frontend holds a
144  * handle (nss_db_root_t) to this structure and passes it in to the
145  * nss_*() routines.
146  *
147  * The nss_setent(), nss_getent() and nss_endent() routines introduce another
148  * variety of state (the current position in the enumeration process).
149  * Within a single source, this information is maintained by private data
150  * in the backend instance -- but, in the presence of multiple sources, the
151  * switch engine must keep track of the current backend instance [e.g either
152  * <"passwd", "files"> or <"passwd", "nis"> instances].  The switch engine
153  * has a separate per-enumeration data structure for this;  again, the
154  * frontend holds a handle (nss_getent_t) and passes it in, along with the
155  * nss_db_root_t handle, to nss_setent(), nss_getent() and nss_endent().
156  *
157  *
158  * Multithreading
159  * --------------
160  *
161  * The switch engine takes care of locking;  frontends should be written to
162  * be reentrant, and a backend instance may assume that all calls to it are
163  * serialized.
164  *
165  * If multiple threads simultaneously want to use a particular backend, the
166  * switch engine creates multiple backend instances (up to some limit
167  * specified by the frontend).  Backends must of course lock any state that
168  * is shared between instances, and must serialize calls to any MT-unsafe
169  * code.
170  *
171  * The switch engine has no notion of per-thread state.
172  *
173  * Frontends can use the nss_getent_t handle to define the scope of the
174  * enumeration (set/get/endXXXent) state:  a static handle gives global state
175  * (which is what Posix has specified for the getXXXent_r routines), handles
176  * in Thread-Specific Data give per-thread state, and handles on the stack
177  * give per-invocation state.
178  */
179 
180 /*
181  * Backend instances
182  * -----------------
183  *
184  * As far as the switch engine is concerned, an instance of a backend is a
185  * struct whose first two members are:
186  *    -	A pointer to a vector of function pointers, one for each
187  *	database-specific function,
188  *    -	The length of the vector (an int), used for bounds-checking.
189  * There are four well-known function slots in the vector:
190  *	[0] is a destructor for the backend instance,
191  *	[1] is the endXXXent routine,
192  *	[2] is the setXXXent routine,
193  *	[3] is the getXXXent routine.
194  * Any other slots are database-specific getXXXbyYYY routines;  the frontend
195  * specifies a slot-number to nss_search().
196  *
197  * The functions take two arguments:
198  *    -	a pointer to the backend instance (like a C++ "this" pointer)
199  *    -	a single (void *) pointer to the database-specific argument/result
200  *	structure (the contents are opaque to the switch engine).
201  * The four well-known functions ignore the (void *) pointer.
202  *
203  * Backend routines return the following status codes to the switch engine:
204  *
205  * SUCCESS, UNAVAIL, NOTFOUND, TRYAGAIN (these are the same codes that may
206  * be specified in the config information;  see nsswitch.conf(4))
207  *
208  * The remaining conditions/errors are internally generated and if
209  * necessary are translated, as to one of the above external errors,
210  * usually NOTFOUND or UNAVAIL.
211  *
212  * NSS_NISSERVDNS_TRYAGAIN (should only be used by the NIS backend for
213  * NIS server in DNS forwarding mode to indicate DNS server non-response).
214  *
215  * The policy component may return NSS_TRYLOCAL which signifies that nscd
216  * is not going to process the request, and it should be performed locally.
217  *
218  * NSS_ERROR is a catchall for internal error conditions, errno will be set
219  * to a system <errno.h> error that can help track down the problem if
220  * it is persistent.  This error is the result of some internal error
221  * condition and should not be seen during or exposed to aan application.
222  * The error may be from the application side switch component or from the
223  * nscd side switch component.
224  *
225  * NSS_ALTRETRY and NSS_ALTRESET are internal codes used by the application
226  * side policy component and nscd to direct the policy component to
227  * communicate to a per-user nscd if/when per-user authentication is enabled.
228  *
229  * NSS_NSCD_PRIV is a catchall for internal nscd errors or status
230  * conditions.  This return code is not visible to applications.  nscd
231  * may use this as a status flag and maintain additional error or status
232  * information elsewhere in other private nscd data.  This status value
233  * is for nscd private/internal use only.
234  */
235 
236 typedef enum {
237 	NSS_SUCCESS = 0,
238 	NSS_NOTFOUND = 1,
239 	NSS_UNAVAIL = 2,
240 	NSS_TRYAGAIN = 3,
241 	NSS_NISSERVDNS_TRYAGAIN = 4,
242 	NSS_TRYLOCAL = 5,
243 	NSS_ERROR = 6,
244 	NSS_ALTRETRY = 7,
245 	NSS_ALTRESET = 8,
246 	NSS_NSCD_PRIV = 9
247 } nss_status_t;
248 
249 struct nss_backend;
250 
251 #if defined(__STDC__)
252 typedef nss_status_t (*nss_backend_op_t)(struct nss_backend *, void *args);
253 #else
254 typedef nss_status_t (*nss_backend_op_t)();
255 #endif
256 
257 struct nss_backend {
258 	nss_backend_op_t	*ops;
259 	int			n_ops;
260 };
261 typedef struct nss_backend	nss_backend_t;
262 typedef int			nss_dbop_t;
263 
264 #define	NSS_DBOP_DESTRUCTOR	0
265 #define	NSS_DBOP_ENDENT		1
266 #define	NSS_DBOP_SETENT		2
267 #define	NSS_DBOP_GETENT		3
268 #define	NSS_DBOP_next_iter	(NSS_DBOP_GETENT + 1)
269 #define	NSS_DBOP_next_noiter	(NSS_DBOP_DESTRUCTOR + 1)
270 #define	NSS_DBOP_next_ipv6_iter	(NSS_DBOP_GETENT + 3)
271 
272 #define	NSS_LOOKUP_DBOP(instp, n)					    \
273 		(((n) >= 0 && (n) < (instp)->n_ops) ? (instp)->ops[n] : 0)
274 
275 #define	NSS_INVOKE_DBOP(instp, n, argp)					    (\
276 		((n) >= 0 && (n) < (instp)->n_ops && (instp)->ops[n] != 0) \
277 		? (*(instp)->ops[n])(instp, argp)			    \
278 		: NSS_UNAVAIL)
279 
280 /*
281  * Locating and instantiating backends
282  * -----------------------------------
283  *
284  * To perform step (a), the switch consults a list of backend-finder routines,
285  * passing a <database, source> pair.
286  *
287  * There is a standard backend-finder;  frontends may augment or replace this
288  * in order to, say, indicate that some backends are "compiled in" with the
289  * frontend.
290  *
291  * Backend-finders return a pointer to a constructor function for the backend.
292  * (or NULL if they can't find the backend).  The switch engine caches these
293  * function pointers;  when it needs to perform step (b), it calls the
294  * constructor function, which returns a pointer to a new instance of the
295  * backend, properly initialized (or returns NULL).
296  */
297 
298 #if defined(__STDC__)
299 typedef	nss_backend_t		*(*nss_backend_constr_t)(const char *db_name,
300 							const char *src_name,
301 /* Hook for (unimplemented) args in nsswitch.conf */	const char *cfg_args);
302 #else
303 typedef	nss_backend_t 		*(*nss_backend_constr_t)();
304 #endif
305 
306 struct nss_backend_finder {
307 #if defined(__STDC__)
308 	nss_backend_constr_t	(*lookup)
309 		(void *lkp_priv, const char *, const char *, void **del_privp);
310 	void			(*delete)
311 		(void *del_priv, nss_backend_constr_t);
312 #else
313 	nss_backend_constr_t	(*lookup)();
314 	void			(*delete)();
315 #endif
316 	struct nss_backend_finder *next;
317 	void			*lookup_priv;
318 };
319 
320 typedef struct nss_backend_finder nss_backend_finder_t;
321 
322 extern nss_backend_finder_t	*nss_default_finders;
323 
324 /*
325  * Frontend parameters
326  * -------------------
327  *
328  * The frontend must tell the switch engine:
329  *    -	the database name,
330  *    -	the compiled-in default configuration entry.
331  * It may also override default values for:
332  *    -	the database name to use when looking up the configuration
333  *	information (e.g. "shadow" uses the config entry for "passwd"),
334  *    -	a limit on the number of instances of each backend that are
335  *	simultaneously active,
336  *    - a limit on the number of instances of each backend that are
337  *	simultaneously dormant (waiting for new requests),
338  *    -	a flag that tells the switch engine to use the default configuration
339  *	entry and ignore any other config entry for this database,
340  *    -	backend-finders (see above)
341  *    - a cleanup routine that should be called when these parameters are
342  *	about to be deleted.
343  *
344  * In order to do this, the frontend includes a pointer to an initialization
345  * function (nss_db_initf_t) in every nss_*() call.  When necessary (normally
346  * just on the first invocation), the switch engine allocates a parameter
347  * structure (nss_db_params_t), fills in the default values, then calls
348  * the initialization function, which should update the parameter structure
349  * as necessary.
350  *
351  * (This might look more natural if we put nss_db_initf_t in nss_db_root_t,
352  * or abolished nss_db_initf_t and put nss_db_params_t in nss_db_root_t.
353  * It's done the way it is for shared-library efficiency, namely:
354  *	- keep the unshared data (nss_db_root_t) to a minimum,
355  *	- keep the symbol lookups and relocations to a minimum.
356  * In particular this means that non-null pointers, e.g. strings and
357  * function pointers, in global data are a bad thing).
358  */
359 
360 enum nss_dbp_flags {
361 	NSS_USE_DEFAULT_CONFIG	= 0x1
362 };
363 
364 struct nss_db_params {
365 	const char 		*name;		/* Mandatory: database name */
366 	const char		*config_name;	/* config-file database name */
367 	const char		*default_config; /* Mandatory: default config */
368 	unsigned		max_active_per_src;
369 	unsigned		max_dormant_per_src;
370 	enum nss_dbp_flags	flags;
371 	nss_backend_finder_t	*finders;
372 	void			*private;	/* Not used by switch */
373 	void			(*cleanup)(struct nss_db_params *);
374 };
375 
376 typedef struct nss_db_params nss_db_params_t;
377 
378 #if defined(__STDC__)
379 typedef void (*nss_db_initf_t)(nss_db_params_t *);
380 #else
381 typedef void (*nss_db_initf_t)();
382 #endif
383 
384 /*
385  * DBD param offsets in NSS2 nscd header.
386  * Offsets are relative to beginning of dbd section.
387  * 32 bit offsets should be sufficient, forever.
388  * 0 offset == NULL
389  * flags == nss_dbp_flags
390  */
391 typedef struct nss_dbd {
392 	uint32_t	o_name;
393 	uint32_t	o_config_name;
394 	uint32_t	o_default_config;
395 	uint32_t	flags;
396 } nss_dbd_t;
397 
398 /*
399  * These structures are defined inside the implementation of the switch
400  * engine;  the interface just holds pointers to them.
401  */
402 struct nss_db_state;
403 struct nss_getent_context;
404 
405 /*
406  * Finally, the two handles that frontends hold:
407  */
408 
409 struct nss_db_root {
410 	struct nss_db_state	*s;
411 	mutex_t			lock;
412 };
413 typedef struct nss_db_root nss_db_root_t;
414 #define	NSS_DB_ROOT_INIT		{ 0, DEFAULTMUTEX }
415 #define	DEFINE_NSS_DB_ROOT(name)	nss_db_root_t name = NSS_DB_ROOT_INIT
416 
417 
418 typedef struct {
419 	struct nss_getent_context *ctx;
420 	mutex_t			lock;
421 } nss_getent_t;
422 
423 #define	NSS_GETENT_INIT			{ 0, DEFAULTMUTEX }
424 #define	DEFINE_NSS_GETENT(name)		nss_getent_t name = NSS_GETENT_INIT
425 
426 /*
427  * Policy Engine Configuration
428  * ---------------------------
429  *
430  * When nscd is running it can reconfigure it's internal policy engine
431  * as well as advise an application's front-end and policy engine on how
432  * respond optimally to results being returned from nscd.  This is done
433  * through the policy engine configuration interface.
434  */
435 
436 typedef enum {
437 	NSS_CONFIG_GET,
438 	NSS_CONFIG_PUT,
439 	NSS_CONFIG_ADD,
440 	NSS_CONFIG_DELETE,
441 	NSS_CONFIG_LIST
442 } nss_config_op_t;
443 
444 struct nss_config {
445 	char		*name;
446 	nss_config_op_t	cop;
447 	mutex_t		*lock;
448 	void		*buffer;
449 	size_t		length;
450 };
451 typedef struct nss_config nss_config_t;
452 
453 
454 #if defined(__STDC__)
455 extern nss_status_t nss_config(nss_config_t **, int);
456 
457 extern nss_status_t nss_search(nss_db_root_t *, nss_db_initf_t,
458 			int search_fnum, void *search_args);
459 extern nss_status_t nss_getent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *,
460 			void *getent_args);
461 extern void nss_setent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *);
462 extern void nss_endent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *);
463 extern void nss_delete(nss_db_root_t *);
464 
465 extern nss_status_t nss_pack(void *, size_t, nss_db_root_t *,
466 			nss_db_initf_t, int, void *);
467 extern nss_status_t nss_pack_ent(void *, size_t, nss_db_root_t *,
468 			nss_db_initf_t, nss_getent_t *);
469 extern nss_status_t nss_unpack(void *, size_t, nss_db_root_t *,
470 			nss_db_initf_t, int, void *);
471 extern nss_status_t nss_unpack_ent(void *, size_t, nss_db_root_t *,
472 			nss_db_initf_t, nss_getent_t *, void *);
473 
474 extern nss_status_t _nsc_search(nss_db_root_t *, nss_db_initf_t,
475 			int search_fnum, void *search_args);
476 extern nss_status_t _nsc_getent_u(nss_db_root_t *, nss_db_initf_t,
477 			nss_getent_t *, void *getent_args);
478 extern nss_status_t _nsc_setent_u(nss_db_root_t *, nss_db_initf_t,
479 			nss_getent_t *);
480 extern nss_status_t _nsc_endent_u(nss_db_root_t *, nss_db_initf_t,
481 			nss_getent_t *);
482 
483 #else
484 extern nss_status_t nss_config();
485 
486 extern nss_status_t nss_search();
487 extern nss_status_t nss_getent();
488 extern void nss_setent();
489 extern void nss_endent();
490 extern void nss_delete();
491 
492 extern int nss_pack();
493 extern int nss_pack_ent();
494 extern int nss_unpack();
495 extern int nss_unpack_ent();
496 
497 extern nss_status_t _nsc_search();
498 extern nss_status_t _nsc_getent_u();
499 extern nss_status_t _nsc_setent_u();
500 extern nss_status_t _nsc_endent_u();
501 #endif
502 
503 #ifdef	__cplusplus
504 }
505 #endif
506 
507 #endif /* _NSS_COMMON_H */
508