vfs: check userland buffers before reading them.
[haiku.git] / src / bin / multiuser / passwd.cpp
blob33df0c54bd17bd2409197c33fdeacce1f114eaa7
1 /*
2 * Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
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>
18 #include <OS.h>
20 #include <RegistrarDefs.h>
21 #include <user_group.h>
22 #include <util/KMessage.h>
24 #include <AutoDeleter.h>
26 #include "multiuser_utils.h"
29 extern const char *__progname;
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"
43 static void
44 print_usage_and_exit(bool error)
46 fprintf(error ? stderr : stdout, kUsage, __progname);
47 exit(error ? 1 : 0);
51 int
52 main(int argc, const char* const* argv)
54 bool deletePassword = false;
56 while (true) {
57 static struct option sLongOptions[] = {
58 { "help", no_argument, 0, 'h' },
59 { 0, 0, 0, 0 }
62 opterr = 0; // don't print errors
63 int c = getopt_long(argc, (char**)argv, "dh", sLongOptions, NULL);
64 if (c == -1)
65 break;
68 switch (c) {
69 case 'd':
70 deletePassword = true;
71 break;
73 case 'h':
74 print_usage_and_exit(false);
75 break;
77 default:
78 print_usage_and_exit(true);
79 break;
83 if (optind + 1 < argc)
84 print_usage_and_exit(true);
86 const char* user = optind < argc ? argv[optind] : NULL;
88 if (geteuid() != 0) {
89 fprintf(stderr, "Error: You need to be root.\n");
90 exit(1);
93 // this is a set-uid tool -- get the real UID
94 uid_t uid = getuid();
96 if (deletePassword) {
97 if (uid != 0) {
98 fprintf(stderr, "Error: Only root can delete users' passwords.\n");
99 exit(1);
102 if (user == NULL) {
103 fprintf(stderr, "Error: A user must be specified.\n");
104 exit(1);
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);
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);
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);
130 user = passwd->pw_name;
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);
141 char password[LINE_MAX];
142 char* encryptedPassword;
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);
154 if (strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) {
155 fprintf(stderr, "Error: The password is too long.\n");
156 exit(1);
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);
166 // passwords need to match
167 if (strcmp(password, repeatedPassword) != 0) {
168 fprintf(stderr, "Error: passwords don't match\n");
169 exit(1);
172 memset(repeatedPassword, 0, sizeof(repeatedPassword));
174 // crypt it
175 encryptedPassword = crypt(password, NULL);
176 memset(password, 0, sizeof(password));
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: Failed to construct message!\n");
186 exit(1);
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);
198 return 0;