/* login.c */ #define LOGIN_PROGRAM #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "str_defs.h" #include "utmp_defs.h" #include "prot_defs.h" #define SCAN_env(prefix, len, off, env) \ if (str_diffn(p, prefix, len)) goto z_1; \ arg[off]=p; env = p+len; p += str_len(p) + 1; static char up[513], buf[300]; static char *arg[8], *pw_dir, *pw_shell, *pw_tty, *pw_last, *name; static uid_t pw_uid; static gid_t pw_gid, tty_gid, gr_list[NGROUPS_MAX], gr_n; static void z(int n) { byte_zero(up, sizeof up); byte_zero(buf, sizeof buf); if (n==0) return; _exit(n); } static void myexit(int n,char *s) { write(2,buf, mycat(buf,s,"\n")); z(n); } int get_userinfo(int pid, int autologin) { char *p = up, *x = buf; int n; dup2(5,3); close(5); close(6); p = up; p += 1 + str_add(p, name, 40); if (autologin) { x = "-autologin"; ++p; } p += str_add(p, x, 120); n = p-up+5; if (n != SAFE_IO(write, 4, up, n)) goto z_1; close(4); z(0); errno = 0; n=SAFE_IO(read, 3, up, sizeof(up)); if (errno || n >= (int)sizeof(up) || n<5 || up[--n] || up[--n]) goto z_1; close(3); p=up; for (gr_n=0; gr_n < NGROUPS_MAX;) { if (!(n=scan_uid(p, "g", gr_list + gr_n))) break; gr_n++; p += n; } if (gr_n<1) goto z_1; if (!(n=scan_uid(p, "t", &tty_gid))) goto z_1; p+=n; if (!(n=scan_uid(p, "UID=", &pw_uid))) goto z_1; p+=n; if (!(n=scan_uid(p, "GID=", &pw_gid))) goto z_1; p+=n; if (str_diffn(p, "USER=", 5) || str_diff(p+5, name)) goto z_1; arg[2] = p; p += 1 + str_len(p); SCAN_env("HOME=", 5, 3, pw_dir); SCAN_env("SHELL=", 6, 4, pw_shell); SCAN_env("TTY=", 4, 0, pw_tty); if (!str_diffn(p, "Last ", 5)) pw_last = p; return 1; /* good user ;-) */ z_1: waitpid(pid,0,0); return 0; } int main(int argc, char **argv, char **env) { char *p; int fd,n, pi[2], OK=0, flag_auto=0; struct termios oldtermios; if (ioctl(0, TCGETS, &oldtermios)) _exit(100); oldtermios.c_lflag &= ~(ECHO|ISIG); tcsetattr(0,TCSAFLUSH,&oldtermios); argv++; (void)argc; while ((p=argv[0]) && p[0] == '-') { if (p[1]=='f') { if (getuid()) goto do_it; if (p[2]) p += 2; /* -fuser */ else p = argv[1]; /* -f user */ if (p && *p && *p != '-') { flag_auto=1; argv[0]=p; break; } else goto do_it; } argv++; } if ((name=argv[0])==0 || name[0]==0) goto do_it; if (flag_auto == 0) if (read_password(buf)) goto do_it; close(3); close(4); close(5); close(6); if (pipe(pi) || pi[0] != 3 || pi[1] != 4 || pipe(pi) || pi[0] != 5 || pi[1] != 6) myexit(111, "unable to open pipes"); switch (n=fork()) { case -1: _exit(11); case 0: z(0); if (prot_uidgid(0, 0, gr_list, 1)) z(21); dup2(6,4); close(5); close(6); arg[0] = LOGIN_AUTHORITY; execve(*arg, arg, 0); _exit(127); default: OK = get_userinfo(n, flag_auto); } do_it: byte_zero(buf, sizeof(buf)); oldtermios.c_lflag |= ECHO; tcsetattr(0, TCSAFLUSH, &oldtermios); if (!OK) { sleep(1); myexit(100,"Sorry :-)"); } if (pw_tty || !str_diffn(pw_tty, "/dev/", 5)) { chown(pw_tty, pw_uid, tty_gid); chmod(pw_tty, 0620); } p = prot_uidgid(pw_uid, pw_gid, gr_list, gr_n); if (p) { mycat(buf, "unable to set", p); myexit(111, buf); } if (chdir(pw_dir)) { n = mycat(buf,"unable to chdir: ", pw_dir); buf[n++] = '\n'; write(1,buf,n); chdir("/"); } if ((fd=open(".hushlogin", O_RDONLY)) >=0) { close(fd); } else { if ((fd=open("/etc/motd", O_RDONLY)) >= -1) { while ((n=read(fd,buf,sizeof buf)) >0) write(1,buf,n); close(fd); } if (pw_last) write(1, pw_last, str_len(pw_last)); } arg[0] = buf; mycat(buf,"-",strip_slash(pw_shell)); for (; *env; env++) if (!str_diffn(*env,"TERM=",5)) { arg[5]=*env; break; } oldtermios.c_lflag |= ISIG; tcsetattr(0, TCSAFLUSH, &oldtermios); execve(pw_shell,arg,arg+2); return 1; }