[BACK]Return to auth-options.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / crypto / external / bsd / openssh / dist

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/crypto/external/bsd/openssh/dist/auth-options.c between version 1.16 and 1.16.2.2

version 1.16, 2017/10/07 19:39:19 version 1.16.2.2, 2018/09/06 06:51:33
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
 /* $OpenBSD: auth-options.c,v 1.74 2017/09/12 06:32:07 djm Exp $ */  /* $OpenBSD: auth-options.c,v 1.83 2018/06/19 02:59:41 djm Exp $ */
   
 /*  /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>   * Copyright (c) 2018 Damien Miller <djm@mindrot.org>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland   *
  *                    All rights reserved   * Permission to use, copy, modify, and distribute this software for any
  * As far as I am concerned, the code I have written for this software   * purpose with or without fee is hereby granted, provided that the above
  * can be used freely for any purpose.  Any derived versions of this   * copyright notice and this permission notice appear in all copies.
  * software must be clearly marked as such, and if the derived work is   *
  * incompatible with the protocol description in the RFC file, it must be   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  * called by a name other than "ssh" or "Secure Shell".   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */   */
   
 #include "includes.h"  #include "includes.h"
Line 23  __RCSID("$NetBSD$");
Line 28  __RCSID("$NetBSD$");
 #include <stdio.h>  #include <stdio.h>
 #include <stdarg.h>  #include <stdarg.h>
 #include <time.h>  #include <time.h>
   #include <ctype.h>
   #include <limits.h>
   
 #include "key.h"        /* XXX for typedef */  
 #include "buffer.h"     /* XXX for typedef */  
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "match.h"  
 #include "ssherr.h"  #include "ssherr.h"
 #include "log.h"  #include "log.h"
 #include "canohost.h"  
 #include "packet.h"  
 #include "sshbuf.h"  #include "sshbuf.h"
 #include "misc.h"  #include "misc.h"
 #include "channels.h"  
 #include "servconf.h"  
 #include "sshkey.h"  #include "sshkey.h"
   #include "match.h"
   #include "ssh2.h"
 #include "auth-options.h"  #include "auth-options.h"
 #include "hostfile.h"  
 #include "auth.h"  
   
 /* Flags set authorized_keys flags */  
 int no_port_forwarding_flag = 0;  
 int no_agent_forwarding_flag = 0;  
 int no_x11_forwarding_flag = 0;  
 int no_pty_flag = 0;  
 int no_user_rc = 0;  
 int key_is_cert_authority = 0;  
   
 /* "command=" option. */  
 char *forced_command = NULL;  
   
 /* "environment=" options. */  
 struct envstring *custom_environment = NULL;  
   
 /* "tunnel=" option. */  
 int forced_tun_device = -1;  
   
 /* "principals=" option. */  
 char *authorized_principals = NULL;  
   
 extern ServerOptions options;  
   
 /* XXX refactor to be stateless */  
   
 void  
 auth_clear_options(void)  
 {  
         struct ssh *ssh = active_state;         /* XXX */  
   
         no_agent_forwarding_flag = 0;  
         no_port_forwarding_flag = 0;  
         no_pty_flag = 0;  
         no_x11_forwarding_flag = 0;  
         no_user_rc = 0;  
         key_is_cert_authority = 0;  
         while (custom_environment) {  
                 struct envstring *ce = custom_environment;  
                 custom_environment = ce->next;  
                 free(ce->s);  
                 free(ce);  
         }  
         free(forced_command);  
         forced_command = NULL;  
         free(authorized_principals);  
         authorized_principals = NULL;  
         forced_tun_device = -1;  
         channel_clear_permitted_opens(ssh);  
 }  
   
 /*  /*
  * Match flag 'opt' in *optsp, and if allow_negate is set then also match   * 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   * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0
  * if negated option matches.   * if negated option matches.
  * If the option or negated option matches, then *optsp is updated to   * 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   * point to the first character after the option.
  * then a message based on it added via auth_debug_add().  
  */   */
 static int  static int
 match_flag(const char *opt, int allow_negate, const char **optsp, const char *msg)  opt_flag(const char *opt, int allow_negate, const char **optsp)
 {  {
         size_t opt_len = strlen(opt);          size_t opt_len = strlen(opt);
         const char *opts = *optsp;          const char *opts = *optsp;
Line 111  match_flag(const char *opt, int allow_ne
Line 61  match_flag(const char *opt, int allow_ne
         }          }
         if (strncasecmp(opts, opt, opt_len) == 0) {          if (strncasecmp(opts, opt, opt_len) == 0) {
                 *optsp = opts + opt_len;                  *optsp = opts + opt_len;
                 if (msg != NULL) {  
                         auth_debug_add("%s %s.", msg,  
                             negate ? "disabled" : "enabled");  
                 }  
                 return negate ? 0 : 1;                  return negate ? 0 : 1;
         }          }
         return -1;          return -1;
 }  }
   
 /*  static char *
  * return 1 if access is granted, 0 if not.  opt_dequote(const char **sp, const char **errstrp)
  * side effect: sets key option flags  
  * XXX remove side effects; fill structure instead.  
  */  
 int  
 auth_parse_options(struct passwd *pw, const char *opts, const char *file,  
     u_long linenum)  
 {  {
         struct ssh *ssh = active_state;         /* XXX */          const char *s = *sp;
         const char *cp;          char *ret;
         int i, r;          size_t i;
   
         /* reset options */          *errstrp = NULL;
         auth_clear_options();          if (*s != '"') {
                   *errstrp = "missing start quote";
                   return NULL;
           }
           s++;
           if ((ret = malloc(strlen((s)) + 1)) == NULL) {
                   *errstrp = "memory allocation failed";
                   return NULL;
           }
           for (i = 0; *s != '\0' && *s != '"';) {
                   if (s[0] == '\\' && s[1] == '"')
                           s++;
                   ret[i++] = *s++;
           }
           if (*s == '\0') {
                   *errstrp = "missing end quote";
                   free(ret);
                   return NULL;
           }
           ret[i] = '\0';
           s++;
           *sp = s;
           return ret;
   }
   
         if (!opts)  static int
   opt_match(const char **opts, const char *term)
   {
           if (strncasecmp((*opts), term, strlen(term)) == 0 &&
               (*opts)[strlen(term)] == '=') {
                   *opts += strlen(term) + 1;
                 return 1;                  return 1;
   
         while (*opts && *opts != ' ' && *opts != '\t') {  
                 if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) {  
                         key_is_cert_authority = r;  
                         goto next_option;  
                 }  
                 if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) {  
                         auth_debug_add("Key is restricted.");  
                         no_port_forwarding_flag = 1;  
                         no_agent_forwarding_flag = 1;  
                         no_x11_forwarding_flag = 1;  
                         no_pty_flag = 1;  
                         no_user_rc = 1;  
                         goto next_option;  
                 }  
                 if ((r = match_flag("port-forwarding", 1, &opts,  
                     "Port forwarding")) != -1) {  
                         no_port_forwarding_flag = r != 1;  
                         goto next_option;  
                 }  
                 if ((r = match_flag("agent-forwarding", 1, &opts,  
                     "Agent forwarding")) != -1) {  
                         no_agent_forwarding_flag = r != 1;  
                         goto next_option;  
                 }  
                 if ((r = match_flag("x11-forwarding", 1, &opts,  
                     "X11 forwarding")) != -1) {  
                         no_x11_forwarding_flag = r != 1;  
                         goto next_option;  
                 }  
                 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);  
                         free(forced_command);  
                         forced_command = xmalloc(strlen(opts) + 1);  
                         i = 0;  
                         while (*opts) {  
                                 if (*opts == '"')  
                                         break;  
                                 if (*opts == '\\' && opts[1] == '"') {  
                                         opts += 2;  
                                         forced_command[i++] = '"';  
                                         continue;  
                                 }  
                                 forced_command[i++] = *opts++;  
                         }  
                         if (!*opts) {  
                                 debug("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 auth_debug_add("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 free(forced_command);  
                                 forced_command = NULL;  
                                 goto bad_option;  
                         }  
                         forced_command[i] = '\0';  
                         auth_debug_add("Forced command.");  
                         opts++;  
                         goto next_option;  
                 }  
                 cp = "principals=\"";  
                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {  
                         opts += strlen(cp);  
                         free(authorized_principals);  
                         authorized_principals = xmalloc(strlen(opts) + 1);  
                         i = 0;  
                         while (*opts) {  
                                 if (*opts == '"')  
                                         break;  
                                 if (*opts == '\\' && opts[1] == '"') {  
                                         opts += 2;  
                                         authorized_principals[i++] = '"';  
                                         continue;  
                                 }  
                                 authorized_principals[i++] = *opts++;  
                         }  
                         if (!*opts) {  
                                 debug("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 auth_debug_add("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 free(authorized_principals);  
                                 authorized_principals = NULL;  
                                 goto bad_option;  
                         }  
                         authorized_principals[i] = '\0';  
                         auth_debug_add("principals: %.900s",  
                             authorized_principals);  
                         opts++;  
                         goto next_option;  
                 }  
                 cp = "environment=\"";  
                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {  
                         char *s;  
                         struct envstring *new_envstring;  
   
                         opts += strlen(cp);  
                         s = xmalloc(strlen(opts) + 1);  
                         i = 0;  
                         while (*opts) {  
                                 if (*opts == '"')  
                                         break;  
                                 if (*opts == '\\' && opts[1] == '"') {  
                                         opts += 2;  
                                         s[i++] = '"';  
                                         continue;  
                                 }  
                                 s[i++] = *opts++;  
                         }  
                         if (!*opts) {  
                                 debug("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 auth_debug_add("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 free(s);  
                                 goto bad_option;  
                         }  
                         s[i] = '\0';  
                         opts++;  
                         if (options.permit_user_env) {  
                                 auth_debug_add("Adding to environment: "  
                                     "%.900s", s);  
                                 debug("Adding to environment: %.900s", s);  
                                 new_envstring = xcalloc(1,  
                                     sizeof(*new_envstring));  
                                 new_envstring->s = s;  
                                 new_envstring->next = custom_environment;  
                                 custom_environment = new_envstring;  
                                 s = NULL;  
                         }  
                         free(s);  
                         goto next_option;  
                 }  
                 cp = "from=\"";  
                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {  
                         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);  
                         i = 0;  
                         while (*opts) {  
                                 if (*opts == '"')  
                                         break;  
                                 if (*opts == '\\' && opts[1] == '"') {  
                                         opts += 2;  
                                         patterns[i++] = '"';  
                                         continue;  
                                 }  
                                 patterns[i++] = *opts++;  
                         }  
                         if (!*opts) {  
                                 debug("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 auth_debug_add("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 free(patterns);  
                                 goto bad_option;  
                         }  
                         patterns[i] = '\0';  
                         opts++;  
                         switch (match_host_and_ip(remote_host, remote_ip,  
                             patterns)) {  
                         case 1:  
                                 free(patterns);  
                                 /* Host name matches. */  
                                 goto next_option;  
                         case -1:  
                                 debug("%.100s, line %lu: invalid criteria",  
                                     file, linenum);  
                                 auth_debug_add("%.100s, line %lu: "  
                                     "invalid criteria", file, linenum);  
                                 /* FALLTHROUGH */  
                         case 0:  
                                 free(patterns);  
                                 logit("Authentication tried for %.100s with "  
                                     "correct key but not from a permitted "  
                                     "host (host=%.200s, ip=%.200s).",  
                                     pw->pw_name, remote_host, remote_ip);  
                                 auth_debug_add("Your host '%.200s' is not "  
                                     "permitted to use this key for login.",  
                                     remote_host);  
                                 break;  
                         }  
                         /* deny access */  
                         return 0;  
                 }  
                 cp = "permitopen=\"";  
                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {  
                         char *host, *p;  
                         int port;  
                         char *patterns = xmalloc(strlen(opts) + 1);  
   
                         opts += strlen(cp);  
                         i = 0;  
                         while (*opts) {  
                                 if (*opts == '"')  
                                         break;  
                                 if (*opts == '\\' && opts[1] == '"') {  
                                         opts += 2;  
                                         patterns[i++] = '"';  
                                         continue;  
                                 }  
                                 patterns[i++] = *opts++;  
                         }  
                         if (!*opts) {  
                                 debug("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 auth_debug_add("%.100s, line %lu: missing "  
                                     "end quote", file, linenum);  
                                 free(patterns);  
                                 goto bad_option;  
                         }  
                         patterns[i] = '\0';  
                         opts++;  
                         p = patterns;  
                         /* XXX - add streamlocal support */  
                         host = hpdelim(&p);  
                         if (host == NULL || strlen(host) >= NI_MAXHOST) {  
                                 debug("%.100s, line %lu: Bad permitopen "  
                                     "specification <%.100s>", file, linenum,  
                                     patterns);  
                                 auth_debug_add("%.100s, line %lu: "  
                                     "Bad permitopen specification", file,  
                                     linenum);  
                                 free(patterns);  
                                 goto bad_option;  
                         }  
                         host = cleanhostname(host);  
                         if (p == NULL || (port = permitopen_port(p)) < 0) {  
                                 debug("%.100s, line %lu: Bad permitopen port "  
                                     "<%.100s>", file, linenum, p ? p : "");  
                                 auth_debug_add("%.100s, line %lu: "  
                                     "Bad permitopen port", file, linenum);  
                                 free(patterns);  
                                 goto bad_option;  
                         }  
                         if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)  
                                 channel_add_permitted_opens(ssh, host, port);  
                         free(patterns);  
                         goto next_option;  
                 }  
                 cp = "tunnel=\"";  
                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {  
                         char *tun = NULL;  
                         opts += strlen(cp);  
                         tun = xmalloc(strlen(opts) + 1);  
                         i = 0;  
                         while (*opts) {  
                                 if (*opts == '"')  
                                         break;  
                                 tun[i++] = *opts++;  
                         }  
                         if (!*opts) {  
                                 debug("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 auth_debug_add("%.100s, line %lu: missing end quote",  
                                     file, linenum);  
                                 free(tun);  
                                 forced_tun_device = -1;  
                                 goto bad_option;  
                         }  
                         tun[i] = '\0';  
                         forced_tun_device = a2tun(tun, NULL);  
                         free(tun);  
                         if (forced_tun_device == SSH_TUNID_ERR) {  
                                 debug("%.100s, line %lu: invalid tun device",  
                                     file, linenum);  
                                 auth_debug_add("%.100s, line %lu: invalid tun device",  
                                     file, linenum);  
                                 forced_tun_device = -1;  
                                 goto bad_option;  
                         }  
                         auth_debug_add("Forced tun device: %d", forced_tun_device);  
                         opts++;  
                         goto next_option;  
                 }  
 next_option:  
                 /*  
                  * Skip the comma, and move to the next option  
                  * (or break out if there are no more).  
                  */  
                 if (!*opts)  
                         fatal("Bugs in auth-options.c option processing.");  
                 if (*opts == ' ' || *opts == '\t')  
                         break;          /* End of options. */  
                 if (*opts != ',')  
                         goto bad_option;  
                 opts++;  
                 /* Process the next option. */  
         }          }
           return 0;
   }
   
         /* grant access */  static int
         return 1;  dup_strings(char ***dstp, size_t *ndstp, char **src, size_t nsrc)
   {
           char **dst;
           size_t i, j;
   
 bad_option:          *dstp = NULL;
         logit("Bad options in %.100s file, line %lu: %.50s",          *ndstp = 0;
             file, linenum, opts);          if (nsrc == 0)
         auth_debug_add("Bad options in %.100s file, line %lu: %.50s",                  return 0;
             file, linenum, opts);  
   
         /* deny access */          if ((dst = calloc(nsrc, sizeof(*src))) == NULL)
                   return -1;
           for (i = 0; i < nsrc; i++) {
                   if ((dst[i] = strdup(src[i])) == NULL) {
                           for (j = 0; j < i; j++)
                                   free(dst[j]);
                           free(dst);
                           return -1;
                   }
           }
           /* success */
           *dstp = dst;
           *ndstp = nsrc;
         return 0;          return 0;
 }  }
   
 #define OPTIONS_CRITICAL        1  #define OPTIONS_CRITICAL        1
 #define OPTIONS_EXTENSIONS      2  #define OPTIONS_EXTENSIONS      2
 static int  static int
 parse_option_list(struct sshbuf *oblob, struct passwd *pw,  cert_option_list(struct sshauthopt *opts, struct sshbuf *oblob,
     u_int which, int crit,      u_int which, int crit)
     int *cert_no_port_forwarding_flag,  
     int *cert_no_agent_forwarding_flag,  
     int *cert_no_x11_forwarding_flag,  
     int *cert_no_pty_flag,  
     int *cert_no_user_rc,  
     char **cert_forced_command,  
     int *cert_source_address_done)  
 {  {
         struct ssh *ssh = active_state;         /* XXX */  
         char *command, *allowed;          char *command, *allowed;
         const char *remote_ip;  
         char *name = NULL;          char *name = NULL;
         struct sshbuf *c = NULL, *data = NULL;          struct sshbuf *c = NULL, *data = NULL;
         int r, ret = -1, result, found;          int r, ret = -1, found;
   
         if ((c = sshbuf_fromb(oblob)) == NULL) {          if ((c = sshbuf_fromb(oblob)) == NULL) {
                 error("%s: sshbuf_fromb failed", __func__);                  error("%s: sshbuf_fromb failed", __func__);
Line 493  parse_option_list(struct sshbuf *oblob, 
Line 167  parse_option_list(struct sshbuf *oblob, 
                 found = 0;                  found = 0;
                 if ((which & OPTIONS_EXTENSIONS) != 0) {                  if ((which & OPTIONS_EXTENSIONS) != 0) {
                         if (strcmp(name, "permit-X11-forwarding") == 0) {                          if (strcmp(name, "permit-X11-forwarding") == 0) {
                                 *cert_no_x11_forwarding_flag = 0;                                  opts->permit_x11_forwarding_flag = 1;
                                 found = 1;                                  found = 1;
                         } else if (strcmp(name,                          } else if (strcmp(name,
                             "permit-agent-forwarding") == 0) {                              "permit-agent-forwarding") == 0) {
                                 *cert_no_agent_forwarding_flag = 0;                                  opts->permit_agent_forwarding_flag = 1;
                                 found = 1;                                  found = 1;
                         } else if (strcmp(name,                          } else if (strcmp(name,
                             "permit-port-forwarding") == 0) {                              "permit-port-forwarding") == 0) {
                                 *cert_no_port_forwarding_flag = 0;                                  opts->permit_port_forwarding_flag = 1;
                                 found = 1;                                  found = 1;
                         } else if (strcmp(name, "permit-pty") == 0) {                          } else if (strcmp(name, "permit-pty") == 0) {
                                 *cert_no_pty_flag = 0;                                  opts->permit_pty_flag = 1;
                                 found = 1;                                  found = 1;
                         } else if (strcmp(name, "permit-user-rc") == 0) {                          } else if (strcmp(name, "permit-user-rc") == 0) {
                                 *cert_no_user_rc = 0;                                  opts->permit_user_rc = 1;
                                 found = 1;                                  found = 1;
                         }                          }
                 }                  }
Line 519  parse_option_list(struct sshbuf *oblob, 
Line 193  parse_option_list(struct sshbuf *oblob, 
                                             "section: %s", name, ssh_err(r));                                              "section: %s", name, ssh_err(r));
                                         goto out;                                          goto out;
                                 }                                  }
                                 if (*cert_forced_command != NULL) {                                  if (opts->force_command != NULL) {
                                         error("Certificate has multiple "                                          error("Certificate has multiple "
                                             "force-command options");                                              "force-command options");
                                         free(command);                                          free(command);
                                         goto out;                                          goto out;
                                 }                                  }
                                 *cert_forced_command = command;                                  opts->force_command = command;
                                 found = 1;                                  found = 1;
                         }                          }
                         if (strcmp(name, "source-address") == 0) {                          if (strcmp(name, "source-address") == 0) {
Line 535  parse_option_list(struct sshbuf *oblob, 
Line 209  parse_option_list(struct sshbuf *oblob, 
                                             "section: %s", name, ssh_err(r));                                              "section: %s", name, ssh_err(r));
                                         goto out;                                          goto out;
                                 }                                  }
                                 if ((*cert_source_address_done)++) {                                  if (opts->required_from_host_cert != NULL) {
                                         error("Certificate has multiple "                                          error("Certificate has multiple "
                                             "source-address options");                                              "source-address options");
                                         free(allowed);                                          free(allowed);
                                         goto out;                                          goto out;
                                 }                                  }
                                 remote_ip = ssh_remote_ipaddr(ssh);                                  /* Check syntax */
                                 result = addr_match_cidr_list(remote_ip,                                  if (addr_match_cidr_list(NULL, allowed) == -1) {
                                     allowed);  
                                 free(allowed);  
                                 switch (result) {  
                                 case 1:  
                                         /* accepted */  
                                         break;  
                                 case 0:  
                                         /* no match */  
                                         logit("Authentication tried for %.100s "  
                                             "with valid certificate but not "  
                                             "from a permitted host "  
                                             "(ip=%.200s).", pw->pw_name,  
                                             remote_ip);  
                                         auth_debug_add("Your address '%.200s' "  
                                             "is not permitted to use this "  
                                             "certificate for login.",  
                                             remote_ip);  
                                         goto out;  
                                 case -1:  
                                 default:  
                                         error("Certificate source-address "                                          error("Certificate source-address "
                                             "contents invalid");                                              "contents invalid");
                                         goto out;                                          goto out;
                                 }                                  }
                                   opts->required_from_host_cert = allowed;
                                 found = 1;                                  found = 1;
                         }                          }
                 }                  }
Line 592  parse_option_list(struct sshbuf *oblob, 
Line 247  parse_option_list(struct sshbuf *oblob, 
         ret = 0;          ret = 0;
   
  out:   out:
         if (ret != 0 &&  
             cert_forced_command != NULL &&  
             *cert_forced_command != NULL) {  
                 free(*cert_forced_command);  
                 *cert_forced_command = NULL;  
         }  
         free(name);          free(name);
         sshbuf_free(data);          sshbuf_free(data);
         sshbuf_free(c);          sshbuf_free(c);
         return ret;          return ret;
 }  }
   
   struct sshauthopt *
   sshauthopt_new(void)
   {
           struct sshauthopt *ret;
   
           if ((ret = calloc(1, sizeof(*ret))) == NULL)
                   return NULL;
           ret->force_tun_device = -1;
           return ret;
   }
   
   void
   sshauthopt_free(struct sshauthopt *opts)
   {
           size_t i;
   
           if (opts == NULL)
                   return;
   
           free(opts->cert_principals);
           free(opts->force_command);
           free(opts->required_from_host_cert);
           free(opts->required_from_host_keys);
   
           for (i = 0; i < opts->nenv; i++)
                   free(opts->env[i]);
           free(opts->env);
   
           for (i = 0; i < opts->npermitopen; i++)
                   free(opts->permitopen[i]);
           free(opts->permitopen);
   
           for (i = 0; i < opts->npermitlisten; i++)
                   free(opts->permitlisten[i]);
           free(opts->permitlisten);
   
           explicit_bzero(opts, sizeof(*opts));
           free(opts);
   }
   
   struct sshauthopt *
   sshauthopt_new_with_keys_defaults(void)
   {
           struct sshauthopt *ret = NULL;
   
           if ((ret = sshauthopt_new()) == NULL)
                   return NULL;
   
           /* Defaults for authorized_keys flags */
           ret->permit_port_forwarding_flag = 1;
           ret->permit_agent_forwarding_flag = 1;
           ret->permit_x11_forwarding_flag = 1;
           ret->permit_pty_flag = 1;
           ret->permit_user_rc = 1;
           return ret;
   }
   
 /*  /*
  * Set options from critical certificate options. These supersede user key   * Parse and record a permitopen/permitlisten directive.
  * options so this must be called after auth_parse_options().   * Return 0 on success. Return -1 on failure and sets *errstrp to error reason.
  */   */
 int  static int
 auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason)  handle_permit(const char **optsp, int allow_bare_port,
       char ***permitsp, size_t *npermitsp, const char **errstrp)
 {  {
         int cert_no_port_forwarding_flag = 1;          char *opt, *tmp, *cp, *host, **permits = *permitsp;
         int cert_no_agent_forwarding_flag = 1;          size_t npermits = *npermitsp;
         int cert_no_x11_forwarding_flag = 1;          const char *errstr = "unknown error";
         int cert_no_pty_flag = 1;  
         int cert_no_user_rc = 1;          if (npermits > INT_MAX) {
         char *cert_forced_command = NULL;                  *errstrp = "too many permission directives";
         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,  
             &cert_forced_command,  
             &cert_source_address_done) == -1)  
                 return -1;                  return -1;
         if (parse_option_list(k->cert->extensions, pw,          }
             OPTIONS_EXTENSIONS, 0,          if ((opt = opt_dequote(optsp, &errstr)) == NULL) {
             &cert_no_port_forwarding_flag,  
             &cert_no_agent_forwarding_flag,  
             &cert_no_x11_forwarding_flag,  
             &cert_no_pty_flag,  
             &cert_no_user_rc,  
             NULL, NULL) == -1)  
                 return -1;                  return -1;
           }
           if (allow_bare_port && strchr(opt, ':') == NULL) {
                   /*
                    * Allow a bare port number in permitlisten to indicate a
                    * listen_host wildcard.
                    */
                   if (asprintf(&tmp, "*:%s", opt) < 0) {
                           *errstrp = "memory allocation failed";
                           return -1;
                   }
                   free(opt);
                   opt = tmp;
           }
           if ((tmp = strdup(opt)) == NULL) {
                   free(opt);
                   *errstrp = "memory allocation failed";
                   return -1;
           }
           cp = tmp;
           /* validate syntax before recording it. */
           host = hpdelim(&cp);
           if (host == NULL || strlen(host) >= NI_MAXHOST) {
                   free(tmp);
                   free(opt);
                   *errstrp = "invalid permission hostname";
                   return -1;
           }
           /*
            * don't want to use permitopen_port to avoid
            * dependency on channels.[ch] here.
            */
           if (cp == NULL ||
               (strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
                   free(tmp);
                   free(opt);
                   *errstrp = "invalid permission port";
                   return -1;
           }
           /* XXX - add streamlocal support */
           free(tmp);
           /* Record it */
           if ((permits = recallocarray(permits, npermits, npermits + 1,
               sizeof(*permits))) == NULL) {
                   free(opt);
                   /* NB. don't update *permitsp if alloc fails */
                   *errstrp = "memory allocation failed";
                   return -1;
           }
           permits[npermits++] = opt;
           *permitsp = permits;
           *npermitsp = npermits;
           return 0;
   }
   
   struct sshauthopt *
   sshauthopt_parse(const char *opts, const char **errstrp)
   {
           char **oarray, *opt, *cp, *tmp;
           int r;
           struct sshauthopt *ret = NULL;
           const char *errstr = "unknown error";
           uint64_t valid_before;
   
           if (errstrp != NULL)
                   *errstrp = NULL;
           if ((ret = sshauthopt_new_with_keys_defaults()) == NULL)
                   goto alloc_fail;
   
           if (opts == NULL)
                   return ret;
   
           while (*opts && *opts != ' ' && *opts != '\t') {
                   /* flag options */
                   if ((r = opt_flag("restrict", 0, &opts)) != -1) {
                           ret->restricted = 1;
                           ret->permit_port_forwarding_flag = 0;
                           ret->permit_agent_forwarding_flag = 0;
                           ret->permit_x11_forwarding_flag = 0;
                           ret->permit_pty_flag = 0;
                           ret->permit_user_rc = 0;
                   } else if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
                           ret->cert_authority = r;
                   } else if ((r = opt_flag("port-forwarding", 1, &opts)) != -1) {
                           ret->permit_port_forwarding_flag = r == 1;
                   } else if ((r = opt_flag("agent-forwarding", 1, &opts)) != -1) {
                           ret->permit_agent_forwarding_flag = r == 1;
                   } else if ((r = opt_flag("x11-forwarding", 1, &opts)) != -1) {
                           ret->permit_x11_forwarding_flag = r == 1;
                   } else if ((r = opt_flag("pty", 1, &opts)) != -1) {
                           ret->permit_pty_flag = r == 1;
                   } else if ((r = opt_flag("user-rc", 1, &opts)) != -1) {
                           ret->permit_user_rc = r == 1;
                   } else if (opt_match(&opts, "command")) {
                           if (ret->force_command != NULL) {
                                   errstr = "multiple \"command\" clauses";
                                   goto fail;
                           }
                           ret->force_command = opt_dequote(&opts, &errstr);
                           if (ret->force_command == NULL)
                                   goto fail;
                   } else if (opt_match(&opts, "principals")) {
                           if (ret->cert_principals != NULL) {
                                   errstr = "multiple \"principals\" clauses";
                                   goto fail;
                           }
                           ret->cert_principals = opt_dequote(&opts, &errstr);
                           if (ret->cert_principals == NULL)
                                   goto fail;
                   } else if (opt_match(&opts, "from")) {
                           if (ret->required_from_host_keys != NULL) {
                                   errstr = "multiple \"from\" clauses";
                                   goto fail;
                           }
                           ret->required_from_host_keys = opt_dequote(&opts,
                               &errstr);
                           if (ret->required_from_host_keys == NULL)
                                   goto fail;
                   } else if (opt_match(&opts, "expiry-time")) {
                           if ((opt = opt_dequote(&opts, &errstr)) == NULL)
                                   goto fail;
                           if (parse_absolute_time(opt, &valid_before) != 0 ||
                               valid_before == 0) {
                                   free(opt);
                                   errstr = "invalid expires time";
                                   goto fail;
                           }
                           free(opt);
                           if (ret->valid_before == 0 ||
                               valid_before < ret->valid_before)
                                   ret->valid_before = valid_before;
                   } else if (opt_match(&opts, "environment")) {
                           if (ret->nenv > INT_MAX) {
                                   errstr = "too many environment strings";
                                   goto fail;
                           }
                           if ((opt = opt_dequote(&opts, &errstr)) == NULL)
                                   goto fail;
                           /* env name must be alphanumeric and followed by '=' */
                           if ((tmp = strchr(opt, '=')) == NULL) {
                                   free(opt);
                                   errstr = "invalid environment string";
                                   goto fail;
                           }
                           for (cp = opt; cp < tmp; cp++) {
                                   if (!isalnum((u_char)*cp) && *cp != '_') {
                                           free(opt);
                                           errstr = "invalid environment string";
                                           goto fail;
                                   }
                           }
                           /* Append it. */
                           oarray = ret->env;
                           if ((ret->env = recallocarray(ret->env, ret->nenv,
                               ret->nenv + 1, sizeof(*ret->env))) == NULL) {
                                   free(opt);
                                   ret->env = oarray; /* put it back for cleanup */
                                   goto alloc_fail;
                           }
                           ret->env[ret->nenv++] = opt;
                   } else if (opt_match(&opts, "permitopen")) {
                           if (handle_permit(&opts, 0, &ret->permitopen,
                               &ret->npermitopen, &errstr) != 0)
                                   goto fail;
                   } else if (opt_match(&opts, "permitlisten")) {
                           if (handle_permit(&opts, 1, &ret->permitlisten,
                               &ret->npermitlisten, &errstr) != 0)
                                   goto fail;
                   } else if (opt_match(&opts, "tunnel")) {
                           if ((opt = opt_dequote(&opts, &errstr)) == NULL)
                                   goto fail;
                           ret->force_tun_device = a2tun(opt, NULL);
                           free(opt);
                           if (ret->force_tun_device == SSH_TUNID_ERR) {
                                   errstr = "invalid tun device";
                                   goto fail;
                           }
                   }
                   /*
                    * Skip the comma, and move to the next option
                    * (or break out if there are no more).
                    */
                   if (*opts == '\0' || *opts == ' ' || *opts == '\t')
                           break;          /* End of options. */
                   /* Anything other than a comma is an unknown option */
                   if (*opts != ',') {
                           errstr = "unknown key option";
                           goto fail;
                   }
                   opts++;
                   if (*opts == '\0') {
                           errstr = "unexpected end-of-options";
                           goto fail;
                   }
           }
   
           /* success */
           if (errstrp != NULL)
                   *errstrp = NULL;
           return ret;
   
   alloc_fail:
           errstr = "memory allocation failed";
   fail:
           sshauthopt_free(ret);
           if (errstrp != NULL)
                   *errstrp = errstr;
           return NULL;
   }
   
   struct sshauthopt *
   sshauthopt_from_cert(struct sshkey *k)
   {
           struct sshauthopt *ret;
   
           if (k == NULL || !sshkey_type_is_cert(k->type) || k->cert == NULL ||
               k->cert->type != SSH2_CERT_TYPE_USER)
                   return NULL;
   
           if ((ret = sshauthopt_new()) == NULL)
                   return NULL;
   
           /* Handle options and critical extensions separately */
           if (cert_option_list(ret, k->cert->critical,
               OPTIONS_CRITICAL, 1) == -1) {
                   sshauthopt_free(ret);
                   return NULL;
           }
           if (cert_option_list(ret, k->cert->extensions,
               OPTIONS_EXTENSIONS, 0) == -1) {
                   sshauthopt_free(ret);
                   return NULL;
           }
           /* success */
           return ret;
   }
   
   /*
    * Merges "additional" options to "primary" and returns the result.
    * NB. Some options from primary have primacy.
    */
   struct sshauthopt *
   sshauthopt_merge(const struct sshauthopt *primary,
       const struct sshauthopt *additional, const char **errstrp)
   {
           struct sshauthopt *ret;
           const char *errstr = "internal error";
           const char *tmp;
   
           if (errstrp != NULL)
                   *errstrp = NULL;
   
           if ((ret = sshauthopt_new()) == NULL)
                   goto alloc_fail;
   
           /* cert_authority and cert_principals are cleared in result */
   
           /* Prefer access lists from primary. */
           /* XXX err is both set and mismatch? */
           tmp = primary->required_from_host_cert;
           if (tmp == NULL)
                   tmp = additional->required_from_host_cert;
           if (tmp != NULL && (ret->required_from_host_cert = strdup(tmp)) == NULL)
                   goto alloc_fail;
           tmp = primary->required_from_host_keys;
           if (tmp == NULL)
                   tmp = additional->required_from_host_keys;
           if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL)
                   goto alloc_fail;
   
         no_port_forwarding_flag |= cert_no_port_forwarding_flag;  
         no_agent_forwarding_flag |= cert_no_agent_forwarding_flag;  
         no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;  
         no_pty_flag |= cert_no_pty_flag;  
         no_user_rc |= cert_no_user_rc;  
         /*          /*
          * Only permit both CA and key option forced-command if they match.           * force_tun_device, permitopen/permitlisten and environment all
          * Otherwise refuse the certificate.           * prefer the primary.
          */           */
         if (cert_forced_command != NULL && forced_command != NULL) {          ret->force_tun_device = primary->force_tun_device;
                 if (strcmp(forced_command, cert_forced_command) == 0) {          if (ret->force_tun_device == -1)
                         free(forced_command);                  ret->force_tun_device = additional->force_tun_device;
                         forced_command = cert_forced_command;          if (primary->nenv > 0) {
                   if (dup_strings(&ret->env, &ret->nenv,
                       primary->env, primary->nenv) != 0)
                           goto alloc_fail;
           } else if (additional->nenv) {
                   if (dup_strings(&ret->env, &ret->nenv,
                       additional->env, additional->nenv) != 0)
                           goto alloc_fail;
           }
           if (primary->npermitopen > 0) {
                   if (dup_strings(&ret->permitopen, &ret->npermitopen,
                       primary->permitopen, primary->npermitopen) != 0)
                           goto alloc_fail;
           } else if (additional->npermitopen > 0) {
                   if (dup_strings(&ret->permitopen, &ret->npermitopen,
                       additional->permitopen, additional->npermitopen) != 0)
                           goto alloc_fail;
           }
   
           if (primary->npermitlisten > 0) {
                   if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
                       primary->permitlisten, primary->npermitlisten) != 0)
                           goto alloc_fail;
           } else if (additional->npermitlisten > 0) {
                   if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
                       additional->permitlisten, additional->npermitlisten) != 0)
                           goto alloc_fail;
           }
   
           /* Flags are logical-AND (i.e. must be set in both for permission) */
   #define OPTFLAG(x) ret->x = (primary->x == 1) && (additional->x == 1)
           OPTFLAG(permit_port_forwarding_flag);
           OPTFLAG(permit_agent_forwarding_flag);
           OPTFLAG(permit_x11_forwarding_flag);
           OPTFLAG(permit_pty_flag);
           OPTFLAG(permit_user_rc);
   #undef OPTFLAG
   
           /* Earliest expiry time should win */
           if (primary->valid_before != 0)
                   ret->valid_before = primary->valid_before;
           if (additional->valid_before != 0 &&
               additional->valid_before < ret->valid_before)
                   ret->valid_before = additional->valid_before;
   
           /*
            * When both multiple forced-command are specified, only
            * proceed if they are identical, otherwise fail.
            */
           if (primary->force_command != NULL &&
               additional->force_command != NULL) {
                   if (strcmp(primary->force_command,
                       additional->force_command) == 0) {
                           /* ok */
                           ret->force_command = strdup(primary->force_command);
                           if (ret->force_command == NULL)
                                   goto alloc_fail;
                 } else {                  } else {
                         *reason = "certificate and key options forced command "                          errstr = "forced command options do not match";
                             "do not match";                          goto fail;
                         free(cert_forced_command);                  }
                         return -1;          } else if (primary->force_command != NULL) {
                   if ((ret->force_command = strdup(
                       primary->force_command)) == NULL)
                           goto alloc_fail;
           } else if (additional->force_command != NULL) {
                   if ((ret->force_command = strdup(
                       additional->force_command)) == NULL)
                           goto alloc_fail;
           }
           /* success */
           if (errstrp != NULL)
                   *errstrp = NULL;
           return ret;
   
    alloc_fail:
           errstr = "memory allocation failed";
    fail:
           if (errstrp != NULL)
                   *errstrp = errstr;
           sshauthopt_free(ret);
           return NULL;
   }
   
   /*
    * Copy options
    */
   struct sshauthopt *
   sshauthopt_copy(const struct sshauthopt *orig)
   {
           struct sshauthopt *ret;
   
           if ((ret = sshauthopt_new()) == NULL)
                   return NULL;
   
   #define OPTSCALAR(x) ret->x = orig->x
           OPTSCALAR(permit_port_forwarding_flag);
           OPTSCALAR(permit_agent_forwarding_flag);
           OPTSCALAR(permit_x11_forwarding_flag);
           OPTSCALAR(permit_pty_flag);
           OPTSCALAR(permit_user_rc);
           OPTSCALAR(restricted);
           OPTSCALAR(cert_authority);
           OPTSCALAR(force_tun_device);
           OPTSCALAR(valid_before);
   #undef OPTSCALAR
   #define OPTSTRING(x) \
           do { \
                   if (orig->x != NULL && (ret->x = strdup(orig->x)) == NULL) { \
                           sshauthopt_free(ret); \
                           return NULL; \
                   } \
           } while (0)
           OPTSTRING(cert_principals);
           OPTSTRING(force_command);
           OPTSTRING(required_from_host_cert);
           OPTSTRING(required_from_host_keys);
   #undef OPTSTRING
   
           if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 ||
               dup_strings(&ret->permitopen, &ret->npermitopen,
               orig->permitopen, orig->npermitopen) != 0 ||
               dup_strings(&ret->permitlisten, &ret->npermitlisten,
               orig->permitlisten, orig->npermitlisten) != 0) {
                   sshauthopt_free(ret);
                   return NULL;
           }
           return ret;
   }
   
   static int
   serialise_array(struct sshbuf *m, char **a, size_t n)
   {
           struct sshbuf *b;
           size_t i;
           int r;
   
           if (n > INT_MAX)
                   return SSH_ERR_INTERNAL_ERROR;
   
           if ((b = sshbuf_new()) == NULL) {
                   return SSH_ERR_ALLOC_FAIL;
           }
           for (i = 0; i < n; i++) {
                   if ((r = sshbuf_put_cstring(b, a[i])) != 0) {
                           sshbuf_free(b);
                           return r;
                 }                  }
         } else if (cert_forced_command != NULL)          }
                 forced_command = cert_forced_command;          if ((r = sshbuf_put_u32(m, n)) != 0 ||
               (r = sshbuf_put_stringb(m, b)) != 0) {
                   sshbuf_free(b);
                   return r;
           }
         /* success */          /* success */
         *reason = NULL;  
         return 0;          return 0;
 }  }
   
   static int
   deserialise_array(struct sshbuf *m, char ***ap, size_t *np)
   {
           char **a = NULL;
           size_t i, n = 0;
           struct sshbuf *b = NULL;
           u_int tmp;
           int r = SSH_ERR_INTERNAL_ERROR;
   
           if ((r = sshbuf_get_u32(m, &tmp)) != 0 ||
               (r = sshbuf_froms(m, &b)) != 0)
                   goto out;
           if (tmp > INT_MAX) {
                   r = SSH_ERR_INVALID_FORMAT;
                   goto out;
           }
           n = tmp;
           if (n > 0 && (a = calloc(n, sizeof(*a))) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           for (i = 0; i < n; i++) {
                   if ((r = sshbuf_get_cstring(b, &a[i], NULL)) != 0)
                           goto out;
           }
           /* success */
           r = 0;
           *ap = a;
           a = NULL;
           *np = n;
           n = 0;
    out:
           for (i = 0; i < n; i++)
                   free(a[i]);
           free(a);
           sshbuf_free(b);
           return r;
   }
   
   static int
   serialise_nullable_string(struct sshbuf *m, const char *s)
   {
           int r;
   
           if ((r = sshbuf_put_u8(m, s == NULL)) != 0 ||
               (r = sshbuf_put_cstring(m, s)) != 0)
                   return r;
           return 0;
   }
   
   static int
   deserialise_nullable_string(struct sshbuf *m, char **sp)
   {
           int r;
           u_char flag;
   
           *sp = NULL;
           if ((r = sshbuf_get_u8(m, &flag)) != 0 ||
               (r = sshbuf_get_cstring(m, flag ? NULL : sp, NULL)) != 0)
                   return r;
           return 0;
   }
   
   int
   sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
       int untrusted)
   {
           int r = SSH_ERR_INTERNAL_ERROR;
   
           /* Flag and simple integer options */
           if ((r = sshbuf_put_u8(m, opts->permit_port_forwarding_flag)) != 0 ||
               (r = sshbuf_put_u8(m, opts->permit_agent_forwarding_flag)) != 0 ||
               (r = sshbuf_put_u8(m, opts->permit_x11_forwarding_flag)) != 0 ||
               (r = sshbuf_put_u8(m, opts->permit_pty_flag)) != 0 ||
               (r = sshbuf_put_u8(m, opts->permit_user_rc)) != 0 ||
               (r = sshbuf_put_u8(m, opts->restricted)) != 0 ||
               (r = sshbuf_put_u8(m, opts->cert_authority)) != 0 ||
               (r = sshbuf_put_u64(m, opts->valid_before)) != 0)
                   return r;
   
           /* tunnel number can be negative to indicate "unset" */
           if ((r = sshbuf_put_u8(m, opts->force_tun_device == -1)) != 0 ||
               (r = sshbuf_put_u32(m, (opts->force_tun_device < 0) ?
               0 : (u_int)opts->force_tun_device)) != 0)
                   return r;
   
           /* String options; these may be NULL */
           if ((r = serialise_nullable_string(m,
               untrusted ? "yes" : opts->cert_principals)) != 0 ||
               (r = serialise_nullable_string(m,
               untrusted ? "true" : opts->force_command)) != 0 ||
               (r = serialise_nullable_string(m,
               untrusted ? NULL : opts->required_from_host_cert)) != 0 ||
               (r = serialise_nullable_string(m,
                untrusted ? NULL : opts->required_from_host_keys)) != 0)
                   return r;
   
           /* Array options */
           if ((r = serialise_array(m, opts->env,
               untrusted ? 0 : opts->nenv)) != 0 ||
               (r = serialise_array(m, opts->permitopen,
               untrusted ? 0 : opts->npermitopen)) != 0 ||
               (r = serialise_array(m, opts->permitlisten,
               untrusted ? 0 : opts->npermitlisten)) != 0)
                   return r;
   
           /* success */
           return 0;
   }
   
   int
   sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
   {
           struct sshauthopt *opts = NULL;
           int r = SSH_ERR_INTERNAL_ERROR;
           u_char f;
           u_int tmp;
   
           if ((opts = calloc(1, sizeof(*opts))) == NULL)
                   return SSH_ERR_ALLOC_FAIL;
   
   #define OPT_FLAG(x) \
           do { \
                   if ((r = sshbuf_get_u8(m, &f)) != 0) \
                           goto out; \
                   opts->x = f; \
           } while (0)
           OPT_FLAG(permit_port_forwarding_flag);
           OPT_FLAG(permit_agent_forwarding_flag);
           OPT_FLAG(permit_x11_forwarding_flag);
           OPT_FLAG(permit_pty_flag);
           OPT_FLAG(permit_user_rc);
           OPT_FLAG(restricted);
           OPT_FLAG(cert_authority);
   #undef OPT_FLAG
   
           if ((r = sshbuf_get_u64(m, &opts->valid_before)) != 0)
                   goto out;
   
           /* tunnel number can be negative to indicate "unset" */
           if ((r = sshbuf_get_u8(m, &f)) != 0 ||
               (r = sshbuf_get_u32(m, &tmp)) != 0)
                   goto out;
           opts->force_tun_device = f ? -1 : (int)tmp;
   
           /* String options may be NULL */
           if ((r = deserialise_nullable_string(m, &opts->cert_principals)) != 0 ||
               (r = deserialise_nullable_string(m, &opts->force_command)) != 0 ||
               (r = deserialise_nullable_string(m,
               &opts->required_from_host_cert)) != 0 ||
               (r = deserialise_nullable_string(m,
               &opts->required_from_host_keys)) != 0)
                   goto out;
   
           /* Array options */
           if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 ||
               (r = deserialise_array(m,
               &opts->permitopen, &opts->npermitopen)) != 0 ||
               (r = deserialise_array(m,
               &opts->permitlisten, &opts->npermitlisten)) != 0)
                   goto out;
   
           /* success */
           r = 0;
           *optsp = opts;
           opts = NULL;
    out:
           sshauthopt_free(opts);
           return r;
   }

Legend:
Removed from v.1.16  
changed lines
  Added in v.1.16.2.2

CVSweb <webmaster@jp.NetBSD.org>