|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 14377 (0x3829)
Types: TextFile
Names: »ds_bind.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z«
└─⟦de7628f85⟧
└─⟦this⟧ »isode-6.0/quipu/ds_bind.c«
/* 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 */
}