]> granicus.if.org Git - shadow/blob - lib/commonio.c
5cfd9babb2aad626f6cb224962210e1b2952db58
[shadow] / lib / commonio.c
1 /*
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 - 2009, Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
19  *
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.
31  */
32
33 #include <config.h>
34
35 #ident "$Id$"
36
37 #include "defines.h"
38 #include <sys/stat.h>
39 #include <stdlib.h>
40 #include <limits.h>
41 #include <utime.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <signal.h>
46 #include "nscd.h"
47 #ifdef WITH_SELINUX
48 #include <selinux/selinux.h>
49 static security_context_t old_context = NULL;
50 #endif
51 #include "commonio.h"
52
53 /* local function prototypes */
54 static int lrename (const char *, const char *);
55 static int check_link_count (const char *file);
56 static int do_lock_file (const char *file, const char *lock);
57 static FILE *fopen_set_perms (const char *, const char *, const struct stat *);
58 static int create_backup (const char *, FILE *);
59 static void free_linked_list (struct commonio_db *);
60 static void add_one_entry (struct commonio_db *, struct commonio_entry *);
61 static bool name_is_nis (const char *name);
62 static int write_all (const struct commonio_db *);
63 static struct commonio_entry *find_entry_by_name (struct commonio_db *,
64                                                   const char *);
65 static struct commonio_entry *next_entry_by_name (struct commonio_db *,
66                                                   struct commonio_entry *pos,
67                                                   const char *);
68
69 static int lock_count = 0;
70 static bool nscd_need_reload = false;
71
72 /*
73  * Simple rename(P) alternative that attempts to rename to symlink
74  * target.
75  */
76 int lrename (const char *old, const char *new)
77 {
78
79         char resolved_path[PATH_MAX];
80         int res;
81
82 #if defined(S_ISLNK)
83         struct stat sb;
84         if (lstat (new, &sb) == 0 && S_ISLNK (sb.st_mode)) {
85                 if (realpath (new, resolved_path) == NULL) {
86                         perror ("realpath in lrename()");
87                 } else {
88                         new = resolved_path;
89                 }
90         }
91 #endif
92         res = rename (old, new);
93         return res;
94 }
95
96 static int check_link_count (const char *file)
97 {
98         struct stat sb;
99
100         if (stat (file, &sb) != 0) {
101                 return 0;
102         }
103
104         if (sb.st_nlink != 2) {
105                 return 0;
106         }
107
108         return 1;
109 }
110
111
112 static int do_lock_file (const char *file, const char *lock)
113 {
114         int fd;
115         pid_t pid;
116         ssize_t len;
117         int retval;
118         char buf[32];
119
120         fd = open (file, O_CREAT | O_EXCL | O_WRONLY, 0600);
121         if (-1 == fd) {
122                 return 0;
123         }
124
125         pid = getpid ();
126         snprintf (buf, sizeof buf, "%lu", (unsigned long) pid);
127         len = (ssize_t) strlen (buf) + 1;
128         if (write (fd, buf, (size_t) len) != len) {
129                 (void) close (fd);
130                 unlink (file);
131                 return 0;
132         }
133         close (fd);
134
135         if (link (file, lock) == 0) {
136                 retval = check_link_count (file);
137                 unlink (file);
138                 return retval;
139         }
140
141         fd = open (lock, O_RDWR);
142         if (-1 == fd) {
143                 unlink (file);
144                 errno = EINVAL;
145                 return 0;
146         }
147         len = read (fd, buf, sizeof (buf) - 1);
148         close (fd);
149         if (len <= 0) {
150                 unlink (file);
151                 errno = EINVAL;
152                 return 0;
153         }
154         buf[len] = '\0';
155         /* FIXME: use a get_pid */
156         pid = strtol (buf, (char **) 0, 10);
157         if (0 == pid) {
158                 unlink (file);
159                 errno = EINVAL;
160                 return 0;
161         }
162         if (kill (pid, 0) == 0) {
163                 unlink (file);
164                 errno = EEXIST;
165                 return 0;
166         }
167         if (unlink (lock) != 0) {
168                 unlink (file);
169                 return 0;
170         }
171
172         retval = 0;
173         if ((link (file, lock) == 0) && (check_link_count (file) != 0)) {
174                 retval = 1;
175         }
176
177         unlink (file);
178         return retval;
179 }
180
181
182 static FILE *fopen_set_perms (const char *name, const char *mode,
183                               const struct stat *sb)
184 {
185         FILE *fp;
186         mode_t mask;
187
188         mask = umask (0777);
189         fp = fopen (name, mode);
190         (void) umask (mask);
191         if (NULL == fp) {
192                 return NULL;
193         }
194
195 #ifdef HAVE_FCHOWN
196         if (fchown (fileno (fp), sb->st_uid, sb->st_gid) != 0) {
197                 goto fail;
198         }
199 #else
200         if (chown (name, sb->st_mode) != 0) {
201                 goto fail;
202         }
203 #endif
204
205 #ifdef HAVE_FCHMOD
206         if (fchmod (fileno (fp), sb->st_mode & 0664) != 0) {
207                 goto fail;
208         }
209 #else
210         if (chmod (name, sb->st_mode & 0664) != 0) {
211                 goto fail;
212         }
213 #endif
214         return fp;
215
216       fail:
217         fclose (fp);
218         unlink (name);
219         return NULL;
220 }
221
222
223 static int create_backup (const char *backup, FILE * fp)
224 {
225         struct stat sb;
226         struct utimbuf ub;
227         FILE *bkfp;
228         int c;
229         mode_t mask;
230
231         if (fstat (fileno (fp), &sb) != 0) {
232                 return -1;
233         }
234
235         mask = umask (077);
236         bkfp = fopen (backup, "w");
237         (void) umask (mask);
238         if (NULL == bkfp) {
239                 return -1;
240         }
241
242         /* TODO: faster copy, not one-char-at-a-time.  --marekm */
243         c = 0;
244         if (fseek (fp, 0, SEEK_SET) == 0) {
245                 while ((c = getc (fp)) != EOF) {
246                         if (putc (c, bkfp) == EOF) {
247                                 break;
248                         }
249                 }
250         }
251         if ((c != EOF) || (ferror (fp) != 0) || (fflush (bkfp) != 0)) {
252                 fclose (bkfp);
253                 return -1;
254         }
255         if (   (fsync (fileno (bkfp)) != 0)
256             || (fclose (bkfp) != 0)) {
257                 return -1;
258         }
259
260         ub.actime = sb.st_atime;
261         ub.modtime = sb.st_mtime;
262         (void) utime (backup, &ub);
263         return 0;
264 }
265
266
267 static void free_linked_list (struct commonio_db *db)
268 {
269         struct commonio_entry *p;
270
271         while (NULL != db->head) {
272                 p = db->head;
273                 db->head = p->next;
274
275                 if (NULL != p->line) {
276                         free (p->line);
277                 }
278
279                 if (NULL != p->eptr) {
280                         db->ops->free (p->eptr);
281                 }
282
283                 free (p);
284         }
285         db->tail = NULL;
286 }
287
288
289 int commonio_setname (struct commonio_db *db, const char *name)
290 {
291         snprintf (db->filename, sizeof (db->filename), "%s", name);
292         return 1;
293 }
294
295
296 bool commonio_present (const struct commonio_db *db)
297 {
298         return (access (db->filename, F_OK) == 0);
299 }
300
301
302 int commonio_lock_nowait (struct commonio_db *db)
303 {
304         char file[1024];
305         char lock[1024];
306
307         if (db->locked) {
308                 return 1;
309         }
310
311         snprintf (file, sizeof file, "%s.%lu",
312                   db->filename, (unsigned long) getpid ());
313         snprintf (lock, sizeof lock, "%s.lock", db->filename);
314         if (do_lock_file (file, lock) != 0) {
315                 db->locked = true;
316                 lock_count++;
317                 return 1;
318         }
319         return 0;
320 }
321
322
323 int commonio_lock (struct commonio_db *db)
324 {
325 #ifdef HAVE_LCKPWDF
326         /*
327          * only if the system libc has a real lckpwdf() - the one from
328          * lockpw.c calls us and would cause infinite recursion!
329          */
330
331         /*
332          * Call lckpwdf() on the first lock.
333          * If it succeeds, call *_lock() only once
334          * (no retries, it should always succeed).
335          */
336         if (0 == lock_count) {
337                 if (lckpwdf () == -1) {
338                         return 0;       /* failure */
339                 }
340         }
341
342         if (commonio_lock_nowait (db) != 0) {
343                 return 1;       /* success */
344         }
345
346         ulckpwdf ();
347         return 0;               /* failure */
348 #else
349         int i;
350
351         /*
352          * lckpwdf() not used - do it the old way.
353          */
354 #ifndef LOCK_TRIES
355 #define LOCK_TRIES 15
356 #endif
357
358 #ifndef LOCK_SLEEP
359 #define LOCK_SLEEP 1
360 #endif
361         for (i = 0; i < LOCK_TRIES; i++) {
362                 if (i > 0) {
363                         sleep (LOCK_SLEEP);     /* delay between retries */
364                 }
365                 if (commonio_lock_nowait (db) != 0) {
366                         return 1;       /* success */
367                 }
368                 /* no unnecessary retries on "permission denied" errors */
369                 if (geteuid () != 0) {
370                         return 0;
371                 }
372         }
373         return 0;               /* failure */
374 #endif
375 }
376
377 static void dec_lock_count (void)
378 {
379         if (lock_count > 0) {
380                 lock_count--;
381                 if (lock_count == 0) {
382                         /* Tell nscd when lock count goes to zero,
383                            if any of the files were changed.  */
384                         if (nscd_need_reload) {
385                                 nscd_flush_cache ("passwd");
386                                 nscd_flush_cache ("group");
387                                 nscd_need_reload = false;
388                         }
389 #ifdef HAVE_LCKPWDF
390                         ulckpwdf ();
391 #endif
392                 }
393         }
394 }
395
396
397 int commonio_unlock (struct commonio_db *db)
398 {
399         char lock[1024];
400
401         if (db->isopen) {
402                 db->readonly = true;
403                 if (commonio_close (db) == 0) {
404                         if (db->locked) {
405                                 dec_lock_count ();
406                         }
407                         return 0;
408                 }
409         }
410         if (db->locked) {
411                 /*
412                  * Unlock in reverse order: remove the lock file,
413                  * then call ulckpwdf() (if used) on last unlock.
414                  */
415                 db->locked = false;
416                 snprintf (lock, sizeof lock, "%s.lock", db->filename);
417                 unlink (lock);
418                 dec_lock_count ();
419                 return 1;
420         }
421         return 0;
422 }
423
424
425 static void add_one_entry (struct commonio_db *db, struct commonio_entry *p)
426 {
427         p->next = NULL;
428         p->prev = db->tail;
429         if (NULL == db->head) {
430                 db->head = p;
431         }
432         if (NULL != db->tail) {
433                 db->tail->next = p;
434         }
435         db->tail = p;
436 }
437
438
439 static bool name_is_nis (const char *name)
440 {
441         return (('+' == name[0]) || ('-' == name[0]));
442 }
443
444
445 /*
446  * New entries are inserted before the first NIS entry.  Order is preserved
447  * when db is written out.
448  */
449 #ifndef KEEP_NIS_AT_END
450 #define KEEP_NIS_AT_END 1
451 #endif
452
453 #if KEEP_NIS_AT_END
454 static void add_one_entry_nis (struct commonio_db *, struct commonio_entry *);
455
456 /*
457  * Insert an entry between the regular entries, and the NIS entries.
458  */
459 static void
460 add_one_entry_nis (struct commonio_db *db, struct commonio_entry *newp)
461 {
462         struct commonio_entry *p;
463
464         for (p = db->head; NULL != p; p = p->next) {
465                 if (name_is_nis (p->eptr ? db->ops->getname (p->eptr)
466                                          : p->line)) {
467                         newp->next = p;
468                         newp->prev = p->prev;
469                         if (NULL != p->prev) {
470                                 p->prev->next = newp;
471                         } else {
472                                 db->head = newp;
473                         }
474                         p->prev = newp;
475                         return;
476                 }
477         }
478         add_one_entry (db, newp);
479 }
480 #endif                          /* KEEP_NIS_AT_END */
481
482 /* Initial buffer size, as well as increment if not sufficient
483    (for reading very long lines in group files).  */
484 #define BUFLEN 4096
485
486 int commonio_open (struct commonio_db *db, int mode)
487 {
488         char *buf;
489         char *cp;
490         char *line;
491         struct commonio_entry *p;
492         void *eptr;
493         int flags = mode;
494         int buflen;
495         int saved_errno;
496
497         mode &= ~O_CREAT;
498
499         if (   db->isopen
500             || (   (O_RDONLY != mode)
501                 && (O_RDWR != mode))) {
502                 errno = EINVAL;
503                 return 0;
504         }
505         db->readonly = (mode == O_RDONLY);
506         if (!db->readonly && !db->locked) {
507                 errno = EACCES;
508                 return 0;
509         }
510
511         db->head = db->tail = db->cursor = NULL;
512         db->changed = false;
513
514         db->fp = fopen (db->filename, db->readonly ? "r" : "r+");
515
516         /*
517          * If O_CREAT was specified and the file didn't exist, it will be
518          * created by commonio_close().  We have no entries to read yet.  --marekm
519          */
520         if (NULL == db->fp) {
521                 if (((flags & O_CREAT) != 0) && (ENOENT == errno)) {
522                         db->isopen = true;
523                         return 1;
524                 }
525                 return 0;
526         }
527
528         /* Do not inherit fd in spawned processes (e.g. nscd) */
529         fcntl(fileno(db->fp), F_SETFD, FD_CLOEXEC);
530
531 #ifdef WITH_SELINUX
532         db->scontext = NULL;
533         if ((is_selinux_enabled () > 0) && (!db->readonly)) {
534                 if (fgetfilecon (fileno (db->fp), &db->scontext) < 0) {
535                         goto cleanup_errno;
536                 }
537         }
538 #endif
539
540         buflen = BUFLEN;
541         buf = (char *) malloc (buflen);
542         if (NULL == buf) {
543                 goto cleanup_ENOMEM;
544         }
545
546         while (db->ops->fgets (buf, buflen, db->fp) == buf) {
547                 while (   ((cp = strrchr (buf, '\n')) == NULL)
548                        && (feof (db->fp) == 0)) {
549                         int len;
550
551                         buflen += BUFLEN;
552                         cp = (char *) realloc (buf, buflen);
553                         if (NULL == cp) {
554                                 goto cleanup_buf;
555                         }
556                         buf = cp;
557                         len = strlen (buf);
558                         if (db->ops->fgets (buf + len, buflen - len, db->fp) == NULL) {
559                                 goto cleanup_buf;
560                         }
561                 }
562                 cp = strrchr (buf, '\n');
563                 if (NULL != cp) {
564                         *cp = '\0';
565                 }
566
567                 line = strdup (buf);
568                 if (NULL == line) {
569                         goto cleanup_buf;
570                 }
571
572                 if (name_is_nis (line)) {
573                         eptr = NULL;
574                 } else {
575                         eptr = db->ops->parse (line);
576                         if (NULL != eptr) {
577                                 eptr = db->ops->dup (eptr);
578                                 if (NULL == eptr) {
579                                         goto cleanup_line;
580                                 }
581                         }
582                 }
583
584                 p = (struct commonio_entry *) malloc (sizeof *p);
585                 if (NULL == p) {
586                         goto cleanup_entry;
587                 }
588
589                 p->eptr = eptr;
590                 p->line = line;
591                 p->changed = false;
592
593                 add_one_entry (db, p);
594         }
595
596         free (buf);
597
598         if (ferror (db->fp) != 0) {
599                 goto cleanup_errno;
600         }
601
602         if ((NULL != db->ops->open_hook) && (db->ops->open_hook () == 0)) {
603                 goto cleanup_errno;
604         }
605
606         db->isopen = true;
607         return 1;
608
609       cleanup_entry:
610         if (NULL != eptr) {
611                 db->ops->free (eptr);
612         }
613       cleanup_line:
614         free (line);
615       cleanup_buf:
616         free (buf);
617       cleanup_ENOMEM:
618         errno = ENOMEM;
619       cleanup_errno:
620         saved_errno = errno;
621         free_linked_list (db);
622 #ifdef WITH_SELINUX
623         if (db->scontext != NULL) {
624                 freecon (db->scontext);
625                 db->scontext = NULL;
626         }
627 #endif
628         fclose (db->fp);
629         db->fp = NULL;
630         errno = saved_errno;
631         return 0;
632 }
633
634 /*
635  * Sort given db according to cmp function (usually compares uids)
636  */
637 int
638 commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
639 {
640         struct commonio_entry **entries, *ptr;
641         int n = 0, i;
642
643         for (ptr = db->head; NULL != ptr; ptr = ptr->next) {
644                 n++;
645         }
646
647         if (n <= 1) {
648                 return 0;
649         }
650
651         entries = malloc (n * sizeof (struct commonio_entry *));
652         if (entries == NULL) {
653                 return -1;
654         }
655
656         n = 0;
657         for (ptr = db->head; NULL != ptr; ptr = ptr->next) {
658                 entries[n++] = ptr;
659         }
660         qsort (entries, n, sizeof (struct commonio_entry *), cmp);
661
662         db->head = entries[0];
663         db->tail = entries[--n];
664         db->head->prev = NULL;
665         db->head->next = entries[1];
666         db->tail->prev = entries[n - 1];
667         db->tail->next = NULL;
668
669         for (i = 1; i < n; i++) {
670                 entries[i]->prev = entries[i - 1];
671                 entries[i]->next = entries[i + 1];
672         }
673
674         free (entries);
675         db->changed = true;
676
677         return 0;
678 }
679
680 /*
681  * Sort entries in db according to order in another.
682  */
683 int commonio_sort_wrt (struct commonio_db *shadow, struct commonio_db *passwd)
684 {
685         struct commonio_entry *head = NULL, *pw_ptr, *spw_ptr;
686         const char *name;
687
688         if ((NULL == shadow) || (NULL == shadow->head)) {
689                 return 0;
690         }
691
692         for (pw_ptr = passwd->head; NULL != pw_ptr; pw_ptr = pw_ptr->next) {
693                 if (NULL == pw_ptr->eptr) {
694                         continue;
695                 }
696                 name = passwd->ops->getname (pw_ptr->eptr);
697                 for (spw_ptr = shadow->head;
698                      NULL != spw_ptr;
699                      spw_ptr = spw_ptr->next) {
700                         if (strcmp (name, shadow->ops->getname (spw_ptr->eptr))
701                             == 0) {
702                                 break;
703                         }
704                 }
705                 if (NULL == spw_ptr) {
706                         continue;
707                 }
708                 commonio_del_entry (shadow, spw_ptr);
709                 spw_ptr->next = head;
710                 head = spw_ptr;
711         }
712
713         for (spw_ptr = head; NULL != spw_ptr; spw_ptr = head) {
714                 head = head->next;
715
716                 if (NULL != shadow->head) {
717                         shadow->head->prev = spw_ptr;
718                 }
719                 spw_ptr->next = shadow->head;
720                 shadow->head = spw_ptr;
721         }
722
723         shadow->head->prev = NULL;
724         shadow->changed = true;
725
726         return 0;
727 }
728
729 /*
730  * write_all - Write the database to its file.
731  *
732  * It returns 0 if all the entries could be written correctly.
733  */
734 static int write_all (const struct commonio_db *db)
735 {
736         const struct commonio_entry *p;
737         void *eptr;
738
739         for (p = db->head; NULL != p; p = p->next) {
740                 if (p->changed) {
741                         eptr = p->eptr;
742                         if (db->ops->put (eptr, db->fp) != 0) {
743                                 return -1;
744                         }
745                 } else if (NULL != p->line) {
746                         if (db->ops->fputs (p->line, db->fp) == EOF) {
747                                 return -1;
748                         }
749                         if (putc ('\n', db->fp) == EOF) {
750                                 return -1;
751                         }
752                 }
753         }
754         return 0;
755 }
756
757
758 int commonio_close (struct commonio_db *db)
759 {
760         char buf[1024];
761         int errors = 0;
762         struct stat sb;
763
764         if (!db->isopen) {
765                 errno = EINVAL;
766                 return 0;
767         }
768         db->isopen = false;
769
770         if (!db->changed || db->readonly) {
771                 fclose (db->fp);
772                 db->fp = NULL;
773                 goto success;
774         }
775
776         if ((NULL != db->ops->close_hook) && (db->ops->close_hook () == 0)) {
777                 goto fail;
778         }
779
780         memzero (&sb, sizeof sb);
781         if (NULL != db->fp) {
782                 if (fstat (fileno (db->fp), &sb) != 0) {
783                         fclose (db->fp);
784                         db->fp = NULL;
785                         goto fail;
786                 }
787 #ifdef WITH_SELINUX
788                 if (db->scontext != NULL) {
789                         if (getfscreatecon (&old_context) < 0) {
790                                 errors++;
791                                 goto fail;
792                         }
793                         if (setfscreatecon (db->scontext) < 0) {
794                                 errors++;
795                                 goto fail;
796                         }
797                 }
798 #endif
799                 /*
800                  * Create backup file.
801                  */
802                 snprintf (buf, sizeof buf, "%s-", db->filename);
803
804                 if (create_backup (buf, db->fp) != 0) {
805                         errors++;
806                 }
807
808                 if (fclose (db->fp) != 0) {
809                         errors++;
810                 }
811
812                 if (errors != 0) {
813                         db->fp = NULL;
814                         goto fail;
815                 }
816         } else {
817                 /*
818                  * Default permissions for new [g]shadow files.
819                  * (passwd and group always exist...)
820                  */
821                 sb.st_mode = 0400;
822                 sb.st_uid = 0;
823                 sb.st_gid = 0;
824         }
825
826         snprintf (buf, sizeof buf, "%s+", db->filename);
827
828         db->fp = fopen_set_perms (buf, "w", &sb);
829         if (NULL == db->fp) {
830                 goto fail;
831         }
832
833         if (write_all (db) != 0) {
834                 errors++;
835         }
836
837         if (fflush (db->fp) != 0) {
838                 errors++;
839         }
840 #ifdef HAVE_FSYNC
841         if (fsync (fileno (db->fp)) != 0) {
842                 errors++;
843         }
844 #else
845         sync ();
846 #endif
847         if (fclose (db->fp) != 0) {
848                 errors++;
849         }
850
851         db->fp = NULL;
852
853         if (errors != 0) {
854                 unlink (buf);
855                 goto fail;
856         }
857
858         if (lrename (buf, db->filename) != 0) {
859                 goto fail;
860         }
861
862         nscd_need_reload = true;
863         goto success;
864       fail:
865         errors++;
866       success:
867
868 #ifdef WITH_SELINUX
869         if (db->scontext != NULL) {
870                 if (setfscreatecon (old_context) < 0) {
871                         errors++;
872                 }
873                 if (NULL != old_context) {
874                         freecon (old_context);
875                         old_context = NULL;
876                 }
877                 freecon (db->scontext);
878                 db->scontext = NULL;
879         }
880 #endif
881         free_linked_list (db);
882         return errors == 0;
883 }
884
885 static struct commonio_entry *next_entry_by_name (struct commonio_db *db,
886                                                   struct commonio_entry *pos,
887                                                   const char *name)
888 {
889         struct commonio_entry *p;
890         void *ep;
891
892         if (NULL == pos) {
893                 return NULL;
894         }
895
896         for (p = pos; NULL != p; p = p->next) {
897                 ep = p->eptr;
898                 if (   (NULL != ep)
899                     && (strcmp (db->ops->getname (ep), name) == 0)) {
900                         break;
901                 }
902         }
903         return p;
904 }
905
906 static struct commonio_entry *find_entry_by_name (struct commonio_db *db,
907                                                   const char *name)
908 {
909         return next_entry_by_name(db, db->head, name);
910 }
911
912
913 int commonio_update (struct commonio_db *db, const void *eptr)
914 {
915         struct commonio_entry *p;
916         void *nentry;
917
918         if (!db->isopen || db->readonly) {
919                 errno = EINVAL;
920                 return 0;
921         }
922         nentry = db->ops->dup (eptr);
923         if (NULL == nentry) {
924                 errno = ENOMEM;
925                 return 0;
926         }
927         p = find_entry_by_name (db, db->ops->getname (eptr));
928         if (NULL != p) {
929                 if (next_entry_by_name (db, p->next, db->ops->getname (eptr)) != NULL) {
930                         fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), db->ops->getname (eptr), db->filename);
931                         return 0;
932                 }
933                 db->ops->free (p->eptr);
934                 p->eptr = nentry;
935                 p->changed = true;
936                 db->cursor = p;
937
938                 db->changed = true;
939                 return 1;
940         }
941         /* not found, new entry */
942         p = (struct commonio_entry *) malloc (sizeof *p);
943         if (NULL == p) {
944                 db->ops->free (nentry);
945                 errno = ENOMEM;
946                 return 0;
947         }
948
949         p->eptr = nentry;
950         p->line = NULL;
951         p->changed = true;
952
953 #if KEEP_NIS_AT_END
954         add_one_entry_nis (db, p);
955 #else
956         add_one_entry (db, p);
957 #endif
958
959         db->changed = true;
960         return 1;
961 }
962
963
964 void commonio_del_entry (struct commonio_db *db, const struct commonio_entry *p)
965 {
966         if (p == db->cursor) {
967                 db->cursor = p->next;
968         }
969
970         if (NULL != p->prev) {
971                 p->prev->next = p->next;
972         } else {
973                 db->head = p->next;
974         }
975
976         if (NULL != p->next) {
977                 p->next->prev = p->prev;
978         } else {
979                 db->tail = p->prev;
980         }
981
982         db->changed = true;
983 }
984
985 /*
986  * commonio_remove - Remove the entry of the given name from the database.
987  */
988 int commonio_remove (struct commonio_db *db, const char *name)
989 {
990         struct commonio_entry *p;
991
992         if (!db->isopen || db->readonly) {
993                 errno = EINVAL;
994                 return 0;
995         }
996         p = find_entry_by_name (db, name);
997         if (NULL == p) {
998                 errno = ENOENT;
999                 return 0;
1000         }
1001         if (next_entry_by_name (db, p->next, name) != NULL) {
1002                 fprintf (stderr, _("Multiple entries named '%s' in %s. Please fix this with pwck or grpck.\n"), name, db->filename);
1003                 return 0;
1004         }
1005
1006         commonio_del_entry (db, p);
1007
1008         if (NULL != p->line) {
1009                 free (p->line);
1010         }
1011
1012         if (NULL != p->eptr) {
1013                 db->ops->free (p->eptr);
1014         }
1015
1016         return 1;
1017 }
1018
1019 /*
1020  * commonio_locate - Find the first entry with the specified name in
1021  *                   the database.
1022  *
1023  *      If found, it returns the entry and set the cursor of the database to
1024  *      that entry.
1025  *
1026  *      Otherwise, it returns NULL.
1027  */
1028 /*@observer@*/ /*@null@*/const void *commonio_locate (struct commonio_db *db, const char *name)
1029 {
1030         struct commonio_entry *p;
1031
1032         if (!db->isopen) {
1033                 errno = EINVAL;
1034                 return NULL;
1035         }
1036         p = find_entry_by_name (db, name);
1037         if (NULL == p) {
1038                 errno = ENOENT;
1039                 return NULL;
1040         }
1041         db->cursor = p;
1042         return p->eptr;
1043 }
1044
1045 /*
1046  * commonio_rewind - Restore the database cursor to the first entry.
1047  *
1048  * It returns 0 on error, 1 on success.
1049  */
1050 int commonio_rewind (struct commonio_db *db)
1051 {
1052         if (!db->isopen) {
1053                 errno = EINVAL;
1054                 return 0;
1055         }
1056         db->cursor = NULL;
1057         return 1;
1058 }
1059
1060 /*
1061  * commonio_next - Return the next entry of the specified database
1062  *
1063  * It returns the next entry, or NULL if no other entries could be found.
1064  */
1065 /*@observer@*/ /*@null@*/const void *commonio_next (struct commonio_db *db)
1066 {
1067         void *eptr;
1068
1069         if (!db->isopen) {
1070                 errno = EINVAL;
1071                 return 0;
1072         }
1073         if (NULL == db->cursor) {
1074                 db->cursor = db->head;
1075         } else {
1076                 db->cursor = db->cursor->next;
1077         }
1078
1079         while (NULL != db->cursor) {
1080                 eptr = db->cursor->eptr;
1081                 if (NULL != eptr) {
1082                         return eptr;
1083                 }
1084
1085                 db->cursor = db->cursor->next;
1086         }
1087         return NULL;
1088 }
1089