version 1.105, 2002/10/01 20:34:12 |
version 1.105.2.2, 2003/09/16 21:20:27 |
|
|
#include "authfd.h" |
#include "authfd.h" |
#include "compat.h" |
#include "compat.h" |
#include "log.h" |
#include "log.h" |
|
#include "readpass.h" |
|
#include "misc.h" |
|
|
#ifdef SMARTCARD |
#ifdef SMARTCARD |
#include "scard.h" |
#include "scard.h" |
|
|
Key *key; |
Key *key; |
char *comment; |
char *comment; |
u_int death; |
u_int death; |
|
u_int confirm; |
} Identity; |
} Identity; |
|
|
typedef struct { |
typedef struct { |
|
|
|
|
extern char *__progname; |
extern char *__progname; |
|
|
|
/* Default lifetime (0 == forever) */ |
|
static int lifetime = 0; |
|
|
static void |
static void |
close_socket(SocketEntry *e) |
close_socket(SocketEntry *e) |
{ |
{ |
|
|
return (NULL); |
return (NULL); |
} |
} |
|
|
|
/* Check confirmation of keysign request */ |
|
static int |
|
confirm_key(Identity *id) |
|
{ |
|
char *p, prompt[1024]; |
|
int ret = -1; |
|
|
|
p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); |
|
snprintf(prompt, sizeof(prompt), "Allow use of key %s?\n" |
|
"Key fingerprint %s.", id->comment, p); |
|
xfree(p); |
|
p = read_passphrase(prompt, RP_ALLOW_EOF); |
|
if (p != NULL) { |
|
/* |
|
* Accept empty responses and responses consisting |
|
* of the word "yes" as affirmative. |
|
*/ |
|
if (*p == '\0' || *p == '\n' || strcasecmp(p, "yes") == 0) |
|
ret = 0; |
|
xfree(p); |
|
} |
|
return (ret); |
|
} |
|
|
/* send list of supported public keys to 'client' */ |
/* send list of supported public keys to 'client' */ |
static void |
static void |
process_request_identities(SocketEntry *e, int version) |
process_request_identities(SocketEntry *e, int version) |
|
|
goto failure; |
goto failure; |
|
|
id = lookup_identity(key, 1); |
id = lookup_identity(key, 1); |
if (id != NULL) { |
if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { |
Key *private = id->key; |
Key *private = id->key; |
/* Decrypt the challenge using the private key. */ |
/* Decrypt the challenge using the private key. */ |
if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) |
if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) |
|
|
/* The response is MD5 of decrypted challenge plus session id. */ |
/* The response is MD5 of decrypted challenge plus session id. */ |
len = BN_num_bytes(challenge); |
len = BN_num_bytes(challenge); |
if (len <= 0 || len > 32) { |
if (len <= 0 || len > 32) { |
log("process_authentication_challenge: bad challenge length %d", len); |
logit("process_authentication_challenge: bad challenge length %d", len); |
goto failure; |
goto failure; |
} |
} |
memset(buf, 0, 32); |
memset(buf, 0, 32); |
|
|
key = key_from_blob(blob, blen); |
key = key_from_blob(blob, blen); |
if (key != NULL) { |
if (key != NULL) { |
Identity *id = lookup_identity(key, 2); |
Identity *id = lookup_identity(key, 2); |
if (id != NULL) |
if (id != NULL && (!id->confirm || confirm_key(id) == 0)) |
ok = key_sign(id->key, &signature, &slen, data, dlen); |
ok = key_sign(id->key, &signature, &slen, data, dlen); |
} |
} |
key_free(key); |
key_free(key); |
|
|
buffer_get_bignum(&e->request, key->rsa->n); |
buffer_get_bignum(&e->request, key->rsa->n); |
|
|
if (bits != key_size(key)) |
if (bits != key_size(key)) |
log("Warning: identity keysize mismatch: actual %u, announced %u", |
logit("Warning: identity keysize mismatch: actual %u, announced %u", |
key_size(key), bits); |
key_size(key), bits); |
break; |
break; |
case 2: |
case 2: |
|
|
process_add_identity(SocketEntry *e, int version) |
process_add_identity(SocketEntry *e, int version) |
{ |
{ |
Idtab *tab = idtab_lookup(version); |
Idtab *tab = idtab_lookup(version); |
int type, success = 0, death = 0; |
int type, success = 0, death = 0, confirm = 0; |
char *type_name, *comment; |
char *type_name, *comment; |
Key *k = NULL; |
Key *k = NULL; |
|
|
|
|
} |
} |
break; |
break; |
} |
} |
|
/* enable blinding */ |
|
switch (k->type) { |
|
case KEY_RSA: |
|
case KEY_RSA1: |
|
if (RSA_blinding_on(k->rsa, NULL) != 1) { |
|
error("process_add_identity: RSA_blinding_on failed"); |
|
key_free(k); |
|
goto send; |
|
} |
|
break; |
|
} |
comment = buffer_get_string(&e->request, NULL); |
comment = buffer_get_string(&e->request, NULL); |
if (k == NULL) { |
if (k == NULL) { |
xfree(comment); |
xfree(comment); |
|
|
case SSH_AGENT_CONSTRAIN_LIFETIME: |
case SSH_AGENT_CONSTRAIN_LIFETIME: |
death = time(NULL) + buffer_get_int(&e->request); |
death = time(NULL) + buffer_get_int(&e->request); |
break; |
break; |
|
case SSH_AGENT_CONSTRAIN_CONFIRM: |
|
confirm = 1; |
|
break; |
default: |
default: |
break; |
break; |
} |
} |
} |
} |
|
if (lifetime && !death) |
|
death = time(NULL) + lifetime; |
if (lookup_identity(k, version) == NULL) { |
if (lookup_identity(k, version) == NULL) { |
Identity *id = xmalloc(sizeof(Identity)); |
Identity *id = xmalloc(sizeof(Identity)); |
id->key = k; |
id->key = k; |
id->comment = comment; |
id->comment = comment; |
id->death = death; |
id->death = death; |
|
id->confirm = confirm; |
TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
/* Increment the number of identities. */ |
/* Increment the number of identities. */ |
tab->nentries++; |
tab->nentries++; |
|
|
process_add_smartcard_key (SocketEntry *e) |
process_add_smartcard_key (SocketEntry *e) |
{ |
{ |
char *sc_reader_id = NULL, *pin; |
char *sc_reader_id = NULL, *pin; |
int i, version, success = 0; |
int i, version, success = 0, death = 0, confirm = 0; |
Key **keys, *k; |
Key **keys, *k; |
Identity *id; |
Identity *id; |
Idtab *tab; |
Idtab *tab; |
|
|
sc_reader_id = buffer_get_string(&e->request, NULL); |
sc_reader_id = buffer_get_string(&e->request, NULL); |
pin = buffer_get_string(&e->request, NULL); |
pin = buffer_get_string(&e->request, NULL); |
|
|
|
while (buffer_len(&e->request)) { |
|
switch (buffer_get_char(&e->request)) { |
|
case SSH_AGENT_CONSTRAIN_LIFETIME: |
|
death = time(NULL) + buffer_get_int(&e->request); |
|
break; |
|
case SSH_AGENT_CONSTRAIN_CONFIRM: |
|
confirm = 1; |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
if (lifetime && !death) |
|
death = time(NULL) + lifetime; |
|
|
keys = sc_get_keys(sc_reader_id, pin); |
keys = sc_get_keys(sc_reader_id, pin); |
xfree(sc_reader_id); |
xfree(sc_reader_id); |
xfree(pin); |
xfree(pin); |
|
|
if (lookup_identity(k, version) == NULL) { |
if (lookup_identity(k, version) == NULL) { |
id = xmalloc(sizeof(Identity)); |
id = xmalloc(sizeof(Identity)); |
id->key = k; |
id->key = k; |
id->comment = xstrdup("smartcard key"); |
id->comment = sc_get_key_label(k); |
id->death = 0; |
id->death = death; |
|
id->confirm = confirm; |
TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
tab->nentries++; |
tab->nentries++; |
success = 1; |
success = 1; |
|
|
break; |
break; |
#ifdef SMARTCARD |
#ifdef SMARTCARD |
case SSH_AGENTC_ADD_SMARTCARD_KEY: |
case SSH_AGENTC_ADD_SMARTCARD_KEY: |
|
case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED: |
process_add_smartcard_key(e); |
process_add_smartcard_key(e); |
break; |
break; |
case SSH_AGENTC_REMOVE_SMARTCARD_KEY: |
case SSH_AGENTC_REMOVE_SMARTCARD_KEY: |
|
|
fprintf(stderr, " -k Kill the current agent.\n"); |
fprintf(stderr, " -k Kill the current agent.\n"); |
fprintf(stderr, " -d Debug mode.\n"); |
fprintf(stderr, " -d Debug mode.\n"); |
fprintf(stderr, " -a socket Bind agent socket to given name.\n"); |
fprintf(stderr, " -a socket Bind agent socket to given name.\n"); |
|
fprintf(stderr, " -t life Default identity lifetime (seconds).\n"); |
exit(1); |
exit(1); |
} |
} |
|
|
int |
int |
main(int ac, char **av) |
main(int ac, char **av) |
{ |
{ |
int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc; |
int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0; |
|
int sock, fd, ch, nalloc; |
char *shell, *format, *pidstr, *agentsocket = NULL; |
char *shell, *format, *pidstr, *agentsocket = NULL; |
fd_set *readsetp = NULL, *writesetp = NULL; |
fd_set *readsetp = NULL, *writesetp = NULL; |
struct sockaddr_un sunaddr; |
struct sockaddr_un sunaddr; |
|
|
|
|
SSLeay_add_all_algorithms(); |
SSLeay_add_all_algorithms(); |
|
|
while ((ch = getopt(ac, av, "cdksa:")) != -1) { |
while ((ch = getopt(ac, av, "cdksa:t:")) != -1) { |
switch (ch) { |
switch (ch) { |
case 'c': |
case 'c': |
if (s_flag) |
if (s_flag) |
|
|
case 'a': |
case 'a': |
agentsocket = optarg; |
agentsocket = optarg; |
break; |
break; |
|
case 't': |
|
if ((lifetime = convtime(optarg)) == -1) { |
|
fprintf(stderr, "Invalid lifetime\n"); |
|
usage(); |
|
} |
|
break; |
default: |
default: |
usage(); |
usage(); |
} |
} |
|
|
} |
} |
|
|
(void)chdir("/"); |
(void)chdir("/"); |
close(0); |
if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { |
close(1); |
/* XXX might close listen socket */ |
close(2); |
(void)dup2(fd, STDIN_FILENO); |
|
(void)dup2(fd, STDOUT_FILENO); |
|
(void)dup2(fd, STDERR_FILENO); |
|
if (fd > 2) |
|
close(fd); |
|
} |
|
|
/* deny core dumps, since memory contains unencrypted private keys */ |
/* deny core dumps, since memory contains unencrypted private keys */ |
rlim.rlim_cur = rlim.rlim_max = 0; |
rlim.rlim_cur = rlim.rlim_max = 0; |