2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 #include "multiuser_utils.h"
15 #include <AutoDeleter.h>
17 #include <user_group.h>
21 read_password(const char* prompt
, char* password
, size_t bufferSize
,
30 // TODO: Open tty with O_NOCTTY!
31 tty
= fopen("/dev/tty", "w+");
33 fprintf(stderr
, "Error: Failed to open tty: %s\n", strerror(errno
));
40 CObjectDeleter
<FILE, int> ttyCloser(tty
, fclose
);
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",
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",
60 status_t error
= B_OK
;
62 // prompt and read pwd
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
;
72 // chop off trailing newline
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
);
88 verify_password(passwd
* passwd
, spwd
* spwd
, const char* plainPassword
)
93 // check whether we need to check the shadow password
94 const char* requiredPassword
= passwd
->pw_passwd
;
95 if (strcmp(requiredPassword
, "x") == 0) {
97 // Mmh, we're suppose to check the shadow password, but we don't
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')
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
126 authenticate_user(const char* prompt
, passwd
* passwd
, spwd
* spwd
, int maxTries
,
129 // check whether a password is need at all
130 if (verify_password(passwd
, spwd
, ""))
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
);
142 bool ok
= verify_password(passwd
, spwd
, plainPassword
);
143 memset(plainPassword
, 0, sizeof(plainPassword
));
147 fprintf(stderr
, "Incorrect password.\n");
149 return B_PERMISSION_DENIED
;
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
,
175 setup_environment(struct passwd
* passwd
, bool preserveEnvironment
, bool chngdir
)
177 const char* term
= getenv("TERM");
178 if (!preserveEnvironment
) {
179 static char *empty
[1];
183 // always preserve $TERM
185 setenv("TERM", term
, false);
186 if (passwd
->pw_shell
)
187 setenv("SHELL", passwd
->pw_shell
, true);
189 setenv("HOME", passwd
->pw_dir
, true);
191 setenv("USER", passwd
->pw_name
, true);
193 pid_t pid
= getpid();
194 if (ioctl(STDIN_FILENO
, TIOCSPGRP
, &pid
) != 0)
197 if (passwd
->pw_gid
&& setgid(passwd
->pw_gid
) != 0)
200 if (passwd
->pw_uid
&& setuid(passwd
->pw_uid
) != 0)
204 const char* home
= getenv("HOME");
206 return B_ENTRY_NOT_FOUND
;
208 if (chdir(home
) != 0)