Beispiel #1
0
static void *
do_onethread( void *arg )
{
	int		i, j, thisconn;
	LDAP		**mlds;
	char		thrstr[BUFSIZ];
	int		rc, refcnt = 0;
	int		idx = (ldap_pvt_thread_t *)arg - rtid;

	mlds = (LDAP **) calloc( sizeof(LDAP *), noconns);
	if (mlds == NULL) {
		thread_error( idx, "Memory error: thread calloc for noconns" );
		exit( EXIT_FAILURE );
	}

	for ( j = 0; j < outerloops; j++ ) {
		for(i = 0; i < noconns; i++) {
			mlds[i] = ldap_dup(lds[i]);
			if (mlds[i] == NULL) {
				thread_error( idx, "ldap_dup error" );
			}
		}
		rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt);
		snprintf(thrstr, BUFSIZ,
			"RO Thread conns: %d refcnt: %d (rc = %d)",
			noconns, refcnt, rc);
		thread_verbose(idx, thrstr);

		thisconn = (idx + j) % noconns;
		if (thisconn < 0 || thisconn >= noconns)
			thisconn = 0;
		if (mlds[thisconn] == NULL) {
			thread_error( idx, "(failed to dup)");
			tester_perror( "ldap_dup", "(failed to dup)" );
			exit( EXIT_FAILURE );
		}
		snprintf(thrstr, BUFSIZ, "Using conn %d", thisconn);
		thread_verbose(idx, thrstr);
		if ( filter != NULL ) {
			if (strchr(filter, '['))
				do_random2( mlds[thisconn], entry, filter, attrs,
					noattrs, nobind, loops, retries, delay, force,
					chaserefs, idx );
			else
				do_random( mlds[thisconn], entry, filter, attrs,
					noattrs, nobind, loops, retries, delay, force,
					chaserefs, idx );

		} else {
			do_read( mlds[thisconn], entry, attrs,
				noattrs, nobind, loops, retries, delay, force,
				chaserefs, idx );
		}
		for(i = 0; i < noconns; i++) {
			(void) ldap_destroy(mlds[i]);
			mlds[i] = NULL;
		}
	}
	free( mlds );
	return( NULL );
}
Beispiel #2
0
/* Convert an LDAP error into an informative python exception */
PyObject*
LDAPerror( LDAP *l, char *msg ) 
{
  if (l == NULL) {
    PyErr_SetFromErrno( LDAPexception_class );
    return NULL;
  }
  else {
    int errnum, opt_errnum;
    PyObject *errobj;
    PyObject *info;
    PyObject *str;

    char *matched, *error;

    opt_errnum = ldap_get_option(l, LDAP_OPT_ERROR_NUMBER, &errnum);
    if (opt_errnum != LDAP_OPT_SUCCESS)
      errnum = opt_errnum;

    if (errnum == LDAP_NO_MEMORY)
      return PyErr_NoMemory();

    if (errnum >= LDAP_ERROR_MIN && errnum <= LDAP_ERROR_MAX)
      errobj = errobjects[errnum+LDAP_ERROR_OFFSET];
    else
      errobj = LDAPexception_class;
    
    info = PyDict_New();
    if (info == NULL)
      return NULL;

    str = PyString_FromString(ldap_err2string(errnum));
    if (str)
      PyDict_SetItemString( info, "desc", str );
    Py_XDECREF(str);

    if (ldap_get_option(l, LDAP_OPT_MATCHED_DN, &matched) >= 0
      && matched != NULL) {
        if (*matched != '\0') {
      str = PyString_FromString(matched);
      if (str)
          PyDict_SetItemString( info, "matched", str );
      Py_XDECREF(str);
        }
        ldap_memfree(matched);
    }
    
    if (errnum == LDAP_REFERRAL) {
        str = PyString_FromString(msg);
        if (str)
      PyDict_SetItemString( info, "info", str );
        Py_XDECREF(str);
    } else if (ldap_get_option(l, LDAP_OPT_ERROR_STRING, &error) >= 0
      && error != NULL) {
        if (error != '\0') {
      str = PyString_FromString(error);
      if (str)
          PyDict_SetItemString( info, "info", str );
      Py_XDECREF(str);
        }
        ldap_memfree(error);
    }
    PyErr_SetObject( errobj, info );
    Py_DECREF(info);
    return NULL;
  }
}
Beispiel #3
0
/** Convert a single group name into a DN
 *
 * Unlike the inverse conversion of a name to a DN, most LDAP directories don't allow filtering by DN,
 * so we need to search for each DN individually.
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[in] request Current request.
 * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
 * @param[in] dn to resolve.
 * @param[out] out Where to write group name (must be freed with talloc_free).
 * @return One of the RLM_MODULE_* values.
 */
static rlm_rcode_t rlm_ldap_group_dn2name(ldap_instance_t const *inst, REQUEST *request,
					  ldap_handle_t **pconn, char const *dn, char **out)
{
	rlm_rcode_t rcode = RLM_MODULE_OK;
	ldap_rcode_t status;
	int ldap_errno;

	struct berval **values = NULL;
	char const *attrs[] = { inst->groupobj_name_attr, NULL };
	LDAPMessage *result = NULL, *entry;

	*out = NULL;

	if (!inst->groupobj_name_attr) {
		REDEBUG("Told to resolve group DN to name but missing 'group.name_attribute' directive");

		return RLM_MODULE_INVALID;
	}

	RDEBUG("Resolving group DN \"%s\" to group name", dn);

	status = rlm_ldap_search(inst, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, &result);
	switch (status) {
	case LDAP_PROC_SUCCESS:
		break;

	case LDAP_PROC_NO_RESULT:
		REDEBUG("Group DN \"%s\" did not resolve to an object", dn);
		return RLM_MODULE_INVALID;

	default:
		return RLM_MODULE_FAIL;
	}

	entry = ldap_first_entry((*pconn)->handle, result);
	if (!entry) {
		ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));

		rcode = RLM_MODULE_INVALID;
		goto finish;
	}

	values = ldap_get_values_len((*pconn)->handle, entry, inst->groupobj_name_attr);
	if (!values) {
		REDEBUG("No %s attributes found in object", inst->groupobj_name_attr);

		rcode = RLM_MODULE_INVALID;

		goto finish;
	}

	*out = rlm_ldap_berval_to_string(request, values[0]);
	RDEBUG("Group DN \"%s\" resolves to name \"%s\"", dn, *out);

finish:
	if (result) ldap_msgfree(result);
	if (values) ldap_value_free_len(values);

	return rcode;
}
Beispiel #4
0
/*
 * call-seq:
 * conn.sasl_bind(dn=nil, mech=nil, cred=nil, sctrls=nil, cctrls=nil, sasl_options=nil)  => self
 * conn.sasl_bind(dn=nil, mech=nil, cred=nil, sctrls=nil, cctrls=nil, sasl_options=nil)
 *   { |conn| }  => nil
 *
 * Bind an LDAP connection, using the DN, +dn+, the mechanism, +mech+, and the
 * credential, +cred+.
 *
 * +sctrls+ is an array of server controls, whilst +cctrls+ is an array of
 * client controls.
 *
 * sasl_options is a hash which should have the following keys:
 *
 * - +:authcid+ and +:authzid+ for alternate SASL authentication
 * - +realm+ to specify the SASL realm
 *
 * If a block is given, +self+ is yielded to the block.
 */
VALUE
rb_ldap_conn_sasl_bind (int argc, VALUE argv[], VALUE self)
{
  RB_LDAP_DATA *ldapdata;

  VALUE arg1, arg2, arg3, arg4, arg5, sasl_options = Qnil;
  int version;
  char *dn = NULL;
  char *mechanism = NULL;
  struct berval *cred = ALLOCA_N (struct berval, 1);
  LDAPControl **serverctrls = NULL;
  LDAPControl **clientctrls = NULL;

  /*
  struct berval *servercred = NULL;
  char *sasl_realm = NULL;
  char *sasl_authc_id = NULL;
  char *sasl_authz_id = NULL;
  char *sasl_secprops = NULL;
  struct berval passwd = { 0, NULL };
  */

  unsigned sasl_flags = LDAP_SASL_AUTOMATIC;

  Data_Get_Struct (self, RB_LDAP_DATA, ldapdata);
  if (!ldapdata->ldap)
    {
      if (rb_iv_get (self, "@args") != Qnil)
	{
	  rb_ldap_conn_rebind (self);
	  GET_LDAP_DATA (self, ldapdata);
	}
      else
	{
	  rb_raise (rb_eLDAP_InvalidDataError,
		    "The LDAP handler has already unbound.");
	}
    }

  if (ldapdata->bind)
    {
      rb_raise (rb_eLDAP_Error, "already bound.");
    };

  switch (rb_scan_args (argc, argv, "24", &arg1, &arg2, &arg3, &arg4, &arg5, &sasl_options))
    {
    case 6:
      /* nothing. this requires credentials to be parsed first. we'll get defaults after arg-scanning */
    case 5:
      clientctrls = rb_ldap_get_controls (arg5);
      /* down seems more likely */
    case 4:
      serverctrls = rb_ldap_get_controls (arg4);
      /* down seems more likely */
    case 3:
      cred->bv_val = StringValueCStr (arg3);
      cred->bv_len = RSTRING_LEN (arg3);
      /* down seems more likely */
    case 2:			/* don't need the cred for GSSAPI */
      dn = StringValuePtr (arg1);
      mechanism = StringValuePtr (arg2);
      if (rb_iv_get (self, "@sasl_quiet") == Qtrue)
        sasl_flags = LDAP_SASL_QUIET;
      break;
    default:
      rb_bug ("rb_ldap_conn_bind_s");
    }

  ldap_get_option (ldapdata->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
  if (version < LDAP_VERSION3)
    {
      version = LDAP_VERSION3;
      ldapdata->err =
	ldap_set_option (ldapdata->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
      Check_LDAP_Result (ldapdata->err);
    }

  /* the following works for GSSAPI, at least */
  ldapdata->err =
    ldap_sasl_interactive_bind_s (ldapdata->ldap, dn, mechanism,
				  serverctrls, clientctrls, sasl_flags,
				  rb_ldap_sasl_interaction, (void*)sasl_options);

  if (ldapdata->err == LDAP_SASL_BIND_IN_PROGRESS)
    {
      rb_raise (rb_eNotImpError,
		"SASL authentication is not fully supported.");
      /* How can I implement this with portability? */
      /* 
         VALUE scred;
	 scred = rb_tainted_str_new(servercred->bv_val,
         servercred->bv_len);
      */
    }
  else
    {
      Check_LDAP_Result (ldapdata->err);
      ldapdata->bind = 1;
    }

  if (rb_block_given_p ())
    {
      rb_ensure (rb_yield, self, rb_ldap_conn_unbind, self);
      return Qnil;
    }
  else
    {
      return self;
    };
}
Beispiel #5
0
/** Expand an LDAP URL into a query, and return a string result from that query.
 *
 */
static ssize_t ldap_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
{
	ldap_rcode_t status;
	size_t len = 0;
	ldap_instance_t *inst = instance;
	LDAPURLDesc *ldap_url;
	LDAPMessage *result = NULL;
	LDAPMessage *entry = NULL;
	char **vals;
	ldap_handle_t *conn;
	int ldap_errno;
	char const *url;
	char const **attrs;

	url = fmt;

	if (!ldap_is_ldap_url(url)) {
		REDEBUG("String passed does not look like an LDAP URL");
		return -1;
	}

	if (ldap_url_parse(url, &ldap_url)){
		REDEBUG("Parsing LDAP URL failed");
		return -1;
	}

	/*
	 *	Nothing, empty string, "*" string, or got 2 things, die.
	 */
	if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
	    !*ldap_url->lud_attrs[0] ||
	    (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
	    ldap_url->lud_attrs[1]) {
		REDEBUG("Bad attributes list in LDAP URL. URL must specify exactly one attribute to retrieve");

		goto free_urldesc;
	}

	if (ldap_url->lud_host &&
	    ((strncmp(inst->server, ldap_url->lud_host, strlen(inst->server)) != 0) ||
	     (ldap_url->lud_port != inst->port))) {
		RDEBUG("Requested server/port is \"%s:%i\"", ldap_url->lud_host, inst->port);

		goto free_urldesc;
	}

	conn = rlm_ldap_get_socket(inst, request);
	if (!conn) goto free_urldesc;

	memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));

	status = rlm_ldap_search(inst, request, &conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter,
				 attrs, &result);
	switch (status) {
		case LDAP_PROC_SUCCESS:
			break;
		case LDAP_PROC_NO_RESULT:
			RDEBUG("Search returned not found");
		default:
			goto free_socket;
	}

	rad_assert(conn);
	rad_assert(result);

	entry = ldap_first_entry(conn->handle, result);
	if (!entry) {
		ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
		len = -1;
		goto free_result;
	}

	vals = ldap_get_values(conn->handle, entry, ldap_url->lud_attrs[0]);
	if (!vals) {
		RDEBUG("No \"%s\" attributes found in specified object", ldap_url->lud_attrs[0]);
		goto free_result;
	}

	len = strlen(vals[0]);
	if (len >= freespace){
		goto free_vals;
	}

	strlcpy(out, vals[0], freespace);

free_vals:
	ldap_value_free(vals);
free_result:
	ldap_msgfree(result);
free_socket:
	rlm_ldap_release_socket(inst, conn);
free_urldesc:
	ldap_free_urldesc(ldap_url);

	return len;
}
Beispiel #6
0
/***********************************************************************
 *      ldap_get_optionW     (WLDAP32.@)
 *
 * Retrieve option values for a given LDAP context.
 *
 * PARAMS
 *  ld      [I] Pointer to an LDAP context.
 *  option  [I] Option to get values for.
 *  value   [O] Pointer to option values.
 *
 * RETURNS
 *  Success: LDAP_SUCCESS
 *  Failure: An LDAP error code.
 */
ULONG CDECL ldap_get_optionW( WLDAP32_LDAP *ld, int option, void *value )
{
    ULONG ret = WLDAP32_LDAP_NOT_SUPPORTED;
#ifdef HAVE_LDAP

    TRACE( "(%p, 0x%08x, %p)\n", ld, option, value );

    if (!ld || !value) return WLDAP32_LDAP_PARAM_ERROR;

    switch (option)
    {
    case WLDAP32_LDAP_OPT_API_FEATURE_INFO:
    {
        LDAPAPIFeatureInfo featureU;
        LDAPAPIFeatureInfoW *featureW = value;

        if (!featureW->ldapaif_name) return WLDAP32_LDAP_PARAM_ERROR;

        featureU.ldapaif_info_version = featureW->ldapaif_info_version;
        featureU.ldapaif_name = strWtoU( featureW->ldapaif_name );
        featureU.ldapaif_version = 0;

        if (!featureU.ldapaif_name) return WLDAP32_LDAP_NO_MEMORY;

        ret = map_error( ldap_get_option( ld, option, &featureU ));

        featureW->ldapaif_version = featureU.ldapaif_version;
        strfreeU( featureU.ldapaif_name );
        return ret;
    }
    case WLDAP32_LDAP_OPT_API_INFO:
    {
        LDAPAPIInfo infoU;
        LDAPAPIInfoW *infoW = value;

        memset( &infoU, 0, sizeof(LDAPAPIInfo) );
        infoU.ldapai_info_version = infoW->ldapai_info_version;

        ret = map_error( ldap_get_option( ld, option, &infoU ));

        infoW->ldapai_api_version = infoU.ldapai_api_version;
        infoW->ldapai_protocol_version = infoU.ldapai_protocol_version;

        if (infoU.ldapai_extensions)
        {
            infoW->ldapai_extensions = strarrayUtoW( infoU.ldapai_extensions );
            if (!infoW->ldapai_extensions) return WLDAP32_LDAP_NO_MEMORY;
        }
        if (infoU.ldapai_vendor_name)
        {
            infoW->ldapai_vendor_name = strUtoW( infoU.ldapai_vendor_name );
            if (!infoW->ldapai_vendor_name)
            {
                ldap_memvfree( (void **)infoU.ldapai_extensions );
                return WLDAP32_LDAP_NO_MEMORY;
            }
        }
        infoW->ldapai_vendor_version = infoU.ldapai_vendor_version;

        ldap_memvfree( (void **)infoU.ldapai_extensions );
        ldap_memfree( infoU.ldapai_vendor_name );
        return ret;
    }

    case WLDAP32_LDAP_OPT_DEREF:
    case WLDAP32_LDAP_OPT_DESC:
    case WLDAP32_LDAP_OPT_ERROR_NUMBER:
    case WLDAP32_LDAP_OPT_PROTOCOL_VERSION:
    case WLDAP32_LDAP_OPT_REFERRALS:
    case WLDAP32_LDAP_OPT_SIZELIMIT:
    case WLDAP32_LDAP_OPT_TIMELIMIT:
        return map_error( ldap_get_option( ld, option, value ));

    case WLDAP32_LDAP_OPT_CACHE_ENABLE:
    case WLDAP32_LDAP_OPT_CACHE_FN_PTRS:
    case WLDAP32_LDAP_OPT_CACHE_STRATEGY:
    case WLDAP32_LDAP_OPT_IO_FN_PTRS:
    case WLDAP32_LDAP_OPT_REBIND_ARG:
    case WLDAP32_LDAP_OPT_REBIND_FN:
    case WLDAP32_LDAP_OPT_RESTART:
    case WLDAP32_LDAP_OPT_THREAD_FN_PTRS:
        return WLDAP32_LDAP_LOCAL_ERROR;

    case WLDAP32_LDAP_OPT_AREC_EXCLUSIVE:
    case WLDAP32_LDAP_OPT_AUTO_RECONNECT:
    case WLDAP32_LDAP_OPT_CLIENT_CERTIFICATE:
    case WLDAP32_LDAP_OPT_DNSDOMAIN_NAME:
    case WLDAP32_LDAP_OPT_ENCRYPT:
    case WLDAP32_LDAP_OPT_ERROR_STRING:
    case WLDAP32_LDAP_OPT_FAST_CONCURRENT_BIND:
    case WLDAP32_LDAP_OPT_GETDSNAME_FLAGS:
    case WLDAP32_LDAP_OPT_HOST_NAME:
    case WLDAP32_LDAP_OPT_HOST_REACHABLE:
    case WLDAP32_LDAP_OPT_PING_KEEP_ALIVE:
    case WLDAP32_LDAP_OPT_PING_LIMIT:
    case WLDAP32_LDAP_OPT_PING_WAIT_TIME:
    case WLDAP32_LDAP_OPT_PROMPT_CREDENTIALS:
    case WLDAP32_LDAP_OPT_REF_DEREF_CONN_PER_MSG:
    case WLDAP32_LDAP_OPT_REFERRAL_CALLBACK:
    case WLDAP32_LDAP_OPT_REFERRAL_HOP_LIMIT:
    case WLDAP32_LDAP_OPT_ROOTDSE_CACHE:
    case WLDAP32_LDAP_OPT_SASL_METHOD:
    case WLDAP32_LDAP_OPT_SECURITY_CONTEXT:
    case WLDAP32_LDAP_OPT_SEND_TIMEOUT:
    case WLDAP32_LDAP_OPT_SERVER_CERTIFICATE:
    case WLDAP32_LDAP_OPT_SERVER_CONTROLS:
    case WLDAP32_LDAP_OPT_SERVER_ERROR:
    case WLDAP32_LDAP_OPT_SERVER_EXT_ERROR:
    case WLDAP32_LDAP_OPT_SIGN:
    case WLDAP32_LDAP_OPT_SSL:
    case WLDAP32_LDAP_OPT_SSL_INFO:
    case WLDAP32_LDAP_OPT_SSPI_FLAGS:
    case WLDAP32_LDAP_OPT_TCP_KEEPALIVE:
        FIXME( "Unsupported option: 0x%02x\n", option );
        return WLDAP32_LDAP_NOT_SUPPORTED;

    default:
        FIXME( "Unknown option: 0x%02x\n", option );
        return WLDAP32_LDAP_LOCAL_ERROR;
    }

#endif
    return ret;
}
Beispiel #7
0
DWORD
VMCAGetDSERootAttribute(
    PVMCA_LDAP_CONTEXT pContext,
    PSTR  pszAttribute,
    PSTR* ppszAttrValue
    )
{
    DWORD dwError = 0; // LDAP_SUCCESS
    PSTR pAttribute = NULL;
    BerValue** ppValue = NULL;
    BerElement* pBer = NULL;
    LDAPMessage* pSearchResult = NULL;
    LDAPMessage* pResults = NULL;
    PCHAR pszFilter = "(objectClass=*)";
    PCHAR ppszAttrs[] = { pszAttribute, NULL };

    dwError = ldap_search_ext_s(
                  pContext->pConnection,     // Session handle
                  "",              // DN to start search
                  LDAP_SCOPE_BASE, // Scope
                  pszFilter,       // Filter
                  ppszAttrs,       // Retrieve list of attributes
                  0,               // Get both attributes and values
                  NULL,
                  NULL,
                  NULL,
                  0,
                  &pSearchResult); // [out] Search results
    BAIL_ON_ERROR(dwError);

    if (ldap_count_entries(pContext->pConnection, pSearchResult) != 1)
    {
        dwError = ERROR_INVALID_STATE;
        BAIL_ON_ERROR(dwError);
    }

    // There should be only one result for this type
    pResults = ldap_first_entry(pContext->pConnection, pSearchResult);
    if (pResults == NULL) {
        ldap_get_option(pContext->pConnection, LDAP_OPT_ERROR_NUMBER, &dwError);
        BAIL_ON_ERROR(dwError);
    }

    pAttribute = ldap_first_attribute(pContext->pConnection,pResults,&pBer);
    if(pAttribute == NULL) {
        ldap_get_option(pContext->pConnection, LDAP_OPT_ERROR_NUMBER, &dwError);
        BAIL_ON_ERROR(dwError);
    }

    ppValue = ldap_get_values_len(pContext->pConnection, pResults, pszAttribute);
    if(ppValue == NULL) {
        ldap_get_option(pContext->pConnection, LDAP_OPT_ERROR_NUMBER, &dwError);
        BAIL_ON_ERROR(dwError);
    }

    dwError = VMCAAllocateStringA(ppValue[0]->bv_val, ppszAttrValue);
    BAIL_ON_ERROR(dwError);

error :

    if ( ppValue != NULL) {
        ldap_value_free_len(ppValue);
    }

    if(pAttribute != NULL) {
        ldap_memfree(pAttribute);
    }

    if(pBer != NULL) {
        ber_free(pBer,0);
    }

    if(pSearchResult != NULL) {
        ldap_msgfree(pSearchResult);
    }

    return dwError;
}
Beispiel #8
0
/*
 * FIXME: error return must be handled in a cleaner way ...
 */
int
meta_back_op_result(
	metaconn_t		*mc,
	Operation		*op,
	SlapReply		*rs,
	int			candidate,
	ber_int_t		msgid,
	time_t			timeout,
	ldap_back_send_t	sendok )
{
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;

	const char	*save_text = rs->sr_text,
			*save_matched = rs->sr_matched;
	BerVarray	save_ref = rs->sr_ref;
	LDAPControl	**save_ctrls = rs->sr_ctrls;
	void		*matched_ctx = NULL;

	char		*matched = NULL;
	char		*text = NULL;
	char		**refs = NULL;
	LDAPControl	**ctrls = NULL;

	assert( mc != NULL );

	rs->sr_text = NULL;
	rs->sr_matched = NULL;
	rs->sr_ref = NULL;
	rs->sr_ctrls = NULL;

	if ( candidate != META_TARGET_NONE ) {
		metatarget_t		*mt = mi->mi_targets[ candidate ];
		metasingleconn_t	*msc = &mc->mc_conns[ candidate ];

		if ( LDAP_ERR_OK( rs->sr_err ) ) {
			int		rc;
			struct timeval	tv;
			LDAPMessage	*res = NULL;
			time_t		stoptime = (time_t)(-1);
			int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
						LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
			const char	*timeout_text = "Operation timed out";

			/* if timeout is not specified, compute and use
			 * the one specific to the ongoing operation */
			if ( timeout == (time_t)(-1) ) {
				slap_op_t	opidx = slap_req2op( op->o_tag );

				if ( opidx == SLAP_OP_SEARCH ) {
					if ( op->ors_tlimit <= 0 ) {
						timeout = 0;

					} else {
						timeout = op->ors_tlimit;
						timeout_err = LDAP_TIMELIMIT_EXCEEDED;
						timeout_text = NULL;
					}

				} else {
					timeout = mt->mt_timeout[ opidx ];
				}
			}

			/* better than nothing :) */
			if ( timeout == 0 ) {
				if ( mi->mi_idle_timeout ) {
					timeout = mi->mi_idle_timeout;

				} else if ( mi->mi_conn_ttl ) {
					timeout = mi->mi_conn_ttl;
				}
			}

			if ( timeout ) {
				stoptime = op->o_time + timeout;
			}

			LDAP_BACK_TV_SET( &tv );

retry:;
			rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
			switch ( rc ) {
			case 0:
				if ( timeout && ldap_time_steady() > stoptime ) {
					(void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok );
					rs->sr_err = timeout_err;
					rs->sr_text = timeout_text;
					break;
				}

				LDAP_BACK_TV_SET( &tv );
				ldap_pvt_thread_yield();
				goto retry;

			case -1:
				ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
						&rs->sr_err );
				break;


			/* otherwise get the result; if it is not
			 * LDAP_SUCCESS, record it in the reply
			 * structure (this includes
			 * LDAP_COMPARE_{TRUE|FALSE}) */
			default:
				/* only touch when activity actually took place... */
				if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
					msc->msc_time = op->o_time;
				}

				rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
						&matched, &text, &refs, &ctrls, 1 );
				res = NULL;
				if ( rc == LDAP_SUCCESS ) {
					rs->sr_text = text;
				} else {
					rs->sr_err = rc;
				}
				rs->sr_err = slap_map_api2result( rs );

				/* RFC 4511: referrals can only appear
				 * if result code is LDAP_REFERRAL */
				if ( refs != NULL
					&& refs[ 0 ] != NULL
					&& refs[ 0 ][ 0 ] != '\0' )
				{
					if ( rs->sr_err != LDAP_REFERRAL ) {
						Debug( LDAP_DEBUG_ANY,
							"%s meta_back_op_result[%d]: "
							"got referrals with err=%d\n",
							op->o_log_prefix,
							candidate, rs->sr_err );

					} else {
						int	i;

						for ( i = 0; refs[ i ] != NULL; i++ )
							/* count */ ;
						rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
							op->o_tmpmemctx );
						for ( i = 0; refs[ i ] != NULL; i++ ) {
							ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
						}
						BER_BVZERO( &rs->sr_ref[ i ] );
					}

				} else if ( rs->sr_err == LDAP_REFERRAL ) {
					Debug( LDAP_DEBUG_ANY,
						"%s meta_back_op_result[%d]: "
						"got err=%d with null "
						"or empty referrals\n",
						op->o_log_prefix,
						candidate, rs->sr_err );

					rs->sr_err = LDAP_NO_SUCH_OBJECT;
				}

				if ( ctrls != NULL ) {
					rs->sr_ctrls = ctrls;
				}
			}

			assert( res == NULL );
		}

		/* if the error in the reply structure is not
		 * LDAP_SUCCESS, try to map it from client
		 * to server error */
		if ( !LDAP_ERR_OK( rs->sr_err ) ) {
			rs->sr_err = slap_map_api2result( rs );

			/* internal ops ( op->o_conn == NULL )
			 * must not reply to client */
			if ( op->o_conn && !op->o_do_not_cache && matched ) {

				/* record the (massaged) matched
				 * DN into the reply structure */
				rs->sr_matched = matched;
			}
		}

		if ( META_BACK_TGT_QUARANTINE( mt ) ) {
			meta_back_quarantine( op, rs, candidate );
		}

	} else {
		int	i,
			err = rs->sr_err;

		for ( i = 0; i < mi->mi_ntargets; i++ ) {
			metasingleconn_t	*msc = &mc->mc_conns[ i ];
			char			*xtext = NULL;
			char			*xmatched = NULL;

			if ( msc->msc_ld == NULL ) {
				continue;
			}

			rs->sr_err = LDAP_SUCCESS;

			ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				/*
				 * better check the type of error. In some cases
				 * (search ?) it might be better to return a
				 * success if at least one of the targets gave
				 * positive result ...
				 */
				ldap_get_option( msc->msc_ld,
						LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext );
				if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
					ldap_memfree( xtext );
					xtext = NULL;
				}

				ldap_get_option( msc->msc_ld,
						LDAP_OPT_MATCHED_DN, &xmatched );
				if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
					ldap_memfree( xmatched );
					xmatched = NULL;
				}

				rs->sr_err = slap_map_api2result( rs );

				if ( DebugTest( LDAP_DEBUG_ANY ) ) {
					char	buf[ SLAP_TEXT_BUFLEN ];

					snprintf( buf, sizeof( buf ),
						"meta_back_op_result[%d] "
						"err=%d text=\"%s\" matched=\"%s\"",
						i, rs->sr_err,
						( xtext ? xtext : "" ),
						( xmatched ? xmatched : "" ) );
					Debug( LDAP_DEBUG_ANY, "%s %s.\n",
						op->o_log_prefix, buf );
				}

				/*
				 * FIXME: need to rewrite "match" (need rwinfo)
				 */
				switch ( rs->sr_err ) {
				default:
					err = rs->sr_err;
					if ( xtext != NULL ) {
						if ( text ) {
							ldap_memfree( text );
						}
						text = xtext;
						xtext = NULL;
					}
					if ( xmatched != NULL ) {
						if ( matched ) {
							ldap_memfree( matched );
						}
						matched = xmatched;
						xmatched = NULL;
					}
					break;
				}

				if ( xtext ) {
					ldap_memfree( xtext );
				}

				if ( xmatched ) {
					ldap_memfree( xmatched );
				}
			}

			if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
				meta_back_quarantine( op, rs, i );
			}
		}

		if ( err != LDAP_SUCCESS ) {
			rs->sr_err = err;
		}
	}

	if ( matched != NULL ) {
		struct berval	dn, pdn;

		ber_str2bv( matched, 0, 0, &dn );
		if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
			ldap_memfree( matched );
			matched_ctx = op->o_tmpmemctx;
			matched = pdn.bv_val;
		}
		rs->sr_matched = matched;
	}

	if ( rs->sr_err == LDAP_UNAVAILABLE ) {
		if ( !( sendok & LDAP_BACK_RETRYING ) ) {
			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
				if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
				send_ldap_result( op, rs );
			}
		}

	} else if ( op->o_conn &&
		( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
			|| ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
	{
		send_ldap_result( op, rs );
	}
	if ( matched ) {
		op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
	}
	if ( text ) {
		ldap_memfree( text );
	}
	if ( rs->sr_ref ) {
		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
		rs->sr_ref = NULL;
	}
	if ( refs ) {
		ber_memvfree( (void **)refs );
	}
	if ( ctrls ) {
		assert( rs->sr_ctrls != NULL );
		ldap_controls_free( ctrls );
	}

	rs->sr_text = save_text;
	rs->sr_matched = save_matched;
	rs->sr_ref = save_ref;
	rs->sr_ctrls = save_ctrls;

	return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
}
Beispiel #9
0
int
main (int argc, char *argv[])
{

	LDAP *ld;
	LDAPMessage *result;

	/* should be 	int result = STATE_UNKNOWN; */

	int status = STATE_UNKNOWN;
	long microsec;
	double elapsed_time;

	/* for ldap tls */

	int tls;
	int version=3;

	setlocale (LC_ALL, "");
	bindtextdomain (PACKAGE, LOCALEDIR);
	textdomain (PACKAGE);

	if (strstr(argv[0],"check_ldaps")) {
		xasprintf (&progname, "check_ldaps");
 	}

	/* Parse extra opts if any */
	argv=np_extra_opts (&argc, argv, progname);

	if (process_arguments (argc, argv) == ERROR)
		usage4 (_("Could not parse arguments"));

	if (strstr(argv[0],"check_ldaps") && ! starttls && ! ssl_on_connect)
		starttls = TRUE;

	/* initialize alarm signal handling */
	signal (SIGALRM, socket_timeout_alarm_handler);

	/* set socket timeout */
	alarm (timeout_interval);

	/* get the start time */
	gettimeofday (&tv, NULL);

	/* initialize ldap */
	if (ld_uri != NULL)
	{
#ifdef HAVE_LDAP_INITIALIZE
		int result = ldap_initialize(&ld, ld_uri);
		if (result != LDAP_SUCCESS)
		{
			printf ("Failed to connect to LDAP server at %s: %s\n",
				ld_uri, ldap_err2string(result));
			return STATE_CRITICAL;
		}
#else
		printf ("Sorry, this version of %s was compiled without URI support!\n",
			argv[0]);
		return STATE_CRITICAL;
#endif
	}
#ifdef HAVE_LDAP_INIT
	else if (!(ld = ldap_init (ld_host, ld_port))) {
		printf ("Could not connect to the server at port %i\n", ld_port);
		return STATE_CRITICAL;
	}
#else
	else if (!(ld = ldap_open (ld_host, ld_port))) {
		if (verbose)
			ldap_perror(ld, "ldap_open");
		printf (_("Could not connect to the server at port %i\n"), ld_port);
		return STATE_CRITICAL;
	}
#endif /* HAVE_LDAP_INIT */

#ifdef HAVE_LDAP_SET_OPTION
	/* set ldap options */
	if (ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &ld_protocol) !=
			LDAP_OPT_SUCCESS ) {
		printf(_("Could not set protocol version %d\n"), ld_protocol);
		return STATE_CRITICAL;
	}
#endif

	if (ld_port == LDAPS_PORT || ssl_on_connect) {
		xasprintf (&SERVICE, "LDAPS");
#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
		/* ldaps: set option tls */
		tls = LDAP_OPT_X_TLS_HARD;

		if (ldap_set_option (ld, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
		{
			if (verbose)
				ldap_perror(ld, "ldaps_option");
			printf (_("Could not init TLS at port %i!\n"), ld_port);
			return STATE_CRITICAL;
		}
#else
		printf (_("TLS not supported by the libraries!\n"));
		return STATE_CRITICAL;
#endif /* LDAP_OPT_X_TLS */
	} else if (starttls) {
		xasprintf (&SERVICE, "LDAP-TLS");
#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S)
		/* ldap with startTLS: set option version */
		if (ldap_get_option(ld,LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS )
		{
			if (version < LDAP_VERSION3)
			{
				version = LDAP_VERSION3;
				ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
			}
		}
		/* call start_tls */
		if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS)
		{
			if (verbose)
				ldap_perror(ld, "ldap_start_tls");
			printf (_("Could not init startTLS at port %i!\n"), ld_port);
			return STATE_CRITICAL;
		}
#else
		printf (_("startTLS not supported by the library, needs LDAPv3!\n"));
		return STATE_CRITICAL;
#endif /* HAVE_LDAP_START_TLS_S */
	}

	/* bind to the ldap server */
	if (ldap_bind_s (ld, ld_binddn, ld_passwd, LDAP_AUTH_SIMPLE) !=
			LDAP_SUCCESS) {
		if (verbose)
			ldap_perror(ld, "ldap_bind");
		printf (_("Could not bind to the LDAP server\n"));
		return STATE_CRITICAL;
	}

	/* do a search of all objectclasses in the base dn */
	if (ldap_search_s (ld, ld_base, LDAP_SCOPE_BASE, ld_attr, NULL, 0, &result)
			!= LDAP_SUCCESS) {
		if (verbose)
			ldap_perror(ld, "ldap_search");
		printf (_("Could not search/find objectclasses in %s\n"), ld_base);
		return STATE_CRITICAL;
	}

	/* unbind from the ldap server */
	ldap_unbind (ld);

	/* reset the alarm handler */
	alarm (0);

	/* calcutate the elapsed time and compare to thresholds */

	microsec = deltime (tv);
	elapsed_time = (double)microsec / 1.0e6;

	if (crit_time!=UNDEFINED && elapsed_time>crit_time)
		status = STATE_CRITICAL;
	else if (warn_time!=UNDEFINED && elapsed_time>warn_time)
		status = STATE_WARNING;
	else
		status = STATE_OK;

	/* print out the result */
	printf (_("LDAP %s - %.3f seconds response time|%s\n"),
	        state_text (status),
	        elapsed_time,
	        fperfdata ("time", elapsed_time, "s",
	                  (int)warn_time, warn_time,
	                  (int)crit_time, crit_time,
	                  TRUE, 0, FALSE, 0));

	return status;
}
/*
 * Delete all the children of an entry recursively until leaf nodes are reached.
 */
static int deletechildren(
	LDAP *ld,
	const char *base,
	int subentries )
{
	LDAPMessage *res, *e;
	int entries;
	int rc = LDAP_SUCCESS, srch_rc;
	static char *attrs[] = { LDAP_NO_ATTRS, NULL };
	LDAPControl c, *ctrls[2], **ctrlsp = NULL;
	BerElement *ber = NULL;

	if ( verbose ) printf ( _("deleting children of: %s\n"), base );

	if ( subentries ) {
		/*
		 * Do a one level search at base for subentry children.
		 */

		if ((ber = ber_alloc_t(LBER_USE_DER)) == NULL) {
			return EXIT_FAILURE;
		}
		rc = ber_printf( ber, "b", 1 );
		if ( rc == -1 ) {
			ber_free( ber, 1 );
			fprintf( stderr, _("Subentries control encoding error!\n"));
			return EXIT_FAILURE;
		}
		if ( ber_flatten2( ber, &c.ldctl_value, 0 ) == -1 ) {
			return EXIT_FAILURE;
		}
		c.ldctl_oid = LDAP_CONTROL_SUBENTRIES;
		c.ldctl_iscritical = 1;
		ctrls[0] = &c;
		ctrls[1] = NULL;
		ctrlsp = ctrls;
	}

	/*
	 * Do a one level search at base for children.  For each, delete its children.
	 */
more:;
	srch_rc = ldap_search_ext_s( ld, base, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
		ctrlsp, NULL, NULL, sizelimit, &res );
	switch ( srch_rc ) {
	case LDAP_SUCCESS:
	case LDAP_SIZELIMIT_EXCEEDED:
		break;
	default:
		tool_perror( "ldap_search", srch_rc, NULL, NULL, NULL, NULL );
		return( srch_rc );
	}

	entries = ldap_count_entries( ld, res );

	if ( entries > 0 ) {
		int i;

		for (e = ldap_first_entry( ld, res ), i = 0; e != NULL;
			e = ldap_next_entry( ld, e ), i++ )
		{
			char *dn = ldap_get_dn( ld, e );

			if( dn == NULL ) {
				ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc );
				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
				ber_memfree( dn );
				return rc;
			}

			rc = deletechildren( ld, dn, 0 );
			if ( rc != LDAP_SUCCESS ) {
				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
				ber_memfree( dn );
				return rc;
			}

			if ( verbose ) {
				printf( _("\tremoving %s\n"), dn );
			}

			rc = ldap_delete_ext_s( ld, dn, NULL, NULL );
			if ( rc != LDAP_SUCCESS ) {
				tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
				ber_memfree( dn );
				return rc;

			}
			
			if ( verbose ) {
				printf( _("\t%s removed\n"), dn );
			}

			ber_memfree( dn );
		}
	}

	ldap_msgfree( res );

	if ( srch_rc == LDAP_SIZELIMIT_EXCEEDED ) {
		goto more;
	}

	return rc;
}
Beispiel #11
0
static int
meta_back_bind_op_result(
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		*mc,
	int			candidate,
	int			msgid,
	ldap_back_send_t	sendok,
	int			dolock )
{
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
	metatarget_t		*mt = mi->mi_targets[ candidate ];
	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
	LDAPMessage		*res;
	struct timeval		tv;
	int			rc;
	int			nretries = mt->mt_nretries;
	char			buf[ SLAP_TEXT_BUFLEN ];

	Debug( LDAP_DEBUG_TRACE,
		">>> %s meta_back_bind_op_result[%d]\n",
		op->o_log_prefix, candidate );

	/* make sure this is clean */
	assert( rs->sr_ctrls == NULL );

	if ( rs->sr_err == LDAP_SUCCESS ) {
		time_t		stoptime = (time_t)(-1),
				timeout;
		int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
				LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
		const char	*timeout_text = "Operation timed out";
		slap_op_t	opidx = slap_req2op( op->o_tag );

		/* since timeout is not specified, compute and use
		 * the one specific to the ongoing operation */
		if ( opidx == (slap_op_t) LDAP_REQ_SEARCH ) {
			if ( op->ors_tlimit <= 0 ) {
				timeout = 0;

			} else {
				timeout = op->ors_tlimit;
				timeout_err = LDAP_TIMELIMIT_EXCEEDED;
				timeout_text = NULL;
			}

		} else {
			timeout = mt->mt_timeout[ opidx ];
		}

		/* better than nothing :) */
		if ( timeout == 0 ) {
			if ( mi->mi_idle_timeout ) {
				timeout = mi->mi_idle_timeout;

			} else if ( mi->mi_conn_ttl ) {
				timeout = mi->mi_conn_ttl;
			}
		}

		if ( timeout ) {
			stoptime = op->o_time + timeout;
		}

		LDAP_BACK_TV_SET( &tv );

		/*
		 * handle response!!!
		 */
retry:;
		rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
		switch ( rc ) {
		case 0:
			if ( nretries != META_RETRY_NEVER
				|| ( timeout && ldap_time_steady() <= stoptime ) )
			{
				ldap_pvt_thread_yield();
				if ( nretries > 0 ) {
					nretries--;
				}
				tv = mt->mt_bind_timeout;
				goto retry;
			}

			/* don't let anyone else use this handler,
			 * because there's a pending bind that will not
			 * be acknowledged */
			if ( dolock) {
				ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
			}
			assert( LDAP_BACK_CONN_BINDING( msc ) );

#ifdef DEBUG_205
			Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n",
				op->o_log_prefix, candidate, (void *)msc->msc_ld );
#endif /* DEBUG_205 */

			meta_clear_one_candidate( op, mc, candidate );
			if ( dolock ) {
				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
			}

			rs->sr_err = timeout_err;
			rs->sr_text = timeout_text;
			break;

		case -1:
			ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
				&rs->sr_err );

			snprintf( buf, sizeof( buf ),
				"err=%d (%s) nretries=%d",
				rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
			Debug( LDAP_DEBUG_ANY,
				"### %s meta_back_bind_op_result[%d]: %s.\n",
				op->o_log_prefix, candidate, buf );
			break;

		default:
			/* only touch when activity actually took place... */
			if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
				msc->msc_time = op->o_time;
			}

			/* FIXME: matched? referrals? response controls? */
			rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
					NULL, NULL, NULL, NULL, 1 );
			if ( rc != LDAP_SUCCESS ) {
				rs->sr_err = rc;
			}
			rs->sr_err = slap_map_api2result( rs );
			break;
		}
	}

	rs->sr_err = slap_map_api2result( rs );

	Debug( LDAP_DEBUG_TRACE,
		"<<< %s meta_back_bind_op_result[%d] err=%d\n",
		op->o_log_prefix, candidate, rs->sr_err );

	return rs->sr_err;
}
Beispiel #12
0
/** Load clients from LDAP on server start
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[in] cs to load client attribute/LDAP attribute mappings from.
 * @return -1 on error else 0.
 */
CC_HINT(nonnull) int rlm_ldap_client_load(ldap_instance_t const *inst, CONF_SECTION *cs)
{
	int 		ret = 0;
	ldap_rcode_t	status;
	ldap_handle_t	*conn = NULL;

	char const	**attrs = NULL;

	CONF_PAIR	*cp;
	int		count = 0, idx = 0;

	LDAPMessage	*result = NULL;
	LDAPMessage	*entry;
	char		*dn = NULL;

	RADCLIENT	*c;

	LDAP_DBG("Loading dynamic clients");

	rad_assert(inst->clientobj_base_dn);

	if (!inst->clientobj_filter) {
		LDAP_ERR("Told to load clients but 'client.filter' not specified");

		return -1;
	}

	count = cf_pair_count(cs);
	count++;

	/*
	 *	Create an array of LDAP attributes to feed to rlm_ldap_search.
	 */
	attrs = talloc_array(inst, char const *, count);
	if (rlm_ldap_client_get_attrs(attrs, &idx, cs) < 0) return -1;

	conn = rlm_ldap_get_socket(inst, NULL);
	if (!conn) return -1;

	/*
	 *	Perform all searches as the admin user.
	 */
	if (conn->rebound) {
		status = rlm_ldap_bind(inst, NULL, &conn, inst->admin_dn, inst->password, true);
		if (status != LDAP_PROC_SUCCESS) {
			ret = -1;
			goto finish;
		}

		rad_assert(conn);

		conn->rebound = false;
	}

	status = rlm_ldap_search(inst, NULL, &conn, inst->clientobj_base_dn, inst->clientobj_scope,
				 inst->clientobj_filter, attrs, &result);
	switch (status) {
	case LDAP_PROC_SUCCESS:
		break;

	case LDAP_PROC_NO_RESULT:
		LDAP_INFO("No clients were found in the directory");
		ret = 0;
		goto finish;

	default:
		ret = -1;
		goto finish;
	}

	rad_assert(conn);
	entry = ldap_first_entry(conn->handle, result);
	if (!entry) {
		int ldap_errno;

		ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		LDAP_ERR("Failed retrieving entry: %s", ldap_err2string(ldap_errno));

		ret = -1;
		goto finish;
	}

	do {
		CONF_SECTION *cc;
		char *id;

		char **value;

		id = dn = ldap_get_dn(conn->handle, entry);
		cp = cf_pair_find(cs, "identifier");
		if (cp) {
			value = ldap_get_values(conn->handle, entry, cf_pair_value(cp));
			if (value) id = value[0];
		}

		/*
		 *	Iterate over mapping sections
		 */
		cc = cf_section_alloc(NULL, "client", id);
		if (rlm_ldap_client_map_section(inst, cc, cs, conn, entry) < 0) {
			talloc_free(cc);
			ret = -1;
			goto finish;
		}

		/*
		 *@todo these should be parented from something
		 */
		c = client_afrom_cs(NULL, cc, false);
		if (!c) {
			talloc_free(cc);
			ret = -1;
			goto finish;
		}

		/*
		 *	Client parents the CONF_SECTION which defined it
		 */
		talloc_steal(c, cc);

		if (!client_add(NULL, c)) {
			LDAP_ERR("Failed to add client \"%s\", possible duplicate?", dn);
			ret = -1;
			client_free(c);
			goto finish;
		}

		LDAP_DBG("Client \"%s\" added", dn);

		ldap_memfree(dn);
		dn = NULL;
	} while ((entry = ldap_next_entry(conn->handle, entry)));

finish:
	talloc_free(attrs);
	if (dn) ldap_memfree(dn);
	if (result) ldap_msgfree(result);

	rlm_ldap_release_socket(inst, conn);

	return ret;
}
/** Open a handle to the LDAP directory
 *
 * @note This is performed synchronously.
 *
 * @param[in] cs	specifying the listener configuration.
 * @param[in] listen	structure encapsulating the libldap socket.
 * @return
 *	- 0 on success.
 *	- -1 on error.
 */
static int proto_ldap_socket_open(UNUSED CONF_SECTION *cs, rad_listen_t *listen)
{
	proto_ldap_inst_t		*inst = listen->data;
	fr_ldap_rcode_t			status;
	size_t				i;

	struct sockaddr_storage		addr;
	socklen_t			len = sizeof(addr);

	/*
	 *	Fixme - Should be the network thread's event loop?
	 */
	inst->el = main_loop_event_list();

	/*
	 *	Destroys any existing syncs and connections
	 */
	TALLOC_FREE(inst->conn);

	/*
	 *	Allocate a brand-new connection
	 */
	inst->conn = fr_ldap_connection_alloc(inst);
	if (!inst->conn) goto error;

	if (fr_ldap_connection_configure(inst->conn, &inst->handle_config) < 0) goto error;

	if (inst->conn->config->start_tls) {
		if (ldap_start_tls_s(inst->conn->handle, NULL, NULL) != LDAP_SUCCESS) {
			int		ldap_errno;
			struct timeval	now, when;

			gettimeofday(&now, NULL);

			ldap_get_option(inst->conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);

			ERROR("Failed starting TLS: %s", ldap_err2string(ldap_errno));

		error:
			TALLOC_FREE(inst->conn);

			PERROR("Failed (re)initialising connection, will retry in %pT seconds",
			      &inst->conn_retry_interval);

			fr_timeval_add(&when, &now, &inst->conn_retry_interval);

			if (fr_event_timer_insert(inst, inst->el, &inst->conn_retry_ev,
						  &when, proto_ldap_connection_init, listen) < 0) {
				FATAL("Failed inserting event: %s", fr_strerror());
			}

			return -1;
		}
	}

	status = fr_ldap_bind(NULL,
			      &inst->conn,
			      inst->conn->config->admin_identity, inst->conn->config->admin_password,
			      &(inst->conn->config->admin_sasl),
			      NULL,
			      NULL, NULL);
	if (status != LDAP_PROC_SUCCESS) goto error;

	/*
	 *	We need to know the directory type so we can synthesize cookies
	 */
	if (fr_ldap_directory_alloc(inst->conn, &inst->conn->directory, &inst->conn) < 0) goto error;

	if (ldap_get_option(inst->conn->handle, LDAP_OPT_DESC, &listen->fd) != LDAP_OPT_SUCCESS) {
		int ldap_errno;

		ldap_get_option(inst->conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);

		ERROR("Failed retrieving file descriptor from LDAP handle: %s", ldap_err2string(ldap_errno));
		goto error;
	}

	/*
	 *	Work back to get src/dst ip address and ports from the file descriptor
	 */
	if (getsockname(listen->fd, (struct sockaddr *)&addr, &len) < 0) {
		ERROR("Failed getting socket information: %s", fr_syserror(errno));
		goto error;
	}
	fr_ipaddr_from_sockaddr(&addr, len, &inst->src_ipaddr, &inst->src_port);

	if (getpeername(listen->fd, (struct sockaddr *)&addr, &len) < 0) {
		ERROR("Failed getting socket information: %s", fr_syserror(errno));
		goto error;
	}

	/*
	 *	Allocate a fake client to use in requests
	 */
	fr_ipaddr_from_sockaddr(&addr, len, &inst->dst_ipaddr, &inst->dst_port);
	inst->client = proto_ldap_fake_client_alloc(inst);

	DEBUG2("Starting sync(s)");
	for (i = 0; i < talloc_array_length(inst->sync_config); i++) {
		uint8_t *cookie;
		int	ret;

		/*
		 *	Synchronously load the cookie... ewww
		 */
		if (proto_ldap_cookie_load(inst, &cookie, listen, inst->sync_config[i]) < 0) goto error;
		ret = sync_state_init(inst->conn, inst->sync_config[i], cookie, false);
		talloc_free(cookie);
		if (ret < 0) goto error;
	}

	return 0;
}
Beispiel #14
0
static void *
do_onerwthread( void *arg )
{
	int		i, j, thisconn;
	LDAP		**mlds, *ld;
	char		thrstr[BUFSIZ];
	char		dn[256], uids[32], cns[32], *base;
	LDAPMod		*attrp[5], attrs[4];
	char		*oc_vals[] = { "top", "OpenLDAPperson", NULL };
	char		*cn_vals[] = { NULL, NULL };
	char		*sn_vals[] = { NULL, NULL };
	char		*uid_vals[] = { NULL, NULL };
	int		ret;
	int		adds = 0;
	int		dels = 0;
	int		rc, refcnt = 0;
	int		idx = (ldap_pvt_thread_t *)arg - rtid;

	mlds = (LDAP **) calloc( sizeof(LDAP *), noconns);
	if (mlds == NULL) {
		thread_error( idx, "Memory error: thread calloc for noconns" );
		exit( EXIT_FAILURE );
	}

	snprintf(uids, sizeof(uids), "rwtest%04d", idx);
	snprintf(cns, sizeof(cns), "rwtest%04d", idx);
	/* add setup */
	for (i = 0; i < 4; i++) {
		attrp[i] = &attrs[i];
		attrs[i].mod_op = 0;
	}
	attrp[4] = NULL;
	attrs[0].mod_type = "objectClass";
	attrs[0].mod_values = oc_vals;
	attrs[1].mod_type = "cn";
	attrs[1].mod_values = cn_vals;
	cn_vals[0] = &cns[0];
	attrs[2].mod_type = "sn";
	attrs[2].mod_values = sn_vals;
	sn_vals[0] = &cns[0];
	attrs[3].mod_type = "uid";
	attrs[3].mod_values = uid_vals;
	uid_vals[0] = &uids[0];

	for ( j = 0; j < outerloops; j++ ) {
		for(i = 0; i < noconns; i++) {
			mlds[i] = ldap_dup(lds[i]);
			if (mlds[i] == NULL) {
				thread_error( idx, "ldap_dup error" );
			}
		}
		rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt);
		snprintf(thrstr, BUFSIZ,
			"RW Thread conns: %d refcnt: %d (rc = %d)",
			noconns, refcnt, rc);
		thread_verbose(idx, thrstr);

		thisconn = (idx + j) % noconns;
		if (thisconn < 0 || thisconn >= noconns)
			thisconn = 0;
		if (mlds[thisconn] == NULL) {
			thread_error( idx, "(failed to dup)");
			tester_perror( "ldap_dup", "(failed to dup)" );
			exit( EXIT_FAILURE );
		}
		snprintf(thrstr, BUFSIZ, "START RW Thread using conn %d", thisconn);
		thread_verbose(idx, thrstr);

		ld = mlds[thisconn];
		if (entry != NULL)
			base = entry;
		else
			base = DEFAULT_BASE;
		snprintf(dn, 256, "cn=%s,%s", cns, base);

		adds = 0;
		dels = 0;
		for (i = 0; i < loops; i++) {
			ret = ldap_add_ext_s(ld, dn, &attrp[0], NULL, NULL);
			if (ret == LDAP_SUCCESS) {
				adds++;
				ret = ldap_delete_ext_s(ld, dn, NULL, NULL);
				if (ret == LDAP_SUCCESS) {
					dels++;
					rt_pass[idx]++;
				} else {
					thread_output(idx, ldap_err2string(ret));
					rt_fail[idx]++;
				}
			} else {
				thread_output(idx, ldap_err2string(ret));
				rt_fail[idx]++;
			}
		}

		snprintf(thrstr, BUFSIZ,
			"INNER STOP RW Thread using conn %d (%d/%d)",
			thisconn, adds, dels);
		thread_verbose(idx, thrstr);

		for(i = 0; i < noconns; i++) {
			(void) ldap_destroy(mlds[i]);
			mlds[i] = NULL;
		}
	}

	free( mlds );
	return( NULL );
}
Beispiel #15
0
int TlsOptions::getIntOption( tls_option opt ) const {
    int value;
    checkOpt(opt, INT);
    ldap_get_option( m_ld, optmap[opt].optval, (void*) &value);
    return value;
}
Beispiel #16
0
krb5_error_code
krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
                        char **db_args)
{
    int                         l=0, kerberos_principal_object_type=0;
    krb5_error_code             st=0, tempst=0;
    LDAP                        *ld=NULL;
    LDAPMessage                 *result=NULL, *ent=NULL;
    char                        *user=NULL, *subtree=NULL, *principal_dn=NULL;
    char                        **values=NULL, *strval[10]={NULL}, errbuf[1024];
    char                        *filtuser=NULL;
    struct berval               **bersecretkey=NULL;
    LDAPMod                     **mods=NULL;
    krb5_boolean                create_standalone_prinicipal=FALSE;
    krb5_boolean                krb_identity_exists=FALSE, establish_links=FALSE;
    char                        *standalone_principal_dn=NULL;
    krb5_tl_data                *tl_data=NULL;
    krb5_key_data               **keys=NULL;
    kdb5_dal_handle             *dal_handle=NULL;
    krb5_ldap_context           *ldap_context=NULL;
    krb5_ldap_server_handle     *ldap_server_handle=NULL;
    osa_princ_ent_rec           princ_ent;
    xargs_t                     xargs = {0};
    char                        *polname = NULL;
    OPERATION optype;
    krb5_boolean                found_entry = FALSE;

    /* Clear the global error string */
    krb5_clear_error_message(context);

    SETUP_CONTEXT();
    if (ldap_context->lrparams == NULL || ldap_context->container_dn == NULL)
        return EINVAL;

    /* get ldap handle */
    GET_HANDLE();

    if (is_principal_in_realm(ldap_context, entry->princ) != 0) {
        st = EINVAL;
        krb5_set_error_message(context, st, _("Principal does not belong to "
                                              "the default realm"));
        goto cleanup;
    }

    /* get the principal information to act on */
    if (((st=krb5_unparse_name(context, entry->princ, &user)) != 0) ||
        ((st=krb5_ldap_unparse_principal_name(user)) != 0))
        goto cleanup;
    filtuser = ldap_filter_correct(user);
    if (filtuser == NULL) {
        st = ENOMEM;
        goto cleanup;
    }

    /* Identity the type of operation, it can be
     * add principal or modify principal.
     * hack if the entry->mask has KRB_PRINCIPAL flag set
     * then it is a add operation
     */
    if (entry->mask & KADM5_PRINCIPAL)
        optype = ADD_PRINCIPAL;
    else
        optype = MODIFY_PRINCIPAL;

    if (((st=krb5_get_princ_type(context, entry, &kerberos_principal_object_type)) != 0) ||
        ((st=krb5_get_userdn(context, entry, &principal_dn)) != 0))
        goto cleanup;

    if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
        goto cleanup;

    if (entry->mask & KADM5_LOAD) {
        unsigned int     tree = 0, ntrees = 0;
        int              numlentries = 0;
        char             **subtreelist = NULL, *filter = NULL;

        /*  A load operation is special, will do a mix-in (add krbprinc
         *  attrs to a non-krb object entry) if an object exists with a
         *  matching krbprincipalname attribute so try to find existing
         *  object and set principal_dn.  This assumes that the
         *  krbprincipalname attribute is unique (only one object entry has
         *  a particular krbprincipalname attribute).
         */
        if (asprintf(&filter, FILTER"%s))", filtuser) < 0) {
            filter = NULL;
            st = ENOMEM;
            goto cleanup;
        }

        /* get the current subtree list */
        if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
            goto cleanup;

        found_entry = FALSE;
        /* search for entry with matching krbprincipalname attribute */
        for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
            result = NULL;
            if (principal_dn == NULL) {
                LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
            } else {
                /* just look for entry with principal_dn */
                LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
            }
            if (st == LDAP_SUCCESS) {
                numlentries = ldap_count_entries(ld, result);
                if (numlentries > 1) {
                    ldap_msgfree(result);
                    free(filter);
                    st = EINVAL;
                    krb5_set_error_message(context, st,
                                           _("operation can not continue, "
                                             "more than one entry with "
                                             "principal name \"%s\" found"),
                                           user);
                    goto cleanup;
                } else if (numlentries == 1) {
                    found_entry = TRUE;
                    if (principal_dn == NULL) {
                        ent = ldap_first_entry(ld, result);
                        if (ent != NULL) {
                            /* setting principal_dn will cause that entry to be modified further down */
                            if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
                                ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
                                st = set_ldap_error (context, st, 0);
                                ldap_msgfree(result);
                                free(filter);
                                goto cleanup;
                            }
                        }
                    }
                }
                if (result)
                    ldap_msgfree(result);
            } else if (st != LDAP_NO_SUCH_OBJECT) {
                /* could not perform search, return with failure */
                st = set_ldap_error (context, st, 0);
                free(filter);
                goto cleanup;
            }
            /*
             * If it isn't found then assume a standalone princ entry is to
             * be created.
             */
        } /* end for (tree = 0; principal_dn == ... */

        free(filter);

        if (found_entry == FALSE && principal_dn != NULL) {
            /*
             * if principal_dn is null then there is code further down to
             * deal with setting standalone_principal_dn.  Also note that
             * this will set create_standalone_prinicipal true for
             * non-mix-in entries which is okay if loading from a dump.
             */
            create_standalone_prinicipal = TRUE;
            standalone_principal_dn = strdup(principal_dn);
            CHECK_NULL(standalone_principal_dn);
        }
    } /* end if (entry->mask & KADM5_LOAD */

    /* time to generate the DN information with the help of
     * containerdn, principalcontainerreference or
     * realmcontainerdn information
     */
    if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
        /* get the subtree information */
        if (entry->princ->length == 2 && entry->princ->data[0].length == strlen("krbtgt") &&
            strncmp(entry->princ->data[0].data, "krbtgt", entry->princ->data[0].length) == 0) {
            /* if the principal is a inter-realm principal, always created in the realm container */
            subtree = strdup(ldap_context->lrparams->realmdn);
        } else if (xargs.containerdn) {
            if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
                if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
                    int ost = st;
                    st = EINVAL;
                    snprintf(errbuf, sizeof(errbuf), _("'%s' not found: "),
                             xargs.containerdn);
                    prepend_err_str(context, errbuf, st, ost);
                }
                goto cleanup;
            }
            subtree = strdup(xargs.containerdn);
        } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
            /*
             * Here the subtree should be changed with
             * principalcontainerreference attribute value
             */
            subtree = strdup(ldap_context->lrparams->containerref);
        } else {
            subtree = strdup(ldap_context->lrparams->realmdn);
        }
        CHECK_NULL(subtree);

        if (asprintf(&standalone_principal_dn, "krbprincipalname=%s,%s",
                     filtuser, subtree) < 0)
            standalone_principal_dn = NULL;
        CHECK_NULL(standalone_principal_dn);
        /*
         * free subtree when you are done using the subtree
         * set the boolean create_standalone_prinicipal to TRUE
         */
        create_standalone_prinicipal = TRUE;
        free(subtree);
        subtree = NULL;
    }

    /*
     * If the DN information is presented by the user, time to
     * validate the input to ensure that the DN falls under
     * any of the subtrees
     */
    if (xargs.dn_from_kbd == TRUE) {
        /* make sure the DN falls in the subtree */
        unsigned int     tre=0, ntrees=0;
        int              dnlen=0, subtreelen=0;
        char             **subtreelist=NULL;
        char             *dn=NULL;
        krb5_boolean     outofsubtree=TRUE;

        if (xargs.dn != NULL) {
            dn = xargs.dn;
        } else if (xargs.linkdn != NULL) {
            dn = xargs.linkdn;
        } else if (standalone_principal_dn != NULL) {
            /*
             * Even though the standalone_principal_dn is constructed
             * within this function, there is the containerdn input
             * from the user that can become part of the it.
             */
            dn = standalone_principal_dn;
        }

        /* get the current subtree list */
        if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
            goto cleanup;

        for (tre=0; tre<ntrees; ++tre) {
            if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
                outofsubtree = FALSE;
                break;
            } else {
                dnlen = strlen (dn);
                subtreelen = strlen(subtreelist[tre]);
                if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
                    outofsubtree = FALSE;
                    break;
                }
            }
        }

        for (tre=0; tre < ntrees; ++tre) {
            free(subtreelist[tre]);
        }

        if (outofsubtree == TRUE) {
            st = EINVAL;
            krb5_set_error_message(context, st,
                                   _("DN is out of the realm subtree"));
            goto cleanup;
        }

        /*
         * dn value will be set either by dn, linkdn or the standalone_principal_dn
         * In the first 2 cases, the dn should be existing and in the last case we
         * are supposed to create the ldap object. so the below should not be
         * executed for the last case.
         */

        if (standalone_principal_dn == NULL) {
            /*
             * If the ldap object is missing, this results in an error.
             */

            /*
             * Search for krbprincipalname attribute here.
             * This is to find if a kerberos identity is already present
             * on the ldap object, in which case adding a kerberos identity
             * on the ldap object should result in an error.
             */
            char  *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};

            LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
            if (st == LDAP_SUCCESS) {
                ent = ldap_first_entry(ld, result);
                if (ent != NULL) {
                    if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
                        ldap_value_free(values);
                    }

                    if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
                        krb_identity_exists = TRUE;
                        ldap_value_free(values);
                    }
                }
                ldap_msgfree(result);
            } else {
                st = set_ldap_error(context, st, OP_SEARCH);
                goto cleanup;
            }
        }
    }

    /*
     * If xargs.dn is set then the request is to add a
     * kerberos principal on a ldap object, but if
     * there is one already on the ldap object this
     * should result in an error.
     */

    if (xargs.dn != NULL && krb_identity_exists == TRUE) {
        st = EINVAL;
        snprintf(errbuf, sizeof(errbuf),
                 _("ldap object is already kerberized"));
        krb5_set_error_message(context, st, "%s", errbuf);
        goto cleanup;
    }

    if (xargs.linkdn != NULL) {
        /*
         * link information can be changed using modprinc.
         * However, link information can be changed only on the
         * standalone kerberos principal objects. A standalone
         * kerberos principal object is of type krbprincipal
         * structural objectclass.
         *
         * NOTE: kerberos principals on an ldap object can't be
         * linked to other ldap objects.
         */
        if (optype == MODIFY_PRINCIPAL &&
            kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
            st = EINVAL;
            snprintf(errbuf, sizeof(errbuf),
                     _("link information can not be set/updated as the "
                       "kerberos principal belongs to an ldap object"));
            krb5_set_error_message(context, st, "%s", errbuf);
            goto cleanup;
        }
        /*
         * Check the link information. If there is already a link
         * existing then this operation is not allowed.
         */
        {
            char **linkdns=NULL;
            int  j=0;

            if ((st=krb5_get_linkdn(context, entry, &linkdns)) != 0) {
                snprintf(errbuf, sizeof(errbuf),
                         _("Failed getting object references"));
                krb5_set_error_message(context, st, "%s", errbuf);
                goto cleanup;
            }
            if (linkdns != NULL) {
                st = EINVAL;
                snprintf(errbuf, sizeof(errbuf),
                         _("kerberos principal is already linked to a ldap "
                           "object"));
                krb5_set_error_message(context, st, "%s", errbuf);
                for (j=0; linkdns[j] != NULL; ++j)
                    free (linkdns[j]);
                free (linkdns);
                goto cleanup;
            }
        }

        establish_links = TRUE;
    }

    if (entry->mask & KADM5_LAST_SUCCESS) {
        memset(strval, 0, sizeof(strval));
        if ((strval[0]=getstringtime(entry->last_success)) == NULL)
            goto cleanup;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
            free (strval[0]);
            goto cleanup;
        }
        free (strval[0]);
    }

    if (entry->mask & KADM5_LAST_FAILED) {
        memset(strval, 0, sizeof(strval));
        if ((strval[0]=getstringtime(entry->last_failed)) == NULL)
            goto cleanup;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
            free (strval[0]);
            goto cleanup;
        }
        free(strval[0]);
    }

    if (entry->mask & KADM5_FAIL_AUTH_COUNT) {
        krb5_kvno fail_auth_count;

        fail_auth_count = entry->fail_auth_count;
        if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
            fail_auth_count++;

        st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
                                       LDAP_MOD_REPLACE,
                                       fail_auth_count);
        if (st != 0)
            goto cleanup;
    } else if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) {
        int attr_mask = 0;
        krb5_boolean has_fail_count;

        /* Check if the krbLoginFailedCount attribute exists.  (Through
         * krb5 1.8.1, it wasn't set in new entries.) */
        st = krb5_get_attributes_mask(context, entry, &attr_mask);
        if (st != 0)
            goto cleanup;
        has_fail_count = ((attr_mask & KDB_FAIL_AUTH_COUNT_ATTR) != 0);

        /*
         * If the client library and server supports RFC 4525,
         * then use it to increment by one the value of the
         * krbLoginFailedCount attribute. Otherwise, assert the
         * (provided) old value by deleting it before adding.
         */
#ifdef LDAP_MOD_INCREMENT
        if (ldap_server_handle->server_info->modify_increment &&
            has_fail_count) {
            st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
                                           LDAP_MOD_INCREMENT, 1);
            if (st != 0)
                goto cleanup;
        } else {
#endif /* LDAP_MOD_INCREMENT */
            if (has_fail_count) {
                st = krb5_add_int_mem_ldap_mod(&mods,
                                               "krbLoginFailedCount",
                                               LDAP_MOD_DELETE,
                                               entry->fail_auth_count);
                if (st != 0)
                    goto cleanup;
            }
            st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
                                           LDAP_MOD_ADD,
                                           entry->fail_auth_count + 1);
            if (st != 0)
                goto cleanup;
#ifdef LDAP_MOD_INCREMENT
        }
#endif
    } else if (optype == ADD_PRINCIPAL) {
        /* Initialize krbLoginFailedCount in new entries to help avoid a
         * race during the first failed login. */
        st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
                                       LDAP_MOD_ADD, 0);
    }

    if (entry->mask & KADM5_MAX_LIFE) {
        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entry->max_life)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_MAX_RLIFE) {
        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
                                          entry->max_renewable_life)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_ATTRIBUTES) {
        if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
                                          entry->attributes)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_PRINCIPAL) {
        memset(strval, 0, sizeof(strval));
        strval[0] = user;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_PRINC_EXPIRE_TIME) {
        memset(strval, 0, sizeof(strval));
        if ((strval[0]=getstringtime(entry->expiration)) == NULL)
            goto cleanup;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
            free (strval[0]);
            goto cleanup;
        }
        free (strval[0]);
    }

    if (entry->mask & KADM5_PW_EXPIRATION) {
        memset(strval, 0, sizeof(strval));
        if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
            goto cleanup;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
                                          LDAP_MOD_REPLACE,
                                          strval)) != 0) {
            free (strval[0]);
            goto cleanup;
        }
        free (strval[0]);
    }

    if (entry->mask & KADM5_POLICY) {
        memset(&princ_ent, 0, sizeof(princ_ent));
        for (tl_data=entry->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
            if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
                /* FIX ME: I guess the princ_ent should be freed after this call */
                if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
                    goto cleanup;
                }
            }
        }

        if (princ_ent.aux_attributes & KADM5_POLICY) {
            memset(strval, 0, sizeof(strval));
            if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
                goto cleanup;
            strval[0] = polname;
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
                goto cleanup;
        } else {
            st = EINVAL;
            krb5_set_error_message(context, st, "Password policy value null");
            goto cleanup;
        }
    } else if (entry->mask & KADM5_LOAD && found_entry == TRUE) {
        /*
         * a load is special in that existing entries must have attrs that
         * removed.
         */

        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_POLICY_CLR) {
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
            goto cleanup;
    }

    if (entry->mask & KADM5_KEY_DATA || entry->mask & KADM5_KVNO) {
        krb5_kvno mkvno;

        if ((st=krb5_dbe_lookup_mkvno(context, entry, &mkvno)) != 0)
            goto cleanup;
        bersecretkey = krb5_encode_krbsecretkey (entry->key_data,
                                                 entry->n_key_data, mkvno);

        if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
                                          LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0)
            goto cleanup;

        if (!(entry->mask & KADM5_PRINCIPAL)) {
            memset(strval, 0, sizeof(strval));
            if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
                goto cleanup;
            if ((st=krb5_add_str_mem_ldap_mod(&mods,
                                              "krbpasswordexpiration",
                                              LDAP_MOD_REPLACE, strval)) != 0) {
                free (strval[0]);
                goto cleanup;
            }
            free (strval[0]);
        }

        /* Update last password change whenever a new key is set */
        {
            krb5_timestamp last_pw_changed;
            if ((st=krb5_dbe_lookup_last_pwd_change(context, entry,
                                                    &last_pw_changed)) != 0)
                goto cleanup;

            memset(strval, 0, sizeof(strval));
            if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
                goto cleanup;

            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
                                              LDAP_MOD_REPLACE, strval)) != 0) {
                free (strval[0]);
                goto cleanup;
            }
            free (strval[0]);
        }

    } /* Modify Key data ends here */

    /* Set tl_data */
    if (entry->tl_data != NULL) {
        int count = 0;
        struct berval **ber_tl_data = NULL;
        krb5_tl_data *ptr;
        krb5_timestamp unlock_time;
        for (ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
            if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
#ifdef SECURID
                || ptr->tl_data_type == KRB5_TL_DB_ARGS
#endif
                || ptr->tl_data_type == KRB5_TL_KADM_DATA
                || ptr->tl_data_type == KDB_TL_USER_INFO
                || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
                || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
                continue;
            count++;
        }
        if (count != 0) {
            int j;
            ber_tl_data = (struct berval **) calloc (count + 1,
                                                     sizeof (struct berval*));
            if (ber_tl_data == NULL) {
                st = ENOMEM;
                goto cleanup;
            }
            for (j = 0, ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
                /* Ignore tl_data that are stored in separate directory
                 * attributes */
                if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
#ifdef SECURID
                    || ptr->tl_data_type == KRB5_TL_DB_ARGS
#endif
                    || ptr->tl_data_type == KRB5_TL_KADM_DATA
                    || ptr->tl_data_type == KDB_TL_USER_INFO
                    || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
                    || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
                    continue;
                if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
                    break;
                j++;
            }
            if (st == 0) {
                ber_tl_data[count] = NULL;
                st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
                                             LDAP_MOD_REPLACE |
                                             LDAP_MOD_BVALUES, ber_tl_data);
            }
            for (j = 0; ber_tl_data[j] != NULL; j++) {
                free(ber_tl_data[j]->bv_val);
                free(ber_tl_data[j]);
            }
            free(ber_tl_data);
            if (st != 0)
                goto cleanup;
        }
        if ((st=krb5_dbe_lookup_last_admin_unlock(context, entry,
                                                  &unlock_time)) != 0)
            goto cleanup;
        if (unlock_time != 0) {
            /* Update last admin unlock */
            memset(strval, 0, sizeof(strval));
            if ((strval[0] = getstringtime(unlock_time)) == NULL)
                goto cleanup;

            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastAdminUnlock",
                                              LDAP_MOD_REPLACE, strval)) != 0) {
                free (strval[0]);
                goto cleanup;
            }
            free (strval[0]);
        }
    }

    /* Directory specific attribute */
    if (xargs.tktpolicydn != NULL) {
        int tmask=0;

        if (strlen(xargs.tktpolicydn) != 0) {
            st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask);
            CHECK_CLASS_VALIDITY(st, tmask, _("ticket policy object value: "));

            strval[0] = xargs.tktpolicydn;
            strval[1] = NULL;
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
                goto cleanup;

        } else {
            /* if xargs.tktpolicydn is a empty string, then delete
             * already existing krbticketpolicyreference attr */
            if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
                goto cleanup;
        }

    }

    if (establish_links == TRUE) {
        memset(strval, 0, sizeof(strval));
        strval[0] = xargs.linkdn;
        if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0)
            goto cleanup;
    }

    /*
     * in case mods is NULL then return
     * not sure but can happen in a modprinc
     * so no need to return an error
     * addprinc will at least have the principal name
     * and the keys passed in
     */
    if (mods == NULL)
        goto cleanup;

    if (create_standalone_prinicipal == TRUE) {
        memset(strval, 0, sizeof(strval));
        strval[0] = "krbprincipal";
        strval[1] = "krbprincipalaux";
        strval[2] = "krbTicketPolicyAux";

        if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
            goto cleanup;

        st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
        if (st == LDAP_ALREADY_EXISTS && entry->mask & KADM5_LOAD) {
            /* a load operation must replace an existing entry */
            st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL);
            if (st != LDAP_SUCCESS) {
                snprintf(errbuf, sizeof(errbuf),
                         _("Principal delete failed (trying to replace "
                           "entry): %s"), ldap_err2string(st));
                st = translate_ldap_error (st, OP_ADD);
                krb5_set_error_message(context, st, "%s", errbuf);
                goto cleanup;
            } else {
                st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
            }
        }
        if (st != LDAP_SUCCESS) {
            snprintf(errbuf, sizeof(errbuf), _("Principal add failed: %s"),
                     ldap_err2string(st));
            st = translate_ldap_error (st, OP_ADD);
            krb5_set_error_message(context, st, "%s", errbuf);
            goto cleanup;
        }
    } else {
        /*
         * Here existing ldap object is modified and can be related
         * to any attribute, so always ensure that the ldap
         * object is extended with all the kerberos related
         * objectclasses so that there are no constraint
         * violations.
         */
        {
            char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
            int p, q, r=0, amask=0;

            if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
                                        "objectclass", attrvalues, &amask)) != 0)
                goto cleanup;

            memset(strval, 0, sizeof(strval));
            for (p=1, q=0; p<=2; p<<=1, ++q) {
                if ((p & amask) == 0)
                    strval[r++] = attrvalues[q];
            }
            if (r != 0) {
                if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
                    goto cleanup;
            }
        }
        if (xargs.dn != NULL)
            st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
        else
            st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);

        if (st != LDAP_SUCCESS) {
            snprintf(errbuf, sizeof(errbuf), _("User modification failed: %s"),
                     ldap_err2string(st));
            st = translate_ldap_error (st, OP_MOD);
            krb5_set_error_message(context, st, "%s", errbuf);
            goto cleanup;
        }

        if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
            entry->fail_auth_count++;
    }

cleanup:
    if (user)
        free(user);

    if (filtuser)
        free(filtuser);

    free_xargs(xargs);

    if (standalone_principal_dn)
        free(standalone_principal_dn);

    if (principal_dn)
        free (principal_dn);

    if (polname != NULL)
        free(polname);

    if (subtree)
        free (subtree);

    if (bersecretkey) {
        for (l=0; bersecretkey[l]; ++l) {
            if (bersecretkey[l]->bv_val)
                free (bersecretkey[l]->bv_val);
            free (bersecretkey[l]);
        }
        free (bersecretkey);
    }

    if (keys)
        free (keys);

    ldap_mods_free(mods, 1);
    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
    return(st);
}
Beispiel #17
0
int
main( int argc, char *argv[] )
{
	int		rc;
	LDAP		*ld = NULL;
	char		*matcheddn = NULL, *text = NULL, **refs = NULL;
	int rcode;
	char * diag = NULL;
	struct berval	*scookie = NULL;
	struct berval	*scred = NULL;
	int		id, code = 0;
	LDAPMessage	*res;
	LDAPControl	**ctrls = NULL;
	LDAPControl	**vcctrls = NULL;
	int nvcctrls = 0;

	tool_init( TOOL_VC );
	prog = lutil_progname( "ldapvc", argc, argv );

	/* LDAPv3 only */
	protocol = LDAP_VERSION3;

	tool_args( argc, argv );

	if (argc - optind > 0) {
		dn = argv[optind++];
	}
	if (argc - optind > 0) {
		cred.bv_val = strdup(argv[optind++]);
		cred.bv_len = strlen(cred.bv_val);
	}
	if (argc - optind > 0) {
		usage();
	}
	if (dn 
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE
           && !vc_sasl_mech 
#endif
           && !cred.bv_val)
	{
		cred.bv_val = strdup(getpassphrase(_("User's password: "******"ldap_verify_credentials_interactive", rc, NULL, NULL, text, NULL);
				ldap_memfree(text);
				tool_exit(ld, rc);
			}
		} while (rc == LDAP_SASL_BIND_IN_PROGRESS);

	    lutil_sasl_freedefs(defaults);

	    if( rc != LDAP_SUCCESS ) {
			ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*) &text);
		    tool_perror( "ldap_verify_credentials", rc, NULL, NULL, text, NULL );
		    rc = EXIT_FAILURE;
		    goto skip;
	    }

	} else
#endif
#endif
    {
	    rc = ldap_verify_credentials( ld,
		    NULL,
		    dn, NULL, cred.bv_val ? &cred: NULL, vcctrls,
		    NULL, NULL, &id ); 
    
	    if( rc != LDAP_SUCCESS ) {
			ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*) &text);
		    tool_perror( "ldap_verify_credentials", rc, NULL, NULL, text, NULL );
		    rc = EXIT_FAILURE;
		    goto skip;
	    }

	    for ( ; ; ) {
		    struct timeval	tv;

		    if ( tool_check_abandon( ld, id ) ) {
			    tool_exit( ld, LDAP_CANCELLED );
		    }

		    tv.tv_sec = 0;
		    tv.tv_usec = 100000;

		    rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
		    if ( rc < 0 ) {
			    tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
			    tool_exit( ld, rc );
		    }

		    if ( rc != 0 ) {
			    break;
		    }
	    }
	}

	ldap_controls_free(vcctrls);
	vcctrls = NULL;

	rc = ldap_parse_result( ld, res,
		&code, &matcheddn, &text, &refs, &ctrls, 0 );

	if (rc == LDAP_SUCCESS) rc = code;

	if (rc != LDAP_SUCCESS) {
		tool_perror( "ldap_parse_result", rc, NULL, matcheddn, text, refs );
		rc = EXIT_FAILURE;
		goto skip;
	}

	rc = ldap_parse_verify_credentials( ld, res, &rcode, &diag, &scookie, &scred, &vcctrls );
	ldap_msgfree(res);

	if (rc != LDAP_SUCCESS) {
		tool_perror( "ldap_parse_verify_credentials", rc, NULL, NULL, NULL, NULL );
		rc = EXIT_FAILURE;
		goto skip;
	}

	if (rcode != LDAP_SUCCESS) {
		printf(_("Failed: %s (%d)\n"), ldap_err2string(rcode), rcode);
	}

	if (diag && *diag) {
	    printf(_("Diagnostic: %s\n"), diag);
	}

	if (vcctrls) {
		tool_print_ctrls( ld, vcctrls );
	}

skip:
	if ( verbose || code != LDAP_SUCCESS ||
		( matcheddn && *matcheddn ) || ( text && *text ) || refs || ctrls )
	{
		printf( _("Result: %s (%d)\n"), ldap_err2string( code ), code );

		if( text && *text ) {
			printf( _("Additional info: %s\n"), text );
		}

		if( matcheddn && *matcheddn ) {
			printf( _("Matched DN: %s\n"), matcheddn );
		}

		if( refs ) {
			int i;
			for( i=0; refs[i]; i++ ) {
				printf(_("Referral: %s\n"), refs[i] );
			}
		}

		if (ctrls) {
			tool_print_ctrls( ld, ctrls );
			ldap_controls_free( ctrls );
		}
	}

	ber_memfree( text );
	ber_memfree( matcheddn );
	ber_memvfree( (void **) refs );
	ber_bvfree( scookie );
	ber_bvfree( scred );
	ber_memfree( diag );
	free( cred.bv_val );

	/* disconnect from server */
	tool_exit( ld, code == LDAP_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE );
}
Beispiel #18
0
int
prldap_x_install_dns_skipdb(LDAP *ld, const char *skip)
{
    enum __nsw_parse_err		pserr;
    struct __nsw_switchconfig       *conf;
    struct __nsw_lookup             *lkp;
    struct ldap_dns_fns             dns_fns;
    char                            *name_list = NULL;
    char                            *tmp;
    const char                      *name;
    int                             len;
    boolean_t                       got_skip = B_FALSE;

    /*
     * db_root_hosts.lock mutex is used to ensure that the name list
     * is not in use by the name service switch while we are updating
     * the host_service
     */

    (void) mutex_lock(&db_root_hosts.lock);
    conf = __nsw_getconfig("hosts", &pserr);
    if (conf == NULL) {
        (void) mutex_unlock(&db_root_hosts.lock);
        return (0);
    }

    /* check for skip and count other backends */
    for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
        name = lkp->service_name;
        if (strcmp(name, skip) == 0) {
            got_skip = B_TRUE;
            continue;
        }
        if (name_list == NULL)
            name_list = strdup(name);
        else {
            len = strlen(name_list);
            tmp = realloc(name_list, len + strlen(name) + 2);
            if (tmp == NULL) {
                free(name_list);
                name_list = NULL;
            } else {
                name_list = tmp;
                name_list[len++] = ' ';
                (void) strcpy(name_list+len, name);
            }
        }
        if (name_list == NULL) {        /* alloc error */
            (void) mutex_unlock(&db_root_hosts.lock);
            __nsw_freeconfig(conf);
            return (-1);
        }
    }
    __nsw_freeconfig(conf);
    if (!got_skip) {
        /*
         * Since skip name service not used for hosts, we do not need
         * to install our private address resolution function
         */
        (void) mutex_unlock(&db_root_hosts.lock);
        if (name_list != NULL)
            free(name_list);
        return (0);
    }
    if (host_service != NULL)
        free(host_service);
    host_service = name_list;
    (void) mutex_unlock(&db_root_hosts.lock);

    if (ldap_get_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0)
        return (-1);
    dns_fns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
    dns_fns.lddnsfn_gethostbyname = prldap_gethostbyname1;
    if (ldap_set_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0)
        return (-1);
    return (0);
}
Beispiel #19
0
DWORD
VMCALdapConnect(
    PSTR   pszHostName,
    DWORD  dwPort,
    PSTR   pszUsername,
    PSTR   pszPassword,
    PVMCA_LDAP_CONTEXT* ppLotus
    )
{

    DWORD dwError = 0;
    PVMCA_LDAP_CONTEXT pContext = NULL;
    PSTR pszUrl = NULL;
    BerValue ldapBindPwd = {0};

//LDAP_SUCCESS is defined as Zero in the Standard
// Which plays well with our BAIL_ON_ERROR macro

    DWORD dwVersion = LDAP_VERSION3;
    DWORD dwReturns = 20;


    if(dwPort == 0) {
        // Let us use the default LDAP_PORT, 389
        dwPort = LDAP_PORT;
    }

    dwError = VMCAAllocateMemory(sizeof(*pContext), (PVOID*)&pContext);
    BAIL_ON_ERROR(dwError);

    if (VMCAIsIPV6AddrFormat(pszHostName))
    {
        dwError = VMCAAllocateStringPrintfA(
                    &pszUrl,
                    "ldap://[%s]:%d",
                    pszHostName,
                    dwPort);
    }
    else
    {
        dwError = VMCAAllocateStringPrintfA(
                    &pszUrl,
                    "ldap://%s:%d",
                    pszHostName,
                    dwPort);
    }
    BAIL_ON_ERROR(dwError);

    if(IsNullOrEmptyString(pszPassword))
    {   // no credentials, do anonymous bind.
        dwError =  ldap_initialize(&pContext->pConnection, pszUrl);
        BAIL_ON_ERROR(dwError);

        if (pContext->pConnection == NULL) {
            ldap_get_option(pContext->pConnection, LDAP_OPT_ERROR_NUMBER, &dwError);
            //dwError = ld_errno; //LdapGetLastError();
            BAIL_ON_ERROR(dwError);
        }

        dwError = ldap_set_option(pContext->pConnection,
                                  LDAP_OPT_PROTOCOL_VERSION,
                                  (void*)&dwVersion);
        BAIL_ON_ERROR(dwError);

        dwError = ldap_set_option(pContext->pConnection,
                                  LDAP_OPT_SIZELIMIT,
                                  (void*)& dwReturns);
        BAIL_ON_ERROR(dwError);

        dwError = ldap_sasl_bind_s(
                    pContext->pConnection,
                    pszUsername,
                    LDAP_SASL_SIMPLE,
                    &ldapBindPwd,  // no credentials
                    NULL,
                    NULL,
                    NULL);
    }
    else
    {
        dwError = VmCASASLSRPBind(
                    &pContext->pConnection,
                    pszUrl,
                    pszUsername,
                    pszPassword);
    }

#ifdef LDAP_ERROR_MESSAGE
    if(dwError != 0) {
        printf("Error :%s\n",ldap_err2string(dwError));
    }
#endif
    BAIL_ON_ERROR(dwError);

    *ppLotus = pContext;

cleanup:
    VMCA_SAFE_FREE_STRINGA(pszUrl);
    return dwError;

error:
    if ((dwError != 0) && pContext)
    {
        VMCALdapClose(pContext);
    }
    goto cleanup;
}
static int
ldap_back_exop_passwd(
	Operation	*op,
	SlapReply	*rs,
	ldapconn_t	**lcp )
{
	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;

	ldapconn_t	*lc = *lcp;
	req_pwdexop_s	*qpw = &op->oq_pwdexop;
	LDAPMessage	*res;
	ber_int_t	msgid;
	int		rc, isproxy, freedn = 0;
	int		do_retry = 1;
	char		*text = NULL;
	struct berval	dn = op->o_req_dn,
			ndn = op->o_req_ndn;

	assert( lc != NULL );
	assert( rs->sr_ctrls == NULL );

	if ( BER_BVISNULL( &ndn ) && op->ore_reqdata != NULL ) {
		/* NOTE: most of this code is mutated
		 * from slap_passwd_parse();
		 * But here we only need
		 * the first berval... */

		ber_tag_t tag;
		ber_len_t len = -1;
		BerElementBuffer berbuf;
		BerElement *ber = (BerElement *)&berbuf;

		struct berval	tmpid = BER_BVNULL;

		if ( op->ore_reqdata->bv_len == 0 ) {
			return LDAP_PROTOCOL_ERROR;
		}

		/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
		ber_init2( ber, op->ore_reqdata, 0 );

		tag = ber_scanf( ber, "{" /*}*/ );

		if ( tag == LBER_ERROR ) {
			return LDAP_PROTOCOL_ERROR;
		}

		tag = ber_peek_tag( ber, &len );
		if ( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_ID ) {
			tag = ber_get_stringbv( ber, &tmpid, LBER_BV_NOTERM );

			if ( tag == LBER_ERROR ) {
				return LDAP_PROTOCOL_ERROR;
			}
		}

		if ( !BER_BVISEMPTY( &tmpid ) ) {
			char idNull = tmpid.bv_val[tmpid.bv_len];
			tmpid.bv_val[tmpid.bv_len] = '\0';
			rs->sr_err = dnPrettyNormal( NULL, &tmpid, &dn,
				&ndn, op->o_tmpmemctx );
			tmpid.bv_val[tmpid.bv_len] = idNull;
			if ( rs->sr_err != LDAP_SUCCESS ) {
				/* should have been successfully parsed earlier! */
				return rs->sr_err;
			}
			freedn = 1;

		} else {
			dn = op->o_dn;
			ndn = op->o_ndn;
		}
	}

	isproxy = ber_bvcmp( &ndn, &op->o_ndn );

	Debug( LDAP_DEBUG_ARGS, "==> ldap_back_exop_passwd(\"%s\")%s\n",
		dn.bv_val, isproxy ? " (proxy)" : "", 0 );

retry:
	rc = ldap_passwd( lc->lc_ld, isproxy ? &dn : NULL,
		qpw->rs_old.bv_val ? &qpw->rs_old : NULL,
		qpw->rs_new.bv_val ? &qpw->rs_new : NULL,
		op->o_ctrls, NULL, &msgid );

	if ( rc == LDAP_SUCCESS ) {
		/* TODO: set timeout? */
		if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) {
			ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc );
			rs->sr_err = rc;

		} else {
			/* only touch when activity actually took place... */
			if ( li->li_idle_timeout && lc ) {
				lc->lc_time = op->o_time;
			}

			/* sigh. parse twice, because parse_passwd
			 * doesn't give us the err / match / msg info.
			 */
			rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
					(char **)&rs->sr_matched,
					&text,
					NULL, &rs->sr_ctrls, 0 );

			if ( rc == LDAP_SUCCESS ) {
				if ( rs->sr_err == LDAP_SUCCESS ) {
					struct berval	newpw;

					/* this never happens because 
					 * the frontend	is generating 
					 * the new password, so when
					 * the passwd exop is proxied,
					 * it never delegates password
					 * generation to the remote server
					 */
					rc = ldap_parse_passwd( lc->lc_ld, res,
							&newpw );
					if ( rc == LDAP_SUCCESS &&
							!BER_BVISNULL( &newpw ) )
					{
						rs->sr_type = REP_EXTENDED;
						rs->sr_rspdata = slap_passwd_return( &newpw );
						free( newpw.bv_val );
					}

				} else {
					rc = rs->sr_err;
				}
			}
			ldap_msgfree( res );
		}
	}

	if ( rc != LDAP_SUCCESS ) {
		rs->sr_err = slap_map_api2result( rs );
		if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
			do_retry = 0;
			if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
				goto retry;
			}
		}

		if ( LDAP_BACK_QUARANTINE( li ) ) {
			ldap_back_quarantine( op, rs );
		}

		if ( text ) rs->sr_text = text;
		send_ldap_extended( op, rs );
		/* otherwise frontend resends result */
		rc = rs->sr_err = SLAPD_ABANDON;

	} else if ( LDAP_BACK_QUARANTINE( li ) ) {
		ldap_back_quarantine( op, rs );
	}

	if ( freedn ) {
		op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
		op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
	}

	/* these have to be freed anyway... */
	if ( rs->sr_matched ) {
		free( (char *)rs->sr_matched );
		rs->sr_matched = NULL;
	}

	if ( rs->sr_ctrls ) {
		ldap_controls_free( rs->sr_ctrls );
		rs->sr_ctrls = NULL;
	}

	if ( text ) {
		free( text );
		rs->sr_text = NULL;
	}

	/* in case, cleanup handler */
	if ( lc == NULL ) {
		*lcp = NULL;
	}

	return rc;
}
Beispiel #21
0
static int ipa_ldap_bind(const char *server_name, krb5_principal bind_princ,
			 const char *bind_dn, const char *bind_pw, LDAP **_ld)
{
    char *msg = NULL;
    struct berval bv;
    int version;
    LDAP *ld;
    int ssl;
    int ret;

    /* TODO: support referrals ? */
    if (bind_dn) {
        ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ca_cert_file);
        if (ret != LDAP_OPT_SUCCESS) {
            fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS_CERTIFICATE\n"));
            return ret;
        }

        ret = ipa_ldap_init(&ld, "ldaps", server_name, 636);
        if (ret != LDAP_SUCCESS) {
            fprintf(stderr, _("Unable to init for ldaps(636) connection\n"));
            return ret;
        }

        ssl = LDAP_OPT_X_TLS_HARD;;
        ret = ldap_set_option(ld, LDAP_OPT_X_TLS, &ssl);
        if (ret != LDAP_OPT_SUCCESS) {
            fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS\n"));
            goto done;
        }
    } else {
        ret = ipa_ldap_init(&ld, "ldap", server_name, 389);
        if (ret != LDAP_SUCCESS) {
            fprintf(stderr, _("Unable to init for ldap(389) connection\n"));
            return ret;
        }
    }

    if (ld == NULL) {
        fprintf(stderr, _("Unable to initialize ldap library!\n"));
        return LDAP_OPERATIONS_ERROR;
    }

#ifdef LDAP_OPT_X_SASL_NOCANON
    /* Don't do DNS canonicalization */
    ret = ldap_set_option(ld, LDAP_OPT_X_SASL_NOCANON, LDAP_OPT_ON);
    if (ret != LDAP_SUCCESS) {
	fprintf(stderr, _("Unable to set LDAP_OPT_X_SASL_NOCANON\n"));
        goto done;
    }
#endif

    version = LDAP_VERSION3;
    ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
    if (ret != LDAP_SUCCESS) {
	fprintf(stderr, _("Unable to set LDAP_OPT_PROTOCOL_VERSION\n"));
	goto done;
    }

    if (bind_dn) {
        bv.bv_val = discard_const(bind_pw);
        bv.bv_len = strlen(bind_pw);

        ret = ldap_sasl_bind_s(ld, bind_dn, LDAP_SASL_SIMPLE,
                               &bv, NULL, NULL, NULL);
        if (ret != LDAP_SUCCESS) {
            fprintf(stderr, _("Simple bind failed\n"));
            goto done;
        }
    } else {
        ret = ldap_sasl_interactive_bind_s(ld, NULL, "GSSAPI",
                                           NULL, NULL, LDAP_SASL_QUIET,
                                           ldap_sasl_interact, bind_princ);
        if (ret != LDAP_SUCCESS) {
#ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE
            ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&msg);
#endif
            fprintf(stderr, "SASL Bind failed %s (%d) %s!\n",
                            ldap_err2string(ret), ret, msg ? msg : "");
            goto done;
        }
    }

    ret = LDAP_SUCCESS;

done:
    if (ret != LDAP_SUCCESS) {
        if (ld) ldap_unbind_ext(ld, NULL, NULL);
    } else {
        *_ld = ld;
    }
    return ret;
}
static int
ldap_back_exop_generic(
	Operation	*op,
	SlapReply	*rs,
	ldapconn_t	**lcp )
{
	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;

	ldapconn_t	*lc = *lcp;
	LDAPMessage	*res;
	ber_int_t	msgid;
	int		rc;
	int		do_retry = 1;
	char		*text = NULL;

	assert( lc != NULL );
	assert( rs->sr_ctrls == NULL );

	Debug( LDAP_DEBUG_ARGS, "==> ldap_back_exop_generic(%s, \"%s\")\n",
		op->ore_reqoid.bv_val, op->o_req_dn.bv_val, 0 );

retry:
	rc = ldap_extended_operation( lc->lc_ld,
		op->ore_reqoid.bv_val, op->ore_reqdata,
		op->o_ctrls, NULL, &msgid );

	if ( rc == LDAP_SUCCESS ) {
		/* TODO: set timeout? */
		if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) {
			ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc );
			rs->sr_err = rc;

		} else {
			/* only touch when activity actually took place... */
			if ( li->li_idle_timeout && lc ) {
				lc->lc_time = op->o_time;
			}

			/* sigh. parse twice, because parse_passwd
			 * doesn't give us the err / match / msg info.
			 */
			rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
					(char **)&rs->sr_matched,
					&text,
					NULL, &rs->sr_ctrls, 0 );
			if ( rc == LDAP_SUCCESS ) {
				if ( rs->sr_err == LDAP_SUCCESS ) {
					rc = ldap_parse_extended_result( lc->lc_ld, res,
							(char **)&rs->sr_rspoid, &rs->sr_rspdata, 0 );
					if ( rc == LDAP_SUCCESS ) {
						rs->sr_type = REP_EXTENDED;
					}

				} else {
					rc = rs->sr_err;
				}
			}
			ldap_msgfree( res );
		}
	}

	if ( rc != LDAP_SUCCESS ) {
		rs->sr_err = slap_map_api2result( rs );
		if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
			do_retry = 0;
			if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
				goto retry;
			}
		}

		if ( LDAP_BACK_QUARANTINE( li ) ) {
			ldap_back_quarantine( op, rs );
		}

		if ( text ) rs->sr_text = text;
		send_ldap_extended( op, rs );
		/* otherwise frontend resends result */
		rc = rs->sr_err = SLAPD_ABANDON;

	} else if ( LDAP_BACK_QUARANTINE( li ) ) {
		ldap_back_quarantine( op, rs );
	}

	/* these have to be freed anyway... */
	if ( rs->sr_matched ) {
		free( (char *)rs->sr_matched );
		rs->sr_matched = NULL;
	}

	if ( rs->sr_ctrls ) {
		ldap_controls_free( rs->sr_ctrls );
		rs->sr_ctrls = NULL;
	}

	if ( text ) {
		free( text );
		rs->sr_text = NULL;
	}

	/* in case, cleanup handler */
	if ( lc == NULL ) {
		*lcp = NULL;
	}

	return rc;
}
Beispiel #23
0
Datei: ldap.c Projekt: fanf2/exim
static int
perform_ldap_search(uschar *ldap_url, uschar *server, int s_port, int search_type,
  uschar **res, uschar **errmsg, BOOL *defer_break, uschar *user, uschar *password,
  int sizelimit, int timelimit, int tcplimit, int dereference, void *referrals)
{
LDAPURLDesc     *ludp = NULL;
LDAPMessage     *result = NULL;
BerElement      *ber;
LDAP_CONNECTION *lcp;

struct timeval timeout;
struct timeval *timeoutptr = NULL;

uschar *attr;
uschar **attrp;
uschar *data = NULL;
uschar *dn = NULL;
uschar *host;
uschar **values;
uschar **firstval;
uschar porttext[16];

uschar *error1 = NULL;   /* string representation of errcode (static) */
uschar *error2 = NULL;   /* error message from the server */
uschar *matched = NULL;  /* partially matched DN */

int    attr_count = 0;
int    error_yield = DEFER;
int    msgid;
int    rc, ldap_rc, ldap_parse_rc;
int    port;
int    ptr = 0;
int    rescount = 0;
int    size = 0;
BOOL   attribute_found = FALSE;
BOOL   ldapi = FALSE;

DEBUG(D_lookup)
  debug_printf("perform_ldap_search: ldap%s URL = \"%s\" server=%s port=%d "
    "sizelimit=%d timelimit=%d tcplimit=%d\n",
    (search_type == SEARCH_LDAP_MULTIPLE)? "m" :
    (search_type == SEARCH_LDAP_DN)? "dn" :
    (search_type == SEARCH_LDAP_AUTH)? "auth" : "",
    ldap_url, server, s_port, sizelimit, timelimit, tcplimit);

/* Check if LDAP thinks the URL is a valid LDAP URL. We assume that if the LDAP
library that is in use doesn't recognize, say, "ldapi", it will barf here. */

if (!ldap_is_ldap_url(CS ldap_url))
  {
  *errmsg = string_sprintf("ldap_is_ldap_url: not an LDAP url \"%s\"\n",
    ldap_url);
  goto RETURN_ERROR_BREAK;
  }

/* Parse the URL */

if ((rc = ldap_url_parse(CS ldap_url, &ludp)) != 0)
  {
  *errmsg = string_sprintf("ldap_url_parse: (error %d) parsing \"%s\"\n", rc,
    ldap_url);
  goto RETURN_ERROR_BREAK;
  }

/* If the host name is empty, take it from the separate argument, if one is
given. OpenLDAP 2.0.6 sets an unset hostname to "" rather than empty, but
expects NULL later in ldap_init() to mean "default", annoyingly. In OpenLDAP
2.0.11 this has changed (it uses NULL). */

if ((ludp->lud_host == NULL || ludp->lud_host[0] == 0) && server != NULL)
  {
  host = server;
  port = s_port;
  }
else
  {
  host = US ludp->lud_host;
  if (host != NULL && host[0] == 0) host = NULL;
  port = ludp->lud_port;
  }

DEBUG(D_lookup) debug_printf("after ldap_url_parse: host=%s port=%d\n",
  host, port);

if (port == 0) port = LDAP_PORT;      /* Default if none given */
sprintf(CS porttext, ":%d", port);    /* For messages */

/* If the "host name" is actually a path, we are going to connect using a Unix
socket, regardless of whether "ldapi" was actually specified or not. This means
that a Unix socket can be declared in eldap_default_servers, and "traditional"
LDAP queries using just "ldap" can be used ("ldaps" is similarly overridden).
The path may start with "/" or it may already be escaped as "%2F" if it was
actually declared that way in eldap_default_servers. (I did it that way the
first time.) If the host name is not a path, the use of "ldapi" causes an
error, except in the default case. (But lud_scheme doesn't seem to exist in
older libraries.) */

if (host != NULL)
  {
  if ((host[0] == '/' || Ustrncmp(host, "%2F", 3) == 0))
    {
    ldapi = TRUE;
    porttext[0] = 0;    /* Remove port from messages */
    }

  #if defined LDAP_LIB_OPENLDAP2
  else if (strncmp(ludp->lud_scheme, "ldapi", 5) == 0)
    {
    *errmsg = string_sprintf("ldapi requires an absolute path (\"%s\" given)",
      host);
    goto RETURN_ERROR;
    }
  #endif
  }

/* Count the attributes; we need this later to tell us how to format results */

for (attrp = USS ludp->lud_attrs; attrp != NULL && *attrp != NULL; attrp++)
  attr_count++;

/* See if we can find a cached connection to this host. The port is not
relevant for ldapi. The host name pointer is set to NULL if no host was given
(implying the library default), rather than to the empty string. Note that in
this case, there is no difference between ldap and ldapi. */

for (lcp = ldap_connections; lcp != NULL; lcp = lcp->next)
  {
  if ((host == NULL) != (lcp->host == NULL) ||
      (host != NULL && strcmpic(lcp->host, host) != 0))
    continue;
  if (ldapi || port == lcp->port) break;
  }

/* Use this network timeout in any requests. */

if (tcplimit > 0)
  {
  timeout.tv_sec = tcplimit;
  timeout.tv_usec = 0;
  timeoutptr = &timeout;
  }

/* If no cached connection found, we must open a connection to the server. If
the server name is actually an absolute path, we set ldapi=TRUE above. This
requests connection via a Unix socket. However, as far as I know, only OpenLDAP
supports the use of sockets, and the use of ldap_initialize(). */

if (lcp == NULL)
  {
  LDAP *ld;


  /* --------------------------- OpenLDAP ------------------------ */

  /* There seems to be a preference under OpenLDAP for ldap_initialize()
  instead of ldap_init(), though I have as yet been unable to find
  documentation that says this. (OpenLDAP documentation is sparse to
  non-existent). So we handle OpenLDAP differently here. Also, support for
  ldapi seems to be OpenLDAP-only at present. */

  #ifdef LDAP_LIB_OPENLDAP2

  /* We now need an empty string for the default host. Get some store in which
  to build a URL for ldap_initialize(). In the ldapi case, it can't be bigger
  than (9 + 3*Ustrlen(shost)), whereas in the other cases it can't be bigger
  than the host name + "ldaps:///" plus : and a port number, say 20 + the
  length of the host name. What we get should accommodate both, easily. */

  uschar *shost = (host == NULL)? US"" : host;
  uschar *init_url = store_get(20 + 3 * Ustrlen(shost));
  uschar *init_ptr;

  /* Handle connection via Unix socket ("ldapi"). We build a basic LDAP URI to
  contain the path name, with slashes escaped as %2F. */

  if (ldapi)
    {
    int ch;
    init_ptr = init_url + 8;
    Ustrcpy(init_url, "ldapi://");
    while ((ch = *shost++) != 0)
      {
      if (ch == '/')
        {
        Ustrncpy(init_ptr, "%2F", 3);
        init_ptr += 3;
        }
      else *init_ptr++ = ch;
      }
    *init_ptr = 0;
    }

  /* This is not an ldapi call. Just build a URI with the protocol type, host
  name, and port. */

  else
    {
    init_ptr = Ustrchr(ldap_url, '/');
    Ustrncpy(init_url, ldap_url, init_ptr - ldap_url);
    init_ptr = init_url + (init_ptr - ldap_url);
    sprintf(CS init_ptr, "//%s:%d/", shost, port);
    }

  /* Call ldap_initialize() and check the result */

  DEBUG(D_lookup) debug_printf("ldap_initialize with URL %s\n", init_url);
  rc = ldap_initialize(&ld, CS init_url);
  if (rc != LDAP_SUCCESS)
    {
    *errmsg = string_sprintf("ldap_initialize: (error %d) URL \"%s\"\n",
      rc, init_url);
    goto RETURN_ERROR;
    }
  store_reset(init_url);   /* Might as well save memory when we can */


  /* ------------------------- Not OpenLDAP ---------------------- */

  /* For libraries other than OpenLDAP, use ldap_init(). */

  #else   /* LDAP_LIB_OPENLDAP2 */
  ld = ldap_init(CS host, port);
  #endif  /* LDAP_LIB_OPENLDAP2 */

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


  /* Handle failure to initialize */

  if (ld == NULL)
    {
    *errmsg = string_sprintf("failed to initialize for LDAP server %s%s - %s",
      host, porttext, strerror(errno));
    goto RETURN_ERROR;
    }

  /* Set the TCP connect time limit if available. This is something that is
  in Netscape SDK v4.1; I don't know about other libraries. */

  #ifdef LDAP_X_OPT_CONNECT_TIMEOUT
  if (tcplimit > 0)
    {
    int timeout1000 = tcplimit*1000;
    ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&timeout1000);
    }
  else
    {
    int notimeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
    ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&notimeout);
    }
  #endif

  /* Set the TCP connect timeout. This works with OpenLDAP 2.2.14. */

  #ifdef LDAP_OPT_NETWORK_TIMEOUT
  if (tcplimit > 0)
    ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *)timeoutptr);
  #endif

  /* I could not get TLS to work until I set the version to 3. That version
  seems to be the default nowadays. The RFC is dated 1997, so I would hope
  that all the LDAP libraries support it. Therefore, if eldap_version hasn't
  been set, go for v3 if we can. */

  if (eldap_version < 0)
    {
    #ifdef LDAP_VERSION3
    eldap_version = LDAP_VERSION3;
    #else
    eldap_version = 2;
    #endif
    }

  #ifdef LDAP_OPT_PROTOCOL_VERSION
  ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void *)&eldap_version);
  #endif

  DEBUG(D_lookup) debug_printf("initialized for LDAP (v%d) server %s%s\n",
    eldap_version, host, porttext);

  /* If not using ldapi and TLS is available, set appropriate TLS options: hard
  for "ldaps" and soft otherwise. */

  #ifdef LDAP_OPT_X_TLS
  if (!ldapi)
    {
    int tls_option;
    if (strncmp(ludp->lud_scheme, "ldaps", 5) == 0)
      {
      tls_option = LDAP_OPT_X_TLS_HARD;
      DEBUG(D_lookup) debug_printf("LDAP_OPT_X_TLS_HARD set\n");
      }
    else
      {
      tls_option = LDAP_OPT_X_TLS_TRY;
      DEBUG(D_lookup) debug_printf("LDAP_OPT_X_TLS_TRY set\n");
      }
    ldap_set_option(ld, LDAP_OPT_X_TLS, (void *)&tls_option);
    }
  #endif  /* LDAP_OPT_X_TLS */

  #ifdef LDAP_OPT_X_TLS_CACERTFILE
  if (eldap_ca_cert_file != NULL)
    {
    ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, eldap_ca_cert_file);
    }
  #endif
  #ifdef LDAP_OPT_X_TLS_CACERTDIR
  if (eldap_ca_cert_dir != NULL)
    {
    ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTDIR, eldap_ca_cert_dir);
    }
  #endif
  #ifdef LDAP_OPT_X_TLS_CERTFILE
  if (eldap_cert_file != NULL)
    {
    ldap_set_option(ld, LDAP_OPT_X_TLS_CERTFILE, eldap_cert_file);
    }
  #endif
  #ifdef LDAP_OPT_X_TLS_KEYFILE
  if (eldap_cert_key != NULL)
    {
    ldap_set_option(ld, LDAP_OPT_X_TLS_KEYFILE, eldap_cert_key);
    }
  #endif
  #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
  if (eldap_cipher_suite != NULL)
    {
    ldap_set_option(ld, LDAP_OPT_X_TLS_CIPHER_SUITE, eldap_cipher_suite);
    }
  #endif
  #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
  if (eldap_require_cert != NULL)
    {
    int cert_option = LDAP_OPT_X_TLS_NEVER;
    if (Ustrcmp(eldap_require_cert, "hard") == 0)
      {
      cert_option = LDAP_OPT_X_TLS_HARD;
      }
    else if (Ustrcmp(eldap_require_cert, "demand") == 0)
      {
      cert_option = LDAP_OPT_X_TLS_DEMAND;
      }
    else if (Ustrcmp(eldap_require_cert, "allow") == 0)
      {
      cert_option = LDAP_OPT_X_TLS_ALLOW;
      }
    else if (Ustrcmp(eldap_require_cert, "try") == 0)
      {
      cert_option = LDAP_OPT_X_TLS_TRY;
      }
    ldap_set_option(ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &cert_option);
    }
  #endif

  /* Now add this connection to the chain of cached connections */

  lcp = store_get(sizeof(LDAP_CONNECTION));
  lcp->host = (host == NULL)? NULL : string_copy(host);
  lcp->bound = FALSE;
  lcp->user = NULL;
  lcp->password = NULL;
  lcp->port = port;
  lcp->ld = ld;
  lcp->next = ldap_connections;
  ldap_connections = lcp;
  }

/* Found cached connection */

else
  {
  DEBUG(D_lookup)
    debug_printf("re-using cached connection to LDAP server %s%s\n",
      host, porttext);
  }

/* Bind with the user/password supplied, or an anonymous bind if these values
are NULL, unless a cached connection is already bound with the same values. */

if (!lcp->bound ||
    (lcp->user == NULL && user != NULL) ||
    (lcp->user != NULL && user == NULL) ||
    (lcp->user != NULL && user != NULL && Ustrcmp(lcp->user, user) != 0) ||
    (lcp->password == NULL && password != NULL) ||
    (lcp->password != NULL && password == NULL) ||
    (lcp->password != NULL && password != NULL &&
      Ustrcmp(lcp->password, password) != 0))
  {
  DEBUG(D_lookup) debug_printf("%sbinding with user=%s password=%s\n",
    (lcp->bound)? "re-" : "", user, password);
#ifdef LDAP_OPT_X_TLS
  /* The Oracle LDAP libraries (LDAP_LIB_TYPE=SOLARIS) don't support this: */
  if (eldap_start_tls)
    {
    ldap_start_tls_s(lcp->ld, NULL, NULL);
    }
#endif
  if ((msgid = ldap_bind(lcp->ld, CS user, CS password, LDAP_AUTH_SIMPLE))
       == -1)
    {
    *errmsg = string_sprintf("failed to bind the LDAP connection to server "
      "%s%s - ldap_bind() returned -1", host, porttext);
    goto RETURN_ERROR;
    }

  if ((rc = ldap_result( lcp->ld, msgid, 1, timeoutptr, &result )) <= 0)
    {
    *errmsg = string_sprintf("failed to bind the LDAP connection to server "
      "%s%s - LDAP error: %s", host, porttext,
      rc == -1 ? "result retrieval failed" : "timeout" );
    result = NULL;
    goto RETURN_ERROR;
    }

  rc = ldap_result2error( lcp->ld, result, 0 );

  /* Invalid credentials when just checking credentials returns FAIL. This
  stops any further servers being tried. */

  if (search_type == SEARCH_LDAP_AUTH && rc == LDAP_INVALID_CREDENTIALS)
    {
    DEBUG(D_lookup)
      debug_printf("Invalid credentials: ldapauth returns FAIL\n");
    error_yield = FAIL;
    goto RETURN_ERROR_NOMSG;
    }

  /* Otherwise we have a problem that doesn't stop further servers from being
  tried. */

  if (rc != LDAP_SUCCESS)
    {
    *errmsg = string_sprintf("failed to bind the LDAP connection to server "
      "%s%s - LDAP error %d: %s", host, porttext, rc, ldap_err2string(rc));
    goto RETURN_ERROR;
    }

  /* Successful bind */

  lcp->bound = TRUE;
  lcp->user = (user == NULL)? NULL : string_copy(user);
  lcp->password = (password == NULL)? NULL : string_copy(password);

  ldap_msgfree(result);
  result = NULL;
  }

/* If we are just checking credentials, return OK. */

if (search_type == SEARCH_LDAP_AUTH)
  {
  DEBUG(D_lookup) debug_printf("Bind succeeded: ldapauth returns OK\n");
  goto RETURN_OK;
  }

/* Before doing the search, set the time and size limits (if given). Here again
the different implementations of LDAP have chosen to do things differently. */

#if defined(LDAP_OPT_SIZELIMIT)
ldap_set_option(lcp->ld, LDAP_OPT_SIZELIMIT, (void *)&sizelimit);
ldap_set_option(lcp->ld, LDAP_OPT_TIMELIMIT, (void *)&timelimit);
#else
lcp->ld->ld_sizelimit = sizelimit;
lcp->ld->ld_timelimit = timelimit;
#endif

/* Similarly for dereferencing aliases. Don't know if this is possible on
an LDAP library without LDAP_OPT_DEREF. */

#if defined(LDAP_OPT_DEREF)
ldap_set_option(lcp->ld, LDAP_OPT_DEREF, (void *)&dereference);
#endif

/* Similarly for the referral setting; should the library follow referrals that
the LDAP server returns? The conditional is just in case someone uses a library
without it. */

#if defined(LDAP_OPT_REFERRALS)
ldap_set_option(lcp->ld, LDAP_OPT_REFERRALS, referrals);
#endif

/* Start the search on the server. */

DEBUG(D_lookup) debug_printf("Start search\n");

msgid = ldap_search(lcp->ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter,
  ludp->lud_attrs, 0);

if (msgid == -1)
  {
  #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2
  int err;
  ldap_get_option(lcp->ld, LDAP_OPT_ERROR_NUMBER, &err);
  *errmsg = string_sprintf("ldap_search failed: %d, %s", err,
    ldap_err2string(err));

  #else
  *errmsg = string_sprintf("ldap_search failed");
  #endif

  goto RETURN_ERROR;
  }

/* Loop to pick up results as they come in, setting a timeout if one was
given. */

while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) ==
        LDAP_RES_SEARCH_ENTRY)
  {
  LDAPMessage  *e;

  DEBUG(D_lookup) debug_printf("ldap_result loop\n");

  for(e = ldap_first_entry(lcp->ld, result);
      e != NULL;
      e = ldap_next_entry(lcp->ld, e))
    {
    uschar *new_dn;
    BOOL insert_space = FALSE;

    DEBUG(D_lookup) debug_printf("LDAP entry loop\n");

    rescount++;   /* Count results */

    /* Results for multiple entries values are separated by newlines. */

    if (data != NULL) data = string_cat(data, &size, &ptr, US"\n", 1);

    /* Get the DN from the last result. */

    new_dn = US ldap_get_dn(lcp->ld, e);
    if (new_dn != NULL)
      {
      if (dn != NULL)
        {
        #if defined LDAP_LIB_NETSCAPE || defined LDAP_LIB_OPENLDAP2
        ldap_memfree(dn);
        #else   /* OPENLDAP 1, UMich, Solaris */
        free(dn);
        #endif
        }
      /* Save for later */
      dn = new_dn;
      }

    /* If the data we want is actually the DN rather than any attribute values,
    (an "ldapdn" search) add it to the data string. If there are multiple
    entries, the DNs will be concatenated, but we test for this case below, as
    for SEARCH_LDAP_SINGLE, and give an error. */

    if (search_type == SEARCH_LDAP_DN)   /* Do not amalgamate these into one */
      {                                  /* condition, because of the else */
      if (new_dn != NULL)                /* below, that's for the first only */
        {
        data = string_cat(data, &size, &ptr, new_dn, Ustrlen(new_dn));
        data[ptr] = 0;
        attribute_found = TRUE;
        }
      }

    /* Otherwise, loop through the entry, grabbing attribute values. If there's
    only one attribute being retrieved, no attribute name is given, and the
    result is not quoted. Multiple values are separated by (comma, space).
    If more than one attribute is being retrieved, the data is given as a
    sequence of name=value pairs, with the value always in quotes. If there are
    multiple values, they are given within the quotes, comma separated. */

    else for (attr = US ldap_first_attribute(lcp->ld, e, &ber);
              attr != NULL;
              attr = US ldap_next_attribute(lcp->ld, e, ber))
      {
      if (attr[0] != 0)
        {
        /* Get array of values for this attribute. */

        if ((firstval = values = USS ldap_get_values(lcp->ld, e, CS attr))
             != NULL)
          {
          if (attr_count != 1)
            {
            if (insert_space)
              data = string_cat(data, &size, &ptr, US" ", 1);
            else
              insert_space = TRUE;
            data = string_cat(data, &size, &ptr, attr, Ustrlen(attr));
            data = string_cat(data, &size, &ptr, US"=\"", 2);
            }

          while (*values != NULL)
            {
            uschar *value = *values;
            int len = Ustrlen(value);

            DEBUG(D_lookup) debug_printf("LDAP attr loop %s:%s\n", attr, value);

            if (values != firstval)
              data = string_cat(data, &size, &ptr, US", ", 2);

            /* For multiple attributes, the data is in quotes. We must escape
            internal quotes, backslashes, newlines. */

            if (attr_count != 1)
              {
              int j;
              for (j = 0; j < len; j++)
                {
                if (value[j] == '\n')
                  data = string_cat(data, &size, &ptr, US"\\n", 2);
                else
                  {
                  if (value[j] == '\"' || value[j] == '\\')
                    data = string_cat(data, &size, &ptr, US"\\", 1);
                  data = string_cat(data, &size, &ptr, value+j, 1);
                  }
                }
              }

            /* For single attributes, copy the value verbatim */

            else data = string_cat(data, &size, &ptr, value, len);

            /* Move on to the next value */

            values++;
            attribute_found = TRUE;
            }

          /* Closing quote at the end of the data for a named attribute. */

          if (attr_count != 1)
            data = string_cat(data, &size, &ptr, US"\"", 1);

          /* Free the values */

          ldap_value_free(CSS firstval);
          }
        }

      #if defined LDAP_LIB_NETSCAPE || defined LDAP_LIB_OPENLDAP2

      /* Netscape and OpenLDAP2 LDAP's attrs are dynamically allocated and need
      to be freed. UMich LDAP stores them in static storage and does not require
      this. */

      ldap_memfree(attr);
      #endif
      }        /* End "for" loop for extracting attributes from an entry */
    }          /* End "for" loop for extracting entries from a result */

  /* Free the result */

  ldap_msgfree(result);
  result = NULL;
  }            /* End "while" loop for multiple results */

/* Terminate the dynamic string that we have built and reclaim unused store */

if (data != NULL)
  {
  data[ptr] = 0;
  store_reset(data + ptr + 1);
  }

/* Copy the last dn into eldap_dn */

if (dn != NULL)
  {
  eldap_dn = string_copy(dn);
  #if defined LDAP_LIB_NETSCAPE || defined LDAP_LIB_OPENLDAP2
  ldap_memfree(dn);
  #else   /* OPENLDAP 1, UMich, Solaris */
  free(dn);
  #endif
  }

DEBUG(D_lookup) debug_printf("search ended by ldap_result yielding %d\n",rc);

if (rc == 0)
  {
  *errmsg = US"ldap_result timed out";
  goto RETURN_ERROR;
  }

/* A return code of -1 seems to mean "ldap_result failed internally or couldn't
provide you with a message". Other error states seem to exist where
ldap_result() didn't give us any message from the server at all, leaving result
set to NULL. Apparently, "the error parameters of the LDAP session handle will
be set accordingly". That's the best we can do to retrieve an error status; we
can't use functions like ldap_result2error because they parse a message from
the server, which we didn't get.

Annoyingly, the different implementations of LDAP have gone for different
methods of handling error codes and generating error messages. */

if (rc == -1 || result == NULL)
  {
  int err;
  DEBUG(D_lookup) debug_printf("ldap_result failed\n");

  #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2
    ldap_get_option(lcp->ld, LDAP_OPT_ERROR_NUMBER, &err);
    *errmsg = string_sprintf("ldap_result failed: %d, %s",
      err, ldap_err2string(err));

  #elif defined LDAP_LIB_NETSCAPE
    /* Dubious (surely 'matched' is spurious here?) */
    (void)ldap_get_lderrno(lcp->ld, &matched, &error1);
    *errmsg = string_sprintf("ldap_result failed: %s (%s)", error1, matched);

  #else                             /* UMich LDAP aka OpenLDAP 1.x */
    *errmsg = string_sprintf("ldap_result failed: %d, %s",
      lcp->ld->ld_errno, ldap_err2string(lcp->ld->ld_errno));
  #endif

  goto RETURN_ERROR;
  }

/* A return code that isn't -1 doesn't necessarily mean there were no problems
with the search. The message must be an LDAP_RES_SEARCH_RESULT or
LDAP_RES_SEARCH_REFERENCE or else it's something we can't handle. Some versions
of LDAP do not define LDAP_RES_SEARCH_REFERENCE (LDAP v1 is one, it seems). So
we don't provide that functionality when we can't. :-) */

if (rc != LDAP_RES_SEARCH_RESULT
#ifdef LDAP_RES_SEARCH_REFERENCE
    && rc != LDAP_RES_SEARCH_REFERENCE
#endif
   )
  {
  *errmsg = string_sprintf("ldap_result returned unexpected code %d", rc);
  goto RETURN_ERROR;
  }

/* We have a result message from the server. This doesn't yet mean all is well.
We need to parse the message to find out exactly what's happened. */

#if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2
  ldap_rc = rc;
  ldap_parse_rc = ldap_parse_result(lcp->ld, result, &rc, CSS &matched,
    CSS &error2, NULL, NULL, 0);
  DEBUG(D_lookup) debug_printf("ldap_parse_result: %d\n", ldap_parse_rc);
  if (ldap_parse_rc < 0 &&
      (ldap_parse_rc != LDAP_NO_RESULTS_RETURNED
      #ifdef LDAP_RES_SEARCH_REFERENCE
      || ldap_rc != LDAP_RES_SEARCH_REFERENCE
      #endif
     ))
    {
    *errmsg = string_sprintf("ldap_parse_result failed %d", ldap_parse_rc);
    goto RETURN_ERROR;
    }
  error1 = US ldap_err2string(rc);

#elif defined LDAP_LIB_NETSCAPE
  /* Dubious (it doesn't reference 'result' at all!) */
  rc = ldap_get_lderrno(lcp->ld, &matched, &error1);

#else                             /* UMich LDAP aka OpenLDAP 1.x */
  rc = ldap_result2error(lcp->ld, result, 0);
  error1 = ldap_err2string(rc);
  error2 = lcp->ld->ld_error;
  matched = lcp->ld->ld_matched;
#endif

/* Process the status as follows:

  (1) If we get LDAP_SIZELIMIT_EXCEEDED, just carry on, to return the
      truncated result list.

  (2) If we get LDAP_RES_SEARCH_REFERENCE, also just carry on. This was a
      submitted patch that is reported to "do the right thing" with Solaris
      LDAP libraries. (The problem it addresses apparently does not occur with
      Open LDAP.)

  (3) The range of errors defined by LDAP_NAME_ERROR generally mean "that
      object does not, or cannot, exist in the database". For those cases we
      fail the lookup.

  (4) All other non-successes here are treated as some kind of problem with
      the lookup, so return DEFER (which is the default in error_yield).
*/

DEBUG(D_lookup) debug_printf("ldap_parse_result yielded %d: %s\n",
  rc, ldap_err2string(rc));

if (rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
    #ifdef LDAP_RES_SEARCH_REFERENCE
    && rc != LDAP_RES_SEARCH_REFERENCE
    #endif
    )
  {
  *errmsg = string_sprintf("LDAP search failed - error %d: %s%s%s%s%s",
    rc,
    (error1 != NULL)?                       error1  : US"",
    (error2 != NULL && error2[0] != 0)?     US"/"   : US"",
    (error2 != NULL)?                       error2  : US"",
    (matched != NULL && matched[0] != 0)?   US"/"   : US"",
    (matched != NULL)?                      matched : US"");

  #if defined LDAP_NAME_ERROR
  if (LDAP_NAME_ERROR(rc))
  #elif defined NAME_ERROR    /* OPENLDAP1 calls it this */
  if (NAME_ERROR(rc))
  #else
  if (rc == LDAP_NO_SUCH_OBJECT)
  #endif

    {
    DEBUG(D_lookup) debug_printf("lookup failure forced\n");
    error_yield = FAIL;
    }
  goto RETURN_ERROR;
  }

/* The search succeeded. Check if we have too many results */

if (search_type != SEARCH_LDAP_MULTIPLE && rescount > 1)
  {
  *errmsg = string_sprintf("LDAP search: more than one entry (%d) was returned "
    "(filter not specific enough?)", rescount);
  goto RETURN_ERROR_BREAK;
  }

/* Check if we have too few (zero) entries */

if (rescount < 1)
  {
  *errmsg = string_sprintf("LDAP search: no results");
  error_yield = FAIL;
  goto RETURN_ERROR_BREAK;
  }

/* If an entry was found, but it had no attributes, we behave as if no entries
were found, that is, the lookup failed. */

if (!attribute_found)
  {
  *errmsg = US"LDAP search: found no attributes";
  error_yield = FAIL;
  goto RETURN_ERROR;
  }

/* Otherwise, it's all worked */

DEBUG(D_lookup) debug_printf("LDAP search: returning: %s\n", data);
*res = data;

RETURN_OK:
if (result != NULL) ldap_msgfree(result);
ldap_free_urldesc(ludp);
return OK;

/* Error returns */

RETURN_ERROR_BREAK:
*defer_break = TRUE;

RETURN_ERROR:
DEBUG(D_lookup) debug_printf("%s\n", *errmsg);

RETURN_ERROR_NOMSG:
if (result != NULL) ldap_msgfree(result);
if (ludp != NULL) ldap_free_urldesc(ludp);

#if defined LDAP_LIB_OPENLDAP2
  if (error2 != NULL)  ldap_memfree(error2);
  if (matched != NULL) ldap_memfree(matched);
#endif

return error_yield;
}
Beispiel #24
0
int
main(int argc, char **argv)
{
    LDAPAPIInfo api;
    int ival;
    char *sval;

    printf("Compile time API Information\n");

#ifdef LDAP_API_INFO_VERSION
    api.ldapai_info_version = LDAP_API_INFO_VERSION;
    printf("  API Info version:  %d\n", (int) api.ldapai_info_version);
#else
    api.ldapai_info_version = 1;
    printf("  API Info version:  unknown\n");
#endif

#ifdef LDAP_FEATURE_INFO_VERSION
    printf("  Feature Info version:  %d\n", (int) LDAP_FEATURE_INFO_VERSION);
#else
    printf("  Feature Info version:  unknown\n");
    api.ldapai_info_version = 1;
#endif

#ifdef LDAP_API_VERSION
    printf("  API version:       %d\n", (int) LDAP_API_VERSION);
#else
    printf("  API version:       unknown\n");
#endif

#ifdef LDAP_VERSION
    printf("  Protocol Version:  %d\n", (int) LDAP_VERSION);
#else
    printf("  Protocol Version:  unknown\n");
#endif
#ifdef LDAP_VERSION_MIN
    printf("  Protocol Min:      %d\n", (int) LDAP_VERSION_MIN);
#else
    printf("  Protocol Min:      unknown\n");
#endif
#ifdef LDAP_VERSION_MAX
    printf("  Protocol Max:      %d\n", (int) LDAP_VERSION_MAX);
#else
    printf("  Protocol Max:      unknown\n");
#endif
#ifdef LDAP_VENDOR_NAME
    printf("  Vendor Name:       %s\n", LDAP_VENDOR_NAME);
#else
    printf("  Vendor Name:       unknown\n");
#endif
#ifdef LDAP_VENDOR_VERSION
    printf("  Vendor Version:    %d\n", (int) LDAP_VENDOR_VERSION);
#else
    printf("  Vendor Version:    unknown\n");
#endif

    if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) != LDAP_SUCCESS) {
        fprintf(stderr, "%s: ldap_get_option(API_INFO) failed\n", argv[0]);
        return EXIT_FAILURE;
    }

    printf("\nExecution time API Information\n");
    printf("  API Info version:  %d\n", api.ldapai_info_version);

    if (api.ldapai_info_version != LDAP_API_INFO_VERSION) {
        printf(" API INFO version mismatch: got %d, expected %d\n",
               api.ldapai_info_version, LDAP_API_INFO_VERSION);
        return EXIT_FAILURE;
    }

    printf("  API Version:       %d\n", api.ldapai_api_version);
    printf("  Protocol Max:      %d\n", api.ldapai_protocol_version);

    if(api.ldapai_extensions == NULL) {
        printf("  Extensions:        none\n");

    } else {
        int i;
        for(i=0; api.ldapai_extensions[i] != NULL; i++) /* empty */;
        printf("  Extensions:        %d\n", i);
        for(i=0; api.ldapai_extensions[i] != NULL; i++) {
#ifdef LDAP_OPT_API_FEATURE_INFO
            LDAPAPIFeatureInfo fi;
            fi.ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
            fi.ldapaif_name = api.ldapai_extensions[i];
            fi.ldapaif_version = 0;

            if( ldap_get_option(NULL, LDAP_OPT_API_FEATURE_INFO, &fi) == LDAP_SUCCESS ) {
                if(fi.ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) {
                    printf("                     %s feature info mismatch: got %d, expected %d\n",
                           api.ldapai_extensions[i],
                           LDAP_FEATURE_INFO_VERSION,
                           fi.ldapaif_info_version);

                } else {
                    printf("                     %s: version %d\n",
                           fi.ldapaif_name,
                           fi.ldapaif_version);
                }

            } else {
                printf("                     %s (NO FEATURE INFO)\n",
                       api.ldapai_extensions[i]);
            }

#else
            printf("                     %s\n",
                   api.ldapai_extensions[i]);
#endif

            ldap_memfree(api.ldapai_extensions[i]);
        }
        ldap_memfree(api.ldapai_extensions);
    }

    printf("  Vendor Name:       %s\n", api.ldapai_vendor_name);
    ldap_memfree(api.ldapai_vendor_name);

    printf("  Vendor Version:    %d\n", api.ldapai_vendor_version);

    printf("\nExecution time Default Options\n");

    if(ldap_get_option(NULL, LDAP_OPT_DEREF, &ival) != LDAP_SUCCESS) {
        fprintf(stderr, "%s: ldap_get_option(api) failed\n", argv[0]);
        return EXIT_FAILURE;
    }
    printf("  DEREF:             %d\n", ival);

    if(ldap_get_option(NULL, LDAP_OPT_SIZELIMIT, &ival) != LDAP_SUCCESS) {
        fprintf(stderr, "%s: ldap_get_option(sizelimit) failed\n", argv[0]);
        return EXIT_FAILURE;
    }
    printf("  SIZELIMIT:         %d\n", ival);

    if(ldap_get_option(NULL, LDAP_OPT_TIMELIMIT, &ival) != LDAP_SUCCESS) {
        fprintf(stderr, "%s: ldap_get_option(timelimit) failed\n", argv[0]);
        return EXIT_FAILURE;
    }
    printf("  TIMELIMIT:         %d\n", ival);

    if(ldap_get_option(NULL, LDAP_OPT_REFERRALS, &ival) != LDAP_SUCCESS) {
        fprintf(stderr, "%s: ldap_get_option(referrals) failed\n", argv[0]);
        return EXIT_FAILURE;
    }
    printf("  REFERRALS:         %s\n", ival ? "on" : "off");

    if(ldap_get_option(NULL, LDAP_OPT_RESTART, &ival) != LDAP_SUCCESS) {
        fprintf(stderr, "%s: ldap_get_option(restart) failed\n", argv[0]);
        return EXIT_FAILURE;
    }
    printf("  RESTART:           %s\n", ival ? "on" : "off");

    if(ldap_get_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ival) != LDAP_SUCCESS) {
        fprintf(stderr, "%s: ldap_get_option(protocol version) failed\n", argv[0]);
        return EXIT_FAILURE;
    }
    printf("  PROTOCOL VERSION:  %d\n", ival);

    if(ldap_get_option(NULL, LDAP_OPT_HOST_NAME, &sval) != LDAP_SUCCESS) {
        fprintf(stderr, "%s: ldap_get_option(host name) failed\n", argv[0]);
        return EXIT_FAILURE;
    }
    if( sval != NULL ) {
        printf("  HOST NAME:         %s\n", sval);
        ldap_memfree(sval);
    } else {
        puts("  HOST NAME:         <not set>");
    }

#if 0
    /* API tests */
    {   /* bindless unbind */
        LDAP *ld;
        int rc;

        ld = ldap_init( "localhost", 389 );
        if( ld == NULL ) {
            perror("ldap_init");
            return EXIT_FAILURE;
        }

        rc = ldap_unbind( ld );
        if( rc != LDAP_SUCCESS ) {
            perror("ldap_unbind");
            return EXIT_FAILURE;
        }
    }
    {   /* bindless unbind */
        LDAP *ld;
        int rc;

        ld = ldap_init( "localhost", 389 );
        if( ld == NULL ) {
            perror("ldap_init");
            return EXIT_FAILURE;
        }

        rc = ldap_abandon_ext( ld, 0, NULL, NULL );
        if( rc != LDAP_SERVER_DOWN ) {
            ldap_perror( ld, "ldap_abandon");
            return EXIT_FAILURE;
        }

        rc = ldap_unbind( ld );
        if( rc != LDAP_SUCCESS ) {
            perror("ldap_unbind");
            return EXIT_FAILURE;
        }
    }
#endif

    return EXIT_SUCCESS;
}
Beispiel #25
0
/** Check if user is authorized for remote access
 *
 */
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
{
	rlm_rcode_t	rcode = RLM_MODULE_OK;
	ldap_rcode_t	status;
	int		ldap_errno;
	int		i;
	ldap_instance_t	*inst = instance;
	char		**vals;
	VALUE_PAIR	*vp;
	ldap_handle_t	*conn;
	LDAPMessage	*result, *entry;
	char const 	*dn = NULL;
	rlm_ldap_map_xlat_t	expanded; /* faster than mallocing every time */

	if (!request->username) {
		RDEBUG2("Attribute \"User-Name\" is required for authorization");

		return RLM_MODULE_NOOP;
	}

	/*
	 *	Check for valid input, zero length names not permitted
	 */
	if (request->username->length == 0) {
		RDEBUG2("Zero length username not permitted");

		return RLM_MODULE_INVALID;
	}

	if (rlm_ldap_map_xlat(request, inst->user_map, &expanded) < 0) {
		return RLM_MODULE_FAIL;
	}

	conn = rlm_ldap_get_socket(inst, request);
	if (!conn) return RLM_MODULE_FAIL;

	/*
	 *	Add any additional attributes we need for checking access, memberships, and profiles
	 */
	if (inst->userobj_access_attr) {
		expanded.attrs[expanded.count++] = inst->userobj_access_attr;
	}

	if (inst->userobj_membership_attr && (inst->cacheable_group_dn || inst->cacheable_group_name)) {
		expanded.attrs[expanded.count++] = inst->userobj_membership_attr;
	}

	if (inst->profile_attr) {
		expanded.attrs[expanded.count++] = inst->profile_attr;
	}

	if (inst->valuepair_attr) {
		expanded.attrs[expanded.count++] = inst->valuepair_attr;
	}

	expanded.attrs[expanded.count] = NULL;

	dn = rlm_ldap_find_user(inst, request, &conn, expanded.attrs, true, &result, &rcode);
	if (!dn) {
		goto finish;
	}

	entry = ldap_first_entry(conn->handle, result);
	if (!entry) {
		ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));

		goto finish;
	}

	/*
	 *	Check for access.
	 */
	if (inst->userobj_access_attr) {
		rcode = rlm_ldap_check_access(inst, request, conn, entry);
		if (rcode != RLM_MODULE_OK) {
			goto finish;
		}
	}

	/*
	 *	Check if we need to cache group memberships
	 */
	if (inst->cacheable_group_dn || inst->cacheable_group_name) {
		if (inst->userobj_membership_attr) {
			rcode = rlm_ldap_cacheable_userobj(inst, request, &conn, entry, inst->userobj_membership_attr);
			if (rcode != RLM_MODULE_OK) {
				goto finish;
			}
		}

		rcode = rlm_ldap_cacheable_groupobj(inst, request, &conn);
		if (rcode != RLM_MODULE_OK) {
			goto finish;
		}
	}

#ifdef WITH_EDIR
	/*
	 *	We already have a Cleartext-Password.  Skip edir.
	 */
	if (pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) {
		goto skip_edir;
	}

	/*
	 *      Retrieve Universal Password if we use eDirectory
	 */
	if (inst->edir) {
		int res = 0;
		char password[256];
		size_t pass_size = sizeof(password);

		/*
		 *	Retrive universal password
		 */
		res = nmasldap_get_password(conn->handle, dn, password, &pass_size);
		if (res != 0) {
			REDEBUG("Failed to retrieve eDirectory password: %s", edir_errstr(res));
			rcode = RLM_MODULE_FAIL;

			goto finish;
		}

		/*
		 *	Add Cleartext-Password attribute to the request
		 */
		vp = radius_paircreate(request, &request->config_items, PW_CLEARTEXT_PASSWORD, 0);
		pairstrcpy(vp, password);
		vp->length = pass_size;

		RDEBUG2("Added eDirectory password in check items as %s = %s", vp->da->name, vp->vp_strvalue);

		if (inst->edir_autz) {
			RDEBUG2("Binding as user for eDirectory authorization checks");
			/*
			 *	Bind as the user
			 */
			conn->rebound = true;
			status = rlm_ldap_bind(inst, request, &conn, dn, vp->vp_strvalue, true);
			switch (status) {
			case LDAP_PROC_SUCCESS:
				rcode = RLM_MODULE_OK;
				RDEBUG("Bind as user \"%s\" was successful", dn);

				break;
			case LDAP_PROC_NOT_PERMITTED:
				rcode = RLM_MODULE_USERLOCK;

				goto finish;
			case LDAP_PROC_REJECT:
				rcode = RLM_MODULE_REJECT;

				goto finish;
			case LDAP_PROC_BAD_DN:
				rcode = RLM_MODULE_INVALID;

				goto finish;
			case LDAP_PROC_NO_RESULT:
				rcode = RLM_MODULE_NOTFOUND;

				goto finish;
			default:
				rcode = RLM_MODULE_FAIL;

				goto finish;
			};
		}
	}

skip_edir:
#endif

	/*
	 *	Apply ONE user profile, or a default user profile.
	 */
	if (inst->default_profile) {
		char profile[1024];

		if (radius_xlat(profile, sizeof(profile), request, inst->default_profile, NULL, NULL) < 0) {
			REDEBUG("Failed creating default profile string");

			rcode = RLM_MODULE_INVALID;
			goto finish;
		}

		rlm_ldap_map_profile(inst, request, &conn, profile, &expanded);
	}

	/*
	 *	Apply a SET of user profiles.
	 */
	if (inst->profile_attr) {
		vals = ldap_get_values(conn->handle, entry, inst->profile_attr);
		if (vals != NULL) {
			for (i = 0; vals[i] != NULL; i++) {
				rlm_ldap_map_profile(inst, request, &conn, vals[i], &expanded);
			}

			ldap_value_free(vals);
		}
	}

	if (inst->user_map || inst->valuepair_attr) {
		RDEBUG("Processing user attributes");
		rlm_ldap_map_do(inst, request, conn->handle, &expanded, entry);
		rlm_ldap_check_reply(inst, request);
	}

finish:
	rlm_ldap_map_xlat_free(&expanded);
	if (result) {
		ldap_msgfree(result);
	}
	rlm_ldap_release_socket(inst, conn);

	return rcode;
}
Beispiel #26
0
/** Convert multiple group names into a DNs
 *
 * Given an array of group names, builds a filter matching all names, then retrieves all group objects
 * and stores the DN associated with each group object.
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[in] request Current request.
 * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
 * @param[in] names to covert to DNs (NULL terminated).
 * @param[out] out Where to write the DNs. DNs must be freed with ldap_memfree(). Will be NULL terminated.
 * @param[in] outlen Size of out.
 * @return One of the RLM_MODULE_* values.
 */
static rlm_rcode_t rlm_ldap_group_name2dn(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
					  char **names, char **out, size_t outlen)
{
	rlm_rcode_t rcode = RLM_MODULE_OK;
	ldap_rcode_t status;
	int ldap_errno;

	unsigned int name_cnt = 0;
	unsigned int entry_cnt;
	char const *attrs[] = { NULL };

	LDAPMessage *result = NULL, *entry;

	char **name = names;
	char **dn = out;
	char const *base_dn = NULL;
	char base_dn_buff[LDAP_MAX_DN_STR_LEN];
	char buffer[LDAP_MAX_GROUP_NAME_LEN + 1];

	char *filter;

	*dn = NULL;

	if (!*names) {
		return RLM_MODULE_OK;
	}

	if (!inst->groupobj_name_attr) {
		REDEBUG("Told to convert group names to DNs but missing 'group.name_attribute' directive");

		return RLM_MODULE_INVALID;
	}

	RDEBUG("Converting group name(s) to group DN(s)");

	/*
	 *	It'll probably only save a few ms in network latency, but it means we can send a query
	 *	for the entire group list at once.
	 */
	filter = talloc_typed_asprintf(request, "%s%s%s",
				 inst->groupobj_filter ? "(&" : "",
				 inst->groupobj_filter ? inst->groupobj_filter : "",
				 names[0] && names[1] ? "(|" : "");
	while (*name) {
		rlm_ldap_escape_func(request, buffer, sizeof(buffer), *name++, NULL);
		filter = talloc_asprintf_append_buffer(filter, "(%s=%s)", inst->groupobj_name_attr, buffer);

		name_cnt++;
	}
	filter = talloc_asprintf_append_buffer(filter, "%s%s",
					       inst->groupobj_filter ? ")" : "",
					       names[0] && names[1] ? ")" : "");

	if (tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request,
			inst->groupobj_base_dn, rlm_ldap_escape_func, NULL) < 0) {
		REDEBUG("Failed creating base_dn");

		return RLM_MODULE_INVALID;
	}

	status = rlm_ldap_search(&result, inst, request, pconn, base_dn, inst->groupobj_scope,
				 filter, attrs, NULL, NULL);
	switch (status) {
	case LDAP_PROC_SUCCESS:
		break;

	case LDAP_PROC_NO_RESULT:
		RDEBUG("Tried to resolve group name(s) to DNs but got no results");
		goto finish;

	default:
		rcode = RLM_MODULE_FAIL;
		goto finish;
	}

	entry_cnt = ldap_count_entries((*pconn)->handle, result);
	if (entry_cnt > name_cnt) {
		REDEBUG("Number of DNs exceeds number of names, group and/or dn should be more restrictive");
		rcode = RLM_MODULE_INVALID;

		goto finish;
	}

	if (entry_cnt > (outlen - 1)) {
		REDEBUG("Number of DNs exceeds limit (%zu)", outlen - 1);
		rcode = RLM_MODULE_INVALID;

		goto finish;
	}

	if (entry_cnt < name_cnt) {
		RWDEBUG("Got partial mapping of group names (%i) to DNs (%i), membership information may be incomplete",
			name_cnt, entry_cnt);
	}

	entry = ldap_first_entry((*pconn)->handle, result);
	if (!entry) {
		ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));

		rcode = RLM_MODULE_FAIL;
		goto finish;
	}

	do {
		*dn = ldap_get_dn((*pconn)->handle, entry);
		if (!*dn) {
			ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
			REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));

			rcode = RLM_MODULE_FAIL;
			goto finish;
		}
		rlm_ldap_normalise_dn(*dn, *dn);

		RDEBUG("Got group DN \"%s\"", *dn);
		dn++;
	} while((entry = ldap_next_entry((*pconn)->handle, entry)));

	*dn = NULL;

finish:
	talloc_free(filter);
	if (result) {
		ldap_msgfree(result);
	}

	/*
	 *	Be nice and cleanup the output array if we error out.
	 */
	if (rcode != RLM_MODULE_OK) {
		dn = out;
		while(*dn) ldap_memfree(*dn++);
		*dn = NULL;
	}

	return rcode;
}
Beispiel #27
0
PyObject *
LDAP_get_option(LDAPObject *self, int option)
{
    int res;
    int intval;
    double doubleval;
    struct timeval *tv;
    LDAPAPIInfo apiinfo;
    LDAPControl **lcs;
    LDAPControl *lc;
    char *strval;
    PyObject *extensions, *v, *tup;
    Py_ssize_t i, num_extensions, num_controls;
    LDAP *ld;

    ld = self ? self->ldap : NULL;

    switch(option) {
    case LDAP_OPT_API_INFO:
	    apiinfo.ldapai_info_version = LDAP_API_INFO_VERSION;
	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
	    res = ldap_get_option( ld, option, &apiinfo );
	    if (self) LDAP_END_ALLOW_THREADS(self);
	    if (res != LDAP_OPT_SUCCESS)
		return LDAPerr(res);
    
	    /* put the extensions into tuple form */
	    num_extensions = 0;
	    while (apiinfo.ldapai_extensions[num_extensions])
		num_extensions++;
	    extensions = PyTuple_New(num_extensions);
	    for (i = 0; i < num_extensions; i++)
		PyTuple_SET_ITEM(extensions, i,
		    PyBytes_FromString(apiinfo.ldapai_extensions[i]));

	    /* return api info as a dictionary */
	    v = Py_BuildValue("{s:i, s:i, s:i, s:s, s:i, s:O}",
		    "info_version",     apiinfo.ldapai_info_version,
		    "api_version",      apiinfo.ldapai_api_version,
		    "protocol_version", apiinfo.ldapai_protocol_version,
		    "vendor_name",      apiinfo.ldapai_vendor_name,
		    "vendor_version",   apiinfo.ldapai_vendor_version,
		    "extensions",       extensions);

	    if (apiinfo.ldapai_vendor_name)
		ldap_memfree(apiinfo.ldapai_vendor_name);
	    for (i = 0; i < num_extensions; i++)
		ldap_memfree(apiinfo.ldapai_extensions[i]);
	    ldap_memfree(apiinfo.ldapai_extensions);
	    Py_DECREF(extensions);

	    return v;

#ifdef HAVE_SASL
    case LDAP_OPT_X_SASL_SSF:
#endif
    case LDAP_OPT_REFERRALS:
    case LDAP_OPT_RESTART:
    case LDAP_OPT_DEREF:
    case LDAP_OPT_SIZELIMIT:
    case LDAP_OPT_TIMELIMIT:
    case LDAP_OPT_PROTOCOL_VERSION:
    case LDAP_OPT_ERROR_NUMBER:
    case LDAP_OPT_DEBUG_LEVEL:
    case LDAP_OPT_X_TLS:
    case LDAP_OPT_X_TLS_REQUIRE_CERT:
#ifdef HAVE_SASL
    case LDAP_OPT_X_SASL_SSF_MIN:
    case LDAP_OPT_X_SASL_SSF_MAX:
#endif
	    /* Integer-valued options */
	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
	    res = ldap_get_option(ld, option, &intval);
	    if (self) LDAP_END_ALLOW_THREADS(self);
	    if (res != LDAP_OPT_SUCCESS)
		return LDAPerr(res);
	    return PyInt_FromLong(intval);

    case LDAP_OPT_HOST_NAME:
    case LDAP_OPT_URI:
    case LDAP_OPT_ERROR_STRING:
    case LDAP_OPT_MATCHED_DN:
    case LDAP_OPT_X_TLS_CACERTFILE:
    case LDAP_OPT_X_TLS_CACERTDIR:
    case LDAP_OPT_X_TLS_CERTFILE:
    case LDAP_OPT_X_TLS_KEYFILE:
    case LDAP_OPT_X_TLS_CIPHER_SUITE:
    case LDAP_OPT_X_TLS_RANDOM_FILE:
#ifdef HAVE_SASL
    case LDAP_OPT_X_SASL_SECPROPS:
    case LDAP_OPT_X_SASL_MECH:
    case LDAP_OPT_X_SASL_REALM:
    case LDAP_OPT_X_SASL_AUTHCID:
    case LDAP_OPT_X_SASL_AUTHZID:
#endif
	    /* String-valued options */
	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
	    res = ldap_get_option(ld, option, &strval);
	    if (self) LDAP_END_ALLOW_THREADS(self);
	    if (res != LDAP_OPT_SUCCESS)
		return LDAPerr(res);
	    if (strval == NULL) {
		Py_INCREF(Py_None);
		return Py_None;
	    }
	    v = PyBytes_FromString(strval);
	    ldap_memfree(strval);
	    return v;

    case LDAP_OPT_TIMEOUT:
    case LDAP_OPT_NETWORK_TIMEOUT:
	    /* Double-valued timeval options */
	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
	    res = ldap_get_option(ld, option, &tv);
	    if (self) LDAP_END_ALLOW_THREADS(self);
	    if (res != LDAP_OPT_SUCCESS)
		return LDAPerr(res);
	    if (tv == NULL) {
		Py_INCREF(Py_None);
		return Py_None;
	    }
	    v = PyFloat_FromDouble(
              (double) tv->tv_sec + ( (double) tv->tv_usec / 1000000.0 )
            );
	    ldap_memfree(tv);
	    return v;

    case LDAP_OPT_SERVER_CONTROLS:
    case LDAP_OPT_CLIENT_CONTROLS:
	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
	    res = ldap_get_option(ld, option, &lcs);
	    if (self) LDAP_END_ALLOW_THREADS(self);

	    if (res != LDAP_OPT_SUCCESS)
		return LDAPerr(res);

            if (lcs == NULL)
                return PyList_New(0);
            
            /* Get the number of controls */
            num_controls = 0;
            while (lcs[num_controls])
                num_controls++;

            /* We'll build a list of controls, with each control a tuple */
            v = PyList_New(num_controls);
            for (i = 0; i < num_controls; i++) {
                lc = lcs[i];
                tup = Py_BuildValue("(sbs)", 
                                    lc->ldctl_oid,
                                    lc->ldctl_iscritical,
                                    lc->ldctl_value.bv_val);
                PyList_SET_ITEM(v, i, tup);
            }
            
            ldap_controls_free(lcs);

            return v;
            
    default:
	    PyErr_SetObject(PyExc_ValueError, Py_None);
	    return NULL;
    }
}
Beispiel #28
0
/** Query the LDAP directory to check if a user object is a member of a group
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[in] request Current request.
 * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
 * @param[in] dn of user object.
 * @param[in] check vp containing the group value (name or dn).
 * @return One of the RLM_MODULE_* values.
 */
rlm_rcode_t rlm_ldap_check_userobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
					   char const *dn, VALUE_PAIR *check)
{
	rlm_rcode_t	rcode = RLM_MODULE_NOTFOUND, ret;
	ldap_rcode_t	status;
	bool		name_is_dn = false, value_is_dn = false;

	LDAPMessage     *result = NULL;
	LDAPMessage     *entry = NULL;
	struct berval	**values = NULL;

	char const	*attrs[] = { inst->userobj_membership_attr, NULL };
	int		i, count, ldap_errno;

	RDEBUG2("Checking user object's %s attributes", inst->userobj_membership_attr);
	RINDENT();
	status = rlm_ldap_search(&result, inst, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL);
	REXDENT();
	switch (status) {
	case LDAP_PROC_SUCCESS:
		break;

	case LDAP_PROC_NO_RESULT:
		RDEBUG("Can't check membership attributes, user object not found");

		rcode = RLM_MODULE_NOTFOUND;

		/* FALL-THROUGH */
	default:
		goto finish;
	}

	entry = ldap_first_entry((*pconn)->handle, result);
	if (!entry) {
		ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));

		rcode = RLM_MODULE_FAIL;

		goto finish;
	}

	values = ldap_get_values_len((*pconn)->handle, entry, inst->userobj_membership_attr);
	if (!values) {
		RDEBUG("No group membership attribute(s) found in user object");

		goto finish;
	}

	/*
	 *	Loop over the list of groups the user is a member of,
	 *	looking for a match.
	 */
	name_is_dn = rlm_ldap_is_dn(check->vp_strvalue, check->vp_length);
	count = ldap_count_values_len(values);
	for (i = 0; i < count; i++) {
		value_is_dn = rlm_ldap_is_dn(values[i]->bv_val, values[i]->bv_len);

		RDEBUG2("Processing %s value \"%.*s\" as a %s", inst->userobj_membership_attr,
			(int)values[i]->bv_len, values[i]->bv_val, value_is_dn ? "DN" : "group name");

		/*
		 *	Both literal group names, do case sensitive comparison
		 */
		if (!name_is_dn && !value_is_dn) {
			if ((check->vp_length == values[i]->bv_len) &&
			    (memcmp(values[i]->bv_val, check->vp_strvalue, values[i]->bv_len) == 0)) {
				RDEBUG("User found in group \"%s\". Comparison between membership: name, check: name",
				       check->vp_strvalue);
				rcode = RLM_MODULE_OK;

				goto finish;
			}

			continue;
		}

		/*
		 *	Both DNs, do case insensitive, binary safe comparison
		 */
		if (name_is_dn && value_is_dn) {
			if (check->vp_length == values[i]->bv_len) {
				int j;

				for (j = 0; j < (int)values[i]->bv_len; j++) {
					if (tolower(values[i]->bv_val[j]) != tolower(check->vp_strvalue[j])) break;
				}
				if (j == (int)values[i]->bv_len) {
					RDEBUG("User found in group DN \"%s\". "
					       "Comparison between membership: dn, check: dn", check->vp_strvalue);
					rcode = RLM_MODULE_OK;

					goto finish;
				}
			}

			continue;
		}

		/*
		 *	If the value is not a DN, and the name we were given is a dn
		 *	convert the value to a DN and do a comparison.
		 */
		if (!value_is_dn && name_is_dn) {
			char *resolved;
			bool eq = false;

			RINDENT();
			ret = rlm_ldap_group_dn2name(inst, request, pconn, check->vp_strvalue, &resolved);
			REXDENT();
			if (ret != RLM_MODULE_OK) {
				rcode = ret;
				goto finish;
			}

			if (((talloc_array_length(resolved) - 1) == values[i]->bv_len) &&
			    (memcmp(values[i]->bv_val, resolved, values[i]->bv_len) == 0)) eq = true;
			talloc_free(resolved);
			if (eq) {
				RDEBUG("User found in group \"%.*s\". Comparison between membership: name, check: name "
				       "(resolved from DN \"%s\")", (int)values[i]->bv_len,
				       values[i]->bv_val, check->vp_strvalue);
				rcode = RLM_MODULE_OK;

				goto finish;
			}

			continue;
		}

		/*
		 *	We have a value which is a DN, and a check item which specifies the name of a group,
		 *	convert the value to a name so we can do a comparison.
		 */
		if (value_is_dn && !name_is_dn) {
			char *resolved;
			char *value;
			bool eq = false;

			value = rlm_ldap_berval_to_string(request, values[i]);
			RINDENT();
			ret = rlm_ldap_group_dn2name(inst, request, pconn, value, &resolved);
			REXDENT();
			talloc_free(value);
			if (ret != RLM_MODULE_OK) {
				rcode = ret;
				goto finish;
			}

			if (((talloc_array_length(resolved) - 1) == check->vp_length) &&
			    (memcmp(check->vp_strvalue, resolved, check->vp_length) == 0)) eq = true;
			talloc_free(resolved);
			if (eq) {
				RDEBUG("User found in group \"%s\". Comparison between membership: name "
				       "(resolved from DN \"%s\"), check: name", check->vp_strvalue, value);
				rcode = RLM_MODULE_OK;

				goto finish;
			}

			continue;
		}
		rad_assert(0);
	}

finish:
	if (values) ldap_value_free_len(values);
	if (result) ldap_msgfree(result);

	return rcode;
}
Beispiel #29
0
/** Convert group membership information into attributes
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[in] request Current request.
 * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
 * @return One of the RLM_MODULE_* values.
 */
rlm_rcode_t rlm_ldap_cacheable_groupobj(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn)
{
	rlm_rcode_t rcode = RLM_MODULE_OK;
	ldap_rcode_t status;
	int ldap_errno;

	LDAPMessage *result = NULL;
	LDAPMessage *entry;

	char base_dn[LDAP_MAX_DN_STR_LEN];

	char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
	char filter[LDAP_MAX_FILTER_STR_LEN + 1];

	char const *attrs[] = { inst->groupobj_name_attr, NULL };

	VALUE_PAIR *vp;
	char *dn;

	rad_assert(inst->groupobj_base_dn);

	if (!inst->groupobj_membership_filter) {
		RDEBUG2("Skipping caching group objects as directive 'group.membership_filter' is not set");

		return RLM_MODULE_OK;
	}

	if (rlm_ldap_xlat_filter(request,
				 filters, sizeof(filters) / sizeof(*filters),
				 filter, sizeof(filter)) < 0) {
		return RLM_MODULE_INVALID;
	}

	if (radius_xlat(base_dn, sizeof(base_dn), request, inst->groupobj_base_dn, rlm_ldap_escape_func, NULL) < 0) {
		REDEBUG("Failed creating base_dn");

		return RLM_MODULE_INVALID;
	}

	status = rlm_ldap_search(inst, request, pconn, base_dn, inst->groupobj_scope, filter, attrs, &result);
	switch (status) {
	case LDAP_PROC_SUCCESS:
		break;

	case LDAP_PROC_NO_RESULT:
		RDEBUG2("No cacheable group memberships found in group objects");

	default:
		goto finish;
	}

	entry = ldap_first_entry((*pconn)->handle, result);
	if (!entry) {
		ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
		REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));

		goto finish;
	}

	do {
		if (inst->cacheable_group_dn) {
			dn = ldap_get_dn((*pconn)->handle, entry);
			if (!dn) {
				ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
				REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));

				goto finish;
			}
			rlm_ldap_normalise_dn(dn, dn);

			MEM(vp = pairmake_config(inst->cache_da->name, NULL, T_OP_ADD));
			pairstrcpy(vp, dn);

			RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, dn);
			ldap_memfree(dn);
		}

		if (inst->cacheable_group_name) {
			struct berval **values;

			values = ldap_get_values_len((*pconn)->handle, entry, inst->groupobj_name_attr);
			if (!values) continue;

			MEM(vp = pairmake_config(inst->cache_da->name, NULL, T_OP_ADD));
			pairstrncpy(vp, values[0]->bv_val, values[0]->bv_len);

			RDEBUG("Added control:%s with value \"%.*s\"", inst->cache_da->name,
			       (int)values[0]->bv_len, values[0]->bv_val);

			ldap_value_free_len(values);
		}
	} while ((entry = ldap_next_entry((*pconn)->handle, entry)));

finish:
	if (result) ldap_msgfree(result);

	return rcode;
}
Beispiel #30
0
static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
				       const struct id_map *map)
{
	NTSTATUS ret;
	TALLOC_CTX *memctx;
	struct idmap_ldap_context *ctx;
	LDAPMessage *entry = NULL;
	LDAPMod **mods = NULL;
	const char *type;
	char *id_str;
	char *sid;
	char *dn;
	int rc = -1;

	/* Only do query if we are online */
	if (idmap_is_offline())	{
		return NT_STATUS_FILE_IS_OFFLINE;
	}

	/* Initilization my have been deferred because we were offline */
	if ( ! dom->initialized) {
		ret = idmap_ldap_db_init(dom);
		if ( ! NT_STATUS_IS_OK(ret)) {
			return ret;
		}
	}

	ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);

	switch(map->xid.type) {
	case ID_TYPE_UID:
		type = get_attr_key2string(sidmap_attr_list,
					   LDAP_ATTR_UIDNUMBER);
		break;

	case ID_TYPE_GID:
		type = get_attr_key2string(sidmap_attr_list,
					   LDAP_ATTR_GIDNUMBER);
		break;

	default:
		return NT_STATUS_INVALID_PARAMETER;
	}

	memctx = talloc_new(ctx);
	if ( ! memctx) {
		DEBUG(0, ("Out of memory!\n"));
		return NT_STATUS_NO_MEMORY;
	}

	id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
	CHECK_ALLOC_DONE(id_str);

	sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
	CHECK_ALLOC_DONE(sid);

	dn = talloc_asprintf(memctx, "%s=%s,%s",
			get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
			sid,
			ctx->suffix);
	CHECK_ALLOC_DONE(dn);

	smbldap_set_mod(&mods, LDAP_MOD_ADD,
			"objectClass", LDAP_OBJ_IDMAP_ENTRY);

	smbldap_make_mod(ctx->smbldap_state->ldap_struct,
			 entry, &mods, type, id_str);

	smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
			 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
			 sid);

	if ( ! mods) {
		DEBUG(2, ("ERROR: No mods?\n"));
		ret = NT_STATUS_UNSUCCESSFUL;
		goto done;
	}

	/* TODO: remove conflicting mappings! */

	smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);

	DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));

	rc = smbldap_add(ctx->smbldap_state, dn, mods);
	ldap_mods_free(mods, True);

	if (rc != LDAP_SUCCESS) {
		char *ld_error = NULL;
		ldap_get_option(ctx->smbldap_state->ldap_struct,
				LDAP_OPT_ERROR_STRING, &ld_error);
		DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
			 "mapping [%s]\n", sid,
			 (unsigned long)map->xid.id, type));
		DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
			ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
		if (ld_error) {
			ldap_memfree(ld_error);
		}
		ret = NT_STATUS_UNSUCCESSFUL;
		goto done;
	}

	DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
		  "%lu [%s]\n",	sid, (unsigned long)map->xid.id, type));

	ret = NT_STATUS_OK;

done:
	talloc_free(memctx);
	return ret;
}