Home | History | Annotate | Download | only in head
      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