DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦c8503755e⟧ TextFile

    Length: 14377 (0x3829)
    Types: TextFile
    Names: »ds_bind.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z« 
        └─⟦de7628f85⟧ 
            └─⟦this⟧ »isode-6.0/quipu/ds_bind.c« 

TextFile

/* ds_bind.c - BindArgument Checking and Authentication */

#ifndef lint
static char *rcsid = "$Header: /f/osi/quipu/RCS/ds_bind.c,v 7.1 89/12/19 16:20:13 mrose Exp $";
#endif

/*
 * $Header: /f/osi/quipu/RCS/ds_bind.c,v 7.1 89/12/19 16:20:13 mrose Exp $
 *
 *
 * $Log:	ds_bind.c,v $
 * Revision 7.1  89/12/19  16:20:13  mrose
 * sync
 * 
 * Revision 7.0  89/11/23  22:17:05  mrose
 * Release 6.0
 * 
 */

/*
 *                                NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include "quipu/util.h"
#include "quipu/entry.h"
#include "quipu/commonarg.h"
#include "quipu/bind.h"
#include "quipu/compare.h"
#include "quipu/dua.h"
#include "quipu/connection.h"

extern LLog * log_dsap;
extern DN	mydsadn;
struct oper_act	* oper_alloc();

#ifndef NO_STATS
extern LLog * log_stat;
extern int dn_print ();
#endif

int bind_window = 300; /* Tailorable timeout for credentials */

int	  ds_bind_init (cn)
struct connection	* cn;
{
    struct ds_bind_arg	* arg = &(cn->cn_init_act.ia_req);
    struct ds_bind_arg	* result = &(cn->cn_init_act.ia_res);
    struct ds_bind_error * error = &(cn->cn_init_act.ia_err);
    Attr_Sequence		  as;
    Entry			  entryptr;
    extern AttributeType	  at_password;
    extern AttributeType	  at_p_password;
    struct di_block		* dsas;
    struct di_block		* di_tmp;
    struct oper_act		* on;
    struct ds_compare_arg	* cma;
    struct DSError		  err;
    static struct common_args	  ca_def = default_common_args;
    int 			  res;
    int				  retval;
    struct protected_password   * pp;
#ifndef NO_STATS
    char buff[LINESIZE];
#endif

    DLOG (log_dsap,LLOG_TRACE,("ds_bind_init"));


    if (arg->dba_version != DBA_VERSION_V1988)
    {
	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = DBE_TYPE_SERVICE;
	error->dbe_value = DSE_SV_UNAVAILABLE;
	return(DS_ERROR_CONNECT);
    }

/* We don't support any bilaterally-defined authentication procedures.
 * Hence, if we get EXTERNAL credentials in the bind, reject them.
 */

    if (arg->dba_auth_type == DBA_AUTH_EXTERNAL)
    {
	DLOG(log_dsap, LLOG_EXCEPTIONS, ("EXTERNAL found in credentials"));
	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = DBE_TYPE_SECURITY;
	error->dbe_value = DSE_SC_AUTHENTICATION;
	return (DS_ERROR_CONNECT);
    }

/* If password is present, but zero length, treat as though absent */
    if ((arg->dba_auth_type == DBA_AUTH_SIMPLE) && (arg->dba_passwd_len == 0))
	arg->dba_auth_type = DBA_AUTH_NONE;


/* If binding as NULLDN (ie. `anonymous') don't need any authentication */
    if (arg->dba_dn == NULLDN)
    {
#ifndef NO_STATS
	LLOG(log_stat, LLOG_NOTICE, ("Bind (%d) (anonymous)", cn->cn_ad));
#endif
	cn->cn_authen = DBA_AUTH_NONE;
	make_dsa_bind_arg(result);
	return(DS_OK);
    }

/* Now we're sure dba_dn contains a valid pointer, can decode it */
    (void) dn_decode (arg->dba_dn);

    switch (arg->dba_auth_type)
    {
    case DBA_AUTH_NONE:
#ifndef NO_STATS
	(void) sprintf (buff,"Bind (%d) (no auth)",cn->cn_ad);
	pslog (log_stat,LLOG_NOTICE,buff,dn_print,(caddr_t)arg->dba_dn);
#endif
	cn->cn_authen = DBA_AUTH_NONE;
	make_dsa_bind_arg(result);
	return (DS_OK);
    case DBA_AUTH_SIMPLE:
#ifndef NO_STATS
	(void) sprintf (buff,"Bind (%d) (simple)",cn->cn_ad);
	pslog (log_stat,LLOG_NOTICE,buff,dn_print,(caddr_t)arg->dba_dn);
#endif
	/* Can't check simple credentials from DSP (livelock risk).
	 * Hence treat DSP accesses as unauthenticated.
	 */
	if (cn->cn_ctx != CN_CTX_X500_DAP)
	{
	cn->cn_authen = DBA_AUTH_NONE;
	make_dsa_bind_arg(result);
	return(DS_OK);
	}
	break;
    case DBA_AUTH_PROTECTED:
#ifndef NO_STATS
	(void) sprintf (buff,"Bind (%d) (protected)",cn->cn_ad);
	pslog (log_stat,LLOG_NOTICE,buff,dn_print,(caddr_t)arg->dba_dn);
#endif
	if (cn->cn_ctx != CN_CTX_X500_DAP)
	{
	cn->cn_authen = DBA_AUTH_NONE;
	make_dsa_bind_arg(result);
	return(DS_OK);
	}
	else
	{
	UTC ut;
	long c_time, s_time, delta;
	time_t time();

	(void) time(&s_time);
	ut = str2utct(arg->dba_time1, strlen(arg->dba_time1));
	if (ut == NULLUTC)
		c_time = 0L; /* 1970 is a convenient out-of-date timestamp */
	else
		c_time = gtime(ut2tm(ut));
	delta = s_time - c_time;
	if ((delta < 0) || (delta > bind_window))
		{
		DLOG(log_dsap, LLOG_EXCEPTIONS, 
			("Time = %s, Delay = %D s : Association rejected", 
			arg->dba_time1, delta));
		error->dbe_version = DBA_VERSION_V1988;
		error->dbe_type = DBE_TYPE_SECURITY;
		error->dbe_value = DSE_SC_INVALIDCREDENTIALS;
		return (DS_ERROR_CONNECT);
		}
	pp = (struct protected_password *) calloc(1, sizeof(*pp));
	/* Ought to check for null pointer ... */
	pp->passwd = malloc((unsigned)arg->dba_passwd_len);
	bcopy(arg->dba_passwd, pp->passwd, arg->dba_passwd_len);
	pp->n_octets = arg->dba_passwd_len;
	pp->time1 = strdup(arg->dba_time1);
	pp->protected = (char) 1;
	}
	break;
    case DBA_AUTH_STRONG:
#ifndef NO_STATS
	(void) sprintf (buff,"Bind (%d) (strong)",cn->cn_ad);
	pslog (log_stat,LLOG_NOTICE,buff,dn_print,(caddr_t)arg->dba_dn);
#endif
	/* Strong authentication is not yet supported.
	 * It will eventually be possible to check strong credentials over DSP.
	 * For the moment, accept them and treat as NONE over DSP, but reject
	 * over DAP.
	 */
	if (cn->cn_ctx != CN_CTX_X500_DAP)
	{
	cn->cn_authen = DBA_AUTH_NONE;
	make_dsa_bind_arg(result);
	return (DS_OK);
	}
	else
	{
	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = DBE_TYPE_SECURITY;
	error->dbe_value = DSE_SC_AUTHENTICATION;
	return (DS_ERROR_CONNECT);
	}
    }

/* If we fall through to here, credentials are simple or protected simple */

    if ((res = really_find_entry(arg->dba_dn, TRUE, NULLDNSEQ, FALSE, &(entryptr), &(err), &(dsas))) == DS_OK) {
	/* is it really OK ??? */
	if ((entryptr->e_data == E_TYPE_CONSTRUCTOR) 
		|| (entryptr->e_data == E_TYPE_CACHE_FROM_MASTER)) {
		DN dn_found;
		DLOG(log_dsap, LLOG_NOTICE, ("rfe (bind) returned a constructor"));
		dn_found = get_copy_dn(entryptr);
		res = constructor_dsa_info(dn_found,NULLDNSEQ,FALSE,entryptr,&err,&dsas);
		dn_free (dn_found);
	}
    }
    switch(res)
    {
    case DS_OK:
	/* entryptr filled out - break through to deal with it */
	break;

    case DS_CONTINUE:
	/*
	*  At this point a remote operation is required to compare
	*  the password given with the password of the entry, so
	*  fire up the remote operation and return without completing.
	*  Mark the operation as a BIND_COMPARE_OP and set the connection
	*  which will need to be restarted.
	*  Generate a compare argument.
	*  Chain the compare operation using the di_blocks.
	*/
	cn->cn_bind_compare = on = oper_alloc();	/* cn knows about on */
	on->on_type = ON_TYPE_BIND_COMPARE;
	on->on_bind_compare = cn;			/* on knows about cn */

	on->on_arg = &(on->on_req);
	set_my_chain_args(&(on->on_req.dca_charg), arg->dba_dn);
	on->on_req.dca_dsarg.arg_type = OP_COMPARE;
	cma = &(on->on_req.dca_dsarg.arg_cm);

	cma->cma_common = ca_def;	/* struct copy */

					/* Set originator/requestor */
	on->on_req.dca_charg.cha_originator = dn_cpy(arg->dba_dn);
	cma->cma_common.ca_requestor = dn_cpy(arg->dba_dn);
 	cma->cma_common.ca_servicecontrol.svc_prio = SVC_PRIO_HIGH;

	cma->cma_object = dn_cpy(arg->dba_dn);

	if (arg->dba_auth_type == DBA_AUTH_SIMPLE)
	{	
		cma->cma_purported.ava_type = AttrT_cpy (at_password);
		cma->cma_purported.ava_value = 
			str2AttrV (arg->dba_passwd,str2syntax("octetstring"));
	}
	else
	{
		cma->cma_purported.ava_type = AttrT_cpy (at_p_password);
		cma->cma_purported.ava_value = 
			(AttributeValue) calloc(1, sizeof(attrVal));
		cma->cma_purported.ava_value->av_syntax = 
				str2syntax("protectedPassword");
		cma->cma_purported.ava_value->av_struct = (caddr_t) pp;
	}


	on->on_dsas = dsas;
	for(di_tmp=on->on_dsas; di_tmp!=NULL_DI_BLOCK; di_tmp=di_tmp->di_next)
	{
	    di_tmp->di_type = DI_OPERATION;
	    di_tmp->di_oper = on;
	}

	if(oper_chain(on) == OK)
	    return(DS_CONTINUE);

	oper_extract(on);
	cn->cn_bind_compare = NULLOPER;

	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = DBE_TYPE_SERVICE;
	error->dbe_value = DSE_SV_UNAVAILABLE;

	return(DS_ERROR_CONNECT);

    case DS_X500_ERROR:
	/* User's entry doesn't exist, for example */
	LLOG(log_dsap, LLOG_NOTICE, ("ds_bind - really_find_entry erred:"));
	log_ds_error(&(err));
	ds_error_free(&(err));
	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = DBE_TYPE_SECURITY;
	error->dbe_value = DSE_SC_INVALIDCREDENTIALS;
	return(DS_ERROR_CONNECT);

    default:
	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = DBE_TYPE_SERVICE;
	error->dbe_value = DSE_SV_DITERROR;
	return(DS_ERROR_CONNECT);
    }

    if ((as = as_find_type (entryptr->e_attributes,
		(arg->dba_auth_type == DBA_AUTH_SIMPLE) ? 
			at_password : at_p_password)) == NULLATTR)
    {
	/* No password in entry.
	 * Simple authentication is not possible for entities without passwords.
	 * Hence, give the `inappropriate authentication' message.
	 */
	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = DBE_TYPE_SECURITY;
	error->dbe_value = DSE_SC_AUTHENTICATION;
	return (DS_ERROR_CONNECT);
    }


    /* Null terminate the password. Probably don't need this anymore,
     * but keep it in for safety.
     */
    arg->dba_passwd[arg->dba_passwd_len] = '\0';

    if (arg->dba_auth_type == DBA_AUTH_SIMPLE)
	retval = strncmp ((char *)as->attr_value->avseq_av.av_struct, 
	arg->dba_passwd, arg->dba_passwd_len);
    else
	retval = check_guard(
		((struct protected_password *)
			as->attr_value->avseq_av.av_struct)->passwd, 
		((struct protected_password *)
			as->attr_value->avseq_av.av_struct)->n_octets, 
		arg->dba_time1, 
		arg->dba_passwd,
		arg->dba_passwd_len);

    if (retval == 0)
	{
	    /* Password OK! */
	    cn->cn_authen = arg->dba_auth_type;
	    make_dsa_bind_arg(result);
	    return (DS_OK);
	}
     else
	{
	/* password wrong ! */
	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type  = DBE_TYPE_SECURITY;
	error->dbe_value = DSE_SC_INVALIDCREDENTIALS;
	return (DS_ERROR_CONNECT);
	}
}

bind_compare_result_wakeup(on)
struct oper_act	* on;
{

    DLOG(log_dsap, LLOG_TRACE, ("bind_compare_result_wakeup()"));
    if(on->on_bind_compare == NULLCONN)
    {
	LLOG(log_dsap, LLOG_EXCEPTIONS, ("bind_compare_result_wakeup - connection initiating compare already failed"));
    }
    else
    {
	if(on->on_resp.resp_res.dcr_dsres.res_cm.cmr_matched)
	{
	    DLOG(log_dsap, LLOG_DEBUG, ("bind_compare - user authenticated"));
	    on->on_bind_compare->cn_authen = on->on_bind_compare->cn_init_act.ia_req.dba_auth_type;
	    conn_init_res(on->on_bind_compare);
	}
	else
	{
	    struct ds_bind_error * error = &(on->on_bind_compare->cn_init_act.ia_err);
	    DLOG(log_dsap, LLOG_DEBUG, ("bind_compare - user NOT authenticated"));
	    error->dbe_version = DBA_VERSION_V1988;
	    error->dbe_type = DBE_TYPE_SECURITY;
	    /* Password match failed, therefore credentials are wrong */
	    error->dbe_value = DSE_SC_INVALIDCREDENTIALS;
	    conn_init_err(on->on_bind_compare);
	}
    }
    oper_conn_extract(on);
    oper_free(on);
}

bind_compare_error_wakeup(on)
struct oper_act	* on;
{
int errmsg = DSE_SV_DITERROR;
int errtype = DBE_TYPE_SERVICE;

    DLOG(log_dsap, LLOG_TRACE, ("bind_compare_error_wakeup()"));

    /*
    *  Check for referral and rechain if appropriate;
    *  Otherwise check if error requires propagation
    *  or another of the original di_blocks to be chained to.
    */

    if(on->on_bind_compare == NULLCONN)
    {
	LLOG(log_dsap, LLOG_EXCEPTIONS, ("bind_compare_error_wakeup - connection initiating compare already failed"));
    }
    else
    {
	struct ds_bind_error * error = &(on->on_bind_compare->cn_init_act.ia_err);
	switch(on->on_resp.resp_err.dse_type)
	{
	case DSE_NOERROR:
	    LLOG(log_dsap, LLOG_EXCEPTIONS, ("bind_compare_error_wakeup() - no error!"));
	break;
	case DSE_REFERRAL:
	    LLOG(log_dsap, LLOG_EXCEPTIONS, ("bind_compare_error_wakeup() - DAP referral received!"));
	case DSE_DSAREFERRAL:
	    /* Follow referral */
	    if(oper_rechain(on) == OK)
		return;
	break;
	case DSE_NAMEERROR:
	case DSE_SECURITYERROR:
	case DSE_ATTRIBUTEERROR:
	    errtype = DBE_TYPE_SECURITY;
	    errmsg = DSE_SC_AUTHENTICATION;
	    break;
	case DSE_SERVICEERROR:
	    errmsg = on->on_resp.resp_err.ERR_SERVICE.DSE_sv_problem;
	    break;
 	default:
	    log_ds_error(&on->on_resp.resp_err);
	    DLOG(log_dsap, LLOG_DEBUG, ("bind_compare_error_wakeup() - assuming all errors finish operation!"));
	break;
	}

	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = errtype;
	error->dbe_value = errmsg;
	conn_init_err(on->on_bind_compare);
    }
    oper_conn_extract(on);
    oper_free(on);
}

bind_compare_fail_wakeup(on)
struct oper_act	* on;
{
    DLOG(log_dsap, LLOG_TRACE, ("bind_compare_fail_wakeup()"));

    /*
    *  If there are any more "di_block"s to attempt it must be
    *  worth a go (perhaps this depends on the failure which
    *  has occurrred).
    */
    if(on->on_bind_compare == NULLCONN)
    {
	LLOG(log_dsap, LLOG_EXCEPTIONS, ("bind_compare_fail_wakeup - connection initiating compare already failed"));
    }
    else
    {
	struct ds_bind_error * error = &(on->on_bind_compare->cn_init_act.ia_err);

	if(on->on_dsas)
	{
	    if(oper_chain(on) == OK)
		return;
	}

	if(on->on_dsas)
	{
	    /* oper_chain must be awaiting deferred di_blocks */
	    return;
	}

	error->dbe_version = DBA_VERSION_V1988;
	error->dbe_type = DBE_TYPE_SERVICE;
	error->dbe_value = DSE_SV_UNAVAILABLE;
	conn_init_err(on->on_bind_compare);
    }
    oper_conn_extract(on);
    oper_free(on);
}

do_ds_unbind (conn)
register        struct connection       * conn;
{
#ifndef NO_STATS
char buff[LINESIZE];

	if(conn->cn_initiator == INITIATED_BY_THIS)
	{
	    (void) dn_decode (conn->cn_what);
	    (void) sprintf (buff,"Unbind (%d) (by this)",conn->cn_ad);
	    pslog (log_stat,LLOG_NOTICE,buff,dn_print,(caddr_t)conn->cn_what);
	}
	else
	{
	    (void) dn_decode (conn->cn_who);
	    (void) sprintf (buff,"Unbind (%d) (by that)",conn->cn_ad);
	    pslog (log_stat,LLOG_NOTICE,buff,dn_print,(caddr_t)conn->cn_who);
	}
#endif
	DLOG (log_dsap,LLOG_TRACE,("ds_un_bind"));
}

bind_arg_free (arg)
struct ds_bind_arg          *arg;
{
	dn_free (arg->dba_dn);
		/* need to free ertificates etc */
}