Skip Menu |
 

Download (untitled) / with headers
text/plain 15.9KiB
From mhpower@MIT.EDU Tue Nov 5 23:42:28 1996
Received: from MIT.EDU (PACIFIC-CARRIER-ANNEX.MIT.EDU [18.69.0.28]) by rt-11.MIT.EDU (8.7.5/8.7.3) with SMTP id XAA15833 for <bugs@RT-11.MIT.EDU>; Tue, 5 Nov 1996 23:42:28 -0500
Received: from YAZ-PISTACHIO.MIT.EDU by MIT.EDU with SMTP
id AA04141; Tue, 5 Nov 96 23:42:27 EST
Received: by yaz-pistachio.MIT.EDU (5.57/4.7) id AA02820; Tue, 5 Nov 96 23:42:26 -0500
Message-Id: <9611060442.AA02820@yaz-pistachio.MIT.EDU>
Date: Tue, 05 Nov 1996 23:42:23 EST
From: mhpower@MIT.EDU
To: krb5-bugs@MIT.EDU
Subject: security concern with using home directory for .k5login

Show quoted text
>Number: 155
>Category: krb5-appl
>Synopsis: security concern with using home directory for .k5login
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: krb5-unassigned
>State: open
>Class: change-request
>Submitter-Id: unknown
>Arrival-Date: Tue Nov 05 23:43:01 EST 1996
>Last-Modified: Thu Sep 13 21:29:27 EDT 2001
>Originator: mhpower@MIT.EDU
>Organization:
>Release:
>Environment:
>Description:
The kuserok function determines login authorization by reading a file
from the directory specified by the user's passwd pw_dir field on the
target machine. In many environments, an attacker may be able to cause
the reading of the file to deliver contents that were not intended by
anyone with legitimate access to the target account. I believe that,
in these environments, security can be improved substantially by
allowing Kerberos to be configured such that a directory different
from the user's home directory is used for .k5login files.

The most common reason that this type of attack is possible is that
the user's home directory is located on a remote filesystem, and
authentication of file reads is either completely absent, or is based
on weak mechanisms such as IP addresses. An attacker can begin a
remote-login attempt to a target machine, and at about the same time
inject onto the network packets from the remote fileserver's IP
address that are sufficient to convince the target machine that it has
read the relevant .k5login file. The injected packets would include
text that lists the attacker's Kerberos principal, and thus the target
machine would allow the remote login.

The attack is also possible in an especially degenerate environment in
which any user can mount an arbitrary filesystem of his choice on the
directory specified by another user's pw_dir field.

I've included patches that address this problem by allowing the
pathname for .k5login files to be specified in krb5.conf. One
potential use involves setting up a directory tree on a target
machine's local disk, e.g., each user's .k5login file would be looked
for in /var/userauth/username/.k5login, and users' home directories
would still remain on NFS or AFS filesystems. For sites with too many
users or too many target machines for this to be practical, one might
instead arrange for the specified .k5login pathname to not exist (or
to exist only for root's account), thus most likely restricting users
to use only one Kerberos principal for remote logins, which could only
be to their own accounts. This would probably be appropriate for
target machines that are intended for general timesharing service.

I've also included a related patch that allows disabling the default
access policy that's implemented in the absence of a .k5login file
(i.e., access is granted if the Kerberos principal matches the local
username). This can be useful if there are only a few legitimate
users, but a lot of default accounts (e.g., operator, news, uucp) that
might otherwise need .k5login files in order to block access.

The patches make no attempt to address the issue of .k5users files.

The patches haven't been tested at all, they may be incomplete or have
other problems, and possibly the patched code won't even compile.

Matt


*** krb5-beta7/src/config-files/krb5.conf.M.old Tue Sep 10 20:26:07 1996
--- krb5-beta7/src/config-files/krb5.conf.M Tue Nov 5 21:04:48 1996
***************
*** 144,149 ****
--- 144,169 ----
do not support the default cache as created by this version of
Kerberos. Use a value of 1 on DCE 1.0.3a systems, and a value of 2 on
DCE 1.1 systems.
+
+ .IP k5login_location
+ This relation identifies a partial pathname used in locating a user's
+ .k5login file. If this relation is unspecified, the location for a
+ user's .k5login file is the top level of his home directory. If the
+ partial pathname begins with a '/', the full pathname of the .k5login
+ file is formed by concatenating this partial pathname with a "/",
+ followed by the user's login name, another "/", and the string
+ ".k5login". Otherwise, the full pathname is formed by concatenating
+ the user's home directory, a "/", this partial pathname, another "/",
+ and the string ".k5login".
+
+ .IP k5login_required
+ This relation identifies whether a .k5login file must be found in
+ order for authorization to succeed. If absent, or if set to the value
+ 0, a .k5login file is not required if a user wishes to access a local
+ account whose name matches the principal part of his Kerberos
+ principal. If present with a non-zero value, a .k5login file is
+ required, e.g., it would need to list a user's Kerberos principal
+ even if he wished only to allow himself to login to his own account.
.SH LOGIN SECTION
The [login] section is used to configure the behavior of the Kerberos V5
login program,


*** krb5-beta7/doc/krb5-user.info.old Tue Sep 10 20:54:39 1996
--- krb5-beta7/doc/krb5-user.info Tue Nov 5 21:13:04 1996
***************
*** 594,601 ****

If you need to give someone access to log into your account, you can do
so through Kerberos, without telling the person your password. Simply
! create a file called `.k5login' in your home directory. This file
! should contain the Kerberos principal (*Note What is a Kerberos
Principal?::) of each person to whom you wish to give access. Each
principal must be on a separate line. Here is a sample `.k5login' file:

--- 594,603 ----

If you need to give someone access to log into your account, you can do
so through Kerberos, without telling the person your password. Simply
! create a file called `.k5login' in your home directory. (It's
! possible that a directory other than your home directory will need to
! be used instead, depending on the configuration of your system.) This
! file should contain the Kerberos principal (*Note What is a Kerberos
Principal?::) of each person to whom you wish to give access. Each
principal must be on a separate line. Here is a sample `.k5login' file:


*** krb5-beta7/src/include/k5-int.h.old Fri Sep 6 18:20:49 1996
--- krb5-beta7/src/include/k5-int.h Tue Nov 5 21:11:07 1996
***************
*** 932,937 ****
--- 932,939 ----
krb5_boolean profile_secure;
int fcc_default_format;
int scc_default_format;
+ char FAR *k5login_location;
+ int k5login_required;
};

#define KRB5_LIBOPT_SYNC_KDCTIME 0x0001


*** krb5-beta7/src/lib/krb5/krb/init_ctx.c.old Wed Jul 10 20:32:12 1996
--- krb5-beta7/src/lib/krb5/krb/init_ctx.c Tue Nov 5 22:46:34 1996
***************
*** 37,42 ****
--- 37,43 ----
krb5_context ctx;
krb5_error_code retval;
int tmp;
+ char *sretval;

#if (defined(_MSDOS) || defined(_WIN32))
/*
***************
*** 69,78 ****
0, 5 * 60, &tmp);
ctx->clockskew = tmp;

! /* Default ticket lifetime is
profile_get_integer(ctx->profile, "libdefaults", "tkt_lifetime",
0, 10 * 60 * 60, &tmp);
! ctx->clockskew = tmp;

/* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2) */
/* DCE add kdc_req_checksum_type = 2 to krb5.conf */
--- 70,81 ----
0, 5 * 60, &tmp);
ctx->clockskew = tmp;

! #if 0
! /* Default ticket lifetime is currently not supported */
profile_get_integer(ctx->profile, "libdefaults", "tkt_lifetime",
0, 10 * 60 * 60, &tmp);
! ctx->tkt_lifetime = tmp;
! #endif

/* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2) */
/* DCE add kdc_req_checksum_type = 2 to krb5.conf */
***************
*** 123,128 ****
--- 126,149 ----
ctx->fcc_default_format = tmp + 0x0500;
ctx->scc_default_format = tmp + 0x0500;

+ retval = profile_get_string(ctx->profile,
+ "libdefaults", "k5login_location", NULL,
+ "",
+ &sretval);
+ if (retval)
+ goto cleanup;
+
+ ctx->k5login_location = malloc(strlen(sretval) + 1);
+ if (!ctx->k5login_location) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ strcpy(ctx->k5login_location, sretval);
+
+ profile_get_integer(ctx->profile, "libdefaults", "k5login_required",
+ 0, 0, &tmp);
+ ctx->k5login_required = tmp;
+
*context = ctx;
return 0;

***************
*** 148,153 ****
--- 169,177 ----

if (ctx->ser_ctx_count && ctx->ser_ctx)
free(ctx->ser_ctx);
+
+ if (ctx->k5login_location)
+ free(ctx->k5login_location);

ctx->magic = 0;
free(ctx);


*** krb5-beta7/src/lib/krb5/krb/ser_ctx.c.old Tue May 14 04:41:32 1996
--- krb5-beta7/src/lib/krb5/krb/ser_ctx.c Tue Nov 5 19:26:08 1996
***************
*** 105,110 ****
--- 105,112 ----
* krb5_int32 for KV5M_CONTEXT
* krb5_int32 for sizeof(default_realm)
* strlen(default_realm) for default_realm.
+ * krb5_int32 for sizeof(k5login_location)
+ * strlen(k5login_location) for k5login_location.
* krb5_int32 for n_in_tkt_ktypes*sizeof(krb5_int32)
* nktypes*sizeof(krb5_int32) for in_tkt_ktypes.
* krb5_int32 for n_tgs_ktypes*sizeof(krb5_int32)
***************
*** 118,123 ****
--- 120,126 ----
* krb5_int32 for profile_secure
* krb5_int32 for fcc_default_format
* krb5_int32 for scc_default_format
+ * krb5_int32 for k5login_required
* <> for os_context
* <> for db_context
* <> for profile
***************
*** 126,137 ****
kret = EINVAL;
if ((context = (krb5_context) arg)) {
/* Calculate base length */
! required = (14 * sizeof(krb5_int32) +
(context->in_tkt_ktype_count * sizeof(krb5_int32)) +
(context->tgs_ktype_count * sizeof(krb5_int32)));

if (context->default_realm)
required += strlen(context->default_realm);
/* Calculate size required by os_context, if appropriate */
if (context->os_context)
kret = krb5_size_opaque(kcontext,
--- 129,142 ----
kret = EINVAL;
if ((context = (krb5_context) arg)) {
/* Calculate base length */
! required = (16 * sizeof(krb5_int32) +
(context->in_tkt_ktype_count * sizeof(krb5_int32)) +
(context->tgs_ktype_count * sizeof(krb5_int32)));

if (context->default_realm)
required += strlen(context->default_realm);
+ if (context->k5login_location)
+ required += strlen(context->k5login_location);
/* Calculate size required by os_context, if appropriate */
if (context->os_context)
kret = krb5_size_opaque(kcontext,
***************
*** 210,215 ****
--- 215,236 ----
return (kret);
}

+ /* Now sizeof k5login location */
+ kret = krb5_ser_pack_int32((context->k5login_location) ?
+ (krb5_int32) strlen(context->k5login_location) : 0,
+ &bp, &remain);
+ if (kret)
+ return (kret);
+
+ /* Now k5login_location bytes */
+ if (context->k5login_location) {
+ kret = krb5_ser_pack_bytes((krb5_octet *) context->k5login_location,
+ strlen(context->k5login_location),
+ &bp, &remain);
+ if (kret)
+ return (kret);
+ }
+
/* Now number of initial ticket ktypes */
kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktype_count,
&bp, &remain);
***************
*** 292,297 ****
--- 313,324 ----
if (kret)
return (kret);

+ /* Now k5login_required */
+ kret = krb5_ser_pack_int32((krb5_int32) context->k5login_required,
+ &bp, &remain);
+ if (kret)
+ return (kret);
+
/* Now handle os_context, if appropriate */
if (context->os_context) {
kret = krb5_externalize_opaque(kcontext, KV5M_OS_CONTEXT,
***************
*** 384,390 ****
--- 411,436 ----

context->default_realm[ibuf] = '\0';
}
+
+ /* Get the size of the k5login location */
+ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+ goto cleanup;
+
+ if (ibuf) {
+ context->k5login_location = (char *) malloc((size_t) ibuf+1);
+ if (!context->k5login_location) {
+ kret = ENOMEM;
+ goto cleanup;
+ }
+
+ kret = krb5_ser_unpack_bytes((krb5_octet *) context->k5login_location,
+ (size_t) ibuf, &bp, &remain);
+ if (kret)
+ goto cleanup;

+ context->k5login_location[ibuf] = '\0';
+ }
+
/* Get the number of in_tkt_ktypes */
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
***************
*** 468,473 ****
--- 514,524 ----
if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
goto cleanup;
context->scc_default_format = (int) ibuf;
+
+ /* k5login_required */
+ if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+ goto cleanup;
+ context->k5login_required = (int) ibuf;

/* Attempt to read in the os_context */
kret = krb5_internalize_opaque(kcontext, KV5M_OS_CONTEXT,


*** krb5-beta7/src/lib/krb5/os/kuserok.c.old Wed Jun 12 01:15:02 1996
--- krb5-beta7/src/lib/krb5/os/kuserok.c Tue Nov 5 21:17:26 1996
***************
*** 77,92 ****
if ((pwd = getpwnam(luser)) == NULL) {
return(FALSE);
}
- (void) strcpy(pbuf, pwd->pw_dir);
- (void) strcat(pbuf, "/.k5login");

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)) {
--- 77,115 ----
if ((pwd = getpwnam(luser)) == NULL) {
return(FALSE);
}

+ /*
+ * .k5login file may be in the top level of his home directory, in some
+ * subdirectory of his home directory, or in some other directory that
+ * has his username as one component of the pathname.
+ */
+ if (!context->k5login_location || context->k5login_location[0] == '\0') {
+ (void) strcpy(pbuf, pwd->pw_dir);
+ (void) strcat(pbuf, "/.k5login");
+ }
+ else if (context->k5login_location[0] != '/') {
+ (void) strcpy(pbuf, pwd->pw_dir);
+ (void) strcat(pbuf, "/");
+ (void) strcat(pbuf, context->k5login_location);
+ (void) strcat(pbuf, "/.k5login");
+ }
+ else {
+ (void) strcpy(pbuf, context->k5login_location);
+ (void) strcat(pbuf, "/");
+ (void) strcat(pbuf, pwd->pw_name);
+ (void) strcat(pbuf, "/.k5login");
+ }
+
if (access(pbuf, F_OK)) { /* not accessible */
/*
* if he's trying to log in as himself, and there is no .k5login file,
! * let him, unless k5login_required is set. To find out if he is
! * logging in as himself, call krb5_aname_to_localname to convert the
! * principal to a name which we can string compare.
*/
+ if (context->k5login_required)
+ return(FALSE);
+
if (!(krb5_aname_to_localname(context, principal,
sizeof(kuser), kuser))
&& (strcmp(kuser, luser) == 0)) {
***************
*** 96,102 ****
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);
--- 119,125 ----
if (krb5_unparse_name(context, principal, &princname))
return(FALSE); /* no hope of matching */

! /* open the .k5login file */
if ((fp = fopen(pbuf, "r")) == NULL) {
free(princname);
return(FALSE);
Show quoted text
>How-To-Repeat:
>Fix:
>Audit-Trail:

Responsible-Changed-From-To: gnats-admin->krb5-unassigned
Responsible-Changed-By: tlyu
Responsible-Changed-When: Wed Nov 13 23:49:04 1996
Responsible-Changed-Why:
refiled

Show quoted text
>Unformatted:
Subject: security concern with using home directory for .k5login
This (or something comparable) really should get folded in at some point....
#6792 implements k5login_directory, which fulfills the purpose of
k5login_location from the patch. #7583 implements the localauth
pluggable interface, which provides enough rope to disable an2ln as a
k5userok facility, thus fulfilling the purpose of k5login_required from
the patch.