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