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