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