155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2006 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "login_locl.h" 3555682Smarkm#ifdef HAVE_CAPABILITY_H 3655682Smarkm#include <capability.h> 3755682Smarkm#endif 3855682Smarkm#ifdef HAVE_SYS_CAPABILITY_H 3955682Smarkm#include <sys/capability.h> 4055682Smarkm#endif 41178825Sdfr#ifdef HAVE_CRYPT_H 42178825Sdfr#include <crypt.h> 43178825Sdfr#endif 4455682Smarkm 45233294SstasRCSID("$Id$"); 4655682Smarkm 4772445Sassarstatic int login_timeout = 60; 4855682Smarkm 4955682Smarkmstatic int 5055682Smarkmstart_login_process(void) 5155682Smarkm{ 5255682Smarkm char *prog, *argv0; 5355682Smarkm prog = login_conf_get_string("login_program"); 5455682Smarkm if(prog == NULL) 5555682Smarkm return 0; 5655682Smarkm argv0 = strrchr(prog, '/'); 5755682Smarkm 5855682Smarkm if(argv0) 5955682Smarkm argv0++; 6055682Smarkm else 6155682Smarkm argv0 = prog; 6255682Smarkm 6355682Smarkm return simple_execle(prog, argv0, NULL, env); 6455682Smarkm} 6555682Smarkm 6655682Smarkmstatic int 6755682Smarkmstart_logout_process(void) 6855682Smarkm{ 6955682Smarkm char *prog, *argv0; 7055682Smarkm pid_t pid; 7155682Smarkm 7255682Smarkm prog = login_conf_get_string("logout_program"); 7355682Smarkm if(prog == NULL) 7455682Smarkm return 0; 7555682Smarkm argv0 = strrchr(prog, '/'); 7655682Smarkm 7755682Smarkm if(argv0) 7855682Smarkm argv0++; 7955682Smarkm else 8055682Smarkm argv0 = prog; 8155682Smarkm 8255682Smarkm pid = fork(); 8372445Sassar if(pid == 0) { 8472445Sassar /* avoid getting signals sent to the shell */ 8572445Sassar setpgid(0, getpid()); 8655682Smarkm return 0; 8772445Sassar } 8855682Smarkm if(pid == -1) 8955682Smarkm err(1, "fork"); 9055682Smarkm /* wait for the real login process to exit */ 9155682Smarkm#ifdef HAVE_SETPROCTITLE 9255682Smarkm setproctitle("waitpid %d", pid); 9355682Smarkm#endif 9455682Smarkm while(1) { 9555682Smarkm int status; 9655682Smarkm int ret; 9755682Smarkm ret = waitpid(pid, &status, 0); 9855682Smarkm if(ret > 0) { 9955682Smarkm if(WIFEXITED(status) || WIFSIGNALED(status)) { 10055682Smarkm execle(prog, argv0, NULL, env); 10155682Smarkm err(1, "exec %s", prog); 10255682Smarkm } 103233294Sstas } else if(ret < 0) 10455682Smarkm err(1, "waitpid"); 10555682Smarkm } 10655682Smarkm} 10755682Smarkm 10855682Smarkmstatic void 10955682Smarkmexec_shell(const char *shell, int fallback) 11055682Smarkm{ 11155682Smarkm char *sh; 11255682Smarkm const char *p; 113233294Sstas 11455682Smarkm extend_env(NULL); 11555682Smarkm if(start_login_process() < 0) 11655682Smarkm warn("login process"); 11755682Smarkm start_logout_process(); 11855682Smarkm 11955682Smarkm p = strrchr(shell, '/'); 12055682Smarkm if(p) 12155682Smarkm p++; 12255682Smarkm else 12355682Smarkm p = shell; 124178825Sdfr if (asprintf(&sh, "-%s", p) == -1) 125178825Sdfr errx(1, "Out of memory"); 12655682Smarkm execle(shell, sh, NULL, env); 12755682Smarkm if(fallback){ 128233294Sstas warnx("Can't exec %s, trying %s", 12955682Smarkm shell, _PATH_BSHELL); 13055682Smarkm execle(_PATH_BSHELL, "-sh", NULL, env); 13155682Smarkm err(1, "%s", _PATH_BSHELL); 13255682Smarkm } 13355682Smarkm err(1, "%s", shell); 13455682Smarkm} 13555682Smarkm 136233294Sstasstatic enum { NONE = 0, AUTH_KRB5 = 2, AUTH_OTP = 3 } auth; 13755682Smarkm 13872445Sassar#ifdef OTP 13972445Sassarstatic OtpContext otp_ctx; 14072445Sassar 14172445Sassarstatic int 14272445Sassarotp_verify(struct passwd *pwd, const char *password) 14372445Sassar{ 14472445Sassar return (otp_verify_user (&otp_ctx, password)); 14572445Sassar} 14672445Sassar#endif /* OTP */ 14772445Sassar 14872445Sassar 149102644Snectarstatic int pag_set = 0; 150102644Snectar 15155682Smarkm#ifdef KRB5 15255682Smarkmstatic krb5_context context; 15355682Smarkmstatic krb5_ccache id, id2; 15455682Smarkm 15555682Smarkmstatic int 15655682Smarkmkrb5_verify(struct passwd *pwd, const char *password) 15755682Smarkm{ 15855682Smarkm krb5_error_code ret; 15955682Smarkm krb5_principal princ; 16055682Smarkm 16172445Sassar ret = krb5_parse_name(context, pwd->pw_name, &princ); 16255682Smarkm if(ret) 16355682Smarkm return 1; 164233294Sstas ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); 16572445Sassar if(ret) { 16655682Smarkm krb5_free_principal(context, princ); 16755682Smarkm return 1; 16855682Smarkm } 16955682Smarkm ret = krb5_verify_user_lrealm(context, 170233294Sstas princ, 17155682Smarkm id, 172233294Sstas password, 17355682Smarkm 1, 17455682Smarkm NULL); 17555682Smarkm krb5_free_principal(context, princ); 17655682Smarkm return ret; 17755682Smarkm} 17855682Smarkm 17972445Sassarstatic int 18072445Sassarkrb5_start_session (const struct passwd *pwd) 18172445Sassar{ 18272445Sassar krb5_error_code ret; 18372445Sassar char residual[64]; 18472445Sassar 18572445Sassar /* copy credentials to file cache */ 186233294Sstas snprintf(residual, sizeof(residual), "FILE:/tmp/krb5cc_%u", 18772445Sassar (unsigned)pwd->pw_uid); 18872445Sassar krb5_cc_resolve(context, residual, &id2); 18972445Sassar ret = krb5_cc_copy_cache(context, id, id2); 19072445Sassar if (ret == 0) 19172445Sassar add_env("KRB5CCNAME", residual); 19272445Sassar else { 19372445Sassar krb5_cc_destroy (context, id2); 19472445Sassar return ret; 19572445Sassar } 19655682Smarkm krb5_cc_close(context, id2); 19755682Smarkm krb5_cc_destroy(context, id); 19855682Smarkm return 0; 19955682Smarkm} 20055682Smarkm 20155682Smarkmstatic void 20255682Smarkmkrb5_finish (void) 20355682Smarkm{ 20455682Smarkm krb5_free_context(context); 20555682Smarkm} 20655682Smarkm 20755682Smarkmstatic void 20855682Smarkmkrb5_get_afs_tokens (const struct passwd *pwd) 20955682Smarkm{ 21055682Smarkm char cell[64]; 21155682Smarkm char *pw_dir; 21255682Smarkm krb5_error_code ret; 21355682Smarkm 21455682Smarkm if (!k_hasafs ()) 21555682Smarkm return; 21655682Smarkm 21755682Smarkm ret = krb5_cc_default(context, &id2); 218233294Sstas 21955682Smarkm if (ret == 0) { 22055682Smarkm pw_dir = pwd->pw_dir; 22155682Smarkm 22255682Smarkm if (!pag_set) { 22355682Smarkm k_setpag(); 22455682Smarkm pag_set = 1; 22555682Smarkm } 22655682Smarkm 22755682Smarkm if(k_afs_cell_of_file(pw_dir, cell, sizeof(cell)) == 0) 22855682Smarkm krb5_afslog_uid_home (context, id2, 22955682Smarkm cell, NULL, pwd->pw_uid, pwd->pw_dir); 23055682Smarkm krb5_afslog_uid_home (context, id2, NULL, NULL, 23155682Smarkm pwd->pw_uid, pwd->pw_dir); 23255682Smarkm krb5_cc_close (context, id2); 23355682Smarkm } 23455682Smarkm} 23555682Smarkm 23655682Smarkm#endif /* KRB5 */ 23755682Smarkm 23855682Smarkmstatic int f_flag; 23955682Smarkmstatic int p_flag; 24072445Sassar#if 0 24155682Smarkmstatic int r_flag; 24272445Sassar#endif 24355682Smarkmstatic int version_flag; 24455682Smarkmstatic int help_flag; 24555682Smarkmstatic char *remote_host; 24672445Sassarstatic char *auth_level = NULL; 24755682Smarkm 24855682Smarkmstruct getargs args[] = { 24972445Sassar { NULL, 'a', arg_string, &auth_level, "authentication mode" }, 25055682Smarkm#if 0 25155682Smarkm { NULL, 'd' }, 25255682Smarkm#endif 25355682Smarkm { NULL, 'f', arg_flag, &f_flag, "pre-authenticated" }, 25455682Smarkm { NULL, 'h', arg_string, &remote_host, "remote host", "hostname" }, 25555682Smarkm { NULL, 'p', arg_flag, &p_flag, "don't purge environment" }, 25655682Smarkm#if 0 25755682Smarkm { NULL, 'r', arg_flag, &r_flag, "rlogin protocol" }, 25855682Smarkm#endif 25955682Smarkm { "version", 0, arg_flag, &version_flag }, 26055682Smarkm { "help", 0, arg_flag,&help_flag, } 26155682Smarkm}; 26255682Smarkm 26355682Smarkmint nargs = sizeof(args) / sizeof(args[0]); 26455682Smarkm 26555682Smarkmstatic void 26655682Smarkmupdate_utmp(const char *username, const char *hostname, 26755682Smarkm char *tty, char *ttyn) 26855682Smarkm{ 26955682Smarkm /* 27055682Smarkm * Update the utmp files, both BSD and SYSV style. 27155682Smarkm */ 27255682Smarkm if (utmpx_login(tty, username, hostname) != 0 && !f_flag) { 27355682Smarkm printf("No utmpx entry. You must exec \"login\" from the " 27455682Smarkm "lowest level shell.\n"); 27555682Smarkm exit(1); 27655682Smarkm } 27755682Smarkm utmp_login(ttyn, username, hostname); 27855682Smarkm} 27955682Smarkm 28055682Smarkmstatic void 28155682Smarkmchecknologin(void) 28255682Smarkm{ 28355682Smarkm FILE *f; 28455682Smarkm char buf[1024]; 28555682Smarkm 28655682Smarkm f = fopen(_PATH_NOLOGIN, "r"); 28755682Smarkm if(f == NULL) 28855682Smarkm return; 28955682Smarkm while(fgets(buf, sizeof(buf), f)) 29055682Smarkm fputs(buf, stdout); 29155682Smarkm fclose(f); 29255682Smarkm exit(0); 29355682Smarkm} 29455682Smarkm 295102644Snectar/* print contents of a file */ 296102644Snectarstatic void 297102644Snectarshow_file(const char *file) 298102644Snectar{ 299102644Snectar FILE *f; 300102644Snectar char buf[BUFSIZ]; 301102644Snectar if((f = fopen(file, "r")) == NULL) 302102644Snectar return; 303102644Snectar while (fgets(buf, sizeof(buf), f)) 304102644Snectar fputs(buf, stdout); 305102644Snectar fclose(f); 306102644Snectar} 307102644Snectar 308233294Sstas/* 30955682Smarkm * Actually log in the user. `pwd' contains all the relevant 31055682Smarkm * information about the user. `ttyn' is the complete name of the tty 31155682Smarkm * and `tty' the short name. 31255682Smarkm */ 31355682Smarkm 31455682Smarkmstatic void 31555682Smarkmdo_login(const struct passwd *pwd, char *tty, char *ttyn) 31655682Smarkm{ 31755682Smarkm#ifdef HAVE_GETSPNAM 31855682Smarkm struct spwd *sp; 31955682Smarkm#endif 32055682Smarkm int rootlogin = (pwd->pw_uid == 0); 32155682Smarkm gid_t tty_gid; 32255682Smarkm struct group *gr; 32355682Smarkm const char *home_dir; 324102644Snectar int i; 32555682Smarkm 32655682Smarkm if(!rootlogin) 32755682Smarkm checknologin(); 328233294Sstas 32955682Smarkm#ifdef HAVE_GETSPNAM 33055682Smarkm sp = getspnam(pwd->pw_name); 33155682Smarkm#endif 33255682Smarkm 33355682Smarkm update_utmp(pwd->pw_name, remote_host ? remote_host : "", 33455682Smarkm tty, ttyn); 33555682Smarkm 33655682Smarkm gr = getgrnam ("tty"); 33755682Smarkm if (gr != NULL) 33855682Smarkm tty_gid = gr->gr_gid; 33955682Smarkm else 34055682Smarkm tty_gid = pwd->pw_gid; 34155682Smarkm 34272445Sassar if (chown (ttyn, pwd->pw_uid, tty_gid) < 0) { 34355682Smarkm warn("chown %s", ttyn); 34455682Smarkm if (rootlogin == 0) 34555682Smarkm exit (1); 34655682Smarkm } 34755682Smarkm 34855682Smarkm if (chmod (ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0) { 34955682Smarkm warn("chmod %s", ttyn); 35055682Smarkm if (rootlogin == 0) 35155682Smarkm exit (1); 35255682Smarkm } 35355682Smarkm 35455682Smarkm#ifdef HAVE_SETLOGIN 35555682Smarkm if(setlogin(pwd->pw_name)){ 35655682Smarkm warn("setlogin(%s)", pwd->pw_name); 35755682Smarkm if(rootlogin == 0) 35855682Smarkm exit(1); 35955682Smarkm } 36055682Smarkm#endif 361178825Sdfr if(rootlogin == 0) { 362178825Sdfr const char *file = login_conf_get_string("limits"); 363178825Sdfr if(file == NULL) 364178825Sdfr file = _PATH_LIMITS_CONF; 365178825Sdfr 366178825Sdfr read_limits_conf(file, pwd); 367178825Sdfr } 368233294Sstas 36990926Snectar#ifdef HAVE_SETPCRED 37090926Snectar if (setpcred (pwd->pw_name, NULL) == -1) 37190926Snectar warn("setpcred(%s)", pwd->pw_name); 37290926Snectar#endif /* HAVE_SETPCRED */ 37355682Smarkm#ifdef HAVE_INITGROUPS 37455682Smarkm if(initgroups(pwd->pw_name, pwd->pw_gid)){ 37555682Smarkm warn("initgroups(%s, %u)", pwd->pw_name, (unsigned)pwd->pw_gid); 37655682Smarkm if(rootlogin == 0) 37755682Smarkm exit(1); 37855682Smarkm } 37955682Smarkm#endif 38090926Snectar if(do_osfc2_magic(pwd->pw_uid)) 38190926Snectar exit(1); 38255682Smarkm if(setgid(pwd->pw_gid)){ 38355682Smarkm warn("setgid(%u)", (unsigned)pwd->pw_gid); 38455682Smarkm if(rootlogin == 0) 38555682Smarkm exit(1); 38655682Smarkm } 38772445Sassar if(setuid(pwd->pw_uid) || (pwd->pw_uid != 0 && setuid(0) == 0)) { 38855682Smarkm warn("setuid(%u)", (unsigned)pwd->pw_uid); 38955682Smarkm if(rootlogin == 0) 39055682Smarkm exit(1); 39155682Smarkm } 392102644Snectar 393102644Snectar /* make sure signals are set to default actions, apparently some 394102644Snectar OS:es like to ignore SIGINT, which is not very convenient */ 395233294Sstas 396102644Snectar for (i = 1; i < NSIG; ++i) 397102644Snectar signal(i, SIG_DFL); 398102644Snectar 39955682Smarkm /* all kinds of different magic */ 40055682Smarkm 40155682Smarkm#ifdef HAVE_GETSPNAM 40255682Smarkm check_shadow(pwd, sp); 40355682Smarkm#endif 40455682Smarkm 40555682Smarkm#if defined(HAVE_GETUDBNAM) && defined(HAVE_SETLIM) 40655682Smarkm { 40755682Smarkm struct udb *udb; 40855682Smarkm long t; 40955682Smarkm const long maxcpu = 46116860184; /* some random constant */ 41055682Smarkm udb = getudbnam(pwd->pw_name); 41155682Smarkm if(udb == UDB_NULL) 41255682Smarkm errx(1, "Failed to get UDB entry."); 41355682Smarkm t = udb->ue_pcpulim[UDBRC_INTER]; 41455682Smarkm if(t == 0 || t > maxcpu) 41555682Smarkm t = CPUUNLIM; 41655682Smarkm else 41755682Smarkm t *= 100 * CLOCKS_PER_SEC; 41855682Smarkm 41955682Smarkm if(limit(C_PROC, 0, L_CPU, t) < 0) 42055682Smarkm warn("limit C_PROC"); 42155682Smarkm 42255682Smarkm t = udb->ue_jcpulim[UDBRC_INTER]; 42355682Smarkm if(t == 0 || t > maxcpu) 42455682Smarkm t = CPUUNLIM; 42555682Smarkm else 42655682Smarkm t *= 100 * CLOCKS_PER_SEC; 42755682Smarkm 42855682Smarkm if(limit(C_JOBPROCS, 0, L_CPU, t) < 0) 42955682Smarkm warn("limit C_JOBPROCS"); 43055682Smarkm 43155682Smarkm nice(udb->ue_nice[UDBRC_INTER]); 43255682Smarkm } 43355682Smarkm#endif 43455682Smarkm#if defined(HAVE_SGI_GETCAPABILITYBYNAME) && defined(HAVE_CAP_SET_PROC) 43555682Smarkm /* XXX SGI capability hack IRIX 6.x (x >= 0?) has something 43655682Smarkm called capabilities, that allow you to give away 43755682Smarkm permissions (such as chown) to specific processes. From 6.5 43855682Smarkm this is default on, and the default capability set seems to 43955682Smarkm not always be the empty set. The problem is that the 44055682Smarkm runtime linker refuses to do just about anything if the 44155682Smarkm process has *any* capabilities set, so we have to remove 44255682Smarkm them here (unless otherwise instructed by /etc/capability). 44355682Smarkm In IRIX < 6.5, these functions was called sgi_cap_setproc, 44455682Smarkm etc, but we ignore this fact (it works anyway). */ 44555682Smarkm { 44655682Smarkm struct user_cap *ucap = sgi_getcapabilitybyname(pwd->pw_name); 44755682Smarkm cap_t cap; 44855682Smarkm if(ucap == NULL) 44955682Smarkm cap = cap_from_text("all="); 45055682Smarkm else 45155682Smarkm cap = cap_from_text(ucap->ca_default); 45255682Smarkm if(cap == NULL) 45355682Smarkm err(1, "cap_from_text"); 45455682Smarkm if(cap_set_proc(cap) < 0) 45555682Smarkm err(1, "cap_set_proc"); 45655682Smarkm cap_free(cap); 45755682Smarkm free(ucap); 45855682Smarkm } 45955682Smarkm#endif 46055682Smarkm home_dir = pwd->pw_dir; 46155682Smarkm if (chdir(home_dir) < 0) { 46255682Smarkm fprintf(stderr, "No home directory \"%s\"!\n", pwd->pw_dir); 46355682Smarkm if (chdir("/")) 46455682Smarkm exit(0); 46555682Smarkm home_dir = "/"; 46655682Smarkm fprintf(stderr, "Logging in with home = \"/\".\n"); 46755682Smarkm } 46855682Smarkm#ifdef KRB5 46955682Smarkm if (auth == AUTH_KRB5) { 47055682Smarkm krb5_start_session (pwd); 47155682Smarkm } 47272445Sassar 47355682Smarkm krb5_get_afs_tokens (pwd); 474120945Snectar 47572445Sassar krb5_finish (); 47655682Smarkm#endif /* KRB5 */ 47755682Smarkm 47872445Sassar add_env("PATH", _PATH_DEFPATH); 47972445Sassar 48072445Sassar { 48172445Sassar const char *str = login_conf_get_string("environment"); 48272445Sassar char buf[MAXPATHLEN]; 48372445Sassar 48472445Sassar if(str == NULL) { 48572445Sassar login_read_env(_PATH_ETC_ENVIRONMENT); 48672445Sassar } else { 48772445Sassar while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) { 48872445Sassar if(buf[0] == '\0') 48972445Sassar continue; 49072445Sassar login_read_env(buf); 49172445Sassar } 49272445Sassar } 49372445Sassar } 494102644Snectar { 495102644Snectar const char *str = login_conf_get_string("motd"); 496102644Snectar char buf[MAXPATHLEN]; 497102644Snectar 498102644Snectar if(str != NULL) { 499102644Snectar while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) { 500102644Snectar if(buf[0] == '\0') 501102644Snectar continue; 502102644Snectar show_file(buf); 503102644Snectar } 504120945Snectar } else { 505120945Snectar str = login_conf_get_string("welcome"); 506120945Snectar if(str != NULL) 507120945Snectar show_file(str); 508102644Snectar } 509102644Snectar } 51055682Smarkm add_env("HOME", home_dir); 51155682Smarkm add_env("USER", pwd->pw_name); 51255682Smarkm add_env("LOGNAME", pwd->pw_name); 51355682Smarkm add_env("SHELL", pwd->pw_shell); 51455682Smarkm exec_shell(pwd->pw_shell, rootlogin); 51555682Smarkm} 51655682Smarkm 51755682Smarkmstatic int 51855682Smarkmcheck_password(struct passwd *pwd, const char *password) 51955682Smarkm{ 52055682Smarkm if(pwd->pw_passwd == NULL) 52155682Smarkm return 1; 52255682Smarkm if(pwd->pw_passwd[0] == '\0'){ 52355682Smarkm#ifdef ALLOW_NULL_PASSWORD 52455682Smarkm return password[0] != '\0'; 52555682Smarkm#else 52655682Smarkm return 1; 52755682Smarkm#endif 52855682Smarkm } 52955682Smarkm if(strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) == 0) 53055682Smarkm return 0; 53155682Smarkm#ifdef KRB5 53255682Smarkm if(krb5_verify(pwd, password) == 0) { 53355682Smarkm auth = AUTH_KRB5; 53455682Smarkm return 0; 53555682Smarkm } 53655682Smarkm#endif 53772445Sassar#ifdef OTP 53872445Sassar if (otp_verify (pwd, password) == 0) { 53972445Sassar auth = AUTH_OTP; 54072445Sassar return 0; 54172445Sassar } 54272445Sassar#endif 54355682Smarkm return 1; 54455682Smarkm} 54555682Smarkm 54655682Smarkmstatic void 54755682Smarkmusage(int status) 54855682Smarkm{ 54955682Smarkm arg_printusage(args, nargs, NULL, "[username]"); 55055682Smarkm exit(status); 55155682Smarkm} 55255682Smarkm 55372445Sassarstatic RETSIGTYPE 55472445Sassarsig_handler(int sig) 55572445Sassar{ 55672445Sassar if (sig == SIGALRM) 55772445Sassar fprintf(stderr, "Login timed out after %d seconds\n", 55872445Sassar login_timeout); 55972445Sassar else 56072445Sassar fprintf(stderr, "Login received signal, exiting\n"); 56172445Sassar exit(0); 56272445Sassar} 56372445Sassar 56455682Smarkmint 56555682Smarkmmain(int argc, char **argv) 56655682Smarkm{ 56755682Smarkm int max_tries = 5; 56855682Smarkm int try; 56955682Smarkm 57055682Smarkm char username[32]; 571178825Sdfr int optidx = 0; 57255682Smarkm 57355682Smarkm int ask = 1; 57472445Sassar struct sigaction sa; 575233294Sstas 57678527Sassar setprogname(argv[0]); 57755682Smarkm 57872445Sassar#ifdef KRB5 57972445Sassar { 58072445Sassar krb5_error_code ret; 58172445Sassar 58272445Sassar ret = krb5_init_context(&context); 58372445Sassar if (ret) 58472445Sassar errx (1, "krb5_init_context failed: %d", ret); 58572445Sassar } 58672445Sassar#endif 58772445Sassar 588178825Sdfr openlog("login", LOG_ODELAY | LOG_PID, LOG_AUTH); 58955682Smarkm 59055682Smarkm if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, 591178825Sdfr &optidx)) 59255682Smarkm usage (1); 593178825Sdfr argc -= optidx; 594178825Sdfr argv += optidx; 59555682Smarkm 59655682Smarkm if(help_flag) 59755682Smarkm usage(0); 59855682Smarkm if (version_flag) { 59955682Smarkm print_version (NULL); 60055682Smarkm return 0; 60155682Smarkm } 602233294Sstas 60355682Smarkm if (geteuid() != 0) 60455682Smarkm errx(1, "only root may use login, use su"); 60555682Smarkm 60655682Smarkm /* Default tty settings. */ 60755682Smarkm stty_default(); 60855682Smarkm 60955682Smarkm if(p_flag) 61055682Smarkm copy_env(); 61155682Smarkm else { 61255682Smarkm /* this set of variables is always preserved by BSD login */ 61355682Smarkm if(getenv("TERM")) 61455682Smarkm add_env("TERM", getenv("TERM")); 61555682Smarkm if(getenv("TZ")) 61655682Smarkm add_env("TZ", getenv("TZ")); 61755682Smarkm } 61855682Smarkm 61955682Smarkm if(*argv){ 62055682Smarkm if(strchr(*argv, '=') == NULL && strcmp(*argv, "-") != 0){ 62155682Smarkm strlcpy (username, *argv, sizeof(username)); 62255682Smarkm ask = 0; 62355682Smarkm } 62455682Smarkm } 62572445Sassar 62672445Sassar#if defined(DCE) && defined(AIX) 62772445Sassar esetenv("AUTHSTATE", "DCE", 1); 62872445Sassar#endif 62972445Sassar 63055682Smarkm /* XXX should we care about environment on the command line? */ 63172445Sassar 63272445Sassar memset(&sa, 0, sizeof(sa)); 63372445Sassar sa.sa_handler = sig_handler; 63472445Sassar sigemptyset(&sa.sa_mask); 63572445Sassar sa.sa_flags = 0; 63672445Sassar sigaction(SIGALRM, &sa, NULL); 63772445Sassar alarm(login_timeout); 63872445Sassar 63955682Smarkm for(try = 0; try < max_tries; try++){ 64055682Smarkm struct passwd *pwd; 64155682Smarkm char password[128]; 64255682Smarkm int ret; 64355682Smarkm char ttname[32]; 64455682Smarkm char *tty, *ttyn; 64572445Sassar char prompt[128]; 64672445Sassar#ifdef OTP 64772445Sassar char otp_str[256]; 64872445Sassar#endif 64955682Smarkm 65055682Smarkm if(ask){ 65172445Sassar f_flag = 0; 65272445Sassar#if 0 65372445Sassar r_flag = 0; 65472445Sassar#endif 65555682Smarkm ret = read_string("login: ", username, sizeof(username), 1); 65655682Smarkm if(ret == -3) 65755682Smarkm exit(0); 65855682Smarkm if(ret == -2) 65972445Sassar sig_handler(0); /* exit */ 66055682Smarkm } 66155682Smarkm pwd = k_getpwnam(username); 66255682Smarkm#ifdef ALLOW_NULL_PASSWORD 66355682Smarkm if (pwd != NULL && (pwd->pw_passwd[0] == '\0')) { 66455682Smarkm strcpy(password,""); 66555682Smarkm } 66655682Smarkm else 66755682Smarkm#endif 66872445Sassar 66972445Sassar { 67072445Sassar#ifdef OTP 67172445Sassar if(auth_level && strcmp(auth_level, "otp") == 0 && 67272445Sassar otp_challenge(&otp_ctx, username, 67372445Sassar otp_str, sizeof(otp_str)) == 0) 67472445Sassar snprintf (prompt, sizeof(prompt), "%s's %s Password: ", 67572445Sassar username, otp_str); 67672445Sassar else 67772445Sassar#endif 67872445Sassar strncpy(prompt, "Password: ", sizeof(prompt)); 67972445Sassar 68072445Sassar if (f_flag == 0) { 68172445Sassar ret = read_string(prompt, password, sizeof(password), 0); 68272445Sassar if (ret == -3) { 68372445Sassar ask = 1; 68472445Sassar continue; 68572445Sassar } 68672445Sassar if (ret == -2) 68772445Sassar sig_handler(0); 68872445Sassar } 68972445Sassar } 690233294Sstas 69155682Smarkm if(pwd == NULL){ 69255682Smarkm fprintf(stderr, "Login incorrect.\n"); 69355682Smarkm ask = 1; 69455682Smarkm continue; 69555682Smarkm } 69655682Smarkm 69755682Smarkm if(f_flag == 0 && check_password(pwd, password)){ 69855682Smarkm fprintf(stderr, "Login incorrect.\n"); 69955682Smarkm ask = 1; 70055682Smarkm continue; 70155682Smarkm } 70255682Smarkm ttyn = ttyname(STDIN_FILENO); 70355682Smarkm if(ttyn == NULL){ 70455682Smarkm snprintf(ttname, sizeof(ttname), "%s??", _PATH_TTY); 70555682Smarkm ttyn = ttname; 70655682Smarkm } 70755682Smarkm if (strncmp (ttyn, _PATH_DEV, strlen(_PATH_DEV)) == 0) 70855682Smarkm tty = ttyn + strlen(_PATH_DEV); 70955682Smarkm else 71055682Smarkm tty = ttyn; 711233294Sstas 71255682Smarkm if (login_access (pwd, remote_host ? remote_host : tty) == 0) { 71355682Smarkm fprintf(stderr, "Permission denied\n"); 71455682Smarkm if (remote_host) 71555682Smarkm syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s", 71655682Smarkm pwd->pw_name, remote_host); 71755682Smarkm else 71855682Smarkm syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s", 71955682Smarkm pwd->pw_name, tty); 72055682Smarkm exit (1); 721178825Sdfr } else { 722178825Sdfr if (remote_host) 723178825Sdfr syslog(LOG_NOTICE, "%s LOGIN ACCEPTED FROM %s ppid=%d", 724178825Sdfr pwd->pw_name, remote_host, (int) getppid()); 725178825Sdfr else 726178825Sdfr syslog(LOG_NOTICE, "%s LOGIN ACCEPTED ON %s ppid=%d", 727178825Sdfr pwd->pw_name, tty, (int) getppid()); 72855682Smarkm } 72972445Sassar alarm(0); 73055682Smarkm do_login(pwd, tty, ttyn); 73155682Smarkm } 73255682Smarkm exit(1); 73355682Smarkm} 734