1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <errno.h> 7 #include <getopt.h> 8 #include <pwd.h> 9 #include <shadow.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <termios.h> 14 #include <time.h> 15 #include <unistd.h> 16 17 #include <OS.h> 18 #include <parsedate.h> 19 20 #include <RegistrarDefs.h> 21 #include <user_group.h> 22 #include <util/KMessage.h> 23 24 #include <AutoDeleter.h> 25 26 #include "multiuser_utils.h" 27 28 29 extern const char *__progname; 30 31 32 static const char* kUsage = 33 "Usage: %s [ -d <home> ] [ -e <expiration> ] [ -f <inactive> ] [ -g <gid> ]\n" 34 " [ -s <shell> ] [ -n <real name> ]\n" 35 ; 36 37 static void 38 print_usage_and_exit(bool error) 39 { 40 fprintf(error ? stderr : stdout, kUsage, __progname); 41 exit(error ? 1 : 0); 42 } 43 44 45 int 46 main(int argc, const char* const* argv) 47 { 48 const char* home = "/boot/home"; 49 int expiration = 99999; 50 int inactive = -1; 51 gid_t gid = 100; 52 const char* shell = "/bin/sh"; 53 const char* realName = ""; 54 55 int min = -1; 56 int max = -1; 57 int warn = 7; 58 59 while (true) { 60 static struct option sLongOptions[] = { 61 { "help", no_argument, 0, 'h' }, 62 { 0, 0, 0, 0 } 63 }; 64 65 opterr = 0; // don't print errors 66 int c = getopt_long(argc, (char**)argv, "d:e:f:g:hn:s:", sLongOptions, 67 NULL); 68 if (c == -1) 69 break; 70 71 72 switch (c) { 73 case 'd': 74 home = optarg; 75 break; 76 77 case 'e': 78 expiration = parsedate(optarg, time(NULL)) / (3600 * 24); 79 break; 80 81 case 'f': 82 inactive = atoi(optarg); 83 break; 84 85 case 'g': 86 gid = atoi(optarg); 87 break; 88 89 case 'h': 90 print_usage_and_exit(false); 91 break; 92 93 case 'n': 94 realName = optarg; 95 break; 96 97 case 's': 98 shell = optarg; 99 break; 100 101 default: 102 print_usage_and_exit(true); 103 break; 104 } 105 } 106 107 if (optind != argc - 1) 108 print_usage_and_exit(true); 109 110 const char* user = argv[optind]; 111 112 if (geteuid() != 0) { 113 fprintf(stderr, "Error: You need to be root.\n"); 114 exit(1); 115 } 116 117 // check, if user already exists 118 if (getpwnam(user) != NULL) { 119 fprintf(stderr, "Error: User \"%s\" already exists.\n", user); 120 exit(1); 121 } 122 123 // read password 124 char password[LINE_MAX]; 125 if (read_password("password for user: ", password, sizeof(password), 126 false) != B_OK) { 127 exit(1); 128 } 129 130 if (strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) { 131 fprintf(stderr, "Error: The password is too long.\n"); 132 exit(1); 133 } 134 135 // read password again 136 char repeatedPassword[LINE_MAX]; 137 if (read_password("repeat password: ", repeatedPassword, 138 sizeof(repeatedPassword), false) != B_OK) { 139 exit(1); 140 } 141 142 // passwords need to match 143 if (strcmp(password, repeatedPassword) != 0) { 144 fprintf(stderr, "Error: passwords don't match\n"); 145 exit(1); 146 } 147 148 memset(repeatedPassword, 0, sizeof(repeatedPassword)); 149 150 // crypt it 151 char* encryptedPassword; 152 if (strlen(password) > 0) { 153 encryptedPassword = crypt(password, user); 154 memset(password, 0, sizeof(password)); 155 } else 156 encryptedPassword = password; 157 158 // find an unused UID 159 uid_t uid = 1000; 160 while (getpwuid(uid) != NULL) 161 uid++; 162 163 // prepare request for the registrar 164 KMessage message(BPrivate::B_REG_UPDATE_USER); 165 if (message.AddInt32("uid", uid) != B_OK 166 || message.AddInt32("gid", gid) != B_OK 167 || message.AddString("name", user) != B_OK 168 || message.AddString("password", "x") != B_OK 169 || message.AddString("home", home) != B_OK 170 || message.AddString("shell", shell) != B_OK 171 || message.AddString("real name", realName) != B_OK 172 || message.AddString("shadow password", encryptedPassword) != B_OK 173 || message.AddInt32("last changed", time(NULL)) != B_OK 174 || message.AddInt32("min", min) != B_OK 175 || message.AddInt32("max", max) != B_OK 176 || message.AddInt32("warn", warn) != B_OK 177 || message.AddInt32("inactive", inactive) != B_OK 178 || message.AddInt32("expiration", expiration) != B_OK 179 || message.AddInt32("flags", 0) != B_OK 180 || message.AddBool("add user", true) != B_OK) { 181 fprintf(stderr, "Error: Out of memory!\n"); 182 exit(1); 183 } 184 185 // send the request 186 KMessage reply; 187 status_t error = send_authentication_request_to_registrar(message, reply); 188 if (error != B_OK) { 189 fprintf(stderr, "Error: Failed to create user: %s\n", strerror(error)); 190 exit(1); 191 } 192 193 return 0; 194 } 195