Annotation of src/usr.bin/ssh/auth-options.c, Revision 1.74
1.74 ! djm 1: /* $OpenBSD: auth-options.c,v 1.73 2017/05/31 10:54:00 markus 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:
1.65 markus 22: #include "key.h" /* XXX for typedef */
23: #include "buffer.h" /* XXX for typedef */
1.1 markus 24: #include "xmalloc.h"
25: #include "match.h"
1.65 markus 26: #include "ssherr.h"
1.11 markus 27: #include "log.h"
28: #include "canohost.h"
1.71 djm 29: #include "packet.h"
1.65 markus 30: #include "sshbuf.h"
1.64 millert 31: #include "misc.h"
1.18 markus 32: #include "channels.h"
1.12 markus 33: #include "servconf.h"
1.65 markus 34: #include "sshkey.h"
1.50 djm 35: #include "auth-options.h"
1.40 deraadt 36: #include "hostfile.h"
37: #include "auth.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.45 djm 45: int key_is_cert_authority = 0;
1.1 markus 46:
47: /* "command=" option. */
48: char *forced_command = NULL;
49:
50: /* "environment=" options. */
51: struct envstring *custom_environment = NULL;
52:
1.32 reyk 53: /* "tunnel=" option. */
54: int forced_tun_device = -1;
55:
1.51 djm 56: /* "principals=" option. */
57: char *authorized_principals = NULL;
58:
1.12 markus 59: extern ServerOptions options;
60:
1.74 ! djm 61: /* XXX refactor to be stateless */
! 62:
1.22 provos 63: void
1.5 markus 64: auth_clear_options(void)
65: {
1.74 ! djm 66: struct ssh *ssh = active_state; /* XXX */
! 67:
1.5 markus 68: no_agent_forwarding_flag = 0;
69: no_port_forwarding_flag = 0;
70: no_pty_flag = 0;
71: no_x11_forwarding_flag = 0;
1.41 djm 72: no_user_rc = 0;
1.45 djm 73: key_is_cert_authority = 0;
1.5 markus 74: while (custom_environment) {
75: struct envstring *ce = custom_environment;
76: custom_environment = ce->next;
1.58 djm 77: free(ce->s);
78: free(ce);
1.5 markus 79: }
1.70 mmcc 80: free(forced_command);
81: forced_command = NULL;
82: free(authorized_principals);
83: authorized_principals = NULL;
1.32 reyk 84: forced_tun_device = -1;
1.74 ! djm 85: channel_clear_permitted_opens(ssh);
1.5 markus 86: }
87:
1.10 markus 88: /*
1.69 djm 89: * Match flag 'opt' in *optsp, and if allow_negate is set then also match
90: * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0
91: * if negated option matches.
92: * If the option or negated option matches, then *optsp is updated to
93: * point to the first character after the option and, if 'msg' is not NULL
94: * then a message based on it added via auth_debug_add().
95: */
96: static int
97: match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
98: {
99: size_t opt_len = strlen(opt);
100: char *opts = *optsp;
101: int negate = 0;
102:
103: if (allow_negate && strncasecmp(opts, "no-", 3) == 0) {
104: opts += 3;
105: negate = 1;
106: }
107: if (strncasecmp(opts, opt, opt_len) == 0) {
108: *optsp = opts + opt_len;
109: if (msg != NULL) {
110: auth_debug_add("%s %s.", msg,
111: negate ? "disabled" : "enabled");
112: }
113: return negate ? 0 : 1;
114: }
115: return -1;
116: }
117:
118: /*
1.10 markus 119: * return 1 if access is granted, 0 if not.
120: * side effect: sets key option flags
1.74 ! djm 121: * XXX remove side effects; fill structure instead.
1.10 markus 122: */
1.1 markus 123: int
1.73 markus 124: auth_parse_options(struct passwd *pw, char *opts, const char *file,
125: u_long linenum)
1.1 markus 126: {
1.71 djm 127: struct ssh *ssh = active_state; /* XXX */
1.1 markus 128: const char *cp;
1.69 djm 129: int i, r;
1.5 markus 130:
131: /* reset options */
132: auth_clear_options();
1.13 markus 133:
134: if (!opts)
135: return 1;
1.5 markus 136:
1.12 markus 137: while (*opts && *opts != ' ' && *opts != '\t') {
1.69 djm 138: if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) {
139: key_is_cert_authority = r;
1.45 djm 140: goto next_option;
141: }
1.69 djm 142: if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) {
143: auth_debug_add("Key is restricted.");
1.1 markus 144: no_port_forwarding_flag = 1;
1.69 djm 145: no_agent_forwarding_flag = 1;
146: no_x11_forwarding_flag = 1;
147: no_pty_flag = 1;
148: no_user_rc = 1;
149: goto next_option;
150: }
151: if ((r = match_flag("port-forwarding", 1, &opts,
152: "Port forwarding")) != -1) {
153: no_port_forwarding_flag = r != 1;
1.1 markus 154: goto next_option;
155: }
1.69 djm 156: if ((r = match_flag("agent-forwarding", 1, &opts,
157: "Agent forwarding")) != -1) {
158: no_agent_forwarding_flag = r != 1;
1.1 markus 159: goto next_option;
160: }
1.69 djm 161: if ((r = match_flag("x11-forwarding", 1, &opts,
162: "X11 forwarding")) != -1) {
163: no_x11_forwarding_flag = r != 1;
1.1 markus 164: goto next_option;
165: }
1.69 djm 166: if ((r = match_flag("pty", 1, &opts,
167: "PTY allocation")) != -1) {
168: no_pty_flag = r != 1;
1.41 djm 169: goto next_option;
170: }
1.69 djm 171: if ((r = match_flag("user-rc", 1, &opts,
172: "User rc execution")) != -1) {
173: no_user_rc = r != 1;
1.1 markus 174: goto next_option;
175: }
176: cp = "command=\"";
1.12 markus 177: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
178: opts += strlen(cp);
1.70 mmcc 179: free(forced_command);
1.12 markus 180: forced_command = xmalloc(strlen(opts) + 1);
1.1 markus 181: i = 0;
1.12 markus 182: while (*opts) {
183: if (*opts == '"')
1.1 markus 184: break;
1.12 markus 185: if (*opts == '\\' && opts[1] == '"') {
186: opts += 2;
1.1 markus 187: forced_command[i++] = '"';
188: continue;
189: }
1.12 markus 190: forced_command[i++] = *opts++;
1.1 markus 191: }
1.12 markus 192: if (!*opts) {
1.1 markus 193: debug("%.100s, line %lu: missing end quote",
1.10 markus 194: file, linenum);
1.24 markus 195: auth_debug_add("%.100s, line %lu: missing end quote",
1.10 markus 196: file, linenum);
1.58 djm 197: free(forced_command);
1.14 markus 198: forced_command = NULL;
199: goto bad_option;
1.1 markus 200: }
1.38 dtucker 201: forced_command[i] = '\0';
1.54 djm 202: auth_debug_add("Forced command.");
1.51 djm 203: opts++;
204: goto next_option;
205: }
206: cp = "principals=\"";
207: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
208: opts += strlen(cp);
1.70 mmcc 209: free(authorized_principals);
1.51 djm 210: authorized_principals = xmalloc(strlen(opts) + 1);
211: i = 0;
212: while (*opts) {
213: if (*opts == '"')
214: break;
215: if (*opts == '\\' && opts[1] == '"') {
216: opts += 2;
217: authorized_principals[i++] = '"';
218: continue;
219: }
220: authorized_principals[i++] = *opts++;
221: }
222: if (!*opts) {
223: debug("%.100s, line %lu: missing end quote",
224: file, linenum);
225: auth_debug_add("%.100s, line %lu: missing end quote",
226: file, linenum);
1.58 djm 227: free(authorized_principals);
1.51 djm 228: authorized_principals = NULL;
229: goto bad_option;
230: }
231: authorized_principals[i] = '\0';
232: auth_debug_add("principals: %.900s",
233: authorized_principals);
1.12 markus 234: opts++;
1.1 markus 235: goto next_option;
236: }
237: cp = "environment=\"";
1.67 djm 238: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
1.1 markus 239: char *s;
240: struct envstring *new_envstring;
1.15 markus 241:
1.12 markus 242: opts += strlen(cp);
243: s = xmalloc(strlen(opts) + 1);
1.1 markus 244: i = 0;
1.12 markus 245: while (*opts) {
246: if (*opts == '"')
1.1 markus 247: break;
1.12 markus 248: if (*opts == '\\' && opts[1] == '"') {
249: opts += 2;
1.1 markus 250: s[i++] = '"';
251: continue;
252: }
1.12 markus 253: s[i++] = *opts++;
1.1 markus 254: }
1.12 markus 255: if (!*opts) {
1.1 markus 256: debug("%.100s, line %lu: missing end quote",
1.10 markus 257: file, linenum);
1.24 markus 258: auth_debug_add("%.100s, line %lu: missing end quote",
1.10 markus 259: file, linenum);
1.58 djm 260: free(s);
1.14 markus 261: goto bad_option;
1.1 markus 262: }
1.38 dtucker 263: s[i] = '\0';
1.12 markus 264: opts++;
1.67 djm 265: if (options.permit_user_env) {
266: auth_debug_add("Adding to environment: "
267: "%.900s", s);
268: debug("Adding to environment: %.900s", s);
269: new_envstring = xcalloc(1,
270: sizeof(*new_envstring));
271: new_envstring->s = s;
272: new_envstring->next = custom_environment;
273: custom_environment = new_envstring;
274: s = NULL;
275: }
276: free(s);
1.1 markus 277: goto next_option;
278: }
279: cp = "from=\"";
1.12 markus 280: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
1.71 djm 281: const char *remote_ip = ssh_remote_ipaddr(ssh);
282: const char *remote_host = auth_get_canonical_hostname(
283: ssh, options.use_dns);
1.12 markus 284: char *patterns = xmalloc(strlen(opts) + 1);
1.15 markus 285:
1.12 markus 286: opts += strlen(cp);
1.1 markus 287: i = 0;
1.12 markus 288: while (*opts) {
289: if (*opts == '"')
1.1 markus 290: break;
1.12 markus 291: if (*opts == '\\' && opts[1] == '"') {
292: opts += 2;
1.1 markus 293: patterns[i++] = '"';
294: continue;
295: }
1.12 markus 296: patterns[i++] = *opts++;
1.1 markus 297: }
1.12 markus 298: if (!*opts) {
1.1 markus 299: debug("%.100s, line %lu: missing end quote",
1.10 markus 300: file, linenum);
1.24 markus 301: auth_debug_add("%.100s, line %lu: missing end quote",
1.10 markus 302: file, linenum);
1.58 djm 303: free(patterns);
1.14 markus 304: goto bad_option;
1.1 markus 305: }
1.38 dtucker 306: patterns[i] = '\0';
1.12 markus 307: opts++;
1.43 djm 308: switch (match_host_and_ip(remote_host, remote_ip,
309: patterns)) {
310: case 1:
1.58 djm 311: free(patterns);
1.43 djm 312: /* Host name matches. */
313: goto next_option;
314: case -1:
315: debug("%.100s, line %lu: invalid criteria",
316: file, linenum);
317: auth_debug_add("%.100s, line %lu: "
318: "invalid criteria", file, linenum);
319: /* FALLTHROUGH */
320: case 0:
1.58 djm 321: free(patterns);
1.27 itojun 322: logit("Authentication tried for %.100s with "
1.12 markus 323: "correct key but not from a permitted "
324: "host (host=%.200s, ip=%.200s).",
325: pw->pw_name, remote_host, remote_ip);
1.24 markus 326: auth_debug_add("Your host '%.200s' is not "
1.12 markus 327: "permitted to use this key for login.",
328: remote_host);
1.43 djm 329: break;
1.1 markus 330: }
1.43 djm 331: /* deny access */
332: return 0;
1.15 markus 333: }
334: cp = "permitopen=\"";
335: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
1.29 djm 336: char *host, *p;
1.44 djm 337: int port;
1.15 markus 338: char *patterns = xmalloc(strlen(opts) + 1);
339:
340: opts += strlen(cp);
341: i = 0;
342: while (*opts) {
343: if (*opts == '"')
344: break;
345: if (*opts == '\\' && opts[1] == '"') {
346: opts += 2;
347: patterns[i++] = '"';
348: continue;
349: }
350: patterns[i++] = *opts++;
351: }
352: if (!*opts) {
353: debug("%.100s, line %lu: missing end quote",
354: file, linenum);
1.29 djm 355: auth_debug_add("%.100s, line %lu: missing "
356: "end quote", file, linenum);
1.58 djm 357: free(patterns);
1.15 markus 358: goto bad_option;
359: }
1.38 dtucker 360: patterns[i] = '\0';
1.15 markus 361: opts++;
1.29 djm 362: p = patterns;
1.64 millert 363: /* XXX - add streamlocal support */
1.29 djm 364: host = hpdelim(&p);
365: if (host == NULL || strlen(host) >= NI_MAXHOST) {
366: debug("%.100s, line %lu: Bad permitopen "
1.31 deraadt 367: "specification <%.100s>", file, linenum,
1.29 djm 368: patterns);
1.24 markus 369: auth_debug_add("%.100s, line %lu: "
1.29 djm 370: "Bad permitopen specification", file,
371: linenum);
1.58 djm 372: free(patterns);
1.15 markus 373: goto bad_option;
374: }
1.30 deraadt 375: host = cleanhostname(host);
1.55 dtucker 376: if (p == NULL || (port = permitopen_port(p)) < 0) {
1.29 djm 377: debug("%.100s, line %lu: Bad permitopen port "
378: "<%.100s>", file, linenum, p ? p : "");
1.24 markus 379: auth_debug_add("%.100s, line %lu: "
1.20 stevesk 380: "Bad permitopen port", file, linenum);
1.58 djm 381: free(patterns);
1.15 markus 382: goto bad_option;
383: }
1.57 djm 384: if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)
1.74 ! djm 385: channel_add_permitted_opens(ssh, host, port);
1.58 djm 386: free(patterns);
1.32 reyk 387: goto next_option;
388: }
389: cp = "tunnel=\"";
390: if (strncasecmp(opts, cp, strlen(cp)) == 0) {
391: char *tun = NULL;
392: opts += strlen(cp);
393: tun = xmalloc(strlen(opts) + 1);
394: i = 0;
395: while (*opts) {
396: if (*opts == '"')
397: break;
398: tun[i++] = *opts++;
399: }
400: if (!*opts) {
401: debug("%.100s, line %lu: missing end quote",
402: file, linenum);
403: auth_debug_add("%.100s, line %lu: missing end quote",
404: file, linenum);
1.58 djm 405: free(tun);
1.32 reyk 406: forced_tun_device = -1;
407: goto bad_option;
408: }
1.38 dtucker 409: tun[i] = '\0';
1.32 reyk 410: forced_tun_device = a2tun(tun, NULL);
1.58 djm 411: free(tun);
1.33 reyk 412: if (forced_tun_device == SSH_TUNID_ERR) {
1.32 reyk 413: debug("%.100s, line %lu: invalid tun device",
414: file, linenum);
415: auth_debug_add("%.100s, line %lu: invalid tun device",
416: file, linenum);
417: forced_tun_device = -1;
418: goto bad_option;
419: }
420: auth_debug_add("Forced tun device: %d", forced_tun_device);
421: opts++;
1.1 markus 422: goto next_option;
423: }
424: next_option:
425: /*
426: * Skip the comma, and move to the next option
427: * (or break out if there are no more).
428: */
1.12 markus 429: if (!*opts)
1.1 markus 430: fatal("Bugs in auth-options.c option processing.");
1.12 markus 431: if (*opts == ' ' || *opts == '\t')
1.1 markus 432: break; /* End of options. */
1.12 markus 433: if (*opts != ',')
1.1 markus 434: goto bad_option;
1.12 markus 435: opts++;
1.1 markus 436: /* Process the next option. */
437: }
1.22 provos 438:
1.1 markus 439: /* grant access */
440: return 1;
441:
442: bad_option:
1.27 itojun 443: logit("Bad options in %.100s file, line %lu: %.50s",
1.12 markus 444: file, linenum, opts);
1.24 markus 445: auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
1.12 markus 446: file, linenum, opts);
1.22 provos 447:
1.1 markus 448: /* deny access */
449: return 0;
450: }
1.45 djm 451:
1.52 djm 452: #define OPTIONS_CRITICAL 1
453: #define OPTIONS_EXTENSIONS 2
454: static int
1.65 markus 455: parse_option_list(struct sshbuf *oblob, struct passwd *pw,
1.52 djm 456: u_int which, int crit,
457: int *cert_no_port_forwarding_flag,
458: int *cert_no_agent_forwarding_flag,
459: int *cert_no_x11_forwarding_flag,
460: int *cert_no_pty_flag,
461: int *cert_no_user_rc,
462: char **cert_forced_command,
463: int *cert_source_address_done)
1.45 djm 464: {
1.71 djm 465: struct ssh *ssh = active_state; /* XXX */
1.52 djm 466: char *command, *allowed;
467: const char *remote_ip;
1.59 djm 468: char *name = NULL;
1.65 markus 469: struct sshbuf *c = NULL, *data = NULL;
470: int r, ret = -1, result, found;
471:
472: if ((c = sshbuf_fromb(oblob)) == NULL) {
473: error("%s: sshbuf_fromb failed", __func__);
474: goto out;
475: }
476:
477: while (sshbuf_len(c) > 0) {
478: sshbuf_free(data);
479: data = NULL;
480: if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 ||
481: (r = sshbuf_froms(c, &data)) != 0) {
482: error("Unable to parse certificate options: %s",
483: ssh_err(r));
1.45 djm 484: goto out;
485: }
1.65 markus 486: debug3("found certificate option \"%.100s\" len %zu",
487: name, sshbuf_len(data));
1.52 djm 488: found = 0;
489: if ((which & OPTIONS_EXTENSIONS) != 0) {
490: if (strcmp(name, "permit-X11-forwarding") == 0) {
491: *cert_no_x11_forwarding_flag = 0;
492: found = 1;
493: } else if (strcmp(name,
494: "permit-agent-forwarding") == 0) {
495: *cert_no_agent_forwarding_flag = 0;
496: found = 1;
497: } else if (strcmp(name,
498: "permit-port-forwarding") == 0) {
499: *cert_no_port_forwarding_flag = 0;
500: found = 1;
501: } else if (strcmp(name, "permit-pty") == 0) {
502: *cert_no_pty_flag = 0;
503: found = 1;
504: } else if (strcmp(name, "permit-user-rc") == 0) {
505: *cert_no_user_rc = 0;
506: found = 1;
507: }
508: }
509: if (!found && (which & OPTIONS_CRITICAL) != 0) {
510: if (strcmp(name, "force-command") == 0) {
1.65 markus 511: if ((r = sshbuf_get_cstring(data, &command,
512: NULL)) != 0) {
513: error("Unable to parse \"%s\" "
514: "section: %s", name, ssh_err(r));
1.52 djm 515: goto out;
516: }
517: if (*cert_forced_command != NULL) {
518: error("Certificate has multiple "
519: "force-command options");
1.58 djm 520: free(command);
1.52 djm 521: goto out;
522: }
523: *cert_forced_command = command;
524: found = 1;
1.45 djm 525: }
1.52 djm 526: if (strcmp(name, "source-address") == 0) {
1.65 markus 527: if ((r = sshbuf_get_cstring(data, &allowed,
528: NULL)) != 0) {
529: error("Unable to parse \"%s\" "
530: "section: %s", name, ssh_err(r));
1.52 djm 531: goto out;
532: }
533: if ((*cert_source_address_done)++) {
534: error("Certificate has multiple "
535: "source-address options");
1.58 djm 536: free(allowed);
1.52 djm 537: goto out;
538: }
1.71 djm 539: remote_ip = ssh_remote_ipaddr(ssh);
1.62 djm 540: result = addr_match_cidr_list(remote_ip,
541: allowed);
542: free(allowed);
543: switch (result) {
1.52 djm 544: case 1:
545: /* accepted */
546: break;
547: case 0:
548: /* no match */
549: logit("Authentication tried for %.100s "
550: "with valid certificate but not "
551: "from a permitted host "
552: "(ip=%.200s).", pw->pw_name,
553: remote_ip);
554: auth_debug_add("Your address '%.200s' "
555: "is not permitted to use this "
556: "certificate for login.",
557: remote_ip);
558: goto out;
559: case -1:
1.62 djm 560: default:
1.52 djm 561: error("Certificate source-address "
562: "contents invalid");
563: goto out;
564: }
565: found = 1;
1.46 djm 566: }
1.52 djm 567: }
568:
569: if (!found) {
570: if (crit) {
571: error("Certificate critical option \"%s\" "
572: "is not supported", name);
1.45 djm 573: goto out;
1.52 djm 574: } else {
575: logit("Certificate extension \"%s\" "
576: "is not supported", name);
1.45 djm 577: }
1.65 markus 578: } else if (sshbuf_len(data) != 0) {
1.52 djm 579: error("Certificate option \"%s\" corrupt "
1.45 djm 580: "(extra data)", name);
581: goto out;
582: }
1.58 djm 583: free(name);
1.59 djm 584: name = NULL;
1.45 djm 585: }
1.50 djm 586: /* successfully parsed all options */
1.45 djm 587: ret = 0;
588:
1.52 djm 589: out:
590: if (ret != 0 &&
591: cert_forced_command != NULL &&
592: *cert_forced_command != NULL) {
1.58 djm 593: free(*cert_forced_command);
1.52 djm 594: *cert_forced_command = NULL;
595: }
1.70 mmcc 596: free(name);
1.65 markus 597: sshbuf_free(data);
598: sshbuf_free(c);
1.52 djm 599: return ret;
600: }
601:
602: /*
603: * Set options from critical certificate options. These supersede user key
604: * options so this must be called after auth_parse_options().
605: */
606: int
1.72 djm 607: auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason)
1.52 djm 608: {
609: int cert_no_port_forwarding_flag = 1;
610: int cert_no_agent_forwarding_flag = 1;
611: int cert_no_x11_forwarding_flag = 1;
612: int cert_no_pty_flag = 1;
613: int cert_no_user_rc = 1;
614: char *cert_forced_command = NULL;
615: int cert_source_address_done = 0;
616:
1.72 djm 617: *reason = "invalid certificate options";
618:
1.68 djm 619: /* Separate options and extensions for v01 certs */
620: if (parse_option_list(k->cert->critical, pw,
621: OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
622: &cert_forced_command,
623: &cert_source_address_done) == -1)
624: return -1;
625: if (parse_option_list(k->cert->extensions, pw,
626: OPTIONS_EXTENSIONS, 0,
627: &cert_no_port_forwarding_flag,
628: &cert_no_agent_forwarding_flag,
629: &cert_no_x11_forwarding_flag,
630: &cert_no_pty_flag,
631: &cert_no_user_rc,
632: NULL, NULL) == -1)
633: return -1;
1.52 djm 634:
1.45 djm 635: no_port_forwarding_flag |= cert_no_port_forwarding_flag;
636: no_agent_forwarding_flag |= cert_no_agent_forwarding_flag;
637: no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
638: no_pty_flag |= cert_no_pty_flag;
639: no_user_rc |= cert_no_user_rc;
1.72 djm 640: /*
641: * Only permit both CA and key option forced-command if they match.
642: * Otherwise refuse the certificate.
643: */
644: if (cert_forced_command != NULL && forced_command != NULL) {
645: if (strcmp(forced_command, cert_forced_command) == 0) {
646: free(forced_command);
647: forced_command = cert_forced_command;
648: } else {
649: *reason = "certificate and key options forced command "
650: "do not match";
651: free(cert_forced_command);
652: return -1;
653: }
654: } else if (cert_forced_command != NULL)
1.45 djm 655: forced_command = cert_forced_command;
1.72 djm 656: /* success */
657: *reason = NULL;
1.52 djm 658: return 0;
1.45 djm 659: }
660: