155682Smarkm/* 2178825Sdfr * Copyright (c) 1997 - 2006 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * 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 45178825SdfrRCSID("$Id: login.c 16498 2006-01-09 16:26:25Z joda $"); 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 } 10355682Smarkm } 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; 11355682Smarkm 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){ 12855682Smarkm 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 13672445Sassarstatic enum { NONE = 0, AUTH_KRB4 = 1, AUTH_KRB5 = 2, AUTH_OTP = 3 } auth; 13755682Smarkm 138178825Sdfr#ifdef KRB4 139178825Sdfrstatic krb5_boolean get_v4_tgt = FALSE; 140178825Sdfr#endif 141178825Sdfr 14272445Sassar#ifdef OTP 14372445Sassarstatic OtpContext otp_ctx; 14472445Sassar 14572445Sassarstatic int 14672445Sassarotp_verify(struct passwd *pwd, const char *password) 14772445Sassar{ 14872445Sassar return (otp_verify_user (&otp_ctx, password)); 14972445Sassar} 15072445Sassar#endif /* OTP */ 15172445Sassar 15272445Sassar 153102644Snectarstatic int pag_set = 0; 154102644Snectar 15555682Smarkm#ifdef KRB5 15655682Smarkmstatic krb5_context context; 15755682Smarkmstatic krb5_ccache id, id2; 15855682Smarkm 15955682Smarkmstatic int 16055682Smarkmkrb5_verify(struct passwd *pwd, const char *password) 16155682Smarkm{ 16255682Smarkm krb5_error_code ret; 16355682Smarkm krb5_principal princ; 16455682Smarkm 16572445Sassar ret = krb5_parse_name(context, pwd->pw_name, &princ); 16655682Smarkm if(ret) 16755682Smarkm return 1; 16855682Smarkm ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id); 16972445Sassar if(ret) { 17055682Smarkm krb5_free_principal(context, princ); 17155682Smarkm return 1; 17255682Smarkm } 17355682Smarkm ret = krb5_verify_user_lrealm(context, 17455682Smarkm princ, 17555682Smarkm id, 17655682Smarkm password, 17755682Smarkm 1, 17855682Smarkm NULL); 17955682Smarkm krb5_free_principal(context, princ); 18055682Smarkm return ret; 18155682Smarkm} 18255682Smarkm 18372445Sassar#ifdef KRB4 18472445Sassarstatic krb5_error_code 18572445Sassarkrb5_to4 (krb5_ccache id) 18655682Smarkm{ 18790926Snectar krb5_error_code ret; 18890926Snectar krb5_principal princ; 18990926Snectar 19090926Snectar ret = krb5_cc_get_principal(context, id, &princ); 191142403Snectar if(ret == 0) { 192142403Snectar krb5_appdefault_boolean(context, "login", 193142403Snectar krb5_principal_get_realm(context, princ), 194142403Snectar "krb4_get_tickets", FALSE, &get_v4_tgt); 19590926Snectar krb5_free_principal(context, princ); 196142403Snectar } else { 197142403Snectar krb5_realm realm = NULL; 198142403Snectar krb5_get_default_realm(context, &realm); 199142403Snectar krb5_appdefault_boolean(context, "login", 200142403Snectar realm, 201142403Snectar "krb4_get_tickets", FALSE, &get_v4_tgt); 202142403Snectar free(realm); 20390926Snectar } 20490926Snectar 20590926Snectar if (get_v4_tgt) { 20655682Smarkm CREDENTIALS c; 20755682Smarkm krb5_creds mcred, cred; 20855682Smarkm char krb4tkfile[MAXPATHLEN]; 20972445Sassar krb5_error_code ret; 21072445Sassar krb5_principal princ; 21155682Smarkm 212178825Sdfr krb5_cc_clear_mcred(&mcred); 213178825Sdfr 21472445Sassar ret = krb5_cc_get_principal (context, id, &princ); 21572445Sassar if (ret) 21672445Sassar return ret; 21772445Sassar 21872445Sassar ret = krb5_make_principal(context, &mcred.server, 21972445Sassar princ->realm, 22072445Sassar "krbtgt", 22172445Sassar princ->realm, 22272445Sassar NULL); 223178825Sdfr if (ret) { 224178825Sdfr krb5_free_principal(context, princ); 22572445Sassar return ret; 226178825Sdfr } 227178825Sdfr mcred.client = princ; 22872445Sassar 22972445Sassar ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred); 23055682Smarkm if(ret == 0) { 23190926Snectar ret = krb524_convert_creds_kdc_ccache(context, id, &cred, &c); 23255682Smarkm if(ret == 0) { 23355682Smarkm snprintf(krb4tkfile,sizeof(krb4tkfile),"%s%d",TKT_ROOT, 23455682Smarkm getuid()); 23555682Smarkm krb_set_tkt_string(krb4tkfile); 23655682Smarkm tf_setup(&c, c.pname, c.pinst); 23755682Smarkm } 23855682Smarkm memset(&c, 0, sizeof(c)); 239178825Sdfr krb5_free_cred_contents(context, &cred); 24055682Smarkm } 241178825Sdfr if (ret != 0) 242178825Sdfr get_v4_tgt = FALSE; 24355682Smarkm krb5_free_principal(context, mcred.server); 244178825Sdfr krb5_free_principal(context, mcred.client); 24555682Smarkm } 24672445Sassar return 0; 24772445Sassar} 24872445Sassar#endif /* KRB4 */ 24972445Sassar 25072445Sassarstatic int 25172445Sassarkrb5_start_session (const struct passwd *pwd) 25272445Sassar{ 25372445Sassar krb5_error_code ret; 25472445Sassar char residual[64]; 25572445Sassar 25672445Sassar /* copy credentials to file cache */ 25772445Sassar snprintf(residual, sizeof(residual), "FILE:/tmp/krb5cc_%u", 25872445Sassar (unsigned)pwd->pw_uid); 25972445Sassar krb5_cc_resolve(context, residual, &id2); 26072445Sassar ret = krb5_cc_copy_cache(context, id, id2); 26172445Sassar if (ret == 0) 26272445Sassar add_env("KRB5CCNAME", residual); 26372445Sassar else { 26472445Sassar krb5_cc_destroy (context, id2); 26572445Sassar return ret; 26672445Sassar } 26772445Sassar#ifdef KRB4 26872445Sassar krb5_to4 (id2); 26955682Smarkm#endif 27055682Smarkm krb5_cc_close(context, id2); 27155682Smarkm krb5_cc_destroy(context, id); 27255682Smarkm return 0; 27355682Smarkm} 27455682Smarkm 27555682Smarkmstatic void 27655682Smarkmkrb5_finish (void) 27755682Smarkm{ 27855682Smarkm krb5_free_context(context); 27955682Smarkm} 28055682Smarkm 28155682Smarkmstatic void 28255682Smarkmkrb5_get_afs_tokens (const struct passwd *pwd) 28355682Smarkm{ 28455682Smarkm char cell[64]; 28555682Smarkm char *pw_dir; 28655682Smarkm krb5_error_code ret; 28755682Smarkm 28855682Smarkm if (!k_hasafs ()) 28955682Smarkm return; 29055682Smarkm 29155682Smarkm ret = krb5_cc_default(context, &id2); 29255682Smarkm 29355682Smarkm if (ret == 0) { 29455682Smarkm pw_dir = pwd->pw_dir; 29555682Smarkm 29655682Smarkm if (!pag_set) { 29755682Smarkm k_setpag(); 29855682Smarkm pag_set = 1; 29955682Smarkm } 30055682Smarkm 30155682Smarkm if(k_afs_cell_of_file(pw_dir, cell, sizeof(cell)) == 0) 30255682Smarkm krb5_afslog_uid_home (context, id2, 30355682Smarkm cell, NULL, pwd->pw_uid, pwd->pw_dir); 30455682Smarkm krb5_afslog_uid_home (context, id2, NULL, NULL, 30555682Smarkm pwd->pw_uid, pwd->pw_dir); 30655682Smarkm krb5_cc_close (context, id2); 30755682Smarkm } 30855682Smarkm} 30955682Smarkm 31055682Smarkm#endif /* KRB5 */ 31155682Smarkm 31255682Smarkm#ifdef KRB4 31355682Smarkm 31455682Smarkmstatic int 31555682Smarkmkrb4_verify(struct passwd *pwd, const char *password) 31655682Smarkm{ 31755682Smarkm char lrealm[REALM_SZ]; 31855682Smarkm int ret; 31955682Smarkm char ticket_file[MaxPathLen]; 32055682Smarkm 32155682Smarkm ret = krb_get_lrealm (lrealm, 1); 32255682Smarkm if (ret) 32355682Smarkm return 1; 32455682Smarkm 32555682Smarkm snprintf (ticket_file, sizeof(ticket_file), 32655682Smarkm "%s%u_%u", 32755682Smarkm TKT_ROOT, (unsigned)pwd->pw_uid, (unsigned)getpid()); 32855682Smarkm 32955682Smarkm krb_set_tkt_string (ticket_file); 33055682Smarkm 33155682Smarkm ret = krb_verify_user (pwd->pw_name, "", lrealm, (char *)password, 33255682Smarkm KRB_VERIFY_SECURE_FAIL, NULL); 33355682Smarkm if (ret) 33455682Smarkm return 1; 33555682Smarkm 33655682Smarkm if (chown (ticket_file, pwd->pw_uid, pwd->pw_gid) < 0) { 33755682Smarkm dest_tkt(); 33855682Smarkm return 1; 33955682Smarkm } 34055682Smarkm 34155682Smarkm add_env ("KRBTKFILE", ticket_file); 34255682Smarkm return 0; 34355682Smarkm} 34455682Smarkm 34555682Smarkmstatic void 34655682Smarkmkrb4_get_afs_tokens (const struct passwd *pwd) 34755682Smarkm{ 34855682Smarkm char cell[64]; 34955682Smarkm char *pw_dir; 35055682Smarkm 35155682Smarkm if (!k_hasafs ()) 35255682Smarkm return; 35355682Smarkm 35455682Smarkm pw_dir = pwd->pw_dir; 35555682Smarkm 35655682Smarkm if (!pag_set) { 35755682Smarkm k_setpag(); 35855682Smarkm pag_set = 1; 35955682Smarkm } 36055682Smarkm 36155682Smarkm if(k_afs_cell_of_file(pw_dir, cell, sizeof(cell)) == 0) 36255682Smarkm krb_afslog_uid_home (cell, NULL, pwd->pw_uid, pwd->pw_dir); 36355682Smarkm 36455682Smarkm krb_afslog_uid_home (NULL, NULL, pwd->pw_uid, pwd->pw_dir); 36555682Smarkm} 36655682Smarkm 36755682Smarkm#endif /* KRB4 */ 36855682Smarkm 36955682Smarkmstatic int f_flag; 37055682Smarkmstatic int p_flag; 37172445Sassar#if 0 37255682Smarkmstatic int r_flag; 37372445Sassar#endif 37455682Smarkmstatic int version_flag; 37555682Smarkmstatic int help_flag; 37655682Smarkmstatic char *remote_host; 37772445Sassarstatic char *auth_level = NULL; 37855682Smarkm 37955682Smarkmstruct getargs args[] = { 38072445Sassar { NULL, 'a', arg_string, &auth_level, "authentication mode" }, 38155682Smarkm#if 0 38255682Smarkm { NULL, 'd' }, 38355682Smarkm#endif 38455682Smarkm { NULL, 'f', arg_flag, &f_flag, "pre-authenticated" }, 38555682Smarkm { NULL, 'h', arg_string, &remote_host, "remote host", "hostname" }, 38655682Smarkm { NULL, 'p', arg_flag, &p_flag, "don't purge environment" }, 38755682Smarkm#if 0 38855682Smarkm { NULL, 'r', arg_flag, &r_flag, "rlogin protocol" }, 38955682Smarkm#endif 39055682Smarkm { "version", 0, arg_flag, &version_flag }, 39155682Smarkm { "help", 0, arg_flag,&help_flag, } 39255682Smarkm}; 39355682Smarkm 39455682Smarkmint nargs = sizeof(args) / sizeof(args[0]); 39555682Smarkm 39655682Smarkmstatic void 39755682Smarkmupdate_utmp(const char *username, const char *hostname, 39855682Smarkm char *tty, char *ttyn) 39955682Smarkm{ 40055682Smarkm /* 40155682Smarkm * Update the utmp files, both BSD and SYSV style. 40255682Smarkm */ 40355682Smarkm if (utmpx_login(tty, username, hostname) != 0 && !f_flag) { 40455682Smarkm printf("No utmpx entry. You must exec \"login\" from the " 40555682Smarkm "lowest level shell.\n"); 40655682Smarkm exit(1); 40755682Smarkm } 40855682Smarkm utmp_login(ttyn, username, hostname); 40955682Smarkm} 41055682Smarkm 41155682Smarkmstatic void 41255682Smarkmchecknologin(void) 41355682Smarkm{ 41455682Smarkm FILE *f; 41555682Smarkm char buf[1024]; 41655682Smarkm 41755682Smarkm f = fopen(_PATH_NOLOGIN, "r"); 41855682Smarkm if(f == NULL) 41955682Smarkm return; 42055682Smarkm while(fgets(buf, sizeof(buf), f)) 42155682Smarkm fputs(buf, stdout); 42255682Smarkm fclose(f); 42355682Smarkm exit(0); 42455682Smarkm} 42555682Smarkm 426102644Snectar/* print contents of a file */ 427102644Snectarstatic void 428102644Snectarshow_file(const char *file) 429102644Snectar{ 430102644Snectar FILE *f; 431102644Snectar char buf[BUFSIZ]; 432102644Snectar if((f = fopen(file, "r")) == NULL) 433102644Snectar return; 434102644Snectar while (fgets(buf, sizeof(buf), f)) 435102644Snectar fputs(buf, stdout); 436102644Snectar fclose(f); 437102644Snectar} 438102644Snectar 43955682Smarkm/* 44055682Smarkm * Actually log in the user. `pwd' contains all the relevant 44155682Smarkm * information about the user. `ttyn' is the complete name of the tty 44255682Smarkm * and `tty' the short name. 44355682Smarkm */ 44455682Smarkm 44555682Smarkmstatic void 44655682Smarkmdo_login(const struct passwd *pwd, char *tty, char *ttyn) 44755682Smarkm{ 44855682Smarkm#ifdef HAVE_GETSPNAM 44955682Smarkm struct spwd *sp; 45055682Smarkm#endif 45155682Smarkm int rootlogin = (pwd->pw_uid == 0); 45255682Smarkm gid_t tty_gid; 45355682Smarkm struct group *gr; 45455682Smarkm const char *home_dir; 455102644Snectar int i; 45655682Smarkm 45755682Smarkm if(!rootlogin) 45855682Smarkm checknologin(); 45955682Smarkm 46055682Smarkm#ifdef HAVE_GETSPNAM 46155682Smarkm sp = getspnam(pwd->pw_name); 46255682Smarkm#endif 46355682Smarkm 46455682Smarkm update_utmp(pwd->pw_name, remote_host ? remote_host : "", 46555682Smarkm tty, ttyn); 46655682Smarkm 46755682Smarkm gr = getgrnam ("tty"); 46855682Smarkm if (gr != NULL) 46955682Smarkm tty_gid = gr->gr_gid; 47055682Smarkm else 47155682Smarkm tty_gid = pwd->pw_gid; 47255682Smarkm 47372445Sassar if (chown (ttyn, pwd->pw_uid, tty_gid) < 0) { 47455682Smarkm warn("chown %s", ttyn); 47555682Smarkm if (rootlogin == 0) 47655682Smarkm exit (1); 47755682Smarkm } 47855682Smarkm 47955682Smarkm if (chmod (ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0) { 48055682Smarkm warn("chmod %s", ttyn); 48155682Smarkm if (rootlogin == 0) 48255682Smarkm exit (1); 48355682Smarkm } 48455682Smarkm 48555682Smarkm#ifdef HAVE_SETLOGIN 48655682Smarkm if(setlogin(pwd->pw_name)){ 48755682Smarkm warn("setlogin(%s)", pwd->pw_name); 48855682Smarkm if(rootlogin == 0) 48955682Smarkm exit(1); 49055682Smarkm } 49155682Smarkm#endif 492178825Sdfr if(rootlogin == 0) { 493178825Sdfr const char *file = login_conf_get_string("limits"); 494178825Sdfr if(file == NULL) 495178825Sdfr file = _PATH_LIMITS_CONF; 496178825Sdfr 497178825Sdfr read_limits_conf(file, pwd); 498178825Sdfr } 499178825Sdfr 50090926Snectar#ifdef HAVE_SETPCRED 50190926Snectar if (setpcred (pwd->pw_name, NULL) == -1) 50290926Snectar warn("setpcred(%s)", pwd->pw_name); 50390926Snectar#endif /* HAVE_SETPCRED */ 50455682Smarkm#ifdef HAVE_INITGROUPS 50555682Smarkm if(initgroups(pwd->pw_name, pwd->pw_gid)){ 50655682Smarkm warn("initgroups(%s, %u)", pwd->pw_name, (unsigned)pwd->pw_gid); 50755682Smarkm if(rootlogin == 0) 50855682Smarkm exit(1); 50955682Smarkm } 51055682Smarkm#endif 51190926Snectar if(do_osfc2_magic(pwd->pw_uid)) 51290926Snectar exit(1); 51355682Smarkm if(setgid(pwd->pw_gid)){ 51455682Smarkm warn("setgid(%u)", (unsigned)pwd->pw_gid); 51555682Smarkm if(rootlogin == 0) 51655682Smarkm exit(1); 51755682Smarkm } 51872445Sassar if(setuid(pwd->pw_uid) || (pwd->pw_uid != 0 && setuid(0) == 0)) { 51955682Smarkm warn("setuid(%u)", (unsigned)pwd->pw_uid); 52055682Smarkm if(rootlogin == 0) 52155682Smarkm exit(1); 52255682Smarkm } 523102644Snectar 524102644Snectar /* make sure signals are set to default actions, apparently some 525102644Snectar OS:es like to ignore SIGINT, which is not very convenient */ 526102644Snectar 527102644Snectar for (i = 1; i < NSIG; ++i) 528102644Snectar signal(i, SIG_DFL); 529102644Snectar 53055682Smarkm /* all kinds of different magic */ 53155682Smarkm 53255682Smarkm#ifdef HAVE_GETSPNAM 53355682Smarkm check_shadow(pwd, sp); 53455682Smarkm#endif 53555682Smarkm 53655682Smarkm#if defined(HAVE_GETUDBNAM) && defined(HAVE_SETLIM) 53755682Smarkm { 53855682Smarkm struct udb *udb; 53955682Smarkm long t; 54055682Smarkm const long maxcpu = 46116860184; /* some random constant */ 54155682Smarkm udb = getudbnam(pwd->pw_name); 54255682Smarkm if(udb == UDB_NULL) 54355682Smarkm errx(1, "Failed to get UDB entry."); 54455682Smarkm t = udb->ue_pcpulim[UDBRC_INTER]; 54555682Smarkm if(t == 0 || t > maxcpu) 54655682Smarkm t = CPUUNLIM; 54755682Smarkm else 54855682Smarkm t *= 100 * CLOCKS_PER_SEC; 54955682Smarkm 55055682Smarkm if(limit(C_PROC, 0, L_CPU, t) < 0) 55155682Smarkm warn("limit C_PROC"); 55255682Smarkm 55355682Smarkm t = udb->ue_jcpulim[UDBRC_INTER]; 55455682Smarkm if(t == 0 || t > maxcpu) 55555682Smarkm t = CPUUNLIM; 55655682Smarkm else 55755682Smarkm t *= 100 * CLOCKS_PER_SEC; 55855682Smarkm 55955682Smarkm if(limit(C_JOBPROCS, 0, L_CPU, t) < 0) 56055682Smarkm warn("limit C_JOBPROCS"); 56155682Smarkm 56255682Smarkm nice(udb->ue_nice[UDBRC_INTER]); 56355682Smarkm } 56455682Smarkm#endif 56555682Smarkm#if defined(HAVE_SGI_GETCAPABILITYBYNAME) && defined(HAVE_CAP_SET_PROC) 56655682Smarkm /* XXX SGI capability hack IRIX 6.x (x >= 0?) has something 56755682Smarkm called capabilities, that allow you to give away 56855682Smarkm permissions (such as chown) to specific processes. From 6.5 56955682Smarkm this is default on, and the default capability set seems to 57055682Smarkm not always be the empty set. The problem is that the 57155682Smarkm runtime linker refuses to do just about anything if the 57255682Smarkm process has *any* capabilities set, so we have to remove 57355682Smarkm them here (unless otherwise instructed by /etc/capability). 57455682Smarkm In IRIX < 6.5, these functions was called sgi_cap_setproc, 57555682Smarkm etc, but we ignore this fact (it works anyway). */ 57655682Smarkm { 57755682Smarkm struct user_cap *ucap = sgi_getcapabilitybyname(pwd->pw_name); 57855682Smarkm cap_t cap; 57955682Smarkm if(ucap == NULL) 58055682Smarkm cap = cap_from_text("all="); 58155682Smarkm else 58255682Smarkm cap = cap_from_text(ucap->ca_default); 58355682Smarkm if(cap == NULL) 58455682Smarkm err(1, "cap_from_text"); 58555682Smarkm if(cap_set_proc(cap) < 0) 58655682Smarkm err(1, "cap_set_proc"); 58755682Smarkm cap_free(cap); 58855682Smarkm free(ucap); 58955682Smarkm } 59055682Smarkm#endif 59155682Smarkm home_dir = pwd->pw_dir; 59255682Smarkm if (chdir(home_dir) < 0) { 59355682Smarkm fprintf(stderr, "No home directory \"%s\"!\n", pwd->pw_dir); 59455682Smarkm if (chdir("/")) 59555682Smarkm exit(0); 59655682Smarkm home_dir = "/"; 59755682Smarkm fprintf(stderr, "Logging in with home = \"/\".\n"); 59855682Smarkm } 59955682Smarkm#ifdef KRB5 60055682Smarkm if (auth == AUTH_KRB5) { 60155682Smarkm krb5_start_session (pwd); 60255682Smarkm } 60355682Smarkm#ifdef KRB4 60472445Sassar else if (auth == 0) { 60572445Sassar krb5_error_code ret; 60672445Sassar krb5_ccache id; 60772445Sassar 60872445Sassar ret = krb5_cc_default (context, &id); 60972445Sassar if (ret == 0) { 61072445Sassar krb5_to4 (id); 61172445Sassar krb5_cc_close (context, id); 61272445Sassar } 61372445Sassar } 614120945Snectar#endif /* KRB4 */ 61572445Sassar 61655682Smarkm krb5_get_afs_tokens (pwd); 617120945Snectar 61872445Sassar krb5_finish (); 61955682Smarkm#endif /* KRB5 */ 62055682Smarkm 62155682Smarkm#ifdef KRB4 622178825Sdfr if (auth == AUTH_KRB4 || get_v4_tgt) 623178825Sdfr krb4_get_afs_tokens (pwd); 62455682Smarkm#endif /* KRB4 */ 62555682Smarkm 62672445Sassar add_env("PATH", _PATH_DEFPATH); 62772445Sassar 62872445Sassar { 62972445Sassar const char *str = login_conf_get_string("environment"); 63072445Sassar char buf[MAXPATHLEN]; 63172445Sassar 63272445Sassar if(str == NULL) { 63372445Sassar login_read_env(_PATH_ETC_ENVIRONMENT); 63472445Sassar } else { 63572445Sassar while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) { 63672445Sassar if(buf[0] == '\0') 63772445Sassar continue; 63872445Sassar login_read_env(buf); 63972445Sassar } 64072445Sassar } 64172445Sassar } 642102644Snectar { 643102644Snectar const char *str = login_conf_get_string("motd"); 644102644Snectar char buf[MAXPATHLEN]; 645102644Snectar 646102644Snectar if(str != NULL) { 647102644Snectar while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) { 648102644Snectar if(buf[0] == '\0') 649102644Snectar continue; 650102644Snectar show_file(buf); 651102644Snectar } 652120945Snectar } else { 653120945Snectar str = login_conf_get_string("welcome"); 654120945Snectar if(str != NULL) 655120945Snectar show_file(str); 656102644Snectar } 657102644Snectar } 65855682Smarkm add_env("HOME", home_dir); 65955682Smarkm add_env("USER", pwd->pw_name); 66055682Smarkm add_env("LOGNAME", pwd->pw_name); 66155682Smarkm add_env("SHELL", pwd->pw_shell); 66255682Smarkm exec_shell(pwd->pw_shell, rootlogin); 66355682Smarkm} 66455682Smarkm 66555682Smarkmstatic int 66655682Smarkmcheck_password(struct passwd *pwd, const char *password) 66755682Smarkm{ 66855682Smarkm if(pwd->pw_passwd == NULL) 66955682Smarkm return 1; 67055682Smarkm if(pwd->pw_passwd[0] == '\0'){ 67155682Smarkm#ifdef ALLOW_NULL_PASSWORD 67255682Smarkm return password[0] != '\0'; 67355682Smarkm#else 67455682Smarkm return 1; 67555682Smarkm#endif 67655682Smarkm } 67755682Smarkm if(strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) == 0) 67855682Smarkm return 0; 67955682Smarkm#ifdef KRB5 68055682Smarkm if(krb5_verify(pwd, password) == 0) { 68155682Smarkm auth = AUTH_KRB5; 68255682Smarkm return 0; 68355682Smarkm } 68455682Smarkm#endif 68555682Smarkm#ifdef KRB4 68655682Smarkm if (krb4_verify (pwd, password) == 0) { 68755682Smarkm auth = AUTH_KRB4; 68855682Smarkm return 0; 68955682Smarkm } 69055682Smarkm#endif 69172445Sassar#ifdef OTP 69272445Sassar if (otp_verify (pwd, password) == 0) { 69372445Sassar auth = AUTH_OTP; 69472445Sassar return 0; 69572445Sassar } 69672445Sassar#endif 69755682Smarkm return 1; 69855682Smarkm} 69955682Smarkm 70055682Smarkmstatic void 70155682Smarkmusage(int status) 70255682Smarkm{ 70355682Smarkm arg_printusage(args, nargs, NULL, "[username]"); 70455682Smarkm exit(status); 70555682Smarkm} 70655682Smarkm 70772445Sassarstatic RETSIGTYPE 70872445Sassarsig_handler(int sig) 70972445Sassar{ 71072445Sassar if (sig == SIGALRM) 71172445Sassar fprintf(stderr, "Login timed out after %d seconds\n", 71272445Sassar login_timeout); 71372445Sassar else 71472445Sassar fprintf(stderr, "Login received signal, exiting\n"); 71572445Sassar exit(0); 71672445Sassar} 71772445Sassar 71855682Smarkmint 71955682Smarkmmain(int argc, char **argv) 72055682Smarkm{ 72155682Smarkm int max_tries = 5; 72255682Smarkm int try; 72355682Smarkm 72455682Smarkm char username[32]; 725178825Sdfr int optidx = 0; 72655682Smarkm 72755682Smarkm int ask = 1; 72872445Sassar struct sigaction sa; 72955682Smarkm 73078527Sassar setprogname(argv[0]); 73155682Smarkm 73272445Sassar#ifdef KRB5 73372445Sassar { 73472445Sassar krb5_error_code ret; 73572445Sassar 73672445Sassar ret = krb5_init_context(&context); 73772445Sassar if (ret) 73872445Sassar errx (1, "krb5_init_context failed: %d", ret); 73972445Sassar } 74072445Sassar#endif 74172445Sassar 742178825Sdfr openlog("login", LOG_ODELAY | LOG_PID, LOG_AUTH); 74355682Smarkm 74455682Smarkm if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, 745178825Sdfr &optidx)) 74655682Smarkm usage (1); 747178825Sdfr argc -= optidx; 748178825Sdfr argv += optidx; 74955682Smarkm 75055682Smarkm if(help_flag) 75155682Smarkm usage(0); 75255682Smarkm if (version_flag) { 75355682Smarkm print_version (NULL); 75455682Smarkm return 0; 75555682Smarkm } 75655682Smarkm 75755682Smarkm if (geteuid() != 0) 75855682Smarkm errx(1, "only root may use login, use su"); 75955682Smarkm 76055682Smarkm /* Default tty settings. */ 76155682Smarkm stty_default(); 76255682Smarkm 76355682Smarkm if(p_flag) 76455682Smarkm copy_env(); 76555682Smarkm else { 76655682Smarkm /* this set of variables is always preserved by BSD login */ 76755682Smarkm if(getenv("TERM")) 76855682Smarkm add_env("TERM", getenv("TERM")); 76955682Smarkm if(getenv("TZ")) 77055682Smarkm add_env("TZ", getenv("TZ")); 77155682Smarkm } 77255682Smarkm 77355682Smarkm if(*argv){ 77455682Smarkm if(strchr(*argv, '=') == NULL && strcmp(*argv, "-") != 0){ 77555682Smarkm strlcpy (username, *argv, sizeof(username)); 77655682Smarkm ask = 0; 77755682Smarkm } 77855682Smarkm } 77972445Sassar 78072445Sassar#if defined(DCE) && defined(AIX) 78172445Sassar esetenv("AUTHSTATE", "DCE", 1); 78272445Sassar#endif 78372445Sassar 78455682Smarkm /* XXX should we care about environment on the command line? */ 78572445Sassar 78672445Sassar memset(&sa, 0, sizeof(sa)); 78772445Sassar sa.sa_handler = sig_handler; 78872445Sassar sigemptyset(&sa.sa_mask); 78972445Sassar sa.sa_flags = 0; 79072445Sassar sigaction(SIGALRM, &sa, NULL); 79172445Sassar alarm(login_timeout); 79272445Sassar 79355682Smarkm for(try = 0; try < max_tries; try++){ 79455682Smarkm struct passwd *pwd; 79555682Smarkm char password[128]; 79655682Smarkm int ret; 79755682Smarkm char ttname[32]; 79855682Smarkm char *tty, *ttyn; 79972445Sassar char prompt[128]; 80072445Sassar#ifdef OTP 80172445Sassar char otp_str[256]; 80272445Sassar#endif 80355682Smarkm 80455682Smarkm if(ask){ 80572445Sassar f_flag = 0; 80672445Sassar#if 0 80772445Sassar r_flag = 0; 80872445Sassar#endif 80955682Smarkm ret = read_string("login: ", username, sizeof(username), 1); 81055682Smarkm if(ret == -3) 81155682Smarkm exit(0); 81255682Smarkm if(ret == -2) 81372445Sassar sig_handler(0); /* exit */ 81455682Smarkm } 81555682Smarkm pwd = k_getpwnam(username); 81655682Smarkm#ifdef ALLOW_NULL_PASSWORD 81755682Smarkm if (pwd != NULL && (pwd->pw_passwd[0] == '\0')) { 81855682Smarkm strcpy(password,""); 81955682Smarkm } 82055682Smarkm else 82155682Smarkm#endif 82272445Sassar 82372445Sassar { 82472445Sassar#ifdef OTP 82572445Sassar if(auth_level && strcmp(auth_level, "otp") == 0 && 82672445Sassar otp_challenge(&otp_ctx, username, 82772445Sassar otp_str, sizeof(otp_str)) == 0) 82872445Sassar snprintf (prompt, sizeof(prompt), "%s's %s Password: ", 82972445Sassar username, otp_str); 83072445Sassar else 83172445Sassar#endif 83272445Sassar strncpy(prompt, "Password: ", sizeof(prompt)); 83372445Sassar 83472445Sassar if (f_flag == 0) { 83572445Sassar ret = read_string(prompt, password, sizeof(password), 0); 83672445Sassar if (ret == -3) { 83772445Sassar ask = 1; 83872445Sassar continue; 83972445Sassar } 84072445Sassar if (ret == -2) 84172445Sassar sig_handler(0); 84272445Sassar } 84372445Sassar } 84455682Smarkm 84555682Smarkm if(pwd == NULL){ 84655682Smarkm fprintf(stderr, "Login incorrect.\n"); 84755682Smarkm ask = 1; 84855682Smarkm continue; 84955682Smarkm } 85055682Smarkm 85155682Smarkm if(f_flag == 0 && check_password(pwd, password)){ 85255682Smarkm fprintf(stderr, "Login incorrect.\n"); 85355682Smarkm ask = 1; 85455682Smarkm continue; 85555682Smarkm } 85655682Smarkm ttyn = ttyname(STDIN_FILENO); 85755682Smarkm if(ttyn == NULL){ 85855682Smarkm snprintf(ttname, sizeof(ttname), "%s??", _PATH_TTY); 85955682Smarkm ttyn = ttname; 86055682Smarkm } 86155682Smarkm if (strncmp (ttyn, _PATH_DEV, strlen(_PATH_DEV)) == 0) 86255682Smarkm tty = ttyn + strlen(_PATH_DEV); 86355682Smarkm else 86455682Smarkm tty = ttyn; 86555682Smarkm 86655682Smarkm if (login_access (pwd, remote_host ? remote_host : tty) == 0) { 86755682Smarkm fprintf(stderr, "Permission denied\n"); 86855682Smarkm if (remote_host) 86955682Smarkm syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s", 87055682Smarkm pwd->pw_name, remote_host); 87155682Smarkm else 87255682Smarkm syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s", 87355682Smarkm pwd->pw_name, tty); 87455682Smarkm exit (1); 875178825Sdfr } else { 876178825Sdfr if (remote_host) 877178825Sdfr syslog(LOG_NOTICE, "%s LOGIN ACCEPTED FROM %s ppid=%d", 878178825Sdfr pwd->pw_name, remote_host, (int) getppid()); 879178825Sdfr else 880178825Sdfr syslog(LOG_NOTICE, "%s LOGIN ACCEPTED ON %s ppid=%d", 881178825Sdfr pwd->pw_name, tty, (int) getppid()); 88255682Smarkm } 88372445Sassar alarm(0); 88455682Smarkm do_login(pwd, tty, ttyn); 88555682Smarkm } 88655682Smarkm exit(1); 88755682Smarkm} 888