krb5/krb5-trunk-k5login.patch
Nalin Dahyabhai 0d4651fac9 - pull down patches from trunk to implement k5login_authoritative and
k5login_directory settings for krb5.conf (#539423)
2010-10-04 15:34:24 -04:00

334 lines
12 KiB
Diff

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;