1/* 2 * Copyright 2007, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel D��rfler, axeld@pinc-software.de 7 */ 8 9 10#include <SupportDefs.h> 11 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> 20 21#include "multiuser_utils.h" 22 23 24extern const char* __progname; 25const char* kProgramName = __progname; 26 27const uint32 kRetries = 3; 28const uint32 kTimeout = 60; 29 30 31static status_t 32read_string(char* string, size_t bufferSize) 33{ 34 // TODO: setup timeout handler 35 36 // read everything until the next carriage return 37 int c; 38 while ((c = fgetc(stdin)) != EOF && c != '\r' && c != '\n') { 39 if (bufferSize > 1) { 40 string[0] = c; 41 string++; 42 bufferSize--; 43 } 44 } 45 46 if (ferror(stdin) != 0) 47 return ferror(stdin); 48 49 string[0] = '\0'; 50 return B_OK; 51} 52 53 54static status_t 55login(const char* user, struct passwd** _passwd) 56{ 57 char userBuffer[64]; 58 59 if (user == NULL) { 60 char host[64]; 61 if (gethostname(host, sizeof(host)) != 0) 62 host[0] = '\0'; 63 64 if (host[0]) 65 printf("%s ", host); 66 printf("login: "); 67 fflush(stdout); 68 69 status_t status = read_string(userBuffer, sizeof(userBuffer)); 70 if (status < B_OK) 71 return status; 72 73 putchar('\n'); 74 user = userBuffer; 75 } 76 77 // if no user is given, we exit immediately 78 if (!user[0]) 79 exit(1); 80 81 char password[64]; 82 status_t status = read_password("password: ", password, sizeof(password), 83 false); 84 85 putchar('\n'); 86 87 if (status < B_OK) 88 return status; 89 90 struct passwd* passwd = getpwnam(user); 91 struct spwd* spwd = getspnam(user); 92 93 bool ok = verify_password(passwd, spwd, password); 94 explicit_bzero(password, sizeof(password)); 95 96 if (!ok) 97 return B_PERMISSION_DENIED; 98 99 *_passwd = passwd; 100 return B_OK; 101} 102 103 104static const char* 105get_from(const char* host) 106{ 107 if (host == NULL) 108 return ""; 109 110 static char buffer[64]; 111 snprintf(buffer, sizeof(buffer), " from %s", host); 112 return buffer; 113} 114 115 116static void 117usage() 118{ 119 fprintf(stderr, "usage: %s [-fp] [-h hostname] [username]\n", kProgramName); 120 exit(1); 121} 122 123 124int 125main(int argc, char *argv[]) 126{ 127 bool noAuthentification = false; 128 bool preserveEnvironment = false; 129 const char* fromHost = NULL; 130 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); 142 } 143 144 fromHost = optarg; 145 break; 146 case 'p': 147 preserveEnvironment = true; 148 break; 149 150 default: 151 usage(); 152 break; 153 } 154 } 155 156 argc -= optind; 157 argv += optind; 158 159 const char* user = NULL; 160 if (argc > 0) 161 user = argv[0]; 162 163 // login 164 165 alarm(kTimeout); 166 openlog(kProgramName, 0, LOG_AUTH); 167 168 uint32 retries = kRetries; 169 status_t status = B_ERROR; 170 struct passwd* passwd = NULL; 171 172 while (retries > 0) { 173 status = login(user, &passwd); 174 if (status == B_OK) 175 break; 176 177 sleep(3); 178 fprintf(stderr, "Login failed.\n"); 179 retries--; 180 181 user = NULL; 182 // ask for the user name as well after the first failure 183 } 184 185 alarm(0); 186 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); 192 } 193 194 // setup environment for the user 195 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); 204 } 205 206 syslog(LOG_INFO, "login%s as \"%s\"", get_from(fromHost), passwd->pw_name); 207 208 // start login shell 209 210 const char* args[] = {getenv("SHELL"), "-login", NULL}; 211 execv(args[0], (char **)args); 212 213 // try default shell 214 args[0] = "/bin/sh"; 215 execv(args[0], (char **)args); 216 217 fprintf(stderr, "%s: starting the shell failed: %s", kProgramName, 218 strerror(errno)); 219 220 return 1; 221} 222 223