From ppomes@qualcomm.com Wed Oct 22 17:35:50 1997 Received: from MIT.EDU (SOUTH-STATION-ANNEX.MIT.EDU [18.72.1.2]) by rt-11.MIT.EDU (8.7.5/8.7.3) with SMTP id RAA11456 for ; Wed, 22 Oct 1997 17:35:40 -0400 Received: from zelkova.qualcomm.com by MIT.EDU with SMTP id AA29260; Wed, 22 Oct 97 17:33:57 EDT Received: (from ppomes@localhost) by zelkova.qualcomm.com (8.8.5/1.4/8.7.2/1.13) id OAA28689; Wed, 22 Oct 1997 14:33:21 -0700 (PDT) Message-Id: <199710222133.OAA28689@zelkova.qualcomm.com> Date: Wed, 22 Oct 1997 14:33:21 -0700 (PDT) From: Paul Pomes Reply-To: ppomes@qualcomm.com To: krb5-bugs@MIT.EDU Cc: ppomes@qualcomm.com Subject: .k5login visibility problem on NFS-mounted home directories X-Send-Pr-Version: 3.99 >Number: 482 >Category: krb5-libs >Synopsis: .k5login file not always readable on NFS-mounted homes >Confidential: no >Severity: critical >Priority: high >Responsible: krb5-unassigned >State: open >Class: sw-bug >Submitter-Id: unknown >Arrival-Date: Wed Oct 22 17:36:01 EDT 1997 >Last-Modified: >Originator: Paul Pomes >Organization: QUALCOMM, Inc. 6455 Lusk Blvd San Diego, CA 92121-2779 >Release: 1.0pl1 >Environment: System: SunOS zelkova 5.5.1 Generic_103640-04 sun4m sparc SUNW,SPARCstation-20 Architecture: sun4 >Description: Unless user home directories are exported with root un-mapped, krb5_kuserok() cannot always read the .k5login file. If search access on the user's home directory is allowed to all and the .k5login file itself is world-readable, then root can be un-mapped. >How-To-Repeat: Make your home directory (/home/foo) mode 700 and/or your ~foo/.k5login file mode 400. Insert bar's principal name into your .k5login file. kinit to bar. Attempt to telnet to a host that has the home directories mounted without the root clause in /etc/dfs/dfstab ala telnet -l foo newhost Note the failed login. Change the /home/foo to mode 755 and ~foo/.k5login to 644. Retry the telnet command and note success. >Fix: Apply the following three patches. The patch to lib/krb5/os/kuserok.c mimics similar behavior in the v4 version of this function. The other changes handle the proper changing to the home directory. The chdir() is attempted twice, once before and once after the setuid() call. *** src/appl/bsd/login.c 1997/10/22 18:59:48 1.1 --- src/appl/bsd/login.c 1997/10/22 21:13:11 *************** *** 133,138 **** --- 133,145 ---- #define siglongjmp longjmp #endif + #ifndef HAVE_SETEUID + #ifdef HAVE_SETRESUID + #define seteuid(e) setresuid(-1,e,-1) + #define setegid(e) setresgid(-1,e,-1) + #endif + #endif + #ifdef POSIX_SIGNALS typedef struct sigaction handler; #define handler_init(H,F) (sigemptyset(&(H).sa_mask), \ *************** *** 1542,1553 **** sleepexit(0); } #endif if (chdir(pwd->pw_dir) < 0) { ! printf("No directory %s!\n", pwd->pw_dir); ! if (chdir("/")) exit(0); ! pwd->pw_dir = "/"; ! printf("Logging in with home = \"/\".\n"); } /* nothing else left to fail -- really log in */ --- 1549,1563 ---- sleepexit(0); } #endif + /* + * Don't complain if the first chdir fails - NFS may prevent that + * until after the setuid(). + */ if (chdir(pwd->pw_dir) < 0) { ! if (chdir("/")) { ! (void) printf("No directory!\n"); exit(0); ! } } /* nothing else left to fail -- really log in */ *************** *** 1748,1753 **** --- 1758,1772 ---- sleepexit(1); } + /* Try the chdir again in case NFS was blocking us before. */ + if (chdir(pwd->pw_dir) < 0) { + printf("No directory %s!\n", pwd->pw_dir); + if (chdir("/")) + sleepexit(1); + pwd->pw_dir = "/"; + printf("Logging in with home = \"/\".\n"); + } + /* * We are the user now. Re-create the destroyed ccache and * ticket file. *************** *** 2249,2254 **** --- 2268,2275 ---- { static char lusername[UT_NAMESIZE+1]; char rusername[UT_NAMESIZE+1]; + int euid = -1; + int rokval; lgetstr(rusername, sizeof(rusername), "Remote user"); lgetstr(lusername, sizeof(lusername), "Local user"); *************** *** 2257,2263 **** pwd = getpwnam(username); if (pwd == NULL) return(-1); ! return(ruserok(host, (pwd->pw_uid == 0), rusername, username)); } #ifdef KRB4_KLOGIN --- 2278,2291 ---- pwd = getpwnam(username); if (pwd == NULL) return(-1); ! if (getuid() == 0 && pwd->pw_uid != 0) { ! euid = geteuid(); ! (void) seteuid(pwd->pw_uid); ! } ! rokval = ruserok(host, (pwd->pw_uid == 0), rusername, username); ! if (euid != -1) ! (void) seteuid (euid); ! return(rokval); } #ifdef KRB4_KLOGIN *** src/appl/bsd/krshd.c 1997/10/22 17:28:10 1.1 --- src/appl/bsd/krshd.c 1997/10/22 21:13:19 *************** *** 150,155 **** --- 150,162 ---- #include "com_err.h" #include "loginpaths.h" + #ifndef HAVE_SETEUID + #ifdef HAVE_SETRESUID + #define seteuid(e) setresuid(-1,e,-1) + #define setegid(e) setresgid(-1,e,-1) + #endif + #endif + #define ARGSTR "ek54ciD:S:M:AP:?L:" *************** *** 1048,1057 **** #else ! if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && ! ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) { ! error("Permission denied.\n"); ! goto signout_please; } #endif /* KERBEROS */ --- 1055,1075 ---- #else ! if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') { ! int euid = -1; ! int rokval; ! ! if (getuid() == 0 && pwd->pw_uid != 0) { ! euid = geteuid(); ! (void) seteuid(pwd->pw_uid); ! } ! rokval = ruserok(hostname, pwd->pw_uid == 0, remuser, locuser); ! if (euid != -1) ! (void) seteuid (euid); ! if (rokval < 0) { ! error("Permission denied.\n"); ! goto signout_please; ! } } #endif /* KERBEROS */ *** src/lib/krb5/os/kuserok.c 1997/10/22 19:03:04 1.1 --- src/lib/krb5/os/kuserok.c 1997/10/22 21:13:55 *************** *** 35,40 **** --- 35,47 ---- #define getpwnam(user) getpwnam((char *)user) #endif + #ifndef HAVE_SETEUID + #ifdef HAVE_SETRESUID + #define seteuid(e) setresuid(-1,e,-1) + #define setegid(e) setresgid(-1,e,-1) + #endif + #endif + #define MAX_USERNAME 10 /* *************** *** 72,77 **** --- 79,85 ---- char linebuf[BUFSIZ]; char *newline; int gobble; + int euid = -1; /* no account => no access */ if ((pwd = getpwnam(luser)) == NULL) { *************** *** 82,103 **** if (access(pbuf, F_OK)) { /* not accessible */ /* * if he's trying to log in as himself, and there is no .k5login file, * let him. To find out, call * krb5_aname_to_localname to convert the principal to a name * which we can string compare. */ ! if (!(krb5_aname_to_localname(context, principal, sizeof(kuser), kuser)) && (strcmp(kuser, luser) == 0)) { return(TRUE); } } ! if (krb5_unparse_name(context, principal, &princname)) return(FALSE); /* no hope of matching */ /* open ~/.k5login */ ! if ((fp = fopen(pbuf, "r")) == NULL) { free(princname); return(FALSE); } --- 90,127 ---- if (access(pbuf, F_OK)) { /* not accessible */ /* + * The .k5login file may not be readable by root on a user's + * home directory accessed via NFS. Switch UIDs and try again. + */ + if (getuid() == 0 && pwd->pw_uid != 0) { + euid = geteuid(); + (void) seteuid(pwd->pw_uid); + } + /* * if he's trying to log in as himself, and there is no .k5login file, * let him. To find out, call * krb5_aname_to_localname to convert the principal to a name * which we can string compare. */ ! if (access(pbuf, F_OK) && !(krb5_aname_to_localname(context, principal, sizeof(kuser), kuser)) && (strcmp(kuser, luser) == 0)) { + if (euid != -1) + (void) seteuid (euid); return(TRUE); } } ! if (krb5_unparse_name(context, principal, &princname)) { ! if (euid != -1) ! (void) seteuid (euid); return(FALSE); /* no hope of matching */ + } /* open ~/.k5login */ ! fp = fopen(pbuf, "r"); ! if (euid != -1) ! (void) seteuid (euid); ! if (fp == NULL) { free(princname); return(FALSE); } >Audit-Trail: >Unformatted: