tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / bin / multiuser / multiuser_utils.cpp
blobdbf2c4980624ba36b26ef046518e895fb903f5a1
1 /*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
6 #include "multiuser_utils.h"
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <termios.h>
13 #include <unistd.h>
15 #include <AutoDeleter.h>
17 #include <user_group.h>
20 status_t
21 read_password(const char* prompt, char* password, size_t bufferSize,
22 bool useStdio)
24 FILE* in = stdin;
25 FILE* out = stdout;
27 // open tty
28 FILE* tty = NULL;
29 if (!useStdio) {
30 // TODO: Open tty with O_NOCTTY!
31 tty = fopen("/dev/tty", "w+");
32 if (tty == NULL) {
33 fprintf(stderr, "Error: Failed to open tty: %s\n", strerror(errno));
34 return errno;
37 in = tty;
38 out = tty;
40 CObjectDeleter<FILE, int> ttyCloser(tty, fclose);
42 // disable echo
43 int inFD = fileno(in);
44 struct termios termAttrs;
45 if (tcgetattr(inFD, &termAttrs) != 0) {
46 fprintf(in, "Error: Failed to get tty attributes: %s\n",
47 strerror(errno));
48 return errno;
51 tcflag_t localFlags = termAttrs.c_lflag;
52 termAttrs.c_lflag &= ~ECHO;
54 if (tcsetattr(inFD, TCSANOW, &termAttrs) != 0) {
55 fprintf(in, "Error: Failed to set tty attributes: %s\n",
56 strerror(errno));
57 return errno;
60 status_t error = B_OK;
62 // prompt and read pwd
63 fprintf(out, prompt);
64 fflush(out);
66 if (fgets(password, bufferSize, in) == NULL) {
67 fprintf(out, "\nError: Failed to read from tty: %s\n", strerror(errno));
68 error = errno != 0 ? errno : B_ERROR;
69 } else
70 fputc('\n', out);
72 // chop off trailing newline
73 if (error == B_OK) {
74 size_t len = strlen(password);
75 if (len > 0 && password[len - 1] == '\n')
76 password[len - 1] = '\0';
79 // restore the terminal attributes
80 termAttrs.c_lflag = localFlags;
81 tcsetattr(inFD, TCSANOW, &termAttrs);
83 return error;
87 bool
88 verify_password(passwd* passwd, spwd* spwd, const char* plainPassword)
90 if (passwd == NULL)
91 return false;
93 // check whether we need to check the shadow password
94 const char* requiredPassword = passwd->pw_passwd;
95 if (strcmp(requiredPassword, "x") == 0) {
96 if (spwd == NULL) {
97 // Mmh, we're suppose to check the shadow password, but we don't
98 // have it. Bail out.
99 return false;
102 requiredPassword = spwd->sp_pwdp;
105 // If no password is required, we're done.
106 if (requiredPassword == NULL || requiredPassword[0] == '\0') {
107 if (plainPassword == NULL || plainPassword[0] == '\0')
108 return true;
110 return false;
113 // crypt and check it
114 char* encryptedPassword = crypt(plainPassword, requiredPassword);
116 return (strcmp(encryptedPassword, requiredPassword) == 0);
120 /*! Checks whether the user needs to authenticate with a password, and, if
121 necessary, asks for it, and checks it.
122 \a passwd must always be given, \a spwd only if there exists an entry
123 for the user.
125 status_t
126 authenticate_user(const char* prompt, passwd* passwd, spwd* spwd, int maxTries,
127 bool useStdio)
129 // check whether a password is need at all
130 if (verify_password(passwd, spwd, ""))
131 return B_OK;
133 while (true) {
134 // prompt the user for the password
135 char plainPassword[MAX_SHADOW_PWD_PASSWORD_LEN];
136 status_t error = read_password(prompt, plainPassword,
137 sizeof(plainPassword), useStdio);
138 if (error != B_OK)
139 return error;
141 // check it
142 bool ok = verify_password(passwd, spwd, plainPassword);
143 memset(plainPassword, 0, sizeof(plainPassword));
144 if (ok)
145 return B_OK;
147 fprintf(stderr, "Incorrect password.\n");
148 if (--maxTries <= 0)
149 return B_PERMISSION_DENIED;
154 status_t
155 authenticate_user(const char* prompt, const char* user, passwd** _passwd,
156 spwd** _spwd, int maxTries, bool useStdio)
158 struct passwd* passwd = getpwnam(user);
159 struct spwd* spwd = getspnam(user);
161 status_t error = authenticate_user(prompt, passwd, spwd, maxTries,
162 useStdio);
163 if (error == B_OK) {
164 if (_passwd)
165 *_passwd = passwd;
166 if (_spwd)
167 *_spwd = spwd;
170 return error;