blob: d409eabb9427f0d121e9dd6cec4bf3cc2b8a7820 [file] [log] [blame]
Robert Griebl1fca5582002-06-04 20:45:46 +00001/* vi: set sw=4 ts=4: */
2/*
3 * adduser - add users to /etc/passwd and /etc/shadow
4 *
5 * Copyright (C) 1999 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00008 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Robert Griebl1fca5582002-06-04 20:45:46 +00009 */
10
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000011#include "libbb.h"
Robert Griebl1fca5582002-06-04 20:45:46 +000012
Denis Vlasenko5df955f2007-03-13 13:01:14 +000013#define OPT_DONT_SET_PASS (1 << 4)
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000014#define OPT_SYSTEM_ACCOUNT (1 << 5)
Denis Vlasenko5df955f2007-03-13 13:01:14 +000015#define OPT_DONT_MAKE_HOME (1 << 6)
Robert Griebl1fca5582002-06-04 20:45:46 +000016
17
Robert Griebl1fca5582002-06-04 20:45:46 +000018/* remix */
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000019/* recoded such that the uid may be passed in *p */
20static void passwd_study(struct passwd *p)
Robert Griebl1fca5582002-06-04 20:45:46 +000021{
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000022 int max;
Robert Griebl1fca5582002-06-04 20:45:46 +000023
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000024 if (getpwnam(p->pw_name))
25 bb_error_msg_and_die("login '%s' is in use", p->pw_name);
Robert Griebl1fca5582002-06-04 20:45:46 +000026
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000027 if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
28 p->pw_uid = 0;
29 max = 999;
30 } else {
31 p->pw_uid = 1000;
32 max = 64999;
Robert Griebl1fca5582002-06-04 20:45:46 +000033 }
34
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000035 /* check for a free uid (and maybe gid) */
36 while (getpwuid(p->pw_uid) || (!p->pw_gid && getgrgid(p->pw_uid)))
37 p->pw_uid++;
Denis Vlasenko6cee58e2007-11-04 15:43:26 +000038
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000039 if (!p->pw_gid) {
40 /* new gid = uid */
Eric Andersenf0f754a2003-06-21 20:03:07 +000041 p->pw_gid = p->pw_uid;
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000042 if (getgrnam(p->pw_name))
43 bb_error_msg_and_die("group name '%s' is in use", p->pw_name);
Eric Andersenf0f754a2003-06-21 20:03:07 +000044 }
Robert Griebl1fca5582002-06-04 20:45:46 +000045
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000046 if (p->pw_uid > max)
47 bb_error_msg_and_die("no free uids left");
Robert Griebl1fca5582002-06-04 20:45:46 +000048}
49
Rob Landley9a2dd512006-04-04 19:19:53 +000050static void addgroup_wrapper(struct passwd *p)
Robert Griebl1fca5582002-06-04 20:45:46 +000051{
Eric Andersenc38678d2002-09-16 06:22:25 +000052 char *cmd;
Robert Griebl1fca5582002-06-04 20:45:46 +000053
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000054 cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name);
Robert Griebl2c0d0f02002-07-16 23:50:05 +000055 system(cmd);
56 free(cmd);
Robert Griebl1fca5582002-06-04 20:45:46 +000057}
58
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +000059static void passwd_wrapper(const char *login) ATTRIBUTE_NORETURN;
Eric Andersenc38678d2002-09-16 06:22:25 +000060
Robert Griebl1fca5582002-06-04 20:45:46 +000061static void passwd_wrapper(const char *login)
62{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000063 static const char prog[] ALIGN1 = "passwd";
64
Denis Vlasenko1d76f432007-02-06 01:20:12 +000065 BB_EXECLP(prog, prog, login, NULL);
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000066 bb_error_msg_and_die("cannot execute %s, you must set password manually", prog);
Robert Griebl1fca5582002-06-04 20:45:46 +000067}
68
Denis Vlasenko753f42a2008-02-15 15:17:23 +000069#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
70static const char adduser_longopts[] ALIGN1 =
71 "home\0" Required_argument "h"
72 "gecos\0" Required_argument "g"
73 "shell\0" Required_argument "s"
74 "ingroup\0" Required_argument "G"
75 "disabled-password\0" No_argument "D"
76 "empty-password\0" No_argument "D"
77 "system\0" No_argument "S"
78 "no-create-home\0" No_argument "H"
79 ;
80#endif
81
Robert Griebl1fca5582002-06-04 20:45:46 +000082/*
83 * adduser will take a login_name as its first parameter.
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000084 * home, shell, gecos:
Robert Griebl1fca5582002-06-04 20:45:46 +000085 * can be customized via command-line parameters.
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000086 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000087int adduser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko68404f12008-03-17 09:00:54 +000088int adduser_main(int argc ATTRIBUTE_UNUSED, char **argv)
Robert Griebl1fca5582002-06-04 20:45:46 +000089{
Eric Andersenf0f754a2003-06-21 20:03:07 +000090 struct passwd pw;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000091 const char *usegroup = NULL;
Denis Vlasenko15ca51e2007-10-29 19:25:45 +000092 FILE *file;
Robert Griebl1fca5582002-06-04 20:45:46 +000093
Denis Vlasenko753f42a2008-02-15 15:17:23 +000094#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
95 applet_long_options = adduser_longopts;
96#endif
97
Denis Vlasenko3ef70d42006-12-26 17:37:38 +000098 /* got root? */
99 if (geteuid()) {
100 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
101 }
102
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000103 pw.pw_gecos = (char *)"Linux User,,,";
Rob Landley9a2dd512006-04-04 19:19:53 +0000104 pw.pw_shell = (char *)DEFAULT_SHELL;
105 pw.pw_dir = NULL;
Eric Andersenf0f754a2003-06-21 20:03:07 +0000106
Denis Vlasenkof1f1b692007-07-30 12:32:37 +0000107 /* exactly one non-option arg */
108 opt_complementary = "=1";
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000109 getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
Denis Vlasenko74324c82007-06-04 10:16:52 +0000110 argv += optind;
Robert Griebl1fca5582002-06-04 20:45:46 +0000111
Denis Vlasenko15ca51e2007-10-29 19:25:45 +0000112 /* fill in the passwd struct */
Denis Vlasenko74324c82007-06-04 10:16:52 +0000113 pw.pw_name = argv[0];
114 if (!pw.pw_dir) {
115 /* create string for $HOME if not specified already */
116 pw.pw_dir = xasprintf("/home/%s", argv[0]);
117 }
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000118 pw.pw_passwd = (char *)"x";
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +0000119 pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */
Eric Andersenf0f754a2003-06-21 20:03:07 +0000120
Denis Vlasenko15ca51e2007-10-29 19:25:45 +0000121 /* make sure everything is kosher and setup uid && maybe gid */
122 passwd_study(&pw);
123
124 /* add to passwd */
125 file = xfopen(bb_path_passwd_file, "a");
126 //fseek(file, 0, SEEK_END); /* paranoia, "a" should ensure that anyway */
127 if (putpwent(&pw, file) != 0) {
128 bb_perror_nomsg_and_die();
129 }
130 /* do fclose even if !ENABLE_FEATURE_CLEAN_UP.
131 * We will exec passwd, files must be flushed & closed before that! */
132 fclose(file);
133
134#if ENABLE_FEATURE_SHADOWPASSWDS
135 /* add to shadow if necessary */
136 file = fopen_or_warn(bb_path_shadow_file, "a");
137 if (file) {
138 //fseek(file, 0, SEEK_END);
139 fprintf(file, "%s:!:%u:0:99999:7:::\n",
140 pw.pw_name, /* username */
141 (unsigned)(time(NULL) / 86400) /* sp->sp_lstchg */
142 /*0,*/ /* sp->sp_min */
143 /*99999,*/ /* sp->sp_max */
144 /*7*/ /* sp->sp_warn */
145 );
146 fclose(file);
147 }
148#endif
149
150 /* add to group */
151 /* addgroup should be responsible for dealing w/ gshadow */
152 /* if using a pre-existing group, don't create one */
153 if (!usegroup)
154 addgroup_wrapper(&pw);
155
156 /* Clear the umask for this process so it doesn't
157 * screw up the permissions on the mkdir and chown. */
158 umask(0);
159 if (!(option_mask32 & OPT_DONT_MAKE_HOME)) {
160 /* Set the owner and group so it is owned by the new user,
161 then fix up the permissions to 2755. Can't do it before
162 since chown will clear the setgid bit */
163 if (mkdir(pw.pw_dir, 0755)
164 || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid)
165 || chmod(pw.pw_dir, 02755) /* set setgid bit on homedir */
Denis Vlasenko6cee58e2007-11-04 15:43:26 +0000166 ) {
Denis Vlasenko15ca51e2007-10-29 19:25:45 +0000167 bb_simple_perror_msg(pw.pw_dir);
168 }
169 }
170
171 if (!(option_mask32 & OPT_DONT_SET_PASS)) {
172 /* interactively set passwd */
173 passwd_wrapper(pw.pw_name);
174 }
175
176 return 0;
Robert Griebl1fca5582002-06-04 20:45:46 +0000177}