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