version 1.50, 2015/05/21 06:38:35 |
version 1.51, 2015/05/21 06:43:30 |
|
|
} |
} |
|
|
static int |
static int |
match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) |
process_principals(FILE *f, char *file, struct passwd *pw, |
|
struct sshkey_cert *cert) |
{ |
{ |
FILE *f; |
|
char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; |
char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; |
u_long linenum = 0; |
u_long linenum = 0; |
u_int i; |
u_int i; |
|
|
temporarily_use_uid(pw); |
|
debug("trying authorized principals file %s", file); |
|
if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { |
|
restore_uid(); |
|
return 0; |
|
} |
|
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { |
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { |
/* Skip leading whitespace. */ |
/* Skip leading whitespace. */ |
for (cp = line; *cp == ' ' || *cp == '\t'; cp++) |
for (cp = line; *cp == ' ' || *cp == '\t'; cp++) |
|
|
} |
} |
for (i = 0; i < cert->nprincipals; i++) { |
for (i = 0; i < cert->nprincipals; i++) { |
if (strcmp(cp, cert->principals[i]) == 0) { |
if (strcmp(cp, cert->principals[i]) == 0) { |
debug3("matched principal \"%.100s\" " |
debug3("%s:%lu: matched principal \"%.100s\"", |
"from file \"%s\" on line %lu", |
file == NULL ? "(command)" : file, |
cert->principals[i], file, linenum); |
linenum, cert->principals[i]); |
if (auth_parse_options(pw, line_opts, |
if (auth_parse_options(pw, line_opts, |
file, linenum) != 1) |
file, linenum) != 1) |
continue; |
continue; |
fclose(f); |
|
restore_uid(); |
|
return 1; |
return 1; |
} |
} |
} |
} |
} |
} |
|
return 0; |
|
} |
|
|
|
static int |
|
match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) |
|
{ |
|
FILE *f; |
|
int success; |
|
|
|
temporarily_use_uid(pw); |
|
debug("trying authorized principals file %s", file); |
|
if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { |
|
restore_uid(); |
|
return 0; |
|
} |
|
success = process_principals(f, file, pw, cert); |
fclose(f); |
fclose(f); |
restore_uid(); |
restore_uid(); |
return 0; |
return success; |
} |
} |
|
|
/* |
/* |
|
* Checks whether principal is allowed in output of command. |
|
* returns 1 if the principal is allowed or 0 otherwise. |
|
*/ |
|
static int |
|
match_principals_command(struct passwd *user_pw, struct sshkey *key) |
|
{ |
|
FILE *f = NULL; |
|
int ok, found_principal = 0; |
|
struct passwd *pw; |
|
int i, ac = 0, uid_swapped = 0; |
|
pid_t pid; |
|
char *tmp, *username = NULL, *command = NULL, **av = NULL; |
|
void (*osigchld)(int); |
|
|
|
if (options.authorized_principals_command == NULL) |
|
return 0; |
|
if (options.authorized_principals_command_user == NULL) { |
|
error("No user for AuthorizedPrincipalsCommand specified, " |
|
"skipping"); |
|
return 0; |
|
} |
|
|
|
/* |
|
* NB. all returns later this function should go via "out" to |
|
* ensure the original SIGCHLD handler is restored properly. |
|
*/ |
|
osigchld = signal(SIGCHLD, SIG_DFL); |
|
|
|
/* Prepare and verify the user for the command */ |
|
username = percent_expand(options.authorized_principals_command_user, |
|
"u", user_pw->pw_name, (char *)NULL); |
|
pw = getpwnam(username); |
|
if (pw == NULL) { |
|
error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", |
|
username, strerror(errno)); |
|
goto out; |
|
} |
|
|
|
/* Turn the command into an argument vector */ |
|
if (split_argv(options.authorized_principals_command, &ac, &av) != 0) { |
|
error("AuthorizedPrincipalsCommand \"%s\" contains " |
|
"invalid quotes", command); |
|
goto out; |
|
} |
|
if (ac == 0) { |
|
error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", |
|
command); |
|
goto out; |
|
} |
|
for (i = 1; i < ac; i++) { |
|
tmp = percent_expand(av[i], |
|
"u", user_pw->pw_name, |
|
"h", user_pw->pw_dir, |
|
(char *)NULL); |
|
if (tmp == NULL) |
|
fatal("%s: percent_expand failed", __func__); |
|
free(av[i]); |
|
av[i] = tmp; |
|
} |
|
/* Prepare a printable command for logs, etc. */ |
|
command = assemble_argv(ac, av); |
|
|
|
if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, |
|
ac, av, &f)) == 0) |
|
goto out; |
|
|
|
uid_swapped = 1; |
|
temporarily_use_uid(pw); |
|
|
|
ok = process_principals(f, NULL, pw, key->cert); |
|
|
|
if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0) |
|
goto out; |
|
|
|
/* Read completed successfully */ |
|
found_principal = ok; |
|
out: |
|
if (f != NULL) |
|
fclose(f); |
|
signal(SIGCHLD, osigchld); |
|
for (i = 0; i < ac; i++) |
|
free(av[i]); |
|
free(av); |
|
if (uid_swapped) |
|
restore_uid(); |
|
free(command); |
|
free(username); |
|
return found_principal; |
|
} |
|
/* |
* Checks whether key is allowed in authorized_keys-format file, |
* Checks whether key is allowed in authorized_keys-format file, |
* returns 1 if the key is allowed or 0 otherwise. |
* returns 1 if the key is allowed or 0 otherwise. |
*/ |
*/ |
|
|
{ |
{ |
char *ca_fp, *principals_file = NULL; |
char *ca_fp, *principals_file = NULL; |
const char *reason; |
const char *reason; |
int ret = 0; |
int ret = 0, found_principal = 0; |
|
|
if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) |
if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) |
return 0; |
return 0; |
|
|
* against the username. |
* against the username. |
*/ |
*/ |
if ((principals_file = authorized_principals_file(pw)) != NULL) { |
if ((principals_file = authorized_principals_file(pw)) != NULL) { |
if (!match_principals_file(principals_file, pw, key->cert)) { |
if (match_principals_file(principals_file, pw, key->cert)) |
reason = "Certificate does not contain an " |
found_principal = 1; |
"authorized principal"; |
} |
|
/* Try querying command if specified */ |
|
if (!found_principal && match_principals_command(pw, key)) |
|
found_principal = 1; |
|
/* If principals file or command specify, then require a match here */ |
|
if (!found_principal && (principals_file != NULL || |
|
options.authorized_principals_command != NULL)) { |
|
reason = "Certificate does not contain an authorized principal"; |
fail_reason: |
fail_reason: |
error("%s", reason); |
error("%s", reason); |
auth_debug_add("%s", reason); |
auth_debug_add("%s", reason); |
goto out; |
goto out; |
} |
|
} |
} |
if (key_cert_check_authority(key, 0, 1, |
if (key_cert_check_authority(key, 0, 1, |
principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) |
principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) |