📄 login.c
字号:
ar[i++] = host; } if(i < AUD_NPARAM) tmask[i] = '\0'; if ( audgen ( LOGIN, tmask, ar ) == -1 ) perror ( "audgen" );#endif NOAUDIT}/* * Cleanup() is the general error exit routine. */cleanup(time, code, message)int time;int code;char *message;{ int pid; signal(SIGALRM, exit_handler); if(code && message) { audit_event(code, message); } alarm(60); fflush(stdout); fflush(stderr); close(1); close(2); if(notty) { for(pid=wait(0);pid != prompt_pid && pid != -1;pid = wait(0)); } else { ioctl(0, TIOCHPCL, (struct sgttyb *) 0); sleep(time); } close(0); exit(code);}static int intcount = 0;void no_dir(i, j, k)int i, j, *k;{ intcount++;}/* * The main program. */main(argc, argv) char *argv[];{ register char *namep; int pflag = 0; /* preserve environment from getty */ int t, f, c; int invalid, quietlog; int lcmask; FILE *nlfd; char *ttyn; int ldisc = 0, zero = 0; struct ttyent *t_ent; char *cmd = NULL; char *prompter = NULL; static int first = TRUE; REQ request; REQ *req = &request; extern int soft_exp, sec_level; char theKey, *pKey, *pChar; ver_t ultrix_v; struct utsname un; struct svcinfo *svcp; int i, j, status, diff; char lastmessage[100];#ifdef AUTHEN char namebuf[ANAME_SZ]; char *ptr;#endif AUTHEN#ifndef NOAUDIT/* Turn off all auditing except for LOGIN and setgroups.*/ if ( audcntl ( SET_PROC_ACNTL, (char *)0, 0, AUDIT_AND, 0 ) == -1 ) perror ( "audcntl" ); A_PROCMASK_SET ( buf, SYS_setgroups, 1, 1 ); A_PROCMASK_SET ( buf, LOGIN, 1, 1 ); if ( audcntl ( SET_PROC_AMASK, buf, LEN, 0, 0 ) == -1 ) perror ( "audcntl" );#endif NOAUDIT for (t = getdtablesize(); t >= 3; t--) close(t); config_auth(); signal(SIGALRM, timedout); signal(SIGQUIT, SIG_IGN); signal(SIGINT, SIG_IGN); setpriority(PRIO_PROCESS, 0, 0); quota(Q_SETUID, 0, 0, 0); /* * -r is used by rlogind to cause the autologin protocol; * -h is used by other servers to pass the name of the * remote host to login so that it may be placed in utmp and wtmp * -p is used by getty to tell login not to destroy the environment * -P is used to specify a prompting program. * -C is used to specify a command to be execed by the users shell * if the user passes the authentication and auth. * -e is used to specify extended prompter communications protocol. * It is only meaningful in the presence of "-P". *//* Initialize Kerberos if possibly needed */#ifdef AUTHEN if((svcp = getsvc()) == NULL) { fputs(" Cannot access security type\n", stderr); exit(0); } if(svcp->svcauth.seclevel >= SEC_UPGRADE) { for (i = 0 ; svcp->svcpath[SVC_AUTH][i] != SVC_LAST; i++) if (svcp->svcpath[SVC_AUTH][i] == SVC_BIND) { if(gethostname(namebuf, sizeof(namebuf)) == -1) { fputs("gethostname failure\n", stderr); } if((ptr = index(namebuf, '.')) != (char *)0) *ptr = '\0'; if(krb_svc_init("hesiod", namebuf, (char *)NULL, 0, (char *)NULL, "/var/dss/kerberos/tkt/tkt.login") != RET_OK) { fputs("Kerberos initialization failure\n",stderr); } } }#endif AUTHEN if (argc > 1) { if (strcmp(argv[1], "-r") == 0) { rflag = doremotelogin(argv[2]); SCPYN(utmp.ut_host, argv[2]); argc = 0; } if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { dflag = dodecnetlogin(); SCPYN(utmp.ut_host, argv[2]); argc = 0; } if (argc > 1 && strcmp(argv[1], "-p") == 0) { argv++; pflag = 1; argc -= 1; } if (argc > 2 && strcmp(argv[1], "-P") == 0) { if(getuid() == 0) { notty = TRUE; prompter = argv[2]; } argv += 2; argc -= 2; } if (argc > 2 && strcmp(argv[1], "-C") == 0) { if(getuid() == 0) { quietlog = TRUE; cmd = argv[2]; } argv += 2; argc -= 2; } if (argc > 1 && strcmp(argv[1], "-e") == 0 && getuid() == 0) { notty = TRUE; eflag = 1; argv++; argc--; } } if( ! notty ) { ioctl(0, TIOCLGET, &lcmask); lcmask &= LPASS8; ioctl(0, TIOCLSET, &zero); lcmask |= (LPRTERA | LCRTBS | LCRTERA); ioctl(0, TIOCLSET, &lcmask); ioctl(0, TIOCNXCL, 0); ioctl(0, FIONBIO, &zero); ioctl(0, FIOASYNC, &zero); ioctl(0, TIOCGETP, &ttyb); /* If on a LAT terminal, store the LAT server's name * into the host field of the utmp record. */ if (ioctl(0, LIOCTTYI, <attyi) == 0) { SCPYN(utmp.ut_host, ltattyi.lta_server_name); } /* * If talking to an rlogin process, * propagate the terminal type and * baud rate across the network. */ if (rflag) doremoteterm(term, &ttyb); ioctl(0, TIOCSLTC, <c); ioctl(0, TIOCSETC, &tc); ioctl(0, TIOCSETP, &ttyb); ttyn = ttyname(0); if (ttyn == (char *)0) ttyn = "/dev/tty??"; tty = rindex(ttyn, '/'); if (tty == NULL) tty = ttyn; else tty++; } else { if(argc > 1) tty = argv[1]; argc--; argv++; } if(prompter != NULL) { start_prompter(prompter, tty); } else alarm(timeout); openlog("login", 0); if(eflag) {/* * If extended login protocol get rid of stderr to prevent spurious data * from getting into the prompter conversation. All errors are reported * through the protocol using sendreq(). */ close(2);/* * Process the initial message from prompter. */ if(getreq(req) < 0) cleanup(5, 1, "Prompter died"); if(req->opcode == INITIALIZE) sendreq(INITIALIZE, VERSION); else { sendreq(ERRORNXIT, "Protocol error\n"); cleanup(10, 1, "Protocol error"); } } t = 0; do { if(!notty) { ldisc = 0; ioctl(0, TIOCSETD, &ldisc); } invalid = FALSE; SCPYN(utmp.ut_name, ""); /* * Name specified, take it. */ if (argc > 1) { SCPYN(utmp.ut_name, argv[1]); argc = 0; } else if (notty) {/* * Talking to prompter. */ /* * 029 - GAG * get the string and decypher */ sendreq(GETENAME, (char *)0); if(getreq(req) < 0) cleanup(5, 1, "Prompter died"); if(req->opcode != NAME) { sendreq(ERRORNXIT, "Protocol error\n"); cleanup(10, 1, "Protocol error"); }/* * unsalt the string. */ pChar = req->data; pKey = pChar++; for (i = req->length; i && (*pChar) && (*pChar != '\n'); i--) { *pKey ^= *pChar; pKey = pChar++; } theKey = *pKey; /* save the Key */ *pKey = NULL; if(!eflag) { if(sscanf(req->data, "name: %s", utmp.ut_name) != 1) utmp.ut_name[0] = '\0'; } else { if(req->length > sizeof utmp.ut_name) req->length = sizeof utmp.ut_name; bzero(utmp.ut_name, sizeof utmp.ut_name); bcopy(req->data, utmp.ut_name, req->length); } if(first) { alarm(timeout); first = FALSE; } } /* * If remote login take given name, * otherwise prompt user for something. */ if (rflag || dflag) { SCPYN(utmp.ut_name, lusername); /* autologin failed, prompt for passwd */ if (rflag == -1) rflag = 0; if (dflag == -1) dflag = 0; } else getloginname(&utmp); if (!notty && !strcmp(pwd->pw_shell, "/bin/csh")) { ldisc = NTTYDISC; ioctl(0, TIOCSETD, &ldisc); } /* * If "termio" is specified in /etc/ttys then use the TERMIODISC * line discipline. */ if ((t_ent = getttynam(tty)) != NULL) if (t_ent->ty_status & TTY_TERMIO){ ldisc = TERMIODISC; ioctl(0, TIOCSETD, &ldisc); } /* * If no remote login authentication and * a password exists for this user, prompt * for one and verify it. */ if(sec_level >= SEC_UPGRADE && (auth == NULL || auth->a_uid != pwd->pw_uid)) auth = getauthuid(pwd->pw_uid); if(!rflag && !dflag) { setpriority(PRIO_PROCESS, 0, -4); if( !notty ) { if((sec_level < SEC_UPGRADE) || sec_level == SEC_UPGRADE && strcmp(pwd->pw_passwd, "*")) { if(*pwd->pw_passwd) pp = getpass("Password:"); else pp = ""; } else { if(!auth || *auth->a_password) pp = getpass("Password:"); else pp = ""; } } else {/* * Talking to prompter. */ int tmp = alarm(10); void (*handler)(); /* * 029 - GAG * unbuffer stdin, line[0] is the Key, * line[1...] is the Cypher, */ handler = signal(SIGALRM, exit_handler); if(!eflag) setbuf(stdin, (char *) NULL); sendreq(GETEPWD, (char *)0); if(getreq(req) < 0) cleanup(5, 1, "Prompter died"); if(req->opcode != PASSWD) { sendreq(ERRORNXIT, "Protocol error\n"); cleanup(10, 1, "Protocol error"); } if(eflag) { LISTOFPASSWORDS *lop = (LISTOFPASSWORDS *)req->data; pp = pChar = lop->passwords[0].data; pKey = pChar++; i = lop->passwords[0].length-1; } else { for(i=req->length+1; i; i--) req->data[i] = req->data[i-1]; pChar = req->data; pKey = pChar++; *pKey = theKey; i = req->length; } alarm(tmp); signal(SIGALRM, handler); /* * 029 - GAG * decypher line, * line[0...] becomes plaintext */ for (; i && (*pChar != '\n'); i--) { *pKey ^= *pChar; pKey = pChar++; } *pKey = NULL; if(!eflag) { if(sscanf(req->data,"password: %[^\n]\n", req->data) != 1) req->data[0] = '\0'; pp = req->data; } } if(sec_level > SEC_UPGRADE || (sec_level == SEC_UPGRADE && !strcmp(pwd->pw_passwd, "*"))) { if(auth && !(!*auth->a_password && *pp)) { namep = crypt16(pp, auth->a_password); pp = auth->a_password; } else { pp = "Nologin"; namep = ""; } } else if(!(!*pwd->pw_passwd && *pp)) { namep = crypt(pp, pwd->pw_passwd); pp = pwd->pw_passwd; } else { pp = "Nologin"; namep = ""; } setpriority(PRIO_PROCESS, 0, 0); if (strcmp(namep, pp)) { bzero(req->data, REQDATASIZ); invalid = TRUE; if(sec_level >= SEC_UPGRADE) { if(auth=getauthuid(pwd->pw_uid)) if(svc_lastlookup == SVC_LOCAL) { auth->a_fail_count++; storeauthent(auth); } } } bzero(req->data, REQDATASIZ); } /* * If user not super-user, check for logins disabled. */ if (!invalid && pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { char error[REQDATASIZ]; int i; for(i=0; (c=getc(nlfd)) != EOF && i < REQDATASIZ-1; i++) error[i] = c; error[i++] = '\0'; sendreq(ERROR, error); cleanup(5, 1, "Logins disabled"); } /* * If valid so far and root is logging in, * see if root logins on this terminal are permitted. */ if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) { sendreq(ERROR, "Requires secure terminal\n"); syslog(LOG_INFO, "ROOT LOGIN REFUSED %s", tty); invalid = TRUE; cleanup(5, 1, "Unsecure terminal"); } if(!invalid && sec_level >= SEC_UPGRADE) { if(!(auth->a_authmask&A_LOGIN)) { sendreq(ERROR, "This account has been disabled\n"); sendreq(ERRORNXIT, (char *)0); cleanup(5, 1, "Account disabled"); } } if(!invalid && sec_level >= SEC_UPGRADE && auth->a_pw_maxexp) {/* * Check for password expiration. */ diff = auth->a_pass_mod + auth->a_pw_maxexp - time((long *) 0); if(diff < 0) { if(-diff > soft_exp || !(auth->a_authmask&A_CHANGE_PASSWORD)) { sendreq(ERROR, "Your password has expired\n"); sendreq(ERRORNXIT, (char *)0); invalid = TRUE; cleanup(5, 1, "Password expired"); } else { sendreq(CHGPWD, "Your password has expired, please change it\n"); endauthent(); if((i=vfork()) < 0) { invalid = TRUE; sendreq(ERRORNXIT, "Unable to fork\n"); cleanup(5, 1, "Unable to fork"); } if(i == 0) { chdir("/"); /* * Fire up passwd(1) to force user to set their password. */ if(eflag) execl("/bin/passwd", "/bin/passwd", "-ea", pwd->pw_name, (char *)0); else { setuid(pwd->pw_uid); setgid(pwd->pw_gid); execl("/bin/passwd", "passwd", pwd->pw_name, (char *) 0); } sendreq(ERROR, "Unable to exec passwd\n"); exit(1); } else { while((j=wait(&status)) != i && j >= 0) ; if(status) { invalid = TRUE; sendreq(ERRORNXIT, "Failed to set new password\n"); cleanup(5, 1, "Failed to set new password"); } else { if(svc_lastlookup == SVC_LOCAL) { if(!(auth=getauthuid(pwd->pw_uid))) { sendreq(ERRORNXIT, "Failed to retrieve auth record\n"); cleanup(5, 2, "No auth record"); } } else auth->a_pass_mod = time((long *) 0); } } } } } if (invalid) { if (++t >= 5) { sendreq(ERRORNXIT, "Login incorrect\n"); syslog(LOG_INFO, "REPEATED LOGIN FAILURES %s, %s", tty, utmp.ut_name); cleanup(5, 1, "Repeated login failures"); } else { if(pwd == &nouser) audit_event(1, "Invalid account"); else audit_event(1, "Failed authentication"); sendreq(ERROR, "Login incorrect\n"); } } else { if(sec_level >= SEC_UPGRADE) { if(auth->a_fail_count) { char line[BUFSIZ]; int i; i = auth->a_fail_count; auth->a_fail_count = 0; if(svc_lastlookup == SVC_LOCAL) storeauthent(auth); sprintf(line, "There have been %d unsuccessful login attempts on your account\n", i); sendreq(ERROR, line); if(!notty) fputs("", stdout); } diff = auth->a_pass_mod + auth->a_pw_maxexp - time((long *) 0); if(auth->a_pw_maxexp && diff < 5*24*60*60) { char line[BUFSIZ]; if(diff < 24*60*60) strcpy(line, "Your password will expire very soon\n"); else sprintf(line, "Your password will expire in %d days\n", diff/(24*60*60)); sendreq(ERROR, line); } } if(notty && !eflag) { sendreq(VALIDNXIT, "Login succeeded\n"); } } if (*pwd->pw_shell == '\0') pwd->pw_shell = "/bin/sh"; /* * Remote login invalid must have been because * of a restriction of some sort, no extra chances. */ if ((rflag|dflag) && invalid) cleanup(0, 1, "Failed remote login"); } while (invalid);/* committed to login turn off timeout */ alarm(timeout); if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0) { if (errno == EUSERS) { sendreq(ERROR, "Too many users logged on already.\nTry again later.\n"); sendreq(ERRORNXIT, (char *) 0); cleanup(5, 1, "Too many users"); } else if (errno == EPROCLIM) { sendreq(ERROR, "You have too many processes running.\n"); sendreq(ERRORNXIT, (char *) 0); cleanup(5, 1, "Too many processes for user"); } else { sendreq(ERROR, "Error in quota call\n"); sendreq(ERRORNXIT, (char *) 0); cleanup(5, 2, "Internal error in quota call"); } } /* Do the LMF check. * The Ultrix version numbers are obtained from the kernel * by uname(). The release date is defined on the command * line which compiles this program, or by the pre-processor * lines below. */ uname(&un); i = sscanf(un.release, "%hd.%hd", &ultrix_v.v_major, &ultrix_v.v_minor); if (i==0) { /* Try again in case it looks like `X4.6' */ i = sscanf(un.release, "%*[^0-9]%hd.%hd", &ultrix_v.v_major, &ultrix_v.v_minor); } if (i<2) ultrix_v.v_minor = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -