chiark / gitweb /
sysusers: Preserve ownership and mode on /etc/passwd and friends
[elogind.git] / src / sysusers / sysusers.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/types.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <shadow.h>
26 #include <gshadow.h>
27 #include <getopt.h>
28 #include <utmp.h>
29
30 #include "util.h"
31 #include "hashmap.h"
32 #include "specifier.h"
33 #include "path-util.h"
34 #include "build.h"
35 #include "strv.h"
36 #include "conf-files.h"
37 #include "copy.h"
38 #include "utf8.h"
39 #include "label.h"
40 #include "fileio-label.h"
41 #include "uid-range.h"
42
43 typedef enum ItemType {
44         ADD_USER = 'u',
45         ADD_GROUP = 'g',
46         ADD_MEMBER = 'm',
47         ADD_RANGE = 'r',
48 } ItemType;
49 typedef struct Item {
50         ItemType type;
51
52         char *name;
53         char *uid_path;
54         char *gid_path;
55         char *description;
56         char *home;
57
58         gid_t gid;
59         uid_t uid;
60
61         bool gid_set:1;
62         bool uid_set:1;
63
64         bool todo_user:1;
65         bool todo_group:1;
66 } Item;
67
68 static char *arg_root = NULL;
69
70 static const char conf_file_dirs[] =
71         "/etc/sysusers.d\0"
72         "/run/sysusers.d\0"
73         "/usr/local/lib/sysusers.d\0"
74         "/usr/lib/sysusers.d\0"
75 #ifdef HAVE_SPLIT_USR
76         "/lib/sysusers.d\0"
77 #endif
78         ;
79
80 static Hashmap *users = NULL, *groups = NULL;
81 static Hashmap *todo_uids = NULL, *todo_gids = NULL;
82 static Hashmap *members = NULL;
83
84 static Hashmap *database_uid = NULL, *database_user = NULL;
85 static Hashmap *database_gid = NULL, *database_group = NULL;
86
87 static uid_t search_uid = (uid_t) -1;
88 static UidRange *uid_range = NULL;
89 static unsigned n_uid_range = 0;
90
91 #define UID_TO_PTR(u) (ULONG_TO_PTR(u+1))
92 #define PTR_TO_UID(u) ((uid_t) (PTR_TO_ULONG(u)-1))
93
94 #define GID_TO_PTR(g) (ULONG_TO_PTR(g+1))
95 #define PTR_TO_GID(g) ((gid_t) (PTR_TO_ULONG(g)-1))
96
97 #define fix_root(x) (arg_root ? strappenda(arg_root, x) : x)
98
99 static int load_user_database(void) {
100         _cleanup_fclose_ FILE *f = NULL;
101         const char *passwd_path;
102         struct passwd *pw;
103         int r;
104
105         passwd_path = fix_root("/etc/passwd");
106         f = fopen(passwd_path, "re");
107         if (!f)
108                 return errno == ENOENT ? 0 : -errno;
109
110         r = hashmap_ensure_allocated(&database_user, &string_hash_ops);
111         if (r < 0)
112                 return r;
113
114         r = hashmap_ensure_allocated(&database_uid, NULL);
115         if (r < 0)
116                 return r;
117
118         errno = 0;
119         while ((pw = fgetpwent(f))) {
120                 char *n;
121                 int k, q;
122
123                 n = strdup(pw->pw_name);
124                 if (!n)
125                         return -ENOMEM;
126
127                 k = hashmap_put(database_user, n, UID_TO_PTR(pw->pw_uid));
128                 if (k < 0 && k != -EEXIST) {
129                         free(n);
130                         return k;
131                 }
132
133                 q = hashmap_put(database_uid, UID_TO_PTR(pw->pw_uid), n);
134                 if (q < 0 && q != -EEXIST) {
135                         if (k < 0)
136                                 free(n);
137                         return q;
138                 }
139
140                 if (q < 0 && k < 0)
141                         free(n);
142
143                 errno = 0;
144         }
145         if (!IN_SET(errno, 0, ENOENT))
146                 return -errno;
147
148         return 0;
149 }
150
151 static int load_group_database(void) {
152         _cleanup_fclose_ FILE *f = NULL;
153         const char *group_path;
154         struct group *gr;
155         int r;
156
157         group_path = fix_root("/etc/group");
158         f = fopen(group_path, "re");
159         if (!f)
160                 return errno == ENOENT ? 0 : -errno;
161
162         r = hashmap_ensure_allocated(&database_group, &string_hash_ops);
163         if (r < 0)
164                 return r;
165
166         r = hashmap_ensure_allocated(&database_gid, NULL);
167         if (r < 0)
168                 return r;
169
170         errno = 0;
171         while ((gr = fgetgrent(f))) {
172                 char *n;
173                 int k, q;
174
175                 n = strdup(gr->gr_name);
176                 if (!n)
177                         return -ENOMEM;
178
179                 k = hashmap_put(database_group, n, GID_TO_PTR(gr->gr_gid));
180                 if (k < 0 && k != -EEXIST) {
181                         free(n);
182                         return k;
183                 }
184
185                 q = hashmap_put(database_gid, GID_TO_PTR(gr->gr_gid), n);
186                 if (q < 0 && q != -EEXIST) {
187                         if (k < 0)
188                                 free(n);
189                         return q;
190                 }
191
192                 if (q < 0 && k < 0)
193                         free(n);
194
195                 errno = 0;
196         }
197         if (!IN_SET(errno, 0, ENOENT))
198                 return -errno;
199
200         return 0;
201 }
202
203 static int make_backup(const char *target, const char *x) {
204         _cleanup_close_ int src = -1;
205         _cleanup_fclose_ FILE *dst = NULL;
206         char *backup, *temp;
207         struct timespec ts[2];
208         struct stat st;
209         int r;
210
211         src = open(x, O_RDONLY|O_CLOEXEC|O_NOCTTY);
212         if (src < 0) {
213                 if (errno == ENOENT) /* No backup necessary... */
214                         return 0;
215
216                 return -errno;
217         }
218
219         if (fstat(src, &st) < 0)
220                 return -errno;
221
222         r = fopen_temporary_label(target, x, &dst, &temp);
223         if (r < 0)
224                 return r;
225
226         r = copy_bytes(src, fileno(dst), (off_t) -1);
227         if (r < 0)
228                 goto fail;
229
230         /* Don't fail on chmod() or chown(). If it stays owned by us
231          * and/or unreadable by others, then it isn't too bad... */
232
233         backup = strappenda(x, "-");
234
235         /* Copy over the access mask */
236         if (fchmod(fileno(dst), st.st_mode & 07777) < 0)
237                 log_warning("Failed to change mode on %s: %m", backup);
238
239         if (fchown(fileno(dst), st.st_uid, st.st_gid)< 0)
240                 log_warning("Failed to change ownership of %s: %m", backup);
241
242         ts[0] = st.st_atim;
243         ts[1] = st.st_mtim;
244         futimens(fileno(dst), ts);
245
246         if (rename(temp, backup) < 0)
247                 goto fail;
248
249         return 0;
250
251 fail:
252         unlink(temp);
253         return r;
254 }
255
256 static int putgrent_with_members(const struct group *gr, FILE *group) {
257         char **a;
258
259         assert(gr);
260         assert(group);
261
262         a = hashmap_get(members, gr->gr_name);
263         if (a) {
264                 _cleanup_strv_free_ char **l = NULL;
265                 bool added = false;
266                 char **i;
267
268                 l = strv_copy(gr->gr_mem);
269                 if (!l)
270                         return -ENOMEM;
271
272                 STRV_FOREACH(i, a) {
273                         if (strv_find(l, *i))
274                                 continue;
275
276                         if (strv_extend(&l, *i) < 0)
277                                 return -ENOMEM;
278
279                         added = true;
280                 }
281
282                 if (added) {
283                         struct group t;
284
285                         strv_uniq(l);
286                         strv_sort(l);
287
288                         t = *gr;
289                         t.gr_mem = l;
290
291                         errno = 0;
292                         if (putgrent(&t, group) != 0)
293                                 return errno ? -errno : -EIO;
294
295                         return 1;
296                 }
297         }
298
299         errno = 0;
300         if (putgrent(gr, group) != 0)
301                 return errno ? -errno : -EIO;
302
303         return 0;
304 }
305
306 static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
307         char **a;
308
309         assert(sg);
310         assert(gshadow);
311
312         a = hashmap_get(members, sg->sg_namp);
313         if (a) {
314                 _cleanup_strv_free_ char **l = NULL;
315                 bool added = false;
316                 char **i;
317
318                 l = strv_copy(sg->sg_mem);
319                 if (!l)
320                         return -ENOMEM;
321
322                 STRV_FOREACH(i, a) {
323                         if (strv_find(l, *i))
324                                 continue;
325
326                         if (strv_extend(&l, *i) < 0)
327                                 return -ENOMEM;
328
329                         added = true;
330                 }
331
332                 if (added) {
333                         struct sgrp t;
334
335                         strv_uniq(l);
336                         strv_sort(l);
337
338                         t = *sg;
339                         t.sg_mem = l;
340
341                         errno = 0;
342                         if (putsgent(&t, gshadow) != 0)
343                                 return errno ? -errno : -EIO;
344
345                         return 1;
346                 }
347         }
348
349         errno = 0;
350         if (putsgent(sg, gshadow) != 0)
351                 return errno ? -errno : -EIO;
352
353         return 0;
354 }
355
356 static int write_files(void) {
357
358         _cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL;
359         _cleanup_free_ char *passwd_tmp = NULL, *group_tmp = NULL, *shadow_tmp = NULL, *gshadow_tmp = NULL;
360         const char *passwd_path = NULL, *group_path = NULL, *shadow_path = NULL, *gshadow_path = NULL;
361         struct stat st;
362         bool group_changed = false;
363         Iterator iterator;
364         Item *i;
365         int r;
366
367         if (hashmap_size(todo_gids) > 0 || hashmap_size(members) > 0) {
368                 _cleanup_fclose_ FILE *original = NULL;
369
370                 /* First we update the actual group list file */
371                 group_path = fix_root("/etc/group");
372                 r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
373                 if (r < 0)
374                         goto finish;
375
376                 original = fopen(group_path, "re");
377                 if (original) {
378                         struct group *gr;
379
380                         if (fstat(fileno(original), &st) < 0 ||
381                             fchmod(fileno(group), st.st_mode & 07777) < 0 ||
382                             fchown(fileno(group), st.st_uid, st.st_gid) < 0) {
383                                 r = -errno;
384                                 goto finish;
385                         }
386
387                         errno = 0;
388                         while ((gr = fgetgrent(original))) {
389                                 /* Safety checks against name and GID
390                                  * collisions. Normally, this should
391                                  * be unnecessary, but given that we
392                                  * look at the entries anyway here,
393                                  * let's make an extra verification
394                                  * step that we don't generate
395                                  * duplicate entries. */
396
397                                 i = hashmap_get(groups, gr->gr_name);
398                                 if (i && i->todo_group) {
399                                         r = -EEXIST;
400                                         goto finish;
401                                 }
402
403                                 if (hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) {
404                                         r = -EEXIST;
405                                         goto finish;
406                                 }
407
408                                 r = putgrent_with_members(gr, group);
409                                 if (r < 0)
410                                         goto finish;
411                                 if (r > 0)
412                                         group_changed = true;
413
414                                 errno = 0;
415                         }
416                         if (!IN_SET(errno, 0, ENOENT)) {
417                                 r = -errno;
418                                 goto finish;
419                         }
420
421                 } else if (errno != ENOENT) {
422                         r = -errno;
423                         goto finish;
424                 } else if (fchmod(fileno(group), 0644) < 0) {
425                         r = -errno;
426                         goto finish;
427                 }
428
429                 HASHMAP_FOREACH(i, todo_gids, iterator) {
430                         struct group n = {
431                                 .gr_name = i->name,
432                                 .gr_gid = i->gid,
433                                 .gr_passwd = (char*) "x",
434                         };
435
436                         r = putgrent_with_members(&n, group);
437                         if (r < 0)
438                                 goto finish;
439
440                         group_changed = true;
441                 }
442
443                 r = fflush_and_check(group);
444                 if (r < 0)
445                         goto finish;
446
447                 if (original) {
448                         fclose(original);
449                         original = NULL;
450                 }
451
452                 /* OK, now also update the shadow file for the group list */
453                 gshadow_path = fix_root("/etc/gshadow");
454                 r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
455                 if (r < 0)
456                         goto finish;
457
458                 original = fopen(gshadow_path, "re");
459                 if (original) {
460                         struct sgrp *sg;
461
462                         if (fstat(fileno(original), &st) < 0 ||
463                             fchmod(fileno(gshadow), st.st_mode & 07777) < 0 ||
464                             fchown(fileno(gshadow), st.st_uid, st.st_gid) < 0) {
465                                 r = -errno;
466                                 goto finish;
467                         }
468
469                         errno = 0;
470                         while ((sg = fgetsgent(original))) {
471
472                                 i = hashmap_get(groups, sg->sg_namp);
473                                 if (i && i->todo_group) {
474                                         r = -EEXIST;
475                                         goto finish;
476                                 }
477
478                                 r = putsgent_with_members(sg, gshadow);
479                                 if (r < 0)
480                                         goto finish;
481                                 if (r > 0)
482                                         group_changed = true;
483
484                                 errno = 0;
485                         }
486                         if (!IN_SET(errno, 0, ENOENT)) {
487                                 r = -errno;
488                                 goto finish;
489                         }
490
491                 } else if (errno != ENOENT) {
492                         r = -errno;
493                         goto finish;
494                 } else if (fchmod(fileno(gshadow), 0000) < 0) {
495                         r = -errno;
496                         goto finish;
497                 }
498
499                 HASHMAP_FOREACH(i, todo_gids, iterator) {
500                         struct sgrp n = {
501                                 .sg_namp = i->name,
502                                 .sg_passwd = (char*) "!!",
503                         };
504
505                         r = putsgent_with_members(&n, gshadow);
506                         if (r < 0)
507                                 goto finish;
508
509                         group_changed = true;
510                 }
511
512                 r = fflush_and_check(gshadow);
513                 if (r < 0)
514                         goto finish;
515         }
516
517         if (hashmap_size(todo_uids) > 0) {
518                 _cleanup_fclose_ FILE *original = NULL;
519                 long lstchg;
520
521                 /* First we update the user database itself */
522                 passwd_path = fix_root("/etc/passwd");
523                 r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
524                 if (r < 0)
525                         goto finish;
526
527                 original = fopen(passwd_path, "re");
528                 if (original) {
529                         struct passwd *pw;
530
531                         if (fstat(fileno(original), &st) < 0 ||
532                             fchmod(fileno(passwd), st.st_mode & 07777) < 0 ||
533                             fchown(fileno(passwd), st.st_uid, st.st_gid) < 0) {
534                                 r = -errno;
535                                 goto finish;
536                         }
537
538                         errno = 0;
539                         while ((pw = fgetpwent(original))) {
540
541                                 i = hashmap_get(users, pw->pw_name);
542                                 if (i && i->todo_user) {
543                                         r = -EEXIST;
544                                         goto finish;
545                                 }
546
547                                 if (hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) {
548                                         r = -EEXIST;
549                                         goto finish;
550                                 }
551
552                                 errno = 0;
553                                 if (putpwent(pw, passwd) < 0) {
554                                         r = errno ? -errno : -EIO;
555                                         goto finish;
556                                 }
557
558                                 errno = 0;
559                         }
560                         if (!IN_SET(errno, 0, ENOENT)) {
561                                 r = -errno;
562                                 goto finish;
563                         }
564
565                 } else if (errno != ENOENT) {
566                         r = -errno;
567                         goto finish;
568                 } else if (fchmod(fileno(passwd), 0644) < 0) {
569                         r = -errno;
570                         goto finish;
571                 }
572
573                 HASHMAP_FOREACH(i, todo_uids, iterator) {
574                         struct passwd n = {
575                                 .pw_name = i->name,
576                                 .pw_uid = i->uid,
577                                 .pw_gid = i->gid,
578                                 .pw_gecos = i->description,
579
580                                 /* "x" means the password is stored in
581                                  * the shadow file */
582                                 .pw_passwd = (char*) "x",
583
584                                 /* We default to the root directory as home */
585                                 .pw_dir = i->home ? i->home : (char*) "/",
586
587                                 /* Initialize the shell to nologin,
588                                  * with one exception: for root we
589                                  * patch in something special */
590                                 .pw_shell = i->uid == 0 ? (char*) "/bin/sh" : (char*) "/sbin/nologin",
591                         };
592
593                         errno = 0;
594                         if (putpwent(&n, passwd) != 0) {
595                                 r = errno ? -errno : -EIO;
596                                 goto finish;
597                         }
598                 }
599
600                 r = fflush_and_check(passwd);
601                 if (r < 0)
602                         goto finish;
603
604                 if (original) {
605                         fclose(original);
606                         original = NULL;
607                 }
608
609                 /* The we update the shadow database */
610                 shadow_path = fix_root("/etc/shadow");
611                 r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
612                 if (r < 0)
613                         goto finish;
614
615                 original = fopen(shadow_path, "re");
616                 if (original) {
617                         struct spwd *sp;
618
619                         if (fstat(fileno(original), &st) < 0 ||
620                             fchmod(fileno(shadow), st.st_mode & 07777) < 0 ||
621                             fchown(fileno(shadow), st.st_uid, st.st_gid) < 0) {
622                                 r = -errno;
623                                 goto finish;
624                         }
625
626                         errno = 0;
627                         while ((sp = fgetspent(original))) {
628
629                                 i = hashmap_get(users, sp->sp_namp);
630                                 if (i && i->todo_user) {
631                                         r = -EEXIST;
632                                         goto finish;
633                                 }
634
635                                 errno = 0;
636                                 if (putspent(sp, shadow) < 0) {
637                                         r = errno ? -errno : -EIO;
638                                         goto finish;
639                                 }
640
641                                 errno = 0;
642                         }
643                         if (!IN_SET(errno, 0, ENOENT)) {
644                                 r = -errno;
645                                 goto finish;
646                         }
647                 } else if (errno != ENOENT) {
648                         r = -errno;
649                         goto finish;
650                 } else if (fchmod(fileno(shadow), 0000) < 0) {
651                         r = -errno;
652                         goto finish;
653                 }
654
655                 lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
656                 HASHMAP_FOREACH(i, todo_uids, iterator) {
657                         struct spwd n = {
658                                 .sp_namp = i->name,
659                                 .sp_pwdp = (char*) "!!",
660                                 .sp_lstchg = lstchg,
661                                 .sp_min = -1,
662                                 .sp_max = -1,
663                                 .sp_warn = -1,
664                                 .sp_inact = -1,
665                                 .sp_expire = -1,
666                                 .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
667                         };
668
669                         errno = 0;
670                         if (putspent(&n, shadow) != 0) {
671                                 r = errno ? -errno : -EIO;
672                                 goto finish;
673                         }
674                 }
675
676                 r = fflush_and_check(shadow);
677                 if (r < 0)
678                         goto finish;
679         }
680
681         /* Make a backup of the old files */
682         if (group_changed) {
683                 if (group) {
684                         r = make_backup("/etc/group", group_path);
685                         if (r < 0)
686                                 goto finish;
687                 }
688                 if (gshadow) {
689                         r = make_backup("/etc/gshadow", gshadow_path);
690                         if (r < 0)
691                                 goto finish;
692                 }
693         }
694
695         if (passwd) {
696                 r = make_backup("/etc/passwd", passwd_path);
697                 if (r < 0)
698                         goto finish;
699         }
700         if (shadow) {
701                 r = make_backup("/etc/shadow", shadow_path);
702                 if (r < 0)
703                         goto finish;
704         }
705
706         /* And make the new files count */
707         if (group_changed) {
708                 if (group) {
709                         if (rename(group_tmp, group_path) < 0) {
710                                 r = -errno;
711                                 goto finish;
712                         }
713
714                         free(group_tmp);
715                         group_tmp = NULL;
716                 }
717                 if (gshadow) {
718                         if (rename(gshadow_tmp, gshadow_path) < 0) {
719                                 r = -errno;
720                                 goto finish;
721                         }
722
723                         free(gshadow_tmp);
724                         gshadow_tmp = NULL;
725                 }
726         }
727
728         if (passwd) {
729                 if (rename(passwd_tmp, passwd_path) < 0) {
730                         r = -errno;
731                         goto finish;
732                 }
733
734                 free(passwd_tmp);
735                 passwd_tmp = NULL;
736         }
737         if (shadow) {
738                 if (rename(shadow_tmp, shadow_path) < 0) {
739                         r = -errno;
740                         goto finish;
741                 }
742
743                 free(shadow_tmp);
744                 shadow_tmp = NULL;
745         }
746
747         r = 0;
748
749 finish:
750         if (passwd_tmp)
751                 unlink(passwd_tmp);
752         if (shadow_tmp)
753                 unlink(shadow_tmp);
754         if (group_tmp)
755                 unlink(group_tmp);
756         if (gshadow_tmp)
757                 unlink(gshadow_tmp);
758
759         return r;
760 }
761
762 static int uid_is_ok(uid_t uid, const char *name) {
763         struct passwd *p;
764         struct group *g;
765         const char *n;
766         Item *i;
767
768         /* Let's see if we already have assigned the UID a second time */
769         if (hashmap_get(todo_uids, UID_TO_PTR(uid)))
770                 return 0;
771
772         /* Try to avoid using uids that are already used by a group
773          * that doesn't have the same name as our new user. */
774         i = hashmap_get(todo_gids, GID_TO_PTR(uid));
775         if (i && !streq(i->name, name))
776                 return 0;
777
778         /* Let's check the files directly */
779         if (hashmap_contains(database_uid, UID_TO_PTR(uid)))
780                 return 0;
781
782         n = hashmap_get(database_gid, GID_TO_PTR(uid));
783         if (n && !streq(n, name))
784                 return 0;
785
786         /* Let's also check via NSS, to avoid UID clashes over LDAP and such, just in case */
787         if (!arg_root) {
788                 errno = 0;
789                 p = getpwuid(uid);
790                 if (p)
791                         return 0;
792                 if (!IN_SET(errno, 0, ENOENT))
793                         return -errno;
794
795                 errno = 0;
796                 g = getgrgid((gid_t) uid);
797                 if (g) {
798                         if (!streq(g->gr_name, name))
799                                 return 0;
800                 } else if (!IN_SET(errno, 0, ENOENT))
801                         return -errno;
802         }
803
804         return 1;
805 }
806
807 static int root_stat(const char *p, struct stat *st) {
808         const char *fix;
809
810         fix = fix_root(p);
811         if (stat(fix, st) < 0)
812                 return -errno;
813
814         return 0;
815 }
816
817 static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
818         struct stat st;
819         bool found_uid = false, found_gid = false;
820         uid_t uid = 0;
821         gid_t gid = 0;
822
823         assert(i);
824
825         /* First, try to get the gid directly */
826         if (_gid && i->gid_path && root_stat(i->gid_path, &st) >= 0) {
827                 gid = st.st_gid;
828                 found_gid = true;
829         }
830
831         /* Then, try to get the uid directly */
832         if ((_uid || (_gid && !found_gid))
833             && i->uid_path
834             && root_stat(i->uid_path, &st) >= 0) {
835
836                 uid = st.st_uid;
837                 found_uid = true;
838
839                 /* If we need the gid, but had no success yet, also derive it from the uid path */
840                 if (_gid && !found_gid) {
841                         gid = st.st_gid;
842                         found_gid = true;
843                 }
844         }
845
846         /* If that didn't work yet, then let's reuse the gid as uid */
847         if (_uid && !found_uid && i->gid_path) {
848
849                 if (found_gid) {
850                         uid = (uid_t) gid;
851                         found_uid = true;
852                 } else if (root_stat(i->gid_path, &st) >= 0) {
853                         uid = (uid_t) st.st_gid;
854                         found_uid = true;
855                 }
856         }
857
858         if (_uid) {
859                 if (!found_uid)
860                         return 0;
861
862                 *_uid = uid;
863         }
864
865         if (_gid) {
866                 if (!found_gid)
867                         return 0;
868
869                 *_gid = gid;
870         }
871
872         return 1;
873 }
874
875 static int add_user(Item *i) {
876         void *z;
877         int r;
878
879         assert(i);
880
881         /* Check the database directly */
882         z = hashmap_get(database_user, i->name);
883         if (z) {
884                 log_debug("User %s already exists.", i->name);
885                 i->uid = PTR_TO_UID(z);
886                 i->uid_set = true;
887                 return 0;
888         }
889
890         if (!arg_root) {
891                 struct passwd *p;
892                 struct spwd *sp;
893
894                 /* Also check NSS */
895                 errno = 0;
896                 p = getpwnam(i->name);
897                 if (p) {
898                         log_debug("User %s already exists.", i->name);
899                         i->uid = p->pw_uid;
900                         i->uid_set = true;
901
902                         free(i->description);
903                         i->description = strdup(p->pw_gecos);
904                         return 0;
905                 }
906                 if (!IN_SET(errno, 0, ENOENT)) {
907                         log_error("Failed to check if user %s already exists: %m", i->name);
908                         return -errno;
909                 }
910
911                 /* And shadow too, just to be sure */
912                 errno = 0;
913                 sp = getspnam(i->name);
914                 if (sp) {
915                         log_error("User %s already exists in shadow database, but not in user database.", i->name);
916                         return -EBADMSG;
917                 }
918                 if (!IN_SET(errno, 0, ENOENT)) {
919                         log_error("Failed to check if user %s already exists in shadow database: %m", i->name);
920                         return -errno;
921                 }
922         }
923
924         /* Try to use the suggested numeric uid */
925         if (i->uid_set) {
926                 r = uid_is_ok(i->uid, i->name);
927                 if (r < 0) {
928                         log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
929                         return r;
930                 }
931                 if (r == 0) {
932                         log_debug("Suggested user ID " UID_FMT " for %s already used.", i->uid, i->name);
933                         i->uid_set = false;
934                 }
935         }
936
937         /* If that didn't work, try to read it from the specified path */
938         if (!i->uid_set) {
939                 uid_t c;
940
941                 if (read_id_from_file(i, &c, NULL) > 0) {
942
943                         if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
944                                 log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name);
945                         else {
946                                 r = uid_is_ok(c, i->name);
947                                 if (r < 0) {
948                                         log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
949                                         return r;
950                                 } else if (r > 0) {
951                                         i->uid = c;
952                                         i->uid_set = true;
953                                 } else
954                                         log_debug("User ID " UID_FMT " of file for %s is already used.", c, i->name);
955                         }
956                 }
957         }
958
959         /* Otherwise try to reuse the group ID */
960         if (!i->uid_set && i->gid_set) {
961                 r = uid_is_ok((uid_t) i->gid, i->name);
962                 if (r < 0) {
963                         log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
964                         return r;
965                 }
966                 if (r > 0) {
967                         i->uid = (uid_t) i->gid;
968                         i->uid_set = true;
969                 }
970         }
971
972         /* And if that didn't work either, let's try to find a free one */
973         if (!i->uid_set) {
974                 for (;;) {
975                         r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
976                         if (r < 0) {
977                                 log_error("No free user ID available for %s.", i->name);
978                                 return r;
979                         }
980
981                         r = uid_is_ok(search_uid, i->name);
982                         if (r < 0) {
983                                 log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
984                                 return r;
985                         } else if (r > 0)
986                                 break;
987                 }
988
989                 i->uid_set = true;
990                 i->uid = search_uid;
991         }
992
993         r = hashmap_ensure_allocated(&todo_uids, NULL);
994         if (r < 0)
995                 return log_oom();
996
997         r = hashmap_put(todo_uids, UID_TO_PTR(i->uid), i);
998         if (r < 0)
999                 return log_oom();
1000
1001         i->todo_user = true;
1002         log_info("Creating user %s (%s) with uid " UID_FMT " and gid " GID_FMT ".", i->name, strna(i->description), i->uid, i->gid);
1003
1004         return 0;
1005 }
1006
1007 static int gid_is_ok(gid_t gid) {
1008         struct group *g;
1009         struct passwd *p;
1010
1011         if (hashmap_get(todo_gids, GID_TO_PTR(gid)))
1012                 return 0;
1013
1014         /* Avoid reusing gids that are already used by a different user */
1015         if (hashmap_get(todo_uids, UID_TO_PTR(gid)))
1016                 return 0;
1017
1018         if (hashmap_contains(database_gid, GID_TO_PTR(gid)))
1019                 return 0;
1020
1021         if (hashmap_contains(database_uid, UID_TO_PTR(gid)))
1022                 return 0;
1023
1024         if (!arg_root) {
1025                 errno = 0;
1026                 g = getgrgid(gid);
1027                 if (g)
1028                         return 0;
1029                 if (!IN_SET(errno, 0, ENOENT))
1030                         return -errno;
1031
1032                 errno = 0;
1033                 p = getpwuid((uid_t) gid);
1034                 if (p)
1035                         return 0;
1036                 if (!IN_SET(errno, 0, ENOENT))
1037                         return -errno;
1038         }
1039
1040         return 1;
1041 }
1042
1043 static int add_group(Item *i) {
1044         void *z;
1045         int r;
1046
1047         assert(i);
1048
1049         /* Check the database directly */
1050         z = hashmap_get(database_group, i->name);
1051         if (z) {
1052                 log_debug("Group %s already exists.", i->name);
1053                 i->gid = PTR_TO_GID(z);
1054                 i->gid_set = true;
1055                 return 0;
1056         }
1057
1058         /* Also check NSS */
1059         if (!arg_root) {
1060                 struct group *g;
1061
1062                 errno = 0;
1063                 g = getgrnam(i->name);
1064                 if (g) {
1065                         log_debug("Group %s already exists.", i->name);
1066                         i->gid = g->gr_gid;
1067                         i->gid_set = true;
1068                         return 0;
1069                 }
1070                 if (!IN_SET(errno, 0, ENOENT)) {
1071                         log_error("Failed to check if group %s already exists: %m", i->name);
1072                         return -errno;
1073                 }
1074         }
1075
1076         /* Try to use the suggested numeric gid */
1077         if (i->gid_set) {
1078                 r = gid_is_ok(i->gid);
1079                 if (r < 0) {
1080                         log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1081                         return r;
1082                 }
1083                 if (r == 0) {
1084                         log_debug("Suggested group ID " GID_FMT " for %s already used.", i->gid, i->name);
1085                         i->gid_set = false;
1086                 }
1087         }
1088
1089         /* Try to reuse the numeric uid, if there's one */
1090         if (!i->gid_set && i->uid_set) {
1091                 r = gid_is_ok((gid_t) i->uid);
1092                 if (r < 0) {
1093                         log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1094                         return r;
1095                 }
1096                 if (r > 0) {
1097                         i->gid = (gid_t) i->uid;
1098                         i->gid_set = true;
1099                 }
1100         }
1101
1102         /* If that didn't work, try to read it from the specified path */
1103         if (!i->gid_set) {
1104                 gid_t c;
1105
1106                 if (read_id_from_file(i, NULL, &c) > 0) {
1107
1108                         if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
1109                                 log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
1110                         else {
1111                                 r = gid_is_ok(c);
1112                                 if (r < 0) {
1113                                         log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1114                                         return r;
1115                                 } else if (r > 0) {
1116                                         i->gid = c;
1117                                         i->gid_set = true;
1118                                 } else
1119                                         log_debug("Group ID " GID_FMT " of file for %s already used.", c, i->name);
1120                         }
1121                 }
1122         }
1123
1124         /* And if that didn't work either, let's try to find a free one */
1125         if (!i->gid_set) {
1126                 for (;;) {
1127                         /* We look for new GIDs in the UID pool! */
1128                         r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
1129                         if (r < 0) {
1130                                 log_error("No free group ID available for %s.", i->name);
1131                                 return r;
1132                         }
1133
1134                         r = gid_is_ok(search_uid);
1135                         if (r < 0) {
1136                                 log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
1137                                 return r;
1138                         } else if (r > 0)
1139                                 break;
1140                 }
1141
1142                 i->gid_set = true;
1143                 i->gid = search_uid;
1144         }
1145
1146         r = hashmap_ensure_allocated(&todo_gids, NULL);
1147         if (r < 0)
1148                 return log_oom();
1149
1150         r = hashmap_put(todo_gids, GID_TO_PTR(i->gid), i);
1151         if (r < 0)
1152                 return log_oom();
1153
1154         i->todo_group = true;
1155         log_info("Creating group %s with gid " GID_FMT ".", i->name, i->gid);
1156
1157         return 0;
1158 }
1159
1160 static int process_item(Item *i) {
1161         int r;
1162
1163         assert(i);
1164
1165         switch (i->type) {
1166
1167         case ADD_USER:
1168                 r = add_group(i);
1169                 if (r < 0)
1170                         return r;
1171
1172                 return add_user(i);
1173
1174         case ADD_GROUP: {
1175                 Item *j;
1176
1177                 j = hashmap_get(users, i->name);
1178                 if (j) {
1179                         /* There's already user to be created for this
1180                          * name, let's process that in one step */
1181
1182                         if (i->gid_set) {
1183                                 j->gid = i->gid;
1184                                 j->gid_set = true;
1185                         }
1186
1187                         if (i->gid_path) {
1188                                 free(j->gid_path);
1189                                 j->gid_path = strdup(i->gid_path);
1190                                 if (!j->gid_path)
1191                                         return log_oom();
1192                         }
1193
1194                         return 0;
1195                 }
1196
1197                 return add_group(i);
1198         }
1199
1200         default:
1201                 assert_not_reached("Unknown item type");
1202         }
1203 }
1204
1205 static void item_free(Item *i) {
1206
1207         if (!i)
1208                 return;
1209
1210         free(i->name);
1211         free(i->uid_path);
1212         free(i->gid_path);
1213         free(i->description);
1214         free(i);
1215 }
1216
1217 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1218
1219 static int add_implicit(void) {
1220         char *g, **l;
1221         Iterator iterator;
1222         int r;
1223
1224         /* Implicitly create additional users and groups, if they were listed in "m" lines */
1225
1226         HASHMAP_FOREACH_KEY(l, g, members, iterator) {
1227                 Item *i;
1228                 char **m;
1229
1230                 i = hashmap_get(groups, g);
1231                 if (!i) {
1232                         _cleanup_(item_freep) Item *j = NULL;
1233
1234                         r = hashmap_ensure_allocated(&groups, &string_hash_ops);
1235                         if (r < 0)
1236                                 return log_oom();
1237
1238                         j = new0(Item, 1);
1239                         if (!j)
1240                                 return log_oom();
1241
1242                         j->type = ADD_GROUP;
1243                         j->name = strdup(g);
1244                         if (!j->name)
1245                                 return log_oom();
1246
1247                         r = hashmap_put(groups, j->name, j);
1248                         if (r < 0)
1249                                 return log_oom();
1250
1251                         log_debug("Adding implicit group '%s' due to m line", j->name);
1252                         j = NULL;
1253                 }
1254
1255                 STRV_FOREACH(m, l) {
1256
1257                         i = hashmap_get(users, *m);
1258                         if (!i) {
1259                                 _cleanup_(item_freep) Item *j = NULL;
1260
1261                                 r = hashmap_ensure_allocated(&users, &string_hash_ops);
1262                                 if (r < 0)
1263                                         return log_oom();
1264
1265                                 j = new0(Item, 1);
1266                                 if (!j)
1267                                         return log_oom();
1268
1269                                 j->type = ADD_USER;
1270                                 j->name = strdup(*m);
1271                                 if (!j->name)
1272                                         return log_oom();
1273
1274                                 r = hashmap_put(users, j->name, j);
1275                                 if (r < 0)
1276                                         return log_oom();
1277
1278                                 log_debug("Adding implicit user '%s' due to m line", j->name);
1279                                 j = NULL;
1280                         }
1281                 }
1282         }
1283
1284         return 0;
1285 }
1286
1287 static bool item_equal(Item *a, Item *b) {
1288         assert(a);
1289         assert(b);
1290
1291         if (a->type != b->type)
1292                 return false;
1293
1294         if (!streq_ptr(a->name, b->name))
1295                 return false;
1296
1297         if (!streq_ptr(a->uid_path, b->uid_path))
1298                 return false;
1299
1300         if (!streq_ptr(a->gid_path, b->gid_path))
1301                 return false;
1302
1303         if (!streq_ptr(a->description, b->description))
1304                 return false;
1305
1306         if (a->uid_set != b->uid_set)
1307                 return false;
1308
1309         if (a->uid_set && a->uid != b->uid)
1310                 return false;
1311
1312         if (a->gid_set != b->gid_set)
1313                 return false;
1314
1315         if (a->gid_set && a->gid != b->gid)
1316                 return false;
1317
1318         if (!streq_ptr(a->home, b->home))
1319                 return false;
1320
1321         return true;
1322 }
1323
1324 static bool valid_user_group_name(const char *u) {
1325         const char *i;
1326         long sz;
1327
1328         if (isempty(u))
1329                 return false;
1330
1331         if (!(u[0] >= 'a' && u[0] <= 'z') &&
1332             !(u[0] >= 'A' && u[0] <= 'Z') &&
1333             u[0] != '_')
1334                 return false;
1335
1336         for (i = u+1; *i; i++) {
1337                 if (!(*i >= 'a' && *i <= 'z') &&
1338                     !(*i >= 'A' && *i <= 'Z') &&
1339                     !(*i >= '0' && *i <= '9') &&
1340                     *i != '_' &&
1341                     *i != '-')
1342                         return false;
1343         }
1344
1345         sz = sysconf(_SC_LOGIN_NAME_MAX);
1346         assert_se(sz > 0);
1347
1348         if ((size_t) (i-u) > (size_t) sz)
1349                 return false;
1350
1351         if ((size_t) (i-u) > UT_NAMESIZE - 1)
1352                 return false;
1353
1354         return true;
1355 }
1356
1357 static bool valid_gecos(const char *d) {
1358
1359         if (!d)
1360                 return false;
1361
1362         if (!utf8_is_valid(d))
1363                 return false;
1364
1365         if (string_has_cc(d, NULL))
1366                 return false;
1367
1368         /* Colons are used as field separators, and hence not OK */
1369         if (strchr(d, ':'))
1370                 return false;
1371
1372         return true;
1373 }
1374
1375 static bool valid_home(const char *p) {
1376
1377         if (isempty(p))
1378                 return false;
1379
1380         if (!utf8_is_valid(p))
1381                 return false;
1382
1383         if (string_has_cc(p, NULL))
1384                 return false;
1385
1386         if (!path_is_absolute(p))
1387                 return false;
1388
1389         if (!path_is_safe(p))
1390                 return false;
1391
1392         /* Colons are used as field separators, and hence not OK */
1393         if (strchr(p, ':'))
1394                 return false;
1395
1396         return true;
1397 }
1398
1399 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1400
1401         static const Specifier specifier_table[] = {
1402                 { 'm', specifier_machine_id, NULL },
1403                 { 'b', specifier_boot_id, NULL },
1404                 { 'H', specifier_host_name, NULL },
1405                 { 'v', specifier_kernel_release, NULL },
1406                 {}
1407         };
1408
1409         _cleanup_free_ char *action = NULL, *name = NULL, *id = NULL, *resolved_name = NULL, *resolved_id = NULL, *description = NULL, *home = NULL;
1410         _cleanup_(item_freep) Item *i = NULL;
1411         Item *existing;
1412         Hashmap *h;
1413         int r;
1414         const char *p;
1415
1416         assert(fname);
1417         assert(line >= 1);
1418         assert(buffer);
1419
1420         /* Parse columns */
1421         p = buffer;
1422         r = unquote_many_words(&p, &action, &name, &id, &description, &home, NULL);
1423         if (r < 0) {
1424                 log_error("[%s:%u] Syntax error.", fname, line);
1425                 return r;
1426         }
1427         if (r < 2) {
1428                 log_error("[%s:%u] Missing action and name columns.", fname, line);
1429                 return -EINVAL;
1430         }
1431         if (*p != 0) {
1432                 log_error("[%s:%u] Trailing garbage.", fname, line);
1433                 return -EINVAL;
1434         }
1435
1436         /* Verify action */
1437         if (strlen(action) != 1) {
1438                 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1439                 return -EINVAL;
1440         }
1441
1442         if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)) {
1443                 log_error("[%s:%u] Unknown command command type '%c'.", fname, line, action[0]);
1444                 return -EBADMSG;
1445         }
1446
1447         /* Verify name */
1448         if (isempty(name) || streq(name, "-")) {
1449                 free(name);
1450                 name = NULL;
1451         }
1452
1453         if (name) {
1454                 r = specifier_printf(name, specifier_table, NULL, &resolved_name);
1455                 if (r < 0) {
1456                         log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
1457                         return r;
1458                 }
1459
1460                 if (!valid_user_group_name(resolved_name)) {
1461                         log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_name);
1462                         return -EINVAL;
1463                 }
1464         }
1465
1466         /* Verify id */
1467         if (isempty(id) || streq(id, "-")) {
1468                 free(id);
1469                 id = NULL;
1470         }
1471
1472         if (id) {
1473                 r = specifier_printf(id, specifier_table, NULL, &resolved_id);
1474                 if (r < 0) {
1475                         log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
1476                         return r;
1477                 }
1478         }
1479
1480         /* Verify description */
1481         if (isempty(description) || streq(description, "-")) {
1482                 free(description);
1483                 description = NULL;
1484         }
1485
1486         if (description) {
1487                 if (!valid_gecos(description)) {
1488                         log_error("[%s:%u] '%s' is not a valid GECOS field.", fname, line, description);
1489                         return -EINVAL;
1490                 }
1491         }
1492
1493         /* Verify home */
1494         if (isempty(home) || streq(home, "-")) {
1495                 free(home);
1496                 home = NULL;
1497         }
1498
1499         if (home) {
1500                 if (!valid_home(home)) {
1501                         log_error("[%s:%u] '%s' is not a valid home directory field.", fname, line, home);
1502                         return -EINVAL;
1503                 }
1504         }
1505
1506         switch (action[0]) {
1507
1508         case ADD_RANGE:
1509                 if (resolved_name) {
1510                         log_error("[%s:%u] Lines of type 'r' don't take a name field.", fname, line);
1511                         return -EINVAL;
1512                 }
1513
1514                 if (!resolved_id) {
1515                         log_error("[%s:%u] Lines of type 'r' require a ID range in the third field.", fname, line);
1516                         return -EINVAL;
1517                 }
1518
1519                 if (description) {
1520                         log_error("[%s:%u] Lines of type 'r' don't take a GECOS field.", fname, line);
1521                         return -EINVAL;
1522                 }
1523
1524                 if (home) {
1525                         log_error("[%s:%u] Lines of type 'r' don't take a home directory field.", fname, line);
1526                         return -EINVAL;
1527                 }
1528
1529                 r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
1530                 if (r < 0) {
1531                         log_error("[%s:%u] Invalid UID range %s.", fname, line, resolved_id);
1532                         return -EINVAL;
1533                 }
1534
1535                 return 0;
1536
1537         case ADD_MEMBER: {
1538                 char **l;
1539
1540                 /* Try to extend an existing member or group item */
1541                 if (!name) {
1542                         log_error("[%s:%u] Lines of type 'm' require a user name in the second field.", fname, line);
1543                         return -EINVAL;
1544                 }
1545
1546                 if (!resolved_id) {
1547                         log_error("[%s:%u] Lines of type 'm' require a group name in the third field.", fname, line);
1548                         return -EINVAL;
1549                 }
1550
1551                 if (!valid_user_group_name(resolved_id)) {
1552                         log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_id);
1553                         return -EINVAL;
1554                 }
1555
1556                 if (description) {
1557                         log_error("[%s:%u] Lines of type 'm' don't take a GECOS field.", fname, line);
1558                         return -EINVAL;
1559                 }
1560
1561                 if (home) {
1562                         log_error("[%s:%u] Lines of type 'm' don't take a home directory field.", fname, line);
1563                         return -EINVAL;
1564                 }
1565
1566                 r = hashmap_ensure_allocated(&members, &string_hash_ops);
1567                 if (r < 0)
1568                         return log_oom();
1569
1570                 l = hashmap_get(members, resolved_id);
1571                 if (l) {
1572                         /* A list for this group name already exists, let's append to it */
1573                         r = strv_push(&l, resolved_name);
1574                         if (r < 0)
1575                                 return log_oom();
1576
1577                         resolved_name = NULL;
1578
1579                         assert_se(hashmap_update(members, resolved_id, l) >= 0);
1580                 } else {
1581                         /* No list for this group name exists yet, create one */
1582
1583                         l = new0(char *, 2);
1584                         if (!l)
1585                                 return -ENOMEM;
1586
1587                         l[0] = resolved_name;
1588                         l[1] = NULL;
1589
1590                         r = hashmap_put(members, resolved_id, l);
1591                         if (r < 0) {
1592                                 free(l);
1593                                 return log_oom();
1594                         }
1595
1596                         resolved_id = resolved_name = NULL;
1597                 }
1598
1599                 return 0;
1600         }
1601
1602         case ADD_USER:
1603                 if (!name) {
1604                         log_error("[%s:%u] Lines of type 'u' require a user name in the second field.", fname, line);
1605                         return -EINVAL;
1606                 }
1607
1608                 r = hashmap_ensure_allocated(&users, &string_hash_ops);
1609                 if (r < 0)
1610                         return log_oom();
1611
1612                 i = new0(Item, 1);
1613                 if (!i)
1614                         return log_oom();
1615
1616                 if (resolved_id) {
1617                         if (path_is_absolute(resolved_id)) {
1618                                 i->uid_path = resolved_id;
1619                                 resolved_id = NULL;
1620
1621                                 path_kill_slashes(i->uid_path);
1622                         } else {
1623                                 r = parse_uid(resolved_id, &i->uid);
1624                                 if (r < 0) {
1625                                         log_error("Failed to parse UID: %s", id);
1626                                         return -EBADMSG;
1627                                 }
1628
1629                                 i->uid_set = true;
1630                         }
1631                 }
1632
1633                 i->description = description;
1634                 description = NULL;
1635
1636                 i->home = home;
1637                 home = NULL;
1638
1639                 h = users;
1640                 break;
1641
1642         case ADD_GROUP:
1643                 if (!name) {
1644                         log_error("[%s:%u] Lines of type 'g' require a user name in the second field.", fname, line);
1645                         return -EINVAL;
1646                 }
1647
1648                 if (description) {
1649                         log_error("[%s:%u] Lines of type 'g' don't take a GECOS field.", fname, line);
1650                         return -EINVAL;
1651                 }
1652
1653                 if (home) {
1654                         log_error("[%s:%u] Lines of type 'g' don't take a home directory field.", fname, line);
1655                         return -EINVAL;
1656                 }
1657
1658                 r = hashmap_ensure_allocated(&groups, &string_hash_ops);
1659                 if (r < 0)
1660                         return log_oom();
1661
1662                 i = new0(Item, 1);
1663                 if (!i)
1664                         return log_oom();
1665
1666                 if (resolved_id) {
1667                         if (path_is_absolute(resolved_id)) {
1668                                 i->gid_path = resolved_id;
1669                                 resolved_id = NULL;
1670
1671                                 path_kill_slashes(i->gid_path);
1672                         } else {
1673                                 r = parse_gid(resolved_id, &i->gid);
1674                                 if (r < 0) {
1675                                         log_error("Failed to parse GID: %s", id);
1676                                         return -EBADMSG;
1677                                 }
1678
1679                                 i->gid_set = true;
1680                         }
1681                 }
1682
1683                 h = groups;
1684                 break;
1685
1686         default:
1687                 return -EBADMSG;
1688         }
1689
1690         i->type = action[0];
1691         i->name = resolved_name;
1692         resolved_name = NULL;
1693
1694         existing = hashmap_get(h, i->name);
1695         if (existing) {
1696
1697                 /* Two identical items are fine */
1698                 if (!item_equal(existing, i))
1699                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->name);
1700
1701                 return 0;
1702         }
1703
1704         r = hashmap_put(h, i->name, i);
1705         if (r < 0)
1706                 return log_oom();
1707
1708         i = NULL;
1709         return 0;
1710 }
1711
1712 static int read_config_file(const char *fn, bool ignore_enoent) {
1713         _cleanup_fclose_ FILE *rf = NULL;
1714         FILE *f = NULL;
1715         char line[LINE_MAX];
1716         unsigned v = 0;
1717         int r = 0;
1718
1719         assert(fn);
1720
1721         if (streq(fn, "-"))
1722                 f = stdin;
1723         else {
1724                 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &rf);
1725                 if (r < 0) {
1726                         if (ignore_enoent && r == -ENOENT)
1727                                 return 0;
1728
1729                         log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1730                         return r;
1731                 }
1732
1733                 f = rf;
1734         }
1735
1736         FOREACH_LINE(line, f, break) {
1737                 char *l;
1738                 int k;
1739
1740                 v++;
1741
1742                 l = strstrip(line);
1743                 if (*l == '#' || *l == 0)
1744                         continue;
1745
1746                 k = parse_line(fn, v, l);
1747                 if (k < 0 && r == 0)
1748                         r = k;
1749         }
1750
1751         if (ferror(f)) {
1752                 log_error("Failed to read from file %s: %m", fn);
1753                 if (r == 0)
1754                         r = -EIO;
1755         }
1756
1757         return r;
1758 }
1759
1760 static void free_database(Hashmap *by_name, Hashmap *by_id) {
1761         char *name;
1762
1763         for (;;) {
1764                 name = hashmap_first(by_id);
1765                 if (!name)
1766                         break;
1767
1768                 hashmap_remove(by_name, name);
1769
1770                 hashmap_steal_first_key(by_id);
1771                 free(name);
1772         }
1773
1774         while ((name = hashmap_steal_first_key(by_name)))
1775                 free(name);
1776
1777         hashmap_free(by_name);
1778         hashmap_free(by_id);
1779 }
1780
1781 static void help(void) {
1782         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1783                "Creates system user accounts.\n\n"
1784                "  -h --help                 Show this help\n"
1785                "     --version              Show package version\n"
1786                "     --root=PATH            Operate on an alternate filesystem root\n"
1787                , program_invocation_short_name);
1788 }
1789
1790 static int parse_argv(int argc, char *argv[]) {
1791
1792         enum {
1793                 ARG_VERSION = 0x100,
1794                 ARG_ROOT,
1795         };
1796
1797         static const struct option options[] = {
1798                 { "help",    no_argument,       NULL, 'h'         },
1799                 { "version", no_argument,       NULL, ARG_VERSION },
1800                 { "root",    required_argument, NULL, ARG_ROOT    },
1801                 {}
1802         };
1803
1804         int c;
1805
1806         assert(argc >= 0);
1807         assert(argv);
1808
1809         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1810
1811                 switch (c) {
1812
1813                 case 'h':
1814                         help();
1815                         return 0;
1816
1817                 case ARG_VERSION:
1818                         puts(PACKAGE_STRING);
1819                         puts(SYSTEMD_FEATURES);
1820                         return 0;
1821
1822                 case ARG_ROOT:
1823                         free(arg_root);
1824                         arg_root = path_make_absolute_cwd(optarg);
1825                         if (!arg_root)
1826                                 return log_oom();
1827
1828                         path_kill_slashes(arg_root);
1829                         break;
1830
1831                 case '?':
1832                         return -EINVAL;
1833
1834                 default:
1835                         assert_not_reached("Unhandled option");
1836                 }
1837
1838         return 1;
1839 }
1840
1841 int main(int argc, char *argv[]) {
1842
1843         _cleanup_close_ int lock = -1;
1844         Iterator iterator;
1845         int r, k;
1846         Item *i;
1847         char *n;
1848
1849         r = parse_argv(argc, argv);
1850         if (r <= 0)
1851                 goto finish;
1852
1853         log_set_target(LOG_TARGET_AUTO);
1854         log_parse_environment();
1855         log_open();
1856
1857         umask(0022);
1858
1859         r = mac_selinux_init(NULL);
1860         if (r < 0) {
1861                 log_error("SELinux setup failed: %s", strerror(-r));
1862                 goto finish;
1863         }
1864
1865         if (optind < argc) {
1866                 int j;
1867
1868                 for (j = optind; j < argc; j++) {
1869                         k = read_config_file(argv[j], false);
1870                         if (k < 0 && r == 0)
1871                                 r = k;
1872                 }
1873         } else {
1874                 _cleanup_strv_free_ char **files = NULL;
1875                 char **f;
1876
1877                 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1878                 if (r < 0) {
1879                         log_error("Failed to enumerate sysusers.d files: %s", strerror(-r));
1880                         goto finish;
1881                 }
1882
1883                 STRV_FOREACH(f, files) {
1884                         k = read_config_file(*f, true);
1885                         if (k < 0 && r == 0)
1886                                 r = k;
1887                 }
1888         }
1889
1890         if (!uid_range) {
1891                 /* Default to default range of 1..SYSTEMD_UID_MAX */
1892                 r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX);
1893                 if (r < 0) {
1894                         log_oom();
1895                         goto finish;
1896                 }
1897         }
1898
1899         r = add_implicit();
1900         if (r < 0)
1901                 goto finish;
1902
1903         lock = take_password_lock(arg_root);
1904         if (lock < 0) {
1905                 log_error("Failed to take lock: %s", strerror(-lock));
1906                 goto finish;
1907         }
1908
1909         r = load_user_database();
1910         if (r < 0) {
1911                 log_error("Failed to load user database: %s", strerror(-r));
1912                 goto finish;
1913         }
1914
1915         r = load_group_database();
1916         if (r < 0) {
1917                 log_error("Failed to read group database: %s", strerror(-r));
1918                 goto finish;
1919         }
1920
1921         HASHMAP_FOREACH(i, groups, iterator)
1922                 process_item(i);
1923
1924         HASHMAP_FOREACH(i, users, iterator)
1925                 process_item(i);
1926
1927         r = write_files();
1928         if (r < 0)
1929                 log_error("Failed to write files: %s", strerror(-r));
1930
1931 finish:
1932         while ((i = hashmap_steal_first(groups)))
1933                 item_free(i);
1934
1935         while ((i = hashmap_steal_first(users)))
1936                 item_free(i);
1937
1938         while ((n = hashmap_first_key(members))) {
1939                 strv_free(hashmap_steal_first(members));
1940                 free(n);
1941         }
1942
1943         hashmap_free(groups);
1944         hashmap_free(users);
1945         hashmap_free(members);
1946         hashmap_free(todo_uids);
1947         hashmap_free(todo_gids);
1948
1949         free_database(database_user, database_uid);
1950         free_database(database_group, database_gid);
1951
1952         free(arg_root);
1953
1954         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1955 }