Exemple #1
0
/**
 * do the keyserver operation
 * @param peer the cn from the client's certificate
 * @param op the operation to perform, one of: 
 *	PERMIT - authorize a keyserver client
 *	GENKEY - generate a new key for peer
 *      SETKEY - key from friend login server
 *      FETCHKEY - peer requests it's key
 *      FETCHGC - peer requests the granting cert
 *      SETPKEY - set the public key for a client's cert
 *      NOOP - for completeness
 * @param newkey if the operation is SETKEY, "peer;base64(key)"
 *               else is effective hostname for the op
 * @param ccert the client's certificate
 * @return 0 on success, non-zero on error
 */
int doit (const char *peer, security_context * context, enum optype op,
          const char *newkey, X509 * ccert)
{
    char buf[8 * PBC_DES_KEY_BUF];
    crypt_stuff c_stuff;
    pool *p = NULL;
    int dokeyret = 0;
    char *thepeer = NULL;       /* effective peer hostname */
    char *thekey64;
    FILE *gcf;
    int lgcf;
    char **keymgt_peers = libpbc_config_getlist (p, "keymgt_peers");
    int x, found;
    char *z;

    /* no HTML headers for me */
    myprintf ("\r\n");
    buf[0] = '\0';

    switch (op) {
    case PERMIT:
        {
            /* 'peer' has asked us to authorize a new CN (newkey) */
            if (check_access_list (peer) == PBC_FAIL) {
                myprintf
                    ("NO you (%s) are not authorized to authorize\r\n",
                     peer);
                pbc_log_activity (p, PBC_LOG_ERROR,
                                  "operation not allowed: %s", peer);
                return (1);
            }

            /* find <cn>;<test> */
            thepeer = strdup (newkey);
            thekey64 = strchr (thepeer, ';');
            if (!thekey64) {
                myprintf ("NO bad form for authorize\r\n");
                /* xxx log */
                return (1);
            }
            *thekey64++ = '\0';
            if (z = strchr (thekey64, ' '))
                *z = '\0';

            if (libpbc_test_crypt_key (p, thepeer) == PBC_OK) {
                myprintf ("OK already authorized\r\n");
                pbc_log_activity (p, PBC_LOG_ERROR, "already authorized");
                return (1);
            }

            /* if just a test, return now */
            if (!strncmp (thekey64, "test", 4)) {
                myprintf ("NO server is not authorized\r\n");
                pbc_log_activity (p, PBC_LOG_ERROR, "test - not yet");
                return (1);
            }


            pbc_log_activity (p, PBC_LOG_AUDIT, "authorizing %s", thepeer);

            if (libpbc_generate_crypt_key (p, thepeer) != PBC_OK) {
                myprintf ("NO generate_new_key() failed\r\n");
                pbc_log_activity (p, PBC_LOG_ERROR,
                                  "generate_new_key() failed");
                return (1);
            }

            /* push the new key to the other login servers */
            pushkey (thepeer, context, NULL);

            dokeyret = 0;       /* don't return the key to this client */
            break;
        }

    case GENKEY:
        {
            /* 'peer' has asked us to generate a new key */
            if (newkey)
                thepeer = strdup (newkey);
            else
                thepeer = (char *) peer;
            if (z = strchr (thepeer, ' '))
                *z = '\0';
            if (!test_peer (thepeer, ccert)) {
                myprintf ("NO you (%s) are not authorized for host %s\r\n",
                          peer, thepeer);
                pbc_log_activity (p, PBC_LOG_ERROR,
                                  "operation not allowed: p=%s, h=%s",
                                  peer, thepeer);
                return (1);
            }
            if (libpbc_test_crypt_key (p, thepeer) == PBC_FAIL) {
                myprintf ("NO you (%s) are not authorized for keys\r\n",
                          thepeer);
                pbc_log_activity (p, PBC_LOG_ERROR,
                                  "operation not allowed: %s", thepeer);
                return (1);
            }

            pbc_log_activity (p, PBC_LOG_AUDIT,
                              "generating a new key for %s", thepeer);

            if (libpbc_generate_crypt_key (p, thepeer) < 0) {
                myprintf ("NO generate_new_key() failed\r\n");
                pbc_log_activity (p, PBC_LOG_ERROR,
                                  "generate_new_key() failed");

                return (1);
            }

            /* push the new key to the other login servers */
            pushkey (thepeer, context, NULL);

            dokeyret = 1;
            break;
        }

    case SETKEY:
        {
            char *thekey64, *thepeer;
            char *thekey;
            int ksize;

            /* someone has asked us to set a key */

            /* verify that 'peer' is a fellow login server
               OR in the list of keymgt_peers.  this allows the pool of 
               key management hosts to push keys to servers outside their 
               cluster */
            if (strcasecmp (peer, PBC_LOGIN_HOST)) {
                found = 0;
                for (x = 0; keymgt_peers[x] != NULL && !found; x++)
                    if (!strcasecmp (peer, keymgt_peers[x]))
                        found = 1;
                if (!found) {
                    pbc_log_activity (p, PBC_LOG_ERROR,
                                      "%s attempted to set a key!", peer);
                    myprintf ("NO you are not authorized to set keys\r\n");
                    return (1);
                }
            }

            /* find <peer>;<key> */
            thepeer = strdup (newkey);
            thekey64 = strchr (thepeer, ';');
            if (!thekey64) {
                myprintf ("NO bad form for new key\r\n");
                /* xxx log */
                return (1);
            }
            *thekey64++ = '\0';
            if (z = strchr (thekey64, ' '))
                *z = '\0';

            /* base64 decode thekey64 */
            thekey = (char *) malloc (strlen (thekey64));
            if (strchr (thekey64, '\r')) {
                /* chomp new line */
                *strchr (thekey64, '\r') = '\0';
            }
            if (!thekey ||
                !libpbc_base64_decode (p, (unsigned char *) thekey64,
                                       (unsigned char *) thekey, &ksize) ||
                ksize != PBC_DES_KEY_BUF) {
                myprintf ("NO couldn't decode key\r\n");
                /* xxx log */
                return (1);
            }

            /* go ahead and write it to disk */
            if (libpbc_set_crypt_key (p, thekey, thepeer) != PBC_OK) {
                myprintf ("NO couldn't set key\r\n");
                /* xxx log */
                return (1);
            }

            free (thekey);

            pbc_log_activity (p, PBC_LOG_AUDIT,
                              "%s set key for %s!", peer, thepeer);
            myprintf ("OK key set\r\n");
            break;
        }

    case FETCHKEY:

        pbc_log_activity (p, PBC_LOG_AUDIT, "Fetching a key..");

        if (newkey)
            thepeer = strdup (newkey);
        else
            thepeer = (char *) peer;
        if (z = strchr (thepeer, ' '))
            *z = '\0';
        if (!test_peer (thepeer, ccert)) {
            myprintf ("NO you (%s) are not authorized for host %s\r\n",
                      peer, thepeer);
            pbc_log_activity (p, PBC_LOG_ERROR,
                              "operation not allowed: p=%s, h=%s", peer,
                              thepeer);
            return (1);
        }
        dokeyret = 1;
        break;

    case FETCHGC:

        pbc_log_activity (p, PBC_LOG_AUDIT, "Fetching the cert..");

        if (!(gcfile && (gcf = fopen (gcfile, "r")))) {
            myprintf ("NO couldn't open cert file\r\n");
            return (1);
        }
        lgcf = fread (buf, 1, sizeof (buf) - 1, gcf);
        if (lgcf <= 0) {
            myprintf ("NO couldn't read cert file\r\n");
            return (1);
        }
        buf[lgcf] = '\0';
        dokeyret = 0;
        break;

    case SETPKEY:
        {
            /* 'peer' has asked us to store the public key for a host */
            /* newkey is the cert (pem) */
            X509 *crt;
            char *cn, *cn1;
            char *fn;
            FILE *fp;

            if (check_access_list (peer) == PBC_FAIL) {
                myprintf
                    ("NO you (%s) are not authorized to set cert keys\r\n",
                     peer);
                pbc_log_activity (p, PBC_LOG_ERROR,
                                  "operation not allowed: %s", peer);
                return (1);
            }

            pbc_log_activity (p, PBC_LOG_DEBUG_VERBOSE, "pkey cert = %s",
                              newkey);
            crt = get_crt_from_pem (newkey);
            if (!crt || !(cn = get_cn_from_crt (crt))) {
                myprintf ("NO bad cert\r\n");
                pbc_log_activity (p, PBC_LOG_ERROR, "bad pkey cert");
                return (1);
            }
            cn1 = cn;
            if (*cn1 == '*')
                cn1++;
            if (*cn1 == '.')
                cn1++;
            pbc_log_activity (p, PBC_LOG_AUDIT,
                              "setting pubkey for %s", cn1);

            fn = (char *) malloc (strlen (PBC_KEY_DIR) + strlen (cn1) +
                                  16);
            sprintf (fn, "%s/%s.crt", PBC_KEY_DIR, cn1);

            if (!((fp = fopen (fn, "w")) && (fputs (newkey, fp) > 0) &&
                  (fclose (fp) == 0))) {
                myprintf ("NO store pkey failed\r\n");
                pbc_log_activity (p, PBC_LOG_ERROR, "store pkey failed");
                return (1);
            }

            /* push the pkey to the other login servers */
            pushkey (thepeer, context, fn);

            dokeyret = 0;       /* don't return a key to this client */
            break;
        }

    case NOOP:

        pbc_log_activity (p, PBC_LOG_AUDIT, "Noop..");
        /* noop;  just for completeness */
        break;
    }

    if (dokeyret) {
        /* return the key */
        if (libpbc_get_crypt_key (p, &c_stuff, (char *) thepeer) != PBC_OK) {
            myprintf ("NO couldn't retrieve key\r\n");
            return 1;
        }

        /* now give the key back to the application */
        libpbc_base64_encode (p, c_stuff.key_a, (unsigned char *) buf,
                              PBC_DES_KEY_BUF);
    }

    myprintf ("OK %s\r\n", buf);
    fflush (stdout);

    return 0;
}
Exemple #2
0
static void test_transaction(void) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *src = NULL, *dst = NULL;
        _c_cleanup_(b1_node_freep) B1Node *node = NULL;
        _c_cleanup_(b1_handle_unrefp) B1Handle *handle = NULL;
        _c_cleanup_(b1_message_unrefp) B1Message *message = NULL;
        const char *payload = "WOOF";
        struct iovec vec = {
                .iov_base = (void*)payload,
                .iov_len = strlen(payload) + 1,
        };
        struct iovec *vec_out;
        size_t n_vec;
        int r, fd;

        r = b1_peer_new(&src);
        assert(r >= 0);

        r = b1_peer_new(&dst);
        assert(r >= 0);

        r = b1_node_new(dst, &node);
        assert(r >= 0);

        r = b1_handle_transfer(b1_node_get_handle(node), src, &handle);
        assert(r >= 0);

        r = b1_message_new(src, &message);
        assert(r >= 0);

        r = b1_message_set_payload(message, &vec, 1);
        assert(r >= 0);

        r = b1_message_set_handles(message, &handle, 1);
        assert(r >= 0);

        fd = eventfd(0, 0);
        assert(fd >= 0);

        r = b1_message_set_fds(message, &fd, 1);
        assert(r >= 0);

        assert(close(fd) >= 0);

        r = b1_message_send(message, &handle, 1);
        assert(r >= 0);

        message = b1_message_unref(message);
        assert(!message);
        handle = b1_handle_unref(handle);
        assert(!handle);

        r = b1_peer_recv(dst, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_DATA);
        assert(b1_message_get_destination_node(message) == node);
        assert(b1_message_get_uid(message) == getuid());
        assert(b1_message_get_gid(message) == getgid());
        assert(b1_message_get_pid(message) == getpid());
        assert(b1_message_get_tid(message) == c_syscall_gettid());
        r = b1_message_get_payload(message, &vec_out, &n_vec);
        assert(r >= 0);
        assert(vec_out);
        assert(n_vec == 1);
        assert(vec_out->iov_len == strlen("WOOF") + 1);
        assert(strcmp(vec_out->iov_base, "WOOF") == 0);
        r = b1_message_get_handle(message, 0, &handle);
        assert(r >= 0);
        assert(handle == b1_node_get_handle(node));
        handle = NULL;
        r = b1_message_get_fd(message, 0, &fd);
        assert(r >= 0);
        assert(fd >= 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_RELEASE);
        assert(b1_message_get_destination_node(message) == node);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_node_destroy(node);
        assert(r >= 0);

        r = b1_peer_recv(dst, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_DESTROY);
        assert(b1_message_get_destination_node(message));
        assert(b1_message_get_destination_node(message) == node);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst, &message);
        assert(r == -EAGAIN);
        r = b1_peer_recv(src, &message);
        assert(r == -EAGAIN);
}

static void test_multicast(void) {
        _c_cleanup_(b1_peer_unrefp) B1Peer *src = NULL, *dst1 = NULL, *dst2 = NULL;
        _c_cleanup_(b1_node_freep) B1Node *node1 = NULL, *node2 = NULL;
        _c_cleanup_(b1_message_unrefp) B1Message *message = NULL;
        const char *payload = "WOOF";
        struct iovec vec = {
                .iov_base = (void*)payload,
                .iov_len = strlen(payload) + 1,
        };
        struct iovec *vec_out;
        size_t n_vec;
        B1Handle *handles[2], *handle;
        int r, fd;

        r = b1_peer_new(&src);
        assert(r >= 0);

        r = b1_peer_new(&dst1);
        assert(r >= 0);

        r = b1_peer_new(&dst2);
        assert(r >= 0);

        r = b1_node_new(dst1, &node1);
        assert(r >= 0);

        r = b1_node_new(dst2, &node2);
        assert(r >= 0);

        r = b1_handle_transfer(b1_node_get_handle(node1), src, &handles[0]);
        assert(r >= 0);

        r = b1_handle_transfer(b1_node_get_handle(node2), src, &handles[1]);
        assert(r >= 0);

        r = b1_message_new(src, &message);
        assert(r >= 0);

        r = b1_message_set_payload(message, &vec, 1);
        assert(r >= 0);

        r = b1_message_set_handles(message, handles, 2);
        assert(r >= 0);

        fd = eventfd(0, 0);
        assert(fd >= 0);

        r = b1_message_set_fds(message, &fd, 1);
        assert(r >= 0);

        assert(close(fd) >= 0);

        r = b1_message_send(message, handles, 2);
        assert(r >= 0);

        message = b1_message_unref(message);
        assert(!message);
        handles[0] = b1_handle_unref(handles[0]);
        assert(!handles[0]);
        handles[1] = b1_handle_unref(handles[1]);
        assert(!handles[1]);

        r = b1_peer_recv(dst1, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_DATA);
        assert(b1_message_get_destination_node(message) == node1);
        assert(b1_message_get_uid(message) == getuid());
        assert(b1_message_get_gid(message) == getgid());
        assert(b1_message_get_pid(message) == getpid());
        assert(b1_message_get_tid(message) == c_syscall_gettid());
        r = b1_message_get_payload(message, &vec_out, &n_vec);
        assert(r >= 0);
        assert(vec_out);
        assert(n_vec == 1);
        assert(vec_out->iov_len == strlen("WOOF") + 1);
        assert(strcmp(vec_out->iov_base, "WOOF") == 0);
        r = b1_message_get_handle(message, 0, &handle);
        assert(r >= 0);
        assert(handle == b1_node_get_handle(node1));
        r = b1_message_get_handle(message, 1, &handle);
        assert(r >= 0);
        assert(handle);
        assert(handle != b1_node_get_handle(node1));
        r = b1_message_get_fd(message, 0, &fd);
        assert(r >= 0);
        assert(fd >= 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst2, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_DATA);
        assert(b1_message_get_destination_node(message) == node2);
        assert(b1_message_get_uid(message) == getuid());
        assert(b1_message_get_gid(message) == getgid());
        assert(b1_message_get_pid(message) == getpid());
        assert(b1_message_get_tid(message) == c_syscall_gettid());
        r = b1_message_get_payload(message, &vec_out, &n_vec);
        assert(r >= 0);
        assert(vec_out);
        assert(n_vec == 1);
        assert(vec_out->iov_len == strlen("WOOF") + 1);
        assert(strcmp(vec_out->iov_base, "WOOF") == 0);
        r = b1_message_get_handle(message, 0, &handle);
        assert(r >= 0);
        assert(handle);
        assert(handle != b1_node_get_handle(node2));
        r = b1_message_get_handle(message, 1, &handle);
        assert(r >= 0);
        assert(handle);
        assert(handle == b1_node_get_handle(node2));
        r = b1_message_get_fd(message, 0, &fd);
        assert(r >= 0);
        assert(fd >= 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst1, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_RELEASE);
        assert(b1_message_get_destination_node(message) == node1);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst2, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_RELEASE);
        assert(b1_message_get_destination_node(message) == node2);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_node_destroy(node1);
        assert(r >= 0);

        r = b1_peer_recv(dst1, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_DESTROY);
        assert(b1_message_get_destination_node(message) == node1);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_node_destroy(node2);
        assert(r >= 0);

        r = b1_peer_recv(dst2, &message);
        assert(r >= 0);
        assert(message);
        assert(b1_message_get_type(message) == BUS1_MSG_NODE_DESTROY);
        assert(b1_message_get_destination_node(message) == node2);
        assert(b1_message_get_uid(message) == (uid_t)-1);
        assert(b1_message_get_gid(message) == (gid_t)-1);
        assert(b1_message_get_pid(message) == 0);
        assert(b1_message_get_tid(message) == 0);
        message = b1_message_unref(message);

        r = b1_peer_recv(dst1, &message);
        assert(r == -EAGAIN);
        r = b1_peer_recv(dst2, &message);
        assert(r == -EAGAIN);
        r = b1_peer_recv(src, &message);
        assert(r == -EAGAIN);
}

int main(int argc, char **argv) {
        if (access("/dev/bus1", F_OK) < 0 && errno == ENOENT)
                return 77;

        test_peer();
        test_node();
        test_handle();
        test_message();
        test_transaction();
        test_multicast();

        return 0;
}