/* * this routine takes two proposals and conjoins them (or) */ struct db_sa *sa_merge_proposals(struct db_sa *a, struct db_sa *b) { struct db_sa *n; unsigned int i, j, k; if (a == NULL || a->prop_conj_cnt == 0) return sa_copy_sa(b, 0); if (b == NULL || b->prop_conj_cnt == 0) return sa_copy_sa(a, 0); n = clone_thing(*a, "conjoin sa"); passert(a->prop_conj_cnt == b->prop_conj_cnt); passert(a->prop_conj_cnt == 1); n->prop_conjs = clone_bytes(n->prop_conjs, n->prop_conj_cnt * sizeof(n->prop_conjs[0]), "sa copy prop conj array"); for (i = 0; i < n->prop_conj_cnt; i++) { struct db_prop_conj *pca = &n->prop_conjs[i]; struct db_prop_conj *pcb = &b->prop_conjs[i]; passert(pca->prop_cnt == pcb->prop_cnt); passert(pca->prop_cnt == 1); pca->props = clone_bytes(pca->props, pca->prop_cnt * sizeof(pca->props[0]), "sa copy prop array"); for (j = 0; j < pca->prop_cnt; j++) { struct db_prop *pa = &pca->props[j]; struct db_prop *pb = &pcb->props[j]; struct db_trans *t; int t_cnt = (pa->trans_cnt + pb->trans_cnt); t = alloc_bytes(t_cnt * sizeof(pa->trans[0]), "sa copy trans array"); memcpy(t, pa->trans, (pa->trans_cnt) * sizeof(pa->trans[0])); memcpy(t + (pa->trans_cnt), pb->trans, (pb->trans_cnt) * sizeof(pa->trans[0])); pa->trans = t; pa->trans_cnt = t_cnt; for (k = 0; k < pa->trans_cnt; k++) clone_trans(&pa->trans[k], 0); } } n->parentSA = a->parentSA; return n; }
void clone_trans(struct db_trans *tr, int extra) { tr->attrs = clone_bytes(tr->attrs, (tr->attr_cnt + extra) * sizeof(tr->attrs[0]), "sa copy attrs array"); if (extra) tr->attr_cnt = tr->attr_cnt + extra; }
void clone_propconj(struct db_prop_conj *pc, int extra) { unsigned int i; pc->props = clone_bytes(pc->props , (pc->prop_cnt+extra)*sizeof(pc->props[0]) , "sa copy prop array"); for(i=0; i<pc->prop_cnt; i++) { clone_prop(&pc->props[i], 0); } }
void clone_prop(struct db_prop *p, int extra) { unsigned int i; p->trans = clone_bytes(p->trans , (p->trans_cnt+extra)*sizeof(p->trans[0]) , "sa copy trans array"); for(i=0; i<p->trans_cnt; i++) { clone_trans(&p->trans[i]); } }
static void clone_prop(struct db_prop *p, int extra) { unsigned int i; p->trans = clone_bytes(p->trans, (p->trans_cnt + extra) * sizeof(p->trans[0]), "sa copy trans array"); /* p->trans_cnt is unchanged */ for (i = 0; i < p->trans_cnt; i++) clone_trans(&p->trans[i], 0); }
/* * clone the sa, but keep only the first transform (if any) of the first proposal (if any) * ??? does this make sense? */ struct db_sa *sa_copy_sa_first(struct db_sa *sa) { struct db_sa *nsa; struct db_prop_conj *pc; struct db_prop *p; nsa = clone_thing(*sa, "sa copy prop_conj"); nsa->dynamic = TRUE; if (nsa->prop_conj_cnt == 0) return nsa; nsa->prop_conj_cnt = 1; nsa->prop_conjs = clone_bytes(nsa->prop_conjs, sizeof(nsa->prop_conjs[0]), "sa copy 1 prop conj array"); pc = &nsa->prop_conjs[0]; if (pc->prop_cnt == 0) return nsa; pc->prop_cnt = 1; pc->props = clone_bytes(pc->props, sizeof(pc->props[0]), "sa copy 1 prop array"); p = &pc->props[0]; if (p->trans_cnt == 0) return nsa; p->trans_cnt = 1; p->trans = clone_bytes(p->trans, sizeof(p->trans[0]), "sa copy 1 trans array"); clone_trans(&p->trans[0], 0); return nsa; }
struct db_sa *sa_copy_sa(struct db_sa *sa, int extra) { unsigned int i; struct db_sa *nsa; nsa = clone_thing(*sa, "sa copy prop_conj"); nsa->dynamic = TRUE; nsa->parentSA= sa->parentSA; nsa->prop_conjs = clone_bytes(nsa->prop_conjs , (nsa->prop_conj_cnt+extra)*sizeof(nsa->prop_conjs[0]) , "sa copy prop conj array"); for(i=0; i<nsa->prop_conj_cnt; i++) { clone_propconj(&nsa->prop_conjs[i], 0); } return nsa; }
/* * Make private copy of string in struct id. * This is needed if the result of atoid is to be kept. */ void unshare_id_content(struct id *id) { switch (id->kind) { case ID_FQDN: case ID_USER_FQDN: case ID_DER_ASN1_DN: case ID_KEY_ID: id->name.ptr = clone_bytes(id->name.ptr, id->name.len, "keep id name"); /* Somehow assert we have a valid id here? */ break; case ID_MYID: case ID_FROMCERT: case ID_NONE: case ID_IPV4_ADDR: case ID_IPV6_ADDR: break; default: bad_case(id->kind); } }
/* * add an ietfAttribute to the chained list */ static ietfAttr_t* add_ietfAttr(ietfAttr_t *attr) { ietfAttrList_t **listp = &ietfAttributes; ietfAttrList_t *list = *listp; int cmp = -1; while (list != NULL) { cmp = cmp_ietfAttr(attr, list->attr); if (cmp <= 0) break; listp = &list->next; list = *listp; } if (cmp == 0) { /* attribute already exists, increase count */ pfree(attr); list->attr->count++; return list->attr; } else { ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList"); /* new attribute, unshare value */ attr->value.ptr = clone_bytes(attr->value.ptr, attr->value.len , "attr value"); attr->count = 1; time(&attr->installed); el->attr = attr; el->next = list; *listp = el; return attr; } }
void recv_pcap_packet_gen(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) { struct msg_digest *md; u_int32_t *dlt; struct iphdr *ip; struct udphdr *udp; u_char *ike; const struct iface_port *ifp = &if1; int packet_len; err_t from_ugh; union { struct sockaddr sa; struct sockaddr_in sa_in4; struct sockaddr_in6 sa_in6; } from; md = alloc_md(); dlt = (u_int32_t *)bytes; if (*dlt != PF_INET) return; ip = (struct iphdr *)(dlt + 1); udp = (struct udphdr *)(dlt + ip->ihl + 1); ike = (u_char *)(udp + 1); from.sa_in4.sin_addr.s_addr = ip->saddr; from.sa_in4.sin_port = udp->source; md->iface = ifp; packet_len = h->len - (ike - bytes); happy(anyaddr(addrtypeof(&ifp->ip_addr), &md->sender)); from_ugh = initaddr((void *) &from.sa_in4.sin_addr, sizeof(from.sa_in4.sin_addr), AF_INET, &md->sender); setportof(from.sa_in4.sin_port, &md->sender); md->sender_port = ntohs(from.sa_in4.sin_port); cur_from = &md->sender; cur_from_port = md->sender_port; /* Clone actual message contents * and set up md->packet_pbs to describe it. */ init_pbs(&md->packet_pbs, clone_bytes(ike, packet_len, "message buffer in comm_handle()"), packet_len, "packet"); DBG_log("*received %d bytes from %s:%u on %s (port=%d)", (int) pbs_room(&md->packet_pbs), ip_str(&md->sender), (unsigned) md->sender_port, ifp->ip_dev->id_rname, ifp->port); DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs)); process_packet(&md); if (md != NULL) release_md(md); cur_state = NULL; reset_cur_connection(); cur_from = NULL; }
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 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 clone_trans(struct db_trans *tr) { tr->attrs = clone_bytes(tr->attrs , tr->attr_cnt*sizeof(tr->attrs[0]) , "sa copy attrs array"); }