tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / bin / multiuser / passwd.cpp
blob920002cf297661548d8733a4eb8111942802c62e
1 /*
2 * Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
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>
17 #include <OS.h>
19 #include <RegistrarDefs.h>
20 #include <user_group.h>
21 #include <util/KMessage.h>
23 #include <AutoDeleter.h>
25 #include "multiuser_utils.h"
28 extern const char *__progname;
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"
42 static void
43 print_usage_and_exit(bool error)
45 fprintf(error ? stderr : stdout, kUsage, __progname);
46 exit(error ? 1 : 0);
50 int
51 main(int argc, const char* const* argv)
53 bool deletePassword = false;
55 while (true) {
56 static struct option sLongOptions[] = {
57 { "help", no_argument, 0, 'h' },
58 { 0, 0, 0, 0 }
61 opterr = 0; // don't print errors
62 int c = getopt_long(argc, (char**)argv, "dh", sLongOptions, NULL);
63 if (c == -1)
64 break;
67 switch (c) {
68 case 'd':
69 deletePassword = true;
70 break;
72 case 'h':
73 print_usage_and_exit(false);
74 break;
76 default:
77 print_usage_and_exit(true);
78 break;
82 if (optind + 1 < argc)
83 print_usage_and_exit(true);
85 const char* user = optind < argc ? argv[optind] : NULL;
87 if (geteuid() != 0) {
88 fprintf(stderr, "Error: You need to be root.\n");
89 exit(1);
92 // this is a set-uid tool -- get the real UID
93 uid_t uid = getuid();
95 if (deletePassword) {
96 if (uid != 0) {
97 fprintf(stderr, "Error: Only root can delete users' passwords.\n");
98 exit(1);
101 if (user == NULL) {
102 fprintf(stderr, "Error: A user must be specified.\n");
103 exit(1);
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);
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);
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);
129 user = passwd->pw_name;
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);
140 char password[LINE_MAX];
141 char* encryptedPassword;
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);
153 if (strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) {
154 fprintf(stderr, "Error: The password is too long.\n");
155 exit(1);
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);
165 // passwords need to match
166 if (strcmp(password, repeatedPassword) != 0) {
167 fprintf(stderr, "Error: passwords don't match\n");
168 exit(1);
171 memset(repeatedPassword, 0, sizeof(repeatedPassword));
173 // crypt it
174 encryptedPassword = crypt(password, user);
175 memset(password, 0, sizeof(password));
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);
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);
196 return 0;