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