/* Add new agent. Send agent ID + number of workers + router map */ static void add_agent(int fd, bool isclient) { unsigned agent = next_agent++; if (agent >= worker_cnt + maxclients) { /* Exceeded client limit */ chunk_ptr msg = msg_new_nack(); if (chunk_write(fd, msg)) { #if RPT >= 1 report(1, "Sent nack to potential client due to client limit being exceeded. Fd = %d", fd); #endif } else { #if RPT >= 3 report(3, "Couldn't send nack to potential client. Fd = %d", fd); #endif } chunk_free(msg); return; } /* Need to break into sequence of messages according to max. chunk length */ chunk_ptr msg = NULL; size_t bcount = 0; size_t ncount = router_addr_set->nelements; set_iterstart(router_addr_set); word_t id; bool ok = true; while (ok && set_iternext(router_addr_set, &id)) { if (bcount == 0) { /* Start new block */ size_t blen = ncount; if (blen > MAX_IDS) blen = MAX_IDS; msg = chunk_new(blen+1); } word_t wd = id << 16; chunk_insert_word(msg, wd, bcount+1); bcount++; if (bcount == MAX_IDS) { /* This block is filled */ size_t h1 = ((word_t) agent << 48) | ((word_t) ncount << 32) | ((word_t) worker_cnt << 16) | MSG_ACK_AGENT; chunk_insert_word(msg, h1, 0); ok = chunk_write(fd, msg); chunk_free(msg); ncount -= bcount; bcount = 0; } } if (ok && ncount > 0) { size_t h1 = ((word_t) agent << 48) | ((word_t) ncount << 32) | ((word_t) worker_cnt << 16) | MSG_ACK_AGENT; chunk_insert_word(msg, h1, 0); ok = chunk_write(fd, msg); chunk_free(msg); ncount -= bcount; } #if RPT >= 3 report(3, "Added agent %u with descriptor %d", agent, fd); #endif }
bool do_controller_flush_cmd(int argc, char *argv[]) { chunk_ptr msg = msg_new_flush(); word_t w; int fd; bool ok = true; set_iterstart(worker_fd_set); while (set_iternext(worker_fd_set, &w)) { fd = w; if (!chunk_write(fd, msg)) { err(false, "Failed to send flush message to worker with descriptor %d", fd); ok = false; } } set_iterstart(client_fd_set); while (set_iternext(client_fd_set, &w)) { fd = w; if (!chunk_write(fd, msg)) { err(false, "Failed to send flush message to client with descriptor %d", fd); ok = false; } } chunk_free(msg); free_global_ops(); gc_state = GC_READY; need_worker_cnt = 0; if (need_client_fd_set != NULL) set_free(need_client_fd_set); need_client_fd_set = NULL; if (defer_client_fd_set != NULL) set_free(defer_client_fd_set); defer_client_fd_set = NULL; return ok; }
bool quit_controller(int argc, char *argv[]) { /* Send kill messages to other nodes and close file connections */ chunk_ptr msg = msg_new_kill(); word_t w; int fd; keyvalue_iterstart(new_conn_map); while (keyvalue_iternext(new_conn_map, &w, NULL)) { fd = w; close(fd); } set_iterstart(router_fd_set); while (set_iternext(router_fd_set, &w)) { fd = w; if (!chunk_write(fd, msg)) err(false, "Failed to send kill message to router with descriptor %d", fd); close(fd); } set_iterstart(worker_fd_set); while (set_iternext(worker_fd_set, &w)) { fd = w; if (!chunk_write(fd, msg)) err(false, "Failed to send kill message to worker with descriptor %d", fd); close(fd); } set_iterstart(client_fd_set); while (set_iternext(client_fd_set, &w)) { fd = w; if (!chunk_write(fd, msg)) err(false, "Failed to send kill message to client with descriptor %d", fd); close(fd); } /* Deallocate */ chunk_free(msg); set_free(router_addr_set); keyvalue_free(new_conn_map); set_free(router_fd_set); set_free(worker_fd_set); set_free(client_fd_set); while (stat_message_cnt > 0) { chunk_free(stat_messages[--stat_message_cnt]); } free_array(stat_messages, sizeof(chunk_ptr), worker_cnt); free_global_ops(); if (need_client_fd_set != NULL) set_free(need_client_fd_set); need_client_fd_set = NULL; if (defer_client_fd_set != NULL) set_free(defer_client_fd_set); defer_client_fd_set = NULL; chunk_deinit(); return true; }
/* Accumulate worker messages with statistics */ static void add_stat_message(chunk_ptr msg) { size_t *stat_summary = NULL; stat_messages[stat_message_cnt++] = msg; /* See if we've accumulated a full set */ if (stat_message_cnt >= worker_cnt) { size_t nstat = stat_messages[0]->length - 1; if (flush_requestor_fd >= 0) stat_summary = calloc_or_fail(nstat * 3, sizeof(size_t), "add_stat_message"); /* Accumulate and print */ #if RPT >= 1 report(1, "Worker statistics:"); #endif size_t i, w; for (i = 0; i < nstat; i++) { chunk_ptr msg = stat_messages[0]; word_t minval, maxval, sumval; minval = maxval = sumval = chunk_get_word(msg, i+1); for (w = 1; w < worker_cnt; w++) { chunk_ptr msg = stat_messages[w]; word_t val = chunk_get_word(msg, i+1); if (val < minval) minval = val; if (val > maxval) maxval = val; sumval += val; } if (stat_summary) { stat_summary[3*i + 0] = minval; stat_summary[3*i + 1] = maxval; stat_summary[3*i + 2] = sumval; } #if RPT >= 1 report(1, "Parameter %d\tMin: %" PRIu64 "\tMax: %" PRIu64 "\tAvg: %.2f\tSum: %" PRIu64, (int) i, minval, maxval, (double) sumval/worker_cnt, sumval); #endif } if (flush_requestor_fd >= 0) { chunk_ptr msg = msg_new_stat(worker_cnt, nstat*3, stat_summary); if (chunk_write(flush_requestor_fd, msg)) { #if RPT >= 5 report(5, "Sent statistical summary to client at fd %d", flush_requestor_fd); #endif } else { err(false, "Failed to send statistical summary to client at fd %d", flush_requestor_fd); } chunk_free(msg); free_array(stat_summary, nstat*3, sizeof(size_t)); } for (w = 0; w < worker_cnt; w++) { chunk_free(stat_messages[w]); stat_messages[w] = NULL; } stat_message_cnt = 0; flush_requestor_fd = -1; } }
bool do_controller_collect_cmd(int argc, char *argv[]) { word_t w; bool ok = true; if (gc_state != GC_READY) { err(false, "Cannot initiate garbage collection while one is still underway"); return false; } gc_generation++; chunk_ptr msg = msg_new_gc_start(); set_iterstart(worker_fd_set); while (set_iternext(worker_fd_set, &w)) { int fd = (int) w; if (!chunk_write(fd, msg)) { err(false, "Failed to send gc start message to worker with descriptor %d", fd); ok = false; } } chunk_free(msg); #if RPT >= 3 report(3, "GC waiting for workers to start"); #endif gc_state = GC_WAIT_WORKER_START; need_worker_cnt = worker_fd_set->nelements; return ok; }
bool do_agent_kill(int argc, char *argv[]) { chunk_ptr msg = msg_new_kill(); if (chunk_write(controller_fd, msg)) { #if RPT >= 3 report(3, "Notified controller that want to kill system"); #endif } else { err(false, "Couldn't notify controller that want to kill system"); } chunk_free(msg); return true; }
static void gc_start(unsigned code) { gc_state = GC_ACTIVE; #if RPT >= 3 report(3, "Starting GC"); #endif if (isclient) { /* Client */ if (start_gc_handler) start_gc_handler(); chunk_ptr msg = msg_new_gc_finish(); if (!chunk_write(controller_fd, msg)) err(false, "Failed to send GC Finish message to controller"); chunk_free(msg); } else { /* Worker */ if (start_gc_handler) start_gc_handler(); chunk_ptr msg = msg_new_gc_start(); if (!chunk_write(controller_fd, msg)) err(false, "Failed to send GC Start message to controller"); chunk_free(msg); } }
bool do_agent_gc(int argc, char *argv[]) { chunk_ptr msg = msg_new_gc_start(); /* Further command processing must wait until gc completes */ block_console(); bool ok = chunk_write(controller_fd, msg); chunk_free(msg); if (ok) { #if RPT >= 4 report(4, "Notified controller that want to run garbage collection"); #endif } else { err(false, "Couldn't notify controller that want to run garbage collection"); } return ok; }
bool do_agent_flush(int argc, char *argv[]) { chunk_ptr msg = msg_new_flush(); /* Further command processing must wait until received statistics from controller */ block_console(); bool ok = chunk_write(controller_fd, msg); if (ok) { #if RPT >= 3 report(3, "Notified controller that want to flush system"); #endif } else { err(false, "Couldn't notify controller that want to flush system"); } chunk_free(msg); gc_state = GC_IDLE; gc_generation = 0; return ok; }
static void gc_finish(unsigned code) { #if RPT >= 3 report(3, "Finishing GC"); #endif if (isclient) { if (finish_gc_handler) finish_gc_handler(); } else { if (finish_gc_handler) finish_gc_handler(); chunk_ptr msg = msg_new_gc_finish(); chunk_write(controller_fd, msg); chunk_free(msg); } gc_state = GC_IDLE; gc_generation++; /* Allow command processing to continue */ unblock_console(); }
void request_gc() { if (gc_state != GC_IDLE) { #if RPT >= 4 report(4, "GC request when not in GC_IDLE state"); #endif return; } unsigned gen = gc_generation+1; chunk_ptr msg = msg_new_gc_request(gen); if (chunk_write(controller_fd, msg)) { #if RPT >= 4 report(4, "Requested garbage collection with generation %u", gen); #endif } else { err(false, "Failed to request garbage collection with generation %u", gen); } chunk_free(msg); gc_state = GC_REQUESTED; }
END_TEST /******************************************************************************* * test for chunk_from_fd */ START_TEST(test_chunk_from_fd_file) { chunk_t in, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05); char *path = "/tmp/strongswan-chunk-fd-test"; int fd; ck_assert(chunk_write(contents, path, 022, TRUE)); fd = open(path, O_RDONLY); ck_assert(fd != -1); ck_assert(chunk_from_fd(fd, &in)); close(fd); ck_assert_msg(chunk_equals(in, contents), "%B", &in); unlink(path); free(in.ptr); }
END_TEST /******************************************************************************* * test for chunk_map and friends */ START_TEST(test_chunk_map) { chunk_t *map, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05); char *path = "/tmp/strongswan-chunk-map-test"; ck_assert(chunk_write(contents, path, 022, TRUE)); /* read */ map = chunk_map(path, FALSE); ck_assert(map != NULL); ck_assert_msg(chunk_equals(*map, contents), "%B", map); /* altering mapped chunk should not hurt */ *map = chunk_empty; ck_assert(chunk_unmap(map)); /* write */ map = chunk_map(path, TRUE); ck_assert(map != NULL); ck_assert_msg(chunk_equals(*map, contents), "%B", map); map->ptr[0] = 0x06; ck_assert(chunk_unmap(map)); /* verify write */ contents.ptr[0] = 0x06; map = chunk_map(path, FALSE); ck_assert(map != NULL); ck_assert_msg(chunk_equals(*map, contents), "%B", map); ck_assert(chunk_unmap(map)); unlink(path); }
bool send_op(chunk_ptr msg) { dword_t dh = chunk_get_dword(msg, 0); unsigned agent = msg_get_dheader_agent(dh); unsigned code = msg_get_dheader_code(dh); if (code == MSG_OPERATION) { agent_stat_counter[STATA_OPERATION_TOTAL]++; if (self_route && agent == own_agent) { agent_stat_counter[STATA_OPERATION_LOCAL]++; #if RPT >= 6 word_t id = msg_get_dheader_op_id(dh); report(6, "Routing operator with id 0x%lx to self", id); #endif receive_operation(chunk_clone(msg)); return true; } } if (code == MSG_OPERAND) { agent_stat_counter[STATA_OPERAND_TOTAL]++; if (self_route && agent == own_agent && !isclient) { agent_stat_counter[STATA_OPERAND_LOCAL]++; #if RPT >= 6 word_t id = msg_get_dheader_op_id(dh); report(6, "Routing operand with id 0x%lx to self", id); #endif receive_operand(chunk_clone(msg)); return true; } } // Try to send to a local router if possible int rfd; if (local_router_fd == -1) { unsigned idx = random() % nrouters; rfd = router_fd_array[idx]; #if RPT >= 5 word_t id = msg_get_dheader_op_id(dh); report(5, "Sending message with id 0x%x through router %u (fd %d)", id, idx, rfd); #endif } else { rfd = local_router_fd; #if RPT >= 5 word_t id = msg_get_dheader_op_id(dh); report(5, "Sending message with id 0x%x through the local router (fd %d)", id, rfd); #endif } bool ok = chunk_write(rfd, msg); if (ok) { #if RPT >= 5 report(5, "Message sent"); #endif } else { err(false, "Failed"); } return ok; }
static void handle_gc_msg(unsigned code, unsigned gen, int fd, bool isclient) { char *source = isclient ? "client" : "worker"; word_t w; #if RPT >= 5 report(5, "Received GC message with code %u from fd %d (%s), while in state %u", code, fd, source, gc_state); #endif switch (gc_state) { case GC_READY: if (isclient && code == MSG_GC_START) { /* Garbage collection initiated by client */ #if RPT >= 4 report(4, "GC request by client"); #endif do_controller_collect_cmd(0, NULL); } else if (!isclient && code == MSG_GC_REQUEST) { if (gen == gc_generation+1) { #if RPT >= 4 report(4, "GC request by worker"); #endif do_controller_collect_cmd(0, NULL); } else { #if RPT >= 4 report(4, "Outdated (gen = %u, current generation = %u) GC request by worker", gen, gc_generation); #endif } } else { err(false, "Unexpected GC message. Code %u. In GC_READY state", code); } break; case GC_WAIT_WORKER_START: if (code == MSG_GC_START && !isclient) { need_worker_cnt--; if (need_worker_cnt == 0) { chunk_ptr msg = msg_new_gc_start(); set_iterstart(client_fd_set); while (set_iternext(client_fd_set, &w)) { int cfd = (int) w; if (!chunk_write(cfd, msg)) { err(false, "Failed to send GC start message to client with fd %d", cfd); } } chunk_free(msg); need_client_fd_set = set_clone(client_fd_set, NULL); gc_state = GC_WAIT_CLIENT; #if RPT >= 3 report(3, "GC waiting for clients to finish"); #endif } } else if (code == MSG_GC_REQUEST) { #if RPT >= 4 report(4, "GC request by worker while waiting for workers to start. Ignored."); #endif } else { err(false, "Unexpected code %u from %s while waiting for workers to start", code, source); } break; case GC_WAIT_CLIENT: if (code == MSG_GC_FINISH && isclient) { if (set_member(need_client_fd_set, (word_t) fd, true)) { if (need_client_fd_set->nelements == 0) { set_free(need_client_fd_set); need_client_fd_set = NULL; chunk_ptr msg = msg_new_gc_finish(); set_iterstart(worker_fd_set); while (set_iternext(worker_fd_set, &w)) { int wfd = (int) w; if (!chunk_write(wfd, msg)) { err(false, "Failed to send GC Finish message to worker with fd %d", wfd); } } chunk_free(msg); gc_state = GC_WAIT_WORKER_FINISH; #if RPT >= 3 report(3, "GC waiting for workers to finish"); #endif need_worker_cnt = worker_fd_set->nelements; } } else { err(false, "Got unexpected GC_FINISH message from client with fd %d", fd); } } else if (code == MSG_GC_REQUEST) { #if RPT >= 4 report(4, "GC request by worker while waiting for client. Ignored."); #endif } else { err(false, "Unexpected code %u from %s while waiting for clients to finish", code, source); } break; case GC_WAIT_WORKER_FINISH: if (code == MSG_GC_FINISH && !isclient) { need_worker_cnt--; if (need_worker_cnt == 0) { chunk_ptr msg = msg_new_gc_finish(); set_iterstart(client_fd_set); while (set_iternext(client_fd_set, &w)) { int cfd = (int) w; if (!chunk_write(cfd, msg)) err(false, "Failed to send GC finish message to client with fd %d", fd); } chunk_free(msg); /* See if there are deferred client connections */ if (defer_client_fd_set != NULL) { set_iterstart(defer_client_fd_set); while (set_iternext(defer_client_fd_set, &w)) { int cfd = (int) w; set_insert(client_fd_set, (word_t) cfd); #if RPT >= 4 report(4, "Added deferred client with fd %d", cfd); #endif if (need_workers == 0) add_agent(cfd, true); } set_free(defer_client_fd_set); defer_client_fd_set = NULL; } gc_state = GC_READY; #if RPT >= 3 report(3, "GC completed"); #endif } } else if (code == MSG_GC_REQUEST) { #if RPT >= 4 report(4, "GC request by worker while waiting for workers to finish. Ignored."); #endif } else { err(false, "Unexpected code %u from %s while waiting for workers to finish", code, source); } break; default: err(false, "GC in unexpected state %u", gc_state); } }
static void run_controller(char *infile_name) { if (!start_cmd(infile_name)) return; while (!cmd_done()) { FD_ZERO(&set); int fd; word_t w; unsigned ip; unsigned port; add_fd(listen_fd); keyvalue_iterstart(new_conn_map); /* Check for messages from newly connected clients, workers, and routers */ while (keyvalue_iternext(new_conn_map, &w, NULL)) { fd = w; add_fd(fd); } if (need_routers == 0) { /* Accept messages from workers */ set_iterstart(worker_fd_set); while (set_iternext(worker_fd_set, &w)) { fd = w; add_fd(fd); } /* Accept messages from clients */ set_iterstart(client_fd_set); while (set_iternext(client_fd_set, &w)) { fd = w; add_fd(fd); } } cmd_select(maxfd+1, &set, NULL, NULL, NULL); for (fd = 0; fd <= maxfd; fd++) { if (!FD_ISSET(fd, &set)) continue; if (fd == listen_fd) { unsigned ip; int connfd = accept_connection(fd, &ip); keyvalue_insert(new_conn_map, (word_t) connfd, (word_t) ip); #if RPT >= 4 report(4, "Accepted new connection. Connfd = %d, IP = 0x%x", connfd, ip); #endif continue; } bool eof; chunk_ptr msg = chunk_read(fd, &eof); if (eof) { /* Unexpected EOF */ if (keyvalue_remove(new_conn_map, (word_t) fd, NULL, NULL)) { err(false, "Unexpected EOF from new connection, fd %d", fd); } else if (set_member(worker_fd_set, (word_t) fd, true)) { err(false, "Unexpected EOF from connected worker, fd %d. Shutting down", fd); /* Shut down system */ finish_cmd(); } else if (set_member(client_fd_set, (word_t) fd, true)) { #if RPT >= 3 report(3, "Disconnection from client (fd %d)", fd); #endif if (need_client_fd_set && set_member(need_client_fd_set, (word_t) fd, false)) { #if RPT >= 3 report(3, "Removing client from GC activities"); #endif handle_gc_msg(MSG_GC_FINISH, 0, fd, true); } } else { err(false, "Unexpected EOF from unknown source, fd %d", fd); } close(fd); continue; } if (msg == NULL) { err(false, "Could not read chunk from fd %d (ignored)", fd); continue; } word_t h = chunk_get_word(msg, 0); unsigned code = msg_get_header_code(h); #if RPT >= 5 report(5, "Received message with code %d from fd %d", code, fd); #endif if (keyvalue_remove(new_conn_map, (word_t) fd, NULL, &w)) { ip = w; chunk_free(msg); /* Should be a registration message */ switch (code) { case MSG_REGISTER_ROUTER: if (need_routers == 0) { err(false, "Unexpected router registration. (Ignored)"); close(fd); break; } port = msg_get_header_port(h); word_t node_id = msg_build_node_id(port, ip); set_insert(router_addr_set, node_id); set_insert(router_fd_set, (word_t) fd); #if RPT >= 4 report(4, "Added router with fd %d. IP 0x%x. Port %u", fd, ip, port); #endif need_routers --; if (need_routers == 0) { #if RPT >= 2 report(2, "All routers connected"); #endif /* Have gotten all of the necessary routers. Notify any registered workers */ set_iterstart(worker_fd_set); int wfd; while (set_iternext(worker_fd_set, &w)) { wfd = w; add_agent(wfd, false); } } break; case MSG_REGISTER_WORKER: if (worker_fd_set->nelements >= worker_cnt) { err(false, "Unexpected worker registration. (Ignored)"); close(fd); break; } set_insert(worker_fd_set, (word_t) fd); #if RPT >= 4 report(4, "Added worker with fd %d", fd); #endif if (need_routers == 0) add_agent(fd, false); break; case MSG_REGISTER_CLIENT: if (gc_state == GC_READY) { set_insert(client_fd_set, (word_t) fd); #if RPT >= 4 report(4, "Added client with fd %d", fd); #endif if (need_workers == 0) add_agent(fd, true); } else { if (!defer_client_fd_set) { defer_client_fd_set = word_set_new(); } set_insert(defer_client_fd_set, (word_t) fd); #if RPT >= 3 report(3, "Deferring client with fd %d until GC completed", fd); #endif } break; default: err(false, "Unexpected message code %u from new connection", code); break; } } else if (set_member(worker_fd_set, (word_t) fd, false)) { /* Message from worker */ switch (code) { unsigned agent; unsigned gen; case MSG_READY_WORKER: chunk_free(msg); if (need_workers == 0) { err(false, "Unexpected worker ready. (Ignored)"); close(fd); break; } need_workers--; if (need_workers == 0) { #if RPT >= 2 report(2, "All workers connected"); #endif /* Notify any pending clients */ set_iterstart(client_fd_set); int cfd; while (set_iternext(client_fd_set, &w)) { cfd = w; add_agent(cfd, true); } } break; case MSG_STAT: /* Message gets stashed away. Don't free it */ add_stat_message(msg); break; case MSG_CLIOP_ACK: /* Worker acknowledging receipt of global operation info */ agent = msg_get_header_agent(h); int client_fd = receive_global_op_worker_ack(agent); if (client_fd >= 0) { /* Have received complete set of acknowledgements. */ /* Send ack to client */ if (chunk_write(client_fd, msg)) { #if RPT >= 6 report(6, "Sent ack to client for global operation with id %u", agent); #endif } else { err(false, "Failed to send ack to client for global operation with id %u. Fd %d", agent, client_fd); } } chunk_free(msg); break; case MSG_GC_START: case MSG_GC_FINISH: handle_gc_msg(code, 0, fd, false); chunk_free(msg); break; case MSG_GC_REQUEST: gen = msg_get_header_generation(h); chunk_free(msg); handle_gc_msg(code, gen, fd, false); break; default: chunk_free(msg); err(false, "Unexpected message code %u from worker", code); } } else if (set_member(client_fd_set, (word_t) fd, false)) { /* Message from client */ switch(code){ unsigned agent; word_t w; case MSG_KILL: /* Shutdown entire system */ chunk_free(msg); #if RPT >= 2 report(2, "Remote request to kill system"); #endif finish_cmd(); return; case MSG_DO_FLUSH: /* Initiate a flush operation */ chunk_free(msg); flush_requestor_fd = fd; do_controller_flush_cmd(0, NULL); break; case MSG_CLIOP_DATA: /* Request for global operation from client */ agent = msg_get_header_agent(h); add_global_op(agent, fd); /* Send message to all workers */ set_iterstart(worker_fd_set); while (set_iternext(worker_fd_set, &w)) { int worker_fd = (int) w; if (chunk_write(worker_fd, msg)) { #if RPT >= 6 report(6, "Sent global operation information with id %u to worker with fd %d", agent, worker_fd); #endif } else { err(false, "Failed to send global operation information with id %u to worker with fd %d", agent, worker_fd); } } chunk_free(msg); break; case MSG_CLIOP_ACK: /* Completion of global operation by client */ agent = msg_get_header_agent(h); /* Send message to all workers */ set_iterstart(worker_fd_set); while (set_iternext(worker_fd_set, &w)) { int worker_fd = (int) w; if (chunk_write(worker_fd, msg)) { #if RPT >= 6 report(6, "Sent global operation acknowledgement with id %u to worker with fd %d", agent, worker_fd); #endif } else { err(false, "Failed to send global operation acknowledgement with id %u to worker with fd %d", agent, worker_fd); } } chunk_free(msg); break; case MSG_GC_START: case MSG_GC_FINISH: handle_gc_msg(code, 0, fd, true); chunk_free(msg); break; default: err(false, "Unexpected message code %u from client", code); } } else { chunk_free(msg); err(false, "Unexpected message on fd %d (Ignored)", fd); } } } }
/** * @brief openac main program * * @param argc number of arguments * @param argv pointer to the argument values */ int main(int argc, char **argv) { certificate_t *attr_cert = NULL; certificate_t *userCert = NULL; certificate_t *signerCert = NULL; private_key_t *signerKey = NULL; time_t notBefore = UNDEFINED_TIME; time_t notAfter = UNDEFINED_TIME; time_t validity = 0; char *keyfile = NULL; char *certfile = NULL; char *usercertfile = NULL; char *outfile = NULL; char *groups = ""; char buf[BUF_LEN]; chunk_t passphrase = { buf, 0 }; chunk_t serial = chunk_empty; chunk_t attr_chunk = chunk_empty; int status = 1; /* enable openac debugging hook */ dbg = openac_dbg; passphrase.ptr[0] = '\0'; openlog("openac", 0, LOG_AUTHPRIV); /* initialize library */ atexit(library_deinit); if (!library_init(NULL)) { exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); } if (lib->integrity && !lib->integrity->check_file(lib->integrity, "openac", argv[0])) { fprintf(stderr, "integrity check of openac failed\n"); exit(SS_RC_DAEMON_INTEGRITY); } if (!lib->plugins->load(lib->plugins, lib->settings->get_str(lib->settings, "openac.load", PLUGINS))) { exit(SS_RC_INITIALIZATION_FAILED); } /* initialize optionsfrom */ options_t *options = options_create(); /* handle arguments */ for (;;) { static const struct option long_opts[] = { /* name, has_arg, flag, val */ { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "optionsfrom", required_argument, NULL, '+' }, { "quiet", no_argument, NULL, 'q' }, { "cert", required_argument, NULL, 'c' }, { "key", required_argument, NULL, 'k' }, { "password", required_argument, NULL, 'p' }, { "usercert", required_argument, NULL, 'u' }, { "groups", required_argument, NULL, 'g' }, { "days", required_argument, NULL, 'D' }, { "hours", required_argument, NULL, 'H' }, { "startdate", required_argument, NULL, 'S' }, { "enddate", required_argument, NULL, 'E' }, { "out", required_argument, NULL, 'o' }, { "debug", required_argument, NULL, 'd' }, { 0,0,0,0 } }; int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:d:", long_opts, NULL); /* Note: "breaking" from case terminates loop */ switch (c) { case EOF: /* end of flags */ break; case 0: /* long option already handled */ continue; case ':': /* diagnostic already printed by getopt_long */ case '?': /* diagnostic already printed by getopt_long */ case 'h': /* --help */ usage(NULL); status = 1; goto end; case 'v': /* --version */ printf("openac (strongSwan %s)\n", VERSION); status = 0; goto end; case '+': /* --optionsfrom <filename> */ { char path[BUF_LEN]; if (*optarg == '/') /* absolute pathname */ { strncpy(path, optarg, BUF_LEN); path[BUF_LEN-1] = '\0'; } else /* relative pathname */ { snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg); } if (!options->from(options, path, &argc, &argv, optind)) { status = 1; goto end; } } continue; case 'q': /* --quiet */ stderr_quiet = TRUE; continue; case 'c': /* --cert */ certfile = optarg; continue; case 'k': /* --key */ keyfile = optarg; continue; case 'p': /* --key */ if (strlen(optarg) >= BUF_LEN) { usage("passphrase too long"); goto end; } strncpy(passphrase.ptr, optarg, BUF_LEN); passphrase.len = min(strlen(optarg), BUF_LEN); continue; case 'u': /* --usercert */ usercertfile = optarg; continue; case 'g': /* --groups */ groups = optarg; continue; case 'D': /* --days */ if (optarg == NULL || !isdigit(optarg[0])) { usage("missing number of days"); goto end; } else { char *endptr; long days = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || days <= 0) { usage("<days> must be a positive number"); goto end; } validity += 24*3600*days; } continue; case 'H': /* --hours */ if (optarg == NULL || !isdigit(optarg[0])) { usage("missing number of hours"); goto end; } else { char *endptr; long hours = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || hours <= 0) { usage("<hours> must be a positive number"); goto end; } validity += 3600*hours; } continue; case 'S': /* --startdate */ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') { usage("date format must be YYYYMMDDHHMMSSZ"); goto end; } else { chunk_t date = { optarg, 15 }; notBefore = asn1_to_time(&date, ASN1_GENERALIZEDTIME); } continue; case 'E': /* --enddate */ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') { usage("date format must be YYYYMMDDHHMMSSZ"); goto end; } else { chunk_t date = { optarg, 15 }; notAfter = asn1_to_time(&date, ASN1_GENERALIZEDTIME); } continue; case 'o': /* --out */ outfile = optarg; continue; case 'd': /* --debug */ debug_level = atoi(optarg); continue; default: usage(""); status = 0; goto end; } /* break from loop */ break; } if (optind != argc) { usage("unexpected argument"); goto end; } DBG1(DBG_LIB, "starting openac (strongSwan Version %s)", VERSION); /* load the signer's RSA private key */ if (keyfile != NULL) { mem_cred_t *mem; shared_key_t *shared; mem = mem_cred_create(); lib->credmgr->add_set(lib->credmgr, &mem->set); shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(passphrase)); mem->add_shared(mem, shared, NULL); signerKey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, BUILD_FROM_FILE, keyfile, BUILD_END); lib->credmgr->remove_set(lib->credmgr, &mem->set); mem->destroy(mem); if (signerKey == NULL) { goto end; } DBG1(DBG_LIB, " loaded private key file '%s'", keyfile); } /* load the signer's X.509 certificate */ if (certfile != NULL) { signerCert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, certfile, BUILD_END); if (signerCert == NULL) { goto end; } } /* load the users's X.509 certificate */ if (usercertfile != NULL) { userCert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, usercertfile, BUILD_END); if (userCert == NULL) { goto end; } } /* compute validity interval */ validity = (validity)? validity : DEFAULT_VALIDITY; notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore; notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter; /* build and parse attribute certificate */ if (userCert != NULL && signerCert != NULL && signerKey != NULL && outfile != NULL) { /* read the serial number and increment it by one */ serial = read_serial(); attr_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_CERT, userCert, BUILD_NOT_BEFORE_TIME, notBefore, BUILD_NOT_AFTER_TIME, notAfter, BUILD_SERIAL, serial, BUILD_IETF_GROUP_ATTR, groups, BUILD_SIGNING_CERT, signerCert, BUILD_SIGNING_KEY, signerKey, BUILD_END); if (!attr_cert) { goto end; } /* write the attribute certificate to file */ if (attr_cert->get_encoding(attr_cert, CERT_ASN1_DER, &attr_chunk)) { if (chunk_write(attr_chunk, outfile, 0022, TRUE)) { DBG1(DBG_APP, " written attribute cert file '%s' (%d bytes)", outfile, attr_chunk.len); write_serial(serial); status = 0; } else { DBG1(DBG_APP, " writing attribute cert file '%s' failed: %s", outfile, strerror(errno)); } } } else { usage("some of the mandatory parameters --usercert --cert --key --out " "are missing"); } end: /* delete all dynamically allocated objects */ DESTROY_IF(signerKey); DESTROY_IF(signerCert); DESTROY_IF(userCert); DESTROY_IF(attr_cert); free(attr_chunk.ptr); free(serial.ptr); closelog(); dbg = dbg_default; options->destroy(options); exit(status); }
void init_agent(bool iscli, char *controller_name, unsigned controller_port, bool try_self_route, bool try_local_router) { operator_table = word_keyvalue_new(); deferred_operand_table = word_keyvalue_new(); size_t i; for (i = 0; i < NSTATA; i++) agent_stat_counter[i] = 0; chunk_ptr msg; bool eof; isclient = iscli; self_route = try_self_route; controller_fd = open_clientfd(controller_name, controller_port); if (controller_fd < 0) err(true, "Cannot create connection to controller at %s:%u", controller_name, controller_port); else { #if RPT >= 2 report(2, "Connection to controller has descriptor %d", controller_fd); #endif } msg = isclient ? msg_new_register_client() : msg_new_register_worker(); bool sok = chunk_write(controller_fd, msg); #if RPT >= 3 report(3, "Sent %s registration to controller", isclient ? "client" : "worker"); #endif chunk_free(msg); if (!sok) err(true, "Could not send registration message to controller"); /* Get acknowledgement from controller */ bool first = true; /* Anticipated number of routers (Will be updated when get first message from controller) */ nrouters = 1; chunk_ptr amsg = NULL; unsigned ridx = 0;; while (ridx < nrouters) { msg = chunk_read_unbuffered(controller_fd, &eof); if (eof) { err(true, "Unexpected EOF from controller while getting router map"); } word_t h = chunk_get_word(msg, 0); unsigned code = msg_get_header_code(h); switch (code) { case MSG_ACK_AGENT: if (first) { own_agent = msg_get_header_agent(h); amsg = msg_new_register_agent(own_agent); nworkers = msg_get_header_workercount(h); nrouters = msg_get_header_wordcount(h); router_fd_array = calloc_or_fail(nrouters, sizeof(int), "init_agent"); #if RPT >= 3 report(3, "Ack from controller. Agent Id %u. %d workers. %d routers.", own_agent, nworkers, nrouters); #endif first = false; } int i; for (i = 1; i < msg->length; i++) { word_t h = chunk_get_word(msg, i); int fd; unsigned ip = msg_get_header_ip(h); unsigned port = msg_get_header_port(h); #if RPT >= 4 report(4, "Attempting to add router %u with ip 0x%x, port %d", ridx, ip, port); #endif fd = open_clientfd_ip(ip, port); if (fd < 0) { err(true, "Couldn't add router with ip 0x%x, port %d", ip, port); } else { router_fd_array[ridx++] = fd; #if RPT >= 3 report(3, "Added router %u with ip 0x%x, port %d, fd %d", ridx, ip, port, fd); #endif if (!chunk_write(fd, amsg)) { err(true, "Couldn't send agent registration message to router with ip 0x%x, port %u", ip, port); } if (try_local_router && local_router_fd == -1 && match_self_ip(ip)) { local_router_fd = fd; #if RPT >= 5 report(5, "Router with fd %d designated as local router and prioritized for sending packets", fd); #endif } } } chunk_free(msg); break; case MSG_NACK: err(true, "Connection request refused."); break; default: err(false, "Unexpected message code %u while getting router information", code); chunk_free(msg); break; } } chunk_free(amsg); #if RPT >= 2 report(2, "All %d routers connected", nrouters); #endif if (isclient) { add_quit_helper(quit_agent); add_cmd("kill", do_agent_kill, " | Shutdown system"); add_cmd("flush", do_agent_flush, " | Flush system"); add_cmd("collect", do_agent_gc, " | Initiate garbage collection"); } else { /* Worker must notify controller that it's ready */ chunk_ptr rmsg = msg_new_worker_ready(own_agent); if (chunk_write(controller_fd, rmsg)) { #if RPT >= 3 report(3, "Notified controller that worker is ready"); #endif } else { err(true, "Couldn't notify controller that worker is ready"); } chunk_free(rmsg); } }
/* Initiate global operation from client. Returns to client when all workers ready to perform their operations */ bool start_client_global(unsigned opcode, unsigned nword, word_t *data) { chunk_ptr rmsg = msg_new_cliop_data(own_agent, opcode, nword, data); if (!chunk_write(controller_fd, rmsg)) { err(false, "Could not send client operation message to controller"); chunk_free(rmsg); return false; } chunk_free(rmsg); /* Read ACK, as well as any other messages the controller might have */ bool done = false; bool ok = true; while (!done) { bool eof = false; chunk_ptr msg = chunk_read_unbuffered(controller_fd, &eof); if (eof) { /* Unexpected EOF */ err(true, "Unexpected EOF from controller (fatal)"); close(controller_fd); done = true; ok = false; } word_t h = chunk_get_word(msg, 0); unsigned code = msg_get_header_code(h); switch (code) { case MSG_DO_FLUSH: chunk_free(msg); #if RPT >= 5 report(5, "Received flush message from controller, superceding client global operation"); #endif if (flush_helper) { flush_helper(); } done = true; ok = false; break; case MSG_STAT: #if RPT >= 5 report(5, "Received summary statistics from controller"); #endif if (stat_helper) { /* Get a copy of the byte usage from memory allocator */ stat_helper(msg); } chunk_free(msg); break; case MSG_KILL: chunk_free(msg); #if RPT >= 1 report(1, "Received kill message from controller, superceding client global operation"); #endif finish_cmd(); done = true; ok = false; break; case MSG_CLIOP_ACK: chunk_free(msg); #if RPT >= 5 report(5, "Received acknowledgement for client global operation"); #endif done = true; ok = true; break; case MSG_GC_START: /* Got notice that should initiate garbage collection. Defer until current operation done */ #if RPT >= 3 report(3, "Deferring GC start"); #endif chunk_free(msg); gc_state = GC_DEFER; break; default: chunk_free(msg); err(false, "Unknown message code %u from controller (ignored)", code); } } return ok; }
void run_worker() { while (true) { /* Select among controller port, and connections to routers */ FD_ZERO(&cset); maxcfd = 0; add_cfd(controller_fd); unsigned ridx; for (ridx = 0; ridx < nrouters; ridx++) add_cfd(router_fd_array[ridx]); buf_select(maxcfd+1, &cset, NULL, NULL, NULL); int fd; for (fd = 0; fd <= maxcfd; fd++) { if (!FD_ISSET(fd, &cset)) continue; bool eof; chunk_ptr msg = chunk_read(fd, &eof); if (eof) { /* Unexpected EOF */ if (fd == controller_fd) { err(true, "Unexpected EOF from controller (fatal)"); } else { err(false, "Unexpected EOF from router with fd %d (shutting down)", fd); finish_cmd(); exit(0); } close(fd); continue; } if (msg == NULL) { err(false, "Could not read chunk from fd %d (ignored)", fd); continue; } word_t h = chunk_get_word(msg, 0); /* Rely on fact that following message fields in same location for both single and double-word headers */ unsigned code = msg_get_header_code(h); unsigned agent = msg_get_header_agent(h); unsigned opcode = msg_get_header_opcode(h); if (fd == controller_fd) { /* Message from controller */ switch(code) { case MSG_KILL: chunk_free(msg); #if RPT >= 1 report(1, "Received kill message from controller"); #endif quit_agent(0, NULL); return; case MSG_DO_FLUSH: chunk_free(msg); #if RPT >= 5 report(5, "Received flush message from controller"); #endif if (flush_helper) { chunk_ptr msg = flush_helper(); if (!msg) break; if (chunk_write(controller_fd, msg)) { #if RPT >= 5 report(5, "Sent statistics information to controller"); #endif } else { err(false, "Failed to send statistics information to controller"); } chunk_free(msg); } break; case MSG_CLIOP_DATA: report(5, "Received client operation data. Agent = %u", agent); word_t *data = &msg->words[1]; unsigned nword = msg->length - 1; if (gop_start_helper) gop_start_helper(agent, opcode, nword, data); chunk_free(msg); chunk_ptr rmsg = msg_new_cliop_ack(agent); if (chunk_write(controller_fd, rmsg)) { #if RPT >= 5 report(5, "Acknowledged client operation data. Agent = %u", agent); #endif } else { err(false, "Failed to acknowledge client operation data. Agent = %u", agent); } chunk_free(rmsg); break; case MSG_CLIOP_ACK: #if RPT >= 5 report(5, "Received client operation ack. Agent = %u", agent); #endif if (gop_finish_helper) gop_finish_helper(agent); chunk_free(msg); break; case MSG_GC_START: chunk_free(msg); gc_start(code); break; case MSG_GC_FINISH: chunk_free(msg); gc_finish(code); break; default: chunk_free(msg); err(false, "Unknown message code %u from controller (ignored)", code); } } else { /* Must be message from router */ switch (code) { case MSG_OPERATION: receive_operation(msg); break; case MSG_OPERAND: receive_operand(msg); break; default: chunk_free(msg); err(false, "Received message with unknown code %u (ignored)", code); } } } } quit_agent(0, NULL); }
void* handle_client_request(void *arg) { struct msghdr *msg; int soc = (int)arg; char * data = (char *) malloc(MAX_BUF_SZ); prepare_msg(0, &msg, data, MAX_BUF_SZ); char * resp; dfs_msg *dfsmsg; int retval = recvmsg(soc, msg, 0); if (retval == -1) { printf("failed to receive message from client - errno-%d\n", errno); } else { dfsmsg = (dfs_msg*)msg->msg_iov[0].iov_base; #ifdef DEBUG printf("received message from client - %d bytes = %d\n", dfsmsg->msg_type, retval); #endif } //extract the message type print_msg(dfsmsg); switch (dfsmsg->msg_type) { case HEARTBEAT: break; case READ_DATA_REQ: resp = (char*) malloc(sizeof(char)*MAX_BUF_SZ); dfsmsg->status = chunk_read(msg->msg_iov[1].iov_base, resp); msg->msg_iov[1].iov_base = resp; msg->msg_iov[1].iov_len = strlen(resp)+1; dfsmsg->msg_type = READ_DATA_RESP; retval = sendmsg(soc, msg, 0); if (retval == -1) { printf("failed to send read reply to client - errno-%d\n", errno); } else { #ifdef DEBUG printf("sent read reply to client\n"); #endif } break; case WRITE_DATA_REQ: dfsmsg->status = chunk_write(msg->msg_iov[1].iov_base); dfsmsg->msg_type = WRITE_DATA_RESP; retval = sendmsg(soc, msg, 0); if (retval == -1) { printf("failed to send write reply to client - errno-%d\n", errno); } else { #ifdef DEBUG printf("sent write reply to client\n"); #endif } break; case ROLLBACK_REQ: dfsmsg->status = chunk_truncate(msg->msg_iov[1].iov_base); dfsmsg->msg_type = ROLLBACK_RESP; retval = sendmsg(soc, msg, 0); if (retval == -1) { printf("failed to send rollback reply to client - errno-%d\n", errno); } else { #ifdef DEBUG printf("sent rollback reply to client\n"); #endif } break; } }
/* Client signals that it has completed the global operation */ bool finish_client_global() { chunk_ptr msg = msg_new_cliop_ack(own_agent); bool ok = chunk_write(controller_fd, msg); chunk_free(msg); return ok; }
static void emit_byte(uint8_t byte) { chunk_write(current_chunk(), byte, parser.previous.line); }
/** * Generate a random level. * * Confusingly, this function also generate the town level (level 0). * \param c is the level we're going to end up with, in practice the global cave * \param p is the current player struct, in practice the global player */ void cave_generate(struct chunk **c, struct player *p) { const char *error = "no generation"; int y, x, tries = 0; struct chunk *chunk; assert(c); /* Generate */ for (tries = 0; tries < 100 && error; tries++) { struct dun_data dun_body; error = NULL; /* Mark the dungeon as being unready (to avoid artifact loss, etc) */ character_dungeon = FALSE; /* Allocate global data (will be freed when we leave the loop) */ dun = &dun_body; dun->cent = mem_zalloc(z_info->level_room_max * sizeof(struct loc)); dun->door = mem_zalloc(z_info->level_door_max * sizeof(struct loc)); dun->wall = mem_zalloc(z_info->wall_pierce_max * sizeof(struct loc)); dun->tunn = mem_zalloc(z_info->tunn_grid_max * sizeof(struct loc)); /* Choose a profile and build the level */ dun->profile = choose_profile(p->depth); chunk = dun->profile->builder(p); if (!chunk) { error = "Failed to find builder"; mem_free(dun->cent); mem_free(dun->door); mem_free(dun->wall); mem_free(dun->tunn); continue; } /* Ensure quest monsters */ if (is_quest(chunk->depth)) { int i; for (i = 1; i < z_info->r_max; i++) { monster_race *r_ptr = &r_info[i]; int y, x; /* The monster must be an unseen quest monster of this depth. */ if (r_ptr->cur_num > 0) continue; if (!rf_has(r_ptr->flags, RF_QUESTOR)) continue; if (r_ptr->level != chunk->depth) continue; /* Pick a location and place the monster */ find_empty(chunk, &y, &x); place_new_monster(chunk, y, x, r_ptr, TRUE, TRUE, ORIGIN_DROP); } } /* Clear generation flags. */ for (y = 0; y < chunk->height; y++) { for (x = 0; x < chunk->width; x++) { sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_INNER); sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_OUTER); sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_SOLID); sqinfo_off(chunk->squares[y][x].info, SQUARE_MON_RESTRICT); } } /* Regenerate levels that overflow their maxima */ if (cave_monster_max(chunk) >= z_info->level_monster_max) error = "too many monsters"; if (error) ROOM_LOG("Generation restarted: %s.", error); mem_free(dun->cent); mem_free(dun->door); mem_free(dun->wall); mem_free(dun->tunn); } if (error) quit_fmt("cave_generate() failed 100 times!"); /* Free the old cave, use the new one */ if (*c) cave_free(*c); *c = chunk; /* Place dungeon squares to trigger feeling (not in town) */ if (player->depth) place_feeling(*c); /* Save the town */ else if (!chunk_find_name("Town")) { struct chunk *town = chunk_write(0, 0, z_info->town_hgt, z_info->town_wid, FALSE, FALSE, FALSE); town->name = string_make("Town"); chunk_list_add(town); } (*c)->feeling = calc_obj_feeling(*c) + calc_mon_feeling(*c); /* Validate the dungeon (we could use more checks here) */ chunk_validate_objects(*c); /* The dungeon is ready */ character_dungeon = TRUE; /* Free old and allocate new known level */ if (cave_k) cave_free(cave_k); cave_k = cave_new(cave->height, cave->width); if (!cave->depth) cave_known(); (*c)->created_at = turn; }
/** * @brief main of scepclient * * @param argc number of arguments * @param argv pointer to the argument values */ int main(int argc, char **argv) { /* external values */ extern char * optarg; extern int optind; /* type of input and output files */ typedef enum { PKCS1 = 0x01, PKCS10 = 0x02, PKCS7 = 0x04, CERT_SELF = 0x08, CERT = 0x10, CACERT_ENC = 0x20, CACERT_SIG = 0x40, } scep_filetype_t; /* filetype to read from, defaults to "generate a key" */ scep_filetype_t filetype_in = 0; /* filetype to write to, no default here */ scep_filetype_t filetype_out = 0; /* input files */ char *file_in_pkcs1 = DEFAULT_FILENAME_PKCS1; char *file_in_pkcs10 = DEFAULT_FILENAME_PKCS10; char *file_in_cert_self = DEFAULT_FILENAME_CERT_SELF; char *file_in_cacert_enc = DEFAULT_FILENAME_CACERT_ENC; char *file_in_cacert_sig = DEFAULT_FILENAME_CACERT_SIG; /* output files */ char *file_out_pkcs1 = DEFAULT_FILENAME_PKCS1; char *file_out_pkcs10 = DEFAULT_FILENAME_PKCS10; char *file_out_pkcs7 = DEFAULT_FILENAME_PKCS7; char *file_out_cert_self = DEFAULT_FILENAME_CERT_SELF; char *file_out_cert = DEFAULT_FILENAME_CERT; char *file_out_ca_cert = DEFAULT_FILENAME_CACERT_ENC; /* by default user certificate is requested */ bool request_ca_certificate = FALSE; /* by default existing files are not overwritten */ bool force = FALSE; /* length of RSA key in bits */ u_int rsa_keylength = DEFAULT_RSA_KEY_LENGTH; /* validity of self-signed certificate */ time_t validity = DEFAULT_CERT_VALIDITY; time_t notBefore = 0; time_t notAfter = 0; /* distinguished name for requested certificate, ASCII format */ char *distinguishedName = NULL; /* challenge password */ char challenge_password_buffer[MAX_PASSWORD_LENGTH]; /* symmetric encryption algorithm used by pkcs7, default is DES */ encryption_algorithm_t pkcs7_symmetric_cipher = ENCR_DES; size_t pkcs7_key_size = 0; /* digest algorithm used by pkcs7, default is MD5 */ hash_algorithm_t pkcs7_digest_alg = HASH_MD5; /* signature algorithm used by pkcs10, default is MD5 */ hash_algorithm_t pkcs10_signature_alg = HASH_MD5; /* URL of the SCEP-Server */ char *scep_url = NULL; /* Name of CA to fetch CA certs for */ char *ca_name = "CAIdentifier"; /* http request method, default is GET */ bool http_get_request = TRUE; /* poll interval time in manual mode in seconds */ u_int poll_interval = DEFAULT_POLL_INTERVAL; /* maximum poll time */ u_int max_poll_time = 0; err_t ugh = NULL; /* initialize library */ if (!library_init(NULL)) { library_deinit(); exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); } if (lib->integrity && !lib->integrity->check_file(lib->integrity, "scepclient", argv[0])) { fprintf(stderr, "integrity check of scepclient failed\n"); library_deinit(); exit(SS_RC_DAEMON_INTEGRITY); } /* initialize global variables */ pkcs1 = chunk_empty; pkcs7 = chunk_empty; serialNumber = chunk_empty; transID = chunk_empty; fingerprint = chunk_empty; encoding = chunk_empty; pkcs10_encoding = chunk_empty; issuerAndSubject = chunk_empty; challengePassword = chunk_empty; getCertInitial = chunk_empty; scep_response = chunk_empty; subjectAltNames = linked_list_create(); options = options_create(); for (;;) { static const struct option long_opts[] = { /* name, has_arg, flag, val */ { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "optionsfrom", required_argument, NULL, '+' }, { "quiet", no_argument, NULL, 'q' }, { "debug", required_argument, NULL, 'l' }, { "in", required_argument, NULL, 'i' }, { "out", required_argument, NULL, 'o' }, { "force", no_argument, NULL, 'f' }, { "httptimeout", required_argument, NULL, 'T' }, { "keylength", required_argument, NULL, 'k' }, { "dn", required_argument, NULL, 'd' }, { "days", required_argument, NULL, 'D' }, { "startdate", required_argument, NULL, 'S' }, { "enddate", required_argument, NULL, 'E' }, { "subjectAltName", required_argument, NULL, 's' }, { "password", required_argument, NULL, 'p' }, { "algorithm", required_argument, NULL, 'a' }, { "url", required_argument, NULL, 'u' }, { "caname", required_argument, NULL, 'c'}, { "method", required_argument, NULL, 'm' }, { "interval", required_argument, NULL, 't' }, { "maxpolltime", required_argument, NULL, 'x' }, { 0,0,0,0 } }; /* parse next option */ int c = getopt_long(argc, argv, "hv+:qi:o:fk:d:s:p:a:u:c:m:t:x:APRCMS", long_opts, NULL); switch (c) { case EOF: /* end of flags */ break; case 'h': /* --help */ usage(NULL); case 'v': /* --version */ version(); case 'q': /* --quiet */ log_to_stderr = FALSE; continue; case 'l': /* --debug <level> */ default_loglevel = atoi(optarg); continue; case 'i': /* --in <type> [= <filename>] */ { char *filename = strstr(optarg, "="); if (filename) { /* replace '=' by '\0' */ *filename = '\0'; /* set pointer to start of filename */ filename++; } if (strcaseeq("pkcs1", optarg)) { filetype_in |= PKCS1; if (filename) file_in_pkcs1 = filename; } else if (strcaseeq("pkcs10", optarg)) { filetype_in |= PKCS10; if (filename) file_in_pkcs10 = filename; } else if (strcaseeq("cacert-enc", optarg)) { filetype_in |= CACERT_ENC; if (filename) file_in_cacert_enc = filename; } else if (strcaseeq("cacert-sig", optarg)) { filetype_in |= CACERT_SIG; if (filename) file_in_cacert_sig = filename; } else if (strcaseeq("cert-self", optarg)) { filetype_in |= CERT_SELF; if (filename) file_in_cert_self = filename; } else { usage("invalid --in file type"); } continue; } case 'o': /* --out <type> [= <filename>] */ { char *filename = strstr(optarg, "="); if (filename) { /* replace '=' by '\0' */ *filename = '\0'; /* set pointer to start of filename */ filename++; } if (strcaseeq("pkcs1", optarg)) { filetype_out |= PKCS1; if (filename) file_out_pkcs1 = filename; } else if (strcaseeq("pkcs10", optarg)) { filetype_out |= PKCS10; if (filename) file_out_pkcs10 = filename; } else if (strcaseeq("pkcs7", optarg)) { filetype_out |= PKCS7; if (filename) file_out_pkcs7 = filename; } else if (strcaseeq("cert-self", optarg)) { filetype_out |= CERT_SELF; if (filename) file_out_cert_self = filename; } else if (strcaseeq("cert", optarg)) { filetype_out |= CERT; if (filename) file_out_cert = filename; } else if (strcaseeq("cacert", optarg)) { request_ca_certificate = TRUE; if (filename) file_out_ca_cert = filename; } else { usage("invalid --out file type"); } continue; } case 'f': /* --force */ force = TRUE; continue; case 'T': /* --httptimeout */ http_timeout = atoi(optarg); if (http_timeout <= 0) { usage("invalid httptimeout specified"); } continue; case '+': /* --optionsfrom <filename> */ if (!options->from(options, optarg, &argc, &argv, optind)) { exit_scepclient("optionsfrom failed"); } continue; case 'k': /* --keylength <length> */ { div_t q; rsa_keylength = atoi(optarg); if (rsa_keylength == 0) usage("invalid keylength"); /* check if key length is a multiple of 8 bits */ q = div(rsa_keylength, 2*BITS_PER_BYTE); if (q.rem != 0) { exit_scepclient("keylength is not a multiple of %d bits!" , 2*BITS_PER_BYTE); } continue; } case 'D': /* --days */ if (optarg == NULL || !isdigit(optarg[0])) { usage("missing number of days"); } else { char *endptr; long days = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || days <= 0) usage("<days> must be a positive number"); validity = 24*3600*days; } continue; case 'S': /* --startdate */ if (optarg == NULL || strlen(optarg) != 13 || optarg[12] != 'Z') { usage("date format must be YYMMDDHHMMSSZ"); } else { chunk_t date = { optarg, 13 }; notBefore = asn1_to_time(&date, ASN1_UTCTIME); } continue; case 'E': /* --enddate */ if (optarg == NULL || strlen(optarg) != 13 || optarg[12] != 'Z') { usage("date format must be YYMMDDHHMMSSZ"); } else { chunk_t date = { optarg, 13 }; notAfter = asn1_to_time(&date, ASN1_UTCTIME); } continue; case 'd': /* --dn */ if (distinguishedName) { usage("only one distinguished name allowed"); } distinguishedName = optarg; continue; case 's': /* --subjectAltName */ { char *value = strstr(optarg, "="); if (value) { /* replace '=' by '\0' */ *value = '\0'; /* set pointer to start of value */ value++; } if (strcaseeq("email", optarg) || strcaseeq("dns", optarg) || strcaseeq("ip", optarg)) { subjectAltNames->insert_last(subjectAltNames, identification_create_from_string(value)); continue; } else { usage("invalid --subjectAltName type"); continue; } } case 'p': /* --password */ if (challengePassword.len > 0) { usage("only one challenge password allowed"); } if (strcaseeq("%prompt", optarg)) { printf("Challenge password: "******"challenge password could not be read"); } } else { challengePassword.ptr = optarg; challengePassword.len = strlen(optarg); } continue; case 'u': /* -- url */ if (scep_url) { usage("only one URL argument allowed"); } scep_url = optarg; continue; case 'c': /* -- caname */ ca_name = optarg; continue; case 'm': /* --method */ if (strcaseeq("get", optarg)) { http_get_request = TRUE; } else if (strcaseeq("post", optarg)) { http_get_request = FALSE; } else { usage("invalid http request method specified"); } continue; case 't': /* --interval */ poll_interval = atoi(optarg); if (poll_interval <= 0) { usage("invalid interval specified"); } continue; case 'x': /* --maxpolltime */ max_poll_time = atoi(optarg); continue; case 'a': /*--algorithm [<type>=]algo */ { const proposal_token_t *token; char *type = optarg; char *algo = strstr(optarg, "="); if (algo) { *algo = '\0'; algo++; } else { type = "enc"; algo = optarg; } if (strcaseeq("enc", type)) { token = lib->proposal->get_token(lib->proposal, algo); if (token == NULL || token->type != ENCRYPTION_ALGORITHM) { usage("invalid algorithm specified"); } pkcs7_symmetric_cipher = token->algorithm; pkcs7_key_size = token->keysize; if (encryption_algorithm_to_oid(token->algorithm, token->keysize) == OID_UNKNOWN) { usage("unsupported encryption algorithm specified"); } } else if (strcaseeq("dgst", type) || strcaseeq("sig", type)) { hash_algorithm_t hash; token = lib->proposal->get_token(lib->proposal, algo); if (token == NULL || token->type != INTEGRITY_ALGORITHM) { usage("invalid algorithm specified"); } hash = hasher_algorithm_from_integrity(token->algorithm, NULL); if (hash == OID_UNKNOWN) { usage("invalid algorithm specified"); } if (strcaseeq("dgst", type)) { pkcs7_digest_alg = hash; } else { pkcs10_signature_alg = hash; } } else { usage("invalid --algorithm type"); } continue; } default: usage("unknown option"); } /* break from loop */ break; } init_log("scepclient"); /* load plugins, further infrastructure may need it */ if (!lib->plugins->load(lib->plugins, NULL, lib->settings->get_str(lib->settings, "scepclient.load", PLUGINS))) { exit_scepclient("plugin loading failed"); } DBG1(DBG_APP, " loaded plugins: %s", lib->plugins->loaded_plugins(lib->plugins)); if ((filetype_out == 0) && (!request_ca_certificate)) { usage("--out filetype required"); } if (request_ca_certificate && (filetype_out > 0 || filetype_in > 0)) { usage("in CA certificate request, no other --in or --out option allowed"); } /* check if url is given, if cert output defined */ if (((filetype_out & CERT) || request_ca_certificate) && !scep_url) { usage("URL of SCEP server required"); } /* check for sanity of --in/--out */ if (!filetype_in && (filetype_in > filetype_out)) { usage("cannot generate --out of given --in!"); } /* get CA cert */ if (request_ca_certificate) { char ca_path[PATH_MAX]; container_t *container; pkcs7_t *pkcs7; if (!scep_http_request(scep_url, chunk_create(ca_name, strlen(ca_name)), SCEP_GET_CA_CERT, http_get_request, http_timeout, &scep_response)) { exit_scepclient("did not receive a valid scep response"); } join_paths(ca_path, sizeof(ca_path), CA_CERT_PATH, file_out_ca_cert); pkcs7 = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7, BUILD_BLOB_ASN1_DER, scep_response, BUILD_END); if (!pkcs7) { /* no PKCS#7 encoded CA+RA certificates, assume simple CA cert */ DBG1(DBG_APP, "unable to parse PKCS#7, assuming plain CA cert"); if (!chunk_write(scep_response, ca_path, "ca cert", 0022, force)) { exit_scepclient("could not write ca cert file '%s'", ca_path); } } else { enumerator_t *enumerator; certificate_t *cert; int ra_certs = 0, ca_certs = 0; int ra_index = 1, ca_index = 1; enumerator = pkcs7->create_cert_enumerator(pkcs7); while (enumerator->enumerate(enumerator, &cert)) { x509_t *x509 = (x509_t*)cert; if (x509->get_flags(x509) & X509_CA) { ca_certs++; } else { ra_certs++; } } enumerator->destroy(enumerator); enumerator = pkcs7->create_cert_enumerator(pkcs7); while (enumerator->enumerate(enumerator, &cert)) { x509_t *x509 = (x509_t*)cert; bool ca_cert = x509->get_flags(x509) & X509_CA; char cert_path[PATH_MAX], *path = ca_path; if (ca_cert && ca_certs > 1) { add_path_suffix(cert_path, sizeof(cert_path), ca_path, "-%.1d", ca_index++); path = cert_path; } else if (!ca_cert) { /* use CA name as base for RA certs */ if (ra_certs > 1) { add_path_suffix(cert_path, sizeof(cert_path), ca_path, "-ra-%.1d", ra_index++); } else { add_path_suffix(cert_path, sizeof(cert_path), ca_path, "-ra"); } path = cert_path; } if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding) || !chunk_write(encoding, path, ca_cert ? "ca cert" : "ra cert", 0022, force)) { exit_scepclient("could not write cert file '%s'", path); } chunk_free(&encoding); } enumerator->destroy(enumerator); container = &pkcs7->container; container->destroy(container); } exit_scepclient(NULL); /* no further output required */ } creds = mem_cred_create(); lib->credmgr->add_set(lib->credmgr, &creds->set); /* * input of PKCS#1 file */ if (filetype_in & PKCS1) /* load an RSA key pair from file */ { char path[PATH_MAX]; join_paths(path, sizeof(path), PRIVATE_KEY_PATH, file_in_pkcs1); private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, BUILD_FROM_FILE, path, BUILD_END); } else /* generate an RSA key pair */ { private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, BUILD_KEY_SIZE, rsa_keylength, BUILD_END); } if (private_key == NULL) { exit_scepclient("no RSA private key available"); } creds->add_key(creds, private_key->get_ref(private_key)); public_key = private_key->get_public_key(private_key); /* check for minimum key length */ if (private_key->get_keysize(private_key) < RSA_MIN_OCTETS / BITS_PER_BYTE) { exit_scepclient("length of RSA key has to be at least %d bits", RSA_MIN_OCTETS * BITS_PER_BYTE); } /* * input of PKCS#10 file */ if (filetype_in & PKCS10) { char path[PATH_MAX]; join_paths(path, sizeof(path), REQ_PATH, file_in_pkcs10); pkcs10_req = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, BUILD_FROM_FILE, path, BUILD_END); if (!pkcs10_req) { exit_scepclient("could not read certificate request '%s'", path); } subject = pkcs10_req->get_subject(pkcs10_req); subject = subject->clone(subject); } else { if (distinguishedName == NULL) { char buf[BUF_LEN]; int n = sprintf(buf, DEFAULT_DN); /* set the common name to the hostname */ if (gethostname(buf + n, BUF_LEN - n) || strlen(buf) == n) { exit_scepclient("no hostname defined, use " "--dn <distinguished name> option"); } distinguishedName = buf; } DBG2(DBG_APP, "dn: '%s'", distinguishedName); subject = identification_create_from_string(distinguishedName); if (subject->get_type(subject) != ID_DER_ASN1_DN) { exit_scepclient("parsing of distinguished name failed"); } DBG2(DBG_APP, "building pkcs10 object:"); pkcs10_req = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, BUILD_SIGNING_KEY, private_key, BUILD_SUBJECT, subject, BUILD_SUBJECT_ALTNAMES, subjectAltNames, BUILD_CHALLENGE_PWD, challengePassword, BUILD_DIGEST_ALG, pkcs10_signature_alg, BUILD_END); if (!pkcs10_req) { exit_scepclient("generating pkcs10 request failed"); } } pkcs10_req->get_encoding(pkcs10_req, CERT_ASN1_DER, &pkcs10_encoding); fingerprint = scep_generate_pkcs10_fingerprint(pkcs10_encoding); DBG1(DBG_APP, " fingerprint: %s", fingerprint.ptr); /* * output of PKCS#10 file */ if (filetype_out & PKCS10) { char path[PATH_MAX]; join_paths(path, sizeof(path), REQ_PATH, file_out_pkcs10); if (!chunk_write(pkcs10_encoding, path, "pkcs10", 0022, force)) { exit_scepclient("could not write pkcs10 file '%s'", path); } filetype_out &= ~PKCS10; /* delete PKCS10 flag */ } if (!filetype_out) { exit_scepclient(NULL); /* no further output required */ } /* * output of PKCS#1 file */ if (filetype_out & PKCS1) { char path[PATH_MAX]; join_paths(path, sizeof(path), PRIVATE_KEY_PATH, file_out_pkcs1); DBG2(DBG_APP, "building pkcs1 object:"); if (!private_key->get_encoding(private_key, PRIVKEY_ASN1_DER, &pkcs1) || !chunk_write(pkcs1, path, "pkcs1", 0066, force)) { exit_scepclient("could not write pkcs1 file '%s'", path); } filetype_out &= ~PKCS1; /* delete PKCS1 flag */ } if (!filetype_out) { exit_scepclient(NULL); /* no further output required */ } scep_generate_transaction_id(public_key, &transID, &serialNumber); DBG1(DBG_APP, " transaction ID: %.*s", (int)transID.len, transID.ptr); /* * read or generate self-signed X.509 certificate */ if (filetype_in & CERT_SELF) { char path[PATH_MAX]; join_paths(path, sizeof(path), HOST_CERT_PATH, file_in_cert_self); x509_signer = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, path, BUILD_END); if (!x509_signer) { exit_scepclient("could not read certificate file '%s'", path); } } else { notBefore = notBefore ? notBefore : time(NULL); notAfter = notAfter ? notAfter : (notBefore + validity); x509_signer = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_SIGNING_KEY, private_key, BUILD_PUBLIC_KEY, public_key, BUILD_SUBJECT, subject, BUILD_NOT_BEFORE_TIME, notBefore, BUILD_NOT_AFTER_TIME, notAfter, BUILD_SERIAL, serialNumber, BUILD_SUBJECT_ALTNAMES, subjectAltNames, BUILD_END); if (!x509_signer) { exit_scepclient("generating certificate failed"); } } creds->add_cert(creds, TRUE, x509_signer->get_ref(x509_signer)); /* * output of self-signed X.509 certificate file */ if (filetype_out & CERT_SELF) { char path[PATH_MAX]; join_paths(path, sizeof(path), HOST_CERT_PATH, file_out_cert_self); if (!x509_signer->get_encoding(x509_signer, CERT_ASN1_DER, &encoding)) { exit_scepclient("encoding certificate failed"); } if (!chunk_write(encoding, path, "self-signed cert", 0022, force)) { exit_scepclient("could not write self-signed cert file '%s'", path); } chunk_free(&encoding); filetype_out &= ~CERT_SELF; /* delete CERT_SELF flag */ } if (!filetype_out) { exit_scepclient(NULL); /* no further output required */ } /* * load ca encryption certificate */ { char path[PATH_MAX]; join_paths(path, sizeof(path), CA_CERT_PATH, file_in_cacert_enc); x509_ca_enc = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, path, BUILD_END); if (!x509_ca_enc) { exit_scepclient("could not load encryption cacert file '%s'", path); } } /* * input of PKCS#7 file */ if (filetype_in & PKCS7) { /* user wants to load a pkcs7 encrypted request * operation is not yet supported! * would require additional parsing of transaction-id pkcs7 = pkcs7_read_from_file(file_in_pkcs7); */ } else { DBG2(DBG_APP, "building pkcs7 request"); pkcs7 = scep_build_request(pkcs10_encoding, transID, SCEP_PKCSReq_MSG, x509_ca_enc, pkcs7_symmetric_cipher, pkcs7_key_size, x509_signer, pkcs7_digest_alg, private_key); if (!pkcs7.ptr) { exit_scepclient("failed to build pkcs7 request"); } } /* * output pkcs7 encrypted and signed certificate request */ if (filetype_out & PKCS7) { char path[PATH_MAX]; join_paths(path, sizeof(path), REQ_PATH, file_out_pkcs7); if (!chunk_write(pkcs7, path, "pkcs7 encrypted request", 0022, force)) { exit_scepclient("could not write pkcs7 file '%s'", path); } filetype_out &= ~PKCS7; /* delete PKCS7 flag */ } if (!filetype_out) { exit_scepclient(NULL); /* no further output required */ } /* * output certificate fetch from SCEP server */ if (filetype_out & CERT) { bool stored = FALSE; certificate_t *cert; enumerator_t *enumerator; char path[PATH_MAX]; time_t poll_start = 0; pkcs7_t *p7; container_t *container = NULL; chunk_t chunk; scep_attributes_t attrs = empty_scep_attributes; join_paths(path, sizeof(path), CA_CERT_PATH, file_in_cacert_sig); x509_ca_sig = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, path, BUILD_END); if (!x509_ca_sig) { exit_scepclient("could not load signature cacert file '%s'", path); } creds->add_cert(creds, TRUE, x509_ca_sig->get_ref(x509_ca_sig)); if (!scep_http_request(scep_url, pkcs7, SCEP_PKI_OPERATION, http_get_request, http_timeout, &scep_response)) { exit_scepclient("did not receive a valid scep response"); } ugh = scep_parse_response(scep_response, transID, &container, &attrs); if (ugh != NULL) { exit_scepclient(ugh); } /* in case of manual mode, we are going into a polling loop */ if (attrs.pkiStatus == SCEP_PENDING) { identification_t *issuer = x509_ca_sig->get_subject(x509_ca_sig); DBG1(DBG_APP, " scep request pending, polling every %d seconds", poll_interval); poll_start = time_monotonic(NULL); issuerAndSubject = asn1_wrap(ASN1_SEQUENCE, "cc", issuer->get_encoding(issuer), subject); } while (attrs.pkiStatus == SCEP_PENDING) { if (max_poll_time > 0 && (time_monotonic(NULL) - poll_start >= max_poll_time)) { exit_scepclient("maximum poll time reached: %d seconds" , max_poll_time); } DBG2(DBG_APP, "going to sleep for %d seconds", poll_interval); sleep(poll_interval); free(scep_response.ptr); container->destroy(container); DBG2(DBG_APP, "fingerprint: %.*s", (int)fingerprint.len, fingerprint.ptr); DBG2(DBG_APP, "transaction ID: %.*s", (int)transID.len, transID.ptr); chunk_free(&getCertInitial); getCertInitial = scep_build_request(issuerAndSubject, transID, SCEP_GetCertInitial_MSG, x509_ca_enc, pkcs7_symmetric_cipher, pkcs7_key_size, x509_signer, pkcs7_digest_alg, private_key); if (!getCertInitial.ptr) { exit_scepclient("failed to build scep request"); } if (!scep_http_request(scep_url, getCertInitial, SCEP_PKI_OPERATION, http_get_request, http_timeout, &scep_response)) { exit_scepclient("did not receive a valid scep response"); } ugh = scep_parse_response(scep_response, transID, &container, &attrs); if (ugh != NULL) { exit_scepclient(ugh); } } if (attrs.pkiStatus != SCEP_SUCCESS) { container->destroy(container); exit_scepclient("reply status is not 'SUCCESS'"); } if (!container->get_data(container, &chunk)) { container->destroy(container); exit_scepclient("extracting signed-data failed"); } container->destroy(container); /* decrypt enveloped-data container */ container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7, BUILD_BLOB_ASN1_DER, chunk, BUILD_END); free(chunk.ptr); if (!container) { exit_scepclient("could not decrypt envelopedData"); } if (!container->get_data(container, &chunk)) { container->destroy(container); exit_scepclient("extracting encrypted-data failed"); } container->destroy(container); /* parse signed-data container */ container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7, BUILD_BLOB_ASN1_DER, chunk, BUILD_END); free(chunk.ptr); if (!container) { exit_scepclient("could not parse singed-data"); } /* no need to verify the signed-data container, the signature does NOT * cover the contained certificates */ /* store the end entity certificate */ join_paths(path, sizeof(path), HOST_CERT_PATH, file_out_cert); p7 = (pkcs7_t*)container; enumerator = p7->create_cert_enumerator(p7); while (enumerator->enumerate(enumerator, &cert)) { x509_t *x509 = (x509_t*)cert; if (!(x509->get_flags(x509) & X509_CA)) { if (stored) { exit_scepclient("multiple certs received, only first stored"); } if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding) || !chunk_write(encoding, path, "requested cert", 0022, force)) { exit_scepclient("could not write cert file '%s'", path); } chunk_free(&encoding); stored = TRUE; } } enumerator->destroy(enumerator); container->destroy(container); chunk_free(&attrs.transID); chunk_free(&attrs.senderNonce); chunk_free(&attrs.recipientNonce); filetype_out &= ~CERT; /* delete CERT flag */ } exit_scepclient(NULL); return -1; /* should never be reached */ }