]> andersk Git - openssh.git/blobdiff - ssh-agent.c
- (djm) Sync sys/tree.h with OpenBSD -current. Rename tree.h and
[openssh.git] / ssh-agent.c
index 13a88afd9cf98ff0a4d93dd4480120d0e92778aa..d4c008bbf6200cc90b6753795510fbeca0c8e3be 100644 (file)
@@ -34,8 +34,8 @@
  */
 
 #include "includes.h"
-#include "openbsd-compat/fake-queue.h"
-RCSID("$OpenBSD: ssh-agent.c,v 1.87 2002/06/05 16:48:54 markus Exp $");
+#include "openbsd-compat/sys-queue.h"
+RCSID("$OpenBSD: ssh-agent.c,v 1.103 2002/09/10 20:24:47 markus Exp $");
 
 #include <openssl/evp.h>
 #include <openssl/md5.h>
@@ -76,6 +76,7 @@ typedef struct identity {
        TAILQ_ENTRY(identity) next;
        Key *key;
        char *comment;
+       u_int death;
 } Identity;
 
 typedef struct {
@@ -95,16 +96,32 @@ pid_t parent_pid = -1;
 char socket_name[1024];
 char socket_dir[1024];
 
+/* locking */
+int locked = 0;
+char *lock_passwd = NULL;
+
 #ifdef HAVE___PROGNAME
 extern char *__progname;
 #else
 char *__progname;
 #endif
 
+static void
+close_socket(SocketEntry *e)
+{
+       close(e->fd);
+       e->fd = -1;
+       e->type = AUTH_UNUSED;
+       buffer_free(&e->input);
+       buffer_free(&e->output);
+       buffer_free(&e->request);
+}
+
 static void
 idtab_init(void)
 {
        int i;
+
        for (i = 0; i <=2; i++) {
                TAILQ_INIT(&idtable[i].idlist);
                idtable[i].nentries = 0;
@@ -120,6 +137,14 @@ idtab_lookup(int version)
        return &idtable[version];
 }
 
+static void
+free_identity(Identity *id)
+{
+       key_free(id->key);
+       xfree(id->comment);
+       xfree(id);
+}
+
 /* return matching private key for given public key */
 static Identity *
 lookup_identity(Key *key, int version)
@@ -134,21 +159,13 @@ lookup_identity(Key *key, int version)
        return (NULL);
 }
 
-static void
-free_identity(Identity *id)
-{
-       key_free(id->key);
-       xfree(id->comment);
-       xfree(id);
-}
-
 /* send list of supported public keys to 'client' */
 static void
 process_request_identities(SocketEntry *e, int version)
 {
        Idtab *tab = idtab_lookup(version);
-       Buffer msg;
        Identity *id;
+       Buffer msg;
 
        buffer_init(&msg);
        buffer_put_char(&msg, (version == 1) ?
@@ -177,21 +194,21 @@ process_request_identities(SocketEntry *e, int version)
 static void
 process_authentication_challenge1(SocketEntry *e)
 {
-       Identity *id;
-       Key *key;
+       u_char buf[32], mdbuf[16], session_id[16];
+       u_int response_type;
        BIGNUM *challenge;
+       Identity *id;
        int i, len;
        Buffer msg;
        MD5_CTX md;
-       u_char buf[32], mdbuf[16], session_id[16];
-       u_int response_type;
+       Key *key;
 
        buffer_init(&msg);
        key = key_new(KEY_RSA1);
        if ((challenge = BN_new()) == NULL)
                fatal("process_authentication_challenge1: BN_new failed");
 
-       buffer_get_int(&e->request);                            /* ignored */
+       (void) buffer_get_int(&e->request);                     /* ignored */
        buffer_get_bignum(&e->request, key->rsa->e);
        buffer_get_bignum(&e->request, key->rsa->n);
        buffer_get_bignum(&e->request, challenge);
@@ -246,13 +263,12 @@ send:
 static void
 process_sign_request2(SocketEntry *e)
 {
-       extern int datafellows;
-       Key *key;
        u_char *blob, *data, *signature = NULL;
        u_int blen, dlen, slen = 0;
-       int flags;
+       extern int datafellows;
+       int ok = -1, flags;
        Buffer msg;
-       int ok = -1;
+       Key *key;
 
        datafellows = 0;
 
@@ -291,11 +307,10 @@ process_sign_request2(SocketEntry *e)
 static void
 process_remove_identity(SocketEntry *e, int version)
 {
+       u_int blen, bits;
+       int success = 0;
        Key *key = NULL;
        u_char *blob;
-       u_int blen;
-       u_int bits;
-       int success = 0;
 
        switch (version) {
        case 1:
@@ -305,7 +320,7 @@ process_remove_identity(SocketEntry *e, int version)
                buffer_get_bignum(&e->request, key->rsa->n);
 
                if (bits != key_size(key))
-                       log("Warning: identity keysize mismatch: actual %d, announced %d",
+                       log("Warning: identity keysize mismatch: actual %u, announced %u",
                            key_size(key), bits);
                break;
        case 2:
@@ -360,22 +375,41 @@ process_remove_all_identities(SocketEntry *e, int version)
        /* Send success. */
        buffer_put_int(&e->output, 1);
        buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
-       return;
+}
+
+static void
+reaper(void)
+{
+       u_int now = time(NULL);
+       Identity *id, *nxt;
+       int version;
+       Idtab *tab;
+
+       for (version = 1; version < 3; version++) {
+               tab = idtab_lookup(version);
+               for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
+                       nxt = TAILQ_NEXT(id, next);
+                       if (id->death != 0 && now >= id->death) {
+                               TAILQ_REMOVE(&tab->idlist, id, next);
+                               free_identity(id);
+                               tab->nentries--;
+                       }
+               }
+       }
 }
 
 static void
 process_add_identity(SocketEntry *e, int version)
 {
-       Key *k = NULL;
-       char *type_name;
-       char *comment;
-       int type, success = 0;
        Idtab *tab = idtab_lookup(version);
+       int type, success = 0, death = 0;
+       char *type_name, *comment;
+       Key *k = NULL;
 
        switch (version) {
        case 1:
                k = key_new_private(KEY_RSA1);
-               buffer_get_int(&e->request);                    /* ignored */
+               (void) buffer_get_int(&e->request);             /* ignored */
                buffer_get_bignum(&e->request, k->rsa->n);
                buffer_get_bignum(&e->request, k->rsa->e);
                buffer_get_bignum(&e->request, k->rsa->d);
@@ -425,10 +459,20 @@ process_add_identity(SocketEntry *e, int version)
                goto send;
        }
        success = 1;
+       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;
+               default:
+                       break;
+               }
+       }
        if (lookup_identity(k, version) == NULL) {
                Identity *id = xmalloc(sizeof(Identity));
                id->key = k;
                id->comment = comment;
+               id->death = death;
                TAILQ_INSERT_TAIL(&tab->idlist, id, next);
                /* Increment the number of identities. */
                tab->nentries++;
@@ -442,16 +486,57 @@ send:
            success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
 }
 
+/* XXX todo: encrypt sensitive data with passphrase */
+static void
+process_lock_agent(SocketEntry *e, int lock)
+{
+       int success = 0;
+       char *passwd;
+
+       passwd = buffer_get_string(&e->request, NULL);
+       if (locked && !lock && strcmp(passwd, lock_passwd) == 0) {
+               locked = 0;
+               memset(lock_passwd, 0, strlen(lock_passwd));
+               xfree(lock_passwd);
+               lock_passwd = NULL;
+               success = 1;
+       } else if (!locked && lock) {
+               locked = 1;
+               lock_passwd = xstrdup(passwd);
+               success = 1;
+       }
+       memset(passwd, 0, strlen(passwd));
+       xfree(passwd);
+
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+no_identities(SocketEntry *e, u_int type)
+{
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg,
+           (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ?
+           SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
+       buffer_put_int(&msg, 0);
+       buffer_put_int(&e->output, buffer_len(&msg));
+       buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
+       buffer_free(&msg);
+}
 
 #ifdef SMARTCARD
 static void
 process_add_smartcard_key (SocketEntry *e)
 {
-       Identity *id;
-       Idtab *tab;
-       Key **keys, *k;
        char *sc_reader_id = NULL, *pin;
        int i, version, success = 0;
+       Key **keys, *k;
+       Identity *id;
+       Idtab *tab;
 
        sc_reader_id = buffer_get_string(&e->request, NULL);
        pin = buffer_get_string(&e->request, NULL);
@@ -471,6 +556,7 @@ process_add_smartcard_key (SocketEntry *e)
                        id = xmalloc(sizeof(Identity));
                        id->key = k;
                        id->comment = xstrdup("smartcard key");
+                       id->death = 0;
                        TAILQ_INSERT_TAIL(&tab->idlist, id, next);
                        tab->nentries++;
                        success = 1;
@@ -489,11 +575,11 @@ send:
 static void
 process_remove_smartcard_key(SocketEntry *e)
 {
-       Identity *id;
-       Idtab *tab;
-       Key **keys, *k = NULL;
        char *sc_reader_id = NULL, *pin;
        int i, version, success = 0;
+       Key **keys, *k = NULL;
+       Identity *id;
+       Idtab *tab;
 
        sc_reader_id = buffer_get_string(&e->request, NULL);
        pin = buffer_get_string(&e->request, NULL);
@@ -510,7 +596,7 @@ process_remove_smartcard_key(SocketEntry *e)
                version = k->type == KEY_RSA1 ? 1 : 2;
                if ((id = lookup_identity(k, version)) != NULL) {
                        tab = idtab_lookup(version);
-                        TAILQ_REMOVE(&tab->idlist, id, next);
+                       TAILQ_REMOVE(&tab->idlist, id, next);
                        tab->nentries--;
                        free_identity(id);
                        success = 1;
@@ -531,20 +617,18 @@ send:
 static void
 process_message(SocketEntry *e)
 {
-       u_int msg_len;
-       u_int type;
+       u_int msg_len, type;
        u_char *cp;
+
+       /* kill dead keys */
+       reaper();
+
        if (buffer_len(&e->input) < 5)
                return;         /* Incomplete message. */
        cp = buffer_ptr(&e->input);
        msg_len = GET_32BIT(cp);
        if (msg_len > 256 * 1024) {
-               shutdown(e->fd, SHUT_RDWR);
-               close(e->fd);
-               e->type = AUTH_UNUSED;
-               buffer_free(&e->input);
-               buffer_free(&e->output);
-               buffer_free(&e->request);
+               close_socket(e);
                return;
        }
        if (buffer_len(&e->input) < msg_len + 4)
@@ -557,8 +641,29 @@ process_message(SocketEntry *e)
        buffer_consume(&e->input, msg_len);
        type = buffer_get_char(&e->request);
 
+       /* check wheter agent is locked */
+       if (locked && type != SSH_AGENTC_UNLOCK) {
+               buffer_clear(&e->request);
+               switch (type) {
+               case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
+               case SSH2_AGENTC_REQUEST_IDENTITIES:
+                       /* send empty lists */
+                       no_identities(e, type);
+                       break;
+               default:
+                       /* send a fail message for all other request types */
+                       buffer_put_int(&e->output, 1);
+                       buffer_put_char(&e->output, SSH_AGENT_FAILURE);
+               }
+               return;
+       }
+
        debug("type %d", type);
        switch (type) {
+       case SSH_AGENTC_LOCK:
+       case SSH_AGENTC_UNLOCK:
+               process_lock_agent(e, type == SSH_AGENTC_LOCK);
+               break;
        /* ssh1 */
        case SSH_AGENTC_RSA_CHALLENGE:
                process_authentication_challenge1(e);
@@ -567,6 +672,7 @@ process_message(SocketEntry *e)
                process_request_identities(e, 1);
                break;
        case SSH_AGENTC_ADD_RSA_IDENTITY:
+       case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED:
                process_add_identity(e, 1);
                break;
        case SSH_AGENTC_REMOVE_RSA_IDENTITY:
@@ -583,6 +689,7 @@ process_message(SocketEntry *e)
                process_request_identities(e, 2);
                break;
        case SSH2_AGENTC_ADD_IDENTITY:
+       case SSH2_AGENTC_ADD_ID_CONSTRAINED:
                process_add_identity(e, 2);
                break;
        case SSH2_AGENTC_REMOVE_IDENTITY:
@@ -613,6 +720,7 @@ static void
 new_socket(sock_type type, int fd)
 {
        u_int i, old_alloc;
+
        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                error("fcntl O_NONBLOCK: %s", strerror(errno));
 
@@ -697,11 +805,13 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp)
 static void
 after_select(fd_set *readset, fd_set *writeset)
 {
-       u_int i;
-       int len, sock;
+       struct sockaddr_un sunaddr;
        socklen_t slen;
        char buf[1024];
-       struct sockaddr_un sunaddr;
+       int len, sock;
+       u_int i;
+       uid_t euid;
+       gid_t egid;
 
        for (i = 0; i < sockets_alloc; i++)
                switch (sockets[i].type) {
@@ -717,6 +827,19 @@ after_select(fd_set *readset, fd_set *writeset)
                                            strerror(errno));
                                        break;
                                }
+                               if (getpeereid(sock, &euid, &egid) < 0) {
+                                       error("getpeereid %d failed: %s",
+                                           sock, strerror(errno));
+                                       close(sock);
+                                       break;
+                               }
+                               if (getuid() != euid) {
+                                       error("uid mismatch: "
+                                           "peer euid %d != uid %d",
+                                           (int) euid, (int) getuid());
+                                       close(sock);
+                                       break;
+                               }
                                new_socket(AUTH_CONNECTION, sock);
                        }
                        break;
@@ -733,12 +856,7 @@ after_select(fd_set *readset, fd_set *writeset)
                                        break;
                                } while (1);
                                if (len <= 0) {
-                                       shutdown(sockets[i].fd, SHUT_RDWR);
-                                       close(sockets[i].fd);
-                                       sockets[i].type = AUTH_UNUSED;
-                                       buffer_free(&sockets[i].input);
-                                       buffer_free(&sockets[i].output);
-                                       buffer_free(&sockets[i].request);
+                                       close_socket(&sockets[i]);
                                        break;
                                }
                                buffer_consume(&sockets[i].output, len);
@@ -752,12 +870,7 @@ after_select(fd_set *readset, fd_set *writeset)
                                        break;
                                } while (1);
                                if (len <= 0) {
-                                       shutdown(sockets[i].fd, SHUT_RDWR);
-                                       close(sockets[i].fd);
-                                       sockets[i].type = AUTH_UNUSED;
-                                       buffer_free(&sockets[i].input);
-                                       buffer_free(&sockets[i].output);
-                                       buffer_free(&sockets[i].request);
+                                       close_socket(&sockets[i]);
                                        break;
                                }
                                buffer_append(&sockets[i].input, buf, len);
@@ -824,6 +937,8 @@ int
 main(int ac, char **av)
 {
        int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
+       char *shell, *format, *pidstr, *agentsocket = NULL;
+       fd_set *readsetp = NULL, *writesetp = NULL;
        struct sockaddr_un sunaddr;
 #ifdef HAVE_SETRLIMIT
        struct rlimit rlim;
@@ -831,11 +946,14 @@ main(int ac, char **av)
 #ifdef HAVE_CYGWIN
        int prev_mask;
 #endif
-       pid_t pid;
-       char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
-       char *agentsocket = NULL;
        extern int optind;
-       fd_set *readsetp = NULL, *writesetp = NULL;
+       extern char *optarg;
+       pid_t pid;
+       char pidstrbuf[1 + 3 * sizeof pid];
+
+       /* drop */
+       setegid(getgid());
+       setgid(getgid());
 
        SSLeay_add_all_algorithms();
 
@@ -843,11 +961,7 @@ main(int ac, char **av)
        init_rng();
        seed_rng();
 
-#ifdef __GNU_LIBRARY__
-       while ((ch = getopt(ac, av, "+cdksa:")) != -1) {
-#else /* __GNU_LIBRARY__ */
        while ((ch = getopt(ac, av, "cdksa:")) != -1) {
-#endif /* __GNU_LIBRARY__ */
                switch (ch) {
                case 'c':
                        if (s_flag)
@@ -905,7 +1019,7 @@ main(int ac, char **av)
                format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
                printf(format, SSH_AUTHSOCKET_ENV_NAME);
                printf(format, SSH_AGENTPID_ENV_NAME);
-               printf("echo Agent pid %d killed;\n", pid);
+               printf("echo Agent pid %ld killed;\n", (long)pid);
                exit(0);
        }
        parent_pid = getpid();
@@ -917,8 +1031,8 @@ main(int ac, char **av)
                        perror("mkdtemp: private socket dir");
                        exit(1);
                }
-               snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
-                   parent_pid);
+               snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
+                   (long)parent_pid);
        } else {
                /* Try to use specified agent socket */
                socket_dir[0] = '\0';
@@ -950,7 +1064,7 @@ main(int ac, char **av)
 #ifdef HAVE_CYGWIN
        umask(prev_mask);
 #endif
-       if (listen(sock, 5) < 0) {
+       if (listen(sock, 128) < 0) {
                perror("listen");
                cleanup_exit(1);
        }
@@ -964,7 +1078,7 @@ main(int ac, char **av)
                format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
                printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
                    SSH_AUTHSOCKET_ENV_NAME);
-               printf("echo Agent pid %d;\n", parent_pid);
+               printf("echo Agent pid %ld;\n", (long)parent_pid);
                goto skip;
        }
        pid = fork();
@@ -974,14 +1088,14 @@ main(int ac, char **av)
        }
        if (pid != 0) {         /* Parent - execute the given command. */
                close(sock);
-               snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
+               snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
                if (ac == 0) {
                        format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
                        printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
                            SSH_AUTHSOCKET_ENV_NAME);
                        printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
                            SSH_AGENTPID_ENV_NAME);
-                       printf("echo Agent pid %d;\n", pid);
+                       printf("echo Agent pid %ld;\n", (long)pid);
                        exit(0);
                }
                if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
This page took 0.102953 seconds and 4 git commands to generate.