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