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 */