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