1 /* vi: set sw=4 ts=4: */
11 #include <sys/resource.h>
13 #include <sys/types.h>
19 #include <selinux/selinux.h> /* for is_selinux_enabled() */
20 #include <selinux/get_context_list.h> /* for get_default_context() */
21 #include <selinux/flask.h> /* for security class definitions */
25 #ifdef CONFIG_FEATURE_UTMP
27 static void checkutmp(int picky);
28 static void setutmp(const char *name, const char *line);
29 /* Stuff global to this file */
30 static struct utmp utent;
35 #define EMPTY_USERNAME_COUNT 10
36 #define USERNAME_SIZE 32
39 static int check_nologin ( int amroot );
41 #if defined CONFIG_FEATURE_SECURETTY
42 static int check_tty ( const char *tty );
45 static inline int check_tty ( const char *tty ) { return 1; }
49 static int is_my_tty ( const char *tty );
50 static int login_prompt ( char *buf_name );
51 static void motd ( void );
54 static void alarm_handler ( int sig ATTRIBUTE_UNUSED)
56 fprintf (stderr, "\nLogin timed out after %d seconds.\n", TIMEOUT );
57 exit ( EXIT_SUCCESS );
61 int login_main(int argc, char **argv)
66 char username[USERNAME_SIZE];
72 struct passwd *pw, pw_copy;
73 #ifdef CONFIG_WHEEL_GROUP
81 security_context_t user_sid = NULL;
85 amroot = ( getuid ( ) == 0 );
86 signal ( SIGALRM, alarm_handler );
90 while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) {
97 * username must be a separate token
98 * (-f root, *NOT* -froot). --marekm
100 if ( optarg != argv[optind-1] )
103 if ( !amroot ) /* Auth bypass only if real UID is zero */
104 bb_error_msg_and_die ( "-f permission denied" );
106 safe_strncpy(username, optarg, USERNAME_SIZE);
117 if (optind < argc) // user from command line (getty)
118 safe_strncpy(username, argv[optind], USERNAME_SIZE);
120 if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 ))
121 return EXIT_FAILURE; /* Must be a terminal */
123 #ifdef CONFIG_FEATURE_UTMP
124 checkutmp ( !amroot );
128 if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 ))
129 safe_strncpy ( tty, tmp + 5, sizeof( tty ));
130 else if ( tmp && *tmp == '/' )
131 safe_strncpy ( tty, tmp, sizeof( tty ));
133 safe_strncpy ( tty, "UNKNOWN", sizeof( tty ));
135 #ifdef CONFIG_FEATURE_UTMP
137 memset ( utent.ut_host, 0, sizeof utent.ut_host );
141 #ifdef CONFIG_FEATURE_UTMP
142 safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host ));
144 snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host );
147 snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty );
151 openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH );
157 if(!login_prompt ( username ))
160 if ( !alarmstarted && ( TIMEOUT > 0 )) {
165 if (!( pw = getpwnam ( username ))) {
166 pw_copy.pw_name = "UNKNOWN";
167 pw_copy.pw_passwd = "!";
175 if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' ))
183 if (!failed && ( pw-> pw_uid == 0 ) && ( !check_tty ( tty )))
186 /* Don't check the password if password entry is empty (!) */
187 if ( !pw-> pw_passwd[0] )
190 /* authorization takes place here */
191 if ( correct_password ( pw ))
200 bb_do_delay(FAIL_DELAY);
201 puts("Login incorrect");
203 if ( ++count == 3 ) {
204 syslog ( LOG_WARNING, "invalid password for `%s'%s\n", pw->pw_name, fromhost);
210 if ( check_nologin ( pw-> pw_uid == 0 ))
213 #ifdef CONFIG_FEATURE_UTMP
214 setutmp ( username, tty );
218 snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty);
220 safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 );
222 #ifdef CONFIG_SELINUX
223 if (is_selinux_enabled())
225 security_context_t old_tty_sid, new_tty_sid;
227 if (get_default_context(username, NULL, &user_sid))
229 fprintf(stderr, "Unable to get SID for %s\n", username);
232 if (getfilecon(full_tty, &old_tty_sid) < 0)
234 fprintf(stderr, "getfilecon(%.100s) failed: %.100s\n", full_tty, strerror(errno));
237 if (security_compute_relabel(user_sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0)
239 fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno));
242 if(setfilecon(full_tty, new_tty_sid) != 0)
244 fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno));
249 if ( !is_my_tty ( full_tty ))
250 syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty );
252 /* Try these, but don't complain if they fail
253 * (for example when the root fs is read only) */
254 chown ( full_tty, pw-> pw_uid, pw-> pw_gid );
255 chmod ( full_tty, 0600 );
257 change_identity ( pw );
261 setup_environment ( tmp, 1, !opt_preserve, pw );
264 signal ( SIGALRM, SIG_DFL ); /* default alarm signal */
266 if ( pw-> pw_uid == 0 )
267 syslog ( LOG_INFO, "root login %s\n", fromhost );
268 #ifdef CONFIG_SELINUX
269 /* well, a simple setexeccon() here would do the job as well,
270 * but let's play the game for now */
271 set_current_security_context(user_sid);
273 run_shell ( tmp, 1, 0, 0); /* exec the shell finally. */
280 static int login_prompt ( char *buf_name )
286 for(i=0; i<EMPTY_USERNAME_COUNT; i++) {
287 print_login_prompt();
289 if ( !fgets ( buf, sizeof( buf ) - 1, stdin ))
292 if ( !strchr ( buf, '\n' ))
295 for ( sp = buf; isspace ( *sp ); sp++ ) { }
296 for ( ep = sp; isgraph ( *ep ); ep++ ) { }
299 safe_strncpy(buf_name, sp, USERNAME_SIZE);
307 static int check_nologin ( int amroot )
309 if ( access ( bb_path_nologin_file, F_OK ) == 0 ) {
313 if (( fp = fopen ( bb_path_nologin_file, "r" ))) {
314 while (( c = getc ( fp )) != EOF )
315 putchar (( c == '\n' ) ? '\r' : c );
320 puts ( "\r\nSystem closed for routine maintenance.\r" );
325 puts ( "\r\n[Disconnect bypassed -- root login allowed.]\r" );
330 #ifdef CONFIG_FEATURE_SECURETTY
332 static int check_tty ( const char *tty )
338 if (( fp = fopen ( bb_path_securetty_file, "r" ))) {
339 while ( fgets ( buf, sizeof( buf ) - 1, fp )) {
340 for ( i = strlen( buf ) - 1; i >= 0; --i ) {
341 if ( !isspace ( buf[i] ))
345 if (( buf [0] == '\0' ) || ( buf [0] == '#' ))
348 if ( strcmp ( buf, tty ) == 0 ) {
356 /* A missing securetty file is not an error. */
362 /* returns 1 if true */
363 static int is_my_tty ( const char *tty )
365 struct stat by_name, by_fd;
367 if ( stat ( tty, &by_name ) || fstat ( 0, &by_fd ))
370 if ( by_name. st_rdev != by_fd. st_rdev )
377 static void motd (void)
382 if (( fp = fopen ( bb_path_motd_file, "r" ))) {
383 while (( c = getc ( fp )) != EOF )
390 #ifdef CONFIG_FEATURE_UTMP
391 // vv Taken from tinylogin utmp.c vv
394 "No utmp entry. You must exec \"login\" from the lowest level \"sh\""
396 "Unable to determine your tty name."
399 * checkutmp - see if utmp file is correct for this process
401 * System V is very picky about the contents of the utmp file
402 * and requires that a slot for the current process exist.
403 * The utmp file is scanned for an entry with the same process
404 * ID. If no entry exists the process exits with a message.
406 * The "picky" flag is for network and other logins that may
407 * use special flags. It allows the pid checks to be overridden.
408 * This means that getty should never invoke login with any
409 * command line flags.
412 static void checkutmp(int picky)
416 pid_t pid = getpid();
420 /* First, try to find a valid utmp entry for this process. */
421 while ((ut = getutent()))
422 if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
423 (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
426 /* If there is one, just use it, otherwise create a new one. */
441 if (strncmp(line, "/dev/", 5) == 0)
443 memset((void *) &utent, 0, sizeof utent);
444 utent.ut_type = LOGIN_PROCESS;
446 strncpy(utent.ut_line, line, sizeof utent.ut_line);
447 /* XXX - assumes /dev/tty?? */
448 strncpy(utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
449 strncpy(utent.ut_user, "LOGIN", sizeof utent.ut_user);
450 t_tmp = (time_t)utent.ut_time;
456 * setutmp - put a USER_PROCESS entry in the utmp file
458 * setutmp changes the type of the current utmp entry to
459 * USER_PROCESS. the wtmp file will be updated as well.
462 static void setutmp(const char *name, const char *line ATTRIBUTE_UNUSED)
464 time_t t_tmp = (time_t)utent.ut_time;
466 utent.ut_type = USER_PROCESS;
467 strncpy(utent.ut_user, name, sizeof utent.ut_user);
469 /* other fields already filled in by checkutmp above */
473 #ifdef CONFIG_FEATURE_WTMP
474 if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
475 close(creat(bb_path_wtmp_file, 0664));
477 updwtmp(bb_path_wtmp_file, &utent);
480 #endif /* CONFIG_FEATURE_UTMP */