diff options
-rw-r--r-- | krb5-trunk-k5login.patch | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/krb5-trunk-k5login.patch b/krb5-trunk-k5login.patch new file mode 100644 index 0000000..e3bfc94 --- /dev/null +++ b/krb5-trunk-k5login.patch @@ -0,0 +1,333 @@ +commit 3ec524d3aa8f92b150a02062ae8faf0bb2ffaa9d +Author: ghudson <ghudson@dc483132-0cff-0310-8789-dd5450dbe970> +Date: Fri Oct 1 15:56:30 2010 +0000 + + ticket: 6792 + subject: Implement k5login_directory and k5login_authoritative options + + Add and document two new options for controlling k5login behavior. + + + git-svn-id: svn://anonsvn.mit.edu:/krb5/trunk@24402 dc483132-0cff-0310-8789-dd5450dbe970 + +diff --git a/doc/admin.texinfo b/doc/admin.texinfo +index 8603b93..2a811de 100644 +--- a/doc/admin.texinfo ++++ b/doc/admin.texinfo +@@ -468,6 +468,20 @@ Sets the maximum allowable amount of clockskew in seconds that the + library will tolerate before assuming that a Kerberos message is + invalid. The default value is @value{DefaultClockskew}. + ++@itemx k5login_authoritative ++If the value of this relation is true (the default), principals must ++be listed in a local user's k5login file to be granted login access, ++if a k5login file exists. If the value of this relation is false, a ++principal may still be granted login access through other mechanisms ++even if a k5login file exists but does not list the principal. ++ ++@itemx k5login_directory ++If set, the library will look for a local user's k5login file within the ++named directory, with a filename corresponding to the local username. ++If not set, the library will look for k5login files in the user's home ++directory, with the filename @code{.k5login}. For security reasons, ++k5login files must be owned by the local user or by root. ++ + @itemx kdc_timesync + If this is set to 1 (for true), then client machines will compute the + difference between their time and the time returned by the KDC in the +diff --git a/src/config-files/krb5.conf.M b/src/config-files/krb5.conf.M +index 2995aa2..e658e89 100644 +--- a/src/config-files/krb5.conf.M ++++ b/src/config-files/krb5.conf.M +@@ -155,6 +155,20 @@ This relation sets the maximum allowable amount of clockskew in seconds + that the library will tolerate before assuming that a Kerberos message + is invalid. The default value is 300 seconds, or five minutes. + ++.IP k5login_authoritative ++If the value of this relation is true (the default), principals must ++be listed in a local user's k5login file to be granted login access, ++if a k5login file exists. If the value of this relation is false, a ++principal may still be granted login access through other mechanisms ++even if a k5login file exists but does not list the principal. ++ ++.IP k5login_directory ++If set, the library will look for a local user's k5login file within ++the named directory, with a filename corresponding to the local ++username. If not set, the library will look for k5login files in the ++user's home directory, with the filename .k5login. For security ++reasons, k5login files must be owned by the local user or by root. ++ + .IP kdc_timesync + If the value of this relation is non-zero (the default), the library + will compute the difference between the system clock and the time +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 750f989..f2a037c 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -222,6 +222,8 @@ typedef INT64_TYPE krb5_int64; + #define KRB5_CONF_IPROP_PORT "iprop_port" + #define KRB5_CONF_IPROP_SLAVE_POLL "iprop_slave_poll" + #define KRB5_CONF_IPROP_LOGFILE "iprop_logfile" ++#define KRB5_CONF_K5LOGIN_AUTHORITATIVE "k5login_authoritative" ++#define KRB5_CONF_K5LOGIN_DIRECTORY "k5login_directory" + #define KRB5_CONF_KADMIND_PORT "kadmind_port" + #define KRB5_CONF_KRB524_SERVER "krb524_server" + #define KRB5_CONF_KDC "kdc" +diff --git a/src/lib/krb5/os/kuserok.c b/src/lib/krb5/os/kuserok.c +index 1bc7505..985bb14 100644 +--- a/src/lib/krb5/os/kuserok.c ++++ b/src/lib/krb5/os/kuserok.c +@@ -48,105 +48,138 @@ + #define FILE_OWNER_OK(UID) ((UID) == 0) + #endif + ++enum result { ACCEPT, REJECT, PASS }; ++ + /* +- * Given a Kerberos principal "principal", and a local username "luser", +- * determine whether user is authorized to login according to the +- * authorization file ("~luser/.k5login" by default). Returns TRUE +- * if authorized, FALSE if not authorized. +- * +- * If there is no account for "luser" on the local machine, returns +- * FALSE. If there is no authorization file, and the given Kerberos +- * name "server" translates to the same name as "luser" (using +- * krb5_aname_to_lname()), returns TRUE. Otherwise, if the authorization file +- * can't be accessed, returns FALSE. Otherwise, the file is read for +- * a matching principal name, instance, and realm. If one is found, +- * returns TRUE, if none is found, returns FALSE. +- * +- * The file entries are in the format produced by krb5_unparse_name(), +- * one entry per line. +- * ++ * Find the k5login filename for luser, either in the user's homedir or in a ++ * configured directory under the username. + */ ++static krb5_error_code ++get_k5login_filename(krb5_context context, const char *luser, ++ const char *homedir, char **filename_out) ++{ ++ krb5_error_code ret; ++ char *dir, *filename; + +-krb5_boolean KRB5_CALLCONV +-krb5_kuserok(krb5_context context, krb5_principal principal, const char *luser) ++ *filename_out = NULL; ++ ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS, ++ KRB5_CONF_K5LOGIN_DIRECTORY, NULL, NULL, &dir); ++ if (ret != 0) ++ return ret; ++ ++ if (dir == NULL) { ++ /* Look in the user's homedir. */ ++ if (asprintf(&filename, "%s/.k5login", homedir) < 0) ++ return ENOMEM; ++ } else { ++ /* Look in the configured directory. */ ++ if (asprintf(&filename, "%s/%s", dir, luser) < 0) ++ ret = ENOMEM; ++ profile_release_string(dir); ++ if (ret) ++ return ret; ++ } ++ *filename_out = filename; ++ return 0; ++} ++ ++/* ++ * Determine whether principal is authorized to log in as luser according to ++ * the user's k5login file. Return ACCEPT if the k5login file authorizes the ++ * principal, PASS if the k5login file does not exist, or REJECT if the k5login ++ * file exists but does not authorize the principal. If k5login files are ++ * configured to be non-authoritative, pass instead of rejecting. ++ */ ++static enum result ++k5login_ok(krb5_context context, krb5_principal principal, const char *luser) + { ++ int authoritative = TRUE; ++ enum result result = REJECT; ++ char *filename = NULL, *princname = NULL; ++ char gobble, *newline, linebuf[BUFSIZ], pwbuf[BUFSIZ]; + struct stat sbuf; +- struct passwd *pwd; +- char pbuf[MAXPATHLEN]; +- krb5_boolean isok = FALSE; +- FILE *fp; +- char kuser[MAX_USERNAME]; +- char *princname; +- char linebuf[BUFSIZ]; +- char *newline; +- int gobble; +- char pwbuf[BUFSIZ]; +- struct passwd pwx; +- int result; +- +- /* no account => no access */ ++ struct passwd pwx, *pwd; ++ FILE *fp = NULL; ++ ++ if (profile_get_boolean(context->profile, KRB5_CONF_LIBDEFAULTS, ++ KRB5_CONF_K5LOGIN_AUTHORITATIVE, NULL, TRUE, ++ &authoritative) != 0) ++ goto cleanup; ++ ++ /* Get the local user's homedir and uid. */ + if (k5_getpwnam_r(luser, &pwx, pwbuf, sizeof(pwbuf), &pwd) != 0) +- return(FALSE); +- result = snprintf(pbuf, sizeof(pbuf), "%s/.k5login", pwd->pw_dir); +- if (SNPRINTF_OVERFLOW(result, sizeof(pbuf))) +- return(FALSE); +- +- 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 */ ++ goto cleanup; ++ ++ if (get_k5login_filename(context, luser, pwd->pw_dir, &filename) != 0) ++ goto cleanup; + +- /* open ~/.k5login */ +- if ((fp = fopen(pbuf, "r")) == NULL) { +- free(princname); +- return(FALSE); ++ if (access(filename, F_OK) != 0) { ++ result = PASS; ++ goto cleanup; + } ++ ++ if (krb5_unparse_name(context, principal, &princname) != 0) ++ goto cleanup; ++ ++ fp = fopen(filename, "r"); ++ if (fp == NULL) ++ goto cleanup; + set_cloexec_file(fp); +- /* +- * For security reasons, the .k5login file must be owned either by +- * the user himself, or by root. Otherwise, don't grant access. +- */ +- if (fstat(fileno(fp), &sbuf)) { +- fclose(fp); +- free(princname); +- return(FALSE); +- } +- if (sbuf.st_uid != pwd->pw_uid && !FILE_OWNER_OK(sbuf.st_uid)) { +- fclose(fp); +- free(princname); +- return(FALSE); +- } + +- /* check each line */ +- while (!isok && (fgets(linebuf, BUFSIZ, fp) != NULL)) { +- /* null-terminate the input string */ +- linebuf[BUFSIZ-1] = '\0'; +- newline = NULL; +- /* nuke the newline if it exists */ +- if ((newline = strchr(linebuf, '\n'))) ++ /* For security reasons, the .k5login file must be owned either by ++ * the user or by root. */ ++ if (fstat(fileno(fp), &sbuf)) ++ goto cleanup; ++ if (sbuf.st_uid != pwd->pw_uid && !FILE_OWNER_OK(sbuf.st_uid)) ++ goto cleanup; ++ ++ /* Check each line. */ ++ while (result != ACCEPT && (fgets(linebuf, sizeof(linebuf), fp) != NULL)) { ++ newline = strrchr(linebuf, '\n'); ++ if (newline != NULL) + *newline = '\0'; +- if (!strcmp(linebuf, princname)) { +- isok = TRUE; +- continue; +- } +- /* clean up the rest of the line if necessary */ +- if (!newline) ++ if (strcmp(linebuf, princname) == 0) ++ result = ACCEPT; ++ /* Clean up the rest of the line if necessary. */ ++ if (newline == NULL) + while (((gobble = getc(fp)) != EOF) && gobble != '\n'); + } ++ ++cleanup: + free(princname); +- fclose(fp); +- return(isok); ++ free(filename); ++ if (fp != NULL) ++ fclose(fp); ++ /* If k5login files are non-authoritative, never reject. */ ++ return (!authoritative && result == REJECT) ? PASS : result; ++} ++ ++/* ++ * Determine whether principal is authorized to log in as luser according to ++ * aname-to-localname translation. Return ACCEPT if principal translates to ++ * luser or PASS if it does not. ++ */ ++static enum result ++an2ln_ok(krb5_context context, krb5_principal principal, const char *luser) ++{ ++ krb5_error_code ret; ++ char kuser[MAX_USERNAME]; ++ ++ ret = krb5_aname_to_localname(context, principal, sizeof(kuser), kuser); ++ if (ret != 0) ++ return PASS; ++ return (strcmp(kuser, luser) == 0) ? ACCEPT : PASS; ++} ++ ++krb5_boolean KRB5_CALLCONV ++krb5_kuserok(krb5_context context, krb5_principal principal, const char *luser) ++{ ++ enum result result; ++ ++ result = k5login_ok(context, principal, luser); ++ if (result == PASS) ++ result = an2ln_ok(context, principal, luser); ++ return (result == ACCEPT) ? TRUE : FALSE; + } + + #else /* _WIN32 */ +commit 6f46ab42b718410aee67a888b3fefe7df8ce2062 +Author: ghudson <ghudson@dc483132-0cff-0310-8789-dd5450dbe970> +Date: Sat Oct 2 11:48:06 2010 +0000 + + ticket: 6792 + + In the krb5_kuserok implementation, fix an unintentional type change + to "gobble" (was an int, was accidentally changed to a char) which + could result in an infinite loop. + + + git-svn-id: svn://anonsvn.mit.edu:/krb5/trunk@24413 dc483132-0cff-0310-8789-dd5450dbe970 + +diff --git a/src/lib/krb5/os/kuserok.c b/src/lib/krb5/os/kuserok.c +index 985bb14..e1619f3 100644 +--- a/src/lib/krb5/os/kuserok.c ++++ b/src/lib/krb5/os/kuserok.c +@@ -93,10 +93,10 @@ get_k5login_filename(krb5_context context, const char *luser, + static enum result + k5login_ok(krb5_context context, krb5_principal principal, const char *luser) + { +- int authoritative = TRUE; ++ int authoritative = TRUE, gobble; + enum result result = REJECT; + char *filename = NULL, *princname = NULL; +- char gobble, *newline, linebuf[BUFSIZ], pwbuf[BUFSIZ]; ++ char *newline, linebuf[BUFSIZ], pwbuf[BUFSIZ]; + struct stat sbuf; + struct passwd pwx, *pwd; + FILE *fp = NULL; |