version 1.31.2.2, 2000/11/08 21:31:21 |
version 1.31.2.3, 2001/03/12 15:44:15 |
|
|
#include "includes.h" |
#include "includes.h" |
RCSID("$OpenBSD$"); |
RCSID("$OpenBSD$"); |
|
|
|
#include <openssl/evp.h> |
|
#include <openssl/md5.h> |
|
|
#include "ssh.h" |
#include "ssh.h" |
#include "rsa.h" |
#include "rsa.h" |
#include "buffer.h" |
#include "buffer.h" |
|
|
#include "packet.h" |
#include "packet.h" |
#include "getput.h" |
#include "getput.h" |
#include "mpaux.h" |
#include "mpaux.h" |
|
|
#include <openssl/evp.h> |
|
#include <openssl/md5.h> |
|
#include <openssl/dsa.h> |
|
#include <openssl/rsa.h> |
|
#include "key.h" |
#include "key.h" |
#include "authfd.h" |
#include "authfd.h" |
#include "dsa.h" |
#include "cipher.h" |
#include "kex.h" |
#include "kex.h" |
#include "compat.h" |
#include "compat.h" |
|
#include "log.h" |
|
|
typedef struct { |
typedef struct { |
int fd; |
int fd; |
|
|
Buffer output; |
Buffer output; |
} SocketEntry; |
} SocketEntry; |
|
|
unsigned int sockets_alloc = 0; |
u_int sockets_alloc = 0; |
SocketEntry *sockets = NULL; |
SocketEntry *sockets = NULL; |
|
|
typedef struct { |
typedef struct { |
|
|
|
|
extern char *__progname; |
extern char *__progname; |
|
|
|
int prepare_select(fd_set **, fd_set **, int *); |
|
|
void |
void |
idtab_init(void) |
idtab_init(void) |
{ |
{ |
|
|
buffer_put_int(&msg, tab->nentries); |
buffer_put_int(&msg, tab->nentries); |
for (i = 0; i < tab->nentries; i++) { |
for (i = 0; i < tab->nentries; i++) { |
Identity *id = &tab->identities[i]; |
Identity *id = &tab->identities[i]; |
if (id->key->type == KEY_RSA) { |
if (id->key->type == KEY_RSA1) { |
buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); |
buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); |
buffer_put_bignum(&msg, id->key->rsa->e); |
buffer_put_bignum(&msg, id->key->rsa->e); |
buffer_put_bignum(&msg, id->key->rsa->n); |
buffer_put_bignum(&msg, id->key->rsa->n); |
} else { |
} else { |
unsigned char *blob; |
u_char *blob; |
unsigned int blen; |
u_int blen; |
dsa_make_key_blob(id->key, &blob, &blen); |
key_to_blob(id->key, &blob, &blen); |
buffer_put_string(&msg, blob, blen); |
buffer_put_string(&msg, blob, blen); |
xfree(blob); |
xfree(blob); |
} |
} |
|
|
int i, len; |
int i, len; |
Buffer msg; |
Buffer msg; |
MD5_CTX md; |
MD5_CTX md; |
unsigned char buf[32], mdbuf[16], session_id[16]; |
u_char buf[32], mdbuf[16], session_id[16]; |
unsigned int response_type; |
u_int response_type; |
|
|
buffer_init(&msg); |
buffer_init(&msg); |
key = key_new(KEY_RSA); |
key = key_new(KEY_RSA1); |
challenge = BN_new(); |
challenge = BN_new(); |
|
|
buffer_get_int(&e->input); /* ignored */ |
buffer_get_int(&e->input); /* ignored */ |
|
|
private = lookup_private_key(key, NULL, 1); |
private = lookup_private_key(key, NULL, 1); |
if (private != NULL) { |
if (private != NULL) { |
/* Decrypt the challenge using the private key. */ |
/* Decrypt the challenge using the private key. */ |
rsa_private_decrypt(challenge, challenge, private->rsa); |
if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) |
|
goto failure; |
|
|
/* 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); |
|
|
{ |
{ |
extern int datafellows; |
extern int datafellows; |
Key *key, *private; |
Key *key, *private; |
unsigned char *blob, *data, *signature = NULL; |
u_char *blob, *data, *signature = NULL; |
unsigned int blen, dlen, slen = 0; |
u_int blen, dlen, slen = 0; |
int flags; |
int flags; |
Buffer msg; |
Buffer msg; |
int ok = -1; |
int ok = -1; |
|
|
datafellows = 0; |
datafellows = 0; |
|
|
blob = buffer_get_string(&e->input, &blen); |
blob = buffer_get_string(&e->input, &blen); |
data = buffer_get_string(&e->input, &dlen); |
data = buffer_get_string(&e->input, &dlen); |
|
|
|
|
if (flags & SSH_AGENT_OLD_SIGNATURE) |
if (flags & SSH_AGENT_OLD_SIGNATURE) |
datafellows = SSH_BUG_SIGBLOB; |
datafellows = SSH_BUG_SIGBLOB; |
|
|
key = dsa_key_from_blob(blob, blen); |
key = key_from_blob(blob, blen); |
if (key != NULL) { |
if (key != NULL) { |
private = lookup_private_key(key, NULL, 2); |
private = lookup_private_key(key, NULL, 2); |
if (private != NULL) |
if (private != NULL) |
ok = dsa_sign(private, &signature, &slen, data, dlen); |
ok = key_sign(private, &signature, &slen, data, dlen); |
} |
} |
key_free(key); |
key_free(key); |
buffer_init(&msg); |
buffer_init(&msg); |
|
|
process_remove_identity(SocketEntry *e, int version) |
process_remove_identity(SocketEntry *e, int version) |
{ |
{ |
Key *key = NULL, *private; |
Key *key = NULL, *private; |
unsigned char *blob; |
u_char *blob; |
unsigned int blen; |
u_int blen; |
unsigned int bits; |
u_int bits; |
int success = 0; |
int success = 0; |
|
|
switch(version){ |
switch(version){ |
case 1: |
case 1: |
key = key_new(KEY_RSA); |
key = key_new(KEY_RSA1); |
bits = buffer_get_int(&e->input); |
bits = buffer_get_int(&e->input); |
buffer_get_bignum(&e->input, key->rsa->e); |
buffer_get_bignum(&e->input, key->rsa->e); |
buffer_get_bignum(&e->input, key->rsa->n); |
buffer_get_bignum(&e->input, key->rsa->n); |
|
|
if (bits != key_size(key)) |
if (bits != key_size(key)) |
log("Warning: identity keysize mismatch: actual %d, announced %d", |
log("Warning: identity keysize mismatch: actual %d, announced %d", |
key_size(key), bits); |
key_size(key), bits); |
break; |
break; |
case 2: |
case 2: |
blob = buffer_get_string(&e->input, &blen); |
blob = buffer_get_string(&e->input, &blen); |
key = dsa_key_from_blob(blob, blen); |
key = key_from_blob(blob, blen); |
xfree(blob); |
xfree(blob); |
break; |
break; |
} |
} |
|
|
/* |
/* |
* We have this key. Free the old key. Since we |
* We have this key. Free the old key. Since we |
* don\'t want to leave empty slots in the middle of |
* don\'t want to leave empty slots in the middle of |
* the array, we actually free the key there and copy |
* the array, we actually free the key there and move |
* data from the last entry. |
* all the entries between the empty slot and the end |
|
* of the array. |
*/ |
*/ |
Idtab *tab = idtab_lookup(version); |
Idtab *tab = idtab_lookup(version); |
key_free(tab->identities[idx].key); |
key_free(tab->identities[idx].key); |
xfree(tab->identities[idx].comment); |
xfree(tab->identities[idx].comment); |
if (idx != tab->nentries) |
if (tab->nentries < 1) |
tab->identities[idx] = tab->identities[tab->nentries]; |
fatal("process_remove_identity: " |
|
"internal error: tab->nentries %d", |
|
tab->nentries); |
|
if (idx != tab->nentries - 1) { |
|
int i; |
|
for (i = idx; i < tab->nentries - 1; i++) |
|
tab->identities[i] = tab->identities[i+1]; |
|
} |
|
tab->identities[tab->nentries - 1].key = NULL; |
|
tab->identities[tab->nentries - 1].comment = NULL; |
tab->nentries--; |
tab->nentries--; |
success = 1; |
success = 1; |
} |
} |
|
|
void |
void |
process_remove_all_identities(SocketEntry *e, int version) |
process_remove_all_identities(SocketEntry *e, int version) |
{ |
{ |
unsigned int i; |
u_int i; |
Idtab *tab = idtab_lookup(version); |
Idtab *tab = idtab_lookup(version); |
|
|
/* Loop over all identities and clear the keys. */ |
/* Loop over all identities and clear the keys. */ |
|
|
} |
} |
|
|
void |
void |
process_add_identity(SocketEntry *e, int version) |
generate_additional_parameters(RSA *rsa) |
{ |
{ |
Key *k = NULL; |
|
RSA *rsa; |
|
BIGNUM *aux; |
BIGNUM *aux; |
BN_CTX *ctx; |
BN_CTX *ctx; |
char *type; |
/* Generate additional parameters */ |
|
aux = BN_new(); |
|
ctx = BN_CTX_new(); |
|
|
|
BN_sub(aux, rsa->q, BN_value_one()); |
|
BN_mod(rsa->dmq1, rsa->d, aux, ctx); |
|
|
|
BN_sub(aux, rsa->p, BN_value_one()); |
|
BN_mod(rsa->dmp1, rsa->d, aux, ctx); |
|
|
|
BN_clear_free(aux); |
|
BN_CTX_free(ctx); |
|
} |
|
|
|
void |
|
process_add_identity(SocketEntry *e, int version) |
|
{ |
|
Key *k = NULL; |
|
char *type_name; |
char *comment; |
char *comment; |
int success = 0; |
int type, success = 0; |
Idtab *tab = idtab_lookup(version); |
Idtab *tab = idtab_lookup(version); |
|
|
switch (version) { |
switch (version) { |
case 1: |
case 1: |
k = key_new(KEY_RSA); |
k = key_new_private(KEY_RSA1); |
rsa = k->rsa; |
buffer_get_int(&e->input); /* ignored */ |
|
buffer_get_bignum(&e->input, k->rsa->n); |
|
buffer_get_bignum(&e->input, k->rsa->e); |
|
buffer_get_bignum(&e->input, k->rsa->d); |
|
buffer_get_bignum(&e->input, k->rsa->iqmp); |
|
|
/* allocate mem for private key */ |
|
/* XXX rsa->n and rsa->e are already allocated */ |
|
rsa->d = BN_new(); |
|
rsa->iqmp = BN_new(); |
|
rsa->q = BN_new(); |
|
rsa->p = BN_new(); |
|
rsa->dmq1 = BN_new(); |
|
rsa->dmp1 = BN_new(); |
|
|
|
buffer_get_int(&e->input); /* ignored */ |
|
|
|
buffer_get_bignum(&e->input, rsa->n); |
|
buffer_get_bignum(&e->input, rsa->e); |
|
buffer_get_bignum(&e->input, rsa->d); |
|
buffer_get_bignum(&e->input, rsa->iqmp); |
|
|
|
/* SSH and SSL have p and q swapped */ |
/* SSH and SSL have p and q swapped */ |
buffer_get_bignum(&e->input, rsa->q); /* p */ |
buffer_get_bignum(&e->input, k->rsa->q); /* p */ |
buffer_get_bignum(&e->input, rsa->p); /* q */ |
buffer_get_bignum(&e->input, k->rsa->p); /* q */ |
|
|
/* Generate additional parameters */ |
/* Generate additional parameters */ |
aux = BN_new(); |
generate_additional_parameters(k->rsa); |
ctx = BN_CTX_new(); |
|
|
|
BN_sub(aux, rsa->q, BN_value_one()); |
|
BN_mod(rsa->dmq1, rsa->d, aux, ctx); |
|
|
|
BN_sub(aux, rsa->p, BN_value_one()); |
|
BN_mod(rsa->dmp1, rsa->d, aux, ctx); |
|
|
|
BN_clear_free(aux); |
|
BN_CTX_free(ctx); |
|
|
|
break; |
break; |
case 2: |
case 2: |
type = buffer_get_string(&e->input, NULL); |
type_name = buffer_get_string(&e->input, NULL); |
if (strcmp(type, KEX_DSS)) { |
type = key_type_from_name(type_name); |
|
xfree(type_name); |
|
switch(type) { |
|
case KEY_DSA: |
|
k = key_new_private(type); |
|
buffer_get_bignum2(&e->input, k->dsa->p); |
|
buffer_get_bignum2(&e->input, k->dsa->q); |
|
buffer_get_bignum2(&e->input, k->dsa->g); |
|
buffer_get_bignum2(&e->input, k->dsa->pub_key); |
|
buffer_get_bignum2(&e->input, k->dsa->priv_key); |
|
break; |
|
case KEY_RSA: |
|
k = key_new_private(type); |
|
buffer_get_bignum2(&e->input, k->rsa->n); |
|
buffer_get_bignum2(&e->input, k->rsa->e); |
|
buffer_get_bignum2(&e->input, k->rsa->d); |
|
buffer_get_bignum2(&e->input, k->rsa->iqmp); |
|
buffer_get_bignum2(&e->input, k->rsa->p); |
|
buffer_get_bignum2(&e->input, k->rsa->q); |
|
|
|
/* Generate additional parameters */ |
|
generate_additional_parameters(k->rsa); |
|
break; |
|
default: |
buffer_clear(&e->input); |
buffer_clear(&e->input); |
xfree(type); |
|
goto send; |
goto send; |
} |
} |
xfree(type); |
|
|
|
k = key_new(KEY_DSA); |
|
|
|
/* allocate mem for private key */ |
|
k->dsa->priv_key = BN_new(); |
|
|
|
buffer_get_bignum2(&e->input, k->dsa->p); |
|
buffer_get_bignum2(&e->input, k->dsa->q); |
|
buffer_get_bignum2(&e->input, k->dsa->g); |
|
buffer_get_bignum2(&e->input, k->dsa->pub_key); |
|
buffer_get_bignum2(&e->input, k->dsa->priv_key); |
|
|
|
break; |
break; |
} |
} |
|
|
comment = buffer_get_string(&e->input, NULL); |
comment = buffer_get_string(&e->input, NULL); |
if (k == NULL) { |
if (k == NULL) { |
xfree(comment); |
xfree(comment); |
|
|
void |
void |
process_message(SocketEntry *e) |
process_message(SocketEntry *e) |
{ |
{ |
unsigned int msg_len; |
u_int msg_len; |
unsigned int type; |
u_int type; |
unsigned char *cp; |
u_char *cp; |
if (buffer_len(&e->input) < 5) |
if (buffer_len(&e->input) < 5) |
return; /* Incomplete message. */ |
return; /* Incomplete message. */ |
cp = (unsigned char *) buffer_ptr(&e->input); |
cp = (u_char *) buffer_ptr(&e->input); |
msg_len = GET_32BIT(cp); |
msg_len = GET_32BIT(cp); |
if (msg_len > 256 * 1024) { |
if (msg_len > 256 * 1024) { |
shutdown(e->fd, SHUT_RDWR); |
shutdown(e->fd, SHUT_RDWR); |
|
|
void |
void |
new_socket(int type, int fd) |
new_socket(int type, int fd) |
{ |
{ |
unsigned int i, old_alloc; |
u_int i, old_alloc; |
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
error("fcntl O_NONBLOCK: %s", strerror(errno)); |
error("fcntl O_NONBLOCK: %s", strerror(errno)); |
|
|
|
|
buffer_init(&sockets[old_alloc].output); |
buffer_init(&sockets[old_alloc].output); |
} |
} |
|
|
void |
int |
prepare_select(fd_set *readset, fd_set *writeset) |
prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl) |
{ |
{ |
unsigned int i; |
u_int i, sz; |
for (i = 0; i < sockets_alloc; i++) |
int n = 0; |
|
|
|
for (i = 0; i < sockets_alloc; i++) { |
switch (sockets[i].type) { |
switch (sockets[i].type) { |
case AUTH_SOCKET: |
case AUTH_SOCKET: |
case AUTH_CONNECTION: |
case AUTH_CONNECTION: |
FD_SET(sockets[i].fd, readset); |
n = MAX(n, sockets[i].fd); |
if (buffer_len(&sockets[i].output) > 0) |
|
FD_SET(sockets[i].fd, writeset); |
|
break; |
break; |
case AUTH_UNUSED: |
case AUTH_UNUSED: |
break; |
break; |
|
|
fatal("Unknown socket type %d", sockets[i].type); |
fatal("Unknown socket type %d", sockets[i].type); |
break; |
break; |
} |
} |
|
} |
|
|
|
sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); |
|
if (*fdrp == NULL || n > *fdl) { |
|
if (*fdrp) |
|
free(*fdrp); |
|
if (*fdwp) |
|
free(*fdwp); |
|
*fdrp = xmalloc(sz); |
|
*fdwp = xmalloc(sz); |
|
*fdl = n; |
|
} |
|
memset(*fdrp, 0, sz); |
|
memset(*fdwp, 0, sz); |
|
|
|
for (i = 0; i < sockets_alloc; i++) { |
|
switch (sockets[i].type) { |
|
case AUTH_SOCKET: |
|
case AUTH_CONNECTION: |
|
FD_SET(sockets[i].fd, *fdrp); |
|
if (buffer_len(&sockets[i].output) > 0) |
|
FD_SET(sockets[i].fd, *fdwp); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
return (1); |
} |
} |
|
|
void |
void |
after_select(fd_set *readset, fd_set *writeset) |
after_select(fd_set *readset, fd_set *writeset) |
{ |
{ |
unsigned int i; |
u_int i; |
int len, sock; |
int len, sock; |
socklen_t slen; |
socklen_t slen; |
char buf[1024]; |
char buf[1024]; |
|
|
case AUTH_SOCKET: |
case AUTH_SOCKET: |
if (FD_ISSET(sockets[i].fd, readset)) { |
if (FD_ISSET(sockets[i].fd, readset)) { |
slen = sizeof(sunaddr); |
slen = sizeof(sunaddr); |
sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &slen); |
sock = accept(sockets[i].fd, |
|
(struct sockaddr *) &sunaddr, &slen); |
if (sock < 0) { |
if (sock < 0) { |
perror("accept from AUTH_SOCKET"); |
perror("accept from AUTH_SOCKET"); |
break; |
break; |
|
|
case AUTH_CONNECTION: |
case AUTH_CONNECTION: |
if (buffer_len(&sockets[i].output) > 0 && |
if (buffer_len(&sockets[i].output) > 0 && |
FD_ISSET(sockets[i].fd, writeset)) { |
FD_ISSET(sockets[i].fd, writeset)) { |
len = write(sockets[i].fd, buffer_ptr(&sockets[i].output), |
len = write(sockets[i].fd, |
buffer_len(&sockets[i].output)); |
buffer_ptr(&sockets[i].output), |
|
buffer_len(&sockets[i].output)); |
if (len <= 0) { |
if (len <= 0) { |
shutdown(sockets[i].fd, SHUT_RDWR); |
shutdown(sockets[i].fd, SHUT_RDWR); |
close(sockets[i].fd); |
close(sockets[i].fd); |
|
|
void |
void |
check_parent_exists(int sig) |
check_parent_exists(int sig) |
{ |
{ |
|
int save_errno = errno; |
|
|
if (parent_pid != -1 && kill(parent_pid, 0) < 0) { |
if (parent_pid != -1 && kill(parent_pid, 0) < 0) { |
/* printf("Parent has died - Authentication agent exiting.\n"); */ |
/* printf("Parent has died - Authentication agent exiting.\n"); */ |
exit(1); |
exit(1); |
} |
} |
signal(SIGALRM, check_parent_exists); |
signal(SIGALRM, check_parent_exists); |
alarm(10); |
alarm(10); |
|
errno = save_errno; |
} |
} |
|
|
void |
void |
cleanup_socket(void) |
cleanup_socket(void) |
{ |
{ |
remove(socket_name); |
if (socket_name[0]) |
rmdir(socket_dir); |
unlink(socket_name); |
|
if (socket_dir[0]) |
|
rmdir(socket_dir); |
} |
} |
|
|
void |
void |
|
|
} |
} |
|
|
void |
void |
usage() |
cleanup_handler(int sig) |
{ |
{ |
|
cleanup_socket(); |
|
_exit(2); |
|
} |
|
|
|
void |
|
usage(void) |
|
{ |
fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); |
fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); |
fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n", |
fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n", |
__progname); |
__progname); |
exit(1); |
exit(1); |
} |
} |
|
|
int |
int |
main(int ac, char **av) |
main(int ac, char **av) |
{ |
{ |
fd_set readset, writeset; |
|
int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; |
int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; |
struct sockaddr_un sunaddr; |
struct sockaddr_un sunaddr; |
|
struct rlimit rlim; |
pid_t pid; |
pid_t pid; |
char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; |
char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; |
|
extern int optind; |
|
fd_set *readsetp = NULL, *writesetp = NULL; |
|
|
/* check if RSA support exists */ |
|
if (rsa_alive() == 0) { |
|
fprintf(stderr, |
|
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n", |
|
__progname); |
|
exit(1); |
|
} |
|
while ((ch = getopt(ac, av, "cks")) != -1) { |
while ((ch = getopt(ac, av, "cks")) != -1) { |
switch (ch) { |
switch (ch) { |
case 'c': |
case 'c': |
|
|
pidstr = getenv(SSH_AGENTPID_ENV_NAME); |
pidstr = getenv(SSH_AGENTPID_ENV_NAME); |
if (pidstr == NULL) { |
if (pidstr == NULL) { |
fprintf(stderr, "%s not set, cannot kill agent\n", |
fprintf(stderr, "%s not set, cannot kill agent\n", |
SSH_AGENTPID_ENV_NAME); |
SSH_AGENTPID_ENV_NAME); |
exit(1); |
exit(1); |
} |
} |
pid = atoi(pidstr); |
pid = atoi(pidstr); |
if (pid < 1) { /* XXX PID_MAX check too */ |
if (pid < 1) { |
/* Yes, PID_MAX check please */ |
|
fprintf(stderr, "%s=\"%s\", which is not a good PID\n", |
fprintf(stderr, "%s=\"%s\", which is not a good PID\n", |
SSH_AGENTPID_ENV_NAME, pidstr); |
SSH_AGENTPID_ENV_NAME, pidstr); |
exit(1); |
exit(1); |
} |
} |
if (kill(pid, SIGTERM) == -1) { |
if (kill(pid, SIGTERM) == -1) { |
|
|
exit(1); |
exit(1); |
} |
} |
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, |
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, |
parent_pid); |
parent_pid); |
|
|
/* |
/* |
* Create socket early so it will exist before command gets run from |
* Create socket early so it will exist before command gets run from |
|
|
perror("listen"); |
perror("listen"); |
cleanup_exit(1); |
cleanup_exit(1); |
} |
} |
|
|
/* |
/* |
* Fork, and have the parent execute the command, if any, or present |
* Fork, and have the parent execute the command, if any, or present |
* the socket data. The child continues as the authentication agent. |
* the socket data. The child continues as the authentication agent. |
|
|
if (ac == 0) { |
if (ac == 0) { |
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; |
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; |
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, |
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, |
SSH_AUTHSOCKET_ENV_NAME); |
SSH_AUTHSOCKET_ENV_NAME); |
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, |
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, |
SSH_AGENTPID_ENV_NAME); |
SSH_AGENTPID_ENV_NAME); |
printf("echo Agent pid %d;\n", pid); |
printf("echo Agent pid %d;\n", pid); |
exit(0); |
exit(0); |
} |
} |
|
|
close(1); |
close(1); |
close(2); |
close(2); |
|
|
|
/* deny core dumps, since memory contains unencrypted private keys */ |
|
rlim.rlim_cur = rlim.rlim_max = 0; |
|
if (setrlimit(RLIMIT_CORE, &rlim) < 0) { |
|
perror("setrlimit rlimit_core failed"); |
|
cleanup_exit(1); |
|
} |
if (setsid() == -1) { |
if (setsid() == -1) { |
perror("setsid"); |
perror("setsid"); |
cleanup_exit(1); |
cleanup_exit(1); |
|
|
idtab_init(); |
idtab_init(); |
signal(SIGINT, SIG_IGN); |
signal(SIGINT, SIG_IGN); |
signal(SIGPIPE, SIG_IGN); |
signal(SIGPIPE, SIG_IGN); |
signal(SIGHUP, cleanup_exit); |
signal(SIGHUP, cleanup_handler); |
signal(SIGTERM, cleanup_exit); |
signal(SIGTERM, cleanup_handler); |
while (1) { |
while (1) { |
FD_ZERO(&readset); |
prepare_select(&readsetp, &writesetp, &max_fd); |
FD_ZERO(&writeset); |
if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) { |
prepare_select(&readset, &writeset); |
|
if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) { |
|
if (errno == EINTR) |
if (errno == EINTR) |
continue; |
continue; |
exit(1); |
exit(1); |
} |
} |
after_select(&readset, &writeset); |
after_select(readsetp, writesetp); |
} |
} |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |