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