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 <pwd.h> 8 #include <shadow.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <termios.h> 13 #include <time.h> 14 #include <unistd.h> 15 16 #include <OS.h> 17 18 #include <RegistrarDefs.h> 19 #include <user_group.h> 20 #include <util/KMessage.h> 21 22 #include <AutoDeleter.h> 23 24 #include "multiuser_utils.h" 25 26 27 extern const char *__progname; 28 29 30 static const char* kUsage = 31 "Usage: %s [ <user name> ]\n" 32 ; 33 34 static void 35 print_usage_and_exit(bool error) 36 { 37 fprintf(error ? stderr : stdout, kUsage, __progname); 38 exit(error ? 1 : 0); 39 } 40 41 42 int 43 main(int argc, const char* const* argv) 44 { 45 if (argc > 2) 46 print_usage_and_exit(true); 47 48 const char* user = NULL; 49 if (argc == 2) 50 user = argv[1]; 51 52 if (geteuid() != 0) { 53 fprintf(stderr, "Error: You need to be root.\n"); 54 exit(1); 55 } 56 57 // this is a set-uid tool -- get the real UID 58 uid_t uid = getuid(); 59 60 // get the passwd entry 61 struct passwd* passwd; 62 if (user != NULL) { 63 passwd = getpwnam(user); 64 if (passwd == NULL) { 65 fprintf(stderr, "Error: No user with name \"%s\".\n", user); 66 exit(1); 67 } 68 69 if (uid != 0 && passwd->pw_uid != uid) { 70 fprintf(stderr, "Error: Only root can change the passwd for other " 71 "users.\n"); 72 exit(1); 73 } 74 } else { 75 passwd = getpwuid(uid); 76 if (passwd == NULL) { 77 fprintf(stderr, "Error: Ugh! Couldn't get passwd entry for uid " 78 "%d.\n", uid); 79 exit(1); 80 } 81 82 user = passwd->pw_name; 83 } 84 85 // if not root, the user needs to authenticate 86 if (uid != 0) { 87 if (authenticate_user("old password: ", passwd, getspnam(user), 1, 88 false) != B_OK) { 89 exit(1); 90 } 91 } 92 93 // read new password 94 char password[LINE_MAX]; 95 if (read_password("new password: ", password, sizeof(password), false) 96 != B_OK) { 97 exit(1); 98 } 99 100 if (strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) { 101 fprintf(stderr, "Error: The password is too long.\n"); 102 exit(1); 103 } 104 105 // read password again 106 char repeatedPassword[LINE_MAX]; 107 if (read_password("repeat new password: ", repeatedPassword, 108 sizeof(repeatedPassword), false) != B_OK) { 109 exit(1); 110 } 111 112 // passwords need to match 113 if (strcmp(password, repeatedPassword) != 0) { 114 fprintf(stderr, "Error: passwords don't match\n"); 115 exit(1); 116 } 117 118 memset(repeatedPassword, 0, sizeof(repeatedPassword)); 119 120 // crypt it 121 char* encryptedPassword; 122 if (strlen(password) > 0) { 123 encryptedPassword = crypt(password, user); 124 memset(password, 0, sizeof(password)); 125 } else 126 encryptedPassword = password; 127 128 // prepare request for the registrar 129 KMessage message(BPrivate::B_REG_UPDATE_USER); 130 if (message.AddInt32("uid", passwd->pw_uid) != B_OK 131 || message.AddInt32("last changed", time(NULL)) != B_OK 132 || message.AddString("password", "x") != B_OK 133 || message.AddString("shadow password", encryptedPassword) != B_OK) { 134 fprintf(stderr, "Error: Out of memory!\n"); 135 exit(1); 136 } 137 138 // send the request 139 KMessage reply; 140 status_t error = send_authentication_request_to_registrar(message, reply); 141 if (error != B_OK) { 142 fprintf(stderr, "Error: Failed to create user: %s\n", strerror(error)); 143 exit(1); 144 } 145 146 return 0; 147 } 148