1ca86bcf2SDag-Erling Smørgrav /* $OpenBSD: auth-options.c,v 1.72 2016/11/30 02:57:40 djm Exp $ */ 2b66f2d16SKris Kennaway /* 3b66f2d16SKris Kennaway * Author: Tatu Ylonen <ylo@cs.hut.fi> 4b66f2d16SKris Kennaway * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5b66f2d16SKris Kennaway * All rights reserved 6b66f2d16SKris Kennaway * As far as I am concerned, the code I have written for this software 7b66f2d16SKris Kennaway * can be used freely for any purpose. Any derived versions of this 8b66f2d16SKris Kennaway * software must be clearly marked as such, and if the derived work is 9b66f2d16SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 10b66f2d16SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 11b66f2d16SKris Kennaway */ 12b66f2d16SKris Kennaway 13b66f2d16SKris Kennaway #include "includes.h" 14761efaa7SDag-Erling Smørgrav 15761efaa7SDag-Erling Smørgrav #include <sys/types.h> 16761efaa7SDag-Erling Smørgrav 17761efaa7SDag-Erling Smørgrav #include <netdb.h> 18761efaa7SDag-Erling Smørgrav #include <pwd.h> 19761efaa7SDag-Erling Smørgrav #include <string.h> 20761efaa7SDag-Erling Smørgrav #include <stdio.h> 21761efaa7SDag-Erling Smørgrav #include <stdarg.h> 22b66f2d16SKris Kennaway 23d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h" 24bc5531deSDag-Erling Smørgrav 25bc5531deSDag-Erling Smørgrav #include "key.h" /* XXX for typedef */ 26bc5531deSDag-Erling Smørgrav #include "buffer.h" /* XXX for typedef */ 27b66f2d16SKris Kennaway #include "xmalloc.h" 28b66f2d16SKris Kennaway #include "match.h" 29bc5531deSDag-Erling Smørgrav #include "ssherr.h" 301e8db6e2SBrian Feldman #include "log.h" 311e8db6e2SBrian Feldman #include "canohost.h" 32076ad2f8SDag-Erling Smørgrav #include "packet.h" 33bc5531deSDag-Erling Smørgrav #include "sshbuf.h" 34a0ee8cc6SDag-Erling Smørgrav #include "misc.h" 351e8db6e2SBrian Feldman #include "channels.h" 361e8db6e2SBrian Feldman #include "servconf.h" 37bc5531deSDag-Erling Smørgrav #include "sshkey.h" 38e2f6069cSDag-Erling Smørgrav #include "auth-options.h" 39761efaa7SDag-Erling Smørgrav #include "hostfile.h" 40545d5ecaSDag-Erling Smørgrav #include "auth.h" 41b66f2d16SKris Kennaway 42b66f2d16SKris Kennaway /* Flags set authorized_keys flags */ 43b66f2d16SKris Kennaway int no_port_forwarding_flag = 0; 44b66f2d16SKris Kennaway int no_agent_forwarding_flag = 0; 45b66f2d16SKris Kennaway int no_x11_forwarding_flag = 0; 46b66f2d16SKris Kennaway int no_pty_flag = 0; 47d4af9e69SDag-Erling Smørgrav int no_user_rc = 0; 48b15c8340SDag-Erling Smørgrav int key_is_cert_authority = 0; 49b66f2d16SKris Kennaway 50b66f2d16SKris Kennaway /* "command=" option. */ 51b66f2d16SKris Kennaway char *forced_command = NULL; 52b66f2d16SKris Kennaway 53b66f2d16SKris Kennaway /* "environment=" options. */ 54b66f2d16SKris Kennaway struct envstring *custom_environment = NULL; 55b66f2d16SKris Kennaway 56021d409fSDag-Erling Smørgrav /* "tunnel=" option. */ 57021d409fSDag-Erling Smørgrav int forced_tun_device = -1; 58021d409fSDag-Erling Smørgrav 59e2f6069cSDag-Erling Smørgrav /* "principals=" option. */ 60e2f6069cSDag-Erling Smørgrav char *authorized_principals = NULL; 61e2f6069cSDag-Erling Smørgrav 621e8db6e2SBrian Feldman extern ServerOptions options; 631e8db6e2SBrian Feldman 645b9b2fafSBrian Feldman void 655b9b2fafSBrian Feldman auth_clear_options(void) 665b9b2fafSBrian Feldman { 675b9b2fafSBrian Feldman no_agent_forwarding_flag = 0; 685b9b2fafSBrian Feldman no_port_forwarding_flag = 0; 695b9b2fafSBrian Feldman no_pty_flag = 0; 705b9b2fafSBrian Feldman no_x11_forwarding_flag = 0; 71d4af9e69SDag-Erling Smørgrav no_user_rc = 0; 72b15c8340SDag-Erling Smørgrav key_is_cert_authority = 0; 735b9b2fafSBrian Feldman while (custom_environment) { 745b9b2fafSBrian Feldman struct envstring *ce = custom_environment; 755b9b2fafSBrian Feldman custom_environment = ce->next; 76e4a9863fSDag-Erling Smørgrav free(ce->s); 77e4a9863fSDag-Erling Smørgrav free(ce); 785b9b2fafSBrian Feldman } 79e4a9863fSDag-Erling Smørgrav free(forced_command); 805b9b2fafSBrian Feldman forced_command = NULL; 81e4a9863fSDag-Erling Smørgrav free(authorized_principals); 82e2f6069cSDag-Erling Smørgrav authorized_principals = NULL; 83021d409fSDag-Erling Smørgrav forced_tun_device = -1; 841e8db6e2SBrian Feldman channel_clear_permitted_opens(); 855b9b2fafSBrian Feldman } 865b9b2fafSBrian Feldman 871e8db6e2SBrian Feldman /* 88acc1a9efSDag-Erling Smørgrav * Match flag 'opt' in *optsp, and if allow_negate is set then also match 89acc1a9efSDag-Erling Smørgrav * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0 90acc1a9efSDag-Erling Smørgrav * if negated option matches. 91acc1a9efSDag-Erling Smørgrav * If the option or negated option matches, then *optsp is updated to 92acc1a9efSDag-Erling Smørgrav * point to the first character after the option and, if 'msg' is not NULL 93acc1a9efSDag-Erling Smørgrav * then a message based on it added via auth_debug_add(). 94acc1a9efSDag-Erling Smørgrav */ 95acc1a9efSDag-Erling Smørgrav static int 96acc1a9efSDag-Erling Smørgrav match_flag(const char *opt, int allow_negate, char **optsp, const char *msg) 97acc1a9efSDag-Erling Smørgrav { 98acc1a9efSDag-Erling Smørgrav size_t opt_len = strlen(opt); 99acc1a9efSDag-Erling Smørgrav char *opts = *optsp; 100acc1a9efSDag-Erling Smørgrav int negate = 0; 101acc1a9efSDag-Erling Smørgrav 102acc1a9efSDag-Erling Smørgrav if (allow_negate && strncasecmp(opts, "no-", 3) == 0) { 103acc1a9efSDag-Erling Smørgrav opts += 3; 104acc1a9efSDag-Erling Smørgrav negate = 1; 105acc1a9efSDag-Erling Smørgrav } 106acc1a9efSDag-Erling Smørgrav if (strncasecmp(opts, opt, opt_len) == 0) { 107acc1a9efSDag-Erling Smørgrav *optsp = opts + opt_len; 108acc1a9efSDag-Erling Smørgrav if (msg != NULL) { 109acc1a9efSDag-Erling Smørgrav auth_debug_add("%s %s.", msg, 110acc1a9efSDag-Erling Smørgrav negate ? "disabled" : "enabled"); 111acc1a9efSDag-Erling Smørgrav } 112acc1a9efSDag-Erling Smørgrav return negate ? 0 : 1; 113acc1a9efSDag-Erling Smørgrav } 114acc1a9efSDag-Erling Smørgrav return -1; 115acc1a9efSDag-Erling Smørgrav } 116acc1a9efSDag-Erling Smørgrav 117acc1a9efSDag-Erling Smørgrav /* 1181e8db6e2SBrian Feldman * return 1 if access is granted, 0 if not. 1191e8db6e2SBrian Feldman * side effect: sets key option flags 1201e8db6e2SBrian Feldman */ 121b66f2d16SKris Kennaway int 1221e8db6e2SBrian Feldman auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) 123b66f2d16SKris Kennaway { 124076ad2f8SDag-Erling Smørgrav struct ssh *ssh = active_state; /* XXX */ 125b66f2d16SKris Kennaway const char *cp; 126acc1a9efSDag-Erling Smørgrav int i, r; 1275b9b2fafSBrian Feldman 1285b9b2fafSBrian Feldman /* reset options */ 1295b9b2fafSBrian Feldman auth_clear_options(); 1305b9b2fafSBrian Feldman 1311e8db6e2SBrian Feldman if (!opts) 1321e8db6e2SBrian Feldman return 1; 1331e8db6e2SBrian Feldman 1341e8db6e2SBrian Feldman while (*opts && *opts != ' ' && *opts != '\t') { 135acc1a9efSDag-Erling Smørgrav if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) { 136acc1a9efSDag-Erling Smørgrav key_is_cert_authority = r; 137b15c8340SDag-Erling Smørgrav goto next_option; 138b15c8340SDag-Erling Smørgrav } 139acc1a9efSDag-Erling Smørgrav if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) { 140acc1a9efSDag-Erling Smørgrav auth_debug_add("Key is restricted."); 141b66f2d16SKris Kennaway no_port_forwarding_flag = 1; 142b66f2d16SKris Kennaway no_agent_forwarding_flag = 1; 143b66f2d16SKris Kennaway no_x11_forwarding_flag = 1; 144b66f2d16SKris Kennaway no_pty_flag = 1; 145acc1a9efSDag-Erling Smørgrav no_user_rc = 1; 146b66f2d16SKris Kennaway goto next_option; 147b66f2d16SKris Kennaway } 148acc1a9efSDag-Erling Smørgrav if ((r = match_flag("port-forwarding", 1, &opts, 149acc1a9efSDag-Erling Smørgrav "Port forwarding")) != -1) { 150acc1a9efSDag-Erling Smørgrav no_port_forwarding_flag = r != 1; 151acc1a9efSDag-Erling Smørgrav goto next_option; 152acc1a9efSDag-Erling Smørgrav } 153acc1a9efSDag-Erling Smørgrav if ((r = match_flag("agent-forwarding", 1, &opts, 154acc1a9efSDag-Erling Smørgrav "Agent forwarding")) != -1) { 155acc1a9efSDag-Erling Smørgrav no_agent_forwarding_flag = r != 1; 156acc1a9efSDag-Erling Smørgrav goto next_option; 157acc1a9efSDag-Erling Smørgrav } 158acc1a9efSDag-Erling Smørgrav if ((r = match_flag("x11-forwarding", 1, &opts, 159acc1a9efSDag-Erling Smørgrav "X11 forwarding")) != -1) { 160acc1a9efSDag-Erling Smørgrav no_x11_forwarding_flag = r != 1; 161acc1a9efSDag-Erling Smørgrav goto next_option; 162acc1a9efSDag-Erling Smørgrav } 163acc1a9efSDag-Erling Smørgrav if ((r = match_flag("pty", 1, &opts, 164acc1a9efSDag-Erling Smørgrav "PTY allocation")) != -1) { 165acc1a9efSDag-Erling Smørgrav no_pty_flag = r != 1; 166acc1a9efSDag-Erling Smørgrav goto next_option; 167acc1a9efSDag-Erling Smørgrav } 168acc1a9efSDag-Erling Smørgrav if ((r = match_flag("user-rc", 1, &opts, 169acc1a9efSDag-Erling Smørgrav "User rc execution")) != -1) { 170acc1a9efSDag-Erling Smørgrav no_user_rc = r != 1; 171d4af9e69SDag-Erling Smørgrav goto next_option; 172d4af9e69SDag-Erling Smørgrav } 173b66f2d16SKris Kennaway cp = "command=\""; 1741e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 1751e8db6e2SBrian Feldman opts += strlen(cp); 176e4a9863fSDag-Erling Smørgrav free(forced_command); 1771e8db6e2SBrian Feldman forced_command = xmalloc(strlen(opts) + 1); 178b66f2d16SKris Kennaway i = 0; 1791e8db6e2SBrian Feldman while (*opts) { 1801e8db6e2SBrian Feldman if (*opts == '"') 181b66f2d16SKris Kennaway break; 1821e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 1831e8db6e2SBrian Feldman opts += 2; 184b66f2d16SKris Kennaway forced_command[i++] = '"'; 185b66f2d16SKris Kennaway continue; 186b66f2d16SKris Kennaway } 1871e8db6e2SBrian Feldman forced_command[i++] = *opts++; 188b66f2d16SKris Kennaway } 1891e8db6e2SBrian Feldman if (!*opts) { 190b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 1911e8db6e2SBrian Feldman file, linenum); 192545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 1931e8db6e2SBrian Feldman file, linenum); 194e4a9863fSDag-Erling Smørgrav free(forced_command); 1951e8db6e2SBrian Feldman forced_command = NULL; 1961e8db6e2SBrian Feldman goto bad_option; 197b66f2d16SKris Kennaway } 198761efaa7SDag-Erling Smørgrav forced_command[i] = '\0'; 1994a421b63SDag-Erling Smørgrav auth_debug_add("Forced command."); 2001e8db6e2SBrian Feldman opts++; 201b66f2d16SKris Kennaway goto next_option; 202b66f2d16SKris Kennaway } 203e2f6069cSDag-Erling Smørgrav cp = "principals=\""; 204e2f6069cSDag-Erling Smørgrav if (strncasecmp(opts, cp, strlen(cp)) == 0) { 205e2f6069cSDag-Erling Smørgrav opts += strlen(cp); 206e4a9863fSDag-Erling Smørgrav free(authorized_principals); 207e2f6069cSDag-Erling Smørgrav authorized_principals = xmalloc(strlen(opts) + 1); 208e2f6069cSDag-Erling Smørgrav i = 0; 209e2f6069cSDag-Erling Smørgrav while (*opts) { 210e2f6069cSDag-Erling Smørgrav if (*opts == '"') 211e2f6069cSDag-Erling Smørgrav break; 212e2f6069cSDag-Erling Smørgrav if (*opts == '\\' && opts[1] == '"') { 213e2f6069cSDag-Erling Smørgrav opts += 2; 214e2f6069cSDag-Erling Smørgrav authorized_principals[i++] = '"'; 215e2f6069cSDag-Erling Smørgrav continue; 216e2f6069cSDag-Erling Smørgrav } 217e2f6069cSDag-Erling Smørgrav authorized_principals[i++] = *opts++; 218e2f6069cSDag-Erling Smørgrav } 219e2f6069cSDag-Erling Smørgrav if (!*opts) { 220e2f6069cSDag-Erling Smørgrav debug("%.100s, line %lu: missing end quote", 221e2f6069cSDag-Erling Smørgrav file, linenum); 222e2f6069cSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 223e2f6069cSDag-Erling Smørgrav file, linenum); 224e4a9863fSDag-Erling Smørgrav free(authorized_principals); 225e2f6069cSDag-Erling Smørgrav authorized_principals = NULL; 226e2f6069cSDag-Erling Smørgrav goto bad_option; 227e2f6069cSDag-Erling Smørgrav } 228e2f6069cSDag-Erling Smørgrav authorized_principals[i] = '\0'; 229e2f6069cSDag-Erling Smørgrav auth_debug_add("principals: %.900s", 230e2f6069cSDag-Erling Smørgrav authorized_principals); 231e2f6069cSDag-Erling Smørgrav opts++; 232e2f6069cSDag-Erling Smørgrav goto next_option; 233e2f6069cSDag-Erling Smørgrav } 234b66f2d16SKris Kennaway cp = "environment=\""; 235557f75e5SDag-Erling Smørgrav if (strncasecmp(opts, cp, strlen(cp)) == 0) { 236b66f2d16SKris Kennaway char *s; 237b66f2d16SKris Kennaway struct envstring *new_envstring; 2381e8db6e2SBrian Feldman 2391e8db6e2SBrian Feldman opts += strlen(cp); 2401e8db6e2SBrian Feldman s = xmalloc(strlen(opts) + 1); 241b66f2d16SKris Kennaway i = 0; 2421e8db6e2SBrian Feldman while (*opts) { 2431e8db6e2SBrian Feldman if (*opts == '"') 244b66f2d16SKris Kennaway break; 2451e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 2461e8db6e2SBrian Feldman opts += 2; 247b66f2d16SKris Kennaway s[i++] = '"'; 248b66f2d16SKris Kennaway continue; 249b66f2d16SKris Kennaway } 2501e8db6e2SBrian Feldman s[i++] = *opts++; 251b66f2d16SKris Kennaway } 2521e8db6e2SBrian Feldman if (!*opts) { 253b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 2541e8db6e2SBrian Feldman file, linenum); 255545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 2561e8db6e2SBrian Feldman file, linenum); 257e4a9863fSDag-Erling Smørgrav free(s); 2581e8db6e2SBrian Feldman goto bad_option; 259b66f2d16SKris Kennaway } 260761efaa7SDag-Erling Smørgrav s[i] = '\0'; 2611e8db6e2SBrian Feldman opts++; 262557f75e5SDag-Erling Smørgrav if (options.permit_user_env) { 263557f75e5SDag-Erling Smørgrav auth_debug_add("Adding to environment: " 264557f75e5SDag-Erling Smørgrav "%.900s", s); 265557f75e5SDag-Erling Smørgrav debug("Adding to environment: %.900s", s); 266557f75e5SDag-Erling Smørgrav new_envstring = xcalloc(1, 267557f75e5SDag-Erling Smørgrav sizeof(*new_envstring)); 268b66f2d16SKris Kennaway new_envstring->s = s; 269b66f2d16SKris Kennaway new_envstring->next = custom_environment; 270b66f2d16SKris Kennaway custom_environment = new_envstring; 271557f75e5SDag-Erling Smørgrav s = NULL; 272557f75e5SDag-Erling Smørgrav } 273557f75e5SDag-Erling Smørgrav free(s); 274b66f2d16SKris Kennaway goto next_option; 275b66f2d16SKris Kennaway } 276b66f2d16SKris Kennaway cp = "from=\""; 2771e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 278076ad2f8SDag-Erling Smørgrav const char *remote_ip = ssh_remote_ipaddr(ssh); 279076ad2f8SDag-Erling Smørgrav const char *remote_host = auth_get_canonical_hostname( 280076ad2f8SDag-Erling Smørgrav ssh, options.use_dns); 2811e8db6e2SBrian Feldman char *patterns = xmalloc(strlen(opts) + 1); 2821e8db6e2SBrian Feldman 2831e8db6e2SBrian Feldman opts += strlen(cp); 284b66f2d16SKris Kennaway i = 0; 2851e8db6e2SBrian Feldman while (*opts) { 2861e8db6e2SBrian Feldman if (*opts == '"') 287b66f2d16SKris Kennaway break; 2881e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 2891e8db6e2SBrian Feldman opts += 2; 290b66f2d16SKris Kennaway patterns[i++] = '"'; 291b66f2d16SKris Kennaway continue; 292b66f2d16SKris Kennaway } 2931e8db6e2SBrian Feldman patterns[i++] = *opts++; 294b66f2d16SKris Kennaway } 2951e8db6e2SBrian Feldman if (!*opts) { 296b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 2971e8db6e2SBrian Feldman file, linenum); 298545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 2991e8db6e2SBrian Feldman file, linenum); 300e4a9863fSDag-Erling Smørgrav free(patterns); 3011e8db6e2SBrian Feldman goto bad_option; 302b66f2d16SKris Kennaway } 303761efaa7SDag-Erling Smørgrav patterns[i] = '\0'; 3041e8db6e2SBrian Feldman opts++; 305d4af9e69SDag-Erling Smørgrav switch (match_host_and_ip(remote_host, remote_ip, 306d4af9e69SDag-Erling Smørgrav patterns)) { 307d4af9e69SDag-Erling Smørgrav case 1: 308e4a9863fSDag-Erling Smørgrav free(patterns); 309d4af9e69SDag-Erling Smørgrav /* Host name matches. */ 310d4af9e69SDag-Erling Smørgrav goto next_option; 311d4af9e69SDag-Erling Smørgrav case -1: 312d4af9e69SDag-Erling Smørgrav debug("%.100s, line %lu: invalid criteria", 313d4af9e69SDag-Erling Smørgrav file, linenum); 314d4af9e69SDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: " 315d4af9e69SDag-Erling Smørgrav "invalid criteria", file, linenum); 316d4af9e69SDag-Erling Smørgrav /* FALLTHROUGH */ 317d4af9e69SDag-Erling Smørgrav case 0: 318e4a9863fSDag-Erling Smørgrav free(patterns); 319d95e11bfSDag-Erling Smørgrav logit("Authentication tried for %.100s with " 3201e8db6e2SBrian Feldman "correct key but not from a permitted " 3211e8db6e2SBrian Feldman "host (host=%.200s, ip=%.200s).", 3221e8db6e2SBrian Feldman pw->pw_name, remote_host, remote_ip); 323545d5ecaSDag-Erling Smørgrav auth_debug_add("Your host '%.200s' is not " 3241e8db6e2SBrian Feldman "permitted to use this key for login.", 3251e8db6e2SBrian Feldman remote_host); 326d4af9e69SDag-Erling Smørgrav break; 327d4af9e69SDag-Erling Smørgrav } 328b66f2d16SKris Kennaway /* deny access */ 329b66f2d16SKris Kennaway return 0; 330b66f2d16SKris Kennaway } 3311e8db6e2SBrian Feldman cp = "permitopen=\""; 3321e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 3335e8dbd04SDag-Erling Smørgrav char *host, *p; 334cce7d346SDag-Erling Smørgrav int port; 3351e8db6e2SBrian Feldman char *patterns = xmalloc(strlen(opts) + 1); 3361e8db6e2SBrian Feldman 3371e8db6e2SBrian Feldman opts += strlen(cp); 3381e8db6e2SBrian Feldman i = 0; 3391e8db6e2SBrian Feldman while (*opts) { 3401e8db6e2SBrian Feldman if (*opts == '"') 3411e8db6e2SBrian Feldman break; 3421e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 3431e8db6e2SBrian Feldman opts += 2; 3441e8db6e2SBrian Feldman patterns[i++] = '"'; 3451e8db6e2SBrian Feldman continue; 3461e8db6e2SBrian Feldman } 3471e8db6e2SBrian Feldman patterns[i++] = *opts++; 3481e8db6e2SBrian Feldman } 3491e8db6e2SBrian Feldman if (!*opts) { 3501e8db6e2SBrian Feldman debug("%.100s, line %lu: missing end quote", 3511e8db6e2SBrian Feldman file, linenum); 3525e8dbd04SDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing " 3535e8dbd04SDag-Erling Smørgrav "end quote", file, linenum); 354e4a9863fSDag-Erling Smørgrav free(patterns); 3551e8db6e2SBrian Feldman goto bad_option; 3561e8db6e2SBrian Feldman } 357761efaa7SDag-Erling Smørgrav patterns[i] = '\0'; 3581e8db6e2SBrian Feldman opts++; 3595e8dbd04SDag-Erling Smørgrav p = patterns; 360a0ee8cc6SDag-Erling Smørgrav /* XXX - add streamlocal support */ 3615e8dbd04SDag-Erling Smørgrav host = hpdelim(&p); 3625e8dbd04SDag-Erling Smørgrav if (host == NULL || strlen(host) >= NI_MAXHOST) { 3635e8dbd04SDag-Erling Smørgrav debug("%.100s, line %lu: Bad permitopen " 3645e8dbd04SDag-Erling Smørgrav "specification <%.100s>", file, linenum, 3655e8dbd04SDag-Erling Smørgrav patterns); 366545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: " 3675e8dbd04SDag-Erling Smørgrav "Bad permitopen specification", file, 3685e8dbd04SDag-Erling Smørgrav linenum); 369e4a9863fSDag-Erling Smørgrav free(patterns); 3701e8db6e2SBrian Feldman goto bad_option; 3711e8db6e2SBrian Feldman } 3725e8dbd04SDag-Erling Smørgrav host = cleanhostname(host); 373462c32cbSDag-Erling Smørgrav if (p == NULL || (port = permitopen_port(p)) < 0) { 3745e8dbd04SDag-Erling Smørgrav debug("%.100s, line %lu: Bad permitopen port " 3755e8dbd04SDag-Erling Smørgrav "<%.100s>", file, linenum, p ? p : ""); 376545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: " 377ae1f160dSDag-Erling Smørgrav "Bad permitopen port", file, linenum); 378e4a9863fSDag-Erling Smørgrav free(patterns); 3791e8db6e2SBrian Feldman goto bad_option; 3801e8db6e2SBrian Feldman } 3816888a9beSDag-Erling Smørgrav if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) 382ae1f160dSDag-Erling Smørgrav channel_add_permitted_opens(host, port); 383e4a9863fSDag-Erling Smørgrav free(patterns); 3841e8db6e2SBrian Feldman goto next_option; 3851e8db6e2SBrian Feldman } 386021d409fSDag-Erling Smørgrav cp = "tunnel=\""; 387021d409fSDag-Erling Smørgrav if (strncasecmp(opts, cp, strlen(cp)) == 0) { 388021d409fSDag-Erling Smørgrav char *tun = NULL; 389021d409fSDag-Erling Smørgrav opts += strlen(cp); 390021d409fSDag-Erling Smørgrav tun = xmalloc(strlen(opts) + 1); 391021d409fSDag-Erling Smørgrav i = 0; 392021d409fSDag-Erling Smørgrav while (*opts) { 393021d409fSDag-Erling Smørgrav if (*opts == '"') 394021d409fSDag-Erling Smørgrav break; 395021d409fSDag-Erling Smørgrav tun[i++] = *opts++; 396021d409fSDag-Erling Smørgrav } 397021d409fSDag-Erling Smørgrav if (!*opts) { 398021d409fSDag-Erling Smørgrav debug("%.100s, line %lu: missing end quote", 399021d409fSDag-Erling Smørgrav file, linenum); 400021d409fSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 401021d409fSDag-Erling Smørgrav file, linenum); 402e4a9863fSDag-Erling Smørgrav free(tun); 403021d409fSDag-Erling Smørgrav forced_tun_device = -1; 404021d409fSDag-Erling Smørgrav goto bad_option; 405021d409fSDag-Erling Smørgrav } 406761efaa7SDag-Erling Smørgrav tun[i] = '\0'; 407021d409fSDag-Erling Smørgrav forced_tun_device = a2tun(tun, NULL); 408e4a9863fSDag-Erling Smørgrav free(tun); 409021d409fSDag-Erling Smørgrav if (forced_tun_device == SSH_TUNID_ERR) { 410021d409fSDag-Erling Smørgrav debug("%.100s, line %lu: invalid tun device", 411021d409fSDag-Erling Smørgrav file, linenum); 412021d409fSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: invalid tun device", 413021d409fSDag-Erling Smørgrav file, linenum); 414021d409fSDag-Erling Smørgrav forced_tun_device = -1; 415021d409fSDag-Erling Smørgrav goto bad_option; 416021d409fSDag-Erling Smørgrav } 417021d409fSDag-Erling Smørgrav auth_debug_add("Forced tun device: %d", forced_tun_device); 418021d409fSDag-Erling Smørgrav opts++; 419021d409fSDag-Erling Smørgrav goto next_option; 420021d409fSDag-Erling Smørgrav } 421b66f2d16SKris Kennaway next_option: 422b66f2d16SKris Kennaway /* 423b66f2d16SKris Kennaway * Skip the comma, and move to the next option 424b66f2d16SKris Kennaway * (or break out if there are no more). 425b66f2d16SKris Kennaway */ 4261e8db6e2SBrian Feldman if (!*opts) 427b66f2d16SKris Kennaway fatal("Bugs in auth-options.c option processing."); 4281e8db6e2SBrian Feldman if (*opts == ' ' || *opts == '\t') 429b66f2d16SKris Kennaway break; /* End of options. */ 4301e8db6e2SBrian Feldman if (*opts != ',') 431b66f2d16SKris Kennaway goto bad_option; 4321e8db6e2SBrian Feldman opts++; 433b66f2d16SKris Kennaway /* Process the next option. */ 434b66f2d16SKris Kennaway } 435545d5ecaSDag-Erling Smørgrav 436b66f2d16SKris Kennaway /* grant access */ 437b66f2d16SKris Kennaway return 1; 438b66f2d16SKris Kennaway 439b66f2d16SKris Kennaway bad_option: 440d95e11bfSDag-Erling Smørgrav logit("Bad options in %.100s file, line %lu: %.50s", 4411e8db6e2SBrian Feldman file, linenum, opts); 442545d5ecaSDag-Erling Smørgrav auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 4431e8db6e2SBrian Feldman file, linenum, opts); 444545d5ecaSDag-Erling Smørgrav 445b66f2d16SKris Kennaway /* deny access */ 446b66f2d16SKris Kennaway return 0; 447b66f2d16SKris Kennaway } 448b15c8340SDag-Erling Smørgrav 449e2f6069cSDag-Erling Smørgrav #define OPTIONS_CRITICAL 1 450e2f6069cSDag-Erling Smørgrav #define OPTIONS_EXTENSIONS 2 451e2f6069cSDag-Erling Smørgrav static int 452bc5531deSDag-Erling Smørgrav parse_option_list(struct sshbuf *oblob, struct passwd *pw, 453e2f6069cSDag-Erling Smørgrav u_int which, int crit, 454e2f6069cSDag-Erling Smørgrav int *cert_no_port_forwarding_flag, 455e2f6069cSDag-Erling Smørgrav int *cert_no_agent_forwarding_flag, 456e2f6069cSDag-Erling Smørgrav int *cert_no_x11_forwarding_flag, 457e2f6069cSDag-Erling Smørgrav int *cert_no_pty_flag, 458e2f6069cSDag-Erling Smørgrav int *cert_no_user_rc, 459e2f6069cSDag-Erling Smørgrav char **cert_forced_command, 460e2f6069cSDag-Erling Smørgrav int *cert_source_address_done) 461b15c8340SDag-Erling Smørgrav { 462076ad2f8SDag-Erling Smørgrav struct ssh *ssh = active_state; /* XXX */ 463e2f6069cSDag-Erling Smørgrav char *command, *allowed; 464e2f6069cSDag-Erling Smørgrav const char *remote_ip; 465e4a9863fSDag-Erling Smørgrav char *name = NULL; 466bc5531deSDag-Erling Smørgrav struct sshbuf *c = NULL, *data = NULL; 467bc5531deSDag-Erling Smørgrav int r, ret = -1, result, found; 468b15c8340SDag-Erling Smørgrav 469bc5531deSDag-Erling Smørgrav if ((c = sshbuf_fromb(oblob)) == NULL) { 470bc5531deSDag-Erling Smørgrav error("%s: sshbuf_fromb failed", __func__); 471b15c8340SDag-Erling Smørgrav goto out; 472b15c8340SDag-Erling Smørgrav } 473bc5531deSDag-Erling Smørgrav 474bc5531deSDag-Erling Smørgrav while (sshbuf_len(c) > 0) { 475bc5531deSDag-Erling Smørgrav sshbuf_free(data); 476bc5531deSDag-Erling Smørgrav data = NULL; 477bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 || 478bc5531deSDag-Erling Smørgrav (r = sshbuf_froms(c, &data)) != 0) { 479bc5531deSDag-Erling Smørgrav error("Unable to parse certificate options: %s", 480bc5531deSDag-Erling Smørgrav ssh_err(r)); 481bc5531deSDag-Erling Smørgrav goto out; 482bc5531deSDag-Erling Smørgrav } 483bc5531deSDag-Erling Smørgrav debug3("found certificate option \"%.100s\" len %zu", 484bc5531deSDag-Erling Smørgrav name, sshbuf_len(data)); 485e2f6069cSDag-Erling Smørgrav found = 0; 486e2f6069cSDag-Erling Smørgrav if ((which & OPTIONS_EXTENSIONS) != 0) { 487e2f6069cSDag-Erling Smørgrav if (strcmp(name, "permit-X11-forwarding") == 0) { 488e2f6069cSDag-Erling Smørgrav *cert_no_x11_forwarding_flag = 0; 489e2f6069cSDag-Erling Smørgrav found = 1; 490e2f6069cSDag-Erling Smørgrav } else if (strcmp(name, 491e2f6069cSDag-Erling Smørgrav "permit-agent-forwarding") == 0) { 492e2f6069cSDag-Erling Smørgrav *cert_no_agent_forwarding_flag = 0; 493e2f6069cSDag-Erling Smørgrav found = 1; 494e2f6069cSDag-Erling Smørgrav } else if (strcmp(name, 495e2f6069cSDag-Erling Smørgrav "permit-port-forwarding") == 0) { 496e2f6069cSDag-Erling Smørgrav *cert_no_port_forwarding_flag = 0; 497e2f6069cSDag-Erling Smørgrav found = 1; 498e2f6069cSDag-Erling Smørgrav } else if (strcmp(name, "permit-pty") == 0) { 499e2f6069cSDag-Erling Smørgrav *cert_no_pty_flag = 0; 500e2f6069cSDag-Erling Smørgrav found = 1; 501e2f6069cSDag-Erling Smørgrav } else if (strcmp(name, "permit-user-rc") == 0) { 502e2f6069cSDag-Erling Smørgrav *cert_no_user_rc = 0; 503e2f6069cSDag-Erling Smørgrav found = 1; 504e2f6069cSDag-Erling Smørgrav } 505e2f6069cSDag-Erling Smørgrav } 506e2f6069cSDag-Erling Smørgrav if (!found && (which & OPTIONS_CRITICAL) != 0) { 507e2f6069cSDag-Erling Smørgrav if (strcmp(name, "force-command") == 0) { 508bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(data, &command, 509bc5531deSDag-Erling Smørgrav NULL)) != 0) { 510bc5531deSDag-Erling Smørgrav error("Unable to parse \"%s\" " 511bc5531deSDag-Erling Smørgrav "section: %s", name, ssh_err(r)); 512b15c8340SDag-Erling Smørgrav goto out; 513b15c8340SDag-Erling Smørgrav } 514e2f6069cSDag-Erling Smørgrav if (*cert_forced_command != NULL) { 515b15c8340SDag-Erling Smørgrav error("Certificate has multiple " 516e2f6069cSDag-Erling Smørgrav "force-command options"); 517e4a9863fSDag-Erling Smørgrav free(command); 518b15c8340SDag-Erling Smørgrav goto out; 519b15c8340SDag-Erling Smørgrav } 520e2f6069cSDag-Erling Smørgrav *cert_forced_command = command; 521e2f6069cSDag-Erling Smørgrav found = 1; 522e2f6069cSDag-Erling Smørgrav } 523e2f6069cSDag-Erling Smørgrav if (strcmp(name, "source-address") == 0) { 524bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(data, &allowed, 525bc5531deSDag-Erling Smørgrav NULL)) != 0) { 526bc5531deSDag-Erling Smørgrav error("Unable to parse \"%s\" " 527bc5531deSDag-Erling Smørgrav "section: %s", name, ssh_err(r)); 528b15c8340SDag-Erling Smørgrav goto out; 529b15c8340SDag-Erling Smørgrav } 530e2f6069cSDag-Erling Smørgrav if ((*cert_source_address_done)++) { 531b15c8340SDag-Erling Smørgrav error("Certificate has multiple " 532e2f6069cSDag-Erling Smørgrav "source-address options"); 533e4a9863fSDag-Erling Smørgrav free(allowed); 534b15c8340SDag-Erling Smørgrav goto out; 535b15c8340SDag-Erling Smørgrav } 536076ad2f8SDag-Erling Smørgrav remote_ip = ssh_remote_ipaddr(ssh); 537f7167e0eSDag-Erling Smørgrav result = addr_match_cidr_list(remote_ip, 538f7167e0eSDag-Erling Smørgrav allowed); 539f7167e0eSDag-Erling Smørgrav free(allowed); 540f7167e0eSDag-Erling Smørgrav switch (result) { 541b15c8340SDag-Erling Smørgrav case 1: 542b15c8340SDag-Erling Smørgrav /* accepted */ 543b15c8340SDag-Erling Smørgrav break; 544b15c8340SDag-Erling Smørgrav case 0: 545b15c8340SDag-Erling Smørgrav /* no match */ 546e2f6069cSDag-Erling Smørgrav logit("Authentication tried for %.100s " 547e2f6069cSDag-Erling Smørgrav "with valid certificate but not " 548e2f6069cSDag-Erling Smørgrav "from a permitted host " 549e2f6069cSDag-Erling Smørgrav "(ip=%.200s).", pw->pw_name, 550e2f6069cSDag-Erling Smørgrav remote_ip); 551e2f6069cSDag-Erling Smørgrav auth_debug_add("Your address '%.200s' " 552e2f6069cSDag-Erling Smørgrav "is not permitted to use this " 553e2f6069cSDag-Erling Smørgrav "certificate for login.", 554e2f6069cSDag-Erling Smørgrav remote_ip); 555b15c8340SDag-Erling Smørgrav goto out; 556b15c8340SDag-Erling Smørgrav case -1: 557f7167e0eSDag-Erling Smørgrav default: 558e2f6069cSDag-Erling Smørgrav error("Certificate source-address " 559e2f6069cSDag-Erling Smørgrav "contents invalid"); 560b15c8340SDag-Erling Smørgrav goto out; 561b15c8340SDag-Erling Smørgrav } 562e2f6069cSDag-Erling Smørgrav found = 1; 563e2f6069cSDag-Erling Smørgrav } 564b15c8340SDag-Erling Smørgrav } 565b15c8340SDag-Erling Smørgrav 566e2f6069cSDag-Erling Smørgrav if (!found) { 567e2f6069cSDag-Erling Smørgrav if (crit) { 568e2f6069cSDag-Erling Smørgrav error("Certificate critical option \"%s\" " 569e2f6069cSDag-Erling Smørgrav "is not supported", name); 570e2f6069cSDag-Erling Smørgrav goto out; 571e2f6069cSDag-Erling Smørgrav } else { 572e2f6069cSDag-Erling Smørgrav logit("Certificate extension \"%s\" " 573e2f6069cSDag-Erling Smørgrav "is not supported", name); 574e2f6069cSDag-Erling Smørgrav } 575bc5531deSDag-Erling Smørgrav } else if (sshbuf_len(data) != 0) { 576e2f6069cSDag-Erling Smørgrav error("Certificate option \"%s\" corrupt " 577b15c8340SDag-Erling Smørgrav "(extra data)", name); 578b15c8340SDag-Erling Smørgrav goto out; 579b15c8340SDag-Erling Smørgrav } 580e4a9863fSDag-Erling Smørgrav free(name); 581e4a9863fSDag-Erling Smørgrav name = NULL; 582b15c8340SDag-Erling Smørgrav } 583e2f6069cSDag-Erling Smørgrav /* successfully parsed all options */ 584b15c8340SDag-Erling Smørgrav ret = 0; 585b15c8340SDag-Erling Smørgrav 586e2f6069cSDag-Erling Smørgrav out: 587e2f6069cSDag-Erling Smørgrav if (ret != 0 && 588e2f6069cSDag-Erling Smørgrav cert_forced_command != NULL && 589e2f6069cSDag-Erling Smørgrav *cert_forced_command != NULL) { 590e4a9863fSDag-Erling Smørgrav free(*cert_forced_command); 591e2f6069cSDag-Erling Smørgrav *cert_forced_command = NULL; 592e2f6069cSDag-Erling Smørgrav } 593e4a9863fSDag-Erling Smørgrav free(name); 594bc5531deSDag-Erling Smørgrav sshbuf_free(data); 595bc5531deSDag-Erling Smørgrav sshbuf_free(c); 596e2f6069cSDag-Erling Smørgrav return ret; 597e2f6069cSDag-Erling Smørgrav } 598e2f6069cSDag-Erling Smørgrav 599e2f6069cSDag-Erling Smørgrav /* 600e2f6069cSDag-Erling Smørgrav * Set options from critical certificate options. These supersede user key 601e2f6069cSDag-Erling Smørgrav * options so this must be called after auth_parse_options(). 602e2f6069cSDag-Erling Smørgrav */ 603e2f6069cSDag-Erling Smørgrav int 604ca86bcf2SDag-Erling Smørgrav auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason) 605e2f6069cSDag-Erling Smørgrav { 606e2f6069cSDag-Erling Smørgrav int cert_no_port_forwarding_flag = 1; 607e2f6069cSDag-Erling Smørgrav int cert_no_agent_forwarding_flag = 1; 608e2f6069cSDag-Erling Smørgrav int cert_no_x11_forwarding_flag = 1; 609e2f6069cSDag-Erling Smørgrav int cert_no_pty_flag = 1; 610e2f6069cSDag-Erling Smørgrav int cert_no_user_rc = 1; 611e2f6069cSDag-Erling Smørgrav char *cert_forced_command = NULL; 612e2f6069cSDag-Erling Smørgrav int cert_source_address_done = 0; 613e2f6069cSDag-Erling Smørgrav 614ca86bcf2SDag-Erling Smørgrav *reason = "invalid certificate options"; 615ca86bcf2SDag-Erling Smørgrav 616e2f6069cSDag-Erling Smørgrav /* Separate options and extensions for v01 certs */ 617bc5531deSDag-Erling Smørgrav if (parse_option_list(k->cert->critical, pw, 618e2f6069cSDag-Erling Smørgrav OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, 619e2f6069cSDag-Erling Smørgrav &cert_forced_command, 620e2f6069cSDag-Erling Smørgrav &cert_source_address_done) == -1) 621e2f6069cSDag-Erling Smørgrav return -1; 622bc5531deSDag-Erling Smørgrav if (parse_option_list(k->cert->extensions, pw, 623557f75e5SDag-Erling Smørgrav OPTIONS_EXTENSIONS, 0, 624e2f6069cSDag-Erling Smørgrav &cert_no_port_forwarding_flag, 625e2f6069cSDag-Erling Smørgrav &cert_no_agent_forwarding_flag, 626e2f6069cSDag-Erling Smørgrav &cert_no_x11_forwarding_flag, 627e2f6069cSDag-Erling Smørgrav &cert_no_pty_flag, 628e2f6069cSDag-Erling Smørgrav &cert_no_user_rc, 629e2f6069cSDag-Erling Smørgrav NULL, NULL) == -1) 630e2f6069cSDag-Erling Smørgrav return -1; 631e2f6069cSDag-Erling Smørgrav 632b15c8340SDag-Erling Smørgrav no_port_forwarding_flag |= cert_no_port_forwarding_flag; 633b15c8340SDag-Erling Smørgrav no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; 634b15c8340SDag-Erling Smørgrav no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; 635b15c8340SDag-Erling Smørgrav no_pty_flag |= cert_no_pty_flag; 636b15c8340SDag-Erling Smørgrav no_user_rc |= cert_no_user_rc; 637ca86bcf2SDag-Erling Smørgrav /* 638ca86bcf2SDag-Erling Smørgrav * Only permit both CA and key option forced-command if they match. 639ca86bcf2SDag-Erling Smørgrav * Otherwise refuse the certificate. 640ca86bcf2SDag-Erling Smørgrav */ 641ca86bcf2SDag-Erling Smørgrav if (cert_forced_command != NULL && forced_command != NULL) { 642ca86bcf2SDag-Erling Smørgrav if (strcmp(forced_command, cert_forced_command) == 0) { 643e4a9863fSDag-Erling Smørgrav free(forced_command); 644b15c8340SDag-Erling Smørgrav forced_command = cert_forced_command; 645ca86bcf2SDag-Erling Smørgrav } else { 646ca86bcf2SDag-Erling Smørgrav *reason = "certificate and key options forced command " 647ca86bcf2SDag-Erling Smørgrav "do not match"; 648ca86bcf2SDag-Erling Smørgrav free(cert_forced_command); 649ca86bcf2SDag-Erling Smørgrav return -1; 650b15c8340SDag-Erling Smørgrav } 651ca86bcf2SDag-Erling Smørgrav } else if (cert_forced_command != NULL) 652ca86bcf2SDag-Erling Smørgrav forced_command = cert_forced_command; 653ca86bcf2SDag-Erling Smørgrav /* success */ 654ca86bcf2SDag-Erling Smørgrav *reason = NULL; 655e2f6069cSDag-Erling Smørgrav return 0; 656b15c8340SDag-Erling Smørgrav } 657b15c8340SDag-Erling Smørgrav 658