1 /* $OpenBSD: auth-options.c,v 1.98 2022/02/08 08:59:12 dtucker Exp $ */
3 * Copyright (c) 2018 Damien Miller <djm@mindrot.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
31 #include "openbsd-compat/sys-queue.h"
41 #include "auth-options.h"
44 dup_strings(char ***dstp
, size_t *ndstp
, char **src
, size_t nsrc
)
54 if ((dst
= calloc(nsrc
, sizeof(*src
))) == NULL
)
56 for (i
= 0; i
< nsrc
; i
++) {
57 if ((dst
[i
] = strdup(src
[i
])) == NULL
) {
58 for (j
= 0; j
< i
; j
++)
70 #define OPTIONS_CRITICAL 1
71 #define OPTIONS_EXTENSIONS 2
73 cert_option_list(struct sshauthopt
*opts
, struct sshbuf
*oblob
,
74 u_int which
, int crit
)
76 char *command
, *allowed
;
78 struct sshbuf
*c
= NULL
, *data
= NULL
;
79 int r
, ret
= -1, found
;
81 if ((c
= sshbuf_fromb(oblob
)) == NULL
) {
82 error_f("sshbuf_fromb failed");
86 while (sshbuf_len(c
) > 0) {
89 if ((r
= sshbuf_get_cstring(c
, &name
, NULL
)) != 0 ||
90 (r
= sshbuf_froms(c
, &data
)) != 0) {
91 error_r(r
, "Unable to parse certificate options");
94 debug3("found certificate option \"%.100s\" len %zu",
95 name
, sshbuf_len(data
));
97 if ((which
& OPTIONS_EXTENSIONS
) != 0) {
98 if (strcmp(name
, "no-touch-required") == 0) {
99 opts
->no_require_user_presence
= 1;
101 } else if (strcmp(name
, "permit-X11-forwarding") == 0) {
102 opts
->permit_x11_forwarding_flag
= 1;
104 } else if (strcmp(name
,
105 "permit-agent-forwarding") == 0) {
106 opts
->permit_agent_forwarding_flag
= 1;
108 } else if (strcmp(name
,
109 "permit-port-forwarding") == 0) {
110 opts
->permit_port_forwarding_flag
= 1;
112 } else if (strcmp(name
, "permit-pty") == 0) {
113 opts
->permit_pty_flag
= 1;
115 } else if (strcmp(name
, "permit-user-rc") == 0) {
116 opts
->permit_user_rc
= 1;
120 if (!found
&& (which
& OPTIONS_CRITICAL
) != 0) {
121 if (strcmp(name
, "verify-required") == 0) {
122 opts
->require_verify
= 1;
124 } else if (strcmp(name
, "force-command") == 0) {
125 if ((r
= sshbuf_get_cstring(data
, &command
,
127 error_r(r
, "Unable to parse \"%s\" "
131 if (opts
->force_command
!= NULL
) {
132 error("Certificate has multiple "
133 "force-command options");
137 opts
->force_command
= command
;
139 } else if (strcmp(name
, "source-address") == 0) {
140 if ((r
= sshbuf_get_cstring(data
, &allowed
,
142 error_r(r
, "Unable to parse \"%s\" "
146 if (opts
->required_from_host_cert
!= NULL
) {
147 error("Certificate has multiple "
148 "source-address options");
153 if (addr_match_cidr_list(NULL
, allowed
) == -1) {
154 error("Certificate source-address "
158 opts
->required_from_host_cert
= allowed
;
165 error("Certificate critical option \"%s\" "
166 "is not supported", name
);
169 logit("Certificate extension \"%s\" "
170 "is not supported", name
);
172 } else if (sshbuf_len(data
) != 0) {
173 error("Certificate option \"%s\" corrupt "
174 "(extra data)", name
);
180 /* successfully parsed all options */
193 struct sshauthopt
*ret
;
195 if ((ret
= calloc(1, sizeof(*ret
))) == NULL
)
197 ret
->force_tun_device
= -1;
202 sshauthopt_free(struct sshauthopt
*opts
)
209 free(opts
->cert_principals
);
210 free(opts
->force_command
);
211 free(opts
->required_from_host_cert
);
212 free(opts
->required_from_host_keys
);
214 for (i
= 0; i
< opts
->nenv
; i
++)
218 for (i
= 0; i
< opts
->npermitopen
; i
++)
219 free(opts
->permitopen
[i
]);
220 free(opts
->permitopen
);
222 for (i
= 0; i
< opts
->npermitlisten
; i
++)
223 free(opts
->permitlisten
[i
]);
224 free(opts
->permitlisten
);
226 freezero(opts
, sizeof(*opts
));
230 sshauthopt_new_with_keys_defaults(void)
232 struct sshauthopt
*ret
= NULL
;
234 if ((ret
= sshauthopt_new()) == NULL
)
237 /* Defaults for authorized_keys flags */
238 ret
->permit_port_forwarding_flag
= 1;
239 ret
->permit_agent_forwarding_flag
= 1;
240 ret
->permit_x11_forwarding_flag
= 1;
241 ret
->permit_pty_flag
= 1;
242 ret
->permit_user_rc
= 1;
247 * Parse and record a permitopen/permitlisten directive.
248 * Return 0 on success. Return -1 on failure and sets *errstrp to error reason.
251 handle_permit(const char **optsp
, int allow_bare_port
,
252 char ***permitsp
, size_t *npermitsp
, const char **errstrp
)
254 char *opt
, *tmp
, *cp
, *host
, **permits
= *permitsp
;
255 size_t npermits
= *npermitsp
;
256 const char *errstr
= "unknown error";
258 if (npermits
> SSH_AUTHOPT_PERMIT_MAX
) {
259 *errstrp
= "too many permission directives";
262 if ((opt
= opt_dequote(optsp
, &errstr
)) == NULL
) {
265 if (allow_bare_port
&& strchr(opt
, ':') == NULL
) {
267 * Allow a bare port number in permitlisten to indicate a
268 * listen_host wildcard.
270 if (asprintf(&tmp
, "*:%s", opt
) == -1) {
272 *errstrp
= "memory allocation failed";
278 if ((tmp
= strdup(opt
)) == NULL
) {
280 *errstrp
= "memory allocation failed";
284 /* validate syntax before recording it. */
285 host
= hpdelim2(&cp
, NULL
);
286 if (host
== NULL
|| strlen(host
) >= NI_MAXHOST
) {
289 *errstrp
= "invalid permission hostname";
293 * don't want to use permitopen_port to avoid
294 * dependency on channels.[ch] here.
297 (strcmp(cp
, "*") != 0 && a2port(cp
) <= 0)) {
300 *errstrp
= "invalid permission port";
303 /* XXX - add streamlocal support */
306 if ((permits
= recallocarray(permits
, npermits
, npermits
+ 1,
307 sizeof(*permits
))) == NULL
) {
309 /* NB. don't update *permitsp if alloc fails */
310 *errstrp
= "memory allocation failed";
313 permits
[npermits
++] = opt
;
315 *npermitsp
= npermits
;
320 sshauthopt_parse(const char *opts
, const char **errstrp
)
322 char **oarray
, *opt
, *cp
, *tmp
;
324 struct sshauthopt
*ret
= NULL
;
325 const char *errstr
= "unknown error";
326 uint64_t valid_before
;
331 if ((ret
= sshauthopt_new_with_keys_defaults()) == NULL
)
337 while (*opts
&& *opts
!= ' ' && *opts
!= '\t') {
339 if ((r
= opt_flag("restrict", 0, &opts
)) != -1) {
341 ret
->permit_port_forwarding_flag
= 0;
342 ret
->permit_agent_forwarding_flag
= 0;
343 ret
->permit_x11_forwarding_flag
= 0;
344 ret
->permit_pty_flag
= 0;
345 ret
->permit_user_rc
= 0;
346 } else if ((r
= opt_flag("cert-authority", 0, &opts
)) != -1) {
347 ret
->cert_authority
= r
;
348 } else if ((r
= opt_flag("port-forwarding", 1, &opts
)) != -1) {
349 ret
->permit_port_forwarding_flag
= r
== 1;
350 } else if ((r
= opt_flag("agent-forwarding", 1, &opts
)) != -1) {
351 ret
->permit_agent_forwarding_flag
= r
== 1;
352 } else if ((r
= opt_flag("x11-forwarding", 1, &opts
)) != -1) {
353 ret
->permit_x11_forwarding_flag
= r
== 1;
354 } else if ((r
= opt_flag("touch-required", 1, &opts
)) != -1) {
355 ret
->no_require_user_presence
= r
!= 1; /* NB. flip */
356 } else if ((r
= opt_flag("verify-required", 1, &opts
)) != -1) {
357 ret
->require_verify
= r
== 1;
358 } else if ((r
= opt_flag("pty", 1, &opts
)) != -1) {
359 ret
->permit_pty_flag
= r
== 1;
360 } else if ((r
= opt_flag("user-rc", 1, &opts
)) != -1) {
361 ret
->permit_user_rc
= r
== 1;
362 } else if (opt_match(&opts
, "command")) {
363 if (ret
->force_command
!= NULL
) {
364 errstr
= "multiple \"command\" clauses";
367 ret
->force_command
= opt_dequote(&opts
, &errstr
);
368 if (ret
->force_command
== NULL
)
370 } else if (opt_match(&opts
, "principals")) {
371 if (ret
->cert_principals
!= NULL
) {
372 errstr
= "multiple \"principals\" clauses";
375 ret
->cert_principals
= opt_dequote(&opts
, &errstr
);
376 if (ret
->cert_principals
== NULL
)
378 } else if (opt_match(&opts
, "from")) {
379 if (ret
->required_from_host_keys
!= NULL
) {
380 errstr
= "multiple \"from\" clauses";
383 ret
->required_from_host_keys
= opt_dequote(&opts
,
385 if (ret
->required_from_host_keys
== NULL
)
387 } else if (opt_match(&opts
, "expiry-time")) {
388 if ((opt
= opt_dequote(&opts
, &errstr
)) == NULL
)
390 if (parse_absolute_time(opt
, &valid_before
) != 0 ||
393 errstr
= "invalid expires time";
397 if (ret
->valid_before
== 0 ||
398 valid_before
< ret
->valid_before
)
399 ret
->valid_before
= valid_before
;
400 } else if (opt_match(&opts
, "environment")) {
401 if (ret
->nenv
> SSH_AUTHOPT_ENV_MAX
) {
402 errstr
= "too many environment strings";
405 if ((opt
= opt_dequote(&opts
, &errstr
)) == NULL
)
407 /* env name must be alphanumeric and followed by '=' */
408 if ((tmp
= strchr(opt
, '=')) == NULL
) {
410 errstr
= "invalid environment string";
413 if ((cp
= strdup(opt
)) == NULL
) {
417 l
= (size_t)(tmp
- opt
);
418 cp
[l
] = '\0'; /* truncate at '=' */
419 if (!valid_env_name(cp
)) {
422 errstr
= "invalid environment string";
425 /* Check for duplicates; XXX O(n*log(n)) */
426 for (i
= 0; i
< ret
->nenv
; i
++) {
427 if (strncmp(ret
->env
[i
], cp
, l
) == 0 &&
428 ret
->env
[i
][l
] == '=')
432 /* First match wins */
433 if (i
>= ret
->nenv
) {
436 if ((ret
->env
= recallocarray(ret
->env
,
437 ret
->nenv
, ret
->nenv
+ 1,
438 sizeof(*ret
->env
))) == NULL
) {
440 /* put it back for cleanup */
444 ret
->env
[ret
->nenv
++] = opt
;
445 opt
= NULL
; /* transferred */
448 } else if (opt_match(&opts
, "permitopen")) {
449 if (handle_permit(&opts
, 0, &ret
->permitopen
,
450 &ret
->npermitopen
, &errstr
) != 0)
452 } else if (opt_match(&opts
, "permitlisten")) {
453 if (handle_permit(&opts
, 1, &ret
->permitlisten
,
454 &ret
->npermitlisten
, &errstr
) != 0)
456 } else if (opt_match(&opts
, "tunnel")) {
457 if ((opt
= opt_dequote(&opts
, &errstr
)) == NULL
)
459 ret
->force_tun_device
= a2tun(opt
, NULL
);
461 if (ret
->force_tun_device
== SSH_TUNID_ERR
) {
462 errstr
= "invalid tun device";
467 * Skip the comma, and move to the next option
468 * (or break out if there are no more).
470 if (*opts
== '\0' || *opts
== ' ' || *opts
== '\t')
471 break; /* End of options. */
472 /* Anything other than a comma is an unknown option */
474 errstr
= "unknown key option";
479 errstr
= "unexpected end-of-options";
490 errstr
= "memory allocation failed";
492 sshauthopt_free(ret
);
499 sshauthopt_from_cert(struct sshkey
*k
)
501 struct sshauthopt
*ret
;
503 if (k
== NULL
|| !sshkey_type_is_cert(k
->type
) || k
->cert
== NULL
||
504 k
->cert
->type
!= SSH2_CERT_TYPE_USER
)
507 if ((ret
= sshauthopt_new()) == NULL
)
510 /* Handle options and critical extensions separately */
511 if (cert_option_list(ret
, k
->cert
->critical
,
512 OPTIONS_CRITICAL
, 1) == -1) {
513 sshauthopt_free(ret
);
516 if (cert_option_list(ret
, k
->cert
->extensions
,
517 OPTIONS_EXTENSIONS
, 0) == -1) {
518 sshauthopt_free(ret
);
526 * Merges "additional" options to "primary" and returns the result.
527 * NB. Some options from primary have primacy.
530 sshauthopt_merge(const struct sshauthopt
*primary
,
531 const struct sshauthopt
*additional
, const char **errstrp
)
533 struct sshauthopt
*ret
;
534 const char *errstr
= "internal error";
540 if ((ret
= sshauthopt_new()) == NULL
)
543 /* cert_authority and cert_principals are cleared in result */
545 /* Prefer access lists from primary. */
546 /* XXX err is both set and mismatch? */
547 tmp
= primary
->required_from_host_cert
;
549 tmp
= additional
->required_from_host_cert
;
550 if (tmp
!= NULL
&& (ret
->required_from_host_cert
= strdup(tmp
)) == NULL
)
552 tmp
= primary
->required_from_host_keys
;
554 tmp
= additional
->required_from_host_keys
;
555 if (tmp
!= NULL
&& (ret
->required_from_host_keys
= strdup(tmp
)) == NULL
)
559 * force_tun_device, permitopen/permitlisten and environment all
560 * prefer the primary.
562 ret
->force_tun_device
= primary
->force_tun_device
;
563 if (ret
->force_tun_device
== -1)
564 ret
->force_tun_device
= additional
->force_tun_device
;
565 if (primary
->nenv
> 0) {
566 if (dup_strings(&ret
->env
, &ret
->nenv
,
567 primary
->env
, primary
->nenv
) != 0)
569 } else if (additional
->nenv
) {
570 if (dup_strings(&ret
->env
, &ret
->nenv
,
571 additional
->env
, additional
->nenv
) != 0)
574 if (primary
->npermitopen
> 0) {
575 if (dup_strings(&ret
->permitopen
, &ret
->npermitopen
,
576 primary
->permitopen
, primary
->npermitopen
) != 0)
578 } else if (additional
->npermitopen
> 0) {
579 if (dup_strings(&ret
->permitopen
, &ret
->npermitopen
,
580 additional
->permitopen
, additional
->npermitopen
) != 0)
584 if (primary
->npermitlisten
> 0) {
585 if (dup_strings(&ret
->permitlisten
, &ret
->npermitlisten
,
586 primary
->permitlisten
, primary
->npermitlisten
) != 0)
588 } else if (additional
->npermitlisten
> 0) {
589 if (dup_strings(&ret
->permitlisten
, &ret
->npermitlisten
,
590 additional
->permitlisten
, additional
->npermitlisten
) != 0)
594 #define OPTFLAG_AND(x) ret->x = (primary->x == 1) && (additional->x == 1)
595 #define OPTFLAG_OR(x) ret->x = (primary->x == 1) || (additional->x == 1)
596 /* Permissive flags are logical-AND (i.e. must be set in both) */
597 OPTFLAG_AND(permit_port_forwarding_flag
);
598 OPTFLAG_AND(permit_agent_forwarding_flag
);
599 OPTFLAG_AND(permit_x11_forwarding_flag
);
600 OPTFLAG_AND(permit_pty_flag
);
601 OPTFLAG_AND(permit_user_rc
);
602 OPTFLAG_AND(no_require_user_presence
);
603 /* Restrictive flags are logical-OR (i.e. must be set in either) */
604 OPTFLAG_OR(require_verify
);
607 /* Earliest expiry time should win */
608 if (primary
->valid_before
!= 0)
609 ret
->valid_before
= primary
->valid_before
;
610 if (additional
->valid_before
!= 0 &&
611 additional
->valid_before
< ret
->valid_before
)
612 ret
->valid_before
= additional
->valid_before
;
615 * When both multiple forced-command are specified, only
616 * proceed if they are identical, otherwise fail.
618 if (primary
->force_command
!= NULL
&&
619 additional
->force_command
!= NULL
) {
620 if (strcmp(primary
->force_command
,
621 additional
->force_command
) == 0) {
623 ret
->force_command
= strdup(primary
->force_command
);
624 if (ret
->force_command
== NULL
)
627 errstr
= "forced command options do not match";
630 } else if (primary
->force_command
!= NULL
) {
631 if ((ret
->force_command
= strdup(
632 primary
->force_command
)) == NULL
)
634 } else if (additional
->force_command
!= NULL
) {
635 if ((ret
->force_command
= strdup(
636 additional
->force_command
)) == NULL
)
645 errstr
= "memory allocation failed";
649 sshauthopt_free(ret
);
657 sshauthopt_copy(const struct sshauthopt
*orig
)
659 struct sshauthopt
*ret
;
661 if ((ret
= sshauthopt_new()) == NULL
)
664 #define OPTSCALAR(x) ret->x = orig->x
665 OPTSCALAR(permit_port_forwarding_flag
);
666 OPTSCALAR(permit_agent_forwarding_flag
);
667 OPTSCALAR(permit_x11_forwarding_flag
);
668 OPTSCALAR(permit_pty_flag
);
669 OPTSCALAR(permit_user_rc
);
670 OPTSCALAR(restricted
);
671 OPTSCALAR(cert_authority
);
672 OPTSCALAR(force_tun_device
);
673 OPTSCALAR(valid_before
);
674 OPTSCALAR(no_require_user_presence
);
675 OPTSCALAR(require_verify
);
677 #define OPTSTRING(x) \
679 if (orig->x != NULL && (ret->x = strdup(orig->x)) == NULL) { \
680 sshauthopt_free(ret); \
684 OPTSTRING(cert_principals
);
685 OPTSTRING(force_command
);
686 OPTSTRING(required_from_host_cert
);
687 OPTSTRING(required_from_host_keys
);
690 if (dup_strings(&ret
->env
, &ret
->nenv
, orig
->env
, orig
->nenv
) != 0 ||
691 dup_strings(&ret
->permitopen
, &ret
->npermitopen
,
692 orig
->permitopen
, orig
->npermitopen
) != 0 ||
693 dup_strings(&ret
->permitlisten
, &ret
->npermitlisten
,
694 orig
->permitlisten
, orig
->npermitlisten
) != 0) {
695 sshauthopt_free(ret
);
702 serialise_array(struct sshbuf
*m
, char **a
, size_t n
)
709 return SSH_ERR_INTERNAL_ERROR
;
711 if ((b
= sshbuf_new()) == NULL
) {
712 return SSH_ERR_ALLOC_FAIL
;
714 for (i
= 0; i
< n
; i
++) {
715 if ((r
= sshbuf_put_cstring(b
, a
[i
])) != 0) {
720 if ((r
= sshbuf_put_u32(m
, n
)) != 0 ||
721 (r
= sshbuf_put_stringb(m
, b
)) != 0) {
730 deserialise_array(struct sshbuf
*m
, char ***ap
, size_t *np
)
734 struct sshbuf
*b
= NULL
;
736 int r
= SSH_ERR_INTERNAL_ERROR
;
738 if ((r
= sshbuf_get_u32(m
, &tmp
)) != 0 ||
739 (r
= sshbuf_froms(m
, &b
)) != 0)
742 r
= SSH_ERR_INVALID_FORMAT
;
746 if (n
> 0 && (a
= calloc(n
, sizeof(*a
))) == NULL
) {
747 r
= SSH_ERR_ALLOC_FAIL
;
750 for (i
= 0; i
< n
; i
++) {
751 if ((r
= sshbuf_get_cstring(b
, &a
[i
], NULL
)) != 0)
762 for (i
= 0; i
< n
; i
++)
771 serialise_nullable_string(struct sshbuf
*m
, const char *s
)
775 if ((r
= sshbuf_put_u8(m
, s
== NULL
)) != 0 ||
776 (r
= sshbuf_put_cstring(m
, s
)) != 0)
782 deserialise_nullable_string(struct sshbuf
*m
, char **sp
)
788 if ((r
= sshbuf_get_u8(m
, &flag
)) != 0 ||
789 (r
= sshbuf_get_cstring(m
, flag
? NULL
: sp
, NULL
)) != 0)
795 sshauthopt_serialise(const struct sshauthopt
*opts
, struct sshbuf
*m
,
798 int r
= SSH_ERR_INTERNAL_ERROR
;
801 if ((r
= sshbuf_put_u8(m
, opts
->permit_port_forwarding_flag
)) != 0 ||
802 (r
= sshbuf_put_u8(m
, opts
->permit_agent_forwarding_flag
)) != 0 ||
803 (r
= sshbuf_put_u8(m
, opts
->permit_x11_forwarding_flag
)) != 0 ||
804 (r
= sshbuf_put_u8(m
, opts
->permit_pty_flag
)) != 0 ||
805 (r
= sshbuf_put_u8(m
, opts
->permit_user_rc
)) != 0 ||
806 (r
= sshbuf_put_u8(m
, opts
->restricted
)) != 0 ||
807 (r
= sshbuf_put_u8(m
, opts
->cert_authority
)) != 0 ||
808 (r
= sshbuf_put_u8(m
, opts
->no_require_user_presence
)) != 0 ||
809 (r
= sshbuf_put_u8(m
, opts
->require_verify
)) != 0)
812 /* Simple integer options */
813 if ((r
= sshbuf_put_u64(m
, opts
->valid_before
)) != 0)
816 /* tunnel number can be negative to indicate "unset" */
817 if ((r
= sshbuf_put_u8(m
, opts
->force_tun_device
== -1)) != 0 ||
818 (r
= sshbuf_put_u32(m
, (opts
->force_tun_device
< 0) ?
819 0 : (u_int
)opts
->force_tun_device
)) != 0)
822 /* String options; these may be NULL */
823 if ((r
= serialise_nullable_string(m
,
824 untrusted
? "yes" : opts
->cert_principals
)) != 0 ||
825 (r
= serialise_nullable_string(m
,
826 untrusted
? "true" : opts
->force_command
)) != 0 ||
827 (r
= serialise_nullable_string(m
,
828 untrusted
? NULL
: opts
->required_from_host_cert
)) != 0 ||
829 (r
= serialise_nullable_string(m
,
830 untrusted
? NULL
: opts
->required_from_host_keys
)) != 0)
834 if ((r
= serialise_array(m
, opts
->env
,
835 untrusted
? 0 : opts
->nenv
)) != 0 ||
836 (r
= serialise_array(m
, opts
->permitopen
,
837 untrusted
? 0 : opts
->npermitopen
)) != 0 ||
838 (r
= serialise_array(m
, opts
->permitlisten
,
839 untrusted
? 0 : opts
->npermitlisten
)) != 0)
847 sshauthopt_deserialise(struct sshbuf
*m
, struct sshauthopt
**optsp
)
849 struct sshauthopt
*opts
= NULL
;
850 int r
= SSH_ERR_INTERNAL_ERROR
;
854 if ((opts
= calloc(1, sizeof(*opts
))) == NULL
)
855 return SSH_ERR_ALLOC_FAIL
;
858 #define OPT_FLAG(x) \
860 if ((r = sshbuf_get_u8(m, &f)) != 0) \
864 OPT_FLAG(permit_port_forwarding_flag
);
865 OPT_FLAG(permit_agent_forwarding_flag
);
866 OPT_FLAG(permit_x11_forwarding_flag
);
867 OPT_FLAG(permit_pty_flag
);
868 OPT_FLAG(permit_user_rc
);
869 OPT_FLAG(restricted
);
870 OPT_FLAG(cert_authority
);
871 OPT_FLAG(no_require_user_presence
);
872 OPT_FLAG(require_verify
);
875 /* Simple integer options */
876 if ((r
= sshbuf_get_u64(m
, &opts
->valid_before
)) != 0)
879 /* tunnel number can be negative to indicate "unset" */
880 if ((r
= sshbuf_get_u8(m
, &f
)) != 0 ||
881 (r
= sshbuf_get_u32(m
, &tmp
)) != 0)
883 opts
->force_tun_device
= f
? -1 : (int)tmp
;
885 /* String options may be NULL */
886 if ((r
= deserialise_nullable_string(m
, &opts
->cert_principals
)) != 0 ||
887 (r
= deserialise_nullable_string(m
, &opts
->force_command
)) != 0 ||
888 (r
= deserialise_nullable_string(m
,
889 &opts
->required_from_host_cert
)) != 0 ||
890 (r
= deserialise_nullable_string(m
,
891 &opts
->required_from_host_keys
)) != 0)
895 if ((r
= deserialise_array(m
, &opts
->env
, &opts
->nenv
)) != 0 ||
896 (r
= deserialise_array(m
,
897 &opts
->permitopen
, &opts
->npermitopen
)) != 0 ||
898 (r
= deserialise_array(m
,
899 &opts
->permitlisten
, &opts
->npermitlisten
)) != 0)
907 sshauthopt_free(opts
);