Esempio n. 1
0
/*
 *	The S flag is set only within the EAP-TLS start message sent
 *	from the EAP server to the peer.
 *
 *	Similarly, when the EAP server receives an EAP-Response with
 *	the M bit set, it MUST respond with an EAP-Request with
 *	EAP-Type=EAP-TLS and no data. This serves as a fragment
 *	ACK. The EAP peer MUST wait.
 */
static eaptls_status_t eaptls_verify(EAP_HANDLER *handler)
{
	EAP_DS *eap_ds = handler->eap_ds;
	EAP_DS *prev_eap_ds = handler->prev_eapds;
	eaptls_packet_t	*eaptls_packet, *eaptls_prev = NULL;
	REQUEST *request = handler->request;

	/*
	 *	We don't check ANY of the input parameters.  It's all
	 *	code which works together, so if something is wrong,
	 *	we SHOULD core dump.
	 *
	 *	e.g. if eap_ds is NULL, of if eap_ds->response is
	 *	NULL, of if it's NOT an EAP-Response, or if the packet
	 *	is too short.  See eap_validation()., in ../../eap.c
	 *
	 *	Also, eaptype_select() takes care of selecting the
	 *	appropriate type, so we don't need to check
	 *	eap_ds->response->type.type == PW_EAP_TLS, or anything
	 *	else.
	 */
	eaptls_packet = (eaptls_packet_t *)eap_ds->response->type.data;
	if (prev_eap_ds && prev_eap_ds->response)
		eaptls_prev = (eaptls_packet_t *)prev_eap_ds->response->type.data;

	/*
	 *	check for ACK
	 *
	 *	If there's no TLS data, or there's 1 byte of TLS data,
	 *	with the flags set to zero, then it's an ACK.
	 *
	 *	Find if this is a reply to the previous request sent
	 */
	if ((eaptls_packet == NULL) ||
	    ((eap_ds->response->length == EAP_HEADER_LEN + 2) &&
	     ((eaptls_packet->flags & 0xc0) == 0x00))) {

#if 0
		/*
		 *	Un-comment this for TLS inside of TTLS/PEAP
		 */
		RDEBUG2("Received EAP-TLS ACK message");
		return eaptls_ack_handler(handler);
#else
		if (prev_eap_ds &&
		    (prev_eap_ds->request->id == eap_ds->response->id)) {
			/*
			 *	Run the ACK handler directly from here.
			 */
			RDEBUG2("Received TLS ACK");
			return eaptls_ack_handler(handler);
		} else {
			radlog_request(L_ERR, 0, request, "Received Invalid TLS ACK");
			return EAPTLS_INVALID;
		}
#endif
	}

	/*
	 *	We send TLS_START, but do not receive it.
	 */
	if (TLS_START(eaptls_packet->flags)) {
		RDEBUG("Received unexpected EAP-TLS Start message");
		return EAPTLS_INVALID;
	}

	/*
	 *	The L bit (length included) is set to indicate the
	 *	presence of the four octet TLS Message Length field,
	 *	and MUST be set for the first fragment of a fragmented
	 *	TLS message or set of messages.
	 *
	 *	The M bit (more fragments) is set on all but the last
	 *	fragment.
	 *
	 *	The S bit (EAP-TLS start) is set in an EAP-TLS Start
	 *	message. This differentiates the EAP-TLS Start message
	 *	from a fragment acknowledgement.
	 */
	if (TLS_LENGTH_INCLUDED(eaptls_packet->flags)) {
		DEBUG2("  TLS Length %d",
		       eaptls_packet->data[2] * 256 | eaptls_packet->data[3]);
		if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) {
			/*
			 * FIRST_FRAGMENT is identified
			 * 1. If there is no previous EAP-response received.
			 * 2. If EAP-response received, then its M bit not set.
			 * 	(It is because Last fragment will not have M bit set)
			 */
			if (!prev_eap_ds ||
			    (prev_eap_ds->response == NULL) ||
			    (eaptls_prev == NULL) ||
			    !TLS_MORE_FRAGMENTS(eaptls_prev->flags)) {

				RDEBUG2("Received EAP-TLS First Fragment of the message");
				return EAPTLS_FIRST_FRAGMENT;
			} else {

				RDEBUG2("More Fragments with length included");
				return EAPTLS_MORE_FRAGMENTS_WITH_LENGTH;
			}
		} else {
			RDEBUG2("Length Included");
			return EAPTLS_LENGTH_INCLUDED;
		}
	}

	if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) {
		RDEBUG2("More fragments to follow");
		return EAPTLS_MORE_FRAGMENTS;
	}

	/*
	 *	None of the flags are set, but it's still a valid
	 *	EAPTLS packet.
	 */
	return EAPTLS_OK;
}
Esempio n. 2
0
GLOBAL void UMF_blas3_update
(
    WorkType *Work
)
{
    /* ---------------------------------------------------------------------- */
    /* local variables */
    /* ---------------------------------------------------------------------- */

    Entry *L, *U, *C, *LU ;
    Int i, j, s, k, m, n, d, nb, dc ;
    
#ifndef NBLAS
    Int blas_ok = TRUE ;
#else
#define blas_ok FALSE
#endif

    DEBUG5 (("In UMF_blas3_update "ID" "ID" "ID"\n",
	Work->fnpiv, Work->fnrows, Work->fncols)) ;

    k = Work->fnpiv ;
    if (k == 0)
    {
	/* no work to do */
	return ;
    }

    m = Work->fnrows ;
    n = Work->fncols ;

    d = Work->fnr_curr ;
    dc = Work->fnc_curr ;
    nb = Work->nb ;
    ASSERT (d >= 0 && (d % 2) == 1) ;
    C = Work->Fcblock ;	    /* ldc is fnr_curr */
    L =	Work->Flblock ;	    /* ldl is fnr_curr */
    U = Work->Fublock ;	    /* ldu is fnc_curr, stored by rows */
    LU = Work->Flublock ;   /* nb-by-nb */

#ifndef NDEBUG
    DEBUG5 (("DO RANK-NB UPDATE of frontal:\n")) ;
    DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
    DEBUG7 (("C  block: ")) ; UMF_dump_dense (C,  d, m, n) ;
    DEBUG7 (("A  block: ")) ; UMF_dump_dense (L,  d, m, k) ;
    DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ;
    DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ;
#endif

    if (k == 1)
    {

#ifndef NBLAS
	BLAS_GER (m, n, L, U, C, d) ;
#endif

	if (!blas_ok)
	{
	    /* rank-1 outer product to update the C block */
	    for (j = 0 ; j < n ; j++)
	    {
		Entry u_j = U [j] ;
		if (IS_NONZERO (u_j))
		{
		    Entry *c_ij, *l_is ;
		    c_ij = & C [j*d] ;
		    l_is = & L [0] ;
#pragma ivdep
		    for (i = 0 ; i < m ; i++)
		    {
			/* C [i+j*d]-= L [i] * U [j] */
			MULT_SUB (*c_ij, *l_is, u_j) ;
			c_ij++ ;
			l_is++ ;
		    }
		}
	    }
	}

    }
    else
    {

	/* triangular solve to update the U block */

#ifndef NBLAS
	BLAS_TRSM_RIGHT (n, k, LU, nb, U, dc) ;
#endif

	if (!blas_ok)
	{
	    /* use plain C code if no BLAS at compile time, or if integer
	     * overflow has occurred */
	    for (s = 0 ; s < k ; s++)
	    {
		for (i = s+1 ; i < k ; i++)
		{
		    Entry l_is = LU [i+s*nb] ;
		    if (IS_NONZERO (l_is))
		    {
			Entry *u_ij, *u_sj ;
			u_ij = & U [i*dc] ;
			u_sj = & U [s*dc] ;
#pragma ivdep
			for (j = 0 ; j < n ; j++)
			{
			    /* U [i*dc+j] -= LU [i+s*nb] * U [s*dc+j] ; */
			    MULT_SUB (*u_ij, l_is, *u_sj) ;
			    u_ij++ ;
			    u_sj++ ;
			}
		    }
		}
	    }
	}

	/* rank-k outer product to update the C block */
	/* C = C - L*U' (U is stored by rows, not columns) */

#ifndef NBLAS
	BLAS_GEMM (m, n, k, L, U, dc, C, d) ;
#endif

	if (!blas_ok)
	{
	    /* use plain C code if no BLAS at compile time, or if integer
	     * overflow has occurred */

	    for (s = 0 ; s < k ; s++)
	    {
		for (j = 0 ; j < n ; j++)
		{
		    Entry u_sj = U [j+s*dc] ;
		    if (IS_NONZERO (u_sj))
		    {
			Entry *c_ij, *l_is ;
			c_ij = & C [j*d] ;
			l_is = & L [s*d] ;
#pragma ivdep
			for (i = 0 ; i < m ; i++)
			{
			    /* C [i+j*d]-= L [i+s*d] * U [s*dc+j] */
			    MULT_SUB (*c_ij, *l_is, u_sj) ;
			    c_ij++ ;
			    l_is++ ;
			}
		    }
		}
	    }
	}
    }

#ifndef NDEBUG
    DEBUG5 (("RANK-NB UPDATE of frontal done:\n")) ;
    DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
    DEBUG7 (("C  block: ")) ; UMF_dump_dense (C,  d, m, n) ;
    DEBUG7 (("A  block: ")) ; UMF_dump_dense (L,  d, m, k) ;
    DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ;
    DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ;
#endif

    DEBUG2 (("blas3 "ID" "ID" "ID"\n", k, Work->fnrows, Work->fncols)) ;
}
Esempio n. 3
0
GLOBAL void UMF_garbage_collection
(
    NumericType *Numeric,
    WorkType *Work,
    Int drnew,	    /* compact current front to drnew-by-dcnew */
    Int dcnew,
    Int do_Fcpos
)
{
    /* ---------------------------------------------------------------------- */
    /* local variables */
    /* ---------------------------------------------------------------------- */

    Int size, e, n_row, n_col, nrows, ncols, nrowsleft, ncolsleft, prevsize,
	csize, size2, i2, j2, i, j, cdeg, rdeg, *E, row, col,
	*Rows, *Cols, *Rows2, *Cols2, nel, e2, *Row_tuples, *Col_tuples,
	*Row_degree, *Col_degree ;
    Entry *C, *C1, *C3, *C2 ;
    Unit *psrc, *pdest, *p, *pnext ;
    Element *epsrc, *epdest ;

#ifndef NDEBUG
    Int nmark ;
#endif

    /* ---------------------------------------------------------------------- */
    /* get parameters */
    /* ---------------------------------------------------------------------- */

    Col_degree = Numeric->Cperm ;	/* for NON_PIVOTAL_COL macro */
    Row_degree = Numeric->Rperm ;	/* for NON_PIVOTAL_ROW macro */
    Row_tuples = Numeric->Uip ;
    Col_tuples = Numeric->Lip ;
    E = Work->E ;
    n_row = Work->n_row ;
    n_col = Work->n_col ;

    /* note that the tuple lengths (Col_tlen and Row_tlen) are updated, but */
    /* the tuple lists themselves are stale and are about to be destroyed */
    /* and recreated.  Do not attempt to scan them until they are recreated. */

#ifndef NDEBUG
    DEBUGm1 (("::::GARBAGE COLLECTION::::\n")) ;
    UMF_dump_memory (Numeric) ;
#endif

    Numeric->ngarbage++ ;

    /* ---------------------------------------------------------------------- */
    /* delete the tuple lists by marking the blocks as free */
    /* ---------------------------------------------------------------------- */

    /* do not modify Row_tlen and Col_tlen */
    /* those are needed for UMF_build_tuples */

    for (row = 0 ; row < n_row ; row++)
    {
	if (NON_PIVOTAL_ROW (row) && Row_tuples [row])
	{
	    DEBUG2 (("row "ID" tuples "ID"\n", row, Row_tuples [row])) ;
	    p = Numeric->Memory + Row_tuples [row] - 1 ;
	    DEBUG2 (("Freeing tuple list row "ID", p-S "ID", size "ID"\n",
		row, (Int) (p-Numeric->Memory), p->header.size)) ;
	    ASSERT (p->header.size > 0) ;
	    ASSERT (p >= Numeric->Memory + Numeric->itail) ;
	    ASSERT (p < Numeric->Memory + Numeric->size) ;
	    p->header.size = -p->header.size ;
	    Row_tuples [row] = 0 ;
	}
    }

    for (col = 0 ; col < n_col ; col++)
    {
	if (NON_PIVOTAL_COL (col) && Col_tuples [col])
	{
	    DEBUG2 (("col "ID" tuples "ID"\n", col, Col_tuples [col])) ;
	    p = Numeric->Memory + Col_tuples [col] - 1 ;
	    DEBUG2 (("Freeing tuple list col "ID", p-S "ID", size "ID"\n",
		col, (Int) (p-Numeric->Memory), p->header.size)) ;
	    ASSERT (p->header.size > 0) ;
	    ASSERT (p >= Numeric->Memory + Numeric->itail) ;
	    ASSERT (p < Numeric->Memory + Numeric->size) ;
	    p->header.size = -p->header.size ;
	    Col_tuples [col] = 0 ;
	}
    }

    /* ---------------------------------------------------------------------- */
    /* mark the elements, and compress the name space */
    /* ---------------------------------------------------------------------- */

    nel = Work->nel ;
    ASSERT (nel < Work->elen) ;

#ifndef NDEBUG
    nmark = 0 ;
    UMF_dump_current_front (Numeric, Work, FALSE) ;
    DEBUGm1 (("E [0] "ID"  \n", E [0])) ;
    ASSERT (IMPLIES (E [0],
		Work->Flublock == (Entry *) (Numeric->Memory + E [0]))) ;
    ASSERT (IMPLIES (Work->Flublock,
		Work->Flublock == (Entry *) (Numeric->Memory + E [0]))) ;
    ASSERT ((E [0] != 0) == (Work->Flublock != (Entry *) NULL)) ;
#endif

    e2 = 0 ;

    for (e = 0 ; e <= nel ; e++) /* for all elements in order of creation */
    {
	if (E [e])
	{
	    psrc = Numeric->Memory + E [e] ;
	    psrc-- ;		/* get the header of this block */
	    if (e > 0)
	    {
		e2++ ;	/* do not renumber element zero */
	    }
	    ASSERT (psrc->header.size > 0) ;
	    psrc->header.size = e2  ;	/* store the new name in the header */
#ifndef NDEBUG
	    nmark++ ;
#endif
	    DEBUG7 ((ID":: Mark e "ID" at psrc-S "ID", new e "ID"\n",
		nmark, e, (Int) (psrc-Numeric->Memory), e2)) ;
	    E [e] = 0 ;
	    if (e == Work->prior_element)
	    {
		Work->prior_element = e2 ;
	    }
	}
    }

    /* all 1..e2 are now in use (element zero may or may not be in use) */
    Work->nel = e2 ;
    nel = Work->nel ;

#ifndef NDEBUG
    for (e = 0 ; e < Work->elen ; e++)
    {
	ASSERT (!E [e]) ;
    }
#endif

    /* ---------------------------------------------------------------------- */
    /* compress the elements */
    /* ---------------------------------------------------------------------- */

    /* point to tail marker block of size 1 + header */
    psrc = Numeric->Memory + Numeric->size - 2 ;
    pdest = psrc ;
    prevsize = psrc->header.prevsize ;
    DEBUG7 (("Starting the compression:\n")) ;

    while (prevsize > 0)
    {

	/* ------------------------------------------------------------------ */
	/* move up to the next element above the current header, and */
	/* get the element name and size */
	/* (if it is an element, the name will be positive) */
	/* ------------------------------------------------------------------ */

	size = prevsize ;
	psrc -= (size + 1) ;
	e = psrc->header.size ;
	prevsize = psrc->header.prevsize ;
	/* top block at tail has prevsize of 0 */

	/* a free block will have a negative size, so skip it */
	/* otherwise, if size >= 0, it holds the element name, not the size */

	DEBUG8 (("psrc-S: "ID" prevsize: "ID" size: "ID,
	    (Int) (psrc-Numeric->Memory), prevsize, size)) ;

	if (e == 0)
	{
	    /* -------------------------------------------------------------- */
	    /* this is the current frontal matrix */
	    /* -------------------------------------------------------------- */

	    Entry *F1, *F2, *Fsrc, *Fdst ;
	    Int c, r, k, dr, dc, gap, gap1, gap2, nb ;

	    /* shift the frontal matrix down */
	    F1 = (Entry *) (psrc + 1) ;

	    /* get the size of the current front.  r and c could be zero */
	    k = Work->fnpiv ;
	    dr = Work->fnr_curr ;
	    dc = Work->fnc_curr ;
	    r = Work->fnrows ;
	    c = Work->fncols ;
	    nb = Work->nb ;

	    ASSERT ((dr >= 0 && (dr % 2) == 1) || dr == 0) ;
	    ASSERT (drnew >= 0) ;
	    if (drnew % 2 == 0)
	    {
		/* make sure leading frontal matrix dimension is always odd */
		drnew++ ;
	    }
	    drnew = MIN (dr, drnew) ;
	    ASSERT ((drnew >= 0 && (drnew % 2) == 1) || drnew == 0) ;

	    pnext = pdest ;

#ifndef NDEBUG
	    DEBUGm2 (("move front: dr "ID" dc "ID" r "ID" drnew "ID" c "ID
		" dcnew " ID" k "ID"\n", dr, dc, r, drnew, c, dcnew, k)) ;
	    DEBUG7 (("\n")) ;
	    DEBUG7 ((ID":: Move current frontal matrix from: psrc-S: "ID" \n",
		nmark, (Int) (psrc-Numeric->Memory))) ;
	    nmark-- ;
	    ASSERT (E [e] == 0) ;
	    ASSERT (Work->Flublock == F1) ;
	    ASSERT (Work->Flblock  == Work->Flublock + nb*nb) ;
	    ASSERT (Work->Fublock  == Work->Flblock  + dr*nb) ;
	    ASSERT (Work->Fcblock  == Work->Fublock  + nb*dc) ;
	    DEBUG7 (("C  block: ")) ;
	    UMF_dump_dense (Work->Fcblock,  dr, r, c) ;
	    DEBUG7 (("L  block: ")) ;
	    UMF_dump_dense (Work->Flblock,  dr, r, k);
	    DEBUG7 (("U' block: ")) ;
	    UMF_dump_dense (Work->Fublock,  dc, c, k) ;
	    DEBUG7 (("LU block: ")) ;
	    UMF_dump_dense (Work->Flublock, nb, k, k) ;
	    ASSERT (r <= drnew && c <= dcnew && drnew <= dr && dcnew <= dc) ;
#endif

	    /* compact frontal matrix to drnew-by-dcnew before moving it */

	    /* do not compact the LU block (nb-by-nb) */

	    /* compact the columns of L (from dr-by-nb to drnew-by-nb) */
	    Fsrc = Work->Flblock ;
	    Fdst = Work->Flblock ;
	    ASSERT (Fdst == F1 + nb*nb) ;
	    gap1 = dr - r ;
	    gap2 = drnew - r ;
	    ASSERT (gap1 >= 0) ;
	    for (j = 0 ; j < k ; j++)
	    {
		for (i = 0 ; i < r ; i++)
		{
		    *Fdst++ = *Fsrc++ ;
		}
		Fsrc += gap1 ;
		Fdst += gap2 ;
	    }
	    ASSERT (Fdst == F1 + nb*nb + drnew*k) ;
	    Fdst += drnew * (nb - k) ;

	    /* compact the rows of U (U' from dc-by-nb to dcnew-by-nb) */
	    Fsrc = Work->Fublock ;
	    ASSERT (Fdst == F1 + nb*nb + drnew*nb) ;
	    gap1 = dc - c ;
	    gap2 = dcnew - c ;
	    for (i = 0 ; i < k ; i++)
	    {
		for (j = 0 ; j < c ; j++)
		{
		    *Fdst++ = *Fsrc++ ;
		}
		Fsrc += gap1 ;
		Fdst += gap2 ;
	    }
	    ASSERT (Fdst == F1 + nb*nb + drnew*nb + dcnew*k) ;
	    Fdst += dcnew * (nb - k) ;

	    /* compact the columns of C (from dr-by-dc to drnew-by-dcnew) */
	    Fsrc = Work->Fcblock ;
	    ASSERT (Fdst == F1 + nb*nb + drnew*nb + nb*dcnew) ;
	    gap1 = dr - r ;
	    gap2 = drnew - r ;
	    for (j = 0 ; j < c ; j++)
	    {
		for (i = 0 ; i < r ; i++)
		{
		    *Fdst++ = *Fsrc++ ;
		}
		Fsrc += gap1 ;
		Fdst += gap2 ;
	    }
	    ASSERT (Fdst == F1 + nb*nb + drnew*nb + nb*dcnew + drnew*c) ;

	    /* recompute Fcpos, if necessary */
	    if (do_Fcpos)
	    {
		Int *Fcols, *Fcpos ;
		Fcols = Work->Fcols ;
		Fcpos = Work->Fcpos ;
		for (j = 0 ; j < c ; j++)
		{
		    col = Fcols [j] ;
		    ASSERT (col >= 0 && col < Work->n_col) ;
		    ASSERT (Fcpos [col] == j * dr) ;
		    Fcpos [col] = j * drnew ;
		}
#ifndef NDEBUG
		{
		    Int cnt = 0 ;
		    for (j = 0 ; j < Work->n_col ; j++)
		    {
			if (Fcpos [j] != EMPTY) cnt++ ;
		    }
		    DEBUGm2 (("Recompute Fcpos cnt "ID" c "ID"\n", cnt, c)) ;
		    ASSERT (cnt == c) ;
		}
#endif
	    }

#ifndef NDEBUG
	    DEBUGm2 (("Compacted front, drnew "ID" dcnew "ID"\n", drnew, dcnew)) ;
	    DEBUG7 (("C  block: ")) ;
	    UMF_dump_dense (F1 + nb*nb + drnew*nb + nb*dcnew, drnew, r, c) ;
	    DEBUG7 (("L  block: ")) ;
	    UMF_dump_dense (F1 + nb*nb, drnew, r, k) ;
	    DEBUG7 (("U  block: ")) ;
	    UMF_dump_dense (F1 + nb*nb + drnew*nb, nb, k, c) ;
	    DEBUG7 (("LU block: ")) ;
	    UMF_dump_dense (F1, nb, k, k) ;
#endif

	    /* Compacted dimensions of the new frontal matrix. */
	    Work->fnr_curr = drnew ;
	    Work->fnc_curr = dcnew ;
	    Work->fcurr_size = (drnew + nb) * (dcnew + nb) ;
	    size = UNITS (Entry, Work->fcurr_size) ;

	    /* make sure the object doesn't evaporate.  The front can have
	     * zero size (Work->fcurr_size = 0), but the size of the memory
	     * block containing it cannot have zero size. */
	    size = MAX (1, size) ;

	    /* get the destination of frontal matrix */
	    pnext->header.prevsize = size ;
	    pdest -= (size + 1) ;
	    F2 = (Entry *) (pdest + 1) ;

	    ASSERT ((unsigned Int) psrc + 1 + size <= (unsigned Int) pnext) ;
	    ASSERT (psrc <= pdest) ;
	    ASSERT (F1 <= F2) ;

	    /* move the C block first */
	    Fsrc = F1 + nb*nb + drnew*nb + nb*dcnew + drnew*c ;
	    Fdst = F2 + nb*nb + drnew*nb + nb*dcnew + drnew*c ;
	    gap = drnew - r ;
	    for (j = c-1 ; j >= 0 ; j--)
	    {
		Fsrc -= gap ;
		Fdst -= gap ;
		/* move column j of C */
		for (i = r-1 ; i >= 0 ; i--)
		{
		    *--Fdst = *--Fsrc ;
		}
	    }
	    ASSERT (Fsrc == F1 + nb*nb + drnew*nb + nb*dcnew) ;
	    ASSERT (Fdst == F2 + nb*nb + drnew*nb + nb*dcnew) ;

	    /* move the U block */
	    Fsrc -= dcnew * (nb - k) ;
	    Fdst -= dcnew * (nb - k) ;
	    ASSERT (Fsrc == F1 + nb*nb + drnew*nb + dcnew*k) ;
	    ASSERT (Fdst == F2 + nb*nb + drnew*nb + dcnew*k) ;
	    gap = dcnew - c ;
	    for (i = k-1 ; i >= 0 ; i--)
	    {
		Fsrc -= gap ;
		Fdst -= gap ;
		for (j = c-1 ; j >= 0 ; j--)
		{
		    *--Fdst = *--Fsrc ;
		}
	    }
	    ASSERT (Fsrc == F1 + nb*nb + drnew*nb) ;
	    ASSERT (Fdst == F2 + nb*nb + drnew*nb) ;

	    /* move the L block */
	    Fsrc -= drnew * (nb - k) ;
	    Fdst -= drnew * (nb - k) ;
	    ASSERT (Fsrc == F1 + nb*nb + drnew*k) ;
	    ASSERT (Fdst == F2 + nb*nb + drnew*k) ;
	    gap = drnew - r ;
	    for (j = k-1 ; j >= 0 ; j--)
	    {
		Fsrc -= gap ;
		Fdst -= gap ;
		for (i = r-1 ; i >= 0 ; i--)
		{
		    *--Fdst = *--Fsrc ;
		}
	    }
	    ASSERT (Fsrc == F1 + nb*nb) ;
	    ASSERT (Fdst == F2 + nb*nb) ;

	    /* move the LU block */
	    Fsrc -= nb * (nb - k) ;
	    Fdst -= nb * (nb - k) ;
	    ASSERT (Fsrc == F1 + nb*k) ;
	    ASSERT (Fdst == F2 + nb*k) ;
	    gap = nb - k ;
	    for (j = k-1 ; j >= 0 ; j--)
	    {
		Fsrc -= gap ;
		Fdst -= gap ;
		for (i = k-1 ; i >= 0 ; i--)
		{
		    *--Fdst = *--Fsrc ;
		}
	    }
	    ASSERT (Fsrc == F1) ;
	    ASSERT (Fdst == F2) ;

	    E [0] = (pdest + 1) - Numeric->Memory ;

	    Work->Flublock = (Entry *) (Numeric->Memory + E [0]) ;
	    ASSERT (Work->Flublock == F2) ;
	    Work->Flblock  = Work->Flublock + nb * nb ;
	    Work->Fublock  = Work->Flblock  + drnew * nb ;
	    Work->Fcblock  = Work->Fublock  + nb * dcnew ;

	    pdest->header.prevsize = 0 ;
	    pdest->header.size = size ;

#ifndef NDEBUG
	    DEBUG7 (("After moving compressed current frontal matrix:\n")) ;
	    DEBUG7 (("C  block: ")) ;
	    UMF_dump_dense (Work->Fcblock,  drnew, r, c) ;
	    DEBUG7 (("L  block: ")) ;
	    UMF_dump_dense (Work->Flblock,  drnew, r, k);
	    DEBUG7 (("U' block: ")) ;
	    UMF_dump_dense (Work->Fublock,  dcnew, c, k) ;
	    DEBUG7 (("LU block: ")) ;
	    UMF_dump_dense (Work->Flublock, nb, k, k) ;
#endif

	}
	else if (e > 0)
	{

	    /* -------------------------------------------------------------- */
	    /* this is an element, compress and move from psrc down to pdest */
	    /* -------------------------------------------------------------- */

#ifndef NDEBUG
	    DEBUG7 (("\n")) ;
	    DEBUG7 ((ID":: Move element "ID": from: "ID" \n",
		nmark, e, (Int) (psrc-Numeric->Memory))) ;
	    nmark-- ;
	    ASSERT (e <= nel) ;
	    ASSERT (E [e] == 0) ;
#endif

	    /* -------------------------------------------------------------- */
	    /* get the element scalars, and pointers to C, Rows, and Cols: */
	    /* -------------------------------------------------------------- */

	    p = psrc + 1 ;
	    GET_ELEMENT (epsrc, p, Cols, Rows, ncols, nrows, C) ;
	    nrowsleft = epsrc->nrowsleft ;
	    ncolsleft = epsrc->ncolsleft ;
	    cdeg = epsrc->cdeg ;
	    rdeg = epsrc->rdeg ;

#ifndef NDEBUG
	    DEBUG7 ((" nrows "ID" nrowsleft "ID"\n", nrows, nrowsleft)) ;
	    DEBUG7 ((" ncols "ID" ncolsleft "ID"\n", ncols, ncolsleft)) ;
	    DEBUG8 ((" Rows:")) ;
	    for (i = 0 ; i < nrows ; i++) DEBUG8 ((" "ID, Rows [i])) ;
	    DEBUG8 (("\n Cols:")) ;
	    for (j = 0 ; j < ncols ; j++) DEBUG8 ((" "ID, Cols [j])) ;
	    DEBUG8 (("\n")) ;
#endif

	    /* -------------------------------------------------------------- */
	    /* determine the layout of the new element */
	    /* -------------------------------------------------------------- */

	    csize = nrowsleft * ncolsleft ;
	    size2 = UNITS (Element, 1)
		  + UNITS (Int, nrowsleft + ncolsleft)
		  + UNITS (Entry, csize) ;

	    DEBUG7 (("Old size "ID" New size "ID"\n", size, size2)) ;

	    pnext = pdest ;
	    pnext->header.prevsize = size2 ;
	    pdest -= (size2 + 1) ;

	    ASSERT (size2 <= size) ;
	    ASSERT ((unsigned Int) psrc + 1 + size <= (unsigned Int) pnext) ;
	    ASSERT (psrc <= pdest) ;

	    p = pdest + 1 ;
	    epdest = (Element *) p ;
	    p += UNITS (Element, 1) ;
	    Cols2 = (Int *) p ;
	    Rows2 = Cols2 + ncolsleft ;
	    p += UNITS (Int, nrowsleft + ncolsleft) ;
	    C2 = (Entry *) p ;

	    ASSERT (epdest >= epsrc) ;
	    ASSERT (Rows2 >= Rows) ;
	    ASSERT (Cols2 >= Cols) ;
	    ASSERT (C2 >= C) ;
	    ASSERT (p + UNITS (Entry, csize) == pnext) ;

	    /* -------------------------------------------------------------- */
	    /* move the contribution block */
	    /* -------------------------------------------------------------- */

	    /* overlap = psrc + size + 1 > pdest ; */

	    if (nrowsleft < nrows || ncolsleft < ncols)
	    {

		/* ---------------------------------------------------------- */
		/* compress contribution block in place prior to moving it */
		/* ---------------------------------------------------------- */

		DEBUG7 (("Compress C in place prior to move:\n"));
#ifndef NDEBUG
		UMF_dump_dense (C, nrows, nrows, ncols) ;
#endif
		C1 = C ;
		C3 = C ;
		for (j = 0 ; j < ncols ; j++)
		{
		    if (Cols [j] >= 0)
		    {
			for (i = 0 ; i < nrows ; i++)
			{
			    if (Rows [i] >= 0)
			    {
				*C3++ = C1 [i] ;
			    }
			}
		    }
		    C1 += nrows ;
		}
		ASSERT (C3-C == csize) ;
		DEBUG8 (("Newly compressed contrib. block (all in use):\n")) ;
#ifndef NDEBUG
		UMF_dump_dense (C, nrowsleft, nrowsleft, ncolsleft) ;
#endif
	    }

	    /* shift the contribution block down */
	    C += csize ;
	    C2 += csize ;
	    for (i = 0 ; i < csize ; i++)
	    {
		*--C2 = *--C ;
	    }

	    /* -------------------------------------------------------------- */
	    /* move the row indices */
	    /* -------------------------------------------------------------- */

	    i2 = nrowsleft ;
	    for (i = nrows - 1 ; i >= 0 ; i--)
	    {
		ASSERT (Rows2+i2 >= Rows+i) ;
		if (Rows [i] >= 0)
		{
		    Rows2 [--i2] = Rows [i] ;
		}
	    }
	    ASSERT (i2 == 0) ;

	    j2 = ncolsleft ;
	    for (j = ncols - 1 ; j >= 0 ; j--)
	    {
		ASSERT (Cols2+j2 >= Cols+j) ;
		if (Cols [j] >= 0)
		{
		    Cols2 [--j2] = Cols [j] ;
		}
	    }
	    ASSERT (j2 == 0) ;

	    /* -------------------------------------------------------------- */
	    /* construct the new header */
	    /* -------------------------------------------------------------- */

	    /* E [0...e] is now valid */
	    E [e] = (pdest + 1) - Numeric->Memory ;
	    epdest = (Element *) (pdest + 1) ;

	    epdest->next = EMPTY ;	/* destroys the son list */
	    epdest->ncols = ncolsleft ;
	    epdest->nrows = nrowsleft ;
	    epdest->ncolsleft = ncolsleft ;
	    epdest->nrowsleft = nrowsleft ;
	    epdest->rdeg = rdeg ;
	    epdest->cdeg = cdeg ;

	    ASSERT (size2 <= size) ;
	    pdest->header.prevsize = 0 ;
	    pdest->header.size = size2 ;

	    DEBUG7 (("After moving it:\n")) ;
#ifndef NDEBUG
	    UMF_dump_element (Numeric, Work, e, FALSE) ;
#endif
	}

#ifndef NDEBUG
	else
	{
	    DEBUG8 ((" free\n")) ;
	}
#endif
	DEBUG7 (("psrc "ID"  tail "ID"\n",
	(Int) (psrc-Numeric->Memory), Numeric->itail)) ;
    }

    ASSERT (psrc == Numeric->Memory + Numeric->itail) ;
    ASSERT (nmark == 0) ;

    /* ---------------------------------------------------------------------- */
    /* final tail pointer */
    /* ---------------------------------------------------------------------- */

    ASSERT (pdest >= Numeric->Memory + Numeric->itail) ;
    Numeric->itail = pdest - Numeric->Memory ;
    pdest->header.prevsize = 0 ;
    Numeric->ibig = EMPTY ;
    Numeric->tail_usage = Numeric->size - Numeric->itail ;

    /* ---------------------------------------------------------------------- */
    /* clear the unused E [nel+1 .. Work->elen - 1] */
    /* ---------------------------------------------------------------------- */

    for (e = nel+1 ; e < Work->elen ; e++)
    {
	E [e] = 0 ;
    }

#ifndef NDEBUG
    UMF_dump_packed_memory (Numeric, Work) ;
#endif

    DEBUG8 (("::::GARBAGE COLLECTION DONE::::\n")) ;
}
Esempio n. 4
0
/** Write the result of a get or getnext operation back to net-snmp
 *
 * Returns three lines of output per attribute:
 * - OID string
 * - type
 * - value
 *
 * Index attributes (num 0) must be in order of depth (shallowest first).
 *
 * If no attributes were written, will write "NONE\n" to inform net-snmp
 * that no value was available at the specified OID.
 *
 * @param fd to write to.
 * @param root of the SNMP portion of the main dictionary.
 * @param type attribute.
 * @param head of list of attributes to convert and write.
 * @return
 *	- >=0 on success (the number of varbind responses written).
 *	- -1 on failure.
 */
static int radsnmp_get_response(int fd,
				fr_dict_attr_t const *root, fr_dict_attr_t const *type,
				VALUE_PAIR *head)
{
	fr_cursor_t		cursor;
	VALUE_PAIR		*vp, *type_vp;
	fr_dict_attr_t const	*parent = root;
	unsigned int		written = 0;

	ssize_t			slen;
	size_t			len;

	char			type_buff[32];	/* type */
	size_t			type_len = 0;
	char			oid_buff[256];
	char			value_buff[128];
	char			*p = oid_buff, *end = p + sizeof(oid_buff);

	struct iovec		io_vector[6];

	char			newline[] = "\n";

	type_buff[0] = '\0';

	/*
	 *	Print first part of OID string.
	 */
	slen = snprintf(oid_buff, sizeof(oid_buff), "%u.", parent->attr);
	if (is_truncated((size_t)slen, sizeof(oid_buff))) {
	oob:
		fr_strerror_printf("OID Buffer too small");
		return -1;
	}
	p += slen;

	/*
	 *	@fixme, this is very dependent on ordering
	 *
	 *	This code should be reworked when we have proper
	 *	attribute grouping to coalesce all related index
	 *	attributes under a single request OID.
	 */
	 for (vp = fr_cursor_init(&cursor, &head);
	      vp;
	      vp = fr_cursor_next(&cursor)) {
	      	fr_dict_attr_t const *common;
	      	/*
	      	 *	We only care about TLV attributes beneath our root
	      	 */
		if (!fr_dict_parent_common(root, vp->da, true)) continue;

		/*
		 *	Sanity checks to ensure we're processing attributes
		 *	in the right order.
		 */
		common = fr_dict_parent_common(parent, vp->da, true);
		if (!common) {
			fr_strerror_printf("Out of order index attributes.  \"%s\" is not a child of \"%s\"",
					   vp->da->name, parent->name);
			return -1;
		}

		/*
		 *	Index attribute
		 */
		if (vp->da->attr == 0) {
			/*
			 *	Print OID from last index/root up to the parent of
			 *	the index attribute.
			 */
			slen = fr_dict_print_attr_oid(p, end - p, parent, vp->da->parent);
			if (slen < 0) return -1;

			if (vp->vp_type != FR_TYPE_UINT32) {
				fr_strerror_printf("Index attribute \"%s\" is not of type \"integer\"", vp->da->name);
				return -1;
			}

			if (slen >= (end - p)) goto oob;
			p += slen;

			/*
			 *	Add the value of the index attribute as the next
			 *	OID component.
			 */
			len = snprintf(p, end - p, ".%i.", vp->vp_uint32);
			if (is_truncated(len, end - p)) goto oob;

			p += len;

			/*
			 *	Set the parent to be the attribute representing
			 *	the entry.
			 */
			parent = fr_dict_attr_child_by_num(vp->da->parent, 1);
			continue;
		}

		/*
		 *	Actual TLV attribute
		 */
		slen = fr_dict_print_attr_oid(p, end - p, parent, vp->da);
		if (slen < 0) return -1;

		/*
		 *	Next attribute should be the type
		 */
		type_vp = fr_cursor_next(&cursor);
		if (!type_vp || (type_vp->da != type)) {
			fr_strerror_printf("No %s found in response, or occurred out of order", type->name);
			return -1;
		}
		type_len = fr_pair_value_snprint(type_buff, sizeof(type_buff), type_vp, '\0');

		/*
		 *	Build up the vector
		 *
		 *	This represents output for a single varbind attribute
		 */
		io_vector[0].iov_base = oid_buff;
		io_vector[0].iov_len = strlen(oid_buff);
		io_vector[1].iov_base = newline;
		io_vector[1].iov_len = 1;
		io_vector[2].iov_base = type_buff;
		io_vector[2].iov_len = type_len;
		io_vector[3].iov_base = newline;
		io_vector[3].iov_len = 1;

		switch (vp->vp_type) {
		case FR_TYPE_OCTETS:
			memcpy(&io_vector[4].iov_base, &vp->vp_strvalue, sizeof(io_vector[4].iov_base));
			io_vector[4].iov_len = vp->vp_length;
			break;

		case FR_TYPE_STRING:
			memcpy(&io_vector[4].iov_base, &vp->vp_strvalue, sizeof(io_vector[4].iov_base));
			io_vector[4].iov_len = vp->vp_length;
			break;

		default:
			/*
			 *	We call fr_value_box_snprint with a NULL da pointer
			 *	because we always need return integer values not
			 *	value aliases.
			 */
			len = fr_value_box_snprint(value_buff, sizeof(value_buff), &vp->data, '\0');
			if (is_truncated(len, sizeof(value_buff))) {
				fr_strerror_printf("Insufficient fixed value buffer");
				return -1;
			}
			io_vector[4].iov_base = value_buff;
			io_vector[4].iov_len = len;
			break;
		}
		io_vector[5].iov_base = newline;
		io_vector[5].iov_len = 1;

		DEBUG2("said: %s", (char *)io_vector[0].iov_base);
		DEBUG2("said: %s", (char *)io_vector[2].iov_base);
		DEBUG2("said: %s", (char *)io_vector[4].iov_base);

		if (writev(fd, io_vector, sizeof(io_vector) / sizeof(*io_vector)) < 0) {
			fr_strerror_printf("Failed writing varbind result: %s", fr_syserror(errno));
			return -1;
		}

		/*
		 *	Reset in case we're encoding multiple values
		 */
		parent = root;
		p = oid_buff;
		type_buff[0] = '\0';
		written++;
	}

	if (!written && (write(fd, "NONE\n", 5)) < 0) {
		fr_strerror_printf("Failed writing get response: %s", fr_syserror(errno));
		return -1;
	}

	return written;
}
int main(int argc, char **argv)
{
	RADIUS_PACKET *req;
	char *p;
	int c;
	int port = 0;
	char *filename = NULL;
	FILE *fp;
	int id;
	int force_af = AF_UNSPEC;

	/*
	 *	We probably don't want to free the talloc autofree context
	 *	directly, so we'll allocate a new context beneath it, and
	 *	free that before any leak reports.
	 */
	TALLOC_CTX *autofree = talloc_init("main");

	id = ((int)getpid() & 0xff);
	fr_debug_flag = 0;

	radlog_dest = L_DST_STDERR;

	set_radius_dir(autofree, RADIUS_DIR);

	while ((c = getopt(argc, argv, "46c:d:D:f:hi:qst:r:S:xXv")) != EOF)
	{
		switch(c) {
		case '4':
			force_af = AF_INET;
			break;
		case '6':
			force_af = AF_INET6;
			break;
		case 'd':
			set_radius_dir(autofree, optarg);
			break;
		case 'D':
			mainconfig.dictionary_dir = talloc_typed_strdup(NULL, optarg);
			break;
		case 'f':
			filename = optarg;
			break;
		case 'q':
			do_output = 0;
			break;
		case 'x':
			debug_flag++;
			fr_debug_flag++;
			break;

		case 'X':
#if 0
		  sha1_data_problems = 1; /* for debugging only */
#endif
		  break;



		case 'r':
			if (!isdigit((int) *optarg))
				usage();
			retries = atoi(optarg);
			break;
		case 'i':
			if (!isdigit((int) *optarg))
				usage();
			id = atoi(optarg);
			if ((id < 0) || (id > 255)) {
				usage();
			}
			break;
		case 's':
			do_summary = 1;
			break;
		case 't':
			if (!isdigit((int) *optarg))
				usage();
			timeout = atof(optarg);
			break;
		case 'v':
			printf("radeapclient: $Id: 20c518ef414933fae3cdf564852c12e483f7c8c9 $ built on " __DATE__ " at " __TIME__ "\n");
			exit(0);
			break;
	       case 'S':
		       fp = fopen(optarg, "r");
		       if (!fp) {
			       fprintf(stderr, "radclient: Error opening %s: %s\n",
				       optarg, fr_syserror(errno));
			       exit(1);
		       }
		       if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
			       fprintf(stderr, "radclient: Error reading %s: %s\n",
				       optarg, fr_syserror(errno));
			       exit(1);
		       }
		       fclose(fp);

		       /* truncate newline */
		       p = filesecret + strlen(filesecret) - 1;
		       while ((p >= filesecret) &&
			      (*p < ' ')) {
			       *p = '\0';
			       --p;
		       }

		       if (strlen(filesecret) < 2) {
			       fprintf(stderr, "radclient: Secret in %s is too short\n", optarg);
			       exit(1);
		       }
		       secret = filesecret;
		       break;
		case 'h':
		default:
			usage();
			break;
		}
	}
	argc -= (optind - 1);
	argv += (optind - 1);

	if ((argc < 3)  ||
	    ((!secret) && (argc < 4))) {
		usage();
	}

	if (!mainconfig.dictionary_dir) {
		mainconfig.dictionary_dir = DICTDIR;
	}

	/*
	 *	Read the distribution dictionaries first, then
	 *	the ones in raddb.
	 */
	DEBUG2("including dictionary file %s/%s", mainconfig.dictionary_dir, RADIUS_DICTIONARY);
	if (dict_init(mainconfig.dictionary_dir, RADIUS_DICTIONARY) != 0) {
		ERROR("Errors reading dictionary: %s",
		      fr_strerror());
		exit(1);
	}

	/*
	 *	It's OK if this one doesn't exist.
	 */
	int rcode = dict_read(radius_dir, RADIUS_DICTIONARY);
	if (rcode == -1) {
		ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY,
		      fr_strerror());
		exit(1);
	}

	/*
	 *	We print this after reading it.  That way if
	 *	it doesn't exist, it's OK, and we don't print
	 *	anything.
	 */
	if (rcode == 0) {
		DEBUG2("including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY);
	}

	req = rad_alloc(NULL, 1);
	if (!req) {
		fr_perror("radclient");
		exit(1);
	}

#if 0
	{
		FILE *randinit;

		if((randinit = fopen("/dev/urandom", "r")) == NULL)
		{
			perror("/dev/urandom");
		} else {
			fread(randctx.randrsl, 256, 1, randinit);
			fclose(randinit);
		}
	}
	fr_randinit(&randctx, 1);
#endif

	req->id = id;

	/*
	 *	Resolve hostname.
	 */
	if (force_af == AF_UNSPEC) force_af = AF_INET;
	req->dst_ipaddr.af = force_af;
	if (strcmp(argv[1], "-") != 0) {
		char const *hostname = argv[1];
		char const *portname = argv[1];
		char buffer[256];

		if (*argv[1] == '[') { /* IPv6 URL encoded */
			p = strchr(argv[1], ']');
			if ((size_t) (p - argv[1]) >= sizeof(buffer)) {
				usage();
			}

			memcpy(buffer, argv[1] + 1, p - argv[1] - 1);
			buffer[p - argv[1] - 1] = '\0';

			hostname = buffer;
			portname = p + 1;

		}
		p = strchr(portname, ':');
		if (p && (strchr(p + 1, ':') == NULL)) {
			*p = '\0';
			portname = p + 1;
		} else {
			portname = NULL;
		}

		if (ip_hton(hostname, force_af, &req->dst_ipaddr) < 0) {
			fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno));
			exit(1);
		}

		/*
		 *	Strip port from hostname if needed.
		 */
		if (portname) port = atoi(portname);
	}

	/*
	 *	See what kind of request we want to send.
	 */
	if (strcmp(argv[2], "auth") == 0) {
		if (port == 0) port = getport("radius");
		if (port == 0) port = PW_AUTH_UDP_PORT;
		req->code = PW_CODE_AUTHENTICATION_REQUEST;

	} else if (strcmp(argv[2], "acct") == 0) {
		if (port == 0) port = getport("radacct");
		if (port == 0) port = PW_ACCT_UDP_PORT;
		req->code = PW_CODE_ACCOUNTING_REQUEST;
		do_summary = 0;

	} else if (strcmp(argv[2], "status") == 0) {
		if (port == 0) port = getport("radius");
		if (port == 0) port = PW_AUTH_UDP_PORT;
		req->code = PW_CODE_STATUS_SERVER;

	} else if (strcmp(argv[2], "disconnect") == 0) {
		if (port == 0) port = PW_POD_UDP_PORT;
		req->code = PW_CODE_DISCONNECT_REQUEST;

	} else if (isdigit((int) argv[2][0])) {
		if (port == 0) port = getport("radius");
		if (port == 0) port = PW_AUTH_UDP_PORT;
		req->code = atoi(argv[2]);
	} else {
		usage();
	}
	req->dst_port = port;

	/*
	 *	Add the secret.
	 */
	if (argv[3]) secret = argv[3];

	/*
	 *	Read valuepairs.
	 *	Maybe read them, from stdin, if there's no
	 *	filename, or if the filename is '-'.
	 */
	if (filename && (strcmp(filename, "-") != 0)) {
		fp = fopen(filename, "r");
		if (!fp) {
			fprintf(stderr, "radclient: Error opening %s: %s\n",
				filename, fr_syserror(errno));
			exit(1);
		}
	} else {
		fp = stdin;
	}

	/*
	 *	Send request.
	 */
	if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("radclient: socket: ");
		exit(1);
	}

	while(!filedone) {
		if(req->vps) pairfree(&req->vps);

		if ((req->vps = readvp2(NULL, fp, &filedone, "radeapclient:")) == NULL) {
			break;
		}

		sendrecv_eap(req);
	}

	if(do_summary) {
		printf("\n\t   Total approved auths:  %d\n", totalapp);
		printf("\t     Total denied auths:  %d\n", totaldeny);
	}

	talloc_free(autofree);

	return 0;
}
Esempio n. 6
0
GLOBAL void UMF_kernel_wrapup
(
    NumericType *Numeric,
    SymbolicType *Symbolic,
    WorkType *Work
)
{

    /* ---------------------------------------------------------------------- */
    /* local variables */
    /* ---------------------------------------------------------------------- */

    Entry pivot_value ;
    double d ;
    Entry *D ;
    Int i, k, col, row, llen, ulen, *ip, *Rperm, *Cperm, *Lilen, npiv, lp,
	*Uilen, *Lip, *Uip, *Cperm_init, up, pivrow, pivcol, *Lpos, *Upos, *Wr,
	*Wc, *Wp, *Frpos, *Fcpos, *Row_degree, *Col_degree, *Rperm_init,
	n_row, n_col, n_inner, zero_pivot, nan_pivot, n1 ;

#ifndef NDEBUG
    UMF_dump_matrix (Numeric, Work, FALSE) ;
#endif

    DEBUG0 (("Kernel complete, Starting Kernel wrapup\n")) ;
    n_row = Symbolic->n_row ;
    n_col = Symbolic->n_col ;
    n_inner = MIN (n_row, n_col) ;
    Rperm = Numeric->Rperm ;
    Cperm = Numeric->Cperm ;
    Lilen = Numeric->Lilen ;
    Uilen = Numeric->Uilen ;
    Upos = Numeric->Upos ;
    Lpos = Numeric->Lpos ;
    Lip = Numeric->Lip ;
    Uip = Numeric->Uip ;
    D = Numeric->D ;

    npiv = Work->npiv ;
    Numeric->npiv = npiv ;
    Numeric->ulen = Work->ulen ;

    ASSERT (n_row == Numeric->n_row) ;
    ASSERT (n_col == Symbolic->n_col) ;
    DEBUG0 (("Wrap-up: npiv "ID" ulen "ID"\n", npiv, Numeric->ulen)) ;
    ASSERT (npiv <= n_inner) ;

    /* this will be nonzero only if matrix is singular or rectangular */
    ASSERT (IMPLIES (npiv == n_col, Work->ulen == 0)) ;

    /* ---------------------------------------------------------------------- */
    /* find the smallest and largest entries in D */
    /* ---------------------------------------------------------------------- */

    for (k = 0 ; k < npiv ; k++)
    {
	pivot_value = D [k] ;
	ABS (d, pivot_value) ;
	zero_pivot = SCALAR_IS_ZERO (d) ;
	nan_pivot = SCALAR_IS_NAN (d) ;

	if (!zero_pivot)
	{
	    /* the pivot is nonzero, but might be Inf or NaN */
	    Numeric->nnzpiv++ ;
	}

	if (k == 0)
	{
	    Numeric->min_udiag = d ;
	    Numeric->max_udiag = d ;
	}
	else
	{
	    /* min (abs (diag (U))) behaves as follows:  If any entry is zero,
	       then the result is zero (regardless of the presence of NaN's).
	       Otherwise, if any entry is NaN, then the result is NaN.
	       Otherwise, the result is the smallest absolute value on the
	       diagonal of U.
	    */

	    if (SCALAR_IS_NONZERO (Numeric->min_udiag))
	    {
		if (zero_pivot || nan_pivot)
		{
		    Numeric->min_udiag = d ;
		}
		else if (!SCALAR_IS_NAN (Numeric->min_udiag))
		{
		    /* d and min_udiag are both non-NaN */
		    Numeric->min_udiag = MIN (Numeric->min_udiag, d) ;
		}
	    }

	    /*
	       max (abs (diag (U))) behaves as follows:  If any entry is NaN
	       then the result is NaN.  Otherise, the result is the largest
	       absolute value on the diagonal of U.
	    */

	    if (nan_pivot)
	    {
		Numeric->max_udiag = d ;
	    }
	    else if (!SCALAR_IS_NAN (Numeric->max_udiag))
	    {
		/* d and max_udiag are both non-NaN */
		Numeric->max_udiag = MAX (Numeric->max_udiag, d) ;
	    }
	}
    }

    /* ---------------------------------------------------------------------- */
    /* check if matrix is singular or rectangular */
    /* ---------------------------------------------------------------------- */

    Col_degree = Cperm ;	/* for NON_PIVOTAL_COL macro */
    Row_degree = Rperm ;	/* for NON_PIVOTAL_ROW macro */

    if (npiv < n_row)
    {
	/* finalize the row permutation */
	k = npiv ;
	DEBUGm3 (("Singular pivot rows "ID" to "ID"\n", k, n_row-1)) ;
	for (row = 0 ; row < n_row ; row++)
	{
	    if (NON_PIVOTAL_ROW (row))
	    {
		Rperm [row] = ONES_COMPLEMENT (k) ;
		DEBUGm3 (("Singular row "ID" is k: "ID" pivot row\n", row, k)) ;
		ASSERT (!NON_PIVOTAL_ROW (row)) ;
		Lpos [row] = EMPTY ;
		Uip [row] = EMPTY ;
		Uilen [row] = 0 ;
		k++ ;
	    }
	}
	ASSERT (k == n_row) ;
    }

    if (npiv < n_col)
    {
	/* finalize the col permutation */
	k = npiv ;
	DEBUGm3 (("Singular pivot cols "ID" to "ID"\n", k, n_col-1)) ;
	for (col = 0 ; col < n_col ; col++)
	{
	    if (NON_PIVOTAL_COL (col))
	    {
		Cperm [col] = ONES_COMPLEMENT (k) ;
		DEBUGm3 (("Singular col "ID" is k: "ID" pivot row\n", col, k)) ;
		ASSERT (!NON_PIVOTAL_COL (col)) ;
		Upos [col] = EMPTY ;
		Lip [col] = EMPTY ;
		Lilen [col] = 0 ;
		k++ ;
	    }
	}
	ASSERT (k == n_col) ;
    }

    if (npiv < n_inner)
    {
	/* finalize the diagonal of U */
	DEBUGm3 (("Diag of U is zero, "ID" to "ID"\n", npiv, n_inner-1)) ;
	for (k = npiv ; k < n_inner ; k++)
	{
	    CLEAR (D [k]) ;
	}
    }

    /* save the pattern of the last row of U */
    if (Numeric->ulen > 0)
    {
	DEBUGm3 (("Last row of U is not empty\n")) ;
	Numeric->Upattern = Work->Upattern ;
	Work->Upattern = (Int *) NULL ;
    }

    DEBUG2 (("Nnzpiv: "ID"  npiv "ID"\n", Numeric->nnzpiv, npiv)) ;
    ASSERT (Numeric->nnzpiv <= npiv) ;
    if (Numeric->nnzpiv < n_inner && !SCALAR_IS_NAN (Numeric->min_udiag))
    {
	/* the rest of the diagonal is zero, so min_udiag becomes 0,
	 * unless it is already NaN. */
	Numeric->min_udiag = 0.0 ;
    }

    /* ---------------------------------------------------------------------- */
    /* size n_row, n_col workspaces that can be used here: */
    /* ---------------------------------------------------------------------- */

    Frpos = Work->Frpos ;	/* of size n_row+1 */
    Fcpos = Work->Fcpos ;	/* of size n_col+1 */
    Wp = Work->Wp ;		/* of size MAX(n_row,n_col)+1 */
    /* Work->Upattern ;		cannot be used (in Numeric) */
    Wr = Work->Lpattern ;	/* of size n_row+1 */
    Wc = Work->Wrp ;		/* of size n_col+1 or bigger */

    /* ---------------------------------------------------------------------- */
    /* construct Rperm from inverse permutations */
    /* ---------------------------------------------------------------------- */

    /* use Frpos for temporary copy of inverse row permutation [ */

    for (pivrow = 0 ; pivrow < n_row ; pivrow++)
    {
	k = Rperm [pivrow] ;
	ASSERT (k < 0) ;
	k = ONES_COMPLEMENT (k) ;
	ASSERT (k >= 0 && k < n_row) ;
	Wp [k] = pivrow ;
	Frpos [pivrow] = k ;
    }
    for (k = 0 ; k < n_row ; k++)
    {
	Rperm [k] = Wp [k] ;
    }

    /* ---------------------------------------------------------------------- */
    /* construct Cperm from inverse permutation */
    /* ---------------------------------------------------------------------- */

    /* use Fcpos for temporary copy of inverse column permutation [ */

    for (pivcol = 0 ; pivcol < n_col ; pivcol++)
    {
	k = Cperm [pivcol] ;
	ASSERT (k < 0) ;
	k = ONES_COMPLEMENT (k) ;
	ASSERT (k >= 0 && k < n_col) ;
	Wp [k] = pivcol ;
	/* save a copy of the inverse column permutation in Fcpos */
	Fcpos [pivcol] = k ;
    }
    for (k = 0 ; k < n_col ; k++)
    {
	Cperm [k] = Wp [k] ;
    }

#ifndef NDEBUG
    for (k = 0 ; k < n_col ; k++)
    {
	col = Cperm [k] ;
	ASSERT (col >= 0 && col < n_col) ;
	ASSERT (Fcpos [col] == k) ;		/* col is the kth pivot */
    }
    for (k = 0 ; k < n_row ; k++)
    {
	row = Rperm [k] ;
	ASSERT (row >= 0 && row < n_row) ;
	ASSERT (Frpos [row] == k) ;		/* row is the kth pivot */
    }
#endif

#ifndef NDEBUG
    UMF_dump_lu (Numeric) ;
#endif

    /* ---------------------------------------------------------------------- */
    /* permute Lpos, Upos, Lilen, Lip, Uilen, and Uip */
    /* ---------------------------------------------------------------------- */

    for (k = 0 ; k < npiv ; k++)
    {
	pivrow = Rperm [k] ;
	Wr [k] = Uilen [pivrow] ;
	Wp [k] = Uip [pivrow] ;
    }

    for (k = 0 ; k < npiv ; k++)
    {
	Uilen [k] = Wr [k] ;
	Uip [k] = Wp [k] ;
    }

    for (k = 0 ; k < npiv ; k++)
    {
	pivrow = Rperm [k] ;
	Wp [k] = Lpos [pivrow] ;
    }

    for (k = 0 ; k < npiv ; k++)
    {
	Lpos [k] = Wp [k] ;
    }

    for (k = 0 ; k < npiv ; k++)
    {
	pivcol = Cperm [k] ;
	Wc [k] = Lilen [pivcol] ;
	Wp [k] = Lip [pivcol] ;
    }

    for (k = 0 ; k < npiv ; k++)
    {
	Lilen [k] = Wc [k] ;
	Lip [k] = Wp [k] ;
    }

    for (k = 0 ; k < npiv ; k++)
    {
	pivcol = Cperm [k] ;
	Wp [k] = Upos [pivcol] ;
    }

    for (k = 0 ; k < npiv ; k++)
    {
	Upos [k] = Wp [k] ;
    }

    /* ---------------------------------------------------------------------- */
    /* terminate the last Uchain and last Lchain */
    /* ---------------------------------------------------------------------- */

    Upos [npiv] = EMPTY ;
    Lpos [npiv] = EMPTY ;
    Uip [npiv] = EMPTY ;
    Lip [npiv] = EMPTY ;
    Uilen [npiv] = 0 ;
    Lilen [npiv] = 0 ;

    /* ---------------------------------------------------------------------- */
    /* convert U to the new pivot order */
    /* ---------------------------------------------------------------------- */

    n1 = Symbolic->n1 ;

    for (k = 0 ; k < n1 ; k++)
    {
	/* this is a singleton row of U */
	ulen = Uilen [k] ;
	DEBUG4 (("K "ID" New U.  ulen "ID" Singleton 1\n", k, ulen)) ;
	if (ulen > 0)
	{
	    up = Uip [k] ;
	    ip = (Int *) (Numeric->Memory + up) ;
	    for (i = 0 ; i < ulen ; i++)
	    {
		col = *ip ;
		DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));
		ASSERT (col >= 0 && col < n_col) ;
		*ip++ = Fcpos [col] ;
	    }
	}
    }

    for (k = n1 ; k < npiv ; k++)
    {
	up = Uip [k] ;
	if (up < 0)
	{
	    /* this is the start of a new Uchain (with a pattern) */
	    ulen = Uilen [k] ;
	    DEBUG4 (("K "ID" New U.  ulen "ID" End_Uchain 1\n", k, ulen)) ;
	    if (ulen > 0)
	    {
		up = -up ;
		ip = (Int *) (Numeric->Memory + up) ;
		for (i = 0 ; i < ulen ; i++)
		{
		    col = *ip ;
		    DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col]));
		    ASSERT (col >= 0 && col < n_col) ;
		    *ip++ = Fcpos [col] ;
		}
	    }
	}
    }

    ulen = Numeric->ulen ;
    if (ulen > 0)
    {
	/* convert last pivot row of U to the new pivot order */
	DEBUG4 (("K "ID" (last)\n", k)) ;
	for (i = 0 ; i < ulen ; i++)
	{
	    col = Numeric->Upattern [i] ;
	    DEBUG4 (("    old col "ID" new col "ID"\n", col, Fcpos [col])) ;
	    Numeric->Upattern [i] = Fcpos [col] ;
	}
    }

    /* Fcpos no longer needed ] */

    /* ---------------------------------------------------------------------- */
    /* convert L to the new pivot order */
    /* ---------------------------------------------------------------------- */

    for (k = 0 ; k < n1 ; k++)
    {
	llen = Lilen [k] ;
	DEBUG4 (("K "ID" New L.  llen "ID" Singleton col\n", k, llen)) ;
	if (llen > 0)
	{
	    lp = Lip [k] ;
	    ip = (Int *) (Numeric->Memory + lp) ;
	    for (i = 0 ; i < llen ; i++)
	    {
		row = *ip ;
		DEBUG4 (("    old row "ID" new row "ID"\n", row, Frpos [row])) ;
		ASSERT (row >= 0 && row < n_row) ;
		*ip++ = Frpos [row] ;
	    }
	}
    }

    for (k = n1 ; k < npiv ; k++)
    {
	llen = Lilen [k] ;
	DEBUG4 (("K "ID" New L.  llen "ID" \n", k, llen)) ;
	if (llen > 0)
	{
	    lp = Lip [k] ;
	    if (lp < 0)
	    {
		/* this starts a new Lchain */
		lp = -lp ;
	    }
	    ip = (Int *) (Numeric->Memory + lp) ;
	    for (i = 0 ; i < llen ; i++)
	    {
		row = *ip ;
		DEBUG4 (("    old row "ID" new row "ID"\n", row, Frpos [row])) ;
		ASSERT (row >= 0 && row < n_row) ;
		*ip++ = Frpos [row] ;
	    }
	}
    }

    /* Frpos no longer needed ] */

    /* ---------------------------------------------------------------------- */
    /* combine symbolic and numeric permutations */
    /* ---------------------------------------------------------------------- */

    Cperm_init = Symbolic->Cperm_init ;
    Rperm_init = Symbolic->Rperm_init ;

    for (k = 0 ; k < n_row ; k++)
    {
	Rperm [k] = Rperm_init [Rperm [k]] ;
    }

    for (k = 0 ; k < n_col ; k++)
    {
	Cperm [k] = Cperm_init [Cperm [k]] ;
    }

    /* Work object will be freed immediately upon return (to UMF_kernel */
    /* and then to UMFPACK_numeric). */
}
Esempio n. 7
0
/*
 *	Parse the module config sections, and load
 *	and call each module's init() function.
 *
 *	Libtool makes your life a LOT easier, especially with libltdl.
 *	see: http://www.gnu.org/software/libtool/
 */
int setup_modules(void)
{
	int comp;
	CONF_SECTION *cs;

	/*
	 *  FIXME: This should be pulled from somewhere else.
	 */
	const char *filename="radiusd.conf";

	/*
	 *	No current list of modules: Go initialize libltdl.
	 */
	if (!module_list) {
		/*
		 *	Set the default list of preloaded symbols.
		 *	This is used to initialize libltdl's list of
		 *	preloaded modules. 
		 *
		 *	i.e. Static modules.
		 */
		LTDL_SET_PRELOADED_SYMBOLS();

		if (lt_dlinit() != 0) {
			radlog(L_ERR|L_CONS, "Failed to initialize libraries: %s\n",
					lt_dlerror());
			exit(1); /* FIXME */
			
		}

		/*
		 *	Set the search path to ONLY our library directory.
		 *	This prevents the modules from being found from
		 *	any location on the disk.
		 */
		lt_dlsetsearchpath(radlib_dir);
		
		DEBUG2("Module: Library search path is %s",
				lt_dlgetsearchpath());

		/*
		 *	Initialize the components.
		 */
		for (comp = 0; comp < RLM_COMPONENT_COUNT; comp++) {
			components[comp] = NULL;
		}

	} else {
		detach_modules();
	}

	/*
	 *	Create any DICT_VALUE's for the types.  See
	 *	'doc/configurable_failover' for examples of 'authtype'
	 *	used to create new Auth-Type values.  In order to
	 *	let the user create new names, we've got to look for
	 *	those names, and create DICT_VALUE's for them.
	 */
	for (comp = 0; section_type_value[comp].section != NULL; comp++) {
		const char	*name2;
		DICT_ATTR	*dattr;
		DICT_VALUE	*dval;
		CONF_SECTION	*sub, *next;
		CONF_PAIR	*cp;

		/*
		 *  Big-time YUCK
		 */
		static int my_value = 32767;

		cs = cf_section_find(section_type_value[comp].section);

		if (!cs) continue;

		sub = NULL;
		do {
			/*
			 *	See if there's a sub-section by that
			 *	name.
			 */
			next = cf_subsection_find_next(cs, sub,
						      section_type_value[comp].typename);

			/*
			 *	Allow some old names, too.
			 */
			if (!next && (comp <= 4)) {
				
				next = cf_subsection_find_next(cs, sub,
							       old_section_type_value[comp].typename);
			}
			sub = next;

			/*
			 *	If so, look for it to define a new
			 *	value.
			 */
			name2 = cf_section_name2(sub);
			if (!name2) continue;


			/*
			 *	If the value already exists, don't
			 *	create it again.
			 */
			dval = dict_valbyname(section_type_value[comp].attr,
					      name2);
			if (dval) continue;

			/*
       			 *	Find the attribute for the value.
			 */
			dattr = dict_attrbyvalue(section_type_value[comp].attr);
			if (!dattr) continue;

			/*
			 *	Finally, create the new attribute.
			 */
			if (dict_addvalue(name2, dattr->name, my_value++) < 0) {
				radlog(L_ERR, "%s", librad_errstr);
				exit(1);
			}
		} while (sub != NULL);

		/*
		 *	Loop over the non-sub-sections, too.
		 */
		cp = NULL;
		do {
			/*
			 *	See if there's a conf-pair by that
			 *	name.
			 */
			cp = cf_pair_find_next(cs, cp, NULL);
			if (!cp) break;


			/*
			 *	If the value already exists, don't
			 *	create it again.
			 */
			name2 = cf_pair_attr(cp);
			dval = dict_valbyname(section_type_value[comp].attr,
					      name2);
			if (dval) continue;

			/*
       			 *	Find the attribute for the value.
			 */
			dattr = dict_attrbyvalue(section_type_value[comp].attr);
			if (!dattr) continue;

			/*
			 *	Finally, create the new attribute.
			 */
			if (dict_addvalue(name2, dattr->name, my_value++) < 0) {
				radlog(L_ERR, "%s", librad_errstr);
				exit(1);
			}
		} while (cp != NULL);
	} /* over the sections which can have redundent sub-sections */
Esempio n. 8
0
static void process_source_stat (stats_source_t *src_stats, stats_event_t *event)
{
    if (event->name)
    {
        stats_node_t *node = _find_node (src_stats->stats_tree, event->name);
        if (node == NULL)
        {
            /* adding node */
            if (event->action != STATS_EVENT_REMOVE && event->value)
            {
                DEBUG3 ("new node on %s \"%s\" (%s)", src_stats->source, event->name, event->value);
                node = (stats_node_t *)calloc (1,sizeof(stats_node_t));
                node->name = (char *)strdup (event->name);
                node->value = (char *)strdup (event->value);
                node->flags = event->flags;
                if (src_stats->flags & STATS_HIDDEN)
                    node->flags |= STATS_HIDDEN;
                stats_listener_send (node->flags, "EVENT %s %s %s\n", src_stats->source, event->name, event->value);
                avl_insert (src_stats->stats_tree, (void *)node);
            }
            return;
        }
        if (event->action == STATS_EVENT_REMOVE)
        {
            DEBUG2 ("delete node %s from %s", event->name, src_stats->source);
            stats_listener_send (node->flags, "DELETE %s %s\n", src_stats->source, event->name);
            avl_delete (src_stats->stats_tree, (void *)node, _free_stats);
            return;
        }
        modify_node_event (node, event);
        stats_listener_send (node->flags, "EVENT %s %s %s\n", src_stats->source, node->name, node->value);
        return;
    }
    if (event->action == STATS_EVENT_REMOVE && event->name == NULL)
    {
        avl_tree_unlock (src_stats->stats_tree);
        avl_tree_wlock (_stats.source_tree);
        avl_tree_wlock (src_stats->stats_tree);
        avl_delete (_stats.source_tree, (void *)src_stats, _free_source_stats);
        avl_tree_unlock (_stats.source_tree);
        return;
    }
    /* change source flags status */
    if (event->action & STATS_EVENT_HIDDEN)
    {
        avl_node *node = avl_get_first (src_stats->stats_tree);
        int visible = 0;

        if ((event->flags&STATS_HIDDEN) == (src_stats->flags&STATS_HIDDEN))
            return;
        if (src_stats->flags & STATS_HIDDEN)
        {
            stats_node_t *ct = _find_node (src_stats->stats_tree, "server_type");
            const char *type = "audio/mpeg";
            if (ct)
                type = ct->value;
            src_stats->flags &= ~STATS_HIDDEN;
            stats_listener_send (src_stats->flags, "NEW %s %s\n", type, src_stats->source);
            visible = 1;
        }
        else
        {
            stats_listener_send (src_stats->flags, "DELETE %s\n", src_stats->source);
            src_stats->flags |= STATS_HIDDEN;
        }
        while (node)
        {
            stats_node_t *stats = (stats_node_t*)node->key;
            if (visible)
            {
                stats->flags &= ~STATS_HIDDEN;
                stats_listener_send (stats->flags, "EVENT %s %s %s\n", src_stats->source, stats->name, stats->value);
            }
            else
                stats->flags |= STATS_HIDDEN;
            node = avl_get_next (node);
        }
    }
}
Esempio n. 9
0
/** Execute a program.
 *
 * @param cmd Command to execute. This is parsed into argv[] parts,
 * 	then each individual argv part is xlat'ed.
 * @param request current request.
 * @param exec_wait set to 1 if you want to read from or write to child
 * @param user_msg buffer to append plaintext (non valuepair) output.
 * @param msg_len length of user_msg buffer.
 * @param input_pairs list of value pairs - these will be put into
 * 	the environment variables of the child.
 * @param[out] output_pairs list of value pairs - child stdout will be
 * 	parsed and added into this list of value pairs.
 * @param shell_escape
 * @return 0 if exec_wait==0, exit code if exec_wait!=0, -1 on error.
 */
int radius_exec_program(const char *cmd, REQUEST *request,
			int exec_wait,
			char *user_msg, int msg_len,
			VALUE_PAIR *input_pairs,
			VALUE_PAIR **output_pairs,
			int shell_escape)
{
	pid_t pid;
	int from_child;
#ifndef __MINGW32__
	VALUE_PAIR *vp;
	char *p;
	pid_t child_pid;
	int comma = 0;
	int status;
	int n, done;
	char answer[4096];
#endif

	pid = radius_start_program(cmd, request, exec_wait, NULL, &from_child, input_pairs, shell_escape);
	if (pid < 0) {
		return -1;
	}

	if (!exec_wait)
		return 0;

#ifndef __MINGW32__
	done = radius_readfrom_program(from_child, pid, 10, answer, sizeof(answer));
	if (done < 0) {
		/*
		 * failure - radius_readfrom_program will
		 * have called close(from_child) for us
		 */
		DEBUG("failed to read from child output");
		return 1;

	}
	answer[done] = 0;


	/*
	 *	Make sure that the writer can't block while writing to
	 *	a pipe that no one is reading from anymore.
	 */
	close(from_child);

	DEBUG2("Exec-Program output: %s", answer);

	/*
	 *	Parse the output, if any.
	 */
	if (done) {
		n = T_OP_INVALID;
		if (output_pairs) {
			/*
			 *	For backwards compatibility, first check
			 *	for plain text (user_msg).
			 */
			vp = NULL;
			n = userparse(answer, &vp);
			if (vp) {
				pairfree(&vp);
			}
		}

		if (n == T_OP_INVALID) {
			DEBUG("Exec-Program-Wait: plaintext: %s", answer);
			if (user_msg) {
				strlcpy(user_msg, answer, msg_len);
			}
		} else {
			/*
			 *	HACK: Replace '\n' with ',' so that
			 *	userparse() can parse the buffer in
			 *	one go (the proper way would be to
			 *	fix userparse(), but oh well).
			 */
			for (p = answer; *p; p++) {
				if (*p == '\n') {
					*p = comma ? ' ' : ',';
					p++;
					comma = 0;
				}
				if (*p == ',') comma++;
			}

			/*
			 *	Replace any trailing comma by a NUL.
			 */
			if (answer[strlen(answer) - 1] == ',') {
				answer[strlen(answer) - 1] = '\0';
			}

			radlog(L_DBG,"Exec-Program-Wait: value-pairs: %s", answer);
			if (userparse(answer, &vp) == T_OP_INVALID) {
				radlog(L_ERR, "Exec-Program-Wait: %s: unparsable reply", cmd);

			} else {
				/*
				 *	Tell the caller about the value
				 *	pairs.
				 */
				*output_pairs = vp;
			}
		} /* else the answer was a set of VP's, not a text message */
	} /* else we didn't read anything from the child */

	/*
	 *	Call rad_waitpid (should map to waitpid on non-threaded
	 *	or single-server systems).
	 */
	child_pid = rad_waitpid(pid, &status);
	if (child_pid == 0) {
		radlog(L_DBG, "Exec-Program: Timeout waiting for child");
		return 2;
	}

	if (child_pid == pid) {
		if (WIFEXITED(status)) {
			status = WEXITSTATUS(status);
			radlog(L_DBG, "Exec-Program: returned: %d", status);
			return status;
		}
	}

	radlog(L_ERR|L_CONS, "Exec-Program: Abnormal child exit: %s",
	       strerror(errno));
#endif	/* __MINGW32__ */

	return 1;
}
void EventsWatcherDbOp::InsertEvent( const long serviceId, const string& correlationId, const string& sessionId,
	const string& evtype, const string& machine, const string& date, const string& messageBuffer, 
	const string& event_class, const string& additionalInfo, const string& innerException )
{
	Database* data = getData();
	
	ParametersVector params;
	
	string guid = Collaboration::GenerateGuid();
	DEBUG2( "guidParam [" << guid << "]" );
	DataParameterBase *guidParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	guidParam->setDimension( guid.size() );
	guidParam->setString( guid );
	params.push_back( guidParam );
		
	DEBUG2( "serviceIdParam [" << serviceId << "]" );
	DataParameterBase *serviceIdParam = m_DatabaseProvider->createParameter( DataType::LONGINT_TYPE );
	serviceIdParam->setLong( serviceId );
	params.push_back( serviceIdParam );

	DEBUG2( "correl [" << correlationId << "]" );
	DataParameterBase *correlIdParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	correlIdParam->setDimension( correlationId.size() );
	correlIdParam->setString( correlationId );
	params.push_back( correlIdParam );
		
	DEBUG2( "session [" << sessionId << "]" );
	DataParameterBase *sessionIdParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	sessionIdParam->setDimension( sessionId.size() );
	sessionIdParam->setString( sessionId );
	params.push_back( sessionIdParam );	

	DEBUG2( "type [" << evtype << "]" );
	DataParameterBase *typeParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	typeParam->setDimension( evtype.size() );
	typeParam->setString( evtype );
	params.push_back( typeParam );	
	
	DEBUG2( "machine [" << machine << "]" );
	DataParameterBase *machineParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	machineParam->setDimension( machine.size() );
	machineParam->setString( machine );
	params.push_back( machineParam );
	
	DEBUG2( "eventdate [" << date << "]" );
	DataParameterBase *dateParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	dateParam->setDimension( date.size() );
	dateParam->setString( date );
	params.push_back( dateParam );

	DEBUG2( "message" );
	DataParameterBase *messageParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	string::size_type messageBufferLength = messageBuffer.length();
	if( messageBufferLength > 256 )
	{
		messageParam->setDimension( 256 );
		messageParam->setString( messageBuffer.substr( 0, 256 ) );
	}
	else
	{
		messageParam->setDimension( messageBufferLength );
		messageParam->setString( messageBuffer );
	}
	params.push_back( messageParam );

	DEBUG2( "class [" << event_class << "]" );
	DataParameterBase *classParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	classParam->setDimension( event_class.size() );
	classParam->setString( event_class );
	params.push_back( classParam );
		
	DEBUG2( "addinfo [" << additionalInfo << "]" );
	DataParameterBase *addInfoParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );
	if( ( additionalInfo.length() == 0 ) && ( messageBufferLength > 256 ) )
	{
		addInfoParam->setDimension( messageBufferLength );
		addInfoParam->setString( messageBuffer );
	}
	else
	{
		if ( additionalInfo.length() > 2999 )
		{
			addInfoParam->setDimension( 2999 );
			addInfoParam->setString( additionalInfo.substr( 0, 2999 ) );
		}
		else
		{
			addInfoParam->setDimension( additionalInfo.length() );
			addInfoParam->setString( additionalInfo );
		}
	}
	params.push_back( addInfoParam );	

	DEBUG2( "innerex [" << innerException << "]" );
	DataParameterBase *innerExParam = m_DatabaseProvider->createParameter( DataType::CHAR_TYPE );

	if( innerException.length() > 3499 )
	{
		innerExParam->setDimension( 3499 );
		innerExParam->setString( innerException.substr( 0, 3499 ) );
	}
	else
	{
		innerExParam->setDimension( innerException.length() );
		innerExParam->setString( innerException );
	}
	params.push_back( innerExParam );	
	
	data->BeginTransaction();
	try
	{
		data->ExecuteNonQueryCached( DataCommand::SP, "INSERTEVENT", params );
	}
	catch( const std::exception& ex )
	{
		TRACE( "Insert event failed [" << ex.what() << "]" );
	}
	catch( ... )
	{
		TRACE( "Insert event failed [unknown reason]" );
	}

	data->EndTransaction( TransactionType::COMMIT );
	DEBUG_GLOBAL( "done" );
}
Esempio n. 11
0
/*
 *	Replace %<whatever> in a string.
 *
 *	%P	pool_name
 *	%I	param
 *	%J	lease_duration
 *
 */
static int sqlippool_expand(char * out, int outlen, char const * fmt,
			    rlm_sqlippool_t *data, char * param, int param_len)
{
	char *q;
	char const *p;
	char tmp[40]; /* For temporary storing of integers */

	q = out;
	for (p = fmt; *p ; p++) {
		int freespace;
		int c;

		/* Calculate freespace in output */
		freespace = outlen - (q - out);
		if (freespace <= 1)
			break;

		c = *p;
		if (c != '%') {
			*q++ = *p;
			continue;
		}

		if (*++p == '\0') {
			break;
		}

		if (c == '%') {
			switch (*p) {
			case 'P': /* pool name */
				strlcpy(q, data->pool_name, freespace);
				q += strlen(q);
				break;
			case 'I': /* IP address */
				if (param && param_len > 0) {
					if (param_len > freespace) {
						strlcpy(q, param, freespace);
						q += strlen(q);
					}
					else {
						memcpy(q, param, param_len);
						q += param_len;
					}
				}
				break;
			case 'J': /* lease duration */
				sprintf(tmp, "%d", data->lease_duration);
				strlcpy(q, tmp, freespace);
				q += strlen(q);
				break;

			default:
				*q++ = '%';
				*q++ = *p;
				break;
			}
		}
	}
	*q = '\0';

#if 0
	DEBUG2("sqlippool_expand: \"%s\"", out);
#endif

	return strlen(out);
}
Esempio n. 12
0
/*
 *	Read config files.
 *
 *	This function can ONLY be called from the main server process.
 */
int main_config_init(void)
{
	char const *p = NULL;
	CONF_SECTION *cs;
	struct stat statbuf;
	cached_config_t *cc;
	char buffer[1024];

	if (stat(radius_dir, &statbuf) < 0) {
		ERROR("Errors reading %s: %s",
		       radius_dir, fr_syserror(errno));
		return -1;
	}

#ifdef S_IWOTH
	if ((statbuf.st_mode & S_IWOTH) != 0) {
		ERROR("Configuration directory %s is globally writable.  Refusing to start due to insecure configuration.",
		       radius_dir);
	  return -1;
	}
#endif

#ifdef S_IROTH
	if (0 && (statbuf.st_mode & S_IROTH) != 0) {
		ERROR("Configuration directory %s is globally readable.  Refusing to start due to insecure configuration.",
		       radius_dir);
		return -1;
	}
#endif
	INFO("Starting - reading configuration files ...");

	/*
	 *	We need to load the dictionaries before reading the
	 *	configuration files.  This is because of the
	 *	pre-compilation in conffile.c.  That should probably
	 *	be fixed to be done as a second stage.
	 */
	if (!main_config.dictionary_dir) {
		main_config.dictionary_dir = talloc_typed_strdup(NULL, DICTDIR);
	}

	/*
	 *	Read the distribution dictionaries first, then
	 *	the ones in raddb.
	 */
	DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
	if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) {
		ERROR("Errors reading dictionary: %s",
		      fr_strerror());
		return -1;
	}

#define DICT_READ_OPTIONAL(_d, _n) \
do {\
	switch (dict_read(_d, _n)) {\
	case -1:\
		ERROR("Errors reading %s/%s: %s", _d, _n, fr_strerror());\
		return -1;\
	case 0:\
		DEBUG2("including dictionary file %s/%s", _d,_n);\
		break;\
	default:\
		break;\
	}\
} while (0)

	/*
	 *	Try to load protocol-specific dictionaries.  It's OK
	 *	if they don't exist.
	 */
#ifdef WITH_DHCP
	DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.dhcp");
#endif

#ifdef WITH_VMPS
	DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.vqp");
#endif

	/*
	 *	It's OK if this one doesn't exist.
	 */
	DICT_READ_OPTIONAL(radius_dir, RADIUS_DICTIONARY);

	/* Read the configuration file */
	snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
		 radius_dir, main_config.name);
	if ((cs = cf_file_read(buffer)) == NULL) {
		ERROR("Errors reading or parsing %s", buffer);
		return -1;
	}

	/*
	 *	If there was no log destination set on the command line,
	 *	set it now.
	 */
	if (default_log.dst == L_DST_NULL) {
		if (cf_section_parse(cs, NULL, serverdest_config) < 0) {
			fprintf(stderr, "radiusd: Error: Failed to parse log{} section.\n");
			cf_file_free(cs);
			return -1;
		}

		if (!radlog_dest) {
			fprintf(stderr, "radiusd: Error: No log destination specified.\n");
			cf_file_free(cs);
			return -1;
		}

		default_log.dst = fr_str2int(log_str2dst, radlog_dest,
					      L_DST_NUM_DEST);
		if (default_log.dst == L_DST_NUM_DEST) {
			fprintf(stderr, "radiusd: Error: Unknown log_destination %s\n",
				radlog_dest);
			cf_file_free(cs);
			return -1;
		}

		if (default_log.dst == L_DST_SYSLOG) {
			/*
			 *	Make sure syslog_facility isn't NULL
			 *	before using it
			 */
			if (!syslog_facility) {
				fprintf(stderr, "radiusd: Error: Syslog chosen but no facility was specified\n");
				cf_file_free(cs);
				return -1;
			}
			main_config.syslog_facility = fr_str2int(syslog_str2fac, syslog_facility, -1);
			if (main_config.syslog_facility < 0) {
				fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n",
					syslog_facility);
				cf_file_free(cs);
				return -1;
			}

#ifdef HAVE_SYSLOG_H
			/*
			 *	Call openlog only once, when the
			 *	program starts.
			 */
			openlog(progname, LOG_PID, main_config.syslog_facility);
#endif

		} else if (default_log.dst == L_DST_FILES) {
			if (!main_config.log_file) {
				fprintf(stderr, "radiusd: Error: Specified \"files\" as a log destination, but no log filename was given!\n");
				cf_file_free(cs);
				return -1;
			}
		}
	}

#ifdef HAVE_SETUID
	/*
	 *	Switch users as early as possible.
	 */
	if (!switch_users(cs)) fr_exit(1);
#endif

	/*
	 *	Open the log file AFTER switching uid / gid.  If we
	 *	did switch uid/gid, then the code in switch_users()
	 *	took care of setting the file permissions correctly.
	 */
	if ((default_log.dst == L_DST_FILES) &&
	    (default_log.fd < 0)) {
		default_log.fd = open(main_config.log_file,
					    O_WRONLY | O_APPEND | O_CREAT, 0640);
		if (default_log.fd < 0) {
			fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno));
			cf_file_free(cs);
			return -1;
		}
	}

	/*
	 *	This allows us to figure out where, relative to
	 *	radiusd.conf, the other configuration files exist.
	 */
	if (cf_section_parse(cs, NULL, server_config) < 0) {
		return -1;
	}

	/*
	 *	We ignore colourization of output until after the
	 *	configuration files have been parsed.
	 */
	p = getenv("TERM");
	if (do_colourise && p && isatty(default_log.fd) && strstr(p, "xterm")) {
		default_log.colourise = true;
	} else {
		default_log.colourise = false;
	}

	/*
	 *	Starting the server, WITHOUT "-x" on the
	 *	command-line: use whatever is in the config
	 *	file.
	 */
	if (debug_flag == 0) {
		debug_flag = main_config.debug_level;
	}
	fr_debug_flag = debug_flag;

	FR_INTEGER_COND_CHECK("max_request_time", main_config.max_request_time, (main_config.max_request_time != 0), 100);
	FR_INTEGER_BOUND_CHECK("reject_delay", main_config.reject_delay, <=, 10);
	FR_INTEGER_BOUND_CHECK("cleanup_delay", main_config.cleanup_delay, <=, 10);

	/*
	 * Set default initial request processing delay to 1/3 of a second.
	 * Will be updated by the lowest response window across all home servers,
	 * if it is less than this.
	 */
	main_config.init_delay.tv_sec = 0;
	main_config.init_delay.tv_usec = 1000000 / 3;

	/*
	 *	Free the old configuration items, and replace them
	 *	with the new ones.
	 *
	 *	Note that where possible, we do atomic switch-overs,
	 *	to ensure that the pointers are always valid.
	 */
	rad_assert(main_config.config == NULL);
	root_config = main_config.config = cs;

	DEBUG2("%s: #### Loading Realms and Home Servers ####", main_config.name);
	if (!realms_init(cs)) {
		return -1;
	}

	DEBUG2("%s: #### Loading Clients ####", main_config.name);
	if (!clients_parse_section(cs, false)) {
		return -1;
	}

	/*
	 *  Register the %{config:section.subsection} xlat function.
	 */
	xlat_register("config", xlat_config, NULL, NULL);
	xlat_register("client", xlat_client, NULL, NULL);
	xlat_register("getclient", xlat_getclient, NULL, NULL);

	/*
	 *  Go update our behaviour, based on the configuration
	 *  changes.
	 */

	/*
	 *	Sanity check the configuration for internal
	 *	consistency.
	 */
	FR_INTEGER_BOUND_CHECK("reject_delay", main_config.reject_delay, <=, main_config.cleanup_delay);

	if (chroot_dir) {
		if (chdir(radlog_dir) < 0) {
			ERROR("Failed to 'chdir %s' after chroot: %s",
			       radlog_dir, fr_syserror(errno));
			return -1;
		}
	}

	cc = talloc_zero(NULL, cached_config_t);
	if (!cc) return -1;

	cc->cs = talloc_steal(cc ,cs);
	rad_assert(cs_cache == NULL);
	cs_cache = cc;

	/* Clear any unprocessed configuration errors */
	(void) fr_strerror();

	return 0;
}
Esempio n. 13
0
/*
 * To process the TLS,
 *  INCOMING DATA:
 * 	1. EAP-TLS should get the compelete TLS data from the peer.
 * 	2. Store that data in a data structure with any other required info
 *	3. Handle that data structure to the TLS module.
 *	4. TLS module will perform its operations on the data and
 *	handle back to EAP-TLS
 *
 *  OUTGOING DATA:
 * 	1. EAP-TLS if necessary will fragment it and send it to the
 * 	destination.
 *
 *	During EAP-TLS initialization, TLS Context object will be
 *	initialized and stored.  For every new authentication
 *	requests, TLS will open a new session object and that session
 *	object should be maintained even after the session is
 *	completed for session resumption. (Probably later as a feature
 *	as we donot know who maintains these session objects ie,
 *	SSL_CTX (internally) or TLS module(explicitly). If TLS module,
 *	then how to let SSL API know about these sessions.)
 */
static eaptls_status_t eaptls_operation(eaptls_status_t status,
					EAP_HANDLER *handler)
{
	tls_session_t *tls_session;

	tls_session = (tls_session_t *)handler->opaque;

	if ((status == EAPTLS_MORE_FRAGMENTS) ||
	    (status == EAPTLS_MORE_FRAGMENTS_WITH_LENGTH) ||
	    (status == EAPTLS_FIRST_FRAGMENT)) {
		/*
		 *	Send the ACK.
		 */
		eaptls_send_ack(handler->eap_ds, tls_session->peap_flag);
		return EAPTLS_HANDLED;

	}

	/*
	 *	We have the complete TLS-data or TLS-message.
	 *
	 *	Clean the dirty message.
	 *
	 *	Authenticate the user and send
	 *	Success/Failure.
	 *
	 *	If more info
	 *	is required then send another request.
	 */
	if (!tls_handshake_recv(tls_session)) {
		DEBUG2("TLS receive handshake failed during operation");
		eaptls_fail(handler, tls_session->peap_flag);
		return EAPTLS_FAIL;
	}

	/*
	 *	FIXME: return success/fail.
	 *
	 *	TLS proper can decide what to do, then.
	 */
	if (tls_session->dirty_out.used > 0) {
		eaptls_request(handler->eap_ds, tls_session);
		return EAPTLS_HANDLED;
	}
		
	/* 
	 *	If there is no data to send i.e
	 *	dirty_out.used <=0 and if the SSL
	 *	handshake is finished, then return a
	 *	EPTLS_SUCCESS
	 */
	
	if (SSL_is_init_finished(tls_session->ssl)) {
		/*
		 *	Init is finished.  The rest is
		 *	application data.
		 */
		tls_session->info.content_type = application_data; 
		return EAPTLS_SUCCESS;
	}
	
	/*
	 *	Who knows what happened...
	 */
	DEBUG2("TLS failed during operation");
	return EAPTLS_FAIL;
}
Esempio n. 14
0
/*
 * EAPTLS_PACKET
 * code   =  EAP-code
 * id     =  EAP-id
 * length = code + id + length + flags + tlsdata
 *        =  1   +  1 +   2    +  1    +  X
 * length = EAP-length - 1(EAP-Type = 1 octet)
 * flags  = EAP-typedata[0] (1 octet)
 * dlen   = EAP-typedata[1-4] (4 octets), if L flag set
 *        = length - 5(code+id+length+flags), otherwise
 * data   = EAP-typedata[5-n], if L flag set
 *        = EAP-typedata[1-n], otherwise
 * packet = EAP-typedata (complete typedata)
 *
 * Points to consider during EAP-TLS data extraction
 * 1. In the received packet, No data will be present incase of ACK-NAK
 * 2. Incase if more fragments need to be received then ACK after retreiving this fragment.
 *
 *  RFC 2716 Section 4.2.  PPP EAP TLS Request Packet
 *
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |     Code      |   Identifier  |            Length             |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |     Type      |     Flags     |      TLS Message Length
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |     TLS Message Length        |       TLS Data...
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 *  The Length field is two octets and indicates the length of the EAP
 *  packet including the Code, Identifir, Length, Type, and TLS data
 *  fields.
 */
static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, eaptls_status_t status)
{
	EAPTLS_PACKET	*tlspacket;
	uint32_t	data_len = 0;
	uint32_t	len = 0;
	uint8_t		*data = NULL;

	if (status  == EAPTLS_INVALID)
		return NULL;

	/*
	 *	The main EAP code & eaptls_verify() take care of
	 *	ensuring that the packet is OK, and that we can
	 *	extract the various fields we want.
	 *
	 *	e.g. a TLS packet with zero data is allowed as an ACK,
	 *	but we will never see it here, as we will simply
	 *	send another fragment, instead of trying to extract
	 *	the data.
	 *
	 *	MUST have TLS type octet, followed by flags, followed
	 *	by data.
	 */
	assert(eap_ds->response->length > 2);

	tlspacket = eaptls_alloc();
	if (tlspacket == NULL) return NULL;

	/*
	 *	Code & id for EAPTLS & EAP are same
	 *	but eaptls_length = eap_length - 1(EAP-Type = 1 octet)
	 *
	 *	length = code + id + length + type + tlsdata
	 *	       =  1   +  1 +   2    +  1    +  X
	 */
	tlspacket->code = eap_ds->response->code;
	tlspacket->id = eap_ds->response->id;
	tlspacket->length = eap_ds->response->length - 1; /* EAP type */
	tlspacket->flags = eap_ds->response->type.data[0];

	/*
	 *	A quick sanity check of the flags.  If we've been told
	 *	that there's a length, and there isn't one, then stop.
	 */
	if (TLS_LENGTH_INCLUDED(tlspacket->flags) &&
	    (tlspacket->length < 5)) { /* flags + TLS message length */
		RDEBUG("Invalid EAP-TLS packet received.  (Length bit is set, but no length was found.)");
		eaptls_free(&tlspacket);
		return NULL;
	}

	/*
	 *	If the final TLS packet is larger than we can handle, die
	 *	now.
	 *
	 *	Likewise, if the EAP packet says N bytes, and the TLS
	 *	packet says there's fewer bytes, it's a problem.
	 *
	 *	FIXME: Try to ensure that the claimed length is
	 *	consistent across multiple TLS fragments.
	 */
	if (TLS_LENGTH_INCLUDED(tlspacket->flags)) {
		memcpy(&data_len, &eap_ds->response->type.data[1], 4);
		data_len = ntohl(data_len);
		if (data_len > MAX_RECORD_SIZE) {
			RDEBUG("The EAP-TLS packet will contain more data than we can process.");
			eaptls_free(&tlspacket);
			return NULL;
		}

#if 0
		DEBUG2(" TLS: %d %d\n", data_len, tlspacket->length);

		if (data_len < tlspacket->length) {
			RDEBUG("EAP-TLS packet claims to be smaller than the encapsulating EAP packet.");
			eaptls_free(&tlspacket);
			return NULL;
		}
#endif
	}

	switch (status) {
	/*
	 *	The TLS Message Length field is four octets, and
	 *	provides the total length of the TLS message or set of
	 *	messages that is being fragmented; this simplifies
	 *	buffer allocation.
	 *
	 *	Dynamic allocation of buffers as & when we know the
	 *	length should solve the problem.
	 */
	case EAPTLS_FIRST_FRAGMENT:
	case EAPTLS_LENGTH_INCLUDED:
	case EAPTLS_MORE_FRAGMENTS_WITH_LENGTH:
		if (tlspacket->length < 5) { /* flags + TLS message length */
			RDEBUG("Invalid EAP-TLS packet received.  (Expected length, got none.)");
			eaptls_free(&tlspacket);
			return NULL;
		}

		/*
		 *	Extract all the TLS fragments from the
		 *	previous eap_ds Start appending this
		 *	fragment to the above ds
		 */
		memcpy(&data_len, &eap_ds->response->type.data[1], sizeof(uint32_t));
		data_len = ntohl(data_len);
		data = (eap_ds->response->type.data + 5/*flags+TLS-Length*/);
		len = eap_ds->response->type.length - 5/*flags+TLS-Length*/;

		/*
		 *	Hmm... this should be an error, too.
		 */
		if (data_len > len) {
			data_len = len;
		}
		break;

		/*
		 *	Data length is implicit, from the EAP header.
		 */
	case EAPTLS_MORE_FRAGMENTS:
	case EAPTLS_OK:
		data_len = eap_ds->response->type.length - 1/*flags*/;
		data = eap_ds->response->type.data + 1/*flags*/;
		break;

	default:
		RDEBUG("Invalid EAP-TLS packet received");
		eaptls_free(&tlspacket);
		return NULL;
	}

	tlspacket->dlen = data_len;
	if (data_len) {
		tlspacket->data = (unsigned char *)malloc(data_len);
		if (tlspacket->data == NULL) {
			RDEBUG("out of memory");
			eaptls_free(&tlspacket);
			return NULL;
		}
		memcpy(tlspacket->data, data, data_len);
	}

	return tlspacket;
}
Esempio n. 15
0
/*
** Description
** Kill event handler loop
*/
void
stop_event_handler (void)
{
  pthread_cancel(event_handler_thread);
  DEBUG2("event.c: event handler stopped\n");
}
Esempio n. 16
0
void exec_trigger(REQUEST *request, CONF_SECTION *cs, const char *name)
{
	CONF_SECTION *subcs;
	CONF_ITEM *ci;
	CONF_PAIR *cp;
	const char *attr;
	const char *value;
	VALUE_PAIR *vp;

	/*
	 *	Use global "trigger" section if no local config is given.
	 */
	if (!cs) {
		cs = mainconfig.config;
		attr = name;
	} else {
		/*
		 *	Try to use pair name, rather than reference.
		 */
		attr = strrchr(name, '.');
		if (attr) {
			attr++;
		} else {
			attr = name;
		}
	}

	/*
	 *	Find local "trigger" subsection.  If it isn't found,
	 *	try using the global "trigger" section, and reset the
	 *	reference to the full path, rather than the sub-path.
	 */
	subcs = cf_section_sub_find(cs, "trigger");
	if (!subcs && (cs != mainconfig.config)) {
		subcs = cf_section_sub_find(mainconfig.config, "trigger");
		attr = name;
	}

	if (!subcs) {
		DEBUG3("No trigger subsection: ignoring trigger %s", name);
		return;
	}

	ci = cf_reference_item(subcs, mainconfig.config, attr);
	if (!ci) {
		DEBUG3("No such item in trigger section: %s", attr);
		return;
	}

	if (!cf_item_is_pair(ci)) {
		DEBUG2("Trigger is not a configuration variable: %s", attr);
		return;
	}

	cp = cf_itemtopair(ci);
	if (!cp) return;

	value = cf_pair_value(cp);
	if (!value) {
		DEBUG2("Trigger has no value: %s", name);
		return;
	}

	/*
	 *	May be called for Status-Server packets.
	 */
	vp = NULL;
	if (request && request->packet) vp = request->packet->vps;

	DEBUG("Trigger %s -> %s", name, value);
	radius_exec_program(value, request, 0, NULL, 0, vp, NULL, 1);
}
Esempio n. 17
0
static int mod_authenticate(UNUSED void *instance, eap_handler_t *handler)
{
	int		rcode;
	leap_session_t	*session;
	leap_packet_t	*packet;
	leap_packet_t	*reply;
	VALUE_PAIR	*password;

	if (!handler->opaque) {
		radlog(L_ERR, "rlm_eap_leap: Cannot authenticate without LEAP history");
		return 0;
	}
	session = (leap_session_t *) handler->opaque;
	reply = NULL;

	/*
	 *	Extract the LEAP packet.
	 */
	if (!(packet = eapleap_extract(handler->eap_ds)))
		return 0;

	/*
	 *	The password is never sent over the wire.
	 *	Always get the configured password, for each user.
	 */
	password = pairfind(handler->request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
	if (!password) password = pairfind(handler->request->config_items, PW_NT_PASSWORD, 0, TAG_ANY);
	if (!password) {
		DEBUG2("rlm_eap_leap: No Cleartext-Password or NT-Password configured for this user");
		talloc_free(packet);
		return 0;
	}

	/*
	 *	We've already sent the AP challenge.  This packet
	 *	should contain the NtChallengeResponse
	 */
	switch (session->stage) {
	case 4:			/* Verify NtChallengeResponse */
		DEBUG2("  rlm_eap_leap: Stage 4");
		rcode = eapleap_stage4(packet, password, session);
		session->stage = 6;

		/*
		 *	We send EAP-Success or EAP-Fail, and not
		 *	any LEAP packet.  So we return here.
		 */
		if (!rcode) {
			handler->eap_ds->request->code = PW_EAP_FAILURE;
			talloc_free(packet);
			return 0;
		}

		handler->eap_ds->request->code = PW_EAP_SUCCESS;

		/*
		 *	Do this only for Success.
		 */
		handler->eap_ds->request->id = handler->eap_ds->response->id + 1;
		handler->eap_ds->set_request_id = 1;

		/*
		 *	LEAP requires a challenge in stage 4, not
		 *	an Access-Accept, which is normally returned
		 *	by eap_compose() in eap.c, when the EAP reply code
		 *	is EAP_SUCCESS.
		 */
		handler->request->reply->code = PW_ACCESS_CHALLENGE;
		talloc_free(packet);
		return 1;

	case 6:			/* Issue session key */
		DEBUG2("  rlm_eap_leap: Stage 6");
		reply = eapleap_stage6(packet, handler->request,
				       handler->request->username, password,
				       session);
		break;

		/*
		 *	Stages 1, 3, and 5 are requests from the AP.
		 *	Stage 2 is handled by initiate()
		 */
	default:
		radlog(L_ERR, "  rlm_eap_leap: Internal sanity check failed on stage");
		break;
	}

	talloc_free(packet);

	/*
	 *	Process the packet.  We don't care about any previous
	 *	EAP packets, as
	 */
	if (!reply) {
		return 0;
	}

	eapleap_compose(handler->eap_ds, reply);
	talloc_free(reply);
	return 1;
}
Esempio n. 18
0
static int mod_process(void *arg, eap_handler_t *handler)
{
	pwd_session_t *session;
	pwd_hdr *hdr;
	pwd_id_packet_t *packet;
	eap_packet_t *response;
	REQUEST *request, *fake;
	VALUE_PAIR *pw, *vp;
	EAP_DS *eap_ds;
	size_t in_len;
	int ret = 0;
	eap_pwd_t *inst = (eap_pwd_t *)arg;
	uint16_t offset;
	uint8_t exch, *in, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN];
	uint8_t peer_confirm[SHA256_DIGEST_LENGTH];

	if (((eap_ds = handler->eap_ds) == NULL) || !inst) return 0;

	session = (pwd_session_t *)handler->opaque;
	request = handler->request;
	response = handler->eap_ds->response;
	hdr = (pwd_hdr *)response->type.data;

	/*
	 *	The header must be at least one byte.
	 */
	if (!hdr || (response->type.length < sizeof(pwd_hdr))) {
		RDEBUG("Packet with insufficient data");
		return 0;
	}

	in = hdr->data;
	in_len = response->type.length - sizeof(pwd_hdr);

	/*
	* see if we're fragmenting, if so continue until we're done
	*/
	if (session->out_pos) {
		if (in_len) RDEBUG2("pwd got something more than an ACK for a fragment");

		return send_pwd_request(session, eap_ds);
	}

	/*
	* the first fragment will have a total length, make a
	* buffer to hold all the fragments
	*/
	if (EAP_PWD_GET_LENGTH_BIT(hdr)) {
		if (session->in) {
			RDEBUG2("pwd already alloced buffer for fragments");
			return 0;
		}

		if (in_len < 2) {
			RDEBUG("Invalid packet: length bit set, but no length field");
			return 0;
		}

		session->in_len = ntohs(in[0] * 256 | in[1]);
		if ((session->in = talloc_zero_array(session, uint8_t, session->in_len)) == NULL) {
			RDEBUG2("pwd cannot allocate %zd buffer to hold fragments",
				session->in_len);
			return 0;
		}
		memset(session->in, 0, session->in_len);
		session->in_pos = 0;
		in += sizeof(uint16_t);
		in_len -= sizeof(uint16_t);
	}

	/*
	 * all fragments, including the 1st will have the M(ore) bit set,
	 * buffer those fragments!
	 */
	if (EAP_PWD_GET_MORE_BIT(hdr)) {
		rad_assert(session->in != NULL);

		if ((session->in_pos + in_len) > session->in_len) {
			RDEBUG2("Fragment overflows packet.");
			return 0;
		}

		memcpy(session->in + session->in_pos, in, in_len);
		session->in_pos += in_len;

		/*
		 * send back an ACK for this fragment
		 */
		exch = EAP_PWD_GET_EXCHANGE(hdr);
		eap_ds->request->code = PW_EAP_REQUEST;
		eap_ds->request->type.num = PW_EAP_PWD;
		eap_ds->request->type.length = sizeof(pwd_hdr);
		if ((eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, sizeof(pwd_hdr))) == NULL) {
			return 0;
		}
		hdr = (pwd_hdr *)eap_ds->request->type.data;
		EAP_PWD_SET_EXCHANGE(hdr, exch);
		return 1;
	}


	if (session->in) {
		/*
		 * the last fragment...
		 */
		if ((session->in_pos + in_len) > session->in_len) {
			RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent");
			return 0;
		}
		memcpy(session->in + session->in_pos, in, in_len);
		in = session->in;
		in_len = session->in_len;
	}

	switch (session->state) {
	case PWD_STATE_ID_REQ:
	{
		BIGNUM	*x = NULL, *y = NULL;

		if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) {
			RDEBUG2("pwd exchange is incorrect: not ID");
			return 0;
		}

		packet = (pwd_id_packet_t *) in;
		if (in_len < sizeof(*packet)) {
			RDEBUG("Packet is too small (%zd < %zd).", in_len, sizeof(*packet));
			return 0;
		}

		if ((packet->prf != EAP_PWD_DEF_PRF) ||
		    (packet->random_function != EAP_PWD_DEF_RAND_FUN) ||
		    (packet->prep != EAP_PWD_PREP_NONE) ||
		    (CRYPTO_memcmp(packet->token, &session->token, 4)) ||
		    (packet->group_num != ntohs(session->group_num))) {
			RDEBUG2("pwd id response is invalid");
			return 0;
		}
		/*
		 * we've agreed on the ciphersuite, record it...
		 */
		ptr = (uint8_t *)&session->ciphersuite;
		memcpy(ptr, (char *)&packet->group_num, sizeof(uint16_t));
		ptr += sizeof(uint16_t);
		*ptr = EAP_PWD_DEF_RAND_FUN;
		ptr += sizeof(uint8_t);
		*ptr = EAP_PWD_DEF_PRF;

		session->peer_id_len = in_len - sizeof(pwd_id_packet_t);
		if (session->peer_id_len >= sizeof(session->peer_id)) {
			RDEBUG2("pwd id response is malformed");
			return 0;
		}

		memcpy(session->peer_id, packet->identity, session->peer_id_len);
		session->peer_id[session->peer_id_len] = '\0';

		/*
		 * make fake request to get the password for the usable ID
		 */
		if ((fake = request_alloc_fake(handler->request)) == NULL) {
			RDEBUG("pwd unable to create fake request!");
			return 0;
		}
		fake->username = fr_pair_afrom_num(fake->packet, PW_USER_NAME, 0);
		if (!fake->username) {
			RDEBUG("Failed creating pair for peer id");
			talloc_free(fake);
			return 0;
		}
		fr_pair_value_bstrncpy(fake->username, session->peer_id, session->peer_id_len);
		fr_pair_add(&fake->packet->vps, fake->username);

		if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
			fake->server = vp->vp_strvalue;
		} else if (inst->virtual_server) {
			fake->server = inst->virtual_server;
		} /* else fake->server == request->server */

		RDEBUG("Sending tunneled request");
		rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);

		if (fake->server) {
			RDEBUG("server %s {", fake->server);
		} else {
			RDEBUG("server {");
		}

		/*
		 *	Call authorization recursively, which will
		 *	get the password.
		 */
		RINDENT();
		process_authorize(0, fake);
		REXDENT();

		/*
		 *	Note that we don't do *anything* with the reply
		 *	attributes.
		 */
		if (fake->server) {
			RDEBUG("} # server %s", fake->server);
		} else {
			RDEBUG("}");
		}

		RDEBUG("Got tunneled reply code %d", fake->reply->code);
		rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL);

		if ((pw = fr_pair_find_by_num(fake->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) {
			DEBUG2("failed to find password for %s to do pwd authentication",
			session->peer_id);
			talloc_free(fake);
			return 0;
		}

		if (compute_password_element(session, session->group_num,
			     		     pw->data.strvalue, strlen(pw->data.strvalue),
					     inst->server_id, strlen(inst->server_id),
					     session->peer_id, strlen(session->peer_id),
					     &session->token)) {
			DEBUG2("failed to obtain password element");
			talloc_free(fake);
			return 0;
		}
		TALLOC_FREE(fake);

		/*
		 * compute our scalar and element
		 */
		if (compute_scalar_element(session, inst->bnctx)) {
			DEBUG2("failed to compute server's scalar and element");
			return 0;
		}

		MEM(x = BN_new());
		MEM(y = BN_new());

		/*
		 * element is a point, get both coordinates: x and y
		 */
		if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->my_element, x, y,
							 inst->bnctx)) {
			DEBUG2("server point assignment failed");
			BN_clear_free(x);
			BN_clear_free(y);
			return 0;
		}

		/*
		 * construct request
		 */
		session->out_len = BN_num_bytes(session->order) + (2 * BN_num_bytes(session->prime));
		if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) {
			return 0;
		}
		memset(session->out, 0, session->out_len);

		ptr = session->out;
		offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
		BN_bn2bin(x, ptr + offset);
		BN_clear_free(x);

		ptr += BN_num_bytes(session->prime);
		offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
		BN_bn2bin(y, ptr + offset);
		BN_clear_free(y);

		ptr += BN_num_bytes(session->prime);
		offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
		BN_bn2bin(session->my_scalar, ptr + offset);

		session->state = PWD_STATE_COMMIT;
		ret = send_pwd_request(session, eap_ds);
	}
		break;

		case PWD_STATE_COMMIT:
		if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) {
			RDEBUG2("pwd exchange is incorrect: not commit!");
			return 0;
		}

		/*
		 * process the peer's commit and generate the shared key, k
		 */
		if (process_peer_commit(session, in, in_len, inst->bnctx)) {
			RDEBUG2("failed to process peer's commit");
			return 0;
		}

		/*
		 * compute our confirm blob
		 */
		if (compute_server_confirm(session, session->my_confirm, inst->bnctx)) {
			ERROR("rlm_eap_pwd: failed to compute confirm!");
			return 0;
		}

		/*
		 * construct a response...which is just our confirm blob
		 */
		session->out_len = SHA256_DIGEST_LENGTH;
		if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) {
			return 0;
		}

		memset(session->out, 0, session->out_len);
		memcpy(session->out, session->my_confirm, SHA256_DIGEST_LENGTH);

		session->state = PWD_STATE_CONFIRM;
		ret = send_pwd_request(session, eap_ds);
		break;

	case PWD_STATE_CONFIRM:
		if (in_len < SHA256_DIGEST_LENGTH) {
			RDEBUG("Peer confirm is too short (%zd < %d)",
			       in_len, SHA256_DIGEST_LENGTH);
			return 0;
		}

		if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) {
			RDEBUG2("pwd exchange is incorrect: not commit!");
			return 0;
		}
		if (compute_peer_confirm(session, peer_confirm, inst->bnctx)) {
			RDEBUG2("pwd exchange cannot compute peer's confirm");
			return 0;
		}
		if (CRYPTO_memcmp(peer_confirm, in, SHA256_DIGEST_LENGTH)) {
			RDEBUG2("pwd exchange fails: peer confirm is incorrect!");
			return 0;
		}
		if (compute_keys(session, peer_confirm, msk, emsk)) {
			RDEBUG2("pwd exchange cannot generate (E)MSK!");
			return 0;
		}
		eap_ds->request->code = PW_EAP_SUCCESS;
		/*
		 * return the MSK (in halves)
		 */
		eap_add_reply(handler->request, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN);
		eap_add_reply(handler->request, "MS-MPPE-Send-Key", msk + MPPE_KEY_LEN, MPPE_KEY_LEN);

		ret = 1;
		break;

	default:
		RDEBUG2("unknown PWD state");
		return 0;
	}

	/*
	 * we processed the buffered fragments, get rid of them
	 */
	if (session->in) {
		talloc_free(session->in);
		session->in = NULL;
	}

	return ret;
}
Esempio n. 19
0
GLOBAL void UMF_assemble
#else
GLOBAL void UMF_assemble_fixq
#endif
(
    NumericType *Numeric,
    WorkType *Work
)
{
    /* ---------------------------------------------------------------------- */
    /* local variables */
    /* ---------------------------------------------------------------------- */

    Int e, i, row, col, i2, nrows, ncols, f, tpi, extcdeg, extrdeg, rdeg0,
	cdeg0, son_list, next, nrows_to_assemble,
	ncols_to_assemble, ngetrows, j, j2,
	nrowsleft,	/* number of rows remaining in S */
	ncolsleft,	/* number of columns remaining in S */
	prior_Lson, prior_Uson, *E, *Cols, *Rows, *Wm, *Woo,
	*Row_tuples, *Row_degree, *Row_tlen,
	*Col_tuples, *Col_tlen ;
    Unit *Memory, *p ;
    Element *ep ;
    Tuple *tp, *tp1, *tp2, *tpend ;
    Entry
	*S,		/* a pointer into the contribution block of a son */
	*Fcblock,	/* current contribution block */
	*Fcol ;		/* a column of FC */
    Int *Frpos,
	*Fcpos,
	fnrows,		/* number of rows in contribution block in F */
	fncols ;	/* number of columns in contribution block in F */

#if !defined (FIXQ) || !defined (NDEBUG)
    Int *Col_degree ;
#endif

#ifndef NDEBUG
    Int n_row, n_col ;
    n_row = Work->n_row ;
    n_col = Work->n_col ;
    DEBUG3 (("::Assemble SCANS 1-4\n")) ;
    UMF_dump_current_front (Numeric, Work, TRUE) ;
#endif

#if !defined (FIXQ) || !defined (NDEBUG)
    Col_degree = Numeric->Cperm ;   /* not updated if FIXQ is true */
#endif

    /* ---------------------------------------------------------------------- */
    /* get parameters */
    /* ---------------------------------------------------------------------- */

    fncols = Work->fncols ;
    fnrows = Work->fnrows ;
    Fcpos = Work->Fcpos ;
    Frpos = Work->Frpos ;
    Row_degree = Numeric->Rperm ;
    Row_tuples = Numeric->Uip ;
    Row_tlen   = Numeric->Uilen ;
    Col_tuples = Numeric->Lip ;
    Col_tlen   = Numeric->Lilen ;
    E = Work->E ;
    Memory = Numeric->Memory ;
    Wm = Work->Wm ;
    Woo = Work->Woo ;
    rdeg0 = Work->rdeg0 ;
    cdeg0 = Work->cdeg0 ;

#ifndef NDEBUG
    DEBUG6 (("============================================\n")) ;
    DEBUG6 (("Degree update, assembly.\n")) ;
    DEBUG6 (("pivot row pattern:  fncols="ID"\n", fncols)) ;
    for (j = 0 ; j < fncols ; j++)
    {
	col = Work->Fcols [j] ;
	DEBUG6 ((ID" ", col)) ;
	ASSERT (Fcpos [col] == j * Work->fnr_curr) ;
	ASSERT (NON_PIVOTAL_COL (col)) ;
    }
    ASSERT (Fcpos [Work->pivcol] >= 0) ;
    DEBUG6 (("pivcol: "ID" pos "ID" fnr_curr "ID" fncols "ID"\n",
	Work->pivcol, Fcpos [Work->pivcol], Work->fnr_curr, fncols)) ;
    ASSERT (Fcpos [Work->pivcol] <  fncols * Work->fnr_curr) ;
    DEBUG6 (("\npivot col pattern:  fnrows="ID"\n", fnrows)) ;
    for (i = 0 ; i < fnrows ; i++)
    {
	row = Work->Frows [i] ;
	DEBUG6 ((ID" ", row)) ;
	ASSERT (Frpos [row] == i) ;
	ASSERT (NON_PIVOTAL_ROW (row)) ;
    }
    DEBUG6 (("\n")) ;
    ASSERT (Frpos [Work->pivrow] >= 0) ;
    ASSERT (Frpos [Work->pivrow] < fnrows) ;
    ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ;
    ASSERT (Work->Fcblock == Work->Flublock + Work->nb *
	(Work->nb + Work->fnr_curr + Work->fnc_curr)) ;
#endif

    Fcblock = Work->Fcblock ;

    /* ---------------------------------------------------------------------- */
    /* determine the largest actual frontal matrix size (for Info only) */
    /* ---------------------------------------------------------------------- */

    ASSERT (fnrows == Work->fnrows_new + 1) ;
    ASSERT (fncols == Work->fncols_new + 1) ;

    Numeric->maxnrows = MAX (Numeric->maxnrows, fnrows) ;
    Numeric->maxncols = MAX (Numeric->maxncols, fncols) ;

    /* this is safe from integer overflow, since the current frontal matrix
     * is already allocated. */
    Numeric->maxfrsize = MAX (Numeric->maxfrsize, fnrows * fncols) ;

    /* ---------------------------------------------------------------------- */
    /* assemble from prior elements into the current frontal matrix */
    /* ---------------------------------------------------------------------- */

    DEBUG2 (("New assemble start [prior_element:"ID"\n", Work->prior_element)) ;

    /* Currently no rows or columns are marked.  No elements are scanned, */
    /* that is, (ep->next == EMPTY) is true for all elements */

    son_list = 0 ;	/* start creating son_list [ */

    /* ---------------------------------------------------------------------- */
    /* determine if most recent element is Lson or Uson of current front */
    /* ---------------------------------------------------------------------- */

    if (!Work->do_extend)
    {
	prior_Uson = ( Work->pivcol_in_front && !Work->pivrow_in_front) ;
	prior_Lson = (!Work->pivcol_in_front &&  Work->pivrow_in_front) ;
	if (prior_Uson || prior_Lson)
	{
	    e = Work->prior_element ;
	    if (e != EMPTY)
	    {
		ASSERT (E [e]) ;
		p = Memory + E [e] ;
		ep = (Element *) p ;
		ep->next = son_list ;
		son_list = e ;
#ifndef NDEBUG
		DEBUG2 (("e "ID" is Prior son "ID" "ID"\n",
		    e, prior_Uson, prior_Lson)) ;
		UMF_dump_element (Numeric, Work, e, FALSE) ;
#endif
		ASSERT (E [e]) ;
	    }
	}
    }
    Work->prior_element = EMPTY ;

    /* ---------------------------------------------------------------------- */
    /* SCAN1-row:  scan the element lists of each new row in the pivot col */
    /* and compute the external column degree for each frontal */
    /* ---------------------------------------------------------------------- */

    for (i2 = Work->fscan_row ; i2 < fnrows ; i2++)
    {
	/* Get a row */
	row = Work->NewRows [i2] ;
	if (row < 0) row = FLIP (row) ;
	ASSERT (row >= 0 && row < n_row) ;

	DEBUG6 (("SCAN1-row: "ID"\n", row)) ;
#ifndef NDEBUG
	UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
#endif

	ASSERT (NON_PIVOTAL_ROW (row)) ;
	tpi = Row_tuples [row] ;
	if (!tpi) continue ;
	tp = (Tuple *) (Memory + tpi) ;
	tp1 = tp ;
	tp2 = tp ;
	tpend = tp + Row_tlen [row] ;
	for ( ; tp < tpend ; tp++)
	{
	    e = tp->e ;
	    ASSERT (e > 0 && e <= Work->nel) ;
	    if (!E [e]) continue ;	/* element already deallocated */
	    f = tp->f ;
	    p = Memory + E [e] ;
	    ep = (Element *) p ;
	    p += UNITS (Element, 1) ;
	    Rows = ((Int *) p) + ep->ncols ;
	    if (Rows [f] == EMPTY) continue ;	/* row already assembled */
	    ASSERT (row == Rows [f]) ;

	    if (ep->cdeg < cdeg0)
	    {
		/* first time seen in scan1-row */
		ep->cdeg = ep->nrowsleft + cdeg0 ;
		DEBUG6 (("e "ID" First seen: cdeg: "ID" ", e, ep->cdeg-cdeg0)) ;
		ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ;
	    }

	    ep->cdeg-- ;	/* decrement external column degree */
	    DEBUG6 (("e "ID" New ext col deg: "ID"\n", e, ep->cdeg - cdeg0)) ;

	    /* this element is not yet in the new son list */
	    if (ep->cdeg == cdeg0 && ep->next == EMPTY)
	    {
		/* A new LUson or Uson has been found */
		ep->next = son_list ;
		son_list = e ;
	    }

	    ASSERT (ep->cdeg >= cdeg0) ;
	    *tp2++ = *tp ;	/* leave the tuple in the list */
	}
	Row_tlen [row] = tp2 - tp1 ;
    }

    /* ---------------------------------------------------------------------- */
    /* SCAN1-col:  scan the element lists of each new col in the pivot row */
    /*	 and compute the external row degree for each frontal */
    /* ---------------------------------------------------------------------- */

    for (j2 = Work->fscan_col ; j2 < fncols ; j2++)
    {
	/* Get a column */
	col = Work->NewCols [j2] ;
	if (col < 0) col = FLIP (col) ;
	ASSERT (col >= 0 && col < n_col) ;

	DEBUG6 (("SCAN 1-col: "ID"\n", col)) ;
#ifndef NDEBUG
	UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
#endif

	ASSERT (NON_PIVOTAL_COL (col)) ;
	tpi = Col_tuples [col] ;
	if (!tpi) continue ;
	tp = (Tuple *) (Memory + tpi) ;
	tp1 = tp ;
	tp2 = tp ;
	tpend = tp + Col_tlen [col] ;
	for ( ; tp < tpend ; tp++)
	{
	    e = tp->e ;
	    ASSERT (e > 0 && e <= Work->nel) ;
	    if (!E [e]) continue ;	/* element already deallocated */
	    f = tp->f ;
	    p = Memory + E [e] ;
	    ep = (Element *) p ;
	    p += UNITS (Element, 1) ;
	    Cols = (Int *) p ;
	    if (Cols [f] == EMPTY) continue ;	/* column already assembled */
	    ASSERT (col == Cols [f]) ;

	    if (ep->rdeg < rdeg0)
	    {
		/* first time seen in scan1-col */
		ep->rdeg = ep->ncolsleft + rdeg0 ;
		DEBUG6 (("e "ID" First seen: rdeg: "ID" ", e, ep->rdeg-rdeg0)) ;
		ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ;
	    }

	    ep->rdeg-- ;	/* decrement external row degree */
	    DEBUG6 (("e "ID" New ext row degree: "ID"\n", e, ep->rdeg-rdeg0)) ;

	    if (ep->rdeg == rdeg0 && ep->next == EMPTY)
	    {
		/* A new LUson or Lson has been found */
		ep->next = son_list ;
		son_list = e ;
	    }

	    ASSERT (ep->rdeg >= rdeg0) ;
	    *tp2++ = *tp ;	/* leave the tuple in the list */
	}
	Col_tlen [col] = tp2 - tp1 ;
    }

    /* ---------------------------------------------------------------------- */
    /* assemble new sons via full scans */
    /* ---------------------------------------------------------------------- */

    next = EMPTY ;

    for (e = son_list ; e > 0 ; e = next)
    {
	ASSERT (e > 0 && e <= Work->nel && E [e]) ;
	p = Memory + E [e] ;
	DEBUG2 (("New son: "ID"\n", e)) ;
#ifndef NDEBUG
	UMF_dump_element (Numeric, Work, e, FALSE) ;
#endif
	GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, S) ;
	nrowsleft = ep->nrowsleft ;
	ncolsleft = ep->ncolsleft ;
	next = ep->next ;
	ep->next = EMPTY ;

	extrdeg = (ep->rdeg < rdeg0) ? ncolsleft : (ep->rdeg - rdeg0) ;
	extcdeg = (ep->cdeg < cdeg0) ? nrowsleft : (ep->cdeg - cdeg0) ;
	ncols_to_assemble = ncolsleft - extrdeg ;
	nrows_to_assemble = nrowsleft - extcdeg ;
	DEBUG2 (("extrdeg "ID" extcdeg "ID"\n", extrdeg, extcdeg)) ;

	if (extrdeg == 0 && extcdeg == 0)
	{

	    /* -------------------------------------------------------------- */
	    /* this is an LUson - assemble an entire contribution block */
	    /* -------------------------------------------------------------- */

	    DEBUG6 (("LUson found: "ID"\n", e)) ;

	    if (nrows == nrowsleft)
	    {
		/* ---------------------------------------------------------- */
		/* no rows assembled out of this LUson yet */
		/* ---------------------------------------------------------- */

		/* compute the compressed column offset vector*/
		/* [ use Wm [0..nrows-1] for offsets */
#pragma ivdep
		for (i = 0 ; i < nrows ; i++)
		{
		    row = Rows [i] ;
		    Row_degree [row] -= ncolsleft ;
		    Wm [i] = Frpos [row] ;
		}

		if (ncols == ncolsleft)
		{
		    /* ------------------------------------------------------ */
		    /* no rows or cols assembled out of LUson yet */
		    /* ------------------------------------------------------ */

		    for (j = 0 ; j < ncols ; j++)
		    {
			col = Cols [j] ;
#ifndef FIXQ
			Col_degree [col] -= nrowsleft ;
#endif
			Fcol = Fcblock + Fcpos [col] ;
#pragma ivdep
			for (i = 0 ; i < nrows ; i++)
			{
			    /* Fcol [Wm [i]] += S [i] ; */
			    ASSEMBLE (Fcol [Wm [i]], S [i]) ;
			}
			S += nrows ;
		    }


		}
		else
		{
		    /* ------------------------------------------------------ */
		    /* only cols have been assembled out of LUson */
		    /* ------------------------------------------------------ */

		    for (j = 0 ; j < ncols ; j++)
		    {
			col = Cols [j] ;
			if (col >= 0)
			{
#ifndef FIXQ
			    Col_degree [col] -= nrowsleft ;
#endif
			    Fcol = Fcblock + Fcpos [col] ;
#pragma ivdep
			    for (i = 0 ; i < nrows ; i++)
			    {
				/* Fcol [Wm [i]] += S [i] ; */
				ASSEMBLE (Fcol [Wm [i]], S [i]) ;
			    }
			}
			S += nrows ;
		    }

		}
		/* ] done using Wm [0..nrows-1] for offsets */
	    }
	    else
	    {
		/* ---------------------------------------------------------- */
		/* some rows have been assembled out of this LUson */
		/* ---------------------------------------------------------- */

		/* compute the compressed column offset vector*/
		/* [ use Woo,Wm [0..nrowsleft-1] for offsets */
		ngetrows = 0 ;
		for (i = 0 ; i < nrows ; i++)
		{
		    row = Rows [i] ;
		    if (row >= 0)
		    {
			Row_degree [row] -= ncolsleft ;
			Woo [ngetrows] = i ;
			Wm [ngetrows++] = Frpos [row] ;
		    }
		}
		ASSERT (ngetrows == nrowsleft) ;

		if (ncols == ncolsleft)
		{
		    /* ------------------------------------------------------ */
		    /* only rows have been assembled out of this LUson */
		    /* ------------------------------------------------------ */

		    for (j = 0 ; j < ncols ; j++)
		    {
			col = Cols [j] ;
#ifndef FIXQ
			Col_degree [col] -= nrowsleft ;
#endif
			Fcol = Fcblock + Fcpos [col] ;
#pragma ivdep
			for (i = 0 ; i < nrowsleft ; i++)
			{
			    /* Fcol [Wm [i]] += S [Woo [i]] ; */
			    ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
			}
			S += nrows ;
		    }

		}
		else
		{
		    /* ------------------------------------------------------ */
		    /* both rows and columns have been assembled out of LUson */
		    /* ------------------------------------------------------ */

		    for (j = 0 ; j < ncols ; j++)
		    {
			col = Cols [j] ;
			if (col >= 0)
			{
#ifndef FIXQ
			    Col_degree [col] -= nrowsleft ;
#endif
			    Fcol = Fcblock + Fcpos [col] ;
#pragma ivdep
			    for (i = 0 ; i < nrowsleft ; i++)
			    {
				/* Fcol [Wm [i]] += S [Woo [i]] ; */
				ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
			    }
			}
			S += nrows ;
		    }

		}
		/* ] done using Woo,Wm [0..nrowsleft-1] */
	    }

	    /* deallocate the element: remove from ordered list */
	    UMF_mem_free_tail_block (Numeric, E [e]) ;
	    E [e] = 0 ;

	}
	else if (extcdeg == 0)
	{

	    /* -------------------------------------------------------------- */
	    /* this is a Uson - assemble all possible columns */
	    /* -------------------------------------------------------------- */

	    DEBUG6 (("New USON: "ID"\n", e)) ;
	    ASSERT (extrdeg > 0) ;

	    DEBUG6 (("New uson "ID" cols to do "ID"\n", e, ncols_to_assemble)) ;

	    if (ncols_to_assemble > 0)
	    {

		Int skip = FALSE ;
		if (ncols_to_assemble * 16 < ncols && nrows == 1)
		{
		    /* this is a tall and thin frontal matrix consisting of
		     * only one column (most likely an original column). Do
		     * not assemble it.   It cannot be the pivot column, since
		     * the pivot column element would be an LU son, not an Lson,
		     * of the current frontal matrix. */
		    ASSERT (nrowsleft == 1) ;
		    ASSERT (Rows [0] >= 0 && Rows [0] < Work->n_row) ;
		    skip = TRUE ;
		    Work->any_skip = TRUE ;
		}

		if (!skip)
		{

		    if (nrows == nrowsleft)
		    {
			/* -------------------------------------------------- */
			/* no rows have been assembled out of this Uson yet */
			/* -------------------------------------------------- */

			/* compute the compressed column offset vector */
			/* [ use Wm [0..nrows-1] for offsets */
#pragma ivdep
			for (i = 0 ; i < nrows ; i++)
			{
			    row = Rows [i] ;
			    ASSERT (row >= 0 && row < n_row) ;
			    Row_degree [row] -= ncols_to_assemble ;
			    Wm [i] = Frpos [row] ;
			}

			for (j = 0 ; j < ncols ; j++)
			{
			    col = Cols [j] ;
			    if ((col >= 0) && (Fcpos [col] >= 0))
			    {
#ifndef FIXQ
				Col_degree [col] -= nrowsleft ;
#endif
				Fcol = Fcblock + Fcpos [col] ;
#pragma ivdep
				for (i = 0 ; i < nrows ; i++)
				{
				    /* Fcol [Wm [i]] += S [i] ; */
				    ASSEMBLE (Fcol [Wm [i]], S [i]) ;
				}
				/* flag the column as assembled from Uson */
				Cols [j] = EMPTY ;
			    }
			    S += nrows ;
			}


			/* ] done using Wm [0..nrows-1] for offsets */
		    }
		    else
		    {
			/* -------------------------------------------------- */
			/* some rows have been assembled out of this Uson */
			/* -------------------------------------------------- */

			/* compute the compressed column offset vector*/
			/* [ use Woo,Wm [0..nrows-1] for offsets */
			ngetrows = 0 ;
			for (i = 0 ; i < nrows ; i++)
			{
			    row = Rows [i] ;
			    if (row >= 0)
			    {
				Row_degree [row] -= ncols_to_assemble ;
				ASSERT (row < n_row && Frpos [row] >= 0) ;
				Woo [ngetrows] = i ;
				Wm [ngetrows++] = Frpos [row] ;
			    }
			}
			ASSERT (ngetrows == nrowsleft) ;

			for (j = 0 ; j < ncols ; j++)
			{
			    col = Cols [j] ;
			    if ((col >= 0) && (Fcpos [col] >= 0))
			    {
#ifndef FIXQ
				Col_degree [col] -= nrowsleft ;
#endif
				Fcol = Fcblock + Fcpos [col] ;
#pragma ivdep
				for (i = 0 ; i < nrowsleft ; i++)
				{
				    /* Fcol [Wm [i]] += S [Woo [i]] ; */
				    ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
				}
				/* flag the column as assembled from Uson */
				Cols [j] = EMPTY ;
			    }
			    S += nrows ;
			}

			/* ] done using Woo,Wm */
		    }
		    ep->ncolsleft = extrdeg ;
		}
	    }

	}
	else
	{

	    /* -------------------------------------------------------------- */
	    /* this is an Lson - assemble all possible rows */
	    /* -------------------------------------------------------------- */

	    DEBUG6 (("New LSON: "ID"\n", e)) ;
	    ASSERT (extrdeg == 0 && extcdeg > 0) ;

	    DEBUG6 (("New lson "ID" rows to do "ID"\n", e, nrows_to_assemble)) ;

	    if (nrows_to_assemble > 0)
	    {

		Int skip = FALSE ;
		if (nrows_to_assemble * 16 < nrows && ncols == 1)
		{
		    /* this is a tall and thin frontal matrix consisting of
		     * only one column (most likely an original column). Do
		     * not assemble it.   It cannot be the pivot column, since
		     * the pivot column element would be an LU son, not an Lson,
		     * of the current frontal matrix. */
		    ASSERT (ncolsleft == 1) ;
		    ASSERT (Cols [0] >= 0 && Cols [0] < Work->n_col) ;
		    Work->any_skip = TRUE ;
		    skip = TRUE ;
		}

		if (!skip)
		{

		    /* compute the compressed column offset vector */
		    /* [ use Woo,Wm [0..nrows-1] for offsets */
		    ngetrows = 0 ;
		    for (i = 0 ; i < nrows ; i++)
		    {
			row = Rows [i] ;
			if ((row >= 0) && (Frpos [row] >= 0))
			{
			    ASSERT (row < n_row) ;
			    Row_degree [row] -= ncolsleft ;
			    Woo [ngetrows] = i ;
			    Wm [ngetrows++] = Frpos [row] ;
			    /* flag the row as assembled from the Lson */
			    Rows [i] = EMPTY ;
			}
		    }
		    ASSERT (nrowsleft - ngetrows == extcdeg) ;
		    ASSERT (ngetrows == nrows_to_assemble) ;

		    if (ncols == ncolsleft)
		    {
			/* -------------------------------------------------- */
			/* no columns assembled out this Lson yet */
			/* -------------------------------------------------- */

			for (j = 0 ; j < ncols ; j++)
			{
			    col = Cols [j] ;
			    ASSERT (col >= 0 && col < n_col) ;
#ifndef FIXQ
			    Col_degree [col] -= nrows_to_assemble ;
#endif
			    Fcol = Fcblock + Fcpos [col] ;
#pragma ivdep
			    for (i = 0 ; i < nrows_to_assemble ; i++)
			    {
				/* Fcol [Wm [i]] += S [Woo [i]] ; */
				ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
			    }
			    S += nrows ;
			}


		    }
		    else
		    {
			/* -------------------------------------------------- */
			/* some columns have been assembled out of this Lson */
			/* -------------------------------------------------- */

			for (j = 0 ; j < ncols ; j++)
			{
			    col = Cols [j] ;
			    ASSERT (col < n_col) ;
			    if (col >= 0)
			    {
#ifndef FIXQ
				Col_degree [col] -= nrows_to_assemble ;
#endif
				Fcol = Fcblock + Fcpos [col] ;
#pragma ivdep
				for (i = 0 ; i < nrows_to_assemble ; i++)
				{
				    /* Fcol [Wm [i]] += S [Woo [i]] ; */
				    ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
				}
			    }
			    S += nrows ;
			}

		    }

		    /* ] done using Woo,Wm */

		    ep->nrowsleft = extcdeg ;
		}
	    }
	}
    }

    /* Note that garbage collection, and build tuples */
    /* both destroy the son list. */

    /* ] son_list now empty */

    /* ---------------------------------------------------------------------- */
    /* If frontal matrix extended, assemble old L/Usons from new rows/cols */
    /* ---------------------------------------------------------------------- */

    /* ---------------------------------------------------------------------- */
    /* SCAN2-row:  assemble rows of old Lsons from the new rows */
    /* ---------------------------------------------------------------------- */

#ifndef NDEBUG
    DEBUG7 (("Current frontal matrix: (prior to scan2-row)\n")) ;
    UMF_dump_current_front (Numeric, Work, TRUE) ;
#endif

    /* rescan the pivot row */
    if (Work->any_skip)
    {
	row_assemble (Work->pivrow, Numeric, Work) ;
    }

    if (Work->do_scan2row)
    {
	for (i2 = Work->fscan_row ; i2 < fnrows ; i2++)
	{
	    /* Get a row */
	    row = Work->NewRows [i2] ;
	    if (row < 0) row = FLIP (row) ;
	    ASSERT (row >= 0 && row < n_row) ;
	    if (!(row == Work->pivrow && Work->any_skip))
	    {
		/* assemble it */
		row_assemble (row, Numeric, Work) ;
	    }
	}
    }

    /* ---------------------------------------------------------------------- */
    /* SCAN2-col:  assemble columns of old Usons from the new columns */
    /* ---------------------------------------------------------------------- */

#ifndef NDEBUG
    DEBUG7 (("Current frontal matrix: (prior to scan2-col)\n")) ;
    UMF_dump_current_front (Numeric, Work, TRUE) ;
#endif

    /* rescan the pivot col */
    if (Work->any_skip)
    {
	col_assemble (Work->pivcol, Numeric, Work) ;
    }

    if (Work->do_scan2col)
    {

	for (j2 = Work->fscan_col ; j2 < fncols ; j2++)
	{
	    /* Get a column */
	    col = Work->NewCols [j2] ;
	    if (col < 0) col = FLIP (col) ;
	    ASSERT (col >= 0 && col < n_col) ;
	    if (!(col == Work->pivcol && Work->any_skip))
	    {
		/* assemble it */
		col_assemble (col, Numeric, Work) ;
	    }
	}
    }

    /* ---------------------------------------------------------------------- */
    /* done.  the remainder of this routine is used only when in debug mode */
    /* ---------------------------------------------------------------------- */

#ifndef NDEBUG

    /* ---------------------------------------------------------------------- */
    /* when debugging: make sure the assembly did everything that it could */
    /* ---------------------------------------------------------------------- */

    DEBUG3 (("::Assemble done\n")) ;

    for (i2 = 0 ; i2 < fnrows ; i2++)
    {
	/* Get a row */
	row = Work->Frows [i2] ;
	ASSERT (row >= 0 && row < n_row) ;

	DEBUG6 (("DEBUG SCAN 1: "ID"\n", row)) ;
	UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;

	ASSERT (NON_PIVOTAL_ROW (row)) ;
	tpi = Row_tuples [row] ;
	if (!tpi) continue ;
	tp = (Tuple *) (Memory + tpi) ;
	tpend = tp + Row_tlen [row] ;
	for ( ; tp < tpend ; tp++)
	{
	    e = tp->e ;
	    ASSERT (e > 0 && e <= Work->nel) ;
	    if (!E [e]) continue ;	/* element already deallocated */
	    f = tp->f ;
	    p = Memory + E [e] ;
	    ep = (Element *) p ;
	    p += UNITS (Element, 1) ;
	    Cols = (Int *) p ;
	    Rows = ((Int *) p) + ep->ncols ;
	    if (Rows [f] == EMPTY) continue ;	/* row already assembled */
	    ASSERT (row == Rows [f]) ;
	    extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ;
	    extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ;
	    DEBUG6 ((
		"e "ID" After assembly ext row deg: "ID" ext col degree "ID"\n",
		e, extrdeg, extcdeg)) ;

	    if (Work->any_skip)
	    {
		/* no Lsons in any row, except for very tall and thin ones */
		ASSERT (extrdeg >= 0) ;
		if (extrdeg == 0)
		{
		    /* this is an unassemble Lson */
		    ASSERT (ep->ncols == 1) ;
		    ASSERT (ep->ncolsleft == 1) ;
		    col = Cols [0] ;
		    ASSERT (col != Work->pivcol) ;
		}
	    }
	    else
	    {
		/* no Lsons in any row */
		ASSERT (extrdeg > 0) ;
		/* Uson external row degree is = number of cols left */
		ASSERT (IMPLIES (extcdeg == 0, extrdeg == ep->ncolsleft)) ;
	    }
	}
    }

    /* ---------------------------------------------------------------------- */

    for (j2 = 0 ; j2 < fncols ; j2++)
    {
	/* Get a column */
	col = Work->Fcols [j2] ;
	ASSERT (col >= 0 && col < n_col) ;

	DEBUG6 (("DEBUG SCAN 2: "ID"\n", col)) ;
#ifndef FIXQ
	UMF_dump_rowcol (1, Numeric, Work, col, TRUE) ;
#else
	UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
#endif

	ASSERT (NON_PIVOTAL_COL (col)) ;
	tpi = Col_tuples [col] ;
	if (!tpi) continue ;
	tp = (Tuple *) (Memory + tpi) ;
	tpend = tp + Col_tlen [col] ;
	for ( ; tp < tpend ; tp++)
	{
	    e = tp->e ;
	    ASSERT (e > 0 && e <= Work->nel) ;
	    if (!E [e]) continue ;	/* element already deallocated */
	    f = tp->f ;
	    p = Memory + E [e] ;
	    ep = (Element *) p ;
	    p += UNITS (Element, 1) ;
	    Cols = (Int *) p ;
	    Rows = ((Int *) p) + ep->ncols ;
	    if (Cols [f] == EMPTY) continue ;	/* column already assembled */
	    ASSERT (col == Cols [f]) ;
	    extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ;
	    extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ;
	    DEBUG6 (("e "ID" After assembly ext col deg: "ID"\n", e, extcdeg)) ;

	    if (Work->any_skip)
	    {
		/* no Usons in any column, except for very tall and thin ones */
		ASSERT (extcdeg >= 0) ;
		if (extcdeg == 0)
		{
		    /* this is an unassemble Uson */
		    ASSERT (ep->nrows == 1) ;
		    ASSERT (ep->nrowsleft == 1) ;
		    row = Rows [0] ;
		    ASSERT (row != Work->pivrow) ;
		}
	    }
	    else
	    {
		/* no Usons in any column */
		ASSERT (extcdeg > 0) ;
		/* Lson external column degree is = number of rows left */
		ASSERT (IMPLIES (extrdeg == 0, extcdeg == ep->nrowsleft)) ;
	    }
	}
    }
#endif /* NDEBUG */
}
Esempio n. 20
0
/*
 *	Check the min_spare_threads and max_spare_threads.
 *
 *	If there are too many or too few threads waiting, then we
 *	either create some more, or delete some.
 */
static void thread_pool_manage(time_t now)
{
	int spare;
	int i, total;
	THREAD_HANDLE *handle, *next;
	int active_threads;

	/*
	 *	We don't need a mutex lock here, as we're reading
	 *	active_threads, and not modifying it.  We want a close
	 *	approximation of the number of active threads, and this
	 *	is good enough.
	 */
	active_threads = thread_pool.active_threads;
	spare = thread_pool.total_threads - active_threads;
	if (debug_flag) {
		static int old_total = -1;
		static int old_active = -1;

		if ((old_total != thread_pool.total_threads) ||
				(old_active != active_threads)) {
			DEBUG2("Threads: total/active/spare threads = %d/%d/%d",
					thread_pool.total_threads, active_threads, spare);
			old_total = thread_pool.total_threads;
			old_active = active_threads;
		}
	}

	/*
	 *	If there are too few spare threads.  Go create some more.
	 */
	if ((thread_pool.total_threads < thread_pool.max_threads) &&
	    (spare < thread_pool.min_spare_threads)) {
		total = thread_pool.min_spare_threads - spare;

		if ((total + thread_pool.total_threads) > thread_pool.max_threads) {
			total = thread_pool.max_threads - thread_pool.total_threads;
		}

		DEBUG2("Threads: Spawning %d spares", total);

		/*
		 *	Create a number of spare threads.
		 */
		for (i = 0; i < total; i++) {
			handle = spawn_thread(now, 1);
			if (handle == NULL) {
				return;
			}
		}

		return;		/* there aren't too many spare threads */
	}

	/*
	 *	Only delete spare threads if we haven't already done
	 *	so this second.
	 */
	if (now == last_cleaned) {
		return;
	}
	last_cleaned = now;

	/*
	 *	Loop over the thread pool, deleting exited threads.
	 */
	for (handle = thread_pool.head; handle; handle = next) {
		next = handle->next;

		/*
		 *	Maybe we've asked the thread to exit, and it
		 *	has agreed.
		 */
		if (handle->status == THREAD_EXITED) {
			pthread_join(handle->pthread_id, NULL);
			delete_thread(handle);
		}
	}

	/*
	 *	Only delete the spare threads if sufficient time has
	 *	passed since we last created one.  This helps to minimize
	 *	the amount of create/delete cycles.
	 */
	if ((now - thread_pool.time_last_spawned) < thread_pool.cleanup_delay) {
		return;
	}

	/*
	 *	If there are too many spare threads, delete one.
	 *
	 *	Note that we only delete ONE at a time, instead of
	 *	wiping out many.  This allows the excess servers to
	 *	be slowly reaped, just in case the load spike comes again.
	 */
	if (spare > thread_pool.max_spare_threads) {

		spare -= thread_pool.max_spare_threads;

		DEBUG2("Threads: deleting 1 spare out of %d spares", spare);

		/*
		 *	Walk through the thread pool, deleting the
		 *	first idle thread we come across.
		 */
		for (handle = thread_pool.head; (handle != NULL) && (spare > 0) ; handle = next) {
			next = handle->next;

			/*
			 *	If the thread is not handling a
			 *	request, but still live, then tell it
			 *	to exit.
			 *
			 *	It will eventually wake up, and realize
			 *	it's been told to commit suicide.
			 */
			if ((handle->request == NULL) &&
			    (handle->status == THREAD_RUNNING)) {
				handle->status = THREAD_CANCELLED;
				/*
				 *	Post an extra semaphore, as a
				 *	signal to wake up, and exit.
				 */
				sem_post(&thread_pool.semaphore);
				spare--;
				break;
			}
		}
	}

	/*
	 *	If the thread has handled too many requests, then make it
	 *	exit.
	 */
	if (thread_pool.max_requests_per_thread > 0) {
		for (handle = thread_pool.head; handle; handle = next) {
			next = handle->next;

			/*
			 *	Not handling a request, but otherwise
			 *	live, we can kill it.
			 */
			if ((handle->request == NULL) &&
			    (handle->status == THREAD_RUNNING) &&
			    (handle->request_count > thread_pool.max_requests_per_thread)) {
				handle->status = THREAD_CANCELLED;
				sem_post(&thread_pool.semaphore);
			}
		}
	}

	/*
	 *	Otherwise everything's kosher.  There are not too few,
	 *	or too many spare threads.  Exit happily.
	 */
	return;
}
Esempio n. 21
0
/*
 *	Check one terminal server to see if a user is logged in.
 *
 *	Return values:
 *		0 The user is off-line.
 *		1 The user is logged in.
 *		2 Some error occured.
 */
int rad_check_ts(uint32_t nasaddr, unsigned int portnum, char const *user,
		 char const *session_id)
{
	pid_t	pid, child_pid;
	int	status;
	char	address[16];
	char	port[11];
	RADCLIENT *cl;
	fr_ipaddr_t ipaddr;

	ipaddr.af = AF_INET;
	ipaddr.ipaddr.ip4addr.s_addr = nasaddr;

	/*
	 *	Find NAS type.
	 */
	cl = client_find_old(&ipaddr);
	if (!cl) {
		/*
		 *  Unknown NAS, so trusting radutmp.
		 */
		DEBUG2("checkrad: Unknown NAS %s, not checking",
		       ip_ntoa(address, nasaddr));
		return 1;
	}

	/*
	 *  No nas_type, or nas type 'other', trust radutmp.
	 */
	if (!cl->nas_type || (cl->nas_type[0] == '\0') ||
	    (strcmp(cl->nas_type, "other") == 0)) {
		DEBUG2("checkrad: No NAS type, or type \"other\" not checking");
		return 1;
	}

	/*
	 *	Fork.
	 */
	if ((pid = rad_fork()) < 0) { /* do wait for the fork'd result */
		ERROR("Accounting: Failed in fork(): Cannot run checkrad\n");
		return 2;
	}

	if (pid > 0) {
		child_pid = rad_waitpid(pid, &status);

		/*
		 *	It's taking too long.  Stop waiting for it.
		 *
		 *	Don't bother to kill it, as we don't care what
		 *	happens to it now.
		 */
		if (child_pid == 0) {
			ERROR("Check-TS: timeout waiting for checkrad");
			return 2;
		}

		if (child_pid < 0) {
			ERROR("Check-TS: unknown error in waitpid()");
			return 2;
		}

		return WEXITSTATUS(status);
	}

	/*
	 *  We don't close fd's 0, 1, and 2.  If we're in debugging mode,
	 *  then they should go to stdout (etc), along with the other
	 *  server log messages.
	 *
	 *  If we're not in debugging mode, then the code in radiusd.c
	 *  takes care of connecting fd's 0, 1, and 2 to /dev/null.
	 */
	closefrom(3);

	ip_ntoa(address, nasaddr);
	snprintf(port, 11, "%u", portnum);

#ifdef __EMX__
	/* OS/2 can't directly execute scripts then we call the command
	   processor to execute checkrad
	*/
	execl(getenv("COMSPEC"), "", "/C","checkrad", cl->nas_type, address, port,
		user, session_id, NULL);
#else
	execl(mainconfig.checkrad, "checkrad", cl->nas_type, address, port,
		user, session_id, NULL);
#endif
	ERROR("Check-TS: exec %s: %s", mainconfig.checkrad, strerror(errno));

	/*
	 *	Exit - 2 means "some error occured".
	 */
	exit(2);
	return 2;
}
Esempio n. 22
0
/*
 *	The main thread handler for requests.
 *
 *	Wait on the semaphore until we have it, and process the request.
 */
static void *request_handler_thread(void *arg)
{
	THREAD_HANDLE	  *self = (THREAD_HANDLE *) arg;

	/*
	 *	Loop forever, until told to exit.
	 */
	do {
		/*
		 *	Wait to be signalled.
		 */
		DEBUG2("Thread %d waiting to be assigned a request",
		       self->thread_num);
	re_wait:
		if (sem_wait(&thread_pool.semaphore) != 0) {
			/*
			 *	Interrupted system call.  Go back to
			 *	waiting, but DON'T print out any more
			 *	text.
			 */
			if (errno == EINTR) {
				DEBUG2("Re-wait %d", self->thread_num);
				goto re_wait;
			}
			radlog(L_ERR, "Thread %d failed waiting for semaphore: %s: Exiting\n",
			       self->thread_num, strerror(errno));
			break;
		}

		DEBUG2("Thread %d got semaphore", self->thread_num);

#ifdef HAVE_OPENSSL_ERR_H
 		/*
		 *	Clear the error queue for the current thread.
		 */
		ERR_clear_error ();
#endif

		/*
		 *	The server is exiting.  Don't dequeue any
		 *	requests.
		 */
		if (thread_pool.stop_flag) break;

		/*
		 *	Try to grab a request from the queue.
		 *
		 *	It may be empty, in which case we fail
		 *	gracefully.
		 */
		if (!request_dequeue(&self->request)) continue;

		self->request->child_pid = self->pthread_id;
		self->request_count++;

		DEBUG2("Thread %d handling request %d, (%d handled so far)",
		       self->thread_num, self->request->number,
		       self->request_count);

		if ((self->request->packet->code == PW_ACCOUNTING_REQUEST) &&
		    thread_pool.auto_limit_acct) {
			VALUE_PAIR *vp;
			REQUEST *request = self->request;

			vp = radius_paircreate(request, &request->config_items,
					       181, VENDORPEC_FREERADIUS,
					       PW_TYPE_INTEGER);
			if (vp) vp->vp_integer = thread_pool.pps_in.pps;

			vp = radius_paircreate(request, &request->config_items,
					       182, VENDORPEC_FREERADIUS,
					       PW_TYPE_INTEGER);
			if (vp) vp->vp_integer = thread_pool.pps_in.pps;
			
			vp = radius_paircreate(request, &request->config_items,
					       183, VENDORPEC_FREERADIUS,
					       PW_TYPE_INTEGER);
			if (vp) {
				vp->vp_integer = thread_pool.max_queue_size - thread_pool.num_queued;
				vp->vp_integer *= 100;
				vp->vp_integer /= thread_pool.max_queue_size;
			}
		}

		self->request->process(self->request, FR_ACTION_RUN);
		self->request = NULL;

		/*
		 *	Update the active threads.
		 */
		pthread_mutex_lock(&thread_pool.queue_mutex);
		rad_assert(thread_pool.active_threads > 0);
		thread_pool.active_threads--;
		pthread_mutex_unlock(&thread_pool.queue_mutex);
	} while (self->status != THREAD_CANCELLED);

	DEBUG2("Thread %d exiting...", self->thread_num);

#ifdef HAVE_OPENSSL_ERR_H
	/*
	 *	If we linked with OpenSSL, the application
	 *	must remove the thread's error queue before
	 *	exiting to prevent memory leaks.
	 */
	ERR_remove_state(0);
#endif

	/*
	 *  Do this as the LAST thing before exiting.
	 */
	self->request = NULL;
	self->status = THREAD_EXITED;
	exec_trigger(NULL, NULL, "server.thread.stop", TRUE);

	return NULL;
}
static SECURID_AUTH_RC securidAuth(void *instance, REQUEST *request,
				   const char* username, 
				   const char* passcode,
				   char* replyMsgBuffer,int replyMsgBufferSize)
{
	rlm_securid_t *inst = (rlm_securid_t *) instance;
	int         acmRet;
	SD_PIN pinParams;
	char newPin[10];
	char format[30];
	SECURID_SESSION *pSecurid_session=NULL;
	int rc=-1;

	if (!username) {
		radlog(L_ERR, "SecurID username is NULL");
		return RC_SECURID_AUTH_FAILURE;		
	}

	if (!passcode) {
		radlog(L_ERR, "SecurID passcode is NULL for %s user",username);
		return RC_SECURID_AUTH_FAILURE;		
	}

	*replyMsgBuffer = '\0';

	pSecurid_session = securid_sessionlist_find(inst,request);
	if (pSecurid_session == NULL) {
		/* securid session not found */
		SDI_HANDLE  sdiHandle = SDI_HANDLE_NONE;

		acmRet = SD_Init(&sdiHandle);
		if (acmRet != ACM_OK) {
			radlog(L_ERR, "Cannot communicate with the ACE/Server");
			return -1;
		}

		acmRet = SD_Lock(sdiHandle, (SD_CHAR*)username);
		if (acmRet != ACM_OK) {
			radlog(L_ERR,"SecurID: Access denied. Name [%s] lock failed.",username);
			return -2;
		}

		acmRet = SD_Check(sdiHandle, (SD_CHAR*) passcode,
				  (SD_CHAR*) username);
		switch (acmRet) {
		case ACM_OK:
			/* we are in now */
			RDEBUG("SecurID authentication successful for %s.",
			       username);
			SD_Close(sdiHandle);

			return RC_SECURID_AUTH_SUCCESS;

		case ACM_ACCESS_DENIED:         
			/* not this time */
			RDEBUG("SecurID Access denied for %s", username);
			SD_Close(sdiHandle);
			return RC_SECURID_AUTH_ACCESS_DENIED_FAILURE;

		case ACM_INVALID_SERVER:
			radlog(L_ERR,"SecurID: Invalid ACE server.");
			return RC_SECURID_AUTH_INVALID_SERVER_FAILURE;

		case ACM_NEW_PIN_REQUIRED:
			RDEBUG2("SecurID new pin required for %s",
				username);

			/* create a new session */
			pSecurid_session = securid_session_alloc();
			pSecurid_session->sdiHandle = sdiHandle; /* save ACE handle for future use */
			pSecurid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;
			pSecurid_session->identity = strdup(username);
			 
			/* Get PIN requirements */
			acmRet = AceGetPinParams(sdiHandle, &pinParams);
			 
			/* If a system-generated PIN is required */
			if (pinParams.Selectable == CANNOT_CHOOSE_PIN) {
				/* Prompt user to accept a system generated PIN */
				snprintf(replyMsgBuffer, replyMsgBufferSize,
					 "\r\nAre you prepared to accept a new system-generated PIN [y/n]?");
				pSecurid_session->securidSessionState = NEW_PIN_SYSTEM_ACCEPT_STATE;

			} else if (pinParams.Selectable == USER_SELECTABLE) { //may be returned by AM 6.x servers.
				snprintf(replyMsgBuffer, replyMsgBufferSize,
					 "\r\nPress 'y' to generate a new PIN\r\nOR\r\n'n'to enter a new PIN yourself [y/n]");
				pSecurid_session->securidSessionState = NEW_PIN_USER_SELECT_STATE;

			} else {
				if (pinParams.Alphanumeric) {
					strcpy(format, "alphanumeric characters");
				} else {
					strcpy(format, "digits");
				}
				snprintf(replyMsgBuffer, replyMsgBufferSize,
					 " \r\n   Enter your new PIN of %d to %d %s,\r\n                or\r\n   <Ctrl-D> to cancel the New PIN procedure:",
					 pinParams.Min, pinParams.Max, format);
			}

			/* insert new session in the session list */
			securid_sessionlist_add(inst,request,pSecurid_session);
			 
			return RC_SECURID_AUTH_CHALLENGE;

		case ACM_NEXT_CODE_REQUIRED:
			RDEBUG2("Next securid token code required for %s",
				username);

			/* create a new session */
			pSecurid_session = securid_session_alloc();
			pSecurid_session->sdiHandle = sdiHandle;
			pSecurid_session->securidSessionState = NEXT_CODE_REQUIRED_STATE;
			pSecurid_session->identity = strdup(username);

			/* insert new session in the session list */
			securid_sessionlist_add(inst,request,pSecurid_session);
		     
			strlcpy(replyMsgBuffer, "\r\nPlease Enter the Next Code from Your Token:", replyMsgBufferSize);
			return RC_SECURID_AUTH_CHALLENGE;
		default:
			radlog(L_ERR,"SecurID: Unexpected error from ACE/Agent API acmRet=%d",acmRet);
			return RC_SECURID_AUTH_FAILURE;
  
			
		}
	} else {
		/* existing session found */
		RDEBUG("Continuing previous session found for user [%s]",username);

		/* continue previous session */
		switch (pSecurid_session->securidSessionState) {
		case NEXT_CODE_REQUIRED_STATE:
			DEBUG2("Securid NEXT_CODE_REQUIRED_STATE: User [%s]",username);
			/* next token code mode */

			acmRet = SD_Next(pSecurid_session->sdiHandle, (SD_CHAR*)passcode);
			if (acmRet == ACM_OK) {
				radlog(L_INFO,"Next SecurID token accepted for [%s].",pSecurid_session->identity);
				rc = RC_SECURID_AUTH_SUCCESS;

			} else {
				radlog(L_INFO,"SecurID: Next token rejected for [%s].",pSecurid_session->identity);
				rc = RC_SECURID_AUTH_FAILURE;
			}

			/* deallocate session */
			securid_session_free(inst,request,pSecurid_session);
			return rc;

		case NEW_PIN_REQUIRED_STATE:
			RDEBUG2("SecurID NEW_PIN_REQUIRED_STATE for %s",
				username);

			/* save the previous pin */
			if (pSecurid_session->pin) {
				free(pSecurid_session->pin);
				pSecurid_session->pin = NULL;
			}
			pSecurid_session->pin = strdup(passcode);

			strlcpy(replyMsgBuffer,"\r\n                 Please re-enter new PIN:", replyMsgBufferSize);

			/* set next state */
			pSecurid_session->securidSessionState = NEW_PIN_USER_CONFIRM_STATE;

			/* insert the updated session in the session list */
			securid_sessionlist_add(inst,request,pSecurid_session);
			return RC_SECURID_AUTH_CHALLENGE;
			  
		case NEW_PIN_USER_CONFIRM_STATE:
			RDEBUG2("SecurID NEW_PIN_USER_CONFIRM_STATE: User [%s]",username);
			/* compare previous pin and current pin */
			if (!pSecurid_session->pin || strcmp(pSecurid_session->pin,passcode)) {
				RDEBUG2("Pin confirmation failed. Pins do not match [%s] and [%s]",
				       SAFE_STR(pSecurid_session->pin),
				       passcode);
				/* pins do not match */

				/* challenge the user again */
				AceGetPinParams(pSecurid_session->sdiHandle, &pinParams);
				if (pinParams.Alphanumeric) {
					strcpy(format, "alphanumeric characters");
				} else {
					strcpy(format, "digits");
				}
				snprintf(replyMsgBuffer, replyMsgBufferSize,
					 " \r\n   Pins do not match--Please try again.\r\n   Enter your new PIN of %d to %d %s,\r\n                or\r\n   <Ctrl-D> to cancel the New PIN procedure:",
					 pinParams.Min, pinParams.Max, format);

				pSecurid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;

				/* insert the updated session in the session list */
				securid_sessionlist_add(inst,request,pSecurid_session);
				rc = RC_SECURID_AUTH_CHALLENGE;

			} else {
				/* pins match */
				RDEBUG2("Pin confirmation succeeded. Pins match");
				acmRet = SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)passcode);
				if (acmRet == ACM_NEW_PIN_ACCEPTED) {
					RDEBUG("New SecurID pin accepted for %s.",pSecurid_session->identity);

					pSecurid_session->securidSessionState = NEW_PIN_AUTH_VALIDATE_STATE;

					/* insert the updated session in the session list */
					securid_sessionlist_add(inst,request,pSecurid_session);

					rc = RC_SECURID_AUTH_CHALLENGE;
					strlcpy(replyMsgBuffer," \r\n\r\nWait for the code on your card to change, then enter new PIN and TokenCode\r\n\r\nEnter PASSCODE:", replyMsgBufferSize);
				} else {
					RDEBUG("SecurID: New SecurID pin rejected for %s.",pSecurid_session->identity);
					SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)"");  /* cancel PIN */
					

					rc = RC_SECURID_AUTH_FAILURE;

					/* deallocate session */
					securid_session_free(inst, request,
							     pSecurid_session);
				}
			}
			return rc;		  
		case NEW_PIN_AUTH_VALIDATE_STATE:
			acmRet = SD_Check(pSecurid_session->sdiHandle, (SD_CHAR*)passcode, (SD_CHAR*)username);
			if (acmRet == ACM_OK) {
				RDEBUG("New SecurID passcode accepted for %s.",
				       pSecurid_session->identity);
				rc = RC_SECURID_AUTH_SUCCESS;

			} else {
				radlog(L_INFO,"SecurID: New passcode rejected for [%s].",pSecurid_session->identity);
				rc = RC_SECURID_AUTH_FAILURE;
			}

			/* deallocate session */
			securid_session_free(inst,request,pSecurid_session);

			return rc;
		case NEW_PIN_SYSTEM_ACCEPT_STATE:
			if (!strcmp(passcode, "y")) {
				AceGetSystemPin(pSecurid_session->sdiHandle, newPin);
					
				/* Save the PIN for the next session
				 * continuation */
				if (pSecurid_session->pin) {
					free(pSecurid_session->pin);
					pSecurid_session->pin = NULL;
				}
				pSecurid_session->pin = strdup(newPin);
					
				snprintf(replyMsgBuffer, replyMsgBufferSize,
					 "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
					 newPin);
				pSecurid_session->securidSessionState = NEW_PIN_SYSTEM_CONFIRM_STATE;
					
				/* insert the updated session in the
				 * session list */
				securid_sessionlist_add(inst, request,
							pSecurid_session);
					
				rc = RC_SECURID_AUTH_CHALLENGE;

			} else {
				SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)""); //Cancel new PIN
					
				/* deallocate session */
				securid_session_free(inst, request,
						     pSecurid_session);
					
				rc = RC_SECURID_AUTH_FAILURE;
			}
				
			return rc;				
			 
		case NEW_PIN_SYSTEM_CONFIRM_STATE:
			acmRet = SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)pSecurid_session->pin);
			if (acmRet == ACM_NEW_PIN_ACCEPTED) {
				strlcpy(replyMsgBuffer," \r\n\r\nPin Accepted. Wait for the code on your card to change, then enter new PIN and TokenCode\r\n\r\nEnter PASSCODE:",replyMsgBufferSize);
				pSecurid_session->securidSessionState = NEW_PIN_AUTH_VALIDATE_STATE;
				/* insert the updated session in the session list */
				securid_sessionlist_add(inst,request,pSecurid_session);
				rc = RC_SECURID_AUTH_CHALLENGE;

			} else {
				SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)""); //Cancel new PIN
				strlcpy(replyMsgBuffer," \r\n\r\nPin Rejected. Wait for the code on your card to change, then try again.\r\n\r\nEnter PASSCODE:",replyMsgBufferSize);
				/* deallocate session */
				securid_session_free(inst, request,
						     pSecurid_session);
				rc = RC_SECURID_AUTH_FAILURE;
			}
				
			return rc;
			 
			/* USER_SELECTABLE state should be implemented to preserve compatibility with AM 6.x servers, which can return this state */
		case NEW_PIN_USER_SELECT_STATE:
			if (!strcmp(passcode, "y")) {
				/* User has opted for a system-generated PIN */
				AceGetSystemPin(pSecurid_session->sdiHandle, newPin);
				snprintf(replyMsgBuffer, replyMsgBufferSize,
					 "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
					 newPin);
				pSecurid_session->securidSessionState = NEW_PIN_SYSTEM_CONFIRM_STATE;
					
				/* insert the updated session in the session list */
				securid_sessionlist_add(inst, request,
							pSecurid_session);
				rc = RC_SECURID_AUTH_CHALLENGE;

			} else {
				/* User has opted for a user-defined PIN */
				AceGetPinParams(pSecurid_session->sdiHandle,
						&pinParams);
				if (pinParams.Alphanumeric) {
					strcpy(format, "alphanumeric characters");
				} else {
					strcpy(format, "digits");
				}
					
				snprintf(replyMsgBuffer, replyMsgBufferSize,
					 " \r\n   Enter your new PIN of %d to %d %s,\r\n                or\r\n   <Ctrl-D> to cancel the New PIN procedure:",
					 pinParams.Min, pinParams.Max, format);
				pSecurid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;
					
				/* insert the updated session in the session list */
				securid_sessionlist_add(inst, request,
							pSecurid_session);
				rc = RC_SECURID_AUTH_CHALLENGE;
			}
				
			return rc;
				
		default:
			radlog(L_ERR|L_CONS, "rlm_securid: Invalid session state %d for user [%s]",
			       pSecurid_session->securidSessionState,
			       username);
			break;	
		}
	}
	
	return 0;
		
}
Esempio n. 24
0
/*
 *	Spawn a new thread, and place it in the thread pool.
 *
 *	The thread is started initially in the blocked state, waiting
 *	for the semaphore.
 */
static THREAD_HANDLE *spawn_thread(time_t now, int do_trigger)
{
	int rcode;
	THREAD_HANDLE *handle;

	/*
	 *	Ensure that we don't spawn too many threads.
	 */
	if (thread_pool.total_threads >= thread_pool.max_threads) {
		DEBUG2("Thread spawn failed.  Maximum number of threads (%d) already running.", thread_pool.max_threads);
		exec_trigger(NULL, NULL, "server.thread.max_threads", TRUE);
		return NULL;
	}

	/*
	 *	Allocate a new thread handle.
	 */
	handle = (THREAD_HANDLE *) rad_malloc(sizeof(THREAD_HANDLE));
	memset(handle, 0, sizeof(THREAD_HANDLE));
	handle->prev = NULL;
	handle->next = NULL;
	handle->thread_num = thread_pool.max_thread_num++;
	handle->request_count = 0;
	handle->status = THREAD_RUNNING;
	handle->timestamp = time(NULL);

	/*
	 *	Create the thread joinable, so that it can be cleaned up
	 *	using pthread_join().
	 *
	 *	Note that the function returns non-zero on error, NOT
	 *	-1.  The return code is the error, and errno isn't set.
	 */
	rcode = pthread_create(&handle->pthread_id, 0,
			request_handler_thread, handle);
	if (rcode != 0) {
		radlog(L_ERR, "Thread create failed: %s",
		       strerror(rcode));
		return NULL;
	}

	/*
	 *	One more thread to go into the list.
	 */
	thread_pool.total_threads++;
	DEBUG2("Thread spawned new child %d. Total threads in pool: %d",
			handle->thread_num, thread_pool.total_threads);
	if (do_trigger) exec_trigger(NULL, NULL, "server.thread.start", TRUE);

	/*
	 *	Add the thread handle to the tail of the thread pool list.
	 */
	if (thread_pool.tail) {
		thread_pool.tail->next = handle;
		handle->prev = thread_pool.tail;
		thread_pool.tail = handle;
	} else {
		rad_assert(thread_pool.head == NULL);
		thread_pool.head = thread_pool.tail = handle;
	}

	/*
	 *	Update the time we last spawned a thread.
	 */
	thread_pool.time_last_spawned = now;

	/*
	 *	And return the new handle to the caller.
	 */
	return handle;
}
Esempio n. 25
0
/*
 *	Relay the request to a remote server.
 *	Returns:
 *
 *      RLM_MODULE_FAIL: we don't reply, caller returns without replying
 *      RLM_MODULE_NOOP: caller falls through to normal processing
 *      RLM_MODULE_HANDLED  : we reply, caller returns without replying
 */
int proxy_send(REQUEST *request)
{
	int rcode;
	int pre_proxy_type = 0;
	VALUE_PAIR *realmpair;
	VALUE_PAIR *strippedname;
	VALUE_PAIR *delaypair;
	VALUE_PAIR *vp;
	REALM *realm;
	char *realmname;

	/*
	 *	Not authentication or accounting.  Stop it.
	 */
	if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
	    (request->packet->code != PW_ACCOUNTING_REQUEST)) {
		DEBUG2("  ERROR: Cannot proxy packets of type %d",
		       request->packet->code);
		return RLM_MODULE_FAIL;
	}

	/*
	 *	The timestamp is used below to figure the
	 *	next_try. The request needs to "hang around" until
	 *	either the other server sends a reply or the retry
	 *	count has been exceeded.  Until then, it should not
	 *	be eligible for the time-based cleanup.  --Pac. */

	realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM);
	if (!realmpair) {
		/*
		 *	Not proxying, so we can exit from the proxy
		 *	code.
		 */
		return RLM_MODULE_NOOP;
	}

	/*
	 *	If the server has already decided to reject the request,
	 *	then don't try to proxy it.
	 */
	if (request->reply->code == PW_AUTHENTICATION_REJECT) {
		DEBUG2("Cancelling proxy as request was already rejected");
		return RLM_MODULE_REJECT;
	}
	if (((vp = pairfind(request->config_items, PW_AUTH_TYPE)) != NULL) &&
	    (vp->lvalue == PW_AUTHTYPE_REJECT)) {
		DEBUG2("Cancelling proxy as request was already rejected");
		return RLM_MODULE_REJECT;
	}
	/*
	 *	Length == 0 means it exists, but there's no realm.
	 *	Don't proxy it.
	 */
	if (realmpair->length == 0) {
		return RLM_MODULE_NOOP;
	}

	realmname = (char *)realmpair->strvalue;

	/*
	 *	Look for the realm, using the load balancing
	 *	version of realm find.
	 */
	realm = proxy_realm_ldb(request, realmname,
				(request->packet->code == PW_ACCOUNTING_REQUEST));
	if (realm == NULL) {
		DEBUG2("  ERROR: Failed to find live home server for realm %s",
		       realmname);
		return RLM_MODULE_FAIL;
	}

	/*
	 *	Remember that we sent the request to a Realm.
	 */
	pairadd(&request->packet->vps,
		pairmake("Realm", realm->realm, T_OP_EQ));

	/*
	 *	Access-Request: look for LOCAL realm.
	 *	Accounting-Request: look for LOCAL realm.
	 */
	if (((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
	     (realm->ipaddr == htonl(INADDR_NONE))) ||
	    ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
	     (realm->acct_ipaddr == htonl(INADDR_NONE)))) {
		DEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
		       realm->realm);
		return RLM_MODULE_NOOP;
	}

	/*
	 *	Allocate the proxy packet, only if it wasn't already
	 *	allocated by a module.  This check is mainly to support
	 *	the proxying of EAP-TTLS and EAP-PEAP tunneled requests.
	 *
	 *	In those cases, the EAP module creates a "fake"
	 *	request, and recursively passes it through the
	 *	authentication stage of the server.  The module then
	 *	checks if the request was supposed to be proxied, and
	 *	if so, creates a proxy packet from the TUNNELED request,
	 *	and not from the EAP request outside of the tunnel.
	 *
	 *	The proxy then works like normal, except that the response
	 *	packet is "eaten" by the EAP module, and encapsulated into
	 *	an EAP packet.
	 */
	if (!request->proxy) {
		/*
		 *	Now build a new RADIUS_PACKET.
		 *
		 *	FIXME: it could be that the id wraps around
		 *	too fast if we have a lot of requests, it
		 *	might be better to keep a seperate ID value
		 *	per remote server.
		 *
		 *	OTOH the remote radius server should be smart
		 *	enough to compare _both_ ID and vector.
		 *	Right?
		 */
		if ((request->proxy = rad_alloc(TRUE)) == NULL) {
			radlog(L_ERR|L_CONS, "no memory");
			exit(1);
		}

		/*
		 *	We now massage the attributes to be proxied...
		 */

		/*
		 *	Copy the request, then look up name and
		 *	plain-text password in the copy.
		 *
		 *	Note that the User-Name attribute is the
		 *	*original* as sent over by the client.  The
		 *	Stripped-User-Name attribute is the one hacked
		 *	through the 'hints' file.
		 */
		request->proxy->vps =  paircopy(request->packet->vps);
	}

	/*
	 *	Strip the name, if told to.
	 *
	 *	Doing it here catches the case of proxied tunneled
	 *	requests.
	 */
	if (realm->striprealm == TRUE &&
	   (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) {
		/*
		 *	If there's a Stripped-User-Name attribute in
		 *	the request, then use THAT as the User-Name
		 *	for the proxied request, instead of the
		 *	original name.
		 *
		 *	This is done by making a copy of the
		 *	Stripped-User-Name attribute, turning it into
		 *	a User-Name attribute, deleting the
		 *	Stripped-User-Name and User-Name attributes
		 *	from the vps list, and making the new
		 *	User-Name the head of the vps list.
		 */
		vp = pairfind(request->proxy->vps, PW_USER_NAME);
		if (!vp) {
			vp = paircreate(PW_USER_NAME, PW_TYPE_STRING);
			if (!vp) {
				radlog(L_ERR|L_CONS, "no memory");
				exit(1);
			}
			vp->next = request->proxy->vps;
			request->proxy->vps = vp;
		}
		memcpy(vp->strvalue, strippedname->strvalue,
		       sizeof(vp->strvalue));
		vp->length = strippedname->length;

		/*
		 *	Do NOT delete Stripped-User-Name.
		 */
	}
	
	/*
	 *	If there is no PW_CHAP_CHALLENGE attribute but
	 *	there is a PW_CHAP_PASSWORD we need to add it
	 *	since we can't use the request authenticator
	 *	anymore - we changed it.
	 */
	if (pairfind(request->proxy->vps, PW_CHAP_PASSWORD) &&
	    pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) {
		vp = paircreate(PW_CHAP_CHALLENGE, PW_TYPE_STRING);
		if (!vp) {
			radlog(L_ERR|L_CONS, "no memory");
			exit(1);
		}
		vp->length = AUTH_VECTOR_LEN;
		memcpy(vp->strvalue, request->packet->vector, AUTH_VECTOR_LEN);
		pairadd(&(request->proxy->vps), vp);
	}

	request->proxy->code = request->packet->code;
	if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
		request->proxy->dst_port = realm->auth_port;
		request->proxy->dst_ipaddr = realm->ipaddr;
	} else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
		request->proxy->dst_port = realm->acct_port;
		request->proxy->dst_ipaddr = realm->acct_ipaddr;
	}

	/*
	 *	Add PROXY_STATE attribute, before pre-proxy stage,
	 *	so the pre-proxy modules have access to it.
	 *
	 *	Note that, at this point, the proxied request HAS NOT
	 *	been assigned a RADIUS Id.
	 */
	proxy_addinfo(request);

	/*
	 *	Set up for sending the request.
	 */
	memcpy(request->proxysecret, realm->secret, sizeof(request->proxysecret));
	request->proxy_try_count = mainconfig.proxy_retry_count - 1;
	request->proxy_next_try = request->timestamp + mainconfig.proxy_retry_delay;
	delaypair = pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME);
	request->proxy->timestamp = request->timestamp - (delaypair ? delaypair->lvalue : 0);

	/*
	 *  Do pre-proxying
	 */
	vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
	if (vp) {
		DEBUG2("  Found Pre-Proxy-Type %s", vp->strvalue);
		pre_proxy_type = vp->lvalue;
	}
	rcode = module_pre_proxy(pre_proxy_type, request);

	/*
	 *	Do NOT free request->proxy->vps, the pairs are needed
	 *	for the retries! --Pac.
	 */

	/*
	 *	Delay sending the proxy packet until after we've
	 *	done the work above, playing with the request.
	 *
	 *	After this point, it becomes dangerous to play
	 *	with the request data structure, as the reply MAY
	 *	come in and get processed before we're done with it here.
	 *
	 *	Only proxy the packet if the pre-proxy code succeeded.
	 */
	if ((rcode == RLM_MODULE_OK) ||
	    (rcode == RLM_MODULE_NOOP) ||
	    (rcode == RLM_MODULE_UPDATED)) {
		request->options |= RAD_REQUEST_OPTION_PROXIED;

		/*
		 *	IF it's a fake request, don't send the proxy
		 *	packet.  The outer tunnel session will take
		 *	care of doing that.
		 */
		if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) == 0) {
			/*
			 *	Add the proxied request to the
			 *	list of outstanding proxied
			 *	requests, BEFORE we send it, so
			 *	we have fewer problems with race
			 *	conditions when the responses come
			 *	back very quickly.
			 */
			if (!rl_add_proxy(request)) {
				DEBUG("ERROR: Failed to proxy request %d",
				      request->number);
				return RLM_MODULE_FAIL; /* caller doesn't reply */
			}

			rad_send(request->proxy, NULL,
				 (char *)request->proxysecret);
		}
		rcode = RLM_MODULE_HANDLED; /* caller doesn't reply */
	} else {
		rcode = RLM_MODULE_FAIL; /* caller doesn't reply */
	}

	return rcode;
}
Esempio n. 26
0
/*
 *	Allocate the thread pool, and seed it with an initial number
 *	of threads.
 *
 *	FIXME: What to do on a SIGHUP???
 */
int thread_pool_init(CONF_SECTION *cs, int *spawn_flag)
{
#ifndef WITH_GCD
	int		i, rcode;
	CONF_SECTION	*pool_cf;
#endif
	time_t		now;

	cs = cs;		/* -Wunused */

	now = time(NULL);

	rad_assert(spawn_flag != NULL);
	rad_assert(*spawn_flag == TRUE);
	rad_assert(pool_initialized == FALSE); /* not called on HUP */

#ifndef WITH_GCD
	pool_cf = cf_subsection_find_next(cs, NULL, "thread");
	if (!pool_cf) *spawn_flag = FALSE;
#endif

	/*
	 *	Initialize the thread pool to some reasonable values.
	 */
	memset(&thread_pool, 0, sizeof(THREAD_POOL));
#ifndef WITH_GCD
	thread_pool.head = NULL;
	thread_pool.tail = NULL;
	thread_pool.total_threads = 0;
	thread_pool.max_thread_num = 1;
	thread_pool.cleanup_delay = 5;
	thread_pool.stop_flag = 0;
#endif
	thread_pool.spawn_flag = *spawn_flag;
	
	/*
	 *	Don't bother initializing the mutexes or
	 *	creating the hash tables.  They won't be used.
	 */
	if (!*spawn_flag) return 0;
	
#ifdef WNOHANG
	if ((pthread_mutex_init(&thread_pool.wait_mutex,NULL) != 0)) {
		radlog(L_ERR, "FATAL: Failed to initialize wait mutex: %s",
		       strerror(errno));
		return -1;
	}

	/*
	 *	Create the hash table of child PID's
	 */
	thread_pool.waiters = fr_hash_table_create(pid_hash,
						   pid_cmp,
						   free);
	if (!thread_pool.waiters) {
		radlog(L_ERR, "FATAL: Failed to set up wait hash");
		return -1;
	}
#endif

#ifndef WITH_GCD
	if (cf_section_parse(pool_cf, NULL, thread_config) < 0) {
		return -1;
	}

	/*
	 *	Catch corner cases.
	 */
	if (thread_pool.min_spare_threads < 1)
		thread_pool.min_spare_threads = 1;
	if (thread_pool.max_spare_threads < 1)
		thread_pool.max_spare_threads = 1;
	if (thread_pool.max_spare_threads < thread_pool.min_spare_threads)
		thread_pool.max_spare_threads = thread_pool.min_spare_threads;
	if (thread_pool.max_threads == 0)
		thread_pool.max_threads = 256;
	if ((thread_pool.max_queue_size < 2) || (thread_pool.max_queue_size > 1048576)) {
		radlog(L_ERR, "FATAL: max_queue_size value must be in range 2-1048576");
		return -1;
	}
#endif	/* WITH_GCD */

	/*
	 *	The pool has already been initialized.  Don't spawn
	 *	new threads, and don't forget about forked children,
	 */
	if (pool_initialized) {
		return 0;
	}

#ifndef WITH_GCD
	/*
	 *	Initialize the queue of requests.
	 */
	memset(&thread_pool.semaphore, 0, sizeof(thread_pool.semaphore));
	rcode = sem_init(&thread_pool.semaphore, 0, SEMAPHORE_LOCKED);
	if (rcode != 0) {
		radlog(L_ERR, "FATAL: Failed to initialize semaphore: %s",
		       strerror(errno));
		return -1;
	}

	rcode = pthread_mutex_init(&thread_pool.queue_mutex,NULL);
	if (rcode != 0) {
		radlog(L_ERR, "FATAL: Failed to initialize queue mutex: %s",
		       strerror(errno));
		return -1;
	}

	/*
	 *	Allocate multiple fifos.
	 */
	for (i = 0; i < RAD_LISTEN_MAX; i++) {
		thread_pool.fifo[i] = fr_fifo_create(thread_pool.max_queue_size, NULL);
		if (!thread_pool.fifo[i]) {
			radlog(L_ERR, "FATAL: Failed to set up request fifo");
			return -1;
		}
	}
#endif

#ifdef HAVE_OPENSSL_CRYPTO_H
	/*
	 *	If we're linking with OpenSSL too, then we need
	 *	to set up the mutexes and enable the thread callbacks.
	 */
	if (!setup_ssl_mutexes()) {
		radlog(L_ERR, "FATAL: Failed to set up SSL mutexes");
		return -1;
	}
#endif


#ifndef WITH_GCD
	/*
	 *	Create a number of waiting threads.
	 *
	 *	If we fail while creating them, do something intelligent.
	 */
	for (i = 0; i < thread_pool.start_threads; i++) {
		if (spawn_thread(now, 0) == NULL) {
			return -1;
		}
	}
#else
	thread_pool.queue = dispatch_queue_create("org.freeradius.threads", NULL);
	if (!thread_pool.queue) {
		radlog(L_ERR, "Failed creating dispatch queue: %s\n",
		       strerror(errno));
		exit(1);
	}
#endif

	DEBUG2("Thread pool initialized");
	pool_initialized = TRUE;
	return 0;
}
Esempio n. 27
0
File: transmit.c Progetto: xalt/xalt
void transmit(const char* transmission, const char* jsonStr, const char* kind, const char* key,
              const char* syshost, char* resultFn)
{
  char * cmdline;
  char * p_dbg        = getenv("XALT_TRACING");
  int    xalt_tracing = (p_dbg && (strcmp(p_dbg,"yes")  == 0 ||
				   strcmp(p_dbg,"run")  == 0 ));

  if ((strcasecmp(transmission,"file")      != 0 ) &&
      (strcasecmp(transmission,"syslog")    != 0 ) && 
      (strcasecmp(transmission,"none")      != 0 ) && 
      (strcasecmp(transmission,"syslogv1")  != 0 ))
    transmission = "file";

  if (strcasecmp(transmission, "file") == 0 || strcasecmp(transmission, "file_separate_dirs") == 0 )
    {
      if (resultFn == NULL)
	{
	  DEBUG0(stderr,"  resultFn is NULL, $HOME might be undefined -> No XALT output\n");
	  return;
	}

      int err = mkpath(resultFn, 0700);
      if (err)
	{
	  if (xalt_tracing)
	    {
	      perror("Error: ");
	      fprintf(stderr,"  unable to mkpath(%s) -> No XALT output\n", resultFn);
	    }
	  return;
	}

      FILE* fp = fopen(resultFn,"w");
      if (fp == NULL && xalt_tracing)
	fprintf(stderr,"  Unable to open: %s -> No XALT output\n", resultFn);
      else
        {
          fprintf(fp, "%s\n", jsonStr);
          fclose(fp);
          DEBUG2(stderr,"  Wrote json %s file : %s\n",kind, resultFn);
        }
    }
  else if (strcasecmp(transmission, "syslogv1") == 0)
    {
      int   zslen;
      int   b64len;
      char* zs      = compress_string(jsonStr,&zslen);
      char* b64     = base64_encode(zs, zslen, &b64len);
      
      asprintf(&cmdline, "PATH=%s logger -t XALT_LOGGING_%s \"%s:%s\"\n",XALT_SYSTEM_PATH, syshost, kind, b64);
      system(cmdline);
      free(zs);
      free(b64);
      free(cmdline);
      
    }
  else if (strcasecmp(transmission, "syslog") == 0)
    {
      int   sz;
      int   zslen;
      char* zs      = compress_string(jsonStr, &zslen);
      char* b64     = base64_encode(zs, zslen, &sz);
      
      int   blkSz   = (sz < syslog_msg_sz) ? sz : syslog_msg_sz;
      int   nBlks   = (sz -  1)/blkSz + 1;
      int   istrt   = 0;
      int   iend    = blkSz;
      int   i;

      for (i = 0; i < nBlks; i++)
        {
          asprintf(&cmdline, "PATH=%s logger -t XALT_LOGGING_%s V:2 kind:%s idx:%d nb:%d syshost:%s key:%s value:%.*s\n",
                   XALT_SYSTEM_PATH, syshost, kind, i, nBlks, syshost, key, iend-istrt, &b64[istrt]);
          system(cmdline);
          free(cmdline);
          istrt = iend;
          iend  = istrt + blkSz;
          if (iend > sz)
            iend = sz;
        }
      free(b64);
    }
}
Esempio n. 28
0
/*
 *	Authenticate a previously sent challenge.
 */
static int eap_sim_authenticate(void *arg, EAP_HANDLER *handler)
{
	struct eap_sim_server_state *ess;
	VALUE_PAIR *vp, *vps;
	enum eapsim_subtype subtype;
	int success;

	arg = arg; /* shut up compiler */

	ess = (struct eap_sim_server_state *)handler->opaque;

	/* vps is the data from the client */
	vps = handler->request->packet->vps;

	success= unmap_eapsim_basictypes(handler->request->packet,
					 handler->eap_ds->response->type.data,
					 handler->eap_ds->response->type.length);

	if(!success) {
	  return 0;
	}

	/* see what kind of message we have gotten */
	if((vp = pairfind(vps, ATTRIBUTE_EAP_SIM_SUBTYPE, 0)) == NULL)
	{
		DEBUG2("   no subtype attribute was created, message dropped");
		return 0;
	}
	subtype = vp->vp_integer;

	/*
	 *	Client error supersedes anything else.
	 */
	if (subtype == eapsim_client_error) {
		return 0;
	}

	switch(ess->state) {
	case eapsim_server_start:
		switch(subtype) {
		default:
			/*
			 * pretty much anything else here is illegal,
			 * so we will retransmit the request.
			 */
			eap_sim_stateenter(handler, ess, eapsim_server_start);
			return 1;

		case eapsim_start:
			/*
			 * a response to our EAP-Sim/Request/Start!
			 *
			 */
			return process_eap_sim_start(handler, vps);
		}
		break;
	case eapsim_server_challenge:
		switch(subtype) {
		default:
			/*
			 * pretty much anything else here is illegal,
			 * so we will retransmit the request.
			 */
			eap_sim_stateenter(handler, ess, eapsim_server_challenge);
			return 1;

		case eapsim_challenge:
			/*
			 * a response to our EAP-Sim/Request/Challenge!
			 *
			 */
			return process_eap_sim_challenge(handler, vps);
		}
		break;

	default:
		/* if we get into some other state, die, as this
		 * is a coding error!
		 */
		DEBUG2("  illegal-unknown state reached in eap_sim_authenticate\n");
		rad_assert(0 == 1);
 	}

	return 0;
}
Esempio n. 29
0
/**
 * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
 * @irq:
 * @dev_id: SCSI driver HA context
 * @regs:
 *
 * Called by system whenever the host adapter generates an interrupt.
 *
 * Returns handled flag.
 */
irqreturn_t
qla2300_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
	scsi_qla_host_t	*ha;
	struct device_reg_2xxx __iomem *reg;
	int		status;
	unsigned long	flags;
	unsigned long	iter;
	uint32_t	stat;
	uint16_t	hccr;
	uint16_t	mb[4];

	ha = (scsi_qla_host_t *) dev_id;
	if (!ha) {
		printk(KERN_INFO
		    "%s(): NULL host pointer\n", __func__);
		return (IRQ_NONE);
	}

	reg = &ha->iobase->isp;
	status = 0;

	spin_lock_irqsave(&ha->hardware_lock, flags);
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
		if (stat & HSR_RISC_PAUSED) {
			hccr = RD_REG_WORD(&reg->hccr);
			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
				qla_printk(KERN_INFO, ha,
				    "Parity error -- HCCR=%x.\n", hccr);
			else
				qla_printk(KERN_INFO, ha,
				    "RISC paused -- HCCR=%x.\n", hccr);

			/*
			 * Issue a "HARD" reset in order for the RISC
			 * interrupt bit to be cleared.  Schedule a big
			 * hammmer to get out of the RISC PAUSED state.
			 */
			WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
			RD_REG_WORD(&reg->hccr);
			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
			break;
		} else if ((stat & HSR_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
			qla2x00_mbx_completion(ha, MSW(stat));
			status |= MBX_INTERRUPT;

			/* Release mailbox registers. */
			WRT_REG_WORD(&reg->semaphore, 0);
			break;
		case 0x12:
			mb[0] = MSW(stat);
			mb[1] = RD_MAILBOX_REG(ha, reg, 1);
			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
			mb[3] = RD_MAILBOX_REG(ha, reg, 3);
			qla2x00_async_event(ha, mb);
			break;
		case 0x13:
			qla2x00_process_response_queue(ha);
			break;
		case 0x15:
			mb[0] = MBA_CMPLT_1_16BIT;
			mb[1] = MSW(stat);
			qla2x00_async_event(ha, mb);
			break;
		case 0x16:
			mb[0] = MBA_SCSI_COMPLETION;
			mb[1] = MSW(stat);
			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
			qla2x00_async_event(ha, mb);
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
			    "(%d).\n",
			    ha->host_no, stat & 0xff));
			break;
		}
		WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
		RD_REG_WORD_RELAXED(&reg->hccr);
	}
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		spin_lock_irqsave(&ha->mbx_reg_lock, flags);

		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
		up(&ha->mbx_intr_sem);

		spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
	}

	return (IRQ_HANDLED);
}
Esempio n. 30
0
/*
 *	Read config files.
 *
 *	This function can ONLY be called from the main server process.
 */
int read_mainconfig(int reload)
{
    const char *p = NULL;
    CONF_PAIR *cp;
    CONF_SECTION *cs;
    struct stat statbuf;
    cached_config_t *cc;
    char buffer[1024];

    if (reload != 0) {
        radlog(L_ERR, "Reload is not implemented");
        return -1;
    }

    if (stat(radius_dir, &statbuf) < 0) {
        radlog(L_ERR, "Errors reading %s: %s",
               radius_dir, strerror(errno));
        return -1;
    }

#ifdef S_IWOTH
    if ((statbuf.st_mode & S_IWOTH) != 0) {
        radlog(L_ERR, "Configuration directory %s is globally writable.  Refusing to start due to insecure configuration.",
               radius_dir);
        return -1;
    }
#endif

#ifdef S_IROTH
    if (0 && (statbuf.st_mode & S_IROTH) != 0) {
        radlog(L_ERR, "Configuration directory %s is globally readable.  Refusing to start due to insecure configuration.",
               radius_dir);
        return -1;
    }
#endif

    radlog(L_INFO, "Starting - reading configuration files ...");

    /* Read the configuration file */
    snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
             radius_dir, mainconfig.name);
    if ((cs = cf_file_read(buffer)) == NULL) {
        radlog(L_ERR, "Errors reading %s", buffer);
        return -1;
    }

    /*
     *	If there was no log destination set on the command line,
     *	set it now.
     */
    if (mainconfig.radlog_dest == RADLOG_NULL) {
        if (cf_section_parse(cs, NULL, serverdest_config) < 0) {
            fprintf(stderr, "radiusd: Error: Failed to parse log{} section.\n");
            cf_section_free(&cs);
            return -1;
        }

        if (!radlog_dest) {
            fprintf(stderr, "radiusd: Error: No log destination specified.\n");
            cf_section_free(&cs);
            return -1;
        }

        mainconfig.radlog_dest = fr_str2int(str2dest, radlog_dest,
                                            RADLOG_NUM_DEST);
        if (mainconfig.radlog_dest == RADLOG_NUM_DEST) {
            fprintf(stderr, "radiusd: Error: Unknown log_destination %s\n",
                    radlog_dest);
            cf_section_free(&cs);
            return -1;
        }

        if (mainconfig.radlog_dest == RADLOG_SYSLOG) {
            /*
             *	Make sure syslog_facility isn't NULL
             *	before using it
             */
            if (!syslog_facility) {
                fprintf(stderr, "radiusd: Error: Syslog chosen but no facility was specified\n");
                cf_section_free(&cs);
                return -1;
            }
            mainconfig.syslog_facility = fr_str2int(str2fac, syslog_facility, -1);
            if (mainconfig.syslog_facility < 0) {
                fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n",
                        syslog_facility);
                cf_section_free(&cs);
                return -1;
            }

            /*
             *	Call openlog only once, when the
             *	program starts.
             */
            openlog(progname, LOG_PID, mainconfig.syslog_facility);

        } else if (mainconfig.radlog_dest == RADLOG_FILES) {
            if (!mainconfig.log_file) {
                fprintf(stderr, "radiusd: Error: Specified \"files\" as a log destination, but no log filename was given!\n");
                cf_section_free(&cs);
                return -1;
            }
        }
    }

#ifdef HAVE_SETUID
    /*
     *	Switch users as early as possible.
     */
    if (!switch_users(cs)) exit(1);
#endif

    /*
     *	Open the log file AFTER switching uid / gid.  If we
     *	did switch uid/gid, then the code in switch_users()
     *	took care of setting the file permissions correctly.
     */
    if ((mainconfig.radlog_dest == RADLOG_FILES) &&
            (mainconfig.radlog_fd < 0)) {
        mainconfig.radlog_fd = open(mainconfig.log_file,
                                    O_WRONLY | O_APPEND | O_CREAT, 0640);
        if (mainconfig.radlog_fd < 0) {
            fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno));
            cf_section_free(&cs);
            return -1;
        }
    }

    /* Initialize the dictionary */
    cp = cf_pair_find(cs, "dictionary");
    if (cp) p = cf_pair_value(cp);
    if (!p) p = radius_dir;
    DEBUG2("including dictionary file %s/%s", p, RADIUS_DICTIONARY);
    if (dict_init(p, RADIUS_DICTIONARY) != 0) {
        radlog(L_ERR, "Errors reading dictionary: %s",
               fr_strerror());
        return -1;
    }

    /*
     *	This allows us to figure out where, relative to
     *	radiusd.conf, the other configuration files exist.
     */
    cf_section_parse(cs, NULL, server_config);

    /*
     *	Free the old configuration items, and replace them
     *	with the new ones.
     *
     *	Note that where possible, we do atomic switch-overs,
     *	to ensure that the pointers are always valid.
     */
    cf_section_free(&mainconfig.config);
    mainconfig.config = cs;

    DEBUG2("%s: #### Loading Realms and Home Servers ####", mainconfig.name);
    if (!realms_init(cs)) {
        return -1;
    }

    DEBUG2("%s: #### Loading Clients ####", mainconfig.name);
    if (!clients_parse_section(cs)) {
        return -1;
    }

    /*
     *  Register the %{config:section.subsection} xlat function.
     */
    xlat_register("config", xlat_config, NULL);
    xlat_register("client", xlat_client, NULL);

    /*
     *	Starting the server, WITHOUT "-x" on the
     *	command-line: use whatever is in the config
     *	file.
     */
    if (debug_flag == 0) {
        debug_flag = mainconfig.debug_level;
    }
    fr_debug_flag = debug_flag;

    /*
     *  Go update our behaviour, based on the configuration
     *  changes.
     */

    /*
     *	Sanity check the configuration for internal
     *	consistency.
     */
    if (mainconfig.reject_delay > mainconfig.cleanup_delay) {
        mainconfig.reject_delay = mainconfig.cleanup_delay;
    }
    if (mainconfig.reject_delay < 0) mainconfig.reject_delay = 0;

    /*  Reload the modules.  */
    if (setup_modules(reload, mainconfig.config) < 0) {
        return -1;
    }

    if (chroot_dir) {
        if (chdir(radlog_dir) < 0) {
            radlog(L_ERR, "Failed to 'chdir %s' after chroot: %s",
                   radlog_dir, strerror(errno));
            return -1;
        }
    }

    cc = rad_malloc(sizeof(*cc));
    memset(cc, 0, sizeof(*cc));

    cc->cs = cs;
    rad_assert(cs_cache == NULL);
    cs_cache = cc;

    return 0;
}