* Implemented a basic "login" command - does not yet support real passwords (it currently

does a plain string comparison with whatever passwd::pw_passwd contains.
* Removed left-over tcptester directory.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21548 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-07-04 16:33:57 +00:00
parent 80b2c30e4f
commit 4e6971bb54
3 changed files with 290 additions and 0 deletions

View File

@ -3,6 +3,7 @@ SubDir HAIKU_TOP src bin network ;
SubInclude HAIKU_TOP src bin network arp ;
SubInclude HAIKU_TOP src bin network ftp ;
SubInclude HAIKU_TOP src bin network ifconfig ;
SubInclude HAIKU_TOP src bin network login ;
SubInclude HAIKU_TOP src bin network mount_nfs ;
SubInclude HAIKU_TOP src bin network nc ;
SubInclude HAIKU_TOP src bin network netstat ;

View File

@ -0,0 +1,5 @@
SubDir HAIKU_TOP src bin network login ;
BinCommand login :
login.cpp
;

View File

@ -0,0 +1,284 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#include <SupportDefs.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <termios.h>
#include <unistd.h>
extern const char* __progname;
const char* kProgramName = __progname;
const uint32 kRetries = 3;
const uint32 kTimeout = 60;
static status_t
set_tty_echo(bool enabled)
{
struct termios termios;
if (ioctl(STDIN_FILENO, TCGETA, &termios) != 0)
return errno;
// do we have to change the current setting at all?
if (enabled == (termios.c_lflag & ECHO) != 0)
return B_OK;
if (enabled)
termios.c_lflag |= ECHO;
else
termios.c_lflag &= ~ECHO;
if (ioctl(STDIN_FILENO, TCSETA, &termios) != 0)
return errno;
return B_OK;
}
static status_t
read_string(char* string, size_t bufferSize)
{
// TODO: setup timeout handler
// read everything until the next carriage return
char 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);
set_tty_echo(true);
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);
printf("password: ");
fflush(stdout);
set_tty_echo(false);
char password[64];
status_t status = read_string(password, sizeof(password));
set_tty_echo(true);
putchar('\n');
if (status < B_OK)
return status;
struct passwd* passwd = getpwnam(user);
if (passwd == NULL || passwd->pw_passwd == NULL)
return B_ERROR;
// TODO: do a real password check!
if (strcmp(password, passwd->pw_passwd))
return B_PERMISSION_DENIED;
*_passwd = passwd;
return B_OK;
}
static status_t
setup_environment(struct passwd* passwd, bool preserveEnvironment)
{
const char* term = getenv("TERM");
if (!preserveEnvironment) {
static char *empty[1];
environ = empty;
}
// always preserve $TERM
if (term != NULL)
setenv("TERM", term, false);
if (passwd->pw_shell)
setenv("SHELL", passwd->pw_shell, true);
if (passwd->pw_dir)
setenv("HOME", passwd->pw_dir, true);
setenv("USER", passwd->pw_name, true);
pid_t pid = getpid();
if (ioctl(STDIN_FILENO, TIOCSPGRP, &pid) != 0)
return errno;
const char* home = getenv("HOME");
if (home == NULL)
return B_ENTRY_NOT_FOUND;
if (chdir(home) != 0)
return errno;
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;
fprintf(stderr, "Login failed.\n");
sleep(1);
user = NULL;
// ask for the user name as well after the first failure
}
alarm(0);
if (status < B_OK) {
// 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;
}