示例#1
0
/*
 * 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++;
    }
}
示例#2
0
/*
 * 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++;
	}
}
示例#3
0
文件: pbs.c 项目: 1309578252/Openswan
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);
}
示例#4
0
/*
 * 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;
}
示例#5
0
/** 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);
}
示例#6
0
/** 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);
}
示例#7
0
/*
 * 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);
}
示例#8
0
/** 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);
}
示例#9
0
文件: pbs.c 项目: 1309578252/Openswan
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);
    }
}
示例#10
0
文件: pbs.c 项目: 1309578252/Openswan
int pbs_offset_get(pb_stream *pbs) {
    return pbs_offset(pbs);
}
示例#11
0
/*
 * 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);
}
示例#12
0
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;
}
示例#13
0
/*
 * 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);
}
示例#14
0
/*
 * 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));
}
示例#15
0
/*
 * 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;
}
示例#16
0
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);
}