xref: /haiku/src/bin/multiuser/passwd.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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