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.28 2003/06/02 09:17:34 markus 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[256], sport[6]; 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 end quote", 240 file, linenum); 241 xfree(patterns); 242 goto bad_option; 243 } 244 patterns[i] = 0; 245 opts++; 246 if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 && 247 sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) { 248 debug("%.100s, line %lu: Bad permitopen specification " 249 "<%.100s>", file, linenum, patterns); 250 auth_debug_add("%.100s, line %lu: " 251 "Bad permitopen specification", file, linenum); 252 xfree(patterns); 253 goto bad_option; 254 } 255 if ((port = a2port(sport)) == 0) { 256 debug("%.100s, line %lu: Bad permitopen port <%.100s>", 257 file, linenum, sport); 258 auth_debug_add("%.100s, line %lu: " 259 "Bad permitopen port", file, linenum); 260 xfree(patterns); 261 goto bad_option; 262 } 263 if (options.allow_tcp_forwarding) 264 channel_add_permitted_opens(host, port); 265 xfree(patterns); 266 goto next_option; 267 } 268 next_option: 269 /* 270 * Skip the comma, and move to the next option 271 * (or break out if there are no more). 272 */ 273 if (!*opts) 274 fatal("Bugs in auth-options.c option processing."); 275 if (*opts == ' ' || *opts == '\t') 276 break; /* End of options. */ 277 if (*opts != ',') 278 goto bad_option; 279 opts++; 280 /* Process the next option. */ 281 } 282 283 if (!use_privsep) 284 auth_debug_send(); 285 286 /* grant access */ 287 return 1; 288 289 bad_option: 290 logit("Bad options in %.100s file, line %lu: %.50s", 291 file, linenum, opts); 292 auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 293 file, linenum, opts); 294 295 if (!use_privsep) 296 auth_debug_send(); 297 298 /* deny access */ 299 return 0; 300 } 301