tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / bin / multiuser / login.cpp
blobd4dfba5181a66ab3546be88e1eda7a9a1d57f503
1 /*
2 * Copyright 2007, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 */
10 #include <SupportDefs.h>
12 #include <errno.h>
13 #include <pwd.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <syslog.h>
19 #include <termios.h>
20 #include <unistd.h>
22 #include "multiuser_utils.h"
25 extern const char* __progname;
26 const char* kProgramName = __progname;
28 const uint32 kRetries = 3;
29 const uint32 kTimeout = 60;
32 static status_t
33 set_tty_echo(bool enabled)
35 struct termios termios;
37 if (ioctl(STDIN_FILENO, TCGETA, &termios) != 0)
38 return errno;
40 // do we have to change the current setting at all?
41 if (enabled == ((termios.c_lflag & ECHO) != 0))
42 return B_OK;
44 if (enabled)
45 termios.c_lflag |= ECHO;
46 else
47 termios.c_lflag &= ~ECHO;
49 if (ioctl(STDIN_FILENO, TCSETA, &termios) != 0)
50 return errno;
52 return B_OK;
56 static status_t
57 read_string(char* string, size_t bufferSize)
59 // TODO: setup timeout handler
61 // read everything until the next carriage return
62 char c;
63 while ((c = fgetc(stdin)) != EOF && c != '\r' && c != '\n') {
64 if (bufferSize > 1) {
65 string[0] = c;
66 string++;
67 bufferSize--;
71 if (ferror(stdin) != 0)
72 return ferror(stdin);
74 string[0] = '\0';
75 return B_OK;
79 static status_t
80 login(const char* user, struct passwd** _passwd)
82 char userBuffer[64];
84 if (user == NULL) {
85 char host[64];
86 if (gethostname(host, sizeof(host)) != 0)
87 host[0] = '\0';
89 if (host[0])
90 printf("%s ", host);
91 printf("login: ");
92 fflush(stdout);
94 set_tty_echo(true);
96 status_t status = read_string(userBuffer, sizeof(userBuffer));
97 if (status < B_OK)
98 return status;
100 putchar('\n');
101 user = userBuffer;
104 // if no user is given, we exit immediately
105 if (!user[0])
106 exit(1);
108 printf("password: ");
109 fflush(stdout);
111 set_tty_echo(false);
113 char password[64];
114 status_t status = read_string(password, sizeof(password));
116 set_tty_echo(true);
117 putchar('\n');
119 if (status < B_OK)
120 return status;
122 struct passwd* passwd = getpwnam(user);
123 struct spwd* spwd = getspnam(user);
125 bool ok = verify_password(passwd, spwd, password);
126 memset(password, 0, sizeof(password));
128 if (!ok)
129 return B_PERMISSION_DENIED;
131 *_passwd = passwd;
132 return B_OK;
136 static status_t
137 setup_environment(struct passwd* passwd, bool preserveEnvironment)
139 const char* term = getenv("TERM");
140 if (!preserveEnvironment) {
141 static char *empty[1];
142 environ = empty;
145 // always preserve $TERM
146 if (term != NULL)
147 setenv("TERM", term, false);
148 if (passwd->pw_shell)
149 setenv("SHELL", passwd->pw_shell, true);
150 if (passwd->pw_dir)
151 setenv("HOME", passwd->pw_dir, true);
153 setenv("USER", passwd->pw_name, true);
155 pid_t pid = getpid();
156 if (ioctl(STDIN_FILENO, TIOCSPGRP, &pid) != 0)
157 return errno;
159 const char* home = getenv("HOME");
160 if (home == NULL)
161 return B_ENTRY_NOT_FOUND;
163 if (chdir(home) != 0)
164 return errno;
166 return B_OK;
170 static const char*
171 get_from(const char* host)
173 if (host == NULL)
174 return "";
176 static char buffer[64];
177 snprintf(buffer, sizeof(buffer), " from %s", host);
178 return buffer;
182 static void
183 usage()
185 fprintf(stderr, "usage: %s [-fp] [-h hostname] [username]\n", kProgramName);
186 exit(1);
191 main(int argc, char *argv[])
193 bool noAuthentification = false;
194 bool preserveEnvironment = false;
195 const char* fromHost = NULL;
197 char c;
198 while ((c = getopt(argc, argv, "fh:p")) != -1) {
199 switch (c) {
200 case 'f':
201 noAuthentification = true;
202 break;
203 case 'h':
204 if (geteuid() != 0) {
205 fprintf(stderr, "%s: %s\n", kProgramName,
206 strerror(B_NOT_ALLOWED));
207 exit(1);
210 fromHost = optarg;
211 break;
212 case 'p':
213 preserveEnvironment = true;
214 break;
216 default:
217 usage();
218 break;
222 argc -= optind;
223 argv += optind;
225 const char* user = NULL;
226 if (argc > 0)
227 user = argv[0];
229 // login
231 alarm(kTimeout);
232 openlog(kProgramName, 0, LOG_AUTH);
234 uint32 retries = kRetries;
235 status_t status = B_ERROR;
236 struct passwd* passwd = NULL;
238 while (retries > 0) {
239 status = login(user, &passwd);
240 if (status == B_OK)
241 break;
243 fprintf(stderr, "Login failed.\n");
244 sleep(1);
246 user = NULL;
247 // ask for the user name as well after the first failure
250 alarm(0);
252 if (status < B_OK) {
253 // login failure
254 syslog(LOG_NOTICE, "login%s failed for \"%s\"", get_from(fromHost),
255 passwd->pw_name);
256 exit(1);
259 // setup environment for the user
261 status = setup_environment(passwd, preserveEnvironment);
262 if (status < B_OK) {
263 // refused login
264 fprintf(stderr, "%s: Refused login. Setting up environment failed: %s\n",
265 kProgramName, strerror(status));
266 syslog(LOG_NOTICE, "login%s refused for \"%s\"", get_from(fromHost),
267 passwd->pw_name);
268 exit(1);
271 syslog(LOG_INFO, "login%s as \"%s\"", get_from(fromHost), passwd->pw_name);
273 // start login shell
275 const char* args[] = {getenv("SHELL"), "-login", NULL};
276 execv(args[0], (char **)args);
278 // try default shell
279 args[0] = "/bin/sh";
280 execv(args[0], (char **)args);
282 fprintf(stderr, "%s: starting the shell failed: %s", kProgramName,
283 strerror(errno));
285 return 1;