2 * Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
18 #include <parsedate.h>
20 #include <RegistrarDefs.h>
21 #include <user_group.h>
22 #include <util/KMessage.h>
24 #include <AutoDeleter.h>
26 #include "multiuser_utils.h"
29 extern const char *__progname
;
32 static const char* kUsage
=
33 "Usage: %s [ <options> ] <user name>\n"
34 "Creates a new user <user name>.\n"
38 " Specifies the home directory for the new user.\n"
40 " Specifies the expiration date for the new user's account.\n"
42 " Specifies the number of days after the expiration of the new user's "
44 " until the account expires.\n"
46 " Specifies the new user's primary group by ID or name.\n"
48 " Print usage info.\n"
50 " Specifies the new user's login shell.\n"
52 " Specifies the new user's real name.\n"
56 print_usage_and_exit(bool error
)
58 fprintf(error
? stderr
: stdout
, kUsage
, __progname
);
64 main(int argc
, const char* const* argv
)
66 const char* home
= "/boot/home";
67 int expiration
= 99999;
69 const char* group
= NULL
;
70 const char* shell
= "/bin/sh";
71 const char* realName
= "";
78 static struct option sLongOptions
[] = {
79 { "help", no_argument
, 0, 'h' },
83 opterr
= 0; // don't print errors
84 int c
= getopt_long(argc
, (char**)argv
, "d:e:f:g:hn:s:", sLongOptions
,
96 expiration
= parsedate(optarg
, time(NULL
)) / (3600 * 24);
100 inactive
= atoi(optarg
);
110 print_usage_and_exit(false);
122 print_usage_and_exit(true);
127 if (optind
!= argc
- 1)
128 print_usage_and_exit(true);
130 const char* user
= argv
[optind
];
132 if (geteuid() != 0) {
133 fprintf(stderr
, "Error: Only root may add users.\n");
137 // check, if user already exists
138 if (getpwnam(user
) != NULL
) {
139 fprintf(stderr
, "Error: User \"%s\" already exists.\n", user
);
147 gid
= strtol(group
, &end
, 0);
149 // seems to be a number
151 fprintf(stderr
, "Error: Invalid group ID \"%s\".\n",
156 // must be a group name -- get it
158 ssize_t bufferSize
= sysconf(_SC_GETGR_R_SIZE_MAX
);
162 buffer
= (char*)realloc(buffer
, bufferSize
);
163 if (buffer
== NULL
) {
164 fprintf(stderr
, "Error: Out of memory!\n");
168 struct group groupBuffer
;
169 struct group
* groupFound
;
170 int error
= getgrnam_r(group
, &groupBuffer
, buffer
, bufferSize
,
172 if (error
== ERANGE
) {
178 fprintf(stderr
, "Error: Failed to get info for group "
182 if (groupFound
== NULL
) {
183 fprintf(stderr
, "Error: Specified group \"%s\" doesn't "
188 gid
= groupFound
->gr_gid
;
194 // find an unused UID
196 while (getpwuid(uid
) != NULL
)
199 // prepare request for the registrar
200 KMessage
message(BPrivate::B_REG_UPDATE_USER
);
201 if (message
.AddInt32("uid", uid
) != B_OK
202 || message
.AddInt32("gid", gid
) != B_OK
203 || message
.AddString("name", user
) != B_OK
204 || message
.AddString("password", "x") != B_OK
205 || message
.AddString("home", home
) != B_OK
206 || message
.AddString("shell", shell
) != B_OK
207 || message
.AddString("real name", realName
) != B_OK
208 || message
.AddString("shadow password", "!") != B_OK
209 || message
.AddInt32("last changed", time(NULL
)) != B_OK
210 || message
.AddInt32("min", min
) != B_OK
211 || message
.AddInt32("max", max
) != B_OK
212 || message
.AddInt32("warn", warn
) != B_OK
213 || message
.AddInt32("inactive", inactive
) != B_OK
214 || message
.AddInt32("expiration", expiration
) != B_OK
215 || message
.AddInt32("flags", 0) != B_OK
216 || message
.AddBool("add user", true) != B_OK
) {
217 fprintf(stderr
, "Error: Out of memory!\n");
223 status_t error
= send_authentication_request_to_registrar(message
, reply
);
225 fprintf(stderr
, "Error: Failed to create user: %s\n", strerror(error
));