/** * 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; }
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; }