1 /* 2 * Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 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 19 #include <RegistrarDefs.h> 20 #include <user_group.h> 21 #include <util/KMessage.h> 22 23 #include <AutoDeleter.h> 24 25 #include "multiuser_utils.h" 26 27 28 extern const char *__progname; 29 30 31 static const char* kUsage = 32 "Usage: %s [ <options> ] [ <user name> ]\n" 33 "Change the password of the specified user.\n" 34 "\n" 35 "Options:\n" 36 " -d\n" 37 " Delete the password for the specified user.\n" 38 " -h, --help\n" 39 " Print usage info.\n" 40 ; 41 42 static void 43 print_usage_and_exit(bool error) 44 { 45 fprintf(error ? stderr : stdout, kUsage, __progname); 46 exit(error ? 1 : 0); 47 } 48 49 50 int 51 main(int argc, const char* const* argv) 52 { 53 bool deletePassword = false; 54 55 while (true) { 56 static struct option sLongOptions[] = { 57 { "help", no_argument, 0, 'h' }, 58 { 0, 0, 0, 0 } 59 }; 60 61 opterr = 0; // don't print errors 62 int c = getopt_long(argc, (char**)argv, "dh", sLongOptions, NULL); 63 if (c == -1) 64 break; 65 66 67 switch (c) { 68 case 'd': 69 deletePassword = true; 70 break; 71 72 case 'h': 73 print_usage_and_exit(false); 74 break; 75 76 default: 77 print_usage_and_exit(true); 78 break; 79 } 80 } 81 82 if (optind + 1 < argc) 83 print_usage_and_exit(true); 84 85 const char* user = optind < argc ? argv[optind] : NULL; 86 87 if (geteuid() != 0) { 88 fprintf(stderr, "Error: You need to be root.\n"); 89 exit(1); 90 } 91 92 // this is a set-uid tool -- get the real UID 93 uid_t uid = getuid(); 94 95 if (deletePassword) { 96 if (uid != 0) { 97 fprintf(stderr, "Error: Only root can delete users' passwords.\n"); 98 exit(1); 99 } 100 101 if (user == NULL) { 102 fprintf(stderr, "Error: A user must be specified.\n"); 103 exit(1); 104 } 105 } 106 107 // get the passwd entry 108 struct passwd* passwd; 109 if (user != NULL) { 110 passwd = getpwnam(user); 111 if (passwd == NULL) { 112 fprintf(stderr, "Error: No user with name \"%s\".\n", user); 113 exit(1); 114 } 115 116 if (uid != 0 && passwd->pw_uid != uid) { 117 fprintf(stderr, "Error: Only root can change the passwd for other " 118 "users.\n"); 119 exit(1); 120 } 121 } else { 122 passwd = getpwuid(uid); 123 if (passwd == NULL) { 124 fprintf(stderr, "Error: Ugh! Couldn't get passwd entry for uid " 125 "%d.\n", uid); 126 exit(1); 127 } 128 129 user = passwd->pw_name; 130 } 131 132 // if not root, the user needs to authenticate 133 if (uid != 0) { 134 if (authenticate_user("old password: ", passwd, getspnam(user), 1, 135 false) != B_OK) { 136 exit(1); 137 } 138 } 139 140 char password[LINE_MAX]; 141 char* encryptedPassword; 142 143 if (deletePassword) { 144 password[0] = '\0'; 145 encryptedPassword = password; 146 } else { 147 // read new password 148 if (read_password("new password: ", password, sizeof(password), false) 149 != B_OK) { 150 exit(1); 151 } 152 153 if (strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) { 154 fprintf(stderr, "Error: The password is too long.\n"); 155 exit(1); 156 } 157 158 // read password again 159 char repeatedPassword[LINE_MAX]; 160 if (read_password("repeat new password: ", repeatedPassword, 161 sizeof(repeatedPassword), false) != B_OK) { 162 exit(1); 163 } 164 165 // passwords need to match 166 if (strcmp(password, repeatedPassword) != 0) { 167 fprintf(stderr, "Error: passwords don't match\n"); 168 exit(1); 169 } 170 171 memset(repeatedPassword, 0, sizeof(repeatedPassword)); 172 173 // crypt it 174 encryptedPassword = crypt(password, user); 175 memset(password, 0, sizeof(password)); 176 } 177 178 // prepare request for the registrar 179 KMessage message(BPrivate::B_REG_UPDATE_USER); 180 if (message.AddInt32("uid", passwd->pw_uid) != B_OK 181 || message.AddInt32("last changed", time(NULL)) != B_OK 182 || message.AddString("password", "x") != B_OK 183 || message.AddString("shadow password", encryptedPassword) != B_OK) { 184 fprintf(stderr, "Error: Out of memory!\n"); 185 exit(1); 186 } 187 188 // send the request 189 KMessage reply; 190 status_t error = send_authentication_request_to_registrar(message, reply); 191 if (error != B_OK) { 192 fprintf(stderr, "Error: Failed to create user: %s\n", strerror(error)); 193 exit(1); 194 } 195 196 return 0; 197 } 198