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