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