1323124Sdes/* $OpenBSD: auth-options.c,v 1.71 2016/03/07 19:02:43 djm Exp $ */ 265668Skris/* 365668Skris * Author: Tatu Ylonen <ylo@cs.hut.fi> 465668Skris * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 565668Skris * All rights reserved 665668Skris * As far as I am concerned, the code I have written for this software 765668Skris * can be used freely for any purpose. Any derived versions of this 865668Skris * software must be clearly marked as such, and if the derived work is 965668Skris * incompatible with the protocol description in the RFC file, it must be 1065668Skris * called by a name other than "ssh" or "Secure Shell". 1165668Skris */ 1265668Skris 1365668Skris#include "includes.h" 1465668Skris 15162852Sdes#include <sys/types.h> 16162852Sdes 17162852Sdes#include <netdb.h> 18162852Sdes#include <pwd.h> 19162852Sdes#include <string.h> 20162852Sdes#include <stdio.h> 21162852Sdes#include <stdarg.h> 22162852Sdes 23181111Sdes#include "openbsd-compat/sys-queue.h" 24295367Sdes 25295367Sdes#include "key.h" /* XXX for typedef */ 26295367Sdes#include "buffer.h" /* XXX for typedef */ 2765668Skris#include "xmalloc.h" 2865668Skris#include "match.h" 29295367Sdes#include "ssherr.h" 3076259Sgreen#include "log.h" 3176259Sgreen#include "canohost.h" 32323124Sdes#include "packet.h" 33295367Sdes#include "sshbuf.h" 34295367Sdes#include "misc.h" 3576259Sgreen#include "channels.h" 3676259Sgreen#include "servconf.h" 37295367Sdes#include "sshkey.h" 38215116Sdes#include "auth-options.h" 39162852Sdes#include "hostfile.h" 40162852Sdes#include "auth.h" 4165668Skris 4265668Skris/* Flags set authorized_keys flags */ 4365668Skrisint no_port_forwarding_flag = 0; 4465668Skrisint no_agent_forwarding_flag = 0; 4565668Skrisint no_x11_forwarding_flag = 0; 4665668Skrisint no_pty_flag = 0; 47181111Sdesint no_user_rc = 0; 48204917Sdesint key_is_cert_authority = 0; 4965668Skris 5065668Skris/* "command=" option. */ 5165668Skrischar *forced_command = NULL; 5265668Skris 5365668Skris/* "environment=" options. */ 5465668Skrisstruct envstring *custom_environment = NULL; 5565668Skris 56157016Sdes/* "tunnel=" option. */ 57157016Sdesint forced_tun_device = -1; 58157016Sdes 59215116Sdes/* "principals=" option. */ 60215116Sdeschar *authorized_principals = NULL; 61215116Sdes 6276259Sgreenextern ServerOptions options; 6376259Sgreen 6469587Sgreenvoid 6569587Sgreenauth_clear_options(void) 6669587Sgreen{ 6769587Sgreen no_agent_forwarding_flag = 0; 6869587Sgreen no_port_forwarding_flag = 0; 6969587Sgreen no_pty_flag = 0; 7069587Sgreen no_x11_forwarding_flag = 0; 71181111Sdes no_user_rc = 0; 72204917Sdes key_is_cert_authority = 0; 7369587Sgreen while (custom_environment) { 7469587Sgreen struct envstring *ce = custom_environment; 7569587Sgreen custom_environment = ce->next; 76255767Sdes free(ce->s); 77255767Sdes free(ce); 7869587Sgreen } 79296781Sdes free(forced_command); 80296781Sdes forced_command = NULL; 81296781Sdes free(authorized_principals); 82296781Sdes authorized_principals = NULL; 83157016Sdes forced_tun_device = -1; 8476259Sgreen channel_clear_permitted_opens(); 8569587Sgreen} 8669587Sgreen 8776259Sgreen/* 88296781Sdes * Match flag 'opt' in *optsp, and if allow_negate is set then also match 89296781Sdes * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0 90296781Sdes * if negated option matches. 91296781Sdes * If the option or negated option matches, then *optsp is updated to 92296781Sdes * point to the first character after the option and, if 'msg' is not NULL 93296781Sdes * then a message based on it added via auth_debug_add(). 94296781Sdes */ 95296781Sdesstatic int 96296781Sdesmatch_flag(const char *opt, int allow_negate, char **optsp, const char *msg) 97296781Sdes{ 98296781Sdes size_t opt_len = strlen(opt); 99296781Sdes char *opts = *optsp; 100296781Sdes int negate = 0; 101296781Sdes 102296781Sdes if (allow_negate && strncasecmp(opts, "no-", 3) == 0) { 103296781Sdes opts += 3; 104296781Sdes negate = 1; 105296781Sdes } 106296781Sdes if (strncasecmp(opts, opt, opt_len) == 0) { 107296781Sdes *optsp = opts + opt_len; 108296781Sdes if (msg != NULL) { 109296781Sdes auth_debug_add("%s %s.", msg, 110296781Sdes negate ? "disabled" : "enabled"); 111296781Sdes } 112296781Sdes return negate ? 0 : 1; 113296781Sdes } 114296781Sdes return -1; 115296781Sdes} 116296781Sdes 117296781Sdes/* 11876259Sgreen * return 1 if access is granted, 0 if not. 11976259Sgreen * side effect: sets key option flags 12076259Sgreen */ 12165668Skrisint 12276259Sgreenauth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) 12365668Skris{ 124323124Sdes struct ssh *ssh = active_state; /* XXX */ 12565668Skris const char *cp; 126296781Sdes int i, r; 12769587Sgreen 12869587Sgreen /* reset options */ 12969587Sgreen auth_clear_options(); 13069587Sgreen 13176259Sgreen if (!opts) 13276259Sgreen return 1; 13376259Sgreen 13476259Sgreen while (*opts && *opts != ' ' && *opts != '\t') { 135296781Sdes if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) { 136296781Sdes key_is_cert_authority = r; 137204917Sdes goto next_option; 138204917Sdes } 139296781Sdes if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) { 140296781Sdes auth_debug_add("Key is restricted."); 14165668Skris no_port_forwarding_flag = 1; 142296781Sdes no_agent_forwarding_flag = 1; 143296781Sdes no_x11_forwarding_flag = 1; 144296781Sdes no_pty_flag = 1; 145296781Sdes no_user_rc = 1; 14665668Skris goto next_option; 14765668Skris } 148296781Sdes if ((r = match_flag("port-forwarding", 1, &opts, 149296781Sdes "Port forwarding")) != -1) { 150296781Sdes no_port_forwarding_flag = r != 1; 15165668Skris goto next_option; 15265668Skris } 153296781Sdes if ((r = match_flag("agent-forwarding", 1, &opts, 154296781Sdes "Agent forwarding")) != -1) { 155296781Sdes no_agent_forwarding_flag = r != 1; 15665668Skris goto next_option; 15765668Skris } 158296781Sdes if ((r = match_flag("x11-forwarding", 1, &opts, 159296781Sdes "X11 forwarding")) != -1) { 160296781Sdes no_x11_forwarding_flag = r != 1; 16165668Skris goto next_option; 16265668Skris } 163296781Sdes if ((r = match_flag("pty", 1, &opts, 164296781Sdes "PTY allocation")) != -1) { 165296781Sdes no_pty_flag = r != 1; 166181111Sdes goto next_option; 167181111Sdes } 168296781Sdes if ((r = match_flag("user-rc", 1, &opts, 169296781Sdes "User rc execution")) != -1) { 170296781Sdes no_user_rc = r != 1; 171296781Sdes goto next_option; 172296781Sdes } 17365668Skris cp = "command=\""; 17476259Sgreen if (strncasecmp(opts, cp, strlen(cp)) == 0) { 17576259Sgreen opts += strlen(cp); 176296781Sdes free(forced_command); 17776259Sgreen forced_command = xmalloc(strlen(opts) + 1); 17865668Skris i = 0; 17976259Sgreen while (*opts) { 18076259Sgreen if (*opts == '"') 18165668Skris break; 18276259Sgreen if (*opts == '\\' && opts[1] == '"') { 18376259Sgreen opts += 2; 18465668Skris forced_command[i++] = '"'; 18565668Skris continue; 18665668Skris } 18776259Sgreen forced_command[i++] = *opts++; 18865668Skris } 18976259Sgreen if (!*opts) { 19065668Skris debug("%.100s, line %lu: missing end quote", 19176259Sgreen file, linenum); 19298675Sdes auth_debug_add("%.100s, line %lu: missing end quote", 19376259Sgreen file, linenum); 194255767Sdes free(forced_command); 19576259Sgreen forced_command = NULL; 19676259Sgreen goto bad_option; 19765668Skris } 198162852Sdes forced_command[i] = '\0'; 199221420Sdes auth_debug_add("Forced command."); 20076259Sgreen opts++; 20165668Skris goto next_option; 20265668Skris } 203215116Sdes cp = "principals=\""; 204215116Sdes if (strncasecmp(opts, cp, strlen(cp)) == 0) { 205215116Sdes opts += strlen(cp); 206296781Sdes free(authorized_principals); 207215116Sdes authorized_principals = xmalloc(strlen(opts) + 1); 208215116Sdes i = 0; 209215116Sdes while (*opts) { 210215116Sdes if (*opts == '"') 211215116Sdes break; 212215116Sdes if (*opts == '\\' && opts[1] == '"') { 213215116Sdes opts += 2; 214215116Sdes authorized_principals[i++] = '"'; 215215116Sdes continue; 216215116Sdes } 217215116Sdes authorized_principals[i++] = *opts++; 218215116Sdes } 219215116Sdes if (!*opts) { 220215116Sdes debug("%.100s, line %lu: missing end quote", 221215116Sdes file, linenum); 222215116Sdes auth_debug_add("%.100s, line %lu: missing end quote", 223215116Sdes file, linenum); 224255767Sdes free(authorized_principals); 225215116Sdes authorized_principals = NULL; 226215116Sdes goto bad_option; 227215116Sdes } 228215116Sdes authorized_principals[i] = '\0'; 229215116Sdes auth_debug_add("principals: %.900s", 230215116Sdes authorized_principals); 231215116Sdes opts++; 232215116Sdes goto next_option; 233215116Sdes } 23465668Skris cp = "environment=\""; 235295367Sdes if (strncasecmp(opts, cp, strlen(cp)) == 0) { 23665668Skris char *s; 23765668Skris struct envstring *new_envstring; 23876259Sgreen 23976259Sgreen opts += strlen(cp); 24076259Sgreen s = xmalloc(strlen(opts) + 1); 24165668Skris i = 0; 24276259Sgreen while (*opts) { 24376259Sgreen if (*opts == '"') 24465668Skris break; 24576259Sgreen if (*opts == '\\' && opts[1] == '"') { 24676259Sgreen opts += 2; 24765668Skris s[i++] = '"'; 24865668Skris continue; 24965668Skris } 25076259Sgreen s[i++] = *opts++; 25165668Skris } 25276259Sgreen if (!*opts) { 25365668Skris debug("%.100s, line %lu: missing end quote", 25476259Sgreen file, linenum); 25598675Sdes auth_debug_add("%.100s, line %lu: missing end quote", 25676259Sgreen file, linenum); 257255767Sdes free(s); 25876259Sgreen goto bad_option; 25965668Skris } 260162852Sdes s[i] = '\0'; 26176259Sgreen opts++; 262295367Sdes if (options.permit_user_env) { 263295367Sdes auth_debug_add("Adding to environment: " 264295367Sdes "%.900s", s); 265295367Sdes debug("Adding to environment: %.900s", s); 266295367Sdes new_envstring = xcalloc(1, 267295367Sdes sizeof(*new_envstring)); 268295367Sdes new_envstring->s = s; 269295367Sdes new_envstring->next = custom_environment; 270295367Sdes custom_environment = new_envstring; 271295367Sdes s = NULL; 272295367Sdes } 273295367Sdes free(s); 27465668Skris goto next_option; 27565668Skris } 27665668Skris cp = "from=\""; 27776259Sgreen if (strncasecmp(opts, cp, strlen(cp)) == 0) { 278323124Sdes const char *remote_ip = ssh_remote_ipaddr(ssh); 279323124Sdes const char *remote_host = auth_get_canonical_hostname( 280323124Sdes ssh, options.use_dns); 28176259Sgreen char *patterns = xmalloc(strlen(opts) + 1); 28276259Sgreen 28376259Sgreen opts += strlen(cp); 28465668Skris i = 0; 28576259Sgreen while (*opts) { 28676259Sgreen if (*opts == '"') 28765668Skris break; 28876259Sgreen if (*opts == '\\' && opts[1] == '"') { 28976259Sgreen opts += 2; 29065668Skris patterns[i++] = '"'; 29165668Skris continue; 29265668Skris } 29376259Sgreen patterns[i++] = *opts++; 29465668Skris } 29576259Sgreen if (!*opts) { 29665668Skris debug("%.100s, line %lu: missing end quote", 29776259Sgreen file, linenum); 29898675Sdes auth_debug_add("%.100s, line %lu: missing end quote", 29976259Sgreen file, linenum); 300255767Sdes free(patterns); 30176259Sgreen goto bad_option; 30265668Skris } 303162852Sdes patterns[i] = '\0'; 30476259Sgreen opts++; 305181111Sdes switch (match_host_and_ip(remote_host, remote_ip, 306181111Sdes patterns)) { 307181111Sdes case 1: 308255767Sdes free(patterns); 309181111Sdes /* Host name matches. */ 310181111Sdes goto next_option; 311181111Sdes case -1: 312181111Sdes debug("%.100s, line %lu: invalid criteria", 313181111Sdes file, linenum); 314181111Sdes auth_debug_add("%.100s, line %lu: " 315181111Sdes "invalid criteria", file, linenum); 316181111Sdes /* FALLTHROUGH */ 317181111Sdes case 0: 318255767Sdes free(patterns); 319124208Sdes logit("Authentication tried for %.100s with " 32076259Sgreen "correct key but not from a permitted " 32176259Sgreen "host (host=%.200s, ip=%.200s).", 32276259Sgreen pw->pw_name, remote_host, remote_ip); 32398675Sdes auth_debug_add("Your host '%.200s' is not " 32476259Sgreen "permitted to use this key for login.", 32576259Sgreen remote_host); 326181111Sdes break; 32765668Skris } 328181111Sdes /* deny access */ 329181111Sdes return 0; 33065668Skris } 33176259Sgreen cp = "permitopen=\""; 33276259Sgreen if (strncasecmp(opts, cp, strlen(cp)) == 0) { 333146998Sdes char *host, *p; 334192595Sdes int port; 33576259Sgreen char *patterns = xmalloc(strlen(opts) + 1); 33676259Sgreen 33776259Sgreen opts += strlen(cp); 33876259Sgreen i = 0; 33976259Sgreen while (*opts) { 34076259Sgreen if (*opts == '"') 34176259Sgreen break; 34276259Sgreen if (*opts == '\\' && opts[1] == '"') { 34376259Sgreen opts += 2; 34476259Sgreen patterns[i++] = '"'; 34576259Sgreen continue; 34676259Sgreen } 34776259Sgreen patterns[i++] = *opts++; 34876259Sgreen } 34976259Sgreen if (!*opts) { 35076259Sgreen debug("%.100s, line %lu: missing end quote", 35176259Sgreen file, linenum); 352146998Sdes auth_debug_add("%.100s, line %lu: missing " 353146998Sdes "end quote", file, linenum); 354255767Sdes free(patterns); 35576259Sgreen goto bad_option; 35676259Sgreen } 357162852Sdes patterns[i] = '\0'; 35876259Sgreen opts++; 359146998Sdes p = patterns; 360295367Sdes /* XXX - add streamlocal support */ 361146998Sdes host = hpdelim(&p); 362146998Sdes if (host == NULL || strlen(host) >= NI_MAXHOST) { 363146998Sdes debug("%.100s, line %lu: Bad permitopen " 364147001Sdes "specification <%.100s>", file, linenum, 365146998Sdes patterns); 36698675Sdes auth_debug_add("%.100s, line %lu: " 367146998Sdes "Bad permitopen specification", file, 368146998Sdes linenum); 369255767Sdes free(patterns); 37076259Sgreen goto bad_option; 37176259Sgreen } 372147001Sdes host = cleanhostname(host); 373240075Sdes if (p == NULL || (port = permitopen_port(p)) < 0) { 374146998Sdes debug("%.100s, line %lu: Bad permitopen port " 375146998Sdes "<%.100s>", file, linenum, p ? p : ""); 37698675Sdes auth_debug_add("%.100s, line %lu: " 37792555Sdes "Bad permitopen port", file, linenum); 378255767Sdes free(patterns); 37976259Sgreen goto bad_option; 38076259Sgreen } 381248619Sdes if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) 38292555Sdes channel_add_permitted_opens(host, port); 383255767Sdes free(patterns); 38476259Sgreen goto next_option; 38576259Sgreen } 386157016Sdes cp = "tunnel=\""; 387157016Sdes if (strncasecmp(opts, cp, strlen(cp)) == 0) { 388157016Sdes char *tun = NULL; 389157016Sdes opts += strlen(cp); 390157016Sdes tun = xmalloc(strlen(opts) + 1); 391157016Sdes i = 0; 392157016Sdes while (*opts) { 393157016Sdes if (*opts == '"') 394157016Sdes break; 395157016Sdes tun[i++] = *opts++; 396157016Sdes } 397157016Sdes if (!*opts) { 398157016Sdes debug("%.100s, line %lu: missing end quote", 399157016Sdes file, linenum); 400157016Sdes auth_debug_add("%.100s, line %lu: missing end quote", 401157016Sdes file, linenum); 402255767Sdes free(tun); 403157016Sdes forced_tun_device = -1; 404157016Sdes goto bad_option; 405157016Sdes } 406162852Sdes tun[i] = '\0'; 407157016Sdes forced_tun_device = a2tun(tun, NULL); 408255767Sdes free(tun); 409157016Sdes if (forced_tun_device == SSH_TUNID_ERR) { 410157016Sdes debug("%.100s, line %lu: invalid tun device", 411157016Sdes file, linenum); 412157016Sdes auth_debug_add("%.100s, line %lu: invalid tun device", 413157016Sdes file, linenum); 414157016Sdes forced_tun_device = -1; 415157016Sdes goto bad_option; 416157016Sdes } 417157016Sdes auth_debug_add("Forced tun device: %d", forced_tun_device); 418157016Sdes opts++; 419157016Sdes goto next_option; 420157016Sdes } 42165668Skrisnext_option: 42265668Skris /* 42365668Skris * Skip the comma, and move to the next option 42465668Skris * (or break out if there are no more). 42565668Skris */ 42676259Sgreen if (!*opts) 42765668Skris fatal("Bugs in auth-options.c option processing."); 42876259Sgreen if (*opts == ' ' || *opts == '\t') 42965668Skris break; /* End of options. */ 43076259Sgreen if (*opts != ',') 43165668Skris goto bad_option; 43276259Sgreen opts++; 43365668Skris /* Process the next option. */ 43465668Skris } 43598675Sdes 43665668Skris /* grant access */ 43765668Skris return 1; 43865668Skris 43965668Skrisbad_option: 440124208Sdes logit("Bad options in %.100s file, line %lu: %.50s", 44176259Sgreen file, linenum, opts); 44298675Sdes auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 44376259Sgreen file, linenum, opts); 44498675Sdes 44565668Skris /* deny access */ 44665668Skris return 0; 44765668Skris} 448204917Sdes 449215116Sdes#define OPTIONS_CRITICAL 1 450215116Sdes#define OPTIONS_EXTENSIONS 2 451215116Sdesstatic int 452295367Sdesparse_option_list(struct sshbuf *oblob, struct passwd *pw, 453215116Sdes u_int which, int crit, 454215116Sdes int *cert_no_port_forwarding_flag, 455215116Sdes int *cert_no_agent_forwarding_flag, 456215116Sdes int *cert_no_x11_forwarding_flag, 457215116Sdes int *cert_no_pty_flag, 458215116Sdes int *cert_no_user_rc, 459215116Sdes char **cert_forced_command, 460215116Sdes int *cert_source_address_done) 461204917Sdes{ 462323124Sdes struct ssh *ssh = active_state; /* XXX */ 463215116Sdes char *command, *allowed; 464215116Sdes const char *remote_ip; 465255767Sdes char *name = NULL; 466295367Sdes struct sshbuf *c = NULL, *data = NULL; 467295367Sdes int r, ret = -1, result, found; 468204917Sdes 469295367Sdes if ((c = sshbuf_fromb(oblob)) == NULL) { 470295367Sdes error("%s: sshbuf_fromb failed", __func__); 471295367Sdes goto out; 472295367Sdes } 473204917Sdes 474295367Sdes while (sshbuf_len(c) > 0) { 475295367Sdes sshbuf_free(data); 476295367Sdes data = NULL; 477295367Sdes if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 || 478295367Sdes (r = sshbuf_froms(c, &data)) != 0) { 479295367Sdes error("Unable to parse certificate options: %s", 480295367Sdes ssh_err(r)); 481204917Sdes goto out; 482204917Sdes } 483295367Sdes debug3("found certificate option \"%.100s\" len %zu", 484295367Sdes name, sshbuf_len(data)); 485215116Sdes found = 0; 486215116Sdes if ((which & OPTIONS_EXTENSIONS) != 0) { 487215116Sdes if (strcmp(name, "permit-X11-forwarding") == 0) { 488215116Sdes *cert_no_x11_forwarding_flag = 0; 489215116Sdes found = 1; 490215116Sdes } else if (strcmp(name, 491215116Sdes "permit-agent-forwarding") == 0) { 492215116Sdes *cert_no_agent_forwarding_flag = 0; 493215116Sdes found = 1; 494215116Sdes } else if (strcmp(name, 495215116Sdes "permit-port-forwarding") == 0) { 496215116Sdes *cert_no_port_forwarding_flag = 0; 497215116Sdes found = 1; 498215116Sdes } else if (strcmp(name, "permit-pty") == 0) { 499215116Sdes *cert_no_pty_flag = 0; 500215116Sdes found = 1; 501215116Sdes } else if (strcmp(name, "permit-user-rc") == 0) { 502215116Sdes *cert_no_user_rc = 0; 503215116Sdes found = 1; 504204917Sdes } 505215116Sdes } 506215116Sdes if (!found && (which & OPTIONS_CRITICAL) != 0) { 507215116Sdes if (strcmp(name, "force-command") == 0) { 508295367Sdes if ((r = sshbuf_get_cstring(data, &command, 509295367Sdes NULL)) != 0) { 510295367Sdes error("Unable to parse \"%s\" " 511295367Sdes "section: %s", name, ssh_err(r)); 512215116Sdes goto out; 513215116Sdes } 514215116Sdes if (*cert_forced_command != NULL) { 515215116Sdes error("Certificate has multiple " 516215116Sdes "force-command options"); 517255767Sdes free(command); 518215116Sdes goto out; 519215116Sdes } 520215116Sdes *cert_forced_command = command; 521215116Sdes found = 1; 522204917Sdes } 523215116Sdes if (strcmp(name, "source-address") == 0) { 524295367Sdes if ((r = sshbuf_get_cstring(data, &allowed, 525295367Sdes NULL)) != 0) { 526295367Sdes error("Unable to parse \"%s\" " 527295367Sdes "section: %s", name, ssh_err(r)); 528215116Sdes goto out; 529215116Sdes } 530215116Sdes if ((*cert_source_address_done)++) { 531215116Sdes error("Certificate has multiple " 532215116Sdes "source-address options"); 533255767Sdes free(allowed); 534215116Sdes goto out; 535215116Sdes } 536323124Sdes remote_ip = ssh_remote_ipaddr(ssh); 537262566Sdes result = addr_match_cidr_list(remote_ip, 538262566Sdes allowed); 539262566Sdes free(allowed); 540262566Sdes switch (result) { 541215116Sdes case 1: 542215116Sdes /* accepted */ 543215116Sdes break; 544215116Sdes case 0: 545215116Sdes /* no match */ 546215116Sdes logit("Authentication tried for %.100s " 547215116Sdes "with valid certificate but not " 548215116Sdes "from a permitted host " 549215116Sdes "(ip=%.200s).", pw->pw_name, 550215116Sdes remote_ip); 551215116Sdes auth_debug_add("Your address '%.200s' " 552215116Sdes "is not permitted to use this " 553215116Sdes "certificate for login.", 554215116Sdes remote_ip); 555215116Sdes goto out; 556215116Sdes case -1: 557262566Sdes default: 558215116Sdes error("Certificate source-address " 559215116Sdes "contents invalid"); 560215116Sdes goto out; 561215116Sdes } 562215116Sdes found = 1; 563204917Sdes } 564215116Sdes } 565215116Sdes 566215116Sdes if (!found) { 567215116Sdes if (crit) { 568215116Sdes error("Certificate critical option \"%s\" " 569215116Sdes "is not supported", name); 570204917Sdes goto out; 571215116Sdes } else { 572215116Sdes logit("Certificate extension \"%s\" " 573215116Sdes "is not supported", name); 574204917Sdes } 575295367Sdes } else if (sshbuf_len(data) != 0) { 576215116Sdes error("Certificate option \"%s\" corrupt " 577204917Sdes "(extra data)", name); 578204917Sdes goto out; 579204917Sdes } 580255767Sdes free(name); 581255767Sdes name = NULL; 582204917Sdes } 583215116Sdes /* successfully parsed all options */ 584204917Sdes ret = 0; 585204917Sdes 586215116Sdes out: 587215116Sdes if (ret != 0 && 588215116Sdes cert_forced_command != NULL && 589215116Sdes *cert_forced_command != NULL) { 590255767Sdes free(*cert_forced_command); 591215116Sdes *cert_forced_command = NULL; 592215116Sdes } 593296781Sdes free(name); 594295367Sdes sshbuf_free(data); 595295367Sdes sshbuf_free(c); 596215116Sdes return ret; 597215116Sdes} 598215116Sdes 599215116Sdes/* 600215116Sdes * Set options from critical certificate options. These supersede user key 601215116Sdes * options so this must be called after auth_parse_options(). 602215116Sdes */ 603215116Sdesint 604295367Sdesauth_cert_options(struct sshkey *k, struct passwd *pw) 605215116Sdes{ 606215116Sdes int cert_no_port_forwarding_flag = 1; 607215116Sdes int cert_no_agent_forwarding_flag = 1; 608215116Sdes int cert_no_x11_forwarding_flag = 1; 609215116Sdes int cert_no_pty_flag = 1; 610215116Sdes int cert_no_user_rc = 1; 611215116Sdes char *cert_forced_command = NULL; 612215116Sdes int cert_source_address_done = 0; 613215116Sdes 614295367Sdes /* Separate options and extensions for v01 certs */ 615295367Sdes if (parse_option_list(k->cert->critical, pw, 616295367Sdes OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, 617295367Sdes &cert_forced_command, 618295367Sdes &cert_source_address_done) == -1) 619295367Sdes return -1; 620295367Sdes if (parse_option_list(k->cert->extensions, pw, 621295367Sdes OPTIONS_EXTENSIONS, 0, 622295367Sdes &cert_no_port_forwarding_flag, 623295367Sdes &cert_no_agent_forwarding_flag, 624295367Sdes &cert_no_x11_forwarding_flag, 625295367Sdes &cert_no_pty_flag, 626295367Sdes &cert_no_user_rc, 627295367Sdes NULL, NULL) == -1) 628295367Sdes return -1; 629215116Sdes 630204917Sdes no_port_forwarding_flag |= cert_no_port_forwarding_flag; 631204917Sdes no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; 632204917Sdes no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; 633204917Sdes no_pty_flag |= cert_no_pty_flag; 634204917Sdes no_user_rc |= cert_no_user_rc; 635204917Sdes /* CA-specified forced command supersedes key option */ 636204917Sdes if (cert_forced_command != NULL) { 637296781Sdes free(forced_command); 638204917Sdes forced_command = cert_forced_command; 639204917Sdes } 640215116Sdes return 0; 641204917Sdes} 642204917Sdes 643