Annotation of src/crypto/external/bsd/openssh/dist/auth-options.c, Revision 1.4.2.2
1.4.2.1 yamt 1: /* $NetBSD$ */
1.4.2.2 ! yamt 2: /* $OpenBSD: auth-options.c,v 1.59.2.1 2013/11/08 01:33:56 djm Exp $ */
1.1 christos 3: /*
4: * Author: Tatu Ylonen <ylo@cs.hut.fi>
5: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6: * All rights reserved
7: * As far as I am concerned, the code I have written for this software
8: * can be used freely for any purpose. Any derived versions of this
9: * software must be clearly marked as such, and if the derived work is
10: * incompatible with the protocol description in the RFC file, it must be
11: * called by a name other than "ssh" or "Secure Shell".
12: */
13:
1.2 christos 14: #include "includes.h"
1.4.2.2 ! yamt 15: __RCSID("$NetBSD: auth-options.c,v 1.4.2.1 2012/05/23 10:07:04 yamt Exp $");
1.1 christos 16: #include <sys/types.h>
17: #include <sys/queue.h>
18:
19: #include <netdb.h>
20: #include <pwd.h>
21: #include <string.h>
22: #include <stdio.h>
23: #include <stdarg.h>
1.2 christos 24: #include <time.h>
1.1 christos 25:
26: #include "xmalloc.h"
27: #include "match.h"
28: #include "log.h"
29: #include "canohost.h"
30: #include "buffer.h"
31: #include "channels.h"
32: #include "servconf.h"
33: #include "misc.h"
34: #include "key.h"
1.3 adam 35: #include "auth-options.h"
1.1 christos 36: #include "hostfile.h"
37: #include "auth.h"
38: #ifdef GSSAPI
39: #include "ssh-gss.h"
40: #endif
41: #include "monitor_wrap.h"
42:
43: /* Flags set authorized_keys flags */
44: int no_port_forwarding_flag = 0;
45: int no_agent_forwarding_flag = 0;
46: int no_x11_forwarding_flag = 0;
47: int no_pty_flag = 0;
48: int no_user_rc = 0;
1.3 adam 49: int key_is_cert_authority = 0;
1.1 christos 50:
51: /* "command=" option. */
52: char *forced_command = NULL;
53:
54: /* "environment=" options. */
55: struct envstring *custom_environment = NULL;
56:
57: /* "tunnel=" option. */
58: int forced_tun_device = -1;
59:
1.3 adam 60: /* "principals=" option. */
61: char *authorized_principals = NULL;
62:
1.1 christos 63: extern ServerOptions options;
64:
65: void
66: auth_clear_options(void)
67: {
68: no_agent_forwarding_flag = 0;
69: no_port_forwarding_flag = 0;
70: no_pty_flag = 0;
71: no_x11_forwarding_flag = 0;
72: no_user_rc = 0;
1.3 adam 73: key_is_cert_authority = 0;
1.1 christos 74: while (custom_environment) {
75: struct envstring *ce = custom_environment;
76: custom_environment = ce->next;
1.4.2.2 ! yamt 77: free(ce->s);
! 78: free(ce);
1.1 christos 79: }
80: if (forced_command) {
1.4.2.2 ! yamt 81: free(forced_command);
1.1 christos 82: forced_command = NULL;
83: }
1.3 adam 84: if (authorized_principals) {
1.4.2.2 ! yamt 85: free(authorized_principals);
1.3 adam 86: authorized_principals = NULL;
87: }
1.1 christos 88: forced_tun_device = -1;
89: channel_clear_permitted_opens();
90: }
91:
92: /*
93: * return 1 if access is granted, 0 if not.
94: * side effect: sets key option flags
95: */
96: int
1.4 christos 97: auth_parse_options(struct passwd *pw, const char *opts, const char *file,
98: u_long linenum)
1.1 christos 99: {
100: const char *cp;
101: int i;
102:
103: /* reset options */
104: auth_clear_options();
105:
106: if (!opts)
107: return 1;
108:
109: while (*opts && *opts != ' ' && *opts != '\t') {
1.3 adam 110: cp = "cert-authority";
111: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
112: key_is_cert_authority = 1;
113: opts += strlen(cp);
114: goto next_option;
115: }
1.1 christos 116: cp = "no-port-forwarding";
117: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
118: auth_debug_add("Port forwarding disabled.");
119: no_port_forwarding_flag = 1;
120: opts += strlen(cp);
121: goto next_option;
122: }
123: cp = "no-agent-forwarding";
124: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
125: auth_debug_add("Agent forwarding disabled.");
126: no_agent_forwarding_flag = 1;
127: opts += strlen(cp);
128: goto next_option;
129: }
130: cp = "no-X11-forwarding";
131: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
132: auth_debug_add("X11 forwarding disabled.");
133: no_x11_forwarding_flag = 1;
134: opts += strlen(cp);
135: goto next_option;
136: }
137: cp = "no-pty";
138: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
139: auth_debug_add("Pty allocation disabled.");
140: no_pty_flag = 1;
141: opts += strlen(cp);
142: goto next_option;
143: }
144: cp = "no-user-rc";
145: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
146: auth_debug_add("User rc file execution disabled.");
147: no_user_rc = 1;
148: opts += strlen(cp);
149: goto next_option;
150: }
151: cp = "command=\"";
152: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
153: opts += strlen(cp);
1.3 adam 154: if (forced_command != NULL)
1.4.2.2 ! yamt 155: free(forced_command);
1.1 christos 156: forced_command = xmalloc(strlen(opts) + 1);
157: i = 0;
158: while (*opts) {
159: if (*opts == '"')
160: break;
161: if (*opts == '\\' && opts[1] == '"') {
162: opts += 2;
163: forced_command[i++] = '"';
164: continue;
165: }
166: forced_command[i++] = *opts++;
167: }
168: if (!*opts) {
169: debug("%.100s, line %lu: missing end quote",
170: file, linenum);
171: auth_debug_add("%.100s, line %lu: missing end quote",
172: file, linenum);
1.4.2.2 ! yamt 173: free(forced_command);
1.1 christos 174: forced_command = NULL;
175: goto bad_option;
176: }
177: forced_command[i] = '\0';
1.4 christos 178: auth_debug_add("Forced command.");
1.1 christos 179: opts++;
180: goto next_option;
181: }
1.3 adam 182: cp = "principals=\"";
183: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
184: opts += strlen(cp);
185: if (authorized_principals != NULL)
1.4.2.2 ! yamt 186: free(authorized_principals);
1.3 adam 187: authorized_principals = xmalloc(strlen(opts) + 1);
188: i = 0;
189: while (*opts) {
190: if (*opts == '"')
191: break;
192: if (*opts == '\\' && opts[1] == '"') {
193: opts += 2;
194: authorized_principals[i++] = '"';
195: continue;
196: }
197: authorized_principals[i++] = *opts++;
198: }
199: if (!*opts) {
200: debug("%.100s, line %lu: missing end quote",
201: file, linenum);
202: auth_debug_add("%.100s, line %lu: missing end quote",
203: file, linenum);
1.4.2.2 ! yamt 204: free(authorized_principals);
1.3 adam 205: authorized_principals = NULL;
206: goto bad_option;
207: }
208: authorized_principals[i] = '\0';
209: auth_debug_add("principals: %.900s",
210: authorized_principals);
211: opts++;
212: goto next_option;
213: }
1.1 christos 214: cp = "environment=\"";
215: if (options.permit_user_env &&
216: strncasecmp(opts, cp, strlen(cp)) == 0) {
217: char *s;
218: struct envstring *new_envstring;
219:
220: opts += strlen(cp);
221: s = xmalloc(strlen(opts) + 1);
222: i = 0;
223: while (*opts) {
224: if (*opts == '"')
225: break;
226: if (*opts == '\\' && opts[1] == '"') {
227: opts += 2;
228: s[i++] = '"';
229: continue;
230: }
231: s[i++] = *opts++;
232: }
233: if (!*opts) {
234: debug("%.100s, line %lu: missing end quote",
235: file, linenum);
236: auth_debug_add("%.100s, line %lu: missing end quote",
237: file, linenum);
1.4.2.2 ! yamt 238: free(s);
1.1 christos 239: goto bad_option;
240: }
241: s[i] = '\0';
242: auth_debug_add("Adding to environment: %.900s", s);
243: debug("Adding to environment: %.900s", s);
244: opts++;
1.4.2.2 ! yamt 245: new_envstring = xcalloc(1, sizeof(struct envstring));
1.1 christos 246: new_envstring->s = s;
247: new_envstring->next = custom_environment;
248: custom_environment = new_envstring;
249: goto next_option;
250: }
251: cp = "from=\"";
252: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
253: const char *remote_ip = get_remote_ipaddr();
254: const char *remote_host = get_canonical_hostname(
255: options.use_dns);
256: char *patterns = xmalloc(strlen(opts) + 1);
257:
258: opts += strlen(cp);
259: i = 0;
260: while (*opts) {
261: if (*opts == '"')
262: break;
263: if (*opts == '\\' && opts[1] == '"') {
264: opts += 2;
265: patterns[i++] = '"';
266: continue;
267: }
268: patterns[i++] = *opts++;
269: }
270: if (!*opts) {
271: debug("%.100s, line %lu: missing end quote",
272: file, linenum);
273: auth_debug_add("%.100s, line %lu: missing end quote",
274: file, linenum);
1.4.2.2 ! yamt 275: free(patterns);
1.1 christos 276: goto bad_option;
277: }
278: patterns[i] = '\0';
279: opts++;
280: switch (match_host_and_ip(remote_host, remote_ip,
281: patterns)) {
282: case 1:
1.4.2.2 ! yamt 283: free(patterns);
1.1 christos 284: /* Host name matches. */
285: goto next_option;
286: case -1:
287: debug("%.100s, line %lu: invalid criteria",
288: file, linenum);
289: auth_debug_add("%.100s, line %lu: "
290: "invalid criteria", file, linenum);
291: /* FALLTHROUGH */
292: case 0:
1.4.2.2 ! yamt 293: free(patterns);
1.1 christos 294: logit("Authentication tried for %.100s with "
295: "correct key but not from a permitted "
296: "host (host=%.200s, ip=%.200s).",
297: pw->pw_name, remote_host, remote_ip);
298: auth_debug_add("Your host '%.200s' is not "
299: "permitted to use this key for login.",
300: remote_host);
301: break;
302: }
303: /* deny access */
304: return 0;
305: }
306: cp = "permitopen=\"";
307: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
308: char *host, *p;
309: int port;
310: char *patterns = xmalloc(strlen(opts) + 1);
311:
312: opts += strlen(cp);
313: i = 0;
314: while (*opts) {
315: if (*opts == '"')
316: break;
317: if (*opts == '\\' && opts[1] == '"') {
318: opts += 2;
319: patterns[i++] = '"';
320: continue;
321: }
322: patterns[i++] = *opts++;
323: }
324: if (!*opts) {
325: debug("%.100s, line %lu: missing end quote",
326: file, linenum);
327: auth_debug_add("%.100s, line %lu: missing "
328: "end quote", file, linenum);
1.4.2.2 ! yamt 329: free(patterns);
1.1 christos 330: goto bad_option;
331: }
332: patterns[i] = '\0';
333: opts++;
334: p = patterns;
335: host = hpdelim(&p);
336: if (host == NULL || strlen(host) >= NI_MAXHOST) {
337: debug("%.100s, line %lu: Bad permitopen "
338: "specification <%.100s>", file, linenum,
339: patterns);
340: auth_debug_add("%.100s, line %lu: "
341: "Bad permitopen specification", file,
342: linenum);
1.4.2.2 ! yamt 343: free(patterns);
1.1 christos 344: goto bad_option;
345: }
346: host = cleanhostname(host);
1.4.2.1 yamt 347: if (p == NULL || (port = permitopen_port(p)) < 0) {
1.1 christos 348: debug("%.100s, line %lu: Bad permitopen port "
349: "<%.100s>", file, linenum, p ? p : "");
350: auth_debug_add("%.100s, line %lu: "
351: "Bad permitopen port", file, linenum);
1.4.2.2 ! yamt 352: free(patterns);
1.1 christos 353: goto bad_option;
354: }
1.4.2.2 ! yamt 355: if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)
1.1 christos 356: channel_add_permitted_opens(host, port);
1.4.2.2 ! yamt 357: free(patterns);
1.1 christos 358: goto next_option;
359: }
360: cp = "tunnel=\"";
361: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
362: char *tun = NULL;
363: opts += strlen(cp);
364: tun = xmalloc(strlen(opts) + 1);
365: i = 0;
366: while (*opts) {
367: if (*opts == '"')
368: break;
369: tun[i++] = *opts++;
370: }
371: if (!*opts) {
372: debug("%.100s, line %lu: missing end quote",
373: file, linenum);
374: auth_debug_add("%.100s, line %lu: missing end quote",
375: file, linenum);
1.4.2.2 ! yamt 376: free(tun);
1.1 christos 377: forced_tun_device = -1;
378: goto bad_option;
379: }
380: tun[i] = '\0';
381: forced_tun_device = a2tun(tun, NULL);
1.4.2.2 ! yamt 382: free(tun);
1.1 christos 383: if (forced_tun_device == SSH_TUNID_ERR) {
384: debug("%.100s, line %lu: invalid tun device",
385: file, linenum);
386: auth_debug_add("%.100s, line %lu: invalid tun device",
387: file, linenum);
388: forced_tun_device = -1;
389: goto bad_option;
390: }
391: auth_debug_add("Forced tun device: %d", forced_tun_device);
392: opts++;
393: goto next_option;
394: }
395: next_option:
396: /*
397: * Skip the comma, and move to the next option
398: * (or break out if there are no more).
399: */
400: if (!*opts)
401: fatal("Bugs in auth-options.c option processing.");
402: if (*opts == ' ' || *opts == '\t')
403: break; /* End of options. */
404: if (*opts != ',')
405: goto bad_option;
406: opts++;
407: /* Process the next option. */
408: }
409:
410: /* grant access */
411: return 1;
412:
413: bad_option:
414: logit("Bad options in %.100s file, line %lu: %.50s",
415: file, linenum, opts);
416: auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
417: file, linenum, opts);
418:
1.3 adam 419: /* deny access */
420: return 0;
421: }
422:
423: #define OPTIONS_CRITICAL 1
424: #define OPTIONS_EXTENSIONS 2
425: static int
426: parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
427: u_int which, int crit,
428: int *cert_no_port_forwarding_flag,
429: int *cert_no_agent_forwarding_flag,
430: int *cert_no_x11_forwarding_flag,
431: int *cert_no_pty_flag,
432: int *cert_no_user_rc,
433: char **cert_forced_command,
434: int *cert_source_address_done)
435: {
436: char *command, *allowed;
437: const char *remote_ip;
1.4.2.2 ! yamt 438: char *name = NULL;
! 439: u_char *data_blob = NULL;
1.3 adam 440: u_int nlen, dlen, clen;
441: Buffer c, data;
442: int ret = -1, found;
443:
444: buffer_init(&data);
445:
446: /* Make copy to avoid altering original */
447: buffer_init(&c);
448: buffer_append(&c, optblob, optblob_len);
449:
450: while (buffer_len(&c) > 0) {
1.4 christos 451: if ((name = buffer_get_cstring_ret(&c, &nlen)) == NULL ||
1.3 adam 452: (data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) {
453: error("Certificate options corrupt");
454: goto out;
455: }
456: buffer_append(&data, data_blob, dlen);
457: debug3("found certificate option \"%.100s\" len %u",
458: name, dlen);
459: found = 0;
460: if ((which & OPTIONS_EXTENSIONS) != 0) {
461: if (strcmp(name, "permit-X11-forwarding") == 0) {
462: *cert_no_x11_forwarding_flag = 0;
463: found = 1;
464: } else if (strcmp(name,
465: "permit-agent-forwarding") == 0) {
466: *cert_no_agent_forwarding_flag = 0;
467: found = 1;
468: } else if (strcmp(name,
469: "permit-port-forwarding") == 0) {
470: *cert_no_port_forwarding_flag = 0;
471: found = 1;
472: } else if (strcmp(name, "permit-pty") == 0) {
473: *cert_no_pty_flag = 0;
474: found = 1;
475: } else if (strcmp(name, "permit-user-rc") == 0) {
476: *cert_no_user_rc = 0;
477: found = 1;
478: }
479: }
480: if (!found && (which & OPTIONS_CRITICAL) != 0) {
481: if (strcmp(name, "force-command") == 0) {
1.4 christos 482: if ((command = buffer_get_cstring_ret(&data,
1.3 adam 483: &clen)) == NULL) {
484: error("Certificate constraint \"%s\" "
485: "corrupt", name);
486: goto out;
487: }
488: if (*cert_forced_command != NULL) {
489: error("Certificate has multiple "
490: "force-command options");
1.4.2.2 ! yamt 491: free(command);
1.3 adam 492: goto out;
493: }
494: *cert_forced_command = command;
495: found = 1;
496: }
497: if (strcmp(name, "source-address") == 0) {
1.4 christos 498: if ((allowed = buffer_get_cstring_ret(&data,
1.3 adam 499: &clen)) == NULL) {
500: error("Certificate constraint "
501: "\"%s\" corrupt", name);
502: goto out;
503: }
504: if ((*cert_source_address_done)++) {
505: error("Certificate has multiple "
506: "source-address options");
1.4.2.2 ! yamt 507: free(allowed);
1.3 adam 508: goto out;
509: }
510: remote_ip = get_remote_ipaddr();
511: switch (addr_match_cidr_list(remote_ip,
512: allowed)) {
513: case 1:
514: /* accepted */
1.4.2.2 ! yamt 515: free(allowed);
1.3 adam 516: break;
517: case 0:
518: /* no match */
519: logit("Authentication tried for %.100s "
520: "with valid certificate but not "
521: "from a permitted host "
522: "(ip=%.200s).", pw->pw_name,
523: remote_ip);
524: auth_debug_add("Your address '%.200s' "
525: "is not permitted to use this "
526: "certificate for login.",
527: remote_ip);
1.4.2.2 ! yamt 528: free(allowed);
1.3 adam 529: goto out;
530: case -1:
531: error("Certificate source-address "
532: "contents invalid");
1.4.2.2 ! yamt 533: free(allowed);
1.3 adam 534: goto out;
535: }
536: found = 1;
537: }
538: }
539:
540: if (!found) {
541: if (crit) {
542: error("Certificate critical option \"%s\" "
543: "is not supported", name);
544: goto out;
545: } else {
546: logit("Certificate extension \"%s\" "
547: "is not supported", name);
548: }
549: } else if (buffer_len(&data) != 0) {
550: error("Certificate option \"%s\" corrupt "
551: "(extra data)", name);
552: goto out;
553: }
554: buffer_clear(&data);
1.4.2.2 ! yamt 555: free(name);
! 556: free(data_blob);
! 557: name = NULL;
! 558: data_blob = NULL;
1.3 adam 559: }
560: /* successfully parsed all options */
561: ret = 0;
562:
563: out:
564: if (ret != 0 &&
565: cert_forced_command != NULL &&
566: *cert_forced_command != NULL) {
1.4.2.2 ! yamt 567: free(*cert_forced_command);
1.3 adam 568: *cert_forced_command = NULL;
569: }
570: if (name != NULL)
1.4.2.2 ! yamt 571: free(name);
1.3 adam 572: if (data_blob != NULL)
1.4.2.2 ! yamt 573: free(data_blob);
1.3 adam 574: buffer_free(&data);
575: buffer_free(&c);
576: return ret;
577: }
578:
579: /*
580: * Set options from critical certificate options. These supersede user key
581: * options so this must be called after auth_parse_options().
582: */
583: int
584: auth_cert_options(Key *k, struct passwd *pw)
585: {
586: int cert_no_port_forwarding_flag = 1;
587: int cert_no_agent_forwarding_flag = 1;
588: int cert_no_x11_forwarding_flag = 1;
589: int cert_no_pty_flag = 1;
590: int cert_no_user_rc = 1;
591: char *cert_forced_command = NULL;
592: int cert_source_address_done = 0;
593:
594: if (key_cert_is_legacy(k)) {
595: /* All options are in the one field for v00 certs */
596: if (parse_option_list(buffer_ptr(&k->cert->critical),
597: buffer_len(&k->cert->critical), pw,
598: OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1,
599: &cert_no_port_forwarding_flag,
600: &cert_no_agent_forwarding_flag,
601: &cert_no_x11_forwarding_flag,
602: &cert_no_pty_flag,
603: &cert_no_user_rc,
604: &cert_forced_command,
605: &cert_source_address_done) == -1)
606: return -1;
607: } else {
608: /* Separate options and extensions for v01 certs */
609: if (parse_option_list(buffer_ptr(&k->cert->critical),
610: buffer_len(&k->cert->critical), pw,
611: OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
612: &cert_forced_command,
613: &cert_source_address_done) == -1)
614: return -1;
615: if (parse_option_list(buffer_ptr(&k->cert->extensions),
616: buffer_len(&k->cert->extensions), pw,
617: OPTIONS_EXTENSIONS, 1,
618: &cert_no_port_forwarding_flag,
619: &cert_no_agent_forwarding_flag,
620: &cert_no_x11_forwarding_flag,
621: &cert_no_pty_flag,
622: &cert_no_user_rc,
623: NULL, NULL) == -1)
624: return -1;
625: }
1.1 christos 626:
1.3 adam 627: no_port_forwarding_flag |= cert_no_port_forwarding_flag;
628: no_agent_forwarding_flag |= cert_no_agent_forwarding_flag;
629: no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
630: no_pty_flag |= cert_no_pty_flag;
631: no_user_rc |= cert_no_user_rc;
632: /* CA-specified forced command supersedes key option */
633: if (cert_forced_command != NULL) {
634: if (forced_command != NULL)
1.4.2.2 ! yamt 635: free(forced_command);
1.3 adam 636: forced_command = cert_forced_command;
637: }
1.1 christos 638: return 0;
639: }
1.3 adam 640:
CVSweb <webmaster@jp.NetBSD.org>