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