/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
*
* Copyright (c) 2004-2005, Novell, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* * The copyright holder's name is not used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
*/
#include <time.h>
#include "ldap_main.h"
#include "kdb_ldap.h"
#include "ldap_principal.h"
#include "princ_xdr.h"
#include "ldap_tkt_policy.h"
#include "ldap_pwd_policy.h"
#include "ldap_err.h"
#include <libintl.h> /* Solaris Kerberos */
extern char* principal_attributes[];
extern char* max_pwd_life_attr[];
static char *
{
return ENOMEM;
return ENOMEM;
}
return 0;
}
/* Return true if it's okay to return aliases according to flags. */
static krb5_boolean
{
/*
* The current DAL does not have a flag to indicate whether
* aliases are okay. For service name lookups (AS or TGT path),
* we can always return aliases. For client name lookups, we can
* only return aliases if the client passed the canonicalize flag.
* We abuse the CLIENT_REFERRALS_ONLY flag to detect client name
* lookups.
*
* This method has the side effect of permitting aliases for
* lookups by administrative interfaces (e.g. kadmin). Since we
* don't have explicit admin support for aliases yet, this is
* okay.
*/
if (!(flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY))
return TRUE;
if (flags & KRB5_KDB_FLAG_CANONICALIZE)
return TRUE;
return FALSE;
}
/*
* look up a principal in the directory.
*/
{
/* Clear the global error string */
/* set initial values */
*nentries = 0;
*more = 0;
return EINVAL;
*more = 0;
goto cleanup;
}
goto cleanup;
goto cleanup;
goto cleanup;
}
goto cleanup;
}
goto cleanup;
GET_HANDLE();
for (ent=ldap_first_entry(ld, result); ent != NULL && *nentries == 0; ent=ldap_next_entry(ld, ent)) {
/* get the associated directory user information */
int i;
/* a wild-card in a principal name can return a list of kerberos principals.
* Make sure that the correct principal is returned.
* NOTE: a principalname k* in ldap server will return all the principals starting with a k
*/
*nentries = 1;
break;
}
}
if (*nentries == 0) /* no matching principal found */
continue;
}
/* We matched an alias, not the canonical name. */
if (aliases_ok(flags)) {
if (st != 0)
goto cleanup;
if (st != 0)
goto cleanup;
} else /* No canonicalization, so don't return aliases. */
*nentries = 0;
}
if (*nentries == 0)
continue;
}
entries)) != 0)
goto cleanup;
}
} /* for (tree=0 ... */
/* once done, put back the ldap handle */
if (filter)
if (subtree) {
}
if (ldap_server_handle)
if (user)
if (filtuser)
if (cname)
if (cprinc)
return st;
}
/*
* ptype is creating confusions. Additionally the logic
* surronding ptype is redundunt and can be achevied
* with the help of dn and containerdn members.
* so dropping the ptype member
*/
typedef struct _xargs_t {
char *dn;
char *linkdn;
char *containerdn;
char *tktpolicydn;
}xargs_t;
static void
{
if (xargs.containerdn)
if (xargs.tktpolicydn)
}
static krb5_error_code
{
int i=0;
unsigned int arg_val_len=0;
if (db_args) {
for (i=0; db_args[i]; ++i) {
} else {
if (optype == MODIFY_PRINCIPAL ||
goto cleanup;
}
if (optype == MODIFY_PRINCIPAL ||
goto cleanup;
}
goto cleanup;
}
} else {
goto cleanup;
}
goto cleanup;
}
}
goto cleanup;
}
dptr)) != 0)
goto cleanup;
} else {
goto cleanup;
}
}
}
}
return st;
}
static krb5_error_code
{
/*
* This should be pushed back into other library initialization
* code.
*/
err = kldap_ensure_initialized ();
if (err)
return err;
}
static krb5_error_code
{
/*
* This should be pushed back into other library initialization
* code.
*/
err = kldap_ensure_initialized ();
if (err)
return err;
if (err)
return err;
*n_key_data = p->n_key_data;
free(p);
return 0;
}
/* Decoding ASN.1 encoded key */
static struct berval **
int currkvno;
int i, j, last;
if (n_key_data <= 0)
return NULL;
/* Find the number of key versions */
for (i = 0; i < n_key_data - 1; i++)
num_versions++;
goto cleanup;
}
&code);
goto cleanup;
}
/*CHECK_NULL(ret[j]); */
j++;
last = i + 1;
}
}
if (err != 0) {
for (i = 0; i <= num_versions; i++)
}
}
return ret;
}
static krb5_error_code
{
return ENOMEM;
return ENOMEM;
}
return 0;
}
{
int i=0, l=0, kerberos_principal_object_type=0;
/* Clear the global error string */
return EINVAL;
/* get ldap handle */
GET_HANDLE();
goto cleanup;
}
/* get the principal information to act on */
goto cleanup;
}
/* Identity the type of operation, it can be
* add principal or modify principal.
* hack if the entries->mask has KRB_PRINCIPAL flag set
* then it is a add operation
*/
else
goto cleanup;
goto cleanup;
/* 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).
*/
/* must have principal name for search */
krb5_set_error_message(context, st, gettext("operation can not continue, principal name not found"));
goto cleanup;
}
goto cleanup;
}
/* get the current subtree list */
goto cleanup;
found_entry = FALSE;
/* search for entry with matching krbprincipalname attribute */
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 */
}
if (st == LDAP_SUCCESS) {
if (numlentries > 1) {
gettext("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) {
/* setting principal_dn will cause that entry to be modified further down */
goto cleanup;
}
}
}
}
if (result)
} else if (st != LDAP_NO_SUCH_OBJECT) {
/* could not perform search, return with failure */
goto cleanup;
}
/*
* If it isn't found then assume a standalone princ entry is to
* be created.
*/
} /* end for (tree = 0; principal_dn == ... */
/*
* 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.
*/
}
} /* end if (entries->mask & KADM5_LOAD */
/* time to generate the DN information with the help of
* containerdn, principalcontainerreference or
* realmcontainerdn information
*/
/* get the subtree information */
/* if the principal is a inter-realm principal, always created in the realm container */
} else if (xargs.containerdn) {
}
goto cleanup;
}
} else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
/*
* Here the subtree should be changed with
* principalcontainerreference attribute value
*/
} else {
}
/*
* free subtree when you are done using the subtree
* set the boolean create_standalone_prinicipal to TRUE
*/
}
/*
* 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
*/
/* make sure the DN falls in the subtree */
} 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.
*/
}
/* get the current subtree list */
goto cleanup;
break;
} else {
break;
}
}
}
}
if (outofsubtree == TRUE) {
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.
*/
if (st == LDAP_SUCCESS) {
}
}
}
} else {
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.
*/
goto cleanup;
}
/*
* 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 &&
gettext("link information can not be set/updated as the kerberos principal belongs to an ldap object"));
goto cleanup;
}
/*
* Check the link information. If there is already a link
* existing then this operation is not allowed.
*/
{
int j=0;
gettext("Failed getting object references"));
goto cleanup;
}
gettext("kerberos principal is already linked "
"to a ldap object"));
goto cleanup;
}
}
}
goto cleanup;
if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
goto cleanup;
}
}
goto cleanup;
goto cleanup;
}
}
if (st != 0)
goto cleanup;
int attr_mask = 0;
/* Check if the krbLoginFailedCount attribute exists. (Through
* krb5 1.8.1, it wasn't set in new entries.) */
if (st != 0)
goto cleanup;
/*
* 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
LDAP_MOD_INCREMENT, 1);
if (st != 0)
goto cleanup;
} else {
#endif /* LDAP_MOD_INCREMENT */
if (has_fail_count) {
"krbLoginFailedCount",
if (st != 0)
goto cleanup;
}
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. */
LDAP_MOD_ADD, 0);
}
if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entries->max_life)) != 0)
goto cleanup;
}
entries->max_renewable_life)) != 0)
goto cleanup;
}
entries->attributes)) != 0)
goto cleanup;
}
goto cleanup;
}
goto cleanup;
if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
goto cleanup;
}
}
goto cleanup;
strval)) != 0) {
goto cleanup;
}
}
/* FIX ME: I guess the princ_ent should be freed after this call */
goto cleanup;
}
}
}
goto cleanup;
goto cleanup;
} else {
goto cleanup;
}
/*
* a load is special in that existing entries must have attrs that
* removed.
*/
goto cleanup;
}
goto cleanup;
}
goto cleanup;
goto cleanup;
goto cleanup;
"krbpasswordexpiration",
LDAP_MOD_REPLACE, strval)) != 0) {
goto cleanup;
}
}
/* Update last password change whenever a new key is set */
{
&last_pw_changed)) != 0)
goto cleanup;
goto cleanup;
LDAP_MOD_REPLACE, strval)) != 0) {
goto cleanup;
}
}
} /* Modify Key data ends here */
/* Set tl_data */
int count = 0;
#ifdef SECURID
#endif
continue;
count++;
}
if (count != 0) {
int j;
sizeof (struct berval*));
if (ber_tl_data == NULL) {
goto cleanup;
}
/* Ignore tl_data that are stored in separate directory
* attributes */
#ifdef SECURID
#endif
continue;
break;
j++;
}
if (st != 0) {
for (j = 0; ber_tl_data[j] != NULL; j++) {
free (ber_tl_data[j]);
}
free (ber_tl_data);
goto cleanup;
}
ber_tl_data)) != 0)
goto cleanup;
}
}
/* Directory specific attribute */
int tmask=0;
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 */
goto cleanup;
}
}
if (establish_links == TRUE) {
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
*/
goto cleanup;
if (create_standalone_prinicipal == TRUE) {
strval[0] = "krbprincipal";
goto cleanup;
/* a load operation must replace an existing entry */
if (st != LDAP_SUCCESS) {
goto cleanup;
} else {
}
}
if (st != LDAP_SUCCESS) {
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.
*/
{
int p, q, r=0, amask=0;
goto cleanup;
for (p=1, q=0; p<=2; p<<=1, ++q) {
if ((p & amask) == 0)
strval[r++] = attrvalues[q];
}
if (r != 0) {
goto cleanup;
}
}
else
if (st != LDAP_SUCCESS) {
goto cleanup;
}
}
}
if (user)
if (principal_dn)
free (principal_dn);
if (subtree)
if (bersecretkey) {
for (l=0; bersecretkey[l]; ++l) {
if (bersecretkey[l]->bv_val)
free (bersecretkey[l]);
}
free (bersecretkey);
}
if (keys)
*nentries = i;
return(st);
}
{
goto cleanup;
goto cleanup;
goto cleanup;
}
st = 0; /* reset the return status */
}
if ((mask & KDB_MAX_LIFE_ATTR) == 0) {
}
if ((mask & KDB_MAX_RLIFE_ATTR) == 0) {
}
if ((mask & KDB_TKT_FLAGS_ATTR) == 0) {
}
return st;
}
{
int i=0, j=0, noofkeys=0;
goto cleanup;
continue;
&kd,
&n_kd,
mkvno);
if (st != 0) {
goto cleanup;
}
goto cleanup;
}
for (j = 0; j < n_kd; j++)
}
return st;
}
static char *
{
return NULL;
/* Solaris Kerberos */
return NULL;
}
return strtime;
}