2 * Copyright (c) 1990 - 1994, Julianne Frances Haugh
3 * Copyright (c) 1996 - 2001, Marek Michałkiewicz
4 * Copyright (c) 2001 - 2006, Tomasz Kłoczko
5 * Copyright (c) 2007 - 2010, Nicolas François
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the copyright holders or contributors may not be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 #include <selinux/selinux.h>
50 #endif /* WITH_SELINUX */
54 #include "prototypes.h"
57 /* local function prototypes */
58 static int lrename (const char *, const char *);
59 static int check_link_count (const char *file);
60 static int do_lock_file (const char *file, const char *lock);
61 static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
64 const struct stat *sb);
65 static int create_backup (const char *, FILE *);
66 static void free_linked_list (struct commonio_db *);
67 static void add_one_entry (
68 struct commonio_db *db,
69 /*@owned@*/struct commonio_entry *p);
70 static bool name_is_nis (const char *name);
71 static int write_all (const struct commonio_db *);
72 static /*@dependent@*/ /*@null@*/struct commonio_entry *find_entry_by_name (
75 static /*@dependent@*/ /*@null@*/struct commonio_entry *next_entry_by_name (
77 /*@null@*/struct commonio_entry *pos,
80 static int lock_count = 0;
81 static bool nscd_need_reload = false;
84 * Simple rename(P) alternative that attempts to rename to symlink
87 int lrename (const char *old, const char *new)
94 char resolved_path[PATH_MAX];
95 #endif /* !__GLIBC__ */
97 if (lstat (new, &sb) == 0 && S_ISLNK (sb.st_mode)) {
98 #ifdef __GLIBC__ /* now a POSIX.1-2008 feature */
99 r = realpath (new, NULL);
100 #else /* !__GLIBC__ */
101 r = realpath (new, resolved_path);
102 #endif /* !__GLIBC__ */
104 perror ("realpath in lrename()");
111 res = rename (old, new);
117 #endif /* __GLIBC__ */
122 static int check_link_count (const char *file)
126 if (stat (file, &sb) != 0) {
130 if (sb.st_nlink != 2) {
138 static int do_lock_file (const char *file, const char *lock)
146 fd = open (file, O_CREAT | O_EXCL | O_WRONLY, 0600);
152 snprintf (buf, sizeof buf, "%lu", (unsigned long) pid);
153 len = (ssize_t) strlen (buf) + 1;
154 if (write (fd, buf, (size_t) len) != len) {
161 if (link (file, lock) == 0) {
162 retval = check_link_count (file);
167 fd = open (lock, O_RDWR);
173 len = read (fd, buf, sizeof (buf) - 1);
181 if (get_pid (buf, &pid) == 0) {
186 if (kill (pid, 0) == 0) {
191 if (unlink (lock) != 0) {
197 if ((link (file, lock) == 0) && (check_link_count (file) != 0)) {
206 static /*@null@*/ /*@dependent@*/FILE *fopen_set_perms (
209 const struct stat *sb)
215 fp = fopen (name, mode);
222 if (fchown (fileno (fp), sb->st_uid, sb->st_gid) != 0) {
225 #else /* !HAVE_FCHOWN */
226 if (chown (name, sb->st_mode) != 0) {
229 #endif /* !HAVE_FCHOWN */
232 if (fchmod (fileno (fp), sb->st_mode & 0664) != 0) {
235 #else /* !HAVE_FCHMOD */
236 if (chmod (name, sb->st_mode & 0664) != 0) {
239 #endif /* !HAVE_FCHMOD */
244 /* fopen_set_perms is used for intermediate files */
245 (void) unlink (name);
250 static int create_backup (const char *backup, FILE * fp)
258 if (fstat (fileno (fp), &sb) != 0) {
263 bkfp = fopen (backup, "w");
269 /* TODO: faster copy, not one-char-at-a-time. --marekm */
271 if (fseek (fp, 0, SEEK_SET) == 0) {
272 while ((c = getc (fp)) != EOF) {
273 if (putc (c, bkfp) == EOF) {
278 if ((c != EOF) || (ferror (fp) != 0) || (fflush (bkfp) != 0)) {
279 (void) fclose (bkfp);
280 /* FIXME: unlink the backup file? */
283 if ( (fsync (fileno (bkfp)) != 0)
284 || (fclose (bkfp) != 0)) {
285 /* FIXME: unlink the backup file? */
289 ub.actime = sb.st_atime;
290 ub.modtime = sb.st_mtime;
291 (void) utime (backup, &ub);
296 static void free_linked_list (struct commonio_db *db)
298 struct commonio_entry *p;
300 while (NULL != db->head) {
304 if (NULL != p->line) {
308 if (NULL != p->eptr) {
309 db->ops->free (p->eptr);
318 int commonio_setname (struct commonio_db *db, const char *name)
320 snprintf (db->filename, sizeof (db->filename), "%s", name);
325 bool commonio_present (const struct commonio_db *db)
327 return (access (db->filename, F_OK) == 0);
331 int commonio_lock_nowait (struct commonio_db *db)
340 snprintf (file, sizeof file, "%s.%lu",
341 db->filename, (unsigned long) getpid ());
342 snprintf (lock, sizeof lock, "%s.lock", db->filename);
343 if (do_lock_file (file, lock) != 0) {
352 int commonio_lock (struct commonio_db *db)
356 * only if the system libc has a real lckpwdf() - the one from
357 * lockpw.c calls us and would cause infinite recursion!
361 * Call lckpwdf() on the first lock.
362 * If it succeeds, call *_lock() only once
363 * (no retries, it should always succeed).
365 if (0 == lock_count) {
366 if (lckpwdf () == -1) {
367 return 0; /* failure */
371 if (commonio_lock_nowait (db) != 0) {
372 return 1; /* success */
376 return 0; /* failure */
377 #else /* !HAVE_LCKPWDF */
381 * lckpwdf() not used - do it the old way.
384 #define LOCK_TRIES 15
390 for (i = 0; i < LOCK_TRIES; i++) {
392 sleep (LOCK_SLEEP); /* delay between retries */
394 if (commonio_lock_nowait (db) != 0) {
395 return 1; /* success */
397 /* no unnecessary retries on "permission denied" errors */
398 if (geteuid () != 0) {
402 return 0; /* failure */
403 #endif /* !HAVE_LCKPWDF */
406 static void dec_lock_count (void)
408 if (lock_count > 0) {
410 if (lock_count == 0) {
411 /* Tell nscd when lock count goes to zero,
412 if any of the files were changed. */
413 if (nscd_need_reload) {
414 nscd_flush_cache ("passwd");
415 nscd_flush_cache ("group");
416 nscd_need_reload = false;
420 #endif /* HAVE_LCKPWDF */
426 int commonio_unlock (struct commonio_db *db)
432 if (commonio_close (db) == 0) {
441 * Unlock in reverse order: remove the lock file,
442 * then call ulckpwdf() (if used) on last unlock.
445 snprintf (lock, sizeof lock, "%s.lock", db->filename);
455 * Add an entry at the end.
457 * defines p->next, p->prev
458 * (unfortunately, owned special are not supported)
460 static void add_one_entry (struct commonio_db *db,
461 /*@owned@*/struct commonio_entry *p)
467 if (NULL == db->head) {
470 if (NULL != db->tail) {
477 static bool name_is_nis (const char *name)
479 return (('+' == name[0]) || ('-' == name[0]));
484 * New entries are inserted before the first NIS entry. Order is preserved
485 * when db is written out.
487 #ifndef KEEP_NIS_AT_END
488 #define KEEP_NIS_AT_END 1
492 static void add_one_entry_nis (struct commonio_db *db,
493 /*@owned@*/struct commonio_entry *newp);
496 * Insert an entry between the regular entries, and the NIS entries.
498 * defines newp->next, newp->prev
499 * (unfortunately, owned special are not supported)
501 static void add_one_entry_nis (struct commonio_db *db,
502 /*@owned@*/struct commonio_entry *newp)
504 struct commonio_entry *p;
506 for (p = db->head; NULL != p; p = p->next) {
507 if (name_is_nis (p->eptr ? db->ops->getname (p->eptr)
511 newp->prev = p->prev;
513 if (NULL != p->prev) {
514 p->prev->next = newp;
522 add_one_entry (db, newp);
524 #endif /* KEEP_NIS_AT_END */
526 /* Initial buffer size, as well as increment if not sufficient
527 (for reading very long lines in group files). */
530 int commonio_open (struct commonio_db *db, int mode)
535 struct commonio_entry *p;
545 || ( (O_RDONLY != mode)
546 && (O_RDWR != mode))) {
550 db->readonly = (mode == O_RDONLY);
551 if (!db->readonly && !db->locked) {
556 db->head = db->tail = NULL;
560 fd = open (db->filename,
561 (db->readonly ? O_RDONLY : O_RDWR)
562 | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
567 if (tcb_is_suspect (fd) != 0) {
572 #endif /* WITH_TCB */
573 db->fp = fdopen (fd, db->readonly ? "r" : "r+");
575 if (NULL == db->fp) {
582 * If O_CREAT was specified and the file didn't exist, it will be
583 * created by commonio_close(). We have no entries to read yet. --marekm
585 if (NULL == db->fp) {
586 if (((flags & O_CREAT) != 0) && (ENOENT == errno)) {
593 /* Do not inherit fd in spawned processes (e.g. nscd) */
594 fcntl (fileno (db->fp), F_SETFD, FD_CLOEXEC);
598 if ((is_selinux_enabled () > 0) && (!db->readonly)) {
599 if (fgetfilecon (fileno (db->fp), &db->scontext) < 0) {
603 #endif /* WITH_SELINUX */
606 buf = (char *) malloc (buflen);
611 while (db->ops->fgets (buf, (int) buflen, db->fp) == buf) {
612 while ( ((cp = strrchr (buf, '\n')) == NULL)
613 && (feof (db->fp) == 0)) {
617 cp = (char *) realloc (buf, buflen);
623 if (db->ops->fgets (buf + len,
624 (int) (buflen - len),
629 cp = strrchr (buf, '\n');
639 if (name_is_nis (line)) {
642 eptr = db->ops->parse (line);
644 eptr = db->ops->dup (eptr);
651 p = (struct commonio_entry *) malloc (sizeof *p);
660 add_one_entry (db, p);
665 if (ferror (db->fp) != 0) {
669 if ((NULL != db->ops->open_hook) && (db->ops->open_hook () == 0)) {
678 db->ops->free (eptr);
688 free_linked_list (db);
690 if (db->scontext != NULL) {
691 freecon (db->scontext);
694 #endif /* WITH_SELINUX */
702 * Sort given db according to cmp function (usually compares uids)
705 commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
707 struct commonio_entry **entries, *ptr;
710 struct commonio_entry *nis = NULL;
716 && (NULL != ptr->line)
717 && ('+' != ptr->line[0])
724 if ((NULL != ptr) && (NULL != ptr->line)) {
733 entries = malloc (n * sizeof (struct commonio_entry *));
734 if (entries == NULL) {
752 qsort (entries, n, sizeof (struct commonio_entry *), cmp);
754 /* Take care of the head and tail separately */
755 db->head = entries[0];
761 db->tail = entries[n];
763 db->head->prev = NULL;
764 db->head->next = entries[1];
765 entries[n]->prev = entries[n - 1];
766 entries[n]->next = NULL;
768 /* Now other elements have prev and next entries */
769 for (i = 1; i < n; i++) {
770 entries[i]->prev = entries[i - 1];
771 entries[i]->next = entries[i + 1];
781 * Sort entries in db according to order in another.
783 int commonio_sort_wrt (struct commonio_db *shadow,
784 const struct commonio_db *passwd)
786 struct commonio_entry *head = NULL, *pw_ptr, *spw_ptr;
789 if ((NULL == shadow) || (NULL == shadow->head)) {
793 for (pw_ptr = passwd->head; NULL != pw_ptr; pw_ptr = pw_ptr->next) {
794 if (NULL == pw_ptr->eptr) {
797 name = passwd->ops->getname (pw_ptr->eptr);
798 for (spw_ptr = shadow->head;
800 spw_ptr = spw_ptr->next) {
801 if (NULL == spw_ptr->eptr) {
804 if (strcmp (name, shadow->ops->getname (spw_ptr->eptr))
809 if (NULL == spw_ptr) {
812 commonio_del_entry (shadow, spw_ptr);
813 spw_ptr->next = head;
817 for (spw_ptr = head; NULL != spw_ptr; spw_ptr = head) {
820 if (NULL != shadow->head) {
821 shadow->head->prev = spw_ptr;
823 spw_ptr->next = shadow->head;
824 shadow->head = spw_ptr;
827 shadow->head->prev = NULL;
828 shadow->changed = true;
834 * write_all - Write the database to its file.
836 * It returns 0 if all the entries could be written correctly.
838 static int write_all (const struct commonio_db *db)
839 /*@requires notnull db->fp@*/
841 const struct commonio_entry *p;
844 for (p = db->head; NULL != p; p = p->next) {
847 assert (NULL != eptr);
848 if (db->ops->put (eptr, db->fp) != 0) {
851 } else if (NULL != p->line) {
852 if (db->ops->fputs (p->line, db->fp) == EOF) {
855 if (putc ('\n', db->fp) == EOF) {
864 int commonio_close (struct commonio_db *db)
865 /*@requires notnull db->fp@*/
872 /*@null@*/security_context_t old_context = NULL;
873 #endif /* WITH_SELINUX */
881 if (!db->changed || db->readonly) {
887 if ((NULL != db->ops->close_hook) && (db->ops->close_hook () == 0)) {
891 memzero (&sb, sizeof sb);
892 if (NULL != db->fp) {
893 if (fstat (fileno (db->fp), &sb) != 0) {
899 if (db->scontext != NULL) {
900 if (getfscreatecon (&old_context) < 0) {
904 if (setfscreatecon (db->scontext) < 0) {
909 #endif /* WITH_SELINUX */
911 * Create backup file.
913 snprintf (buf, sizeof buf, "%s-", db->filename);
915 if (create_backup (buf, db->fp) != 0) {
919 if (fclose (db->fp) != 0) {
929 * Default permissions for new [g]shadow files.
930 * (passwd and group always exist...)
937 snprintf (buf, sizeof buf, "%s+", db->filename);
939 db->fp = fopen_set_perms (buf, "w", &sb);
940 if (NULL == db->fp) {
944 if (write_all (db) != 0) {
948 if (fflush (db->fp) != 0) {
952 if (fsync (fileno (db->fp)) != 0) {
955 #else /* !HAVE_FSYNC */
957 #endif /* !HAVE_FSYNC */
958 if (fclose (db->fp) != 0) {
969 if (lrename (buf, db->filename) != 0) {
973 nscd_need_reload = true;
980 if (db->scontext != NULL) {
981 if (NULL != old_context) {
982 if (setfscreatecon (old_context) < 0) {
985 freecon (old_context);
988 freecon (db->scontext);
991 #endif /* WITH_SELINUX */
992 free_linked_list (db);
996 static /*@dependent@*/ /*@null@*/struct commonio_entry *next_entry_by_name (
997 struct commonio_db *db,
998 /*@null@*/struct commonio_entry *pos,
1001 struct commonio_entry *p;
1008 for (p = pos; NULL != p; p = p->next) {
1011 && (strcmp (db->ops->getname (ep), name) == 0)) {
1018 static /*@dependent@*/ /*@null@*/struct commonio_entry *find_entry_by_name (
1019 struct commonio_db *db,
1022 return next_entry_by_name (db, db->head, name);
1026 int commonio_update (struct commonio_db *db, const void *eptr)
1028 struct commonio_entry *p;
1031 if (!db->isopen || db->readonly) {
1035 nentry = db->ops->dup (eptr);
1036 if (NULL == nentry) {
1040 p = find_entry_by_name (db, db->ops->getname (eptr));
1042 if (next_entry_by_name (db, p->next, db->ops->getname (eptr)) != NULL) {
1043 fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename);
1046 db->ops->free (p->eptr);
1054 /* not found, new entry */
1055 p = (struct commonio_entry *) malloc (sizeof *p);
1057 db->ops->free (nentry);
1067 add_one_entry_nis (db, p);
1068 #else /* !KEEP_NIS_AT_END */
1069 add_one_entry (db, p);
1070 #endif /* !KEEP_NIS_AT_END */
1077 void commonio_del_entry (struct commonio_db *db, const struct commonio_entry *p)
1079 if (p == db->cursor) {
1080 db->cursor = p->next;
1083 if (NULL != p->prev) {
1084 p->prev->next = p->next;
1089 if (NULL != p->next) {
1090 p->next->prev = p->prev;
1099 * commonio_remove - Remove the entry of the given name from the database.
1101 int commonio_remove (struct commonio_db *db, const char *name)
1103 struct commonio_entry *p;
1105 if (!db->isopen || db->readonly) {
1109 p = find_entry_by_name (db, name);
1114 if (next_entry_by_name (db, p->next, name) != NULL) {
1115 fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename);
1119 commonio_del_entry (db, p);
1121 if (NULL != p->line) {
1125 if (NULL != p->eptr) {
1126 db->ops->free (p->eptr);
1133 * commonio_locate - Find the first entry with the specified name in
1136 * If found, it returns the entry and set the cursor of the database to
1139 * Otherwise, it returns NULL.
1141 /*@observer@*/ /*@null@*/const void *commonio_locate (struct commonio_db *db, const char *name)
1143 struct commonio_entry *p;
1149 p = find_entry_by_name (db, name);
1159 * commonio_rewind - Restore the database cursor to the first entry.
1161 * It returns 0 on error, 1 on success.
1163 int commonio_rewind (struct commonio_db *db)
1174 * commonio_next - Return the next entry of the specified database
1176 * It returns the next entry, or NULL if no other entries could be found.
1178 /*@observer@*/ /*@null@*/const void *commonio_next (struct commonio_db *db)
1186 if (NULL == db->cursor) {
1187 db->cursor = db->head;
1189 db->cursor = db->cursor->next;
1192 while (NULL != db->cursor) {
1193 eptr = db->cursor->eptr;
1198 db->cursor = db->cursor->next;