version 1.11, 1999/11/22 21:02:38 |
version 1.12, 1999/11/23 22:25:52 |
|
|
/* The .ssh/authorized_keys file contains public keys, one per line, in the |
/* The .ssh/authorized_keys file contains public keys, one per line, in the |
following format: |
following format: |
options bits e n comment |
options bits e n comment |
where bits, e and n are decimal numbers, |
where bits, e and n are decimal numbers, |
and comment is any string of characters up to newline. The maximum |
and comment is any string of characters up to newline. The maximum |
length of a line is 8000 characters. See the documentation for a |
length of a line is 8000 characters. See the documentation for a |
description of the options. |
description of the options. |
|
|
int |
int |
auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n) |
auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n) |
{ |
{ |
BIGNUM *challenge, *encrypted_challenge, *aux; |
BIGNUM *challenge, *encrypted_challenge, *aux; |
RSA *pk; |
RSA *pk; |
BN_CTX *ctx = BN_CTX_new(); |
BN_CTX *ctx = BN_CTX_new(); |
unsigned char buf[32], mdbuf[16], response[16]; |
unsigned char buf[32], mdbuf[16], response[16]; |
MD5_CTX md; |
MD5_CTX md; |
unsigned int i; |
unsigned int i; |
int plen, len; |
int plen, len; |
|
|
encrypted_challenge = BN_new(); |
encrypted_challenge = BN_new(); |
challenge = BN_new(); |
challenge = BN_new(); |
aux = BN_new(); |
aux = BN_new(); |
|
|
/* Generate a random challenge. */ |
/* Generate a random challenge. */ |
BN_rand(challenge, 256, 0, 0); |
BN_rand(challenge, 256, 0, 0); |
BN_mod(challenge, challenge, n, ctx); |
BN_mod(challenge, challenge, n, ctx); |
|
|
/* Create the public key data structure. */ |
|
pk = RSA_new(); |
|
pk->e = BN_new(); |
|
BN_copy(pk->e, e); |
|
pk->n = BN_new(); |
|
BN_copy(pk->n, n); |
|
|
|
/* Encrypt the challenge with the public key. */ |
/* Create the public key data structure. */ |
rsa_public_encrypt(encrypted_challenge, challenge, pk); |
pk = RSA_new(); |
RSA_free(pk); |
pk->e = BN_new(); |
|
BN_copy(pk->e, e); |
|
pk->n = BN_new(); |
|
BN_copy(pk->n, n); |
|
|
/* Send the encrypted challenge to the client. */ |
/* Encrypt the challenge with the public key. */ |
packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); |
rsa_public_encrypt(encrypted_challenge, challenge, pk); |
packet_put_bignum(encrypted_challenge); |
RSA_free(pk); |
packet_send(); |
|
packet_write_wait(); |
|
|
|
/* The response is MD5 of decrypted challenge plus session id. */ |
/* Send the encrypted challenge to the client. */ |
len = BN_num_bytes(challenge); |
packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); |
if (len <= 0 || len > 32) |
packet_put_bignum(encrypted_challenge); |
fatal("auth_rsa_challenge_dialog: bad challenge length %d", len); |
packet_send(); |
memset(buf, 0, 32); |
packet_write_wait(); |
BN_bn2bin(challenge, buf + 32 - len); |
|
MD5_Init(&md); |
|
MD5_Update(&md, buf, 32); |
|
MD5_Update(&md, session_id, 16); |
|
MD5_Final(mdbuf, &md); |
|
|
|
/* We will no longer need these. */ |
/* The response is MD5 of decrypted challenge plus session id. */ |
BN_clear_free(encrypted_challenge); |
len = BN_num_bytes(challenge); |
BN_clear_free(challenge); |
if (len <= 0 || len > 32) |
BN_clear_free(aux); |
fatal("auth_rsa_challenge_dialog: bad challenge length %d", len); |
BN_CTX_free(ctx); |
memset(buf, 0, 32); |
|
BN_bn2bin(challenge, buf + 32 - len); |
/* Wait for a response. */ |
MD5_Init(&md); |
packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE); |
MD5_Update(&md, buf, 32); |
packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE); |
MD5_Update(&md, session_id, 16); |
for (i = 0; i < 16; i++) |
MD5_Final(mdbuf, &md); |
response[i] = packet_get_char(); |
|
|
|
/* Verify that the response is the original challenge. */ |
/* We will no longer need these. */ |
if (memcmp(response, mdbuf, 16) != 0) |
BN_clear_free(encrypted_challenge); |
{ |
BN_clear_free(challenge); |
/* Wrong answer. */ |
BN_clear_free(aux); |
return 0; |
BN_CTX_free(ctx); |
} |
|
|
|
/* Correct answer. */ |
/* Wait for a response. */ |
return 1; |
packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE); |
|
packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE); |
|
for (i = 0; i < 16; i++) |
|
response[i] = packet_get_char(); |
|
|
|
/* Verify that the response is the original challenge. */ |
|
if (memcmp(response, mdbuf, 16) != 0) { |
|
/* Wrong answer. */ |
|
return 0; |
|
} |
|
/* Correct answer. */ |
|
return 1; |
} |
} |
|
|
/* Performs the RSA authentication dialog with the client. This returns |
/* Performs the RSA authentication dialog with the client. This returns |
|
|
int |
int |
auth_rsa(struct passwd *pw, BIGNUM *client_n) |
auth_rsa(struct passwd *pw, BIGNUM *client_n) |
{ |
{ |
extern ServerOptions options; |
extern ServerOptions options; |
char line[8192], file[1024]; |
char line[8192], file[1024]; |
int authenticated; |
int authenticated; |
unsigned int bits; |
unsigned int bits; |
FILE *f; |
FILE *f; |
unsigned long linenum = 0; |
unsigned long linenum = 0; |
struct stat st; |
struct stat st; |
BIGNUM *e, *n; |
BIGNUM *e, *n; |
|
|
/* Temporarily use the user's uid. */ |
/* Temporarily use the user's uid. */ |
temporarily_use_uid(pw->pw_uid); |
temporarily_use_uid(pw->pw_uid); |
|
|
/* The authorized keys. */ |
/* The authorized keys. */ |
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, |
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, |
SSH_USER_PERMITTED_KEYS); |
SSH_USER_PERMITTED_KEYS); |
|
|
/* Fail quietly if file does not exist */ |
|
if (stat(file, &st) < 0) |
|
{ |
|
/* Restore the privileged uid. */ |
|
restore_uid(); |
|
return 0; |
|
} |
|
|
|
/* Open the file containing the authorized keys. */ |
/* Fail quietly if file does not exist */ |
f = fopen(file, "r"); |
if (stat(file, &st) < 0) { |
if (!f) |
/* Restore the privileged uid. */ |
{ |
restore_uid(); |
/* Restore the privileged uid. */ |
return 0; |
restore_uid(); |
} |
packet_send_debug("Could not open %.900s for reading.", file); |
/* Open the file containing the authorized keys. */ |
packet_send_debug("If your home is on an NFS volume, it may need to be world-readable."); |
f = fopen(file, "r"); |
return 0; |
if (!f) { |
} |
/* Restore the privileged uid. */ |
|
restore_uid(); |
|
packet_send_debug("Could not open %.900s for reading.", file); |
|
packet_send_debug("If your home is on an NFS volume, it may need to be world-readable."); |
|
return 0; |
|
} |
|
if (options.strict_modes) { |
|
int fail = 0; |
|
char buf[1024]; |
|
/* Check open file in order to avoid open/stat races */ |
|
if (fstat(fileno(f), &st) < 0 || |
|
(st.st_uid != 0 && st.st_uid != pw->pw_uid) || |
|
(st.st_mode & 022) != 0) { |
|
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: " |
|
"bad ownership or modes for '%s'.", pw->pw_name, file); |
|
fail = 1; |
|
} else { |
|
/* Check path to SSH_USER_PERMITTED_KEYS */ |
|
int i; |
|
static const char *check[] = { |
|
"", SSH_USER_DIR, NULL |
|
}; |
|
for (i = 0; check[i]; i++) { |
|
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]); |
|
if (stat(line, &st) < 0 || |
|
(st.st_uid != 0 && st.st_uid != pw->pw_uid) || |
|
(st.st_mode & 022) != 0) { |
|
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: " |
|
"bad ownership or modes for '%s'.", pw->pw_name, line); |
|
fail = 1; |
|
break; |
|
} |
|
} |
|
} |
|
if (fail) { |
|
log(buf); |
|
packet_send_debug(buf); |
|
restore_uid(); |
|
return 0; |
|
} |
|
} |
|
/* Flag indicating whether authentication has succeeded. */ |
|
authenticated = 0; |
|
|
if (options.strict_modes) { |
/* Initialize mp-int variables. */ |
int fail=0; |
e = BN_new(); |
char buf[1024]; |
n = BN_new(); |
/* Check open file in order to avoid open/stat races */ |
|
if (fstat(fileno(f), &st) < 0 || |
|
(st.st_uid != 0 && st.st_uid != pw->pw_uid) || |
|
(st.st_mode & 022) != 0) { |
|
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: " |
|
"bad ownership or modes for '%s'.", pw->pw_name, file); |
|
fail=1; |
|
}else{ |
|
/* Check path to SSH_USER_PERMITTED_KEYS */ |
|
int i; |
|
static const char *check[] = { |
|
"", SSH_USER_DIR, NULL |
|
}; |
|
for (i=0; check[i]; i++) { |
|
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]); |
|
if (stat(line, &st) < 0 || |
|
(st.st_uid != 0 && st.st_uid != pw->pw_uid) || |
|
(st.st_mode & 022) != 0) { |
|
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: " |
|
"bad ownership or modes for '%s'.", pw->pw_name, line); |
|
fail=1; |
|
break; |
|
} |
|
} |
|
} |
|
if (fail) { |
|
log(buf); |
|
packet_send_debug(buf); |
|
restore_uid(); |
|
return 0; |
|
} |
|
} |
|
|
|
/* Flag indicating whether authentication has succeeded. */ |
/* Go though the accepted keys, looking for the current key. If |
authenticated = 0; |
found, perform a challenge-response dialog to verify that the |
|
user really has the corresponding private key. */ |
/* Initialize mp-int variables. */ |
while (fgets(line, sizeof(line), f)) { |
e = BN_new(); |
char *cp; |
n = BN_new(); |
char *options; |
|
|
/* Go though the accepted keys, looking for the current key. If found, |
linenum++; |
perform a challenge-response dialog to verify that the user really has |
|
the corresponding private key. */ |
|
while (fgets(line, sizeof(line), f)) |
|
{ |
|
char *cp; |
|
char *options; |
|
|
|
linenum++; |
/* Skip leading whitespace. */ |
|
for (cp = line; *cp == ' ' || *cp == '\t'; cp++); |
|
|
/* Skip leading whitespace. */ |
/* Skip empty and comment lines. */ |
for (cp = line; *cp == ' ' || *cp == '\t'; cp++) |
if (!*cp || *cp == '\n' || *cp == '#') |
; |
continue; |
|
|
/* Skip empty and comment lines. */ |
/* Check if there are options for this key, and if so, |
if (!*cp || *cp == '\n' || *cp == '#') |
save their starting address and skip the option part |
continue; |
for now. If there are no options, set the starting |
|
address to NULL. */ |
|
if (*cp < '0' || *cp > '9') { |
|
int quoted = 0; |
|
options = cp; |
|
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { |
|
if (*cp == '\\' && cp[1] == '"') |
|
cp++; /* Skip both */ |
|
else if (*cp == '"') |
|
quoted = !quoted; |
|
} |
|
} else |
|
options = NULL; |
|
|
/* Check if there are options for this key, and if so, save their |
/* Parse the key from the line. */ |
starting address and skip the option part for now. If there are no |
if (!auth_rsa_read_key(&cp, &bits, e, n)) { |
options, set the starting address to NULL. */ |
debug("%.100s, line %lu: bad key syntax", |
if (*cp < '0' || *cp > '9') |
SSH_USER_PERMITTED_KEYS, linenum); |
{ |
packet_send_debug("%.100s, line %lu: bad key syntax", |
int quoted = 0; |
SSH_USER_PERMITTED_KEYS, linenum); |
options = cp; |
continue; |
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) |
} |
{ |
/* cp now points to the comment part. */ |
if (*cp == '\\' && cp[1] == '"') |
|
cp++; /* Skip both */ |
|
else |
|
if (*cp == '"') |
|
quoted = !quoted; |
|
} |
|
} |
|
else |
|
options = NULL; |
|
|
|
/* Parse the key from the line. */ |
|
if (!auth_rsa_read_key(&cp, &bits, e, n)) |
|
{ |
|
debug("%.100s, line %lu: bad key syntax", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
packet_send_debug("%.100s, line %lu: bad key syntax", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
continue; |
|
} |
|
/* cp now points to the comment part. */ |
|
|
|
/* check the real bits */ |
/* check the real bits */ |
if (bits != BN_num_bits(n)) |
if (bits != BN_num_bits(n)) |
error("Warning: error in %s, line %ld: keysize mismatch: " |
error("Warning: error in %s, line %ld: keysize mismatch: " |
"actual size %d vs. announced %d.", |
"actual size %d vs. announced %d.", |
file, linenum, BN_num_bits(n), bits); |
file, linenum, BN_num_bits(n), bits); |
|
|
/* Check if the we have found the desired key (identified by its |
/* Check if the we have found the desired key (identified by its modulus). */ |
modulus). */ |
if (BN_cmp(n, client_n) != 0) |
if (BN_cmp(n, client_n) != 0) |
continue; /* Wrong key. */ |
continue; /* Wrong key. */ |
|
|
|
/* We have found the desired key. */ |
/* We have found the desired key. */ |
|
|
/* Perform the challenge-response dialog for this key. */ |
/* Perform the challenge-response dialog for this key. */ |
if (!auth_rsa_challenge_dialog(e, n)) |
if (!auth_rsa_challenge_dialog(e, n)) { |
{ |
/* Wrong response. */ |
/* Wrong response. */ |
verbose("Wrong response to RSA authentication challenge."); |
verbose("Wrong response to RSA authentication challenge."); |
packet_send_debug("Wrong response to RSA authentication challenge."); |
packet_send_debug("Wrong response to RSA authentication challenge."); |
continue; |
continue; |
} |
} |
/* Correct response. The client has been successfully |
|
authenticated. Note that we have not yet processed the |
|
options; this will be reset if the options cause the |
|
authentication to be rejected. */ |
|
authenticated = 1; |
|
|
/* Correct response. The client has been successfully authenticated. |
/* RSA part of authentication was accepted. Now process the options. */ |
Note that we have not yet processed the options; this will be reset |
if (options) { |
if the options cause the authentication to be rejected. */ |
while (*options && *options != ' ' && *options != '\t') { |
authenticated = 1; |
cp = "no-port-forwarding"; |
|
if (strncmp(options, cp, strlen(cp)) == 0) { |
|
packet_send_debug("Port forwarding disabled."); |
|
no_port_forwarding_flag = 1; |
|
options += strlen(cp); |
|
goto next_option; |
|
} |
|
cp = "no-agent-forwarding"; |
|
if (strncmp(options, cp, strlen(cp)) == 0) { |
|
packet_send_debug("Agent forwarding disabled."); |
|
no_agent_forwarding_flag = 1; |
|
options += strlen(cp); |
|
goto next_option; |
|
} |
|
cp = "no-X11-forwarding"; |
|
if (strncmp(options, cp, strlen(cp)) == 0) { |
|
packet_send_debug("X11 forwarding disabled."); |
|
no_x11_forwarding_flag = 1; |
|
options += strlen(cp); |
|
goto next_option; |
|
} |
|
cp = "no-pty"; |
|
if (strncmp(options, cp, strlen(cp)) == 0) { |
|
packet_send_debug("Pty allocation disabled."); |
|
no_pty_flag = 1; |
|
options += strlen(cp); |
|
goto next_option; |
|
} |
|
cp = "command=\""; |
|
if (strncmp(options, cp, strlen(cp)) == 0) { |
|
int i; |
|
options += strlen(cp); |
|
forced_command = xmalloc(strlen(options) + 1); |
|
i = 0; |
|
while (*options) { |
|
if (*options == '"') |
|
break; |
|
if (*options == '\\' && options[1] == '"') { |
|
options += 2; |
|
forced_command[i++] = '"'; |
|
continue; |
|
} |
|
forced_command[i++] = *options++; |
|
} |
|
if (!*options) { |
|
debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
packet_send_debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
continue; |
|
} |
|
forced_command[i] = 0; |
|
packet_send_debug("Forced command: %.900s", forced_command); |
|
options++; |
|
goto next_option; |
|
} |
|
cp = "environment=\""; |
|
if (strncmp(options, cp, strlen(cp)) == 0) { |
|
int i; |
|
char *s; |
|
struct envstring *new_envstring; |
|
options += strlen(cp); |
|
s = xmalloc(strlen(options) + 1); |
|
i = 0; |
|
while (*options) { |
|
if (*options == '"') |
|
break; |
|
if (*options == '\\' && options[1] == '"') { |
|
options += 2; |
|
s[i++] = '"'; |
|
continue; |
|
} |
|
s[i++] = *options++; |
|
} |
|
if (!*options) { |
|
debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
packet_send_debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
continue; |
|
} |
|
s[i] = 0; |
|
packet_send_debug("Adding to environment: %.900s", s); |
|
debug("Adding to environment: %.900s", s); |
|
options++; |
|
new_envstring = xmalloc(sizeof(struct envstring)); |
|
new_envstring->s = s; |
|
new_envstring->next = custom_environment; |
|
custom_environment = new_envstring; |
|
goto next_option; |
|
} |
|
cp = "from=\""; |
|
if (strncmp(options, cp, strlen(cp)) == 0) { |
|
char *patterns = xmalloc(strlen(options) + 1); |
|
int i; |
|
options += strlen(cp); |
|
i = 0; |
|
while (*options) { |
|
if (*options == '"') |
|
break; |
|
if (*options == '\\' && options[1] == '"') { |
|
options += 2; |
|
patterns[i++] = '"'; |
|
continue; |
|
} |
|
patterns[i++] = *options++; |
|
} |
|
if (!*options) { |
|
debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
packet_send_debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
continue; |
|
} |
|
patterns[i] = 0; |
|
options++; |
|
if (!match_hostname(get_canonical_hostname(), patterns, |
|
strlen(patterns)) && |
|
!match_hostname(get_remote_ipaddr(), patterns, |
|
strlen(patterns))) { |
|
log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", |
|
pw->pw_name, get_canonical_hostname(), |
|
get_remote_ipaddr()); |
|
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", |
|
get_canonical_hostname()); |
|
xfree(patterns); |
|
authenticated = 0; |
|
break; |
|
} |
|
xfree(patterns); |
|
/* Host name matches. */ |
|
goto next_option; |
|
} |
|
bad_option: |
|
/* Unknown option. */ |
|
log("Bad options in %.100s file, line %lu: %.50s", |
|
SSH_USER_PERMITTED_KEYS, linenum, options); |
|
packet_send_debug("Bad options in %.100s file, line %lu: %.50s", |
|
SSH_USER_PERMITTED_KEYS, linenum, options); |
|
authenticated = 0; |
|
break; |
|
|
/* RSA part of authentication was accepted. Now process the options. */ |
next_option: |
if (options) |
/* Skip the comma, and move to the next option |
{ |
(or break out if there are no more). */ |
while (*options && *options != ' ' && *options != '\t') |
if (!*options) |
{ |
fatal("Bugs in auth-rsa.c option processing."); |
cp = "no-port-forwarding"; |
if (*options == ' ' || *options == '\t') |
if (strncmp(options, cp, strlen(cp)) == 0) |
break; /* End of options. */ |
{ |
if (*options != ',') |
packet_send_debug("Port forwarding disabled."); |
goto bad_option; |
no_port_forwarding_flag = 1; |
options++; |
options += strlen(cp); |
/* Process the next option. */ |
goto next_option; |
continue; |
} |
|
cp = "no-agent-forwarding"; |
|
if (strncmp(options, cp, strlen(cp)) == 0) |
|
{ |
|
packet_send_debug("Agent forwarding disabled."); |
|
no_agent_forwarding_flag = 1; |
|
options += strlen(cp); |
|
goto next_option; |
|
} |
|
cp = "no-X11-forwarding"; |
|
if (strncmp(options, cp, strlen(cp)) == 0) |
|
{ |
|
packet_send_debug("X11 forwarding disabled."); |
|
no_x11_forwarding_flag = 1; |
|
options += strlen(cp); |
|
goto next_option; |
|
} |
|
cp = "no-pty"; |
|
if (strncmp(options, cp, strlen(cp)) == 0) |
|
{ |
|
packet_send_debug("Pty allocation disabled."); |
|
no_pty_flag = 1; |
|
options += strlen(cp); |
|
goto next_option; |
|
} |
|
cp = "command=\""; |
|
if (strncmp(options, cp, strlen(cp)) == 0) |
|
{ |
|
int i; |
|
options += strlen(cp); |
|
forced_command = xmalloc(strlen(options) + 1); |
|
i = 0; |
|
while (*options) |
|
{ |
|
if (*options == '"') |
|
break; |
|
if (*options == '\\' && options[1] == '"') |
|
{ |
|
options += 2; |
|
forced_command[i++] = '"'; |
|
continue; |
|
} |
} |
forced_command[i++] = *options++; |
|
} |
|
if (!*options) |
|
{ |
|
debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
packet_send_debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
continue; |
|
} |
|
forced_command[i] = 0; |
|
packet_send_debug("Forced command: %.900s", forced_command); |
|
options++; |
|
goto next_option; |
|
} |
} |
cp = "environment=\""; |
/* Break out of the loop if authentication was successful; |
if (strncmp(options, cp, strlen(cp)) == 0) |
otherwise continue searching. */ |
{ |
if (authenticated) |
int i; |
|
char *s; |
|
struct envstring *new_envstring; |
|
options += strlen(cp); |
|
s = xmalloc(strlen(options) + 1); |
|
i = 0; |
|
while (*options) |
|
{ |
|
if (*options == '"') |
|
break; |
break; |
if (*options == '\\' && options[1] == '"') |
|
{ |
|
options += 2; |
|
s[i++] = '"'; |
|
continue; |
|
} |
|
s[i++] = *options++; |
|
} |
|
if (!*options) |
|
{ |
|
debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
packet_send_debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
continue; |
|
} |
|
s[i] = 0; |
|
packet_send_debug("Adding to environment: %.900s", s); |
|
debug("Adding to environment: %.900s", s); |
|
options++; |
|
new_envstring = xmalloc(sizeof(struct envstring)); |
|
new_envstring->s = s; |
|
new_envstring->next = custom_environment; |
|
custom_environment = new_envstring; |
|
goto next_option; |
|
} |
|
cp = "from=\""; |
|
if (strncmp(options, cp, strlen(cp)) == 0) |
|
{ |
|
char *patterns = xmalloc(strlen(options) + 1); |
|
int i; |
|
options += strlen(cp); |
|
i = 0; |
|
while (*options) |
|
{ |
|
if (*options == '"') |
|
break; |
|
if (*options == '\\' && options[1] == '"') |
|
{ |
|
options += 2; |
|
patterns[i++] = '"'; |
|
continue; |
|
} |
|
patterns[i++] = *options++; |
|
} |
|
if (!*options) |
|
{ |
|
debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
packet_send_debug("%.100s, line %lu: missing end quote", |
|
SSH_USER_PERMITTED_KEYS, linenum); |
|
continue; |
|
} |
|
patterns[i] = 0; |
|
options++; |
|
if (!match_hostname(get_canonical_hostname(), patterns, |
|
strlen(patterns)) && |
|
!match_hostname(get_remote_ipaddr(), patterns, |
|
strlen(patterns))) |
|
{ |
|
log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", |
|
pw->pw_name, get_canonical_hostname(), |
|
get_remote_ipaddr()); |
|
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", |
|
get_canonical_hostname()); |
|
xfree(patterns); |
|
authenticated = 0; |
|
break; |
|
} |
|
xfree(patterns); |
|
/* Host name matches. */ |
|
goto next_option; |
|
} |
|
bad_option: |
|
/* Unknown option. */ |
|
log("Bad options in %.100s file, line %lu: %.50s", |
|
SSH_USER_PERMITTED_KEYS, linenum, options); |
|
packet_send_debug("Bad options in %.100s file, line %lu: %.50s", |
|
SSH_USER_PERMITTED_KEYS, linenum, options); |
|
authenticated = 0; |
|
break; |
|
|
|
next_option: |
|
/* Skip the comma, and move to the next option (or break out |
|
if there are no more). */ |
|
if (!*options) |
|
fatal("Bugs in auth-rsa.c option processing."); |
|
if (*options == ' ' || *options == '\t') |
|
break; /* End of options. */ |
|
if (*options != ',') |
|
goto bad_option; |
|
options++; |
|
/* Process the next option. */ |
|
continue; |
|
} |
|
} |
} |
|
|
/* Break out of the loop if authentication was successful; otherwise |
/* Restore the privileged uid. */ |
continue searching. */ |
restore_uid(); |
if (authenticated) |
|
break; |
|
} |
|
|
|
/* Restore the privileged uid. */ |
/* Close the file. */ |
restore_uid(); |
fclose(f); |
|
|
/* Close the file. */ |
/* Clear any mp-int variables. */ |
fclose(f); |
BN_clear_free(n); |
|
BN_clear_free(e); |
/* Clear any mp-int variables. */ |
|
BN_clear_free(n); |
|
BN_clear_free(e); |
|
|
|
if (authenticated) |
if (authenticated) |
packet_send_debug("RSA authentication accepted."); |
packet_send_debug("RSA authentication accepted."); |
|
|
/* Return authentication result. */ |
/* Return authentication result. */ |
return authenticated; |
return authenticated; |
} |
} |