auth-options.c revision 157016
1219820Sjeff/* 2219820Sjeff * Author: Tatu Ylonen <ylo@cs.hut.fi> 3219820Sjeff * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4219820Sjeff * All rights reserved 5219820Sjeff * As far as I am concerned, the code I have written for this software 6219820Sjeff * can be used freely for any purpose. Any derived versions of this 7219820Sjeff * software must be clearly marked as such, and if the derived work is 8219820Sjeff * incompatible with the protocol description in the RFC file, it must be 9219820Sjeff * called by a name other than "ssh" or "Secure Shell". 10219820Sjeff */ 11219820Sjeff 12219820Sjeff#include "includes.h" 13219820SjeffRCSID("$OpenBSD: auth-options.c,v 1.33 2005/12/08 18:34:11 reyk Exp $"); 14219820Sjeff 15219820Sjeff#include "xmalloc.h" 16219820Sjeff#include "match.h" 17219820Sjeff#include "log.h" 18219820Sjeff#include "canohost.h" 19219820Sjeff#include "channels.h" 20219820Sjeff#include "auth-options.h" 21219820Sjeff#include "servconf.h" 22219820Sjeff#include "misc.h" 23219820Sjeff#include "monitor_wrap.h" 24219820Sjeff#include "auth.h" 25219820Sjeff 26219820Sjeff/* Flags set authorized_keys flags */ 27219820Sjeffint no_port_forwarding_flag = 0; 28219820Sjeffint no_agent_forwarding_flag = 0; 29219820Sjeffint no_x11_forwarding_flag = 0; 30219820Sjeffint no_pty_flag = 0; 31219820Sjeff 32219820Sjeff/* "command=" option. */ 33219820Sjeffchar *forced_command = NULL; 34219820Sjeff 35219820Sjeff/* "environment=" options. */ 36219820Sjeffstruct envstring *custom_environment = NULL; 37219820Sjeff 38219820Sjeff/* "tunnel=" option. */ 39219820Sjeffint forced_tun_device = -1; 40219820Sjeff 41219820Sjeffextern ServerOptions options; 42219820Sjeff 43219820Sjeffvoid 44219820Sjeffauth_clear_options(void) 45219820Sjeff{ 46219820Sjeff no_agent_forwarding_flag = 0; 47219820Sjeff no_port_forwarding_flag = 0; 48219820Sjeff no_pty_flag = 0; 49219820Sjeff no_x11_forwarding_flag = 0; 50219820Sjeff while (custom_environment) { 51219820Sjeff struct envstring *ce = custom_environment; 52219820Sjeff custom_environment = ce->next; 53219820Sjeff xfree(ce->s); 54219820Sjeff xfree(ce); 55219820Sjeff } 56219820Sjeff if (forced_command) { 57219820Sjeff xfree(forced_command); 58219820Sjeff forced_command = NULL; 59219820Sjeff } 60219820Sjeff forced_tun_device = -1; 61219820Sjeff channel_clear_permitted_opens(); 62219820Sjeff auth_debug_reset(); 63219820Sjeff} 64219820Sjeff 65219820Sjeff/* 66219820Sjeff * return 1 if access is granted, 0 if not. 67219820Sjeff * side effect: sets key option flags 68219820Sjeff */ 69219820Sjeffint 70219820Sjeffauth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) 71219820Sjeff{ 72219820Sjeff const char *cp; 73219820Sjeff int i; 74219820Sjeff 75219820Sjeff /* reset options */ 76219820Sjeff auth_clear_options(); 77219820Sjeff 78219820Sjeff if (!opts) 79219820Sjeff return 1; 80219820Sjeff 81219820Sjeff while (*opts && *opts != ' ' && *opts != '\t') { 82219820Sjeff cp = "no-port-forwarding"; 83219820Sjeff if (strncasecmp(opts, cp, strlen(cp)) == 0) { 84219820Sjeff auth_debug_add("Port forwarding disabled."); 85219820Sjeff no_port_forwarding_flag = 1; 86219820Sjeff opts += strlen(cp); 87219820Sjeff goto next_option; 88219820Sjeff } 89219820Sjeff cp = "no-agent-forwarding"; 90219820Sjeff if (strncasecmp(opts, cp, strlen(cp)) == 0) { 91219820Sjeff auth_debug_add("Agent forwarding disabled."); 92219820Sjeff no_agent_forwarding_flag = 1; 93219820Sjeff opts += strlen(cp); 94219820Sjeff goto next_option; 95219820Sjeff } 96219820Sjeff cp = "no-X11-forwarding"; 97219820Sjeff if (strncasecmp(opts, cp, strlen(cp)) == 0) { 98219820Sjeff auth_debug_add("X11 forwarding disabled."); 99219820Sjeff no_x11_forwarding_flag = 1; 100219820Sjeff opts += strlen(cp); 101219820Sjeff goto next_option; 102219820Sjeff } 103219820Sjeff cp = "no-pty"; 104219820Sjeff if (strncasecmp(opts, cp, strlen(cp)) == 0) { 105219820Sjeff auth_debug_add("Pty allocation disabled."); 106219820Sjeff no_pty_flag = 1; 107219820Sjeff opts += strlen(cp); 108219820Sjeff goto next_option; 109219820Sjeff } 110219820Sjeff cp = "command=\""; 111219820Sjeff if (strncasecmp(opts, cp, strlen(cp)) == 0) { 112219820Sjeff opts += strlen(cp); 113219820Sjeff forced_command = xmalloc(strlen(opts) + 1); 114219820Sjeff i = 0; 115219820Sjeff while (*opts) { 116219820Sjeff if (*opts == '"') 117219820Sjeff break; 118219820Sjeff if (*opts == '\\' && opts[1] == '"') { 119219820Sjeff opts += 2; 120219820Sjeff forced_command[i++] = '"'; 121219820Sjeff continue; 122219820Sjeff } 123219820Sjeff forced_command[i++] = *opts++; 124219820Sjeff } 125219820Sjeff if (!*opts) { 126219820Sjeff debug("%.100s, line %lu: missing end quote", 127219820Sjeff file, linenum); 128219820Sjeff auth_debug_add("%.100s, line %lu: missing end quote", 129219820Sjeff file, linenum); 130219820Sjeff xfree(forced_command); 131219820Sjeff forced_command = NULL; 132219820Sjeff goto bad_option; 133219820Sjeff } 134219820Sjeff forced_command[i] = 0; 135219820Sjeff auth_debug_add("Forced command: %.900s", forced_command); 136219820Sjeff opts++; 137219820Sjeff goto next_option; 138219820Sjeff } 139219820Sjeff cp = "environment=\""; 140219820Sjeff if (options.permit_user_env && 141219820Sjeff strncasecmp(opts, cp, strlen(cp)) == 0) { 142219820Sjeff char *s; 143219820Sjeff struct envstring *new_envstring; 144219820Sjeff 145219820Sjeff opts += strlen(cp); 146219820Sjeff s = xmalloc(strlen(opts) + 1); 147219820Sjeff i = 0; 148219820Sjeff while (*opts) { 149219820Sjeff if (*opts == '"') 150219820Sjeff break; 151219820Sjeff if (*opts == '\\' && opts[1] == '"') { 152219820Sjeff opts += 2; 153219820Sjeff s[i++] = '"'; 154219820Sjeff continue; 155219820Sjeff } 156219820Sjeff s[i++] = *opts++; 157219820Sjeff } 158219820Sjeff if (!*opts) { 159219820Sjeff debug("%.100s, line %lu: missing end quote", 160219820Sjeff file, linenum); 161219820Sjeff auth_debug_add("%.100s, line %lu: missing end quote", 162219820Sjeff file, linenum); 163219820Sjeff xfree(s); 164219820Sjeff goto bad_option; 165219820Sjeff } 166219820Sjeff s[i] = 0; 167219820Sjeff auth_debug_add("Adding to environment: %.900s", s); 168219820Sjeff debug("Adding to environment: %.900s", s); 169219820Sjeff opts++; 170219820Sjeff new_envstring = xmalloc(sizeof(struct envstring)); 171219820Sjeff new_envstring->s = s; 172219820Sjeff new_envstring->next = custom_environment; 173219820Sjeff custom_environment = new_envstring; 174219820Sjeff goto next_option; 175219820Sjeff } 176219820Sjeff cp = "from=\""; 177219820Sjeff if (strncasecmp(opts, cp, strlen(cp)) == 0) { 178219820Sjeff const char *remote_ip = get_remote_ipaddr(); 179219820Sjeff const char *remote_host = get_canonical_hostname( 180219820Sjeff options.use_dns); 181219820Sjeff char *patterns = xmalloc(strlen(opts) + 1); 182219820Sjeff 183219820Sjeff opts += strlen(cp); 184219820Sjeff i = 0; 185219820Sjeff while (*opts) { 186219820Sjeff if (*opts == '"') 187219820Sjeff break; 188219820Sjeff if (*opts == '\\' && opts[1] == '"') { 189219820Sjeff opts += 2; 190219820Sjeff patterns[i++] = '"'; 191219820Sjeff continue; 192219820Sjeff } 193219820Sjeff patterns[i++] = *opts++; 194219820Sjeff } 195219820Sjeff if (!*opts) { 196219820Sjeff debug("%.100s, line %lu: missing end quote", 197219820Sjeff file, linenum); 198219820Sjeff auth_debug_add("%.100s, line %lu: missing end quote", 199219820Sjeff file, linenum); 200219820Sjeff xfree(patterns); 201219820Sjeff goto bad_option; 202219820Sjeff } 203219820Sjeff patterns[i] = 0; 204219820Sjeff opts++; 205219820Sjeff if (match_host_and_ip(remote_host, remote_ip, 206219820Sjeff patterns) != 1) { 207219820Sjeff xfree(patterns); 208219820Sjeff logit("Authentication tried for %.100s with " 209219820Sjeff "correct key but not from a permitted " 210219820Sjeff "host (host=%.200s, ip=%.200s).", 211219820Sjeff pw->pw_name, remote_host, remote_ip); 212219820Sjeff auth_debug_add("Your host '%.200s' is not " 213219820Sjeff "permitted to use this key for login.", 214219820Sjeff remote_host); 215219820Sjeff /* deny access */ 216219820Sjeff return 0; 217219820Sjeff } 218219820Sjeff xfree(patterns); 219219820Sjeff /* Host name matches. */ 220219820Sjeff goto next_option; 221219820Sjeff } 222219820Sjeff cp = "permitopen=\""; 223219820Sjeff if (strncasecmp(opts, cp, strlen(cp)) == 0) { 224219820Sjeff char *host, *p; 225219820Sjeff u_short port; 226219820Sjeff char *patterns = xmalloc(strlen(opts) + 1); 227219820Sjeff 228219820Sjeff opts += strlen(cp); 229219820Sjeff i = 0; 230219820Sjeff while (*opts) { 231219820Sjeff if (*opts == '"') 232219820Sjeff break; 233219820Sjeff if (*opts == '\\' && opts[1] == '"') { 234219820Sjeff opts += 2; 235219820Sjeff patterns[i++] = '"'; 236219820Sjeff continue; 237219820Sjeff } 238219820Sjeff patterns[i++] = *opts++; 239219820Sjeff } 240219820Sjeff if (!*opts) { 241219820Sjeff debug("%.100s, line %lu: missing end quote", 242219820Sjeff file, linenum); 243219820Sjeff auth_debug_add("%.100s, line %lu: missing " 244219820Sjeff "end quote", file, linenum); 245219820Sjeff xfree(patterns); 246219820Sjeff goto bad_option; 247219820Sjeff } 248219820Sjeff patterns[i] = 0; 249219820Sjeff opts++; 250219820Sjeff p = patterns; 251219820Sjeff host = hpdelim(&p); 252219820Sjeff if (host == NULL || strlen(host) >= NI_MAXHOST) { 253219820Sjeff debug("%.100s, line %lu: Bad permitopen " 254219820Sjeff "specification <%.100s>", file, linenum, 255219820Sjeff patterns); 256219820Sjeff auth_debug_add("%.100s, line %lu: " 257219820Sjeff "Bad permitopen specification", file, 258219820Sjeff linenum); 259219820Sjeff xfree(patterns); 260219820Sjeff goto bad_option; 261219820Sjeff } 262219820Sjeff host = cleanhostname(host); 263219820Sjeff if (p == NULL || (port = a2port(p)) == 0) { 264219820Sjeff debug("%.100s, line %lu: Bad permitopen port " 265219820Sjeff "<%.100s>", file, linenum, p ? p : ""); 266219820Sjeff auth_debug_add("%.100s, line %lu: " 267219820Sjeff "Bad permitopen port", file, linenum); 268219820Sjeff xfree(patterns); 269219820Sjeff goto bad_option; 270219820Sjeff } 271219820Sjeff if (options.allow_tcp_forwarding) 272219820Sjeff channel_add_permitted_opens(host, port); 273219820Sjeff xfree(patterns); 274219820Sjeff goto next_option; 275219820Sjeff } 276219820Sjeff cp = "tunnel=\""; 277219820Sjeff if (strncasecmp(opts, cp, strlen(cp)) == 0) { 278219820Sjeff char *tun = NULL; 279219820Sjeff opts += strlen(cp); 280219820Sjeff tun = xmalloc(strlen(opts) + 1); 281219820Sjeff i = 0; 282219820Sjeff while (*opts) { 283219820Sjeff if (*opts == '"') 284219820Sjeff break; 285219820Sjeff tun[i++] = *opts++; 286219820Sjeff } 287219820Sjeff if (!*opts) { 288219820Sjeff debug("%.100s, line %lu: missing end quote", 289219820Sjeff file, linenum); 290219820Sjeff auth_debug_add("%.100s, line %lu: missing end quote", 291219820Sjeff file, linenum); 292219820Sjeff xfree(tun); 293219820Sjeff forced_tun_device = -1; 294219820Sjeff goto bad_option; 295219820Sjeff } 296219820Sjeff tun[i] = 0; 297219820Sjeff forced_tun_device = a2tun(tun, NULL); 298219820Sjeff xfree(tun); 299219820Sjeff if (forced_tun_device == SSH_TUNID_ERR) { 300219820Sjeff debug("%.100s, line %lu: invalid tun device", 301219820Sjeff file, linenum); 302219820Sjeff auth_debug_add("%.100s, line %lu: invalid tun device", 303219820Sjeff file, linenum); 304219820Sjeff forced_tun_device = -1; 305219820Sjeff goto bad_option; 306219820Sjeff } 307219820Sjeff auth_debug_add("Forced tun device: %d", forced_tun_device); 308219820Sjeff opts++; 309219820Sjeff goto next_option; 310219820Sjeff } 311219820Sjeffnext_option: 312219820Sjeff /* 313219820Sjeff * Skip the comma, and move to the next option 314219820Sjeff * (or break out if there are no more). 315219820Sjeff */ 316219820Sjeff if (!*opts) 317219820Sjeff fatal("Bugs in auth-options.c option processing."); 318219820Sjeff if (*opts == ' ' || *opts == '\t') 319219820Sjeff break; /* End of options. */ 320219820Sjeff if (*opts != ',') 321219820Sjeff goto bad_option; 322219820Sjeff opts++; 323219820Sjeff /* Process the next option. */ 324219820Sjeff } 325219820Sjeff 326219820Sjeff if (!use_privsep) 327219820Sjeff auth_debug_send(); 328219820Sjeff 329219820Sjeff /* grant access */ 330219820Sjeff return 1; 331219820Sjeff 332219820Sjeffbad_option: 333219820Sjeff logit("Bad options in %.100s file, line %lu: %.50s", 334219820Sjeff file, linenum, opts); 335219820Sjeff auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 336219820Sjeff file, linenum, opts); 337219820Sjeff 338219820Sjeff if (!use_privsep) 339219820Sjeff auth_debug_send(); 340219820Sjeff 341219820Sjeff /* deny access */ 342219820Sjeff return 0; 343219820Sjeff} 344219820Sjeff