/* * send 1 unit of backlog, if any, to indicated worker. */ static void crypto_send_backlog(struct pluto_crypto_worker *w) { struct pluto_crypto_req *r; struct pluto_crypto_req_cont *cn; if(backlogqueue_len > 0) { passert(backlog.tqh_first != NULL); cn = backlog.tqh_first; TAILQ_REMOVE(&backlog, cn, pcrc_list); backlogqueue_len--; r = cn->pcrc_pcr; DBG(DBG_CONTROL , DBG_log("removing backlog item id: q#%u from queue: %d left" , r->pcr_id, backlogqueue_len)); /* w points to a worker. Make sure it is live */ if(w->pcw_pid == -1) { init_crypto_helper(w, pc_worker_num); if(w->pcw_pid == -1) { DBG(DBG_CONTROL , DBG_log("found only a dead helper, and failed to restart it")); /* XXX invoke callback with failure */ passert(0); if (pbs_offset(&cn->pcrc_reply_stream)) pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; return; } } /* link it to the active worker list */ TAILQ_INSERT_TAIL(&w->pcw_active, cn, pcrc_list); passert(w->pcw_pid != -1); passert(w->pcw_pipe != -1); passert(w->pcw_work > 0); /* send the request, and then mark the worker as having more work */ if(!crypto_write_request(w, r)) { /* XXX invoke callback with failure */ passert(0); if (pbs_offset(&cn->pcrc_reply_stream)) pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; return; } /* if it was on the backlog, it was saved, free it */ pfree(r); cn->pcrc_pcr = NULL; w->pcw_work++; } }
/* * send 1 unit of backlog, if any, to indicated worker. */ static void crypto_send_backlog(struct pluto_crypto_worker *w) { if (backlog_queue_len > 0) { struct pluto_crypto_req_cont *cn = backlog.tqh_first; struct pluto_crypto_req *r; passert(cn != NULL); TAILQ_REMOVE(&backlog, cn, pcrc_list); backlog_queue_len--; r = cn->pcrc_pcr; DBG(DBG_CONTROL, DBG_log("removing request ID %u from crypto backlog queue; %d left", r->pcr_id, backlog_queue_len)); /* w points to a worker. Make sure it is live */ if (w->pcw_dead) { init_crypto_helper(w, w->pcw_helpernum); if (w->pcw_dead) { DBG(DBG_CONTROL, DBG_log("found only a dead crypto helper %d, and failed to restart it", w->pcw_helpernum)); /* discard request ??? is this the best action? */ /* XXX invoke callback with failure */ passert(FALSE); if (pbs_offset(&cn->pcrc_reply_stream) != 0) { pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; } return; } } /* link it to the active worker list */ TAILQ_INSERT_TAIL(&w->pcw_active, cn, pcrc_list); passert(w->pcw_master_fd != -1); passert(w->pcw_work > 0); /* send the request, and then mark the worker as having more work */ if (!crypto_write_request(w, r)) { /* XXX invoke callback with failure */ passert(FALSE); if (pbs_offset(&cn->pcrc_reply_stream) != 0) pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; return; } /* if it was on the backlog, it was saved, free it */ pfree(r); cn->pcrc_pcr = NULL; w->pcw_work++; } }
void pbs_bytes(pb_stream *pbs, char *out, int *max) { if(max) { if(*max > pbs_offset(pbs)) { *max = pbs_offset(pbs); } } memcpy(out, pbs->start, *max); }
/* * In IKEv1, some implementations (including freeswan/openswan/libreswan) * interpreted the RFC that the whole IKE message must padded to a multiple * of 4 octets, but other implementations (i.e. Checkpoint in Aggressive Mode) * drop padded IKE packets. Some of the text on this topic can be found in the * IKEv1 RFC 2408 section 3.6 Transform Payload. * * The ikepad= option can be set to yes or no on a per-connection basis, * and defaults to yes. * * In IKEv2, there is no padding specified in the RFC and some implementations * will reject IKEv2 messages that are padded. As there are no known IKEv2 * clients that REQUIRE padding, padding is never done for IKEv2. If IKEv2 * clients are discovered in the wild, we will revisit this - please contact * the libreswan developers if you find such an implementation. * Therefor, the ikepad= option has no effect on IKEv2 connections. * * @param pbs PB Stream */ bool close_message(pb_stream *pbs, struct state *st) { size_t padding; if (st->st_ikev2) { DBG(DBG_CONTROLMORE, DBG_log("no IKE message padding required for IKEv2")); close_output_pbs(pbs); return TRUE; } padding = pad_up(pbs_offset(pbs), 4); if (padding != 0 && st != NULL && st->st_connection != NULL && (st->st_connection->policy & POLICY_NO_IKEPAD)) { DBG(DBG_CONTROLMORE, DBG_log("IKEv1 message padding of %zu bytes skipped by policy", padding)); } else if (padding != 0) { DBG(DBG_CONTROLMORE, DBG_log("padding IKEv1 message with %zu bytes", padding)); if (!out_zero(padding, pbs, "message padding")) return FALSE; } else { DBG(DBG_CONTROLMORE, DBG_log("no IKEv1 message padding required")); } close_output_pbs(pbs); return TRUE; }
/** The whole message must be a multiple of 4 octets. * I'm not sure where this is spelled out, but look at * rfc2408 3.6 Transform Payload. * Note: it talks about 4 BYTE boundaries! * * @param pbs PB Stream */ void close_message(pb_stream *pbs) { size_t padding = pad_up(pbs_offset(pbs), 4); if (padding != 0) (void) out_zero(padding, pbs, "message padding"); close_output_pbs(pbs); }
/** The whole message must be a multiple of 4 octets. * I'm not sure where this is spelled out, but look at * rfc2408 3.6 Transform Payload. * Note: it talks about 4 BYTE boundaries! * * @param pbs PB Stream */ void close_message(pb_stream *pbs, struct state *st) { size_t padding = pad_up(pbs_offset(pbs), 4); if (st && st->st_connection && (st->st_connection->policy & POLICY_IKEPAD) == 0) padding = 0; if (padding != 0) (void) out_zero(padding, pbs, "message padding"); close_output_pbs(pbs); }
/* * look for any states attached to continuations * also check the backlog */ static void scrap_crypto_cont(/*TAILQ_HEAD*/ struct req_queue *qh, struct pluto_crypto_req_cont *cn, const char *what) { DBG(DBG_CONTROL, DBG_log("scrapping crypto request ID%u for #%lu from %s", cn->pcrc_id, cn->pcrc_serialno, what)); TAILQ_REMOVE(qh, cn, pcrc_list); if (pbs_offset(&cn->pcrc_reply_stream) != 0) { pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; } pfree(cn); }
/** The whole message must be a multiple of 4 octets. * I'm not sure where this is spelled out, but look at * rfc2408 3.6 Transform Payload. * Note: it talks about 4 BYTE boundaries! * * @param pbs PB Stream */ void close_message(pb_stream *pbs, struct state *st) { size_t padding = pad_up(pbs_offset(pbs), 4); /* Workaround for overzealous Checkpoint firewal */ if (padding && st && st->st_connection && (st->st_connection->policy & POLICY_NO_IKEPAD)) { DBG(DBG_CONTROLMORE, DBG_log("IKE message padding of %lu bytes skipped by policy", padding)); padding = 0; } if (padding != 0) { DBG(DBG_CONTROLMORE, DBG_log("padding IKE message with %lu bytes", padding)); (void) out_zero(padding, pbs, "message padding"); } else { DBG(DBG_CONTROLMORE, DBG_log("no IKE message padding required")); } close_output_pbs(pbs); }
int pbs_append(pb_stream *dest, int destoffset , pb_stream *src, int offset, int length) { /* -1 means end of destination stream */ if(destoffset == -1) { destoffset = pbs_offset(dest); } if(destoffset > pbs_room(dest) || destoffset + length > pbs_room(dest)) { return 0; } if(offset > pbs_room(src) || offset + length > pbs_room(src)) { return 0; } memcpy(&dest->start[destoffset], &src->start[offset], length); if(dest->cur < (dest->start + destoffset + length)) { dest->cur = dest->start + (destoffset + length); } }
int pbs_offset_get(pb_stream *pbs) { return pbs_offset(pbs); }
/* * This function is called when there is socketpair input from a helper. * This is the answer from the helper. * We read the request from the socketpair, and find the associated continuation, * and dispatch to that continuation. * * This function should process only a single answer, and then go back * to the select call to get called again. This is not most efficient, * but is is most fair. * */ static void handle_helper_answer(struct pluto_crypto_worker *w) { struct pluto_crypto_req rr; ssize_t actlen; struct pluto_crypto_req_cont *cn; DBG(DBG_CONTROL, DBG_log("crypto helper %d has finished work (pcw_work now %d)", w->pcw_helpernum, w->pcw_work)); /* read from the socketpair in one gulp */ errno = 0; actlen = read(w->pcw_master_fd, (void *)&rr, sizeof(rr)); if (actlen != sizeof(rr)) { if (actlen == -1) { loglog(RC_LOG_SERIOUS, "read from crypto helper %d failed: %s. Killing helper.", w->pcw_helpernum, strerror(errno)); kill_helper(w); } else if (actlen == 0) { /* EOF: mark worker as dead. */ w->pcw_dead = TRUE; } else if (errno == 0) { loglog(RC_LOG_SERIOUS, "read from crypto helper %d failed with short length %zd of %zu. Killing helper.", w->pcw_helpernum, actlen, sizeof(rr)); kill_helper(w); } else { loglog(RC_LOG_SERIOUS, "read from crypto helper %d failed with short length %zd of %zu (errno=%s). Killing helper.", w->pcw_helpernum, actlen, sizeof(rr), strerror(errno)); kill_helper(w); } return; } if (rr.pcr_len != sizeof(rr)) { loglog(RC_LOG_SERIOUS, "crypto helper %d screwed up length: %zu != %zu; killing it", w->pcw_helpernum, rr.pcr_len, sizeof(rr)); kill_helper(w); return; } DBG(DBG_CONTROL, DBG_log("crypto helper %d replies to request ID %u", w->pcw_helpernum, rr.pcr_id)); /* worker w can accept more work now that we have read from its socketpair */ w->pcw_work--; /* * if there is work queued, then send it off after reading, since this * avoids the most deadlocks */ crypto_send_backlog(w); /* now match up request to continuation, and invoke it */ for (cn = w->pcw_active.tqh_first; cn != NULL && rr.pcr_id != cn->pcrc_id; cn = cn->pcrc_list.tqe_next) ; if (cn == NULL) { loglog(RC_LOG_SERIOUS, "failed to find crypto continuation associated with request ID %u performed by crypto helper %d", rr.pcr_id, w->pcw_helpernum); return; } /* unlink it */ TAILQ_REMOVE(&w->pcw_active, cn, pcrc_list); passert(cn->pcrc_func != NULL); DBG(DBG_CONTROL, DBG_log("calling continuation function %p", cn->pcrc_func)); reply_stream = cn->pcrc_reply_stream; if (pbs_offset(&reply_stream) != 0) { memcpy(reply_stream.start, cn->pcrc_reply_buffer, pbs_offset(&reply_stream)); pfree(cn->pcrc_reply_buffer); } cn->pcrc_reply_buffer = NULL; /* call the continuation (skip if suppressed) */ cn->pcrc_pcr = &rr; reset_cur_state(); if (cn->pcrc_serialno != SOS_NOBODY) (*cn->pcrc_func)(cn, &rr); /* now free up the continuation */ pfree(cn); }
stf_status send_crypto_helper_request(struct pluto_crypto_req *r, struct pluto_crypto_req_cont *cn) { static int pc_worker_num = 0; /* index of last worker assigned work */ struct pluto_crypto_worker *w; /* best worker for task */ struct pluto_crypto_worker *c; /* candidate worker */ struct state *st = cur_state; /* TRANSITIONAL */ /* * transitional: caller must have set pcrc_serialno. * It ought to match cur_state->st_serialno. */ passert(cn->pcrc_serialno == st->st_serialno); passert(st->st_serialno != SOS_NOBODY); cn->pcrc_serialno = st->st_serialno; passert(cn->pcrc_func != NULL); /* do it all ourselves? */ if (pc_workers == NULL) { reset_cur_state(); pluto_do_crypto_op(r, -1); /* call the continuation */ (*cn->pcrc_func)(cn, r); pfree(cn); /* ownership transferred from caller */ /* indicate that we completed the work */ return STF_INLINE; } /* attempt to send to a worker thread */ /* set up the id */ r->pcr_id = pcw_id++; cn->pcrc_id = r->pcr_id; cn->pcrc_pcr = r; /* Find the first of the least-busy workers (if any) */ w = NULL; for (c = pc_workers; c != &pc_workers[pc_workers_cnt]; c++) { DBG(DBG_CONTROL, DBG_log("crypto helper %d%s: pcw_work: %d", pc_worker_num, c->pcw_dead? " DEAD" : "", c->pcw_work)); if (!c->pcw_dead && (w == NULL || c->pcw_work < w->pcw_work)) { w = c; /* c is the best so far */ if (c->pcw_work == 0) break; /* early out: cannot do better */ } } if (w != NULL && (w->pcw_work < w->pcw_maxbasicwork || (w->pcw_work < w->pcw_maxcritwork && r->pcr_pcim > pcim_ongoing_crypto))) { /* allocate task to worker w */ /* link it to the worker's active list * cn transferred from caller */ TAILQ_INSERT_TAIL(&w->pcw_active, cn, pcrc_list); passert(w->pcw_master_fd != -1); cn->pcrc_reply_stream = reply_stream; if (pbs_offset(&reply_stream) != 0) { /* copy partially built reply stream to heap * IMPORTANT: don't leak this. */ cn->pcrc_reply_buffer = clone_bytes(reply_stream.start, pbs_offset(&reply_stream), "saved reply buffer"); } if (!crypto_write_request(w, r)) { /* free the heap space */ if (pbs_offset(&cn->pcrc_reply_stream) != 0) pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; loglog(RC_LOG_SERIOUS, "cannot start crypto helper %d: failed to write", w->pcw_helpernum); return STF_FAIL; } w->pcw_work++; } else if (r->pcr_pcim >= pcim_demand_crypto) { /* Task is important: put it all on the backlog queue for later */ /* cn transferred from caller */ TAILQ_INSERT_TAIL(&backlog, cn, pcrc_list); /* copy the request */ r = clone_bytes(r, r->pcr_len, "saved crypto request"); cn->pcrc_pcr = r; cn->pcrc_reply_stream = reply_stream; if (pbs_offset(&reply_stream) != 0) { /* copy partially built reply stream to heap * IMPORTANT: don't leak this. */ cn->pcrc_reply_buffer = clone_bytes(reply_stream.start, pbs_offset(&reply_stream), "saved reply buffer"); } backlog_queue_len++; DBG(DBG_CONTROL, DBG_log("critical demand crypto operation queued on backlog as %dth item; request ID %u", backlog_queue_len, r->pcr_id)); } else { /* didn't find any available workers */ DBG(DBG_CONTROL, DBG_log("failed to find any available crypto worker (import=%s)", enum_name(&pluto_cryptoimportance_names, r->pcr_pcim))); loglog(RC_LOG_SERIOUS, "cannot start crypto helper: failed to find any available worker"); pfree(cn); /* ownership transferred from caller */ return STF_TOOMUCHCRYPTO; } /* cn ownership transferred on to backlog */ DBG(DBG_CONTROLMORE, DBG_log("#%lu %s:%u st->st_calculating = TRUE;", st->st_serialno, __FUNCTION__, __LINE__)); st->st_calculating = TRUE; delete_event(st); event_schedule(EVENT_CRYPTO_FAILED, EVENT_CRYPTO_FAILED_DELAY, st); return STF_SUSPEND; }
/* * this function is called when there is a helper pipe that is ready. * we read the request from the pipe, and find the associated continuation, * and dispatch to that continuation. * * this function should process only a single answer, and then go back * to the select call to get called again. This is not most efficient, * but is is most fair. * */ void handle_helper_comm(struct pluto_crypto_worker *w) { struct pluto_crypto_req reqbuf[2]; unsigned char *inloc; struct pluto_crypto_req *r; int restlen; int actlen; struct pluto_crypto_req_cont *cn; DBG(DBG_CRYPT|DBG_CONTROL , DBG_log("helper %u has finished work (cnt now %d)" ,w->pcw_helpernum ,w->pcw_work)); /* read from the pipe */ memset(reqbuf, 0, sizeof(reqbuf)); actlen = read(w->pcw_pipe, (char *)reqbuf, sizeof(r->pcr_len)); if(actlen != sizeof(r->pcr_len)) { if(actlen != 0) { loglog(RC_LOG_SERIOUS, "read failed with %d: %s" , actlen, strerror(errno)); } /* * eof, mark worker as dead. If already reaped, then free. */ w->pcw_dead = TRUE; if(w->pcw_reaped) { cleanup_crypto_helper(w, 0); } return; } /* we can accept more work now that we have read from the pipe */ w->pcw_work--; r = &reqbuf[0]; if(r->pcr_len > sizeof(reqbuf)) { loglog(RC_LOG_SERIOUS, "helper(%d) pid=%lu screwed up length: %lu > %lu, killing it" , w->pcw_helpernum , (unsigned long)w->pcw_pid, (unsigned long)r->pcr_len , (unsigned long)sizeof(reqbuf)); killit: #ifdef HAVE_LIBNSS pthread_cancel((pthread_t)w->pcw_pid); #else kill(w->pcw_pid, SIGTERM); #endif w->pcw_dead = TRUE; return; } restlen = r->pcr_len-sizeof(r->pcr_len); inloc = ((unsigned char*)reqbuf)+sizeof(r->pcr_len); while(restlen > 0) { /* okay, got a basic size, read the rest of it */ actlen = read(w->pcw_pipe, inloc, restlen); if(actlen <= 0) { /* faulty read. note this fact, and close pipe. */ /* we actually need to restart this query, but we'll do that * another day. */ loglog(RC_LOG_SERIOUS , "cryptographic handler(%d) read(%d)=%d failed: %s\n" , w->pcw_pipe, restlen, actlen, strerror(errno)); goto killit; } restlen -= actlen; inloc += actlen; } DBG(DBG_CRYPT|DBG_CONTROL, DBG_log("helper %u replies to id: q#%u" ,w->pcw_helpernum ,r->pcr_id)); /* * if there is work queued, then send it off after reading, since this * avoids the most deadlocks */ crypto_send_backlog(w); /* now match up request to continuation, and invoke it */ for(cn = w->pcw_active.tqh_first; cn!=NULL && r->pcr_id != cn->pcrc_id; cn = cn->pcrc_list.tqe_next); if(cn == NULL) { loglog(RC_LOG_SERIOUS , "failed to find continuation associated with req %u\n", (unsigned int)r->pcr_id); return; } /* unlink it */ TAILQ_REMOVE(&w->pcw_active, cn, pcrc_list); passert(cn->pcrc_func != NULL); DBG(DBG_CRYPT, DBG_log("calling callback function %p" ,cn->pcrc_func)); reply_stream = cn->pcrc_reply_stream; if (pbs_offset(&reply_stream)) { memcpy(reply_stream.start, cn->pcrc_reply_buffer , pbs_offset(&reply_stream)); pfree(cn->pcrc_reply_buffer); } cn->pcrc_reply_buffer = NULL; /* call the continuation */ cn->pcrc_pcr = r; reset_cur_state(); (*cn->pcrc_func)(cn, r, NULL); /* now free up the continuation */ pfree(cn); }
/* * look for any states attaches to continuations * also check the backlog */ void delete_cryptographic_continuation(struct state *st) { int i; if(backlogqueue_len > 0) { struct pluto_crypto_req_cont *cn; struct pluto_crypto_req *r; passert(backlog.tqh_first != NULL); for(cn = backlog.tqh_first; cn!=NULL && st->st_serialno != cn->pcrc_serialno; cn = cn->pcrc_list.tqe_next); if(cn != NULL) { TAILQ_REMOVE(&backlog, cn, pcrc_list); backlogqueue_len--; r = cn->pcrc_pcr; DBG(DBG_CONTROL , DBG_log("removing deleted backlog item id: q#%u from queue: %d left" , r->pcr_id, backlogqueue_len)); /* if it was on the backlog, it was saved, free it */ pfree(r); cn->pcrc_pcr = NULL; if (pbs_offset(&cn->pcrc_reply_stream)) pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; } } for(i=0; i<pc_workers_cnt; i++) { struct pluto_crypto_worker *w = &pc_workers[i]; struct pluto_crypto_req_cont *cn; for(cn = w->pcw_active.tqh_first; cn!=NULL && st->st_serialno != cn->pcrc_serialno; cn = cn->pcrc_list.tqe_next); if(cn == NULL) { continue; } /* unlink it, and free it */ TAILQ_REMOVE(&w->pcw_active, cn, pcrc_list); if (pbs_offset(&cn->pcrc_reply_stream)) pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; if(cn->pcrc_free) { /* * use special free function which can deal with other * saved structures. */ (*cn->pcrc_free)(cn, cn->pcrc_pcr, "state removed"); } else { pfree(cn); } } DBG(DBG_CRYPT, DBG_log("no suspended cryptographic state for %lu\n" , st->st_serialno)); }
/* * this function is called with a request to do some cryptographic operations * along with a continuation structure, which will be used to deal with * the response. * * This may fail if there are no helpers that can take any data, in which * case an error is returned. * */ err_t send_crypto_helper_request(struct pluto_crypto_req *r , struct pluto_crypto_req_cont *cn , bool *toomuch) { struct pluto_crypto_worker *w; int cnt; /* do it all ourselves? */ if(pc_workers == NULL) { reset_cur_state(); #ifdef HAVE_LIBNSS pluto_do_crypto_op(r,pc_helper_num); #else pluto_do_crypto_op(r); #endif /* call the continuation */ (*cn->pcrc_func)(cn, r, NULL); /* indicate that we did everything ourselves */ *toomuch = TRUE; pfree(cn); return NULL; } /* set up the id */ r->pcr_id = pcw_id++; cn->pcrc_id = r->pcr_id; cn->pcrc_pcr = r; /* find an available worker */ cnt = pc_workers_cnt; do { pc_worker_num++; if(pc_worker_num >= pc_workers_cnt) { pc_worker_num = 0; } w = &pc_workers[pc_worker_num]; DBG(DBG_CONTROL , DBG_log("%d: w->pcw_dead: %d w->pcw_work: %d cnt: %d", pc_worker_num, w->pcw_dead, w->pcw_work, cnt)); /* see if there is something to clean up after */ if(w->pcw_dead == TRUE && w->pcw_reaped == TRUE) { cleanup_crypto_helper(w, 0); DBG(DBG_CONTROL , DBG_log("clnup %d: w->pcw_dead: %d w->pcw_work: %d cnt: %d", pc_worker_num, w->pcw_dead, w->pcw_work, cnt)); } } while(((w->pcw_work >= w->pcw_maxbasicwork)) && --cnt > 0); if(cnt == 0 && r->pcr_pcim > pcim_ongoing_crypto) { cnt = pc_workers_cnt; while((w->pcw_work >= w->pcw_maxcritwork) && --cnt > 0) { /* find an available worker */ pc_worker_num++; if(pc_worker_num >= pc_workers_cnt) { pc_worker_num = 0; } w = &pc_workers[pc_worker_num]; /* see if there is something to clean up after */ if(w->pcw_dead == TRUE && w->pcw_reaped == TRUE) { cleanup_crypto_helper(w, 0); } } DBG(DBG_CONTROL , DBG_log("crit %d: w->pcw_dead: %d w->pcw_work: %d cnt: %d", pc_worker_num, w->pcw_dead, w->pcw_work, cnt)); } if(cnt == 0 && r->pcr_pcim >= pcim_demand_crypto) { /* it is very important. Put it all on a queue for later */ TAILQ_INSERT_TAIL(&backlog, cn, pcrc_list); /* copy the request */ r = clone_bytes(r, r->pcr_len, "saved cryptorequest"); cn->pcrc_pcr = r; cn->pcrc_reply_stream = reply_stream; if (pbs_offset(&reply_stream)) { cn->pcrc_reply_buffer = clone_bytes(reply_stream.start , pbs_offset(&reply_stream), "saved reply buffer"); } backlogqueue_len++; DBG(DBG_CONTROL , DBG_log("critical demand crypto operation queued on backlog as %d'th item, id: q#%u" , backlogqueue_len, r->pcr_id)); *toomuch = FALSE; return NULL; } if(cnt == 0) { /* didn't find any workers */ DBG(DBG_CONTROL , DBG_log("failed to find any available worker (import=%s)" , enum_name(&pluto_cryptoimportance_names,r->pcr_pcim))); *toomuch = TRUE; return "failed to find any available worker"; } /* w points to a work. Make sure it is live */ if(w->pcw_pid == -1) { init_crypto_helper(w, pc_worker_num); if(w->pcw_pid == -1) { DBG(DBG_CONTROL , DBG_log("found only a dead helper, and failed to restart it")); *toomuch = TRUE; return "failed to start a new helper"; } } /* link it to the active worker list */ TAILQ_INSERT_TAIL(&w->pcw_active, cn, pcrc_list); passert(w->pcw_pid != -1); passert(w->pcw_pipe != -1); passert(w->pcw_work < w->pcw_maxcritwork); cn->pcrc_reply_stream = reply_stream; if (pbs_offset(&reply_stream)) cn->pcrc_reply_buffer = clone_bytes(reply_stream.start , pbs_offset(&reply_stream), "saved reply buffer"); if(!crypto_write_request(w, r)) { openswan_log("failed to write crypto request: %s\n", strerror(errno)); if (pbs_offset(&cn->pcrc_reply_stream)) pfree(cn->pcrc_reply_buffer); cn->pcrc_reply_buffer = NULL; return "failed to write"; } w->pcw_work++; *toomuch = FALSE; return NULL; }
void send_v2_notification(struct state *p1st, u_int16_t type , struct state *encst , u_char *icookie , u_char *rcookie , chunk_t *n_data) { u_char buffer[1024]; pb_stream reply; pb_stream rbody; /* this function is not generic enough yet just enough for 6msg * TBD accept HDR FLAGS as arg. default ISAKMP_FLAGS_R * TBD when there is a child SA use that SPI in the notify paylod. * TBD support encrypted notifications payloads. * TBD accept Critical bit as an argument. default is set. * TBD accept exchange type as an arg, default is ISAKMP_v2_SA_INIT * do we need to send a notify with empty data? * do we need to support more Protocol ID? more than PROTO_ISAKMP */ IPSEC_dbg("sending %snotification %s to %s:%u" , encst ? "encrypted " : "" , enum_name(&ikev2_notify_names, type) , ip_str(&p1st->st_remoteaddr) , p1st->st_remoteport); if(n_data == NULL) { DBG(DBG_CONTROLMORE, DBG_log("don't send packet when notification data empty")); return; } memset(buffer, 0, sizeof(buffer)); init_pbs(&reply, buffer, sizeof(buffer), "notification msg"); /* HDR out */ { struct isakmp_hdr n_hdr ; zero(&n_hdr); /* default to 0 */ /* AAA should we copy from MD? */ n_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION; memcpy(n_hdr.isa_rcookie, rcookie, COOKIE_SIZE); memcpy(n_hdr.isa_icookie, icookie, COOKIE_SIZE); n_hdr.isa_xchg = ISAKMP_v2_SA_INIT; n_hdr.isa_np = ISAKMP_NEXT_v2N; n_hdr.isa_flags &= ~ISAKMP_FLAGS_I; n_hdr.isa_flags |= ISAKMP_FLAGS_R; if (!out_struct(&n_hdr, &isakmp_hdr_desc, &reply, &rbody)) { IPSEC_dbg("error initializing hdr for notify message"); return; } } chunk_t child_spi; child_spi.ptr = NULL; child_spi.len = 0; /* build and add v2N payload to the packet */ ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_CRITICAL, PROTO_ISAKMP, &child_spi,type, n_data, &rbody); close_message(&rbody); close_output_pbs(&reply); clonetochunk(p1st->st_tpacket, reply.start, pbs_offset(&reply) , "notification packet"); ipsec_child_send_packet(p1st, "notification", TRUE); }