]> git.ipfire.org Git - people/arne_f/ipfire-3.x.git/blobdiff - openssh/patches/openssh-5.8p2-force_krb.patch
openssh: Update to 5.9p1.
[people/arne_f/ipfire-3.x.git] / openssh / patches / openssh-5.8p2-force_krb.patch
diff --git a/openssh/patches/openssh-5.8p2-force_krb.patch b/openssh/patches/openssh-5.8p2-force_krb.patch
new file mode 100644 (file)
index 0000000..1842ce4
--- /dev/null
@@ -0,0 +1,288 @@
+diff -up openssh-5.8p2/gss-serv-krb5.c.force_krb openssh-5.8p2/gss-serv-krb5.c
+--- openssh-5.8p2/gss-serv-krb5.c.force_krb    2006-09-01 07:38:36.000000000 +0200
++++ openssh-5.8p2/gss-serv-krb5.c      2011-05-19 03:41:45.801109545 +0200
+@@ -32,7 +32,9 @@
+ #include <sys/types.h>
+ #include <stdarg.h>
++#include <stdio.h>
+ #include <string.h>
++#include <unistd.h>
+ #include "xmalloc.h"
+ #include "key.h"
+@@ -40,12 +42,11 @@
+ #include "auth.h"
+ #include "log.h"
+ #include "servconf.h"
++#include "misc.h"
+ #include "buffer.h"
+ #include "ssh-gss.h"
+-extern ServerOptions options;
+-
+ #ifdef HEIMDAL
+ # include <krb5.h>
+ #else
+@@ -56,6 +57,16 @@ extern ServerOptions options;
+ # endif
+ #endif
++extern Authctxt *the_authctxt;
++extern ServerOptions options;
++
++/* all commands are allowed by default */
++char **k5users_allowed_cmds = NULL;
++
++static int ssh_gssapi_k5login_exists();
++static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *,
++    int);
++
+ static krb5_context krb_context = NULL;
+ /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
+@@ -83,10 +94,11 @@ ssh_gssapi_krb5_init(void)
+  */
+ static int
+-ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
++ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *luser)
+ {
+       krb5_principal princ;
+       int retval;
++      int k5login_exists;
+       if (ssh_gssapi_krb5_init() == 0)
+               return 0;
+@@ -97,10 +109,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
+                   krb5_get_err_text(krb_context, retval));
+               return 0;
+       }
+-      if (krb5_kuserok(krb_context, princ, name)) {
++      /* krb5_kuserok() returns 1 if .k5login DNE and this is self-login.
++       * We have to make sure to check .k5users in that case. */
++      k5login_exists = ssh_gssapi_k5login_exists();
++      /* NOTE: .k5login and .k5users must opened as root, not the user,
++       * because if they are on a krb5-protected filesystem, user credentials
++       * to access these files aren't available yet. */
++      if (krb5_kuserok(krb_context, princ, luser) && k5login_exists) {
+               retval = 1;
+               logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
+-                  name, (char *)client->displayname.value);
++                  luser, (char *)client->displayname.value);
++      } else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value,
++              luser, k5login_exists)) {
++              retval = 1;
++              logit("Authorized to %s, krb5 principal %s "
++                  "(ssh_gssapi_krb5_cmdok)",
++                  luser, (char *)client->displayname.value);
+       } else
+               retval = 0;
+@@ -108,6 +132,134 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
+       return retval;
+ }
++/* Test for existence of .k5login.
++ * We need this as part of our .k5users check, because krb5_kuserok()
++ * returns success if .k5login DNE and user is logging in as himself.
++ * With .k5login absent and .k5users present, we don't want absence
++ * of .k5login to authorize self-login.  (absence of both is required)
++ * Returns 1 if .k5login is available, 0 otherwise.
++ */
++static int
++ssh_gssapi_k5login_exists()
++{
++      char file[MAXPATHLEN];
++      struct passwd *pw = the_authctxt->pw;
++
++      snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
++      return access(file, F_OK) == 0;
++}
++
++/* check .k5users for login or command authorization
++ * Returns 1 if principal is authorized, 0 otherwise.
++ * If principal is authorized, (global) k5users_allowed_cmds may be populated.
++ */
++static int
++ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
++    const char *luser, int k5login_exists)
++{
++      FILE *fp;
++      char file[MAXPATHLEN];
++      char line[BUFSIZ];
++      char kuser[65]; /* match krb5_kuserok() */
++      struct stat st;
++      struct passwd *pw = the_authctxt->pw;
++      int found_principal = 0;
++      int ncommands = 0, allcommands = 0;
++      u_long linenum;
++
++      snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir);
++      /* If both .k5login and .k5users DNE, self-login is ok. */
++      if (!k5login_exists && (access(file, F_OK) == -1)) {
++              return (krb5_aname_to_localname(krb_context, principal,
++                  sizeof(kuser), kuser) == 0) &&
++                  (strcmp(kuser, luser) == 0);
++      }
++      if ((fp = fopen(file, "r")) == NULL) {
++              int saved_errno = errno;
++              /* 2nd access check to ease debugging if file perms are wrong.
++               * But we don't want to report this if .k5users simply DNE. */
++              if (access(file, F_OK) == 0) {
++                      logit("User %s fopen %s failed: %s",
++                          pw->pw_name, file, strerror(saved_errno));
++              }
++              return 0;
++      }
++      /* .k5users must be owned either by the user or by root */
++      if (fstat(fileno(fp), &st) == -1) {
++              /* can happen, but very wierd error so report it */
++              logit("User %s fstat %s failed: %s",
++                  pw->pw_name, file, strerror(errno));
++              fclose(fp);
++              return 0;
++      }
++      if (!(st.st_uid == pw->pw_uid || st.st_uid == 0)) {
++              logit("User %s %s is not owned by root or user",
++                  pw->pw_name, file);
++              fclose(fp);
++              return 0;
++      }
++      /* .k5users must be a regular file.  krb5_kuserok() doesn't do this
++        * check, but we don't want to be deficient if they add a check. */
++      if (!S_ISREG(st.st_mode)) {
++              logit("User %s %s is not a regular file", pw->pw_name, file);
++              fclose(fp);
++              return 0;
++      }
++      /* file exists; initialize k5users_allowed_cmds (to none!) */
++      k5users_allowed_cmds = xcalloc(++ncommands,
++          sizeof(*k5users_allowed_cmds));
++
++      /* Check each line.  ksu allows unlimited length lines.  We don't. */
++      while (!allcommands && read_keyfile_line(fp, file, line, sizeof(line),
++          &linenum) != -1) {
++              char *token;
++
++              /* we parse just like ksu, even though we could do better */
++              token = strtok(line, " \t\n");
++              if (strcmp(name, token) == 0) {
++                      /* we matched on client principal */
++                      found_principal = 1;
++                      if ((token = strtok(NULL, " \t\n")) == NULL) {
++                              /* only shell is allowed */
++                              k5users_allowed_cmds[ncommands-1] =
++                                  xstrdup(pw->pw_shell);
++                              k5users_allowed_cmds =
++                                  xrealloc(k5users_allowed_cmds, ++ncommands,
++                                      sizeof(*k5users_allowed_cmds));
++                              break;
++                      }
++                      /* process the allowed commands */
++                      while (token) {
++                              if (strcmp(token, "*") == 0) {
++                                      allcommands = 1;
++                                      break;
++                              }
++                              k5users_allowed_cmds[ncommands-1] =
++                                  xstrdup(token);
++                              k5users_allowed_cmds =
++                                  xrealloc(k5users_allowed_cmds, ++ncommands,
++                                      sizeof(*k5users_allowed_cmds));
++                              token = strtok(NULL, " \t\n");
++                      }
++              }
++       }
++      if (k5users_allowed_cmds) {
++              /* terminate vector */
++              k5users_allowed_cmds[ncommands-1] = NULL;
++              /* if all commands are allowed, free vector */
++              if (allcommands) {
++                      int i;
++                      for (i = 0; i < ncommands; i++) {
++                              free(k5users_allowed_cmds[i]);
++                      }
++                      free(k5users_allowed_cmds);
++                      k5users_allowed_cmds = NULL;
++              }
++      }
++      fclose(fp);
++      return found_principal;
++}
++ 
+ /* This writes out any forwarded credentials from the structure populated
+  * during userauth. Called after we have setuid to the user */
+diff -up openssh-5.8p2/session.c.force_krb openssh-5.8p2/session.c
+--- openssh-5.8p2/session.c.force_krb  2011-05-19 03:41:41.000000000 +0200
++++ openssh-5.8p2/session.c    2011-05-19 03:43:32.437173662 +0200
+@@ -816,6 +816,29 @@ do_exec(Session *s, const char *command)
+               debug("Forced command (key option) '%.900s'", command);
+       }
++#ifdef GSSAPI
++#ifdef KRB5 /* k5users_allowed_cmds only available w/ GSSAPI+KRB5 */
++      else if (k5users_allowed_cmds) {
++              const char *match = command;
++              int allowed = 0, i = 0;
++ 
++              if (!match)
++                      match = s->pw->pw_shell;
++              while (k5users_allowed_cmds[i]) {
++                      if (strcmp(match, k5users_allowed_cmds[i++]) == 0) {
++                              debug("Allowed command '%.900s'", match);
++                              allowed = 1;
++                              break;
++                      }
++              }
++              if (!allowed) {
++                      debug("command '%.900s' not allowed", match);
++                      return 1;
++              }
++      }
++#endif
++#endif
++
+ #ifdef SSH_AUDIT_EVENTS
+       if (s->command != NULL || s->command_handle != -1)
+               fatal("do_exec: command already set");
+diff -up openssh-5.8p2/sshd.8.force_krb openssh-5.8p2/sshd.8
+--- openssh-5.8p2/sshd.8.force_krb     2011-05-19 03:41:30.582114401 +0200
++++ openssh-5.8p2/sshd.8       2011-05-19 03:41:46.159106308 +0200
+@@ -320,6 +320,7 @@ Finally, the server and the client enter
+ The client tries to authenticate itself using
+ host-based authentication,
+ public key authentication,
++GSSAPI authentication,
+ challenge-response authentication,
+ or password authentication.
+ .Pp
+@@ -788,6 +789,12 @@ This file is used in exactly the same wa
+ but allows host-based authentication without permitting login with
+ rlogin/rsh.
+ .Pp
++.It Pa ~/.k5login
++.It Pa ~/.k5users
++These files enforce GSSAPI/Kerberos authentication access control.
++Further details are described in
++.Xr ksu 1 .
++.Pp
+ .It Pa ~/.ssh/
+ This directory is the default location for all user-specific configuration
+ and authentication information.
+diff -up openssh-5.8p2/ssh-gss.h.force_krb openssh-5.8p2/ssh-gss.h
+--- openssh-5.8p2/ssh-gss.h.force_krb  2007-06-12 15:40:39.000000000 +0200
++++ openssh-5.8p2/ssh-gss.h    2011-05-19 03:41:46.302234118 +0200
+@@ -48,6 +48,10 @@
+ #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+ #endif /* GSS_C_NT_... */
+ #endif /* !HEIMDAL */
++
++/* .k5users support */
++extern char **k5users_allowed_cmds;
++
+ #endif /* KRB5 */
+ /* draft-ietf-secsh-gsskeyex-06 */