1 /* useradd.c - add a new user
2 *
3 * Copyright 2013 Ashwini Kumar <[email protected]>
4 * Copyright 2013 Kyungwan Han <[email protected]>
5 *
6 * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/useradd.html
7
8 USE_USERADD(NEWTOY(useradd, "<1>2u#<0G:s:g:h:SDH", TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
9 USE_USERADD(OLDTOY(adduser, useradd, TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
10
11 config USERADD
12 bool "useradd"
13 default n
14 help
15 usage: useradd [-SDH] [-h DIR] [-s SHELL] [-G GRP] [-g NAME] [-u UID] USER [GROUP]
16
17 Create new user, or add USER to GROUP
18
19 -D Don't assign a password
20 -g NAME Real name
21 -G GRP Add user to existing group
22 -h DIR Home directory
23 -H Don't create home directory
24 -s SHELL Login shell
25 -S Create a system user
26 -u UID User id
27 */
28
29 #define FOR_useradd
30 #include "toys.h"
31
GLOBALS(char * dir;char * gecos;char * shell;char * u_grp;long uid;long gid;)32 GLOBALS(
33 char *dir;
34 char *gecos;
35 char *shell;
36 char *u_grp;
37 long uid;
38
39 long gid;
40 )
41
42 // TODO user exists error
43 void useradd_main(void)
44 {
45 char *s = *toys.optargs, *entry;
46 struct passwd pwd;
47
48 // Act like groupadd?
49 if (toys.optc == 2) {
50 if (toys.optflags) help_exit("options with USER GROUP");
51 xexec((char *[]){"groupadd", toys.optargs[0], toys.optargs[1], 0});
52 }
53
54 // Sanity check user to add
55 if (s[strcspn(s, ":/\n")] || strlen(s) > LOGIN_NAME_MAX)
56 error_exit("bad username");
57 // race condition: two adds at same time?
58 if (getpwnam(s)) error_exit("'%s' in use", s);
59
60 // Add a new group to the system, if UID is given then that is validated
61 // to be free, else a free UID is choosen by self.
62 // SYSTEM IDs are considered in the range 100 ... 999
63 // add_user(), add a new entry in /etc/passwd, /etc/shadow files
64
65 pwd.pw_name = s;
66 pwd.pw_passwd = "x";
67 pwd.pw_gecos = TT.gecos ? TT.gecos : "Linux User,";
68 pwd.pw_dir = TT.dir ? TT.dir : xmprintf("/home/%s", *toys.optargs);
69
70 if (!TT.shell) {
71 TT.shell = getenv("SHELL");
72
73 if (!TT.shell) {
74 struct passwd *pw = getpwuid(getuid());
75
76 if (pw && pw->pw_shell && *pw->pw_shell) TT.shell = xstrdup(pw->pw_shell);
77 else TT.shell = "/bin/sh";
78 }
79 }
80 pwd.pw_shell = TT.shell;
81
82 if (toys.optflags & FLAG_u) {
83 if (TT.uid > INT_MAX) error_exit("bad uid");
84 if (getpwuid(TT.uid)) error_exit("uid '%ld' in use", TT.uid);
85 } else {
86 if (toys.optflags & FLAG_S) TT.uid = CFG_TOYBOX_UID_SYS;
87 else TT.uid = CFG_TOYBOX_UID_USR;
88 //find unused uid
89 while (getpwuid(TT.uid)) TT.uid++;
90 }
91 pwd.pw_uid = TT.uid;
92
93 if (toys.optflags & FLAG_G) TT.gid = xgetgrnam(TT.u_grp)->gr_gid;
94 else {
95 // Set the GID for the user, if not specified
96 if (toys.optflags & FLAG_S) TT.gid = CFG_TOYBOX_UID_SYS;
97 else TT.gid = CFG_TOYBOX_UID_USR;
98 if (getgrnam(pwd.pw_name)) error_exit("group '%s' in use", pwd.pw_name);
99 //find unused gid
100 while (getgrgid(TT.gid)) TT.gid++;
101 }
102 pwd.pw_gid = TT.gid;
103
104 // Create a new group for user
105 if (!(toys.optflags & FLAG_G)) {
106 char *s = xmprintf("-g%ld", (long)pwd.pw_gid);
107
108 if (xrun((char *[]){"groupadd", *toys.optargs, s, 0}))
109 error_msg("addgroup -g%ld fail", (long)pwd.pw_gid);
110 free(s);
111 }
112
113 /*add user to system
114 * 1. add an entry to /etc/passwd and /etcshadow file
115 * 2. Copy /etc/skel dir contents to use home dir
116 * 3. update the user passwd by running 'passwd' utility
117 */
118
119 // 1. add an entry to /etc/passwd and /etc/shadow file
120 entry = xmprintf("%s:%s:%ld:%ld:%s:%s:%s", pwd.pw_name, pwd.pw_passwd,
121 (long)pwd.pw_uid, (long)pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
122 pwd.pw_shell);
123 update_password("/etc/passwd", pwd.pw_name, entry, 0);
124 free(entry);
125
126 if (toys.optflags & FLAG_S)
127 entry = xmprintf("%s:!!:%u::::::", pwd.pw_name,
128 (unsigned)(time(NULL))/(24*60*60)); //passwd is not set initially
129 else entry = xmprintf("%s:!!:%u:0:99999:7:::", pwd.pw_name,
130 (unsigned)(time(0))/(24*60*60)); //passwd is not set initially
131 update_password("/etc/shadow", pwd.pw_name, entry, 0);
132 free(entry);
133
134 // create home dir & copy skel dir to home
135 if (!(toys.optflags & (FLAG_S|FLAG_H))) {
136 char *skel = "/etc/skel", *p = pwd.pw_dir;
137
138 // Copy and change ownership
139 if (access(p, F_OK)) {
140 if (!access(skel, R_OK))
141 toys.exitval = xrun((char *[]){"cp", "-R", skel, p, 0});
142 else toys.exitval = xrun((char *[]){"mkdir", "-p", p, 0});
143 if (!toys.exitval)
144 toys.exitval |= xrun((char *[]){"chown", "-R",
145 xmprintf("%lu:%lu", TT.uid, TT.gid), p, 0});
146 wfchmodat(AT_FDCWD, p, 0700);
147 } else fprintf(stderr, "'%s' exists, not copying '%s'", p, skel);
148 }
149
150 //3. update the user passwd by running 'passwd' utility
151 if (!(toys.optflags & FLAG_D))
152 if (xrun((char *[]){"passwd", pwd.pw_name, 0})) error_exit("passwd");
153
154 if (toys.optflags & FLAG_G) {
155 /*add user to the existing group, invoke addgroup command */
156 if (xrun((char *[]){"groupadd", *toys.optargs, TT.u_grp, 0}))
157 error_exit("groupadd");
158 }
159 }
160