#include <time.h>
#include "busybox.h"
+#ifdef CONFIG_SELINUX
+#include <selinux/selinux.h> /* for is_selinux_enabled() */
+#include <selinux/get_context_list.h> /* for get_default_context() */
+#include <selinux/flask.h> /* for security class definitions */
+#include <errno.h>
+#endif
-
-#ifdef CONFIG_FEATURE_U_W_TMP
+#ifdef CONFIG_FEATURE_UTMP
// import from utmp.c
static void checkutmp(int picky);
static void setutmp(const char *name, const char *line);
+/* Stuff global to this file */
+static struct utmp utent;
#endif
-// import from encrypt.c
-extern char *pw_encrypt(const char *clear, const char *salt);
-
-
// login defines
#define TIMEOUT 60
#define EMPTY_USERNAME_COUNT 10
#define USERNAME_SIZE 32
-/* Stuff global to this file */
-struct utmp utent;
-
static int check_nologin ( int amroot );
static void motd ( void );
-static void alarm_handler ( int sig )
+static void alarm_handler ( int sig ATTRIBUTE_UNUSED)
{
fprintf (stderr, "\nLogin timed out after %d seconds.\n", TIMEOUT );
exit ( EXIT_SUCCESS );
}
-extern int login_main(int argc, char **argv)
+int login_main(int argc, char **argv)
{
char tty[BUFSIZ];
char full_tty[200];
char fromhost[512];
char username[USERNAME_SIZE];
- char *tmp;
+ const char *tmp;
int amroot;
int flag;
int failed;
int opt_preserve = 0;
int opt_fflag = 0;
char *opt_host = 0;
- int alarmstarted = 0;
+ int alarmstarted = 0;
+#ifdef CONFIG_SELINUX
+ security_context_t user_sid = NULL;
+#endif
username[0]=0;
amroot = ( getuid ( ) == 0 );
signal ( SIGALRM, alarm_handler );
-
- if (( argc > 1 ) && ( TIMEOUT > 0 )) {
- alarm ( TIMEOUT );
- alarmstarted = 1;
- }
+ alarm ( TIMEOUT );
+ alarmstarted = 1;
while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) {
switch ( flag ) {
break;
case 'f':
/*
- * username must be a seperate token
+ * username must be a separate token
* (-f root, *NOT* -froot). --marekm
*/
if ( optarg != argv[optind-1] )
- show_usage ( );
+ bb_show_usage( );
+
+ if ( !amroot ) /* Auth bypass only if real UID is zero */
+ bb_error_msg_and_die ( "-f permission denied" );
- if ( !amroot ) /* Auth bypass only if real UID is zero */
- error_msg_and_die ( "-f permission denied" );
-
safe_strncpy(username, optarg, USERNAME_SIZE);
opt_fflag = 1;
break;
opt_host = optarg;
break;
default:
- show_usage ( );
+ bb_show_usage( );
}
}
if (optind < argc) // user from command line (getty)
safe_strncpy(username, argv[optind], USERNAME_SIZE);
- if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 ))
+ if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 ))
return EXIT_FAILURE; /* Must be a terminal */
-#ifdef CONFIG_FEATURE_U_W_TMP
+#ifdef CONFIG_FEATURE_UTMP
checkutmp ( !amroot );
#endif
tmp = ttyname ( 0 );
if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 ))
safe_strncpy ( tty, tmp + 5, sizeof( tty ));
+ else if ( tmp && *tmp == '/' )
+ safe_strncpy ( tty, tmp, sizeof( tty ));
else
safe_strncpy ( tty, "UNKNOWN", sizeof( tty ));
+#ifdef CONFIG_FEATURE_UTMP
if ( amroot )
memset ( utent.ut_host, 0, sizeof utent.ut_host );
-
+#endif
+
if ( opt_host ) {
+#ifdef CONFIG_FEATURE_UTMP
safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host ));
-
+#endif
snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host );
}
else
snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty );
-
+
setpgrp();
openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH );
pw_copy.pw_passwd = "!";
opt_fflag = 0;
failed = 1;
- } else
+ } else
pw_copy = *pw;
pw = &pw_copy;
if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' ))
failed = 1;
-
+
if ( opt_fflag ) {
opt_fflag = 0;
goto auth_ok;
goto auth_ok;
failed = 1;
-
+
auth_ok:
- if ( !failed)
+ if ( !failed)
break;
- { // delay next try
- time_t start, now;
-
- time ( &start );
- now = start;
- while ( difftime ( now, start ) < FAIL_DELAY) {
- sleep ( FAIL_DELAY );
- time ( &now );
- }
- }
-
+ bb_do_delay(FAIL_DELAY);
puts("Login incorrect");
username[0] = 0;
if ( ++count == 3 ) {
return EXIT_FAILURE;
}
}
-
+
alarm ( 0 );
if ( check_nologin ( pw-> pw_uid == 0 ))
return EXIT_FAILURE;
-#ifdef CONFIG_FEATURE_U_W_TMP
+#ifdef CONFIG_FEATURE_UTMP
setutmp ( username, tty );
#endif
- if ( *tty != '/' )
+
+ if ( *tty != '/' )
snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty);
else
safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 );
-
- if ( !is_my_tty ( full_tty ))
+
+#ifdef CONFIG_SELINUX
+ if (is_selinux_enabled())
+ {
+ security_context_t old_tty_sid, new_tty_sid;
+
+ if (get_default_context(username, NULL, &user_sid))
+ {
+ fprintf(stderr, "Unable to get SID for %s\n", username);
+ exit(1);
+ }
+ if (getfilecon(full_tty, &old_tty_sid) < 0)
+ {
+ fprintf(stderr, "getfilecon(%.100s) failed: %.100s\n", full_tty, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ if (security_compute_relabel(user_sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0)
+ {
+ fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ if(setfilecon(full_tty, new_tty_sid) != 0)
+ {
+ fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
+#endif
+ if ( !is_my_tty ( full_tty ))
syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty );
-
- /* Try these, but don't complain if they fail
+
+ /* Try these, but don't complain if they fail
* (for example when the root fs is read only) */
chown ( full_tty, pw-> pw_uid, pw-> pw_gid );
chmod ( full_tty, 0600 );
change_identity ( pw );
- setup_environment ( pw-> pw_shell, 1, !opt_preserve, pw );
+ tmp = pw-> pw_shell;
+ if(!tmp || !*tmp)
+ tmp = DEFAULT_SHELL;
+ setup_environment ( tmp, 1, !opt_preserve, pw );
motd ( );
signal ( SIGALRM, SIG_DFL ); /* default alarm signal */
- if ( pw-> pw_uid == 0 )
+ if ( pw-> pw_uid == 0 )
syslog ( LOG_INFO, "root login %s\n", fromhost );
-
- run_shell ( pw-> pw_shell, 1, 0, 0 ); /* exec the shell finally. */
-
+#ifdef CONFIG_SELINUX
+ /* well, a simple setexeccon() here would do the job as well,
+ * but let's play the game for now */
+ set_current_security_context(user_sid);
+#endif
+ run_shell ( tmp, 1, 0, 0); /* exec the shell finally. */
+
return EXIT_FAILURE;
}
int i;
for(i=0; i<EMPTY_USERNAME_COUNT; i++) {
- gethostname ( buf, sizeof( buf ));
- printf ( "\nBusyBox on %s login: ", buf );
- fflush ( stdout );
+ print_login_prompt();
+
+ if ( !fgets ( buf, sizeof( buf ) - 1, stdin ))
+ return 0;
- if ( !fgets ( buf, sizeof( buf ) - 1, stdin ))
- return 0;
-
if ( !strchr ( buf, '\n' ))
- return 0;
-
- for ( sp = buf; isspace ( *sp ); sp++ ) { }
- for ( ep = sp; isgraph ( *ep ); ep++ ) { }
+ return 0;
- *ep = 0;
+ for ( sp = buf; isspace ( *sp ); sp++ ) { }
+ for ( ep = sp; isgraph ( *ep ); ep++ ) { }
+
+ *ep = 0;
safe_strncpy(buf_name, sp, USERNAME_SIZE);
if(buf_name[0])
return 1;
static int check_nologin ( int amroot )
{
- if ( access ( nologin_file, F_OK ) == 0 ) {
+ if ( access ( bb_path_nologin_file, F_OK ) == 0 ) {
FILE *fp;
int c;
- if (( fp = fopen ( nologin_file, "r" ))) {
+ if (( fp = fopen ( bb_path_nologin_file, "r" ))) {
while (( c = getc ( fp )) != EOF )
putchar (( c == '\n' ) ? '\r' : c );
}
if ( !amroot )
return 1;
-
+
puts ( "\r\n[Disconnect bypassed -- root login allowed.]\r" );
}
return 0;
int i;
char buf[BUFSIZ];
- if (( fp = fopen ( securetty_file, "r" ))) {
+ if (( fp = fopen ( bb_path_securetty_file, "r" ))) {
while ( fgets ( buf, sizeof( buf ) - 1, fp )) {
- for ( i = xstrlen( buf ) - 1; i >= 0; --i ) {
+ for ( i = bb_strlen( buf ) - 1; i >= 0; --i ) {
if ( !isspace ( buf[i] ))
break;
}
fclose(fp);
return 0;
}
- else {
- syslog ( LOG_WARNING, "cannot open securetty file.\n" );
- return 1;
- }
+ /* A missing securetty file is not an error. */
+ return 1;
}
#endif
if ( stat ( tty, &by_name ) || fstat ( 0, &by_fd ))
return 0;
-
+
if ( by_name. st_rdev != by_fd. st_rdev )
return 0;
else
}
-static void motd ( )
+static void motd (void)
{
FILE *fp;
register int c;
- if (( fp = fopen ( motd_file, "r" ))) {
- while (( c = getc ( fp )) != EOF )
- putchar ( c );
+ if (( fp = fopen ( bb_path_motd_file, "r" ))) {
+ while (( c = getc ( fp )) != EOF )
+ putchar ( c );
fclose ( fp );
}
}
-#ifdef CONFIG_FEATURE_U_W_TMP
+#ifdef CONFIG_FEATURE_UTMP
// vv Taken from tinylogin utmp.c vv
-#define _WTMP_FILE "/var/log/wtmp"
-
#define NO_UTENT \
"No utmp entry. You must exec \"login\" from the lowest level \"sh\""
#define NO_TTY \
if (ut) {
utent = *ut;
} else {
+ time_t t_tmp;
+
if (picky) {
puts(NO_UTENT);
exit(1);
/* XXX - assumes /dev/tty?? */
strncpy(utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
strncpy(utent.ut_user, "LOGIN", sizeof utent.ut_user);
- time(&utent.ut_time);
+ t_tmp = (time_t)utent.ut_time;
+ time(&t_tmp);
}
}
* USER_PROCESS. the wtmp file will be updated as well.
*/
-static void setutmp(const char *name, const char *line)
+static void setutmp(const char *name, const char *line ATTRIBUTE_UNUSED)
{
+ time_t t_tmp = (time_t)utent.ut_time;
+
utent.ut_type = USER_PROCESS;
strncpy(utent.ut_user, name, sizeof utent.ut_user);
- time(&utent.ut_time);
+ time(&t_tmp);
/* other fields already filled in by checkutmp above */
setutent();
pututline(&utent);
endutent();
- updwtmp(_WTMP_FILE, &utent);
+#ifdef CONFIG_FEATURE_WTMP
+ if (access(_PATH_WTMP, R_OK|W_OK) == -1) {
+ close(creat(_PATH_WTMP, 0664));
+ }
+ updwtmp(_PATH_WTMP, &utent);
+#endif
}
-#endif /* CONFIG_FEATURE_U_W_TMP */
+#endif /* CONFIG_FEATURE_UTMP */