Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/loginutils/login.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 3  Line 3 
3   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
4   */   */
5    
6  #include "busybox.h"  #include "libbb.h"
7    #include <syslog.h>
8  #include <utmp.h>  #include <utmp.h>
9  #include <sys/resource.h>  #include <sys/resource.h>
 #include <syslog.h>  
10    
11  #ifdef CONFIG_SELINUX  #if ENABLE_SELINUX
12  #include <selinux/selinux.h>  /* for is_selinux_enabled()  */  #include <selinux/selinux.h>  /* for is_selinux_enabled()  */
13  #include <selinux/get_context_list.h> /* for get_default_context() */  #include <selinux/get_context_list.h> /* for get_default_context() */
14  #include <selinux/flask.h> /* for security class definitions  */  #include <selinux/flask.h> /* for security class definitions  */
15  #include <errno.h>  #endif
16    
17    #if ENABLE_PAM
18    /* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
19    #undef setlocale
20    /* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
21     * Apparently they like to confuse people. */
22    #include <security/pam_appl.h>
23    #include <security/pam_misc.h>
24    static const struct pam_conv conv = {
25     misc_conv,
26     NULL
27    };
28  #endif  #endif
29    
30  enum {  enum {
# Line 22  enum { Line 34  enum {
34   TTYNAME_SIZE = 32,   TTYNAME_SIZE = 32,
35  };  };
36    
37  static char full_tty[TTYNAME_SIZE];  static char* short_tty;
 static char* short_tty = full_tty;  
38    
39  #if ENABLE_FEATURE_UTMP  #if ENABLE_FEATURE_UTMP
40  /* vv  Taken from tinylogin utmp.c  vv */  /* vv  Taken from tinylogin utmp.c  vv */
# Line 41  static char* short_tty = full_tty; Line 52  static char* short_tty = full_tty;
52   * command line flags.   * command line flags.
53   */   */
54    
55  static struct utmp utent;  static void read_or_build_utent(struct utmp *utptr, int run_by_root)
   
 static void read_or_build_utent(int picky)  
56  {  {
57   struct utmp *ut;   struct utmp *ut;
58   pid_t pid = getpid();   pid_t pid = getpid();
# Line 51  static void read_or_build_utent(int pick Line 60  static void read_or_build_utent(int pick
60   setutent();   setutent();
61    
62   /* First, try to find a valid utmp entry for this process.  */   /* First, try to find a valid utmp entry for this process.  */
63   while ((ut = getutent()))   /* If there is one, just use it.  */
64   if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&   while ((ut = getutent()) != NULL)
65   (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))   if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0]
66   break;   && (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS)
67     ) {
68     *utptr = *ut; /* struct copy */
69     if (run_by_root) /* why only for root? */
70     memset(utptr->ut_host, 0, sizeof(utptr->ut_host));
71     return;
72     }
73    
74   /* If there is one, just use it, otherwise create a new one.  */  // Why? Do we require non-root to exec login from another
75   if (ut) {  // former login process (e.g. login shell)? Some login's have
76   utent = *ut;  // login shells as children, so it won't work...
77   } else {  // if (!run_by_root)
78   if (picky)  // bb_error_msg_and_die("no utmp entry found");
79   bb_error_msg_and_die("no utmp entry found");  
80     /* Otherwise create a new one.  */
81   memset(&utent, 0, sizeof(utent));   memset(utptr, 0, sizeof(*utptr));
82   utent.ut_type = LOGIN_PROCESS;   utptr->ut_type = LOGIN_PROCESS;
83   utent.ut_pid = pid;   utptr->ut_pid = pid;
84   strncpy(utent.ut_line, short_tty, sizeof(utent.ut_line));   strncpy(utptr->ut_line, short_tty, sizeof(utptr->ut_line));
85   /* This one is only 4 chars wide. Try to fit something   /* This one is only 4 chars wide. Try to fit something
86   * remotely meaningful by skipping "tty"... */   * remotely meaningful by skipping "tty"... */
87   strncpy(utent.ut_id, short_tty + 3, sizeof(utent.ut_id));   strncpy(utptr->ut_id, short_tty + 3, sizeof(utptr->ut_id));
88   strncpy(utent.ut_user, "LOGIN", sizeof(utent.ut_user));   strncpy(utptr->ut_user, "LOGIN", sizeof(utptr->ut_user));
89   utent.ut_time = time(NULL);   utptr->ut_tv.tv_sec = time(NULL);
  }  
  if (!picky) /* root login */  
  memset(utent.ut_host, 0, sizeof(utent.ut_host));  
90  }  }
91    
92  /*  /*
# Line 83  static void read_or_build_utent(int pick Line 95  static void read_or_build_utent(int pick
95   * write_utent changes the type of the current utmp entry to   * write_utent changes the type of the current utmp entry to
96   * USER_PROCESS.  the wtmp file will be updated as well.   * USER_PROCESS.  the wtmp file will be updated as well.
97   */   */
98  static void write_utent(const char *username)  static void write_utent(struct utmp *utptr, const char *username)
99  {  {
100   utent.ut_type = USER_PROCESS;   utptr->ut_type = USER_PROCESS;
101   strncpy(utent.ut_user, username, sizeof(utent.ut_user));   strncpy(utptr->ut_user, username, sizeof(utptr->ut_user));
102   utent.ut_time = time(NULL);   utptr->ut_tv.tv_sec = time(NULL);
103   /* other fields already filled in by read_or_build_utent above */   /* other fields already filled in by read_or_build_utent above */
104   setutent();   setutent();
105   pututline(&utent);   pututline(utptr);
106   endutent();   endutent();
107  #if ENABLE_FEATURE_WTMP  #if ENABLE_FEATURE_WTMP
108   if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {   if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
109   close(creat(bb_path_wtmp_file, 0664));   close(creat(bb_path_wtmp_file, 0664));
110   }   }
111   updwtmp(bb_path_wtmp_file, &utent);   updwtmp(bb_path_wtmp_file, utptr);
112  #endif  #endif
113  }  }
114  #else /* !ENABLE_FEATURE_UTMP */  #else /* !ENABLE_FEATURE_UTMP */
115  static inline void read_or_build_utent(int ATTRIBUTE_UNUSED picky) {}  #define read_or_build_utent(utptr, run_by_root) ((void)0)
116  static inline void write_utent(const char ATTRIBUTE_UNUSED *username) {}  #define write_utent(utptr, username) ((void)0)
117  #endif /* !ENABLE_FEATURE_UTMP */  #endif /* !ENABLE_FEATURE_UTMP */
118    
119  static void die_if_nologin_and_non_root(int amroot)  #if ENABLE_FEATURE_NOLOGIN
120    static void die_if_nologin(void)
121  {  {
122   FILE *fp;   FILE *fp;
123   int c;   int c;
124     int empty = 1;
125    
126   if (access(bb_path_nologin_file, F_OK))   fp = fopen_for_read("/etc/nologin");
127     if (!fp) /* assuming it does not exist */
128   return;   return;
129    
130   fp = fopen(bb_path_nologin_file, "r");   while ((c = getc(fp)) != EOF) {
131   if (fp) {   if (c == '\n')
132   while ((c = getc(fp)) != EOF)   bb_putchar('\r');
133   putchar((c=='\n') ? '\r' : c);   bb_putchar(c);
134   fflush(stdout);   empty = 0;
135   fclose(fp);   }
136   } else   if (empty)
137   puts("\r\nSystem closed for routine maintenance\r");   puts("\r\nSystem closed for routine maintenance\r");
138   if (!amroot)  
139   exit(1);   fclose(fp);
140   puts("\r\n[Disconnect bypassed -- root login allowed.]\r");   fflush(NULL);
141     /* Users say that they do need this prior to exit: */
142     tcdrain(STDOUT_FILENO);
143     exit(EXIT_FAILURE);
144  }  }
145    #else
146    static ALWAYS_INLINE void die_if_nologin(void) {}
147    #endif
148    
149  #if ENABLE_FEATURE_SECURETTY  #if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
150  static int check_securetty(void)  static int check_securetty(void)
151  {  {
152   FILE *fp;   char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */
153   int i;   parser_t *parser = config_open2("/etc/securetty", fopen_for_read);
154   char buf[BUFSIZ];   while (config_read(parser, &buf, 1, 1, "# \t", PARSE_NORMAL)) {
155     if (strcmp(buf, short_tty) == 0)
156   fp = fopen(bb_path_securetty_file, "r");   break;
157   if (!fp) {   buf = NULL;
  /* A missing securetty file is not an error. */  
  return 1;  
  }  
  while (fgets(buf, sizeof(buf)-1, fp)) {  
  for (i = strlen(buf)-1; i>=0; --i) {  
  if (!isspace(buf[i]))  
  break;  
  }  
  buf[++i] = '\0';  
  if ((buf[0]=='\0') || (buf[0]=='#'))  
  continue;  
  if (strcmp(buf, short_tty) == 0) {  
  fclose(fp);  
  return 1;  
  }  
158   }   }
159   fclose(fp);   config_close(parser);
160   return 0;   /* buf != NULL here if config file was not found, empty
161     * or line was found which equals short_tty */
162     return buf != NULL;
163  }  }
164  #else  #else
165  static inline int check_securetty(void) { return 1; }  static ALWAYS_INLINE int check_securetty(void) { return 1; }
166  #endif  #endif
167    
168  static void get_username_or_die(char *buf, int size_buf)  static void get_username_or_die(char *buf, int size_buf)
169  {  {
170   int c, cntdown;   int c, cntdown;
171    
172   cntdown = EMPTY_USERNAME_COUNT;   cntdown = EMPTY_USERNAME_COUNT;
173  prompt:   prompt:
  /* skip whitespace */  
174   print_login_prompt();   print_login_prompt();
175     /* skip whitespace */
176   do {   do {
177   c = getchar();   c = getchar();
178   if (c == EOF) exit(1);   if (c == EOF) exit(EXIT_FAILURE);
179   if (c == '\n') {   if (c == '\n') {
180   if (!--cntdown) exit(1);   if (!--cntdown) exit(EXIT_FAILURE);
181   goto prompt;   goto prompt;
182   }   }
183   } while (isspace(c));   } while (isspace(c));
184    
185   *buf++ = c;   *buf++ = c;
186   if (!fgets(buf, size_buf-2, stdin))   if (!fgets(buf, size_buf-2, stdin))
187   exit(1);   exit(EXIT_FAILURE);
188   if (!strchr(buf, '\n'))   if (!strchr(buf, '\n'))
189   exit(1);   exit(EXIT_FAILURE);
190   while (isgraph(*buf)) buf++;   while (isgraph(*buf)) buf++;
191   *buf = '\0';   *buf = '\0';
192  }  }
193    
194  static void motd(void)  static void motd(void)
195  {  {
196   FILE *fp;   int fd;
  int c;  
197    
198   fp = fopen(bb_path_motd_file, "r");   fd = open(bb_path_motd_file, O_RDONLY);
199   if (fp) {   if (fd >= 0) {
200   while ((c = getc(fp)) != EOF)   fflush(stdout);
201   putchar(c);   bb_copyfd_eof(fd, STDOUT_FILENO);
202   fclose(fp);   close(fd);
203   }   }
204  }  }
205    
206  static void nonblock(int fd)  static void alarm_handler(int sig UNUSED_PARAM)
 {  
  fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));  
 }  
   
 static void alarm_handler(int sig ATTRIBUTE_UNUSED)  
207  {  {
208   /* This is the escape hatch!  Poor serial line users and the like   /* This is the escape hatch!  Poor serial line users and the like
209   * arrive here when their connection is broken.   * arrive here when their connection is broken.
210   * We don't want to block here */   * We don't want to block here */
211   nonblock(1);   ndelay_on(1);
212   nonblock(2);   printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT);
213   bb_info_msg("\r\nLogin timed out after %d seconds\r", TIMEOUT);   fflush(stdout);
214   exit(EXIT_SUCCESS);   /* unix API is brain damaged regarding O_NONBLOCK,
215     * we should undo it, or else we can affect other processes */
216     ndelay_off(1);
217     _exit(EXIT_SUCCESS);
218  }  }
219    
220  int login_main(int argc, char **argv)  int login_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
221    int login_main(int argc UNUSED_PARAM, char **argv)
222  {  {
223   enum {   enum {
224   LOGIN_OPT_f = (1<<0),   LOGIN_OPT_f = (1<<0),
225   LOGIN_OPT_h = (1<<1),   LOGIN_OPT_h = (1<<1),
226   LOGIN_OPT_p = (1<<2),   LOGIN_OPT_p = (1<<2),
227   };   };
228   char fromhost[512];   char *fromhost;
229   char username[USERNAME_SIZE];   char username[USERNAME_SIZE];
230   const char *tmp;   const char *tmp;
231   int amroot;   int run_by_root;
232   unsigned opt;   unsigned opt;
233   int count = 0;   int count = 0;
234   struct passwd *pw;   struct passwd *pw;
235   char *opt_host = NULL;   char *opt_host = opt_host; /* for compiler */
236   char *opt_user = NULL;   char *opt_user = opt_user; /* for compiler */
237     char full_tty[TTYNAME_SIZE];
238   USE_SELINUX(security_context_t user_sid = NULL;)   USE_SELINUX(security_context_t user_sid = NULL;)
239     USE_FEATURE_UTMP(struct utmp utent;)
240    #if ENABLE_PAM
241     int pamret;
242     pam_handle_t *pamh;
243     const char *pamuser;
244     const char *failed_msg;
245     struct passwd pwdstruct;
246     char pwdbuf[256];
247    #endif
248    
249     short_tty = full_tty;
250   username[0] = '\0';   username[0] = '\0';
  amroot = (getuid() == 0);  
251   signal(SIGALRM, alarm_handler);   signal(SIGALRM, alarm_handler);
252   alarm(TIMEOUT);   alarm(TIMEOUT);
253    
254   opt = getopt32(argc, argv, "f:h:p", &opt_user, &opt_host);   /* More of suid paranoia if called by non-root: */
255     /* Clear dangerous stuff, set PATH */
256     run_by_root = !sanitize_env_if_suid();
257    
258     /* Mandatory paranoia for suid applet:
259     * ensure that fd# 0,1,2 are opened (at least to /dev/null)
260     * and any extra open fd's are closed.
261     * (The name of the function is misleading. Not daemonizing here.) */
262     bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL);
263    
264     opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
265   if (opt & LOGIN_OPT_f) {   if (opt & LOGIN_OPT_f) {
266   if (!amroot)   if (!run_by_root)
267   bb_error_msg_and_die("-f is for root only");   bb_error_msg_and_die("-f is for root only");
268   safe_strncpy(username, opt_user, sizeof(username));   safe_strncpy(username, opt_user, sizeof(username));
269   }   }
270   if (optind < argc) /* user from command line (getty) */   argv += optind;
271   safe_strncpy(username, argv[optind], sizeof(username));   if (argv[0]) /* user from command line (getty) */
272     safe_strncpy(username, argv[0], sizeof(username));
273    
274   /* Let's find out and memorize our tty */   /* Let's find out and memorize our tty */
275   if (!isatty(0) || !isatty(1) || !isatty(2))   if (!isatty(0) || !isatty(1) || !isatty(2))
# Line 254  int login_main(int argc, char **argv) Line 282  int login_main(int argc, char **argv)
282   short_tty = full_tty + 5;   short_tty = full_tty + 5;
283   }   }
284    
285   read_or_build_utent(!amroot);   read_or_build_utent(&utent, run_by_root);
286    
287   if (opt_host) {   if (opt & LOGIN_OPT_h) {
288   USE_FEATURE_UTMP(   USE_FEATURE_UTMP(
289   safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));   safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));
290   )   )
291   snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s' from "   fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host);
292   "'%.200s'", short_tty, opt_host);   } else
293   }   fromhost = xasprintf(" on '%s'", short_tty);
  else  
  snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s'", short_tty);  
294    
295   bb_setpgrp;   /* Was breaking "login <username>" from shell command line: */
296     /*bb_setpgrp();*/
297    
298   openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);   openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
299    
300   while (1) {   while (1) {
301     /* flush away any type-ahead (as getty does) */
302     ioctl(0, TCFLSH, TCIFLUSH);
303    
304   if (!username[0])   if (!username[0])
305   get_username_or_die(username, sizeof(username));   get_username_or_die(username, sizeof(username));
306    
307    #if ENABLE_PAM
308     pamret = pam_start("login", username, &conv, &pamh);
309     if (pamret != PAM_SUCCESS) {
310     failed_msg = "start";
311     goto pam_auth_failed;
312     }
313     /* set TTY (so things like securetty work) */
314     pamret = pam_set_item(pamh, PAM_TTY, short_tty);
315     if (pamret != PAM_SUCCESS) {
316     failed_msg = "set_item(TTY)";
317     goto pam_auth_failed;
318     }
319     pamret = pam_authenticate(pamh, 0);
320     if (pamret != PAM_SUCCESS) {
321     failed_msg = "authenticate";
322     goto pam_auth_failed;
323     /* TODO: or just "goto auth_failed"
324     * since user seems to enter wrong password
325     * (in this case pamret == 7)
326     */
327     }
328     /* check that the account is healthy */
329     pamret = pam_acct_mgmt(pamh, 0);
330     if (pamret != PAM_SUCCESS) {
331     failed_msg = "acct_mgmt";
332     goto pam_auth_failed;
333     }
334     /* read user back */
335     pamuser = NULL;
336     /* gcc: "dereferencing type-punned pointer breaks aliasing rules..."
337     * thus we cast to (void*) */
338     if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) {
339     failed_msg = "get_item(USER)";
340     goto pam_auth_failed;
341     }
342     if (!pamuser || !pamuser[0])
343     goto auth_failed;
344     safe_strncpy(username, pamuser, sizeof(username));
345     /* Don't use "pw = getpwnam(username);",
346     * PAM is said to be capable of destroying static storage
347     * used by getpwnam(). We are using safe(r) function */
348     pw = NULL;
349     getpwnam_r(username, &pwdstruct, pwdbuf, sizeof(pwdbuf), &pw);
350     if (!pw)
351     goto auth_failed;
352     pamret = pam_open_session(pamh, 0);
353     if (pamret != PAM_SUCCESS) {
354     failed_msg = "open_session";
355     goto pam_auth_failed;
356     }
357     pamret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
358     if (pamret != PAM_SUCCESS) {
359     failed_msg = "setcred";
360     goto pam_auth_failed;
361     }
362     break; /* success, continue login process */
363    
364     pam_auth_failed:
365     bb_error_msg("pam_%s call failed: %s (%d)", failed_msg,
366     pam_strerror(pamh, pamret), pamret);
367     safe_strncpy(username, "UNKNOWN", sizeof(username));
368    #else /* not PAM */
369   pw = getpwnam(username);   pw = getpwnam(username);
370   if (!pw) {   if (!pw) {
371   safe_strncpy(username, "UNKNOWN", sizeof(username));   strcpy(username, "UNKNOWN");
372   goto auth_failed;   goto fake_it;
373   }   }
374    
375   if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')   if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
# Line 292  int login_main(int argc, char **argv) Line 384  int login_main(int argc, char **argv)
384   /* Don't check the password if password entry is empty (!) */   /* Don't check the password if password entry is empty (!) */
385   if (!pw->pw_passwd[0])   if (!pw->pw_passwd[0])
386   break;   break;
387     fake_it:
388   /* authorization takes place here */   /* authorization takes place here */
389   if (correct_password(pw))   if (correct_password(pw))
390   break;   break;
391    #endif /* ENABLE_PAM */
392  auth_failed:   auth_failed:
393   opt &= ~LOGIN_OPT_f;   opt &= ~LOGIN_OPT_f;
394   bb_do_delay(FAIL_DELAY);   bb_do_delay(FAIL_DELAY);
395     /* TODO: doesn't sound like correct English phrase to me */
396   puts("Login incorrect");   puts("Login incorrect");
397   if (++count == 3) {   if (++count == 3) {
398   syslog(LOG_WARNING, "invalid password for '%s'%s",   syslog(LOG_WARNING, "invalid password for '%s'%s",
# Line 307  auth_failed: Line 400  auth_failed:
400   return EXIT_FAILURE;   return EXIT_FAILURE;
401   }   }
402   username[0] = '\0';   username[0] = '\0';
403   }   } /* while (1) */
404    
405   alarm(0);   alarm(0);
406   die_if_nologin_and_non_root(pw->pw_uid == 0);   /* We can ignore /etc/nologin if we are logging in as root,
407     * it doesn't matter whether we are run by root or not */
408     if (pw->pw_uid != 0)
409     die_if_nologin();
410    
411   write_utent(username);   write_utent(&utent, username);
412    
413  #ifdef CONFIG_SELINUX  #if ENABLE_SELINUX
414   if (is_selinux_enabled()) {   if (is_selinux_enabled()) {
415   security_context_t old_tty_sid, new_tty_sid;   security_context_t old_tty_sid, new_tty_sid;
416    
# Line 342  auth_failed: Line 438  auth_failed:
438   fchown(0, pw->pw_uid, pw->pw_gid);   fchown(0, pw->pw_uid, pw->pw_gid);
439   fchmod(0, 0600);   fchmod(0, 0600);
440    
441   /* TODO: be nommu-friendly, use spawn? */   /* We trust environment only if we run by root */
442   if (ENABLE_LOGIN_SCRIPTS) {   if (ENABLE_LOGIN_SCRIPTS && run_by_root) {
443   char *script = getenv("LOGIN_PRE_SUID_SCRIPT");   char *t_argv[2];
444   if (script) {  
445   char *t_argv[2] = { script, NULL };   t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT");
446   switch (fork()) {   if (t_argv[0]) {
447   case -1: break;   t_argv[1] = NULL;
448   case 0: /* child */   xsetenv("LOGIN_TTY", full_tty);
449   xchdir("/");   xsetenv("LOGIN_USER", pw->pw_name);
450   setenv("LOGIN_TTY", full_tty, 1);   xsetenv("LOGIN_UID", utoa(pw->pw_uid));
451   setenv("LOGIN_USER", pw->pw_name, 1);   xsetenv("LOGIN_GID", utoa(pw->pw_gid));
452   setenv("LOGIN_UID", utoa(pw->pw_uid), 1);   xsetenv("LOGIN_SHELL", pw->pw_shell);
453   setenv("LOGIN_GID", utoa(pw->pw_gid), 1);   spawn_and_wait(t_argv); /* NOMMU-friendly */
454   setenv("LOGIN_SHELL", pw->pw_shell, 1);   unsetenv("LOGIN_TTY"  );
455   execvp(script, t_argv);   unsetenv("LOGIN_USER" );
456   exit(1);   unsetenv("LOGIN_UID"  );
457   default: /* parent */   unsetenv("LOGIN_GID"  );
458   wait(NULL);   unsetenv("LOGIN_SHELL");
  }  
459   }   }
460   }   }
461    
# Line 368  auth_failed: Line 463  auth_failed:
463   tmp = pw->pw_shell;   tmp = pw->pw_shell;
464   if (!tmp || !*tmp)   if (!tmp || !*tmp)
465   tmp = DEFAULT_SHELL;   tmp = DEFAULT_SHELL;
466   setup_environment(tmp, 1, !(opt & LOGIN_OPT_p), pw);   /* setup_environment params: shell, clear_env, change_env, pw */
467     setup_environment(tmp, !(opt & LOGIN_OPT_p), 1, pw);
468    
469   motd();   motd();
470    
471   if (pw->pw_uid == 0)   if (pw->pw_uid == 0)
472   syslog(LOG_INFO, "root login%s", fromhost);   syslog(LOG_INFO, "root login%s", fromhost);
473  #ifdef CONFIG_SELINUX  #if ENABLE_SELINUX
474   /* well, a simple setexeccon() here would do the job as well,   /* well, a simple setexeccon() here would do the job as well,
475   * but let's play the game for now */   * but let's play the game for now */
476   set_current_security_context(user_sid);   set_current_security_context(user_sid);
# Line 385  auth_failed: Line 481  auth_failed:
481   // setsid();   // setsid();
482   // /* TIOCSCTTY: steal tty from other process group */   // /* TIOCSCTTY: steal tty from other process group */
483   // if (ioctl(0, TIOCSCTTY, 1)) error_msg...   // if (ioctl(0, TIOCSCTTY, 1)) error_msg...
484     // BBox login used to do this (see above):
485     // bb_setpgrp();
486     // If this stuff is really needed, add it and explain why!
487    
488     /* Set signals to defaults */
489     /* Non-ignored signals revert to SIG_DFL on exec anyway */
490     /*signal(SIGALRM, SIG_DFL);*/
491    
  /* set signals to defaults */  
  signal(SIGALRM, SIG_DFL);  
492   /* Is this correct? This way user can ctrl-c out of /etc/profile,   /* Is this correct? This way user can ctrl-c out of /etc/profile,
493   * potentially creating security breach (tested with bash 3.0).   * potentially creating security breach (tested with bash 3.0).
494   * But without this, bash 3.0 will not enable ctrl-c either.   * But without this, bash 3.0 will not enable ctrl-c either.
495   * Maybe bash is buggy?   * Maybe bash is buggy?
496   * Need to find out what standards say about /bin/login -   * Need to find out what standards say about /bin/login -
497   * should it leave SIGINT etc enabled or disabled? */   * should we leave SIGINT etc enabled or disabled? */
498   signal(SIGINT, SIG_DFL);   signal(SIGINT, SIG_DFL);
499    
500   run_shell(tmp, 1, 0, 0); /* exec the shell finally */   /* Exec login shell with no additional parameters */
501     run_shell(tmp, 1, NULL, NULL);
502    
503   return EXIT_FAILURE;   /* return EXIT_FAILURE; - not reached */
504  }  }

Legend:
Removed from v.532  
changed lines
  Added in v.816