version 1.79, 2018/04/06 04:15:45 |
version 1.80, 2018/06/06 18:23:32 |
|
|
free(opts->permitopen[i]); |
free(opts->permitopen[i]); |
free(opts->permitopen); |
free(opts->permitopen); |
|
|
|
for (i = 0; i < opts->npermitlisten; i++) |
|
free(opts->permitlisten[i]); |
|
free(opts->permitlisten); |
|
|
explicit_bzero(opts, sizeof(*opts)); |
explicit_bzero(opts, sizeof(*opts)); |
free(opts); |
free(opts); |
} |
} |
|
|
return ret; |
return ret; |
} |
} |
|
|
|
/* |
|
* Parse and record a permitopen/permitlisten directive. |
|
* Return 0 on success. Return -1 on failure and sets *errstrp to error reason. |
|
*/ |
|
static int |
|
handle_permit(const char *opts, char ***permitsp, size_t *npermitsp, |
|
const char **errstrp) |
|
{ |
|
char *opt, *tmp, *cp, *host, **permits = *permitsp; |
|
size_t npermits = *npermitsp; |
|
const char *errstr = "unknown error"; |
|
|
|
if (npermits > INT_MAX) { |
|
*errstrp = "too many permission directives"; |
|
return -1; |
|
} |
|
if ((opt = opt_dequote(&opts, &errstr)) == NULL) { |
|
return -1; |
|
} |
|
if ((tmp = strdup(opt)) == NULL) { |
|
free(opt); |
|
*errstrp = "memory allocation failed"; |
|
return -1; |
|
} |
|
cp = tmp; |
|
/* validate syntax before recording it. */ |
|
host = hpdelim(&cp); |
|
if (host == NULL || strlen(host) >= NI_MAXHOST) { |
|
free(tmp); |
|
free(opt); |
|
*errstrp = "invalid permission hostname"; |
|
return -1; |
|
} |
|
/* |
|
* don't want to use permitopen_port to avoid |
|
* dependency on channels.[ch] here. |
|
*/ |
|
if (cp == NULL || |
|
(strcmp(cp, "*") != 0 && a2port(cp) <= 0)) { |
|
free(tmp); |
|
free(opt); |
|
*errstrp = "invalid permission port"; |
|
return -1; |
|
} |
|
/* XXX - add streamlocal support */ |
|
free(tmp); |
|
/* Record it */ |
|
if ((permits = recallocarray(permits, npermits, npermits + 1, |
|
sizeof(*permits))) == NULL) { |
|
free(opt); |
|
/* NB. don't update *permitsp if alloc fails */ |
|
*errstrp = "memory allocation failed"; |
|
return -1; |
|
} |
|
permits[npermits++] = opt; |
|
*permitsp = permits; |
|
*npermitsp = npermits; |
|
return 0; |
|
} |
|
|
struct sshauthopt * |
struct sshauthopt * |
sshauthopt_parse(const char *opts, const char **errstrp) |
sshauthopt_parse(const char *opts, const char **errstrp) |
{ |
{ |
char **oarray, *opt, *cp, *tmp, *host; |
char **oarray, *opt, *cp, *tmp; |
int r; |
int r; |
struct sshauthopt *ret = NULL; |
struct sshauthopt *ret = NULL; |
const char *errstr = "unknown error"; |
const char *errstr = "unknown error"; |
|
|
} |
} |
ret->env[ret->nenv++] = opt; |
ret->env[ret->nenv++] = opt; |
} else if (opt_match(&opts, "permitopen")) { |
} else if (opt_match(&opts, "permitopen")) { |
if (ret->npermitopen > INT_MAX) { |
if (handle_permit(opts, &ret->permitopen, |
errstr = "too many permitopens"; |
&ret->npermitopen, &errstr) != 0) |
goto fail; |
goto fail; |
} |
} else if (opt_match(&opts, "permitlisten")) { |
if ((opt = opt_dequote(&opts, &errstr)) == NULL) |
if (handle_permit(opts, &ret->permitlisten, |
|
&ret->npermitlisten, &errstr) != 0) |
goto fail; |
goto fail; |
if ((tmp = strdup(opt)) == NULL) { |
|
free(opt); |
|
goto alloc_fail; |
|
} |
|
cp = tmp; |
|
/* validate syntax of permitopen before recording it. */ |
|
host = hpdelim(&cp); |
|
if (host == NULL || strlen(host) >= NI_MAXHOST) { |
|
free(tmp); |
|
free(opt); |
|
errstr = "invalid permitopen hostname"; |
|
goto fail; |
|
} |
|
/* |
|
* don't want to use permitopen_port to avoid |
|
* dependency on channels.[ch] here. |
|
*/ |
|
if (cp == NULL || |
|
(strcmp(cp, "*") != 0 && a2port(cp) <= 0)) { |
|
free(tmp); |
|
free(opt); |
|
errstr = "invalid permitopen port"; |
|
goto fail; |
|
} |
|
/* XXX - add streamlocal support */ |
|
free(tmp); |
|
/* Record it */ |
|
oarray = ret->permitopen; |
|
if ((ret->permitopen = recallocarray(ret->permitopen, |
|
ret->npermitopen, ret->npermitopen + 1, |
|
sizeof(*ret->permitopen))) == NULL) { |
|
free(opt); |
|
ret->permitopen = oarray; |
|
goto alloc_fail; |
|
} |
|
ret->permitopen[ret->npermitopen++] = opt; |
|
} else if (opt_match(&opts, "tunnel")) { |
} else if (opt_match(&opts, "tunnel")) { |
if ((opt = opt_dequote(&opts, &errstr)) == NULL) |
if ((opt = opt_dequote(&opts, &errstr)) == NULL) |
goto fail; |
goto fail; |
|
|
if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL) |
if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL) |
goto alloc_fail; |
goto alloc_fail; |
|
|
/* force_tun_device, permitopen and environment prefer the primary. */ |
/* |
|
* force_tun_device, permitopen/permitlisten and environment all |
|
* prefer the primary. |
|
*/ |
ret->force_tun_device = primary->force_tun_device; |
ret->force_tun_device = primary->force_tun_device; |
if (ret->force_tun_device == -1) |
if (ret->force_tun_device == -1) |
ret->force_tun_device = additional->force_tun_device; |
ret->force_tun_device = additional->force_tun_device; |
|
|
goto alloc_fail; |
goto alloc_fail; |
} |
} |
|
|
|
if (primary->npermitlisten > 0) { |
|
if (dup_strings(&ret->permitlisten, &ret->npermitlisten, |
|
primary->permitlisten, primary->npermitlisten) != 0) |
|
goto alloc_fail; |
|
} else if (additional->npermitlisten > 0) { |
|
if (dup_strings(&ret->permitlisten, &ret->npermitlisten, |
|
additional->permitlisten, additional->npermitlisten) != 0) |
|
goto alloc_fail; |
|
} |
|
|
/* Flags are logical-AND (i.e. must be set in both for permission) */ |
/* Flags are logical-AND (i.e. must be set in both for permission) */ |
#define OPTFLAG(x) ret->x = (primary->x == 1) && (additional->x == 1) |
#define OPTFLAG(x) ret->x = (primary->x == 1) && (additional->x == 1) |
OPTFLAG(permit_port_forwarding_flag); |
OPTFLAG(permit_port_forwarding_flag); |
|
|
|
|
if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 || |
if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 || |
dup_strings(&ret->permitopen, &ret->npermitopen, |
dup_strings(&ret->permitopen, &ret->npermitopen, |
orig->permitopen, orig->npermitopen) != 0) { |
orig->permitopen, orig->npermitopen) != 0 || |
|
dup_strings(&ret->permitlisten, &ret->npermitlisten, |
|
orig->permitlisten, orig->npermitlisten) != 0) { |
sshauthopt_free(ret); |
sshauthopt_free(ret); |
return NULL; |
return NULL; |
} |
} |
|
|
if ((r = serialise_array(m, opts->env, |
if ((r = serialise_array(m, opts->env, |
untrusted ? 0 : opts->nenv)) != 0 || |
untrusted ? 0 : opts->nenv)) != 0 || |
(r = serialise_array(m, opts->permitopen, |
(r = serialise_array(m, opts->permitopen, |
untrusted ? 0 : opts->npermitopen)) != 0) |
untrusted ? 0 : opts->npermitopen)) || |
|
(r = serialise_array(m, opts->permitlisten, |
|
untrusted ? 0 : opts->npermitlisten)) != 0) |
return r; |
return r; |
|
|
/* success */ |
/* success */ |
|
|
/* Array options */ |
/* Array options */ |
if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 || |
if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 || |
(r = deserialise_array(m, |
(r = deserialise_array(m, |
&opts->permitopen, &opts->npermitopen)) != 0) |
&opts->permitopen, &opts->npermitopen)) != 0 || |
|
(r = deserialise_array(m, |
|
&opts->permitlisten, &opts->npermitlisten)) != 0) |
goto out; |
goto out; |
|
|
/* success */ |
/* success */ |