vfs: check userland buffers before reading them.
[haiku.git] / src / bin / multiuser / login.cpp
blob37c01f08663b37eb8644fb5c8fa3c2c3ec305734
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 <unistd.h>
21 #include "multiuser_utils.h"
24 extern const char* __progname;
25 const char* kProgramName = __progname;
27 const uint32 kRetries = 3;
28 const uint32 kTimeout = 60;
31 static status_t
32 read_string(char* string, size_t bufferSize)
34 // TODO: setup timeout handler
36 // read everything until the next carriage return
37 char c;
38 while ((c = fgetc(stdin)) != EOF && c != '\r' && c != '\n') {
39 if (bufferSize > 1) {
40 string[0] = c;
41 string++;
42 bufferSize--;
46 if (ferror(stdin) != 0)
47 return ferror(stdin);
49 string[0] = '\0';
50 return B_OK;
54 static status_t
55 login(const char* user, struct passwd** _passwd)
57 char userBuffer[64];
59 if (user == NULL) {
60 char host[64];
61 if (gethostname(host, sizeof(host)) != 0)
62 host[0] = '\0';
64 if (host[0])
65 printf("%s ", host);
66 printf("login: ");
67 fflush(stdout);
69 status_t status = read_string(userBuffer, sizeof(userBuffer));
70 if (status < B_OK)
71 return status;
73 putchar('\n');
74 user = userBuffer;
77 // if no user is given, we exit immediately
78 if (!user[0])
79 exit(1);
81 char password[64];
82 status_t status = read_password("password: ", password, sizeof(password),
83 false);
85 putchar('\n');
87 if (status < B_OK)
88 return status;
90 struct passwd* passwd = getpwnam(user);
91 struct spwd* spwd = getspnam(user);
93 bool ok = verify_password(passwd, spwd, password);
94 memset(password, 0, sizeof(password));
96 if (!ok)
97 return B_PERMISSION_DENIED;
99 *_passwd = passwd;
100 return B_OK;
104 static const char*
105 get_from(const char* host)
107 if (host == NULL)
108 return "";
110 static char buffer[64];
111 snprintf(buffer, sizeof(buffer), " from %s", host);
112 return buffer;
116 static void
117 usage()
119 fprintf(stderr, "usage: %s [-fp] [-h hostname] [username]\n", kProgramName);
120 exit(1);
125 main(int argc, char *argv[])
127 bool noAuthentification = false;
128 bool preserveEnvironment = false;
129 const char* fromHost = NULL;
131 char c;
132 while ((c = getopt(argc, argv, "fh:p")) != -1) {
133 switch (c) {
134 case 'f':
135 noAuthentification = true;
136 break;
137 case 'h':
138 if (geteuid() != 0) {
139 fprintf(stderr, "%s: %s\n", kProgramName,
140 strerror(B_NOT_ALLOWED));
141 exit(1);
144 fromHost = optarg;
145 break;
146 case 'p':
147 preserveEnvironment = true;
148 break;
150 default:
151 usage();
152 break;
156 argc -= optind;
157 argv += optind;
159 const char* user = NULL;
160 if (argc > 0)
161 user = argv[0];
163 // login
165 alarm(kTimeout);
166 openlog(kProgramName, 0, LOG_AUTH);
168 uint32 retries = kRetries;
169 status_t status = B_ERROR;
170 struct passwd* passwd = NULL;
172 while (retries > 0) {
173 status = login(user, &passwd);
174 if (status == B_OK)
175 break;
177 sleep(3);
178 fprintf(stderr, "Login failed.\n");
179 retries--;
181 user = NULL;
182 // ask for the user name as well after the first failure
185 alarm(0);
187 if (status < B_OK || passwd == NULL) {
188 // login failure
189 syslog(LOG_NOTICE, "login%s failed for \"%s\"", get_from(fromHost),
190 passwd->pw_name);
191 exit(1);
194 // setup environment for the user
196 status = setup_environment(passwd, preserveEnvironment);
197 if (status < B_OK) {
198 // refused login
199 fprintf(stderr, "%s: Refused login. Setting up environment failed: %s\n",
200 kProgramName, strerror(status));
201 syslog(LOG_NOTICE, "login%s refused for \"%s\"", get_from(fromHost),
202 passwd->pw_name);
203 exit(1);
206 syslog(LOG_INFO, "login%s as \"%s\"", get_from(fromHost), passwd->pw_name);
208 // start login shell
210 const char* args[] = {getenv("SHELL"), "-login", NULL};
211 execv(args[0], (char **)args);
213 // try default shell
214 args[0] = "/bin/sh";
215 execv(args[0], (char **)args);
217 fprintf(stderr, "%s: starting the shell failed: %s", kProgramName,
218 strerror(errno));
220 return 1;