OSDN Git Service

Merge openssh 7.5p1
[android-x86/external-openssh.git] / auth-options.c
index e387697..57b49f7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.68 2015/07/03 03:43:18 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.72 2016/11/30 02:57:40 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -29,6 +29,7 @@
 #include "ssherr.h"
 #include "log.h"
 #include "canohost.h"
+#include "packet.h"
 #include "sshbuf.h"
 #include "misc.h"
 #include "channels.h"
@@ -75,27 +76,54 @@ auth_clear_options(void)
                free(ce->s);
                free(ce);
        }
-       if (forced_command) {
-               free(forced_command);
-               forced_command = NULL;
-       }
-       if (authorized_principals) {
-               free(authorized_principals);
-               authorized_principals = NULL;
-       }
+       free(forced_command);
+       forced_command = NULL;
+       free(authorized_principals);
+       authorized_principals = NULL;
        forced_tun_device = -1;
        channel_clear_permitted_opens();
 }
 
 /*
+ * Match flag 'opt' in *optsp, and if allow_negate is set then also match
+ * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0
+ * if negated option matches. 
+ * If the option or negated option matches, then *optsp is updated to
+ * point to the first character after the option and, if 'msg' is not NULL
+ * then a message based on it added via auth_debug_add().
+ */
+static int
+match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
+{
+       size_t opt_len = strlen(opt);
+       char *opts = *optsp;
+       int negate = 0;
+
+       if (allow_negate && strncasecmp(opts, "no-", 3) == 0) {
+               opts += 3;
+               negate = 1;
+       }
+       if (strncasecmp(opts, opt, opt_len) == 0) {
+               *optsp = opts + opt_len;
+               if (msg != NULL) {
+                       auth_debug_add("%s %s.", msg,
+                           negate ? "disabled" : "enabled");
+               }
+               return negate ? 0 : 1;
+       }
+       return -1;
+}
+
+/*
  * return 1 if access is granted, 0 if not.
  * side effect: sets key option flags
  */
 int
 auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
 {
+       struct ssh *ssh = active_state;         /* XXX */
        const char *cp;
-       int i;
+       int i, r;
 
        /* reset options */
        auth_clear_options();
@@ -104,52 +132,48 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                return 1;
 
        while (*opts && *opts != ' ' && *opts != '\t') {
-               cp = "cert-authority";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       key_is_cert_authority = 1;
-                       opts += strlen(cp);
+               if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) {
+                       key_is_cert_authority = r;
                        goto next_option;
                }
-               cp = "no-port-forwarding";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       auth_debug_add("Port forwarding disabled.");
+               if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) {
+                       auth_debug_add("Key is restricted.");
                        no_port_forwarding_flag = 1;
-                       opts += strlen(cp);
+                       no_agent_forwarding_flag = 1;
+                       no_x11_forwarding_flag = 1;
+                       no_pty_flag = 1;
+                       no_user_rc = 1;
                        goto next_option;
                }
-               cp = "no-agent-forwarding";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       auth_debug_add("Agent forwarding disabled.");
-                       no_agent_forwarding_flag = 1;
-                       opts += strlen(cp);
+               if ((r = match_flag("port-forwarding", 1, &opts,
+                   "Port forwarding")) != -1) {
+                       no_port_forwarding_flag = r != 1;
                        goto next_option;
                }
-               cp = "no-X11-forwarding";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       auth_debug_add("X11 forwarding disabled.");
-                       no_x11_forwarding_flag = 1;
-                       opts += strlen(cp);
+               if ((r = match_flag("agent-forwarding", 1, &opts,
+                   "Agent forwarding")) != -1) {
+                       no_agent_forwarding_flag = r != 1;
                        goto next_option;
                }
-               cp = "no-pty";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       auth_debug_add("Pty allocation disabled.");
-                       no_pty_flag = 1;
-                       opts += strlen(cp);
+               if ((r = match_flag("x11-forwarding", 1, &opts,
+                   "X11 forwarding")) != -1) {
+                       no_x11_forwarding_flag = r != 1;
                        goto next_option;
                }
-               cp = "no-user-rc";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       auth_debug_add("User rc file execution disabled.");
-                       no_user_rc = 1;
-                       opts += strlen(cp);
+               if ((r = match_flag("pty", 1, &opts,
+                   "PTY allocation")) != -1) {
+                       no_pty_flag = r != 1;
+                       goto next_option;
+               }
+               if ((r = match_flag("user-rc", 1, &opts,
+                   "User rc execution")) != -1) {
+                       no_user_rc = r != 1;
                        goto next_option;
                }
                cp = "command=\"";
                if (strncasecmp(opts, cp, strlen(cp)) == 0) {
                        opts += strlen(cp);
-                       if (forced_command != NULL)
-                               free(forced_command);
+                       free(forced_command);
                        forced_command = xmalloc(strlen(opts) + 1);
                        i = 0;
                        while (*opts) {
@@ -179,8 +203,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                cp = "principals=\"";
                if (strncasecmp(opts, cp, strlen(cp)) == 0) {
                        opts += strlen(cp);
-                       if (authorized_principals != NULL)
-                               free(authorized_principals);
+                       free(authorized_principals);
                        authorized_principals = xmalloc(strlen(opts) + 1);
                        i = 0;
                        while (*opts) {
@@ -252,9 +275,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                }
                cp = "from=\"";
                if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       const char *remote_ip = get_remote_ipaddr();
-                       const char *remote_host = get_canonical_hostname(
-                           options.use_dns);
+                       const char *remote_ip = ssh_remote_ipaddr(ssh);
+                       const char *remote_host = auth_get_canonical_hostname(
+                           ssh, options.use_dns);
                        char *patterns = xmalloc(strlen(opts) + 1);
 
                        opts += strlen(cp);
@@ -436,6 +459,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
     char **cert_forced_command,
     int *cert_source_address_done)
 {
+       struct ssh *ssh = active_state;         /* XXX */
        char *command, *allowed;
        const char *remote_ip;
        char *name = NULL;
@@ -509,7 +533,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
                                        free(allowed);
                                        goto out;
                                }
-                               remote_ip = get_remote_ipaddr();
+                               remote_ip = ssh_remote_ipaddr(ssh);
                                result = addr_match_cidr_list(remote_ip,
                                    allowed);
                                free(allowed);
@@ -566,8 +590,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
                free(*cert_forced_command);
                *cert_forced_command = NULL;
        }
-       if (name != NULL)
-               free(name);
+       free(name);
        sshbuf_free(data);
        sshbuf_free(c);
        return ret;
@@ -578,7 +601,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
  * options so this must be called after auth_parse_options().
  */
 int
-auth_cert_options(struct sshkey *k, struct passwd *pw)
+auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason)
 {
        int cert_no_port_forwarding_flag = 1;
        int cert_no_agent_forwarding_flag = 1;
@@ -588,6 +611,8 @@ auth_cert_options(struct sshkey *k, struct passwd *pw)
        char *cert_forced_command = NULL;
        int cert_source_address_done = 0;
 
+       *reason = "invalid certificate options";
+
        /* Separate options and extensions for v01 certs */
        if (parse_option_list(k->cert->critical, pw,
            OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
@@ -609,12 +634,24 @@ auth_cert_options(struct sshkey *k, struct passwd *pw)
        no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
        no_pty_flag |= cert_no_pty_flag;
        no_user_rc |= cert_no_user_rc;
-       /* CA-specified forced command supersedes key option */
-       if (cert_forced_command != NULL) {
-               if (forced_command != NULL)
+       /*
+        * Only permit both CA and key option forced-command if they match.
+        * Otherwise refuse the certificate.
+        */
+       if (cert_forced_command != NULL && forced_command != NULL) {
+               if (strcmp(forced_command, cert_forced_command) == 0) {
                        free(forced_command);
+                       forced_command = cert_forced_command;
+               } else {
+                       *reason = "certificate and key options forced command "
+                           "do not match";
+                       free(cert_forced_command);
+                       return -1;
+               }
+       } else if (cert_forced_command != NULL)
                forced_command = cert_forced_command;
-       }
+       /* success */
+       *reason = NULL;
        return 0;
 }