1 /* $OpenBSD: auth-options.c,v 1.43 2008/06/10 23:06:19 djm Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * As far as I am concerned, the code I have written for this software 7 * can be used freely for any purpose. Any derived versions of this 8 * software must be clearly marked as such, and if the derived work is 9 * incompatible with the protocol description in the RFC file, it must be 10 * called by a name other than "ssh" or "Secure Shell". 11 */ 12 13 #include "includes.h" 14 15 #include <sys/types.h> 16 17 #include <netdb.h> 18 #include <pwd.h> 19 #include <string.h> 20 #include <stdio.h> 21 #include <stdarg.h> 22 23 #include "openbsd-compat/sys-queue.h" 24 #include "xmalloc.h" 25 #include "match.h" 26 #include "log.h" 27 #include "canohost.h" 28 #include "buffer.h" 29 #include "channels.h" 30 #include "auth-options.h" 31 #include "servconf.h" 32 #include "misc.h" 33 #include "key.h" 34 #include "hostfile.h" 35 #include "auth.h" 36 #ifdef GSSAPI 37 #include "ssh-gss.h" 38 #endif 39 #include "monitor_wrap.h" 40 41 /* Flags set authorized_keys flags */ 42 int no_port_forwarding_flag = 0; 43 int no_agent_forwarding_flag = 0; 44 int no_x11_forwarding_flag = 0; 45 int no_pty_flag = 0; 46 int no_user_rc = 0; 47 48 /* "command=" option. */ 49 char *forced_command = NULL; 50 51 /* "environment=" options. */ 52 struct envstring *custom_environment = NULL; 53 54 /* "tunnel=" option. */ 55 int forced_tun_device = -1; 56 57 extern ServerOptions options; 58 59 void 60 auth_clear_options(void) 61 { 62 no_agent_forwarding_flag = 0; 63 no_port_forwarding_flag = 0; 64 no_pty_flag = 0; 65 no_x11_forwarding_flag = 0; 66 no_user_rc = 0; 67 while (custom_environment) { 68 struct envstring *ce = custom_environment; 69 custom_environment = ce->next; 70 xfree(ce->s); 71 xfree(ce); 72 } 73 if (forced_command) { 74 xfree(forced_command); 75 forced_command = NULL; 76 } 77 forced_tun_device = -1; 78 channel_clear_permitted_opens(); 79 auth_debug_reset(); 80 } 81 82 /* 83 * return 1 if access is granted, 0 if not. 84 * side effect: sets key option flags 85 */ 86 int 87 auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) 88 { 89 const char *cp; 90 int i; 91 92 /* reset options */ 93 auth_clear_options(); 94 95 if (!opts) 96 return 1; 97 98 while (*opts && *opts != ' ' && *opts != '\t') { 99 cp = "no-port-forwarding"; 100 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 101 auth_debug_add("Port forwarding disabled."); 102 no_port_forwarding_flag = 1; 103 opts += strlen(cp); 104 goto next_option; 105 } 106 cp = "no-agent-forwarding"; 107 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 108 auth_debug_add("Agent forwarding disabled."); 109 no_agent_forwarding_flag = 1; 110 opts += strlen(cp); 111 goto next_option; 112 } 113 cp = "no-X11-forwarding"; 114 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 115 auth_debug_add("X11 forwarding disabled."); 116 no_x11_forwarding_flag = 1; 117 opts += strlen(cp); 118 goto next_option; 119 } 120 cp = "no-pty"; 121 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 122 auth_debug_add("Pty allocation disabled."); 123 no_pty_flag = 1; 124 opts += strlen(cp); 125 goto next_option; 126 } 127 cp = "no-user-rc"; 128 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 129 auth_debug_add("User rc file execution disabled."); 130 no_user_rc = 1; 131 opts += strlen(cp); 132 goto next_option; 133 } 134 cp = "command=\""; 135 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 136 opts += strlen(cp); 137 forced_command = xmalloc(strlen(opts) + 1); 138 i = 0; 139 while (*opts) { 140 if (*opts == '"') 141 break; 142 if (*opts == '\\' && opts[1] == '"') { 143 opts += 2; 144 forced_command[i++] = '"'; 145 continue; 146 } 147 forced_command[i++] = *opts++; 148 } 149 if (!*opts) { 150 debug("%.100s, line %lu: missing end quote", 151 file, linenum); 152 auth_debug_add("%.100s, line %lu: missing end quote", 153 file, linenum); 154 xfree(forced_command); 155 forced_command = NULL; 156 goto bad_option; 157 } 158 forced_command[i] = '\0'; 159 auth_debug_add("Forced command: %.900s", forced_command); 160 opts++; 161 goto next_option; 162 } 163 cp = "environment=\""; 164 if (options.permit_user_env && 165 strncasecmp(opts, cp, strlen(cp)) == 0) { 166 char *s; 167 struct envstring *new_envstring; 168 169 opts += strlen(cp); 170 s = xmalloc(strlen(opts) + 1); 171 i = 0; 172 while (*opts) { 173 if (*opts == '"') 174 break; 175 if (*opts == '\\' && opts[1] == '"') { 176 opts += 2; 177 s[i++] = '"'; 178 continue; 179 } 180 s[i++] = *opts++; 181 } 182 if (!*opts) { 183 debug("%.100s, line %lu: missing end quote", 184 file, linenum); 185 auth_debug_add("%.100s, line %lu: missing end quote", 186 file, linenum); 187 xfree(s); 188 goto bad_option; 189 } 190 s[i] = '\0'; 191 auth_debug_add("Adding to environment: %.900s", s); 192 debug("Adding to environment: %.900s", s); 193 opts++; 194 new_envstring = xmalloc(sizeof(struct envstring)); 195 new_envstring->s = s; 196 new_envstring->next = custom_environment; 197 custom_environment = new_envstring; 198 goto next_option; 199 } 200 cp = "from=\""; 201 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 202 const char *remote_ip = get_remote_ipaddr(); 203 const char *remote_host = get_canonical_hostname( 204 options.use_dns); 205 char *patterns = xmalloc(strlen(opts) + 1); 206 207 opts += strlen(cp); 208 i = 0; 209 while (*opts) { 210 if (*opts == '"') 211 break; 212 if (*opts == '\\' && opts[1] == '"') { 213 opts += 2; 214 patterns[i++] = '"'; 215 continue; 216 } 217 patterns[i++] = *opts++; 218 } 219 if (!*opts) { 220 debug("%.100s, line %lu: missing end quote", 221 file, linenum); 222 auth_debug_add("%.100s, line %lu: missing end quote", 223 file, linenum); 224 xfree(patterns); 225 goto bad_option; 226 } 227 patterns[i] = '\0'; 228 opts++; 229 switch (match_host_and_ip(remote_host, remote_ip, 230 patterns)) { 231 case 1: 232 xfree(patterns); 233 /* Host name matches. */ 234 goto next_option; 235 case -1: 236 debug("%.100s, line %lu: invalid criteria", 237 file, linenum); 238 auth_debug_add("%.100s, line %lu: " 239 "invalid criteria", file, linenum); 240 /* FALLTHROUGH */ 241 case 0: 242 xfree(patterns); 243 logit("Authentication tried for %.100s with " 244 "correct key but not from a permitted " 245 "host (host=%.200s, ip=%.200s).", 246 pw->pw_name, remote_host, remote_ip); 247 auth_debug_add("Your host '%.200s' is not " 248 "permitted to use this key for login.", 249 remote_host); 250 break; 251 } 252 /* deny access */ 253 return 0; 254 } 255 cp = "permitopen=\""; 256 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 257 char *host, *p; 258 u_short port; 259 char *patterns = xmalloc(strlen(opts) + 1); 260 261 opts += strlen(cp); 262 i = 0; 263 while (*opts) { 264 if (*opts == '"') 265 break; 266 if (*opts == '\\' && opts[1] == '"') { 267 opts += 2; 268 patterns[i++] = '"'; 269 continue; 270 } 271 patterns[i++] = *opts++; 272 } 273 if (!*opts) { 274 debug("%.100s, line %lu: missing end quote", 275 file, linenum); 276 auth_debug_add("%.100s, line %lu: missing " 277 "end quote", file, linenum); 278 xfree(patterns); 279 goto bad_option; 280 } 281 patterns[i] = '\0'; 282 opts++; 283 p = patterns; 284 host = hpdelim(&p); 285 if (host == NULL || strlen(host) >= NI_MAXHOST) { 286 debug("%.100s, line %lu: Bad permitopen " 287 "specification <%.100s>", file, linenum, 288 patterns); 289 auth_debug_add("%.100s, line %lu: " 290 "Bad permitopen specification", file, 291 linenum); 292 xfree(patterns); 293 goto bad_option; 294 } 295 host = cleanhostname(host); 296 if (p == NULL || (port = a2port(p)) == 0) { 297 debug("%.100s, line %lu: Bad permitopen port " 298 "<%.100s>", file, linenum, p ? p : ""); 299 auth_debug_add("%.100s, line %lu: " 300 "Bad permitopen port", file, linenum); 301 xfree(patterns); 302 goto bad_option; 303 } 304 if (options.allow_tcp_forwarding) 305 channel_add_permitted_opens(host, port); 306 xfree(patterns); 307 goto next_option; 308 } 309 cp = "tunnel=\""; 310 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 311 char *tun = NULL; 312 opts += strlen(cp); 313 tun = xmalloc(strlen(opts) + 1); 314 i = 0; 315 while (*opts) { 316 if (*opts == '"') 317 break; 318 tun[i++] = *opts++; 319 } 320 if (!*opts) { 321 debug("%.100s, line %lu: missing end quote", 322 file, linenum); 323 auth_debug_add("%.100s, line %lu: missing end quote", 324 file, linenum); 325 xfree(tun); 326 forced_tun_device = -1; 327 goto bad_option; 328 } 329 tun[i] = '\0'; 330 forced_tun_device = a2tun(tun, NULL); 331 xfree(tun); 332 if (forced_tun_device == SSH_TUNID_ERR) { 333 debug("%.100s, line %lu: invalid tun device", 334 file, linenum); 335 auth_debug_add("%.100s, line %lu: invalid tun device", 336 file, linenum); 337 forced_tun_device = -1; 338 goto bad_option; 339 } 340 auth_debug_add("Forced tun device: %d", forced_tun_device); 341 opts++; 342 goto next_option; 343 } 344 next_option: 345 /* 346 * Skip the comma, and move to the next option 347 * (or break out if there are no more). 348 */ 349 if (!*opts) 350 fatal("Bugs in auth-options.c option processing."); 351 if (*opts == ' ' || *opts == '\t') 352 break; /* End of options. */ 353 if (*opts != ',') 354 goto bad_option; 355 opts++; 356 /* Process the next option. */ 357 } 358 359 if (!use_privsep) 360 auth_debug_send(); 361 362 /* grant access */ 363 return 1; 364 365 bad_option: 366 logit("Bad options in %.100s file, line %lu: %.50s", 367 file, linenum, opts); 368 auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 369 file, linenum, opts); 370 371 if (!use_privsep) 372 auth_debug_send(); 373 374 /* deny access */ 375 return 0; 376 } 377