/* * Copyright 2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Axel Dörfler, axeld@pinc-software.de */ #include #include #include #include #include #include #include #include #include #include "multiuser_utils.h" extern const char* __progname; const char* kProgramName = __progname; const uint32 kRetries = 3; const uint32 kTimeout = 60; static status_t read_string(char* string, size_t bufferSize) { // TODO: setup timeout handler // read everything until the next carriage return int c; while ((c = fgetc(stdin)) != EOF && c != '\r' && c != '\n') { if (bufferSize > 1) { string[0] = c; string++; bufferSize--; } } if (ferror(stdin) != 0) return ferror(stdin); string[0] = '\0'; return B_OK; } static status_t login(const char* user, struct passwd** _passwd) { char userBuffer[64]; if (user == NULL) { char host[64]; if (gethostname(host, sizeof(host)) != 0) host[0] = '\0'; if (host[0]) printf("%s ", host); printf("login: "); fflush(stdout); status_t status = read_string(userBuffer, sizeof(userBuffer)); if (status < B_OK) return status; putchar('\n'); user = userBuffer; } // if no user is given, we exit immediately if (!user[0]) exit(1); char password[64]; status_t status = read_password("password: ", password, sizeof(password), false); putchar('\n'); if (status < B_OK) return status; struct passwd* passwd = getpwnam(user); struct spwd* spwd = getspnam(user); bool ok = verify_password(passwd, spwd, password); explicit_bzero(password, sizeof(password)); if (!ok) return B_PERMISSION_DENIED; *_passwd = passwd; return B_OK; } static const char* get_from(const char* host) { if (host == NULL) return ""; static char buffer[64]; snprintf(buffer, sizeof(buffer), " from %s", host); return buffer; } static void usage() { fprintf(stderr, "usage: %s [-fp] [-h hostname] [username]\n", kProgramName); exit(1); } int main(int argc, char *argv[]) { bool noAuthentification = false; bool preserveEnvironment = false; const char* fromHost = NULL; char c; while ((c = getopt(argc, argv, "fh:p")) != -1) { switch (c) { case 'f': noAuthentification = true; break; case 'h': if (geteuid() != 0) { fprintf(stderr, "%s: %s\n", kProgramName, strerror(B_NOT_ALLOWED)); exit(1); } fromHost = optarg; break; case 'p': preserveEnvironment = true; break; default: usage(); break; } } argc -= optind; argv += optind; const char* user = NULL; if (argc > 0) user = argv[0]; // login alarm(kTimeout); openlog(kProgramName, 0, LOG_AUTH); uint32 retries = kRetries; status_t status = B_ERROR; struct passwd* passwd = NULL; while (retries > 0) { status = login(user, &passwd); if (status == B_OK) break; sleep(3); fprintf(stderr, "Login failed.\n"); retries--; user = NULL; // ask for the user name as well after the first failure } alarm(0); if (status < B_OK || passwd == NULL) { // login failure syslog(LOG_NOTICE, "login%s failed for \"%s\"", get_from(fromHost), passwd->pw_name); exit(1); } // setup environment for the user status = setup_environment(passwd, preserveEnvironment); if (status < B_OK) { // refused login fprintf(stderr, "%s: Refused login. Setting up environment failed: %s\n", kProgramName, strerror(status)); syslog(LOG_NOTICE, "login%s refused for \"%s\"", get_from(fromHost), passwd->pw_name); exit(1); } syslog(LOG_INFO, "login%s as \"%s\"", get_from(fromHost), passwd->pw_name); // start login shell const char* args[] = {getenv("SHELL"), "-login", NULL}; execv(args[0], (char **)args); // try default shell args[0] = "/bin/sh"; execv(args[0], (char **)args); fprintf(stderr, "%s: starting the shell failed: %s", kProgramName, strerror(errno)); return 1; }