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