]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/pwdcache.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / nscd / pwdcache.c
CommitLineData
67479a70 1/* Cache handling for passwd lookup.
bfff8b1b 2 Copyright (C) 1998-2017 Free Software Foundation, Inc.
d67281a7 3 This file is part of the GNU C Library.
67479a70 4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
d67281a7 5
43bc8ac6 6 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; version 2 of the License, or
9 (at your option) any later version.
d67281a7 10
43bc8ac6 11 This program is distributed in the hope that it will be useful,
d67281a7 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
d67281a7 15
43bc8ac6 16 You should have received a copy of the GNU General Public License
59ba27a6 17 along with this program; if not, see <http://www.gnu.org/licenses/>. */
d67281a7 18
9caf4f1c 19#include <alloca.h>
a95a08b4 20#include <assert.h>
d67281a7 21#include <errno.h>
67479a70 22#include <error.h>
a95a08b4 23#include <libintl.h>
d67281a7 24#include <pwd.h>
c7a9b6e2 25#include <stdbool.h>
67479a70
UD
26#include <stddef.h>
27#include <stdio.h>
28#include <stdlib.h>
d67281a7 29#include <string.h>
67479a70 30#include <time.h>
ba9234d9 31#include <unistd.h>
a95a08b4 32#include <sys/mman.h>
0b20008e 33#include <sys/socket.h>
c7a9b6e2 34#include <stackinfo.h>
d67281a7 35
d67281a7 36#include "nscd.h"
67479a70 37#include "dbg_log.h"
eac10791
UD
38#ifdef HAVE_SENDFILE
39# include <kernel-features.h>
40#endif
d67281a7 41
67479a70
UD
42/* This is the standard reply in case the service is disabled. */
43static const pw_response_header disabled =
44{
c2e13112
RM
45 .version = NSCD_VERSION,
46 .found = -1,
47 .pw_name_len = 0,
48 .pw_passwd_len = 0,
49 .pw_uid = -1,
50 .pw_gid = -1,
51 .pw_gecos_len = 0,
52 .pw_dir_len = 0,
53 .pw_shell_len = 0
d67281a7 54};
d67281a7 55
67479a70
UD
56/* This is the struct describing how to write this record. */
57const struct iovec pwd_iov_disabled =
d67281a7 58{
c2e13112
RM
59 .iov_base = (void *) &disabled,
60 .iov_len = sizeof (disabled)
d67281a7 61};
d67281a7 62
d67281a7 63
67479a70
UD
64/* This is the standard reply in case we haven't found the dataset. */
65static const pw_response_header notfound =
d67281a7 66{
c2e13112
RM
67 .version = NSCD_VERSION,
68 .found = 0,
69 .pw_name_len = 0,
70 .pw_passwd_len = 0,
71 .pw_uid = -1,
72 .pw_gid = -1,
73 .pw_gecos_len = 0,
74 .pw_dir_len = 0,
75 .pw_shell_len = 0
67479a70 76};
d67281a7 77
d67281a7 78
a4c7ea7b 79static time_t
a95a08b4
UD
80cache_addpw (struct database_dyn *db, int fd, request_header *req,
81 const void *key, struct passwd *pwd, uid_t owner,
20e498bd 82 struct hashentry *const he, struct datahead *dh, int errval)
d67281a7 83{
306dfba9 84 bool all_written = true;
67479a70 85 ssize_t total;
67479a70 86 time_t t = time (NULL);
d67281a7 87
a95a08b4
UD
88 /* We allocate all data in one memory block: the iov vector,
89 the response header and the dataset itself. */
90 struct dataset
91 {
92 struct datahead head;
93 pw_response_header resp;
94 char strdata[0];
95 } *dataset;
96
97 assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
98
a4c7ea7b 99 time_t timeout = MAX_TIMEOUT_VALUE;
67479a70 100 if (pwd == NULL)
d67281a7 101 {
a95a08b4
UD
102 if (he != NULL && errval == EAGAIN)
103 {
104 /* If we have an old record available but cannot find one
105 now because the service is not available we keep the old
106 record and make sure it does not get removed. */
107 if (reload_count != UINT_MAX && dh->nreloads == reload_count)
108 /* Do not reset the value if we never not reload the record. */
109 dh->nreloads = reload_count - 1;
110
a4c7ea7b
UD
111 /* Reload with the same time-to-live value. */
112 timeout = dh->timeout = t + db->postimeout;
113
306dfba9 114 total = 0;
a95a08b4
UD
115 }
116 else
117 {
118 /* We have no data. This means we send the standard reply for this
119 case. */
306dfba9 120 total = sizeof (notfound);
d67281a7 121
306dfba9
AS
122 if (fd != -1
123 && TEMP_FAILURE_RETRY (send (fd, &notfound, total,
124 MSG_NOSIGNAL)) != total)
125 all_written = false;
d67281a7 126
3e1aa84e
UD
127 /* If we have a transient error or cannot permanently store
128 the result, so be it. */
129 if (errno == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
445b4a53
TK
130 {
131 /* Mark the old entry as obsolete. */
132 if (dh != NULL)
133 dh->usable = false;
134 }
99231d9a
UD
135 else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
136 + req->key_len), 1)) != NULL)
a95a08b4 137 {
1cdeb237
SP
138 timeout = datahead_init_neg (&dataset->head,
139 (sizeof (struct dataset)
140 + req->key_len), total,
141 db->negtimeout);
d67281a7 142
a95a08b4
UD
143 /* This is the reply. */
144 memcpy (&dataset->resp, &notfound, total);
d67281a7 145
a95a08b4
UD
146 /* Copy the key data. */
147 char *key_copy = memcpy (dataset->strdata, key, req->key_len);
d67281a7 148
cf244b74
UD
149 /* If necessary, we also propagate the data to disk. */
150 if (db->persistent)
151 {
152 // XXX async OK?
153 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
154 msync ((void *) pval,
155 ((uintptr_t) dataset & pagesize_m1)
156 + sizeof (struct dataset) + req->key_len, MS_ASYNC);
157 }
158
7e71e55f 159 (void) cache_add (req->type, key_copy, req->key_len,
528741cb 160 &dataset->head, true, db, owner, he == NULL);
a95a08b4 161
00ebd7ed
UD
162 pthread_rwlock_unlock (&db->lock);
163
a95a08b4
UD
164 /* Mark the old entry as obsolete. */
165 if (dh != NULL)
166 dh->usable = false;
167 }
99bb9f42 168 }
d67281a7
UD
169 }
170 else
171 {
67479a70 172 /* Determine the I/O structure. */
67479a70
UD
173 size_t pw_name_len = strlen (pwd->pw_name) + 1;
174 size_t pw_passwd_len = strlen (pwd->pw_passwd) + 1;
175 size_t pw_gecos_len = strlen (pwd->pw_gecos) + 1;
176 size_t pw_dir_len = strlen (pwd->pw_dir) + 1;
177 size_t pw_shell_len = strlen (pwd->pw_shell) + 1;
178 char *cp;
a95a08b4
UD
179 const size_t key_len = strlen (key);
180 const size_t buf_len = 3 * sizeof (pwd->pw_uid) + key_len + 1;
181 char *buf = alloca (buf_len);
67479a70
UD
182 ssize_t n;
183
184 /* We need this to insert the `byuid' entry. */
a95a08b4
UD
185 int key_offset;
186 n = snprintf (buf, buf_len, "%d%c%n%s", pwd->pw_uid, '\0',
187 &key_offset, (char *) key) + 1;
188
306dfba9
AS
189 total = (offsetof (struct dataset, strdata)
190 + pw_name_len + pw_passwd_len
191 + pw_gecos_len + pw_dir_len + pw_shell_len);
a95a08b4
UD
192
193 /* If we refill the cache, first assume the reconrd did not
194 change. Allocate memory on the cache since it is likely
195 discarded anyway. If it turns out to be necessary to have a
196 new record we can still allocate real memory. */
197 bool alloca_used = false;
198 dataset = NULL;
199
200 if (he == NULL)
bd499987
AS
201 {
202 /* Prevent an INVALIDATE request from pruning the data between
203 the two calls to cache_add. */
204 if (db->propagate)
205 pthread_mutex_lock (&db->prune_run_lock);
206 dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
207 }
a95a08b4
UD
208
209 if (dataset == NULL)
210 {
bd499987
AS
211 if (he == NULL && db->propagate)
212 pthread_mutex_unlock (&db->prune_run_lock);
213
a95a08b4
UD
214 /* We cannot permanently add the result in the moment. But
215 we can provide the result as is. Store the data in some
216 temporary memory. */
217 dataset = (struct dataset *) alloca (total + n);
218
219 /* We cannot add this record to the permanent database. */
220 alloca_used = true;
221 }
222
1cdeb237
SP
223 timeout = datahead_init_pos (&dataset->head, total + n,
224 total - offsetof (struct dataset, resp),
225 he == NULL ? 0 : dh->nreloads + 1,
226 db->postimeout);
a95a08b4
UD
227
228 dataset->resp.version = NSCD_VERSION;
229 dataset->resp.found = 1;
230 dataset->resp.pw_name_len = pw_name_len;
231 dataset->resp.pw_passwd_len = pw_passwd_len;
232 dataset->resp.pw_uid = pwd->pw_uid;
233 dataset->resp.pw_gid = pwd->pw_gid;
234 dataset->resp.pw_gecos_len = pw_gecos_len;
235 dataset->resp.pw_dir_len = pw_dir_len;
236 dataset->resp.pw_shell_len = pw_shell_len;
237
238 cp = dataset->strdata;
67479a70
UD
239
240 /* Copy the strings over into the buffer. */
241 cp = mempcpy (cp, pwd->pw_name, pw_name_len);
242 cp = mempcpy (cp, pwd->pw_passwd, pw_passwd_len);
243 cp = mempcpy (cp, pwd->pw_gecos, pw_gecos_len);
244 cp = mempcpy (cp, pwd->pw_dir, pw_dir_len);
245 cp = mempcpy (cp, pwd->pw_shell, pw_shell_len);
246
a95a08b4 247 /* Finally the stringified UID value. */
67479a70 248 memcpy (cp, buf, n);
a95a08b4
UD
249 char *key_copy = cp + key_offset;
250 assert (key_copy == (char *) rawmemchr (cp, '\0') + 1);
67479a70 251
5a337776
UD
252 assert (cp == dataset->strdata + total - offsetof (struct dataset,
253 strdata));
254
a95a08b4
UD
255 /* Now we can determine whether on refill we have to create a new
256 record or not. */
257 if (he != NULL)
258 {
259 assert (fd == -1);
801ddb6a 260
20e498bd 261 if (dataset->head.allocsize == dh->allocsize
5a337776 262 && dataset->head.recsize == dh->recsize
a95a08b4
UD
263 && memcmp (&dataset->resp, dh->data,
264 dh->allocsize - offsetof (struct dataset, resp)) == 0)
265 {
cf244b74 266 /* The data has not changed. We will just bump the
a95a08b4
UD
267 timeout value. Note that the new record has been
268 allocated on the stack and need not be freed. */
269 dh->timeout = dataset->head.timeout;
270 ++dh->nreloads;
271 }
272 else
273 {
274 /* We have to create a new record. Just allocate
275 appropriate memory and copy it. */
276 struct dataset *newp
20e498bd 277 = (struct dataset *) mempool_alloc (db, total + n, 1);
a95a08b4
UD
278 if (newp != NULL)
279 {
280 /* Adjust pointer into the memory block. */
281 cp = (char *) newp + (cp - (char *) dataset);
61705e06 282 key_copy = (char *) newp + (key_copy - (char *) dataset);
a95a08b4
UD
283
284 dataset = memcpy (newp, dataset, total + n);
285 alloca_used = false;
286 }
287
288 /* Mark the old record as obsolete. */
289 dh->usable = false;
290 }
291 }
292 else
293 {
294 /* We write the dataset before inserting it to the database
295 since while inserting this thread might block and so would
296 unnecessarily let the receiver wait. */
297 assert (fd != -1);
67479a70 298
eac10791 299#ifdef HAVE_SENDFILE
74158740 300 if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
eac10791
UD
301 {
302 assert (db->wr_fd != -1);
303 assert ((char *) &dataset->resp > (char *) db->data);
ea547a1a 304 assert ((char *) dataset - (char *) db->head
eac10791
UD
305 + total
306 <= (sizeof (struct database_pers_head)
a4c7ea7b
UD
307 + db->head->module * sizeof (ref_t)
308 + db->head->data_size));
306dfba9
AS
309 ssize_t written = sendfileall (fd, db->wr_fd,
310 (char *) &dataset->resp
311 - (char *) db->head,
312 dataset->head.recsize);
313 if (written != dataset->head.recsize)
314 {
eac10791 315# ifndef __ASSUME_SENDFILE
306dfba9
AS
316 if (written == -1 && errno == ENOSYS)
317 goto use_write;
eac10791 318# endif
306dfba9
AS
319 all_written = false;
320 }
eac10791
UD
321 }
322 else
323# ifndef __ASSUME_SENDFILE
324 use_write:
325# endif
326#endif
306dfba9
AS
327 if (writeall (fd, &dataset->resp, dataset->head.recsize)
328 != dataset->head.recsize)
329 all_written = false;
a95a08b4 330 }
67479a70 331
67479a70 332
a95a08b4
UD
333 /* Add the record to the database. But only if it has not been
334 stored on the stack. */
335 if (! alloca_used)
336 {
337 /* If necessary, we also propagate the data to disk. */
338 if (db->persistent)
3418007e
UD
339 {
340 // XXX async OK?
341 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
342 msync ((void *) pval,
343 ((uintptr_t) dataset & pagesize_m1) + total + n,
344 MS_ASYNC);
345 }
67479a70 346
a95a08b4
UD
347 /* NB: in the following code we always must add the entry
348 marked with FIRST first. Otherwise we end up with
349 dangling "pointers" in case a latter hash entry cannot be
350 added. */
797ed6f7 351 bool first = true;
67479a70 352
a95a08b4 353 /* If the request was by UID, add that entry first. */
797ed6f7 354 if (req->type == GETPWBYUID)
a95a08b4 355 {
03e157d8 356 if (cache_add (GETPWBYUID, cp, key_offset, &dataset->head, true,
528741cb 357 db, owner, he == NULL) < 0)
7e71e55f 358 goto out;
797ed6f7
UD
359
360 first = false;
a95a08b4
UD
361 }
362 /* If the key is different from the name add a separate entry. */
363 else if (strcmp (key_copy, dataset->strdata) != 0)
364 {
365 if (cache_add (GETPWBYNAME, key_copy, key_len + 1,
528741cb 366 &dataset->head, true, db, owner, he == NULL) < 0)
7e71e55f 367 goto out;
a95a08b4
UD
368
369 first = false;
370 }
371
372 /* We have to add the value for both, byname and byuid. */
797ed6f7
UD
373 if ((req->type == GETPWBYNAME || db->propagate)
374 && __builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
375 pw_name_len, &dataset->head,
528741cb
UD
376 first, db, owner, he == NULL)
377 == 0, 1))
a95a08b4 378 {
797ed6f7 379 if (req->type == GETPWBYNAME && db->propagate)
03e157d8 380 (void) cache_add (GETPWBYUID, cp, key_offset, &dataset->head,
528741cb 381 false, db, owner, false);
a95a08b4 382 }
00ebd7ed
UD
383
384 out:
385 pthread_rwlock_unlock (&db->lock);
bd499987
AS
386 if (he == NULL && db->propagate)
387 pthread_mutex_unlock (&db->prune_run_lock);
a95a08b4 388 }
d67281a7 389 }
14e9dd67 390
306dfba9 391 if (__builtin_expect (!all_written, 0) && debug_level > 0)
d67281a7 392 {
67479a70
UD
393 char buf[256];
394 dbg_log (_("short write in %s: %s"), __FUNCTION__,
395 strerror_r (errno, buf, sizeof (buf)));
d67281a7 396 }
a4c7ea7b
UD
397
398 return timeout;
d67281a7
UD
399}
400
d67281a7 401
a95a08b4
UD
402union keytype
403{
404 void *v;
405 uid_t u;
406};
407
408
409static int
410lookup (int type, union keytype key, struct passwd *resultbufp, char *buffer,
411 size_t buflen, struct passwd **pwd)
412{
413 if (type == GETPWBYNAME)
414 return __getpwnam_r (key.v, resultbufp, buffer, buflen, pwd);
415 else
416 return __getpwuid_r (key.u, resultbufp, buffer, buflen, pwd);
417}
418
419
a4c7ea7b 420static time_t
a95a08b4
UD
421addpwbyX (struct database_dyn *db, int fd, request_header *req,
422 union keytype key, const char *keystr, uid_t c_uid,
423 struct hashentry *he, struct datahead *dh)
67479a70
UD
424{
425 /* Search for the entry matching the key. Please note that we don't
426 look again in the table whether the dataset is now available. We
427 simply insert it. It does not matter if it is in there twice. The
428 pruning function only will look at the timestamp. */
a95a08b4 429 size_t buflen = 1024;
c7a9b6e2 430 char *buffer = (char *) alloca (buflen);
67479a70
UD
431 struct passwd resultbuf;
432 struct passwd *pwd;
c7a9b6e2 433 bool use_malloc = false;
a95a08b4 434 int errval = 0;
d67281a7 435
a1ffb40e 436 if (__glibc_unlikely (debug_level > 0))
a95a08b4
UD
437 {
438 if (he == NULL)
439 dbg_log (_("Haven't found \"%s\" in password cache!"), keystr);
440 else
441 dbg_log (_("Reloading \"%s\" in password cache!"), keystr);
442 }
d67281a7 443
a95a08b4
UD
444 while (lookup (req->type, key, &resultbuf, buffer, buflen, &pwd) != 0
445 && (errval = errno) == ERANGE)
d67281a7 446 {
67479a70 447 errno = 0;
c7a9b6e2 448
a1ffb40e 449 if (__glibc_unlikely (buflen > 32768))
c7a9b6e2 450 {
b21fa963 451 char *old_buffer = buffer;
4379b403 452 buflen *= 2;
c7a9b6e2
UD
453 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
454 if (buffer == NULL)
455 {
456 /* We ran out of memory. We cannot do anything but
457 sending a negative response. In reality this should
458 never happen. */
459 pwd = NULL;
460 buffer = old_buffer;
a95a08b4
UD
461
462 /* We set the error to indicate this is (possibly) a
463 temporary error and that it does not mean the entry
464 is not available at all. */
465 errval = EAGAIN;
c7a9b6e2
UD
466 break;
467 }
468 use_malloc = true;
469 }
470 else
9caf4f1c
UD
471 /* Allocate a new buffer on the stack. If possible combine it
472 with the previously allocated buffer. */
4379b403 473 buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
d67281a7 474 }
14e9dd67 475
a95a08b4 476 /* Add the entry to the cache. */
a4c7ea7b
UD
477 time_t timeout = cache_addpw (db, fd, req, keystr, pwd, c_uid, he, dh,
478 errval);
c7a9b6e2
UD
479
480 if (use_malloc)
481 free (buffer);
a4c7ea7b
UD
482
483 return timeout;
d67281a7
UD
484}
485
d67281a7 486
67479a70 487void
a95a08b4
UD
488addpwbyname (struct database_dyn *db, int fd, request_header *req,
489 void *key, uid_t c_uid)
490{
491 union keytype u = { .v = key };
492
493 addpwbyX (db, fd, req, u, key, c_uid, NULL, NULL);
494}
495
496
a4c7ea7b 497time_t
a95a08b4
UD
498readdpwbyname (struct database_dyn *db, struct hashentry *he,
499 struct datahead *dh)
500{
501 request_header req =
502 {
503 .type = GETPWBYNAME,
504 .key_len = he->len
505 };
506 union keytype u = { .v = db->data + he->key };
507
a4c7ea7b 508 return addpwbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
a95a08b4
UD
509}
510
511
512void
513addpwbyuid (struct database_dyn *db, int fd, request_header *req,
a1c542bf 514 void *key, uid_t c_uid)
67479a70 515{
8e9b2075 516 char *ep;
c7a9b6e2 517 uid_t uid = strtoul ((char *) key, &ep, 10);
c7a9b6e2
UD
518
519 if (*(char *) key == '\0' || *ep != '\0') /* invalid numeric uid */
8e9b2075 520 {
c7a9b6e2 521 if (debug_level > 0)
a4c7ea7b 522 dbg_log (_("Invalid numeric uid \"%s\"!"), (char *) key);
8e9b2075
UD
523
524 errno = EINVAL;
525 return;
526 }
d67281a7 527
a95a08b4 528 union keytype u = { .u = uid };
d67281a7 529
a95a08b4
UD
530 addpwbyX (db, fd, req, u, key, c_uid, NULL, NULL);
531}
a1c542bf 532
c7a9b6e2 533
a4c7ea7b 534time_t
a95a08b4
UD
535readdpwbyuid (struct database_dyn *db, struct hashentry *he,
536 struct datahead *dh)
537{
538 char *ep;
539 uid_t uid = strtoul (db->data + he->key, &ep, 10);
d67281a7 540
a95a08b4
UD
541 /* Since the key has been added before it must be OK. */
542 assert (*(db->data + he->key) != '\0' && *ep == '\0');
a1c542bf 543
a95a08b4
UD
544 request_header req =
545 {
546 .type = GETPWBYUID,
547 .key_len = he->len
548 };
549 union keytype u = { .u = uid };
c7a9b6e2 550
a4c7ea7b 551 return addpwbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
d67281a7 552}