/* * Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "multiuser_utils.h" extern const char *__progname; static const char* kUsage = "Usage: %s [ ] \n" "Creates a new user .\n" "\n" "Options:\n" " -d \n" " Specifies the home directory for the new user.\n" " -e \n" " Specifies the expiration date for the new user's account.\n" " -f \n" " Specifies the number of days after the expiration of the new user's " "password\n" " until the account expires.\n" " -g \n" " Specifies the new user's primary group by ID or name.\n" " -h, --help\n" " Print usage info.\n" " -s \n" " Specifies the new user's login shell.\n" " -n \n" " Specifies the new user's real name.\n" ; static void print_usage_and_exit(bool error) { fprintf(error ? stderr : stdout, kUsage, __progname); exit(error ? 1 : 0); } int main(int argc, const char* const* argv) { const char* home = "/boot/home"; int expiration = 99999; int inactive = -1; const char* group = NULL; const char* shell = "/bin/sh"; const char* realName = ""; int min = -1; int max = -1; int warn = 7; while (true) { static struct option sLongOptions[] = { { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; opterr = 0; // don't print errors int c = getopt_long(argc, (char**)argv, "d:e:f:g:hn:s:", sLongOptions, NULL); if (c == -1) break; switch (c) { case 'd': home = optarg; break; case 'e': expiration = parsedate(optarg, time(NULL)) / (3600 * 24); break; case 'f': inactive = atoi(optarg); break; case 'g': { group = optarg; break; } case 'h': print_usage_and_exit(false); break; case 'n': realName = optarg; break; case 's': shell = optarg; break; default: print_usage_and_exit(true); break; } } if (optind != argc - 1) print_usage_and_exit(true); const char* user = argv[optind]; if (geteuid() != 0) { fprintf(stderr, "Error: Only root may add users.\n"); exit(1); } // check, if user already exists if (getpwnam(user) != NULL) { fprintf(stderr, "Error: User \"%s\" already exists.\n", user); exit(1); } // get group ID gid_t gid = 100; if (group != NULL) { char* end; gid = strtol(group, &end, 0); if (*end == '\0') { // seems to be a number if (gid < 1) { fprintf(stderr, "Error: Invalid group ID \"%s\".\n", group); exit(1); } } else { // must be a group name -- get it char* buffer = NULL; ssize_t bufferSize = sysconf(_SC_GETGR_R_SIZE_MAX); if (bufferSize <= 0) bufferSize = 256; for (;;) { buffer = (char*)realloc(buffer, bufferSize); if (buffer == NULL) { fprintf(stderr, "Error: Out of memory!\n"); exit(1); } struct group groupBuffer; struct group* groupFound; int error = getgrnam_r(group, &groupBuffer, buffer, bufferSize, &groupFound); if (error == ERANGE) { bufferSize *= 2; continue; } if (error != 0) { fprintf(stderr, "Error: Failed to get info for group " "\"%s\".\n", group); exit(1); } if (groupFound == NULL) { fprintf(stderr, "Error: Specified group \"%s\" doesn't " "exist.\n", group); exit(1); } gid = groupFound->gr_gid; break; } } } // find an unused UID uid_t uid = 1000; while (getpwuid(uid) != NULL) uid++; // prepare request for the registrar KMessage message(BPrivate::B_REG_UPDATE_USER); if (message.AddInt32("uid", uid) != B_OK || message.AddInt32("gid", gid) != B_OK || message.AddString("name", user) != B_OK || message.AddString("password", "x") != B_OK || message.AddString("home", home) != B_OK || message.AddString("shell", shell) != B_OK || message.AddString("real name", realName) != B_OK || message.AddString("shadow password", "!") != B_OK || message.AddInt32("last changed", time(NULL)) != B_OK || message.AddInt32("min", min) != B_OK || message.AddInt32("max", max) != B_OK || message.AddInt32("warn", warn) != B_OK || message.AddInt32("inactive", inactive) != B_OK || message.AddInt32("expiration", expiration) != B_OK || message.AddInt32("flags", 0) != B_OK || message.AddBool("add user", true) != B_OK) { fprintf(stderr, "Error: Out of memory!\n"); exit(1); } // send the request KMessage reply; status_t error = send_authentication_request_to_registrar(message, reply); if (error != B_OK) { fprintf(stderr, "Error: Failed to create user: %s\n", strerror(error)); exit(1); } return 0; }