| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Copyright (c) 1998-2016 Free Software Foundation, Inc. | 
 | 2 |    This file is part of the GNU C Library. | 
 | 3 |    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. | 
 | 4 |  | 
 | 5 |    The GNU C Library is free software; you can redistribute it and/or | 
 | 6 |    modify it under the terms of the GNU Lesser General Public | 
 | 7 |    License as published by the Free Software Foundation; either | 
 | 8 |    version 2.1 of the License, or (at your option) any later version. | 
 | 9 |  | 
 | 10 |    The GNU C Library is distributed in the hope that it will be useful, | 
 | 11 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 12 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 13 |    Lesser General Public License for more details. | 
 | 14 |  | 
 | 15 |    You should have received a copy of the GNU Lesser General Public | 
 | 16 |    License along with the GNU C Library; if not, see | 
 | 17 |    <http://www.gnu.org/licenses/>.  */ | 
 | 18 |  | 
 | 19 | /* This file defines everything that client code should need to | 
 | 20 |    know to talk to the nscd daemon.  */ | 
 | 21 |  | 
 | 22 | #ifndef _NSCD_CLIENT_H | 
 | 23 | #define _NSCD_CLIENT_H	1 | 
 | 24 |  | 
 | 25 | #include <stdbool.h> | 
 | 26 | #include <stdint.h> | 
 | 27 | #include <string.h> | 
 | 28 | #include <time.h> | 
 | 29 | #include <sys/types.h> | 
 | 30 | #include <atomic.h> | 
 | 31 | #include <nscd-types.h> | 
 | 32 | #include <sys/uio.h> | 
 | 33 |  | 
 | 34 |  | 
 | 35 | /* Version number of the daemon interface */ | 
 | 36 | #define NSCD_VERSION 2 | 
 | 37 |  | 
 | 38 | /* Path of the file where the PID of the running system is stored.  */ | 
 | 39 | #define _PATH_NSCDPID	 "/var/run/nscd/nscd.pid" | 
 | 40 |  | 
 | 41 | /* Path for the Unix domain socket.  */ | 
 | 42 | #define _PATH_NSCDSOCKET "/var/run/nscd/socket" | 
 | 43 |  | 
 | 44 | /* Path for the configuration file.  */ | 
 | 45 | #define _PATH_NSCDCONF	 "/etc/nscd.conf" | 
 | 46 |  | 
 | 47 | /* Maximum allowed length for the key.  */ | 
 | 48 | #define MAXKEYLEN 1024 | 
 | 49 |  | 
 | 50 |  | 
 | 51 | /* Available services.  */ | 
 | 52 | typedef enum | 
 | 53 | { | 
 | 54 |   GETPWBYNAME, | 
 | 55 |   GETPWBYUID, | 
 | 56 |   GETGRBYNAME, | 
 | 57 |   GETGRBYGID, | 
 | 58 |   GETHOSTBYNAME, | 
 | 59 |   GETHOSTBYNAMEv6, | 
 | 60 |   GETHOSTBYADDR, | 
 | 61 |   GETHOSTBYADDRv6, | 
 | 62 |   SHUTDOWN,		/* Shut the server down.  */ | 
 | 63 |   GETSTAT,		/* Get the server statistic.  */ | 
 | 64 |   INVALIDATE,           /* Invalidate one special cache.  */ | 
 | 65 |   GETFDPW, | 
 | 66 |   GETFDGR, | 
 | 67 |   GETFDHST, | 
 | 68 |   GETAI, | 
 | 69 |   INITGROUPS, | 
 | 70 |   GETSERVBYNAME, | 
 | 71 |   GETSERVBYPORT, | 
 | 72 |   GETFDSERV, | 
 | 73 |   GETNETGRENT, | 
 | 74 |   INNETGR, | 
 | 75 |   GETFDNETGR, | 
 | 76 |   LASTREQ | 
 | 77 | } request_type; | 
 | 78 |  | 
 | 79 |  | 
 | 80 | /* Header common to all requests */ | 
 | 81 | typedef struct | 
 | 82 | { | 
 | 83 |   int32_t version;	/* Version number of the daemon interface.  */ | 
 | 84 |   request_type type;	/* Service requested.  */ | 
 | 85 |   int32_t key_len;	/* Key length.  */ | 
 | 86 | } request_header; | 
 | 87 |  | 
 | 88 |  | 
 | 89 | /* Structure sent in reply to password query.  Note that this struct is | 
 | 90 |    sent also if the service is disabled or there is no record found.  */ | 
 | 91 | typedef struct | 
 | 92 | { | 
 | 93 |   int32_t version; | 
 | 94 |   int32_t found; | 
 | 95 |   nscd_ssize_t pw_name_len; | 
 | 96 |   nscd_ssize_t pw_passwd_len; | 
 | 97 |   uid_t pw_uid; | 
 | 98 |   gid_t pw_gid; | 
 | 99 |   nscd_ssize_t pw_gecos_len; | 
 | 100 |   nscd_ssize_t pw_dir_len; | 
 | 101 |   nscd_ssize_t pw_shell_len; | 
 | 102 | } pw_response_header; | 
 | 103 |  | 
 | 104 |  | 
 | 105 | /* Structure sent in reply to group query.  Note that this struct is | 
 | 106 |    sent also if the service is disabled or there is no record found.  */ | 
 | 107 | typedef struct | 
 | 108 | { | 
 | 109 |   int32_t version; | 
 | 110 |   int32_t found; | 
 | 111 |   nscd_ssize_t gr_name_len; | 
 | 112 |   nscd_ssize_t gr_passwd_len; | 
 | 113 |   gid_t gr_gid; | 
 | 114 |   nscd_ssize_t gr_mem_cnt; | 
 | 115 | } gr_response_header; | 
 | 116 |  | 
 | 117 |  | 
 | 118 | /* Structure sent in reply to host query.  Note that this struct is | 
 | 119 |    sent also if the service is disabled or there is no record found.  */ | 
 | 120 | typedef struct | 
 | 121 | { | 
 | 122 |   int32_t version; | 
 | 123 |   int32_t found; | 
 | 124 |   nscd_ssize_t h_name_len; | 
 | 125 |   nscd_ssize_t h_aliases_cnt; | 
 | 126 |   int32_t h_addrtype; | 
 | 127 |   int32_t h_length; | 
 | 128 |   nscd_ssize_t h_addr_list_cnt; | 
 | 129 |   int32_t error; | 
 | 130 | } hst_response_header; | 
 | 131 |  | 
 | 132 |  | 
 | 133 | /* Structure sent in reply to addrinfo query.  Note that this struct is | 
 | 134 |    sent also if the service is disabled or there is no record found.  */ | 
 | 135 | typedef struct | 
 | 136 | { | 
 | 137 |   int32_t version; | 
 | 138 |   int32_t found; | 
 | 139 |   nscd_ssize_t naddrs; | 
 | 140 |   nscd_ssize_t addrslen; | 
 | 141 |   nscd_ssize_t canonlen; | 
 | 142 |   int32_t error; | 
 | 143 | } ai_response_header; | 
 | 144 |  | 
 | 145 | /* Structure filled in by __nscd_getai.  */ | 
 | 146 | struct nscd_ai_result | 
 | 147 | { | 
 | 148 |   int naddrs; | 
 | 149 |   char *canon; | 
 | 150 |   uint8_t *family; | 
 | 151 |   char *addrs; | 
 | 152 | }; | 
 | 153 |  | 
 | 154 | /* Structure sent in reply to initgroups query.  Note that this struct is | 
 | 155 |    sent also if the service is disabled or there is no record found.  */ | 
 | 156 | typedef struct | 
 | 157 | { | 
 | 158 |   int32_t version; | 
 | 159 |   int32_t found; | 
 | 160 |   nscd_ssize_t ngrps; | 
 | 161 | } initgr_response_header; | 
 | 162 |  | 
 | 163 |  | 
 | 164 | /* Structure sent in reply to services query.  Note that this struct is | 
 | 165 |    sent also if the service is disabled or there is no record found.  */ | 
 | 166 | typedef struct | 
 | 167 | { | 
 | 168 |   int32_t version; | 
 | 169 |   int32_t found; | 
 | 170 |   nscd_ssize_t s_name_len; | 
 | 171 |   nscd_ssize_t s_proto_len; | 
 | 172 |   nscd_ssize_t s_aliases_cnt; | 
 | 173 |   int32_t s_port; | 
 | 174 | } serv_response_header; | 
 | 175 |  | 
 | 176 |  | 
 | 177 | /* Structure send in reply to netgroup query.  Note that this struct is | 
 | 178 |    sent also if the service is disabled or there is no record found.  */ | 
 | 179 | typedef struct | 
 | 180 | { | 
 | 181 |   int32_t version; | 
 | 182 |   int32_t found; | 
 | 183 |   nscd_ssize_t nresults; | 
 | 184 |   nscd_ssize_t result_len; | 
 | 185 | } netgroup_response_header; | 
 | 186 |  | 
 | 187 | typedef struct | 
 | 188 | { | 
 | 189 |   int32_t version; | 
 | 190 |   int32_t found; | 
 | 191 |   int32_t result; | 
 | 192 | } innetgroup_response_header; | 
 | 193 |  | 
 | 194 |  | 
 | 195 | /* Type for offsets in data part of database.  */ | 
 | 196 | typedef uint32_t ref_t; | 
 | 197 | /* Value for invalid/no reference.  */ | 
 | 198 | #define ENDREF	UINT32_MAX | 
 | 199 |  | 
 | 200 | /* Timestamp type.  */ | 
 | 201 | typedef uint64_t nscd_time_t; | 
 | 202 |  | 
 | 203 | /* Maximum timestamp.  */ | 
 | 204 | #define MAX_TIMEOUT_VALUE \ | 
 | 205 |   (sizeof (time_t) == sizeof (long int) ? LONG_MAX : INT_MAX) | 
 | 206 |  | 
 | 207 | /* Alignment requirement of the beginning of the data region.  */ | 
 | 208 | #define ALIGN 16 | 
 | 209 |  | 
 | 210 |  | 
 | 211 | /* Head of record in data part of database.  */ | 
 | 212 | struct datahead | 
 | 213 | { | 
 | 214 |   nscd_ssize_t allocsize;	/* Allocated Bytes.  */ | 
 | 215 |   nscd_ssize_t recsize;		/* Size of the record.  */ | 
 | 216 |   nscd_time_t timeout;		/* Time when this entry becomes invalid.  */ | 
 | 217 |   uint8_t notfound;		/* Nonzero if data has not been found.  */ | 
 | 218 |   uint8_t nreloads;		/* Reloads without use.  */ | 
 | 219 |   uint8_t usable;		/* False if the entry must be ignored.  */ | 
 | 220 |   uint8_t unused;		/* Unused.  */ | 
 | 221 |   uint32_t ttl;			/* TTL value used.  */ | 
 | 222 |  | 
 | 223 |   /* We need to have the following element aligned for the response | 
 | 224 |      header data types and their use in the 'struct dataset' types | 
 | 225 |      defined in the XXXcache.c files.  */ | 
 | 226 |   union | 
 | 227 |   { | 
 | 228 |     pw_response_header pwdata; | 
 | 229 |     gr_response_header grdata; | 
 | 230 |     hst_response_header hstdata; | 
 | 231 |     ai_response_header aidata; | 
 | 232 |     initgr_response_header initgrdata; | 
 | 233 |     serv_response_header servdata; | 
 | 234 |     netgroup_response_header netgroupdata; | 
 | 235 |     innetgroup_response_header innetgroupdata; | 
 | 236 |     nscd_ssize_t align1; | 
 | 237 |     nscd_time_t align2; | 
 | 238 |   } data[0]; | 
 | 239 | }; | 
 | 240 |  | 
 | 241 | static inline time_t | 
 | 242 | datahead_init_common (struct datahead *head, nscd_ssize_t allocsize, | 
 | 243 | 		      nscd_ssize_t recsize, uint32_t ttl) | 
 | 244 | { | 
 | 245 |   /* Initialize so that we don't write out junk in uninitialized data to the | 
 | 246 |      cache.  */ | 
 | 247 |   memset (head, 0, sizeof (*head)); | 
 | 248 |  | 
 | 249 |   head->allocsize = allocsize; | 
 | 250 |   head->recsize = recsize; | 
 | 251 |   head->usable = true; | 
 | 252 |  | 
 | 253 |   head->ttl = ttl; | 
 | 254 |  | 
 | 255 |   /* Compute and return the timeout time.  */ | 
 | 256 |   return head->timeout = time (NULL) + ttl; | 
 | 257 | } | 
 | 258 |  | 
 | 259 | static inline time_t | 
 | 260 | datahead_init_pos (struct datahead *head, nscd_ssize_t allocsize, | 
 | 261 | 		   nscd_ssize_t recsize, uint8_t nreloads, uint32_t ttl) | 
 | 262 | { | 
 | 263 |   time_t ret = datahead_init_common (head, allocsize, recsize, ttl); | 
 | 264 |  | 
 | 265 |   head->notfound = false; | 
 | 266 |   head->nreloads = nreloads; | 
 | 267 |  | 
 | 268 |   return ret; | 
 | 269 | } | 
 | 270 |  | 
 | 271 | static inline time_t | 
 | 272 | datahead_init_neg (struct datahead *head, nscd_ssize_t allocsize, | 
 | 273 | 		   nscd_ssize_t recsize, uint32_t ttl) | 
 | 274 | { | 
 | 275 |   time_t ret = datahead_init_common (head, allocsize, recsize, ttl); | 
 | 276 |  | 
 | 277 |   /* We don't need to touch nreloads here since it is set to our desired value | 
 | 278 |      (0) when we clear the structure.  */ | 
 | 279 |   head->notfound = true; | 
 | 280 |  | 
 | 281 |   return ret; | 
 | 282 | } | 
 | 283 |  | 
 | 284 | /* Structure for one hash table entry.  */ | 
 | 285 | struct hashentry | 
 | 286 | { | 
 | 287 |   request_type type:8;		/* Which type of dataset.  */ | 
 | 288 |   bool first;			/* True if this was the original key.  */ | 
 | 289 |   nscd_ssize_t len;		/* Length of key.  */ | 
 | 290 |   ref_t key;			/* Pointer to key.  */ | 
 | 291 |   int32_t owner;		/* If secure table, this is the owner.  */ | 
 | 292 |   ref_t next;			/* Next entry in this hash bucket list.  */ | 
 | 293 |   ref_t packet;			/* Records for the result.  */ | 
 | 294 |   union | 
 | 295 |   { | 
 | 296 |     struct hashentry *dellist;	/* Next record to be deleted.  This can be a | 
 | 297 | 				   pointer since only nscd uses this field.  */ | 
 | 298 |     ref_t *prevp;		/* Pointer to field containing forward | 
 | 299 | 				   reference.  */ | 
 | 300 |   }; | 
 | 301 | }; | 
 | 302 |  | 
 | 303 |  | 
 | 304 | /* Current persistent database version.  */ | 
 | 305 | #define DB_VERSION	2 | 
 | 306 |  | 
 | 307 | /* Maximum time allowed between updates of the timestamp.  */ | 
 | 308 | #define MAPPING_TIMEOUT (5 * 60) | 
 | 309 |  | 
 | 310 |  | 
 | 311 | /* Used indices for the EXTRA_DATA element of 'database_pers_head'. | 
 | 312 |    Each database has its own indices.  */ | 
 | 313 | #define NSCD_HST_IDX_CONF_TIMESTAMP	0 | 
 | 314 |  | 
 | 315 |  | 
 | 316 | /* Header of persistent database file.  */ | 
 | 317 | struct database_pers_head | 
 | 318 | { | 
 | 319 |   int32_t version; | 
 | 320 |   int32_t header_size; | 
 | 321 |   volatile int32_t gc_cycle; | 
 | 322 |   volatile int32_t nscd_certainly_running; | 
 | 323 |   volatile nscd_time_t timestamp; | 
 | 324 |   /* Room for extensions.  */ | 
 | 325 |   volatile uint32_t extra_data[4]; | 
 | 326 |  | 
 | 327 |   nscd_ssize_t module; | 
 | 328 |   nscd_ssize_t data_size; | 
 | 329 |  | 
 | 330 |   nscd_ssize_t first_free;	/* Offset of first free byte in data area.  */ | 
 | 331 |  | 
 | 332 |   nscd_ssize_t nentries; | 
 | 333 |   nscd_ssize_t maxnentries; | 
 | 334 |   nscd_ssize_t maxnsearched; | 
 | 335 |  | 
 | 336 |   uint64_t poshit; | 
 | 337 |   uint64_t neghit; | 
 | 338 |   uint64_t posmiss; | 
 | 339 |   uint64_t negmiss; | 
 | 340 |  | 
 | 341 |   uint64_t rdlockdelayed; | 
 | 342 |   uint64_t wrlockdelayed; | 
 | 343 |  | 
 | 344 |   uint64_t addfailed; | 
 | 345 |  | 
 | 346 |   ref_t array[0]; | 
 | 347 | }; | 
 | 348 |  | 
 | 349 |  | 
 | 350 | /* Mapped database record.  */ | 
 | 351 | struct mapped_database | 
 | 352 | { | 
 | 353 |   const struct database_pers_head *head; | 
 | 354 |   const char *data; | 
 | 355 |   size_t mapsize; | 
 | 356 |   int counter;		/* > 0 indicates it is usable.  */ | 
 | 357 |   size_t datasize; | 
 | 358 | }; | 
 | 359 | #define NO_MAPPING ((struct mapped_database *) -1l) | 
 | 360 |  | 
 | 361 | struct locked_map_ptr | 
 | 362 | { | 
 | 363 |   int lock; | 
 | 364 |   struct mapped_database *mapped; | 
 | 365 | }; | 
 | 366 | #define libc_locked_map_ptr(class, name) class struct locked_map_ptr name | 
 | 367 |  | 
 | 368 | /* Try acquiring lock for mapptr, returns true if it succeeds, false | 
 | 369 |    if not.  */ | 
 | 370 | static inline bool | 
 | 371 | __nscd_acquire_maplock (volatile struct locked_map_ptr *mapptr) | 
 | 372 | { | 
 | 373 |   int cnt = 0; | 
 | 374 |   while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock, | 
 | 375 | 								1, 0) != 0, 0)) | 
 | 376 |     { | 
 | 377 |       // XXX Best number of rounds? | 
 | 378 |       if (__glibc_unlikely (++cnt > 5)) | 
 | 379 | 	return false; | 
 | 380 |  | 
 | 381 |       atomic_spin_nop (); | 
 | 382 |     } | 
 | 383 |  | 
 | 384 |   return true; | 
 | 385 | } | 
 | 386 |  | 
 | 387 |  | 
 | 388 | /* Open socket connection to nscd server.  */ | 
 | 389 | extern int __nscd_open_socket (const char *key, size_t keylen, | 
 | 390 | 			       request_type type, void *response, | 
 | 391 | 			       size_t responselen) attribute_hidden; | 
 | 392 |  | 
 | 393 | /* Try to get a file descriptor for the shared meory segment | 
 | 394 |    containing the database.  */ | 
 | 395 | extern struct mapped_database *__nscd_get_mapping (request_type type, | 
 | 396 | 						   const char *key, | 
 | 397 | 						   struct mapped_database **mappedp) attribute_hidden; | 
 | 398 |  | 
 | 399 | /* Get reference of mapping.  */ | 
 | 400 | extern struct mapped_database *__nscd_get_map_ref (request_type type, | 
 | 401 | 						   const char *name, | 
 | 402 | 						   volatile struct locked_map_ptr *mapptr, | 
 | 403 | 						   int *gc_cyclep); | 
 | 404 |  | 
 | 405 | /* Unmap database.  */ | 
 | 406 | extern void __nscd_unmap (struct mapped_database *mapped); | 
 | 407 |  | 
 | 408 | /* Drop reference of mapping.  */ | 
 | 409 | static int | 
 | 410 | __attribute__ ((unused)) | 
 | 411 | __nscd_drop_map_ref (struct mapped_database *map, int *gc_cycle) | 
 | 412 | { | 
 | 413 |   if (map != NO_MAPPING) | 
 | 414 |     { | 
 | 415 |       int now_cycle = map->head->gc_cycle; | 
 | 416 |       if (__glibc_unlikely (now_cycle != *gc_cycle)) | 
 | 417 | 	{ | 
 | 418 | 	  /* We might have read inconsistent data.  */ | 
 | 419 | 	  *gc_cycle = now_cycle; | 
 | 420 | 	  return -1; | 
 | 421 | 	} | 
 | 422 |  | 
 | 423 |       if (atomic_decrement_val (&map->counter) == 0) | 
 | 424 | 	__nscd_unmap (map); | 
 | 425 |     } | 
 | 426 |  | 
 | 427 |   return 0; | 
 | 428 | } | 
 | 429 |  | 
 | 430 |  | 
 | 431 | /* Search the mapped database.  */ | 
 | 432 | extern struct datahead *__nscd_cache_search (request_type type, | 
 | 433 | 					     const char *key, | 
 | 434 | 					     size_t keylen, | 
 | 435 | 					     const struct mapped_database *mapped, | 
 | 436 | 					     size_t datalen); | 
 | 437 |  | 
 | 438 | /* Wrappers around read, readv and write that only read/write less than LEN | 
 | 439 |    bytes on error or EOF.  */ | 
 | 440 | extern ssize_t __readall (int fd, void *buf, size_t len) | 
 | 441 |   attribute_hidden; | 
 | 442 | extern ssize_t __readvall (int fd, const struct iovec *iov, int iovcnt) | 
 | 443 |   attribute_hidden; | 
 | 444 | extern ssize_t writeall (int fd, const void *buf, size_t len) | 
 | 445 |   attribute_hidden; | 
 | 446 | extern ssize_t sendfileall (int tofd, int fromfd, off_t off, size_t len) | 
 | 447 |   attribute_hidden; | 
 | 448 |  | 
 | 449 | /* Get netlink timestamp counter from mapped area or zero.  */ | 
 | 450 | extern uint32_t __nscd_get_nl_timestamp (void); | 
 | 451 |  | 
 | 452 | #endif /* nscd.h */ |