diff options
Diffstat (limited to 'lib/ldaputil/ldapauth.c')
-rw-r--r-- | lib/ldaputil/ldapauth.c | 1099 |
1 files changed, 1099 insertions, 0 deletions
diff --git a/lib/ldaputil/ldapauth.c b/lib/ldaputil/ldapauth.c new file mode 100644 index 00000000..d8088269 --- /dev/null +++ b/lib/ldaputil/ldapauth.c @@ -0,0 +1,1099 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ldapauth.cpp: Implements LDAP integration in the web server. + * + * Nitin More, John Kristian + */ + +/* #define DBG_PRINT */ + +#include <stdio.h> /* for BUFSIZ */ +#include <string.h> /* for strncpy, strcat */ +#include <ldap.h> + +#include <ldaputil/certmap.h> +#include <ldaputil/errors.h> +#include <ldaputil/ldapauth.h> + +#include <ldaputili.h> + +/* If we are not interested in the returned attributes, just ask for one + * attribute in the call to ldap_search. Also don't ask for the attribute + * value -- just the attr. + */ +static const char *default_search_attrs[] = { "c" , 0 }; +static int default_search_attrsonly = 1; + +/* + * ldapu_find + * Description: + * Caller should free res if it is not NULL. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * base basedn (where to start the search) + * scope scope for the search. One of + * LDAP_SCOPE_SUBTREE, LDAP_SCOPE_ONELEVEL, and + * LDAP_SCOPE_BASE + * filter LDAP filter + * attrs A NULL-terminated array of strings indicating which + * attributes to return for each matching entry. Passing + * NULL for this parameter causes all available + * attributes to be retrieved. + * attrsonly A boolean value that should be zero if both attribute + * types and values are to be returned, non-zero if only + * types are wanted. + * res A result parameter which will contain the results of + * the search upon completion of the call. + * Return Values: + * LDAPU_SUCCESS if entry is found + * LDAPU_FAILED if entry is not found + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_find (LDAP *ld, const char *base, int scope, + const char *filter, const char **attrs, + int attrsonly, LDAPMessage **res) +{ + int retval; +#ifdef USE_THIS_CODE /* ASYNCHRONOUS */ + int msgid; +#endif + int numEntries; + + *res = 0; + + /* If base is NULL set it to null string */ + if (!base) { + DBG_PRINT1("ldapu_find: basedn is missing -- assuming null string\n"); + base = ""; + } + + if (!filter || !*filter) { + DBG_PRINT1("ldapu_find: filter is missing -- assuming objectclass=*\n"); + filter = ldapu_strings[LDAPU_STR_FILTER_DEFAULT]; + } + + DBG_PRINT2("\tbase:\t\"%s\"\n", base); + DBG_PRINT2("\tfilter:\t\"%s\"\n", filter ? filter : "<NULL>"); + DBG_PRINT2("\tscope:\t\"%s\"\n", + (scope == LDAP_SCOPE_SUBTREE ? "LDAP_SCOPE_SUBTREE" + : (scope == LDAP_SCOPE_ONELEVEL ? "LDAP_SCOPE_ONELEVEL" + : "LDAP_SCOPE_BASE"))); + + retval = ldapu_search_s(ld, base, scope, filter, (char **)attrs, + attrsonly, res); + + if (retval != LDAP_SUCCESS) + { + /* retval = ldap_result2error(ld, *res, 0); */ + DBG_PRINT2("ldapu_search_s: %s\n", ldapu_err2string(retval)); + return(retval); + } + + numEntries = ldapu_count_entries(ld, *res); + + if (numEntries == 1) { + /* success */ + return LDAPU_SUCCESS; + } + else if (numEntries == 0) { + /* not found -- but not an error */ + DBG_PRINT1("ldapu_search_s: Entry not found\n"); + return LDAPU_FAILED; + } + else if (numEntries > 0) { + /* Found more than one entry! */ + DBG_PRINT1("ldapu_search_s: Found more than one entry\n"); + return LDAPU_ERR_MULTIPLE_MATCHES; + } + else { + /* should never get here */ + DBG_PRINT1("ldapu_search_s: should never reach here\n"); + ldapu_msgfree(ld, *res); + return LDAP_OPERATIONS_ERROR; + } +} + + +/* Search function for the cases where base = "" = NULL suffix, that is, search to + * be performed on the entire DIT tree. + * We actually do various searches taking a naming context at a time as the base for + * the search. */ + +int ldapu_find_entire_tree (LDAP *ld, int scope, + const char *filter, const char **attrs, + int attrsonly, LDAPMessage ***res) +{ + int retval = LDAPU_FAILED; + int rv,i, num_namingcontexts; + LDAPMessage *result_entry, *result = NULL; + const char *suffix_attr[2] = {"namingcontexts", NULL}; + /* these are private suffixes that may contain pseudo users + e.g. replication manager that may have certs */ + int num_private_suffix = 1; + const char *private_suffix_list[2] = {"cn=config", NULL}; + char **suffix_list, **suffix = NULL; + + rv = ldapu_find(ld, "",LDAP_SCOPE_BASE, "objectclass=*", suffix_attr, 0, &result); + if (rv != LDAP_SUCCESS) { + if (result) ldapu_msgfree(ld, result); + return rv; + } + + result_entry = ldapu_first_entry(ld, result); + suffix = ldapu_get_values(ld, result_entry, suffix_attr[0]); + suffix_list = suffix; + num_namingcontexts = ldap_count_values(suffix); + /* add private suffixes to our list of suffixes to search */ + if (num_private_suffix) { + suffix_list = ldapu_realloc(suffix_list, + sizeof(char *)*(num_namingcontexts+num_private_suffix+1)); + if (!suffix_list) { + if (result) { + ldapu_msgfree(ld, result); + } + retval = LDAPU_FAILED; + return retval; + } + for (i = num_namingcontexts; i < (num_namingcontexts+num_private_suffix); ++i) { + suffix_list[i] = strdup(private_suffix_list[i-num_namingcontexts]); + } + suffix_list[i] = NULL; + num_namingcontexts += num_private_suffix; + suffix = suffix_list; + } + if (result) ldapu_msgfree(ld, result); + result = 0; + i = 0; + + /* ugaston - the caller function must remember to free the memory allocated here */ + *res = (LDAPMessage **) ldapu_malloc((num_namingcontexts + 1) * sizeof(LDAPMessage *)); + while (suffix && *suffix) { + rv = ldapu_find(ld, *suffix, scope, filter, attrs, attrsonly, &result); + if (scope == LDAP_SCOPE_BASE && rv == LDAP_SUCCESS) { + retval = rv; + (*res)[i++] = result; + break; + } + + switch (rv) { + case LDAP_SUCCESS: + if (retval == LDAP_SUCCESS) { + retval = LDAPU_ERR_MULTIPLE_MATCHES; + (*res)[i++] = result; + break; + } + case LDAPU_ERR_MULTIPLE_MATCHES: + retval = rv; + (*res)[i++] = result; + break; + default: + if (retval != LDAP_SUCCESS && retval != LDAPU_ERR_MULTIPLE_MATCHES) { + retval = rv; + } + if (result) ldapu_msgfree(ld, result); + result = 0; + break; + } + + suffix++; + } + + (*res)[i] = NULL; + ldapu_value_free(ld, suffix_list); + return retval; +} + + + +/* + * ldapu_find_uid_attrs + * Description: + * Maps the given uid to a user dn. Caller should free res if it is not + * NULL. Accepts the attrs & attrsonly args. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * uid User's name + * base basedn (where to start the search) + * attrs list of attributes to retrieve + * attrsonly flag indicating if attr values are to be retrieved + * res A result parameter which will contain the results of + * the search upon completion of the call. + * Return Values: + * LDAPU_SUCCESS if entry is found + * LDAPU_FAILED if entry is not found + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_find_uid_attrs (LDAP *ld, const char *uid, const char *base, + const char **attrs, int attrsonly, + LDAPMessage **res) +{ + int scope = LDAP_SCOPE_SUBTREE; + char filter[ BUFSIZ ]; + int retval; + + /* setup filter as (uid=<uid>) */ + sprintf(filter, ldapu_strings[LDAPU_STR_FILTER_USER], uid); + + retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, res); + + return retval; +} + +/* + * ldapu_find_uid + * Description: + * Maps the given uid to a user dn. Caller should free res if it is not + * NULL. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * uid User's name + * base basedn (where to start the search) + * res A result parameter which will contain the results of + * the search upon completion of the call. + * Return Values: + * LDAPU_SUCCESS if entry is found + * LDAPU_FAILED if entry is not found + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_find_uid (LDAP *ld, const char *uid, const char *base, + LDAPMessage **res) +{ + const char **attrs = 0; /* get all attributes ... */ + int attrsonly = 0; /* ... and their values */ + int retval; + + retval = ldapu_find_uid_attrs(ld, uid, base, attrs, attrsonly, res); + + return retval; +} + +/* + * ldapu_find_userdn + * Description: + * Maps the given uid to a user dn. Caller should free dn if it is not + * NULL. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * uid User's name + * base basedn (where to start the search) + * dn user dn + * Return Values: + * LDAPU_SUCCESS if entry is found + * LDAPU_FAILED if entry is not found + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_find_userdn (LDAP *ld, const char *uid, const char *base, + char **dn) +{ + LDAPMessage *res = 0; + int retval; + + retval = ldapu_find_uid_attrs(ld, uid, base, default_search_attrs, + default_search_attrsonly, &res); + + if (retval == LDAPU_SUCCESS) { + LDAPMessage *entry; + + entry = ldapu_first_entry(ld, res); + *dn = ldapu_get_dn(ld, entry); + } + else { + *dn = 0; + } + + if (res) ldapu_msgfree(ld, res); + + return retval; +} + +/* + * ldapu_find_group_attrs + * Description: + * Maps the given groupid to a group dn. Caller should free res if it is + * not NULL. Accepts the attrs & attrsonly args. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * groupid Groups's name + * base basedn (where to start the search) + * attrs list of attributes to retrieve + * attrsonly flag indicating if attr values are to be retrieved + * res A result parameter which will contain the results of + * the search upon completion of the call. + * Return Values: + * LDAPU_SUCCESS if entry is found + * LDAPU_FAILED if entry is not found + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_find_group_attrs (LDAP *ld, const char *groupid, + const char *base, const char **attrs, + int attrsonly, LDAPMessage **res) +{ + int scope = LDAP_SCOPE_SUBTREE; + char filter[ BUFSIZ ]; + int retval; + + /* setup the filter */ + sprintf(filter, + ldapu_strings[LDAPU_STR_FILTER_GROUP], + groupid); + + retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, res); + + return retval; +} + +/* + * ldapu_find_group + * Description: + * Maps the given groupid to a group dn. Caller should free res if it is + * not NULL. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * groupid Groups's name + * base basedn (where to start the search) + * res A result parameter which will contain the results of + * the search upon completion of the call. + * Return Values: + * LDAPU_SUCCESS if entry is found + * LDAPU_FAILED if entry is not found + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_find_group (LDAP *ld, const char *groupid, const char *base, + LDAPMessage **res) +{ + const char **attrs = 0; /* get all attributes ... */ + int attrsonly = 0; /* ... and their values */ + int retval; + + retval = ldapu_find_group_attrs (ld, groupid, base, attrs, attrsonly, res); + + return retval; +} + +/* + * ldapu_find_groupdn + * Description: + * Maps the given groupid to a group dn. Caller should free dn if it is + * not NULL. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * groupid Groups's name + * base basedn (where to start the search) + * dn group dn + * Return Values: + * LDAPU_SUCCESS if entry is found + * LDAPU_FAILED if entry is not found + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_find_groupdn (LDAP *ld, const char *groupid, const char *base, + char **dn) +{ + LDAPMessage *res = 0; + int retval; + + retval = ldapu_find_group_attrs(ld, groupid, base, default_search_attrs, + default_search_attrsonly, &res); + + if (retval == LDAPU_SUCCESS) { + LDAPMessage *entry; + + /* get ldap entry */ + entry = ldapu_first_entry(ld, res); + *dn = ldapu_get_dn(ld, entry); + } + else { + *dn = 0; + } + + if (res) ldapu_msgfree(ld, res); + + return retval; +} + + +/* + * continuable_err + * Description: + * Returns true for benign errors (i.e. errors for which recursive + * search can continue. + * Return Values: + * 0 (zero) - if not a benign error + * 1 - if a benign error -- search can continue. + */ +static int continuable_err (int err) +{ + return (err == LDAPU_FAILED); +} + +int ldapu_auth_udn_gdn_recurse (LDAP *ld, const char *userdn, + const char *groupdn, const char *base, + int recurse_cnt) +{ + char filter[ BUFSIZ ]; + const char **attrs = default_search_attrs; + int attrsonly = default_search_attrsonly; + LDAPMessage *res = 0; + int retval; + char member_filter[ BUFSIZ ]; + + if (recurse_cnt >= 30) + return LDAPU_ERR_CIRCULAR_GROUPS; + + /* setup the filter */ + sprintf(member_filter, ldapu_strings[LDAPU_STR_FILTER_MEMBER], userdn, userdn); + + retval = ldapu_find(ld, groupdn, LDAP_SCOPE_BASE, member_filter, attrs, + attrsonly, &res); + + if (res) ldap_msgfree(res); + + if (retval != LDAPU_SUCCESS && continuable_err(retval)) { + LDAPMessage *entry; + + DBG_PRINT2("Find parent groups of \"%s\"\n", userdn); + + /* Modify the filter to include the objectclass check */ + sprintf(filter, ldapu_strings[LDAPU_STR_FILTER_MEMBER_RECURSE], + member_filter); + retval = ldapu_find(ld, base, LDAP_SCOPE_SUBTREE, filter, + attrs, attrsonly, &res); + + if (retval == LDAPU_SUCCESS || retval == LDAPU_ERR_MULTIPLE_MATCHES) { + /* Found at least one group the userdn is member of */ + + if (!res) { + /* this should never happen */ + retval = LDAPU_ERR_EMPTY_LDAP_RESULT; + } + else { + retval = LDAPU_ERR_MISSING_RES_ENTRY; + + for (entry = ldap_first_entry(ld, res); entry != NULL; + entry = ldap_next_entry(ld, entry)) + { + char *dn = ldap_get_dn(ld, entry); + + retval = ldapu_auth_udn_gdn_recurse(ld, dn, groupdn, + base, recurse_cnt+1); + ldap_memfree(dn); + + if (retval == LDAPU_SUCCESS || !continuable_err(retval)) { + break; + } + } + } + } + + if (res) ldap_msgfree(res); + } + + return retval; +} + +/* + * ldapu_auth_userdn_groupdn: + * Description: + * Checks if the user (userdn) belongs to the given group (groupdn). + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * userdn User's full DN -- actually it could be a group + * dn to check subgroup membership. + * groupdn Group's full DN + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user is member of the group + * LDAPU_FAILED if user is not a member of the group + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_userdn_groupdn (LDAP *ld, const char *userdn, + const char *groupdn, const char *base) +{ + return ldapu_auth_udn_gdn_recurse(ld, userdn, groupdn, base, 0); +} + + +/* + * ldapu_auth_uid_groupdn: + * Description: + * Similar to ldapu_auth_userdn_groupdn but first maps the uid to a + * full user DN before calling ldapu_auth_userdn_groupdn. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * uid User's login name + * groupdn Group's full DN + * base basedn (where to start the search) + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user is member of the group + * LDAPU_FAILED if user is not a member of the group + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_uid_groupdn (LDAP *ld, const char *uid, const char *groupdn, + const char *base) +{ + int retval; + char *dn; + + /* First find userdn for the given uid and + then call ldapu_auth_userdn_groupdn */ + retval = ldapu_find_userdn(ld, uid, base, &dn); + + if (retval == LDAPU_SUCCESS) { + + retval = ldapu_auth_userdn_groupdn(ld, dn, groupdn, base); + ldap_memfree(dn); + } + + return retval; +} + +/* + * ldapu_auth_uid_groupid: + * Description: + * Similar to ldapu_auth_uid_groupdn but first maps the groupid to a + * full group DN before calling ldapu_auth_uid_groupdn. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * uid User's login name + * groupid Group's name + * base basedn (where to start the search) + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user is member of the group + * LDAPU_FAILED if user is not a member of the group + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_uid_groupid (LDAP *ld, const char *uid, + const char *groupid, const char *base) +{ + int retval; + char *dn; + + /* First find groupdn for the given groupid and + then call ldapu_auth_uid_groupdn */ + retval = ldapu_find_groupdn(ld, groupid, base, &dn); + + if (retval == LDAPU_SUCCESS) { + retval = ldapu_auth_uid_groupdn(ld, uid, dn, base); + ldapu_memfree(ld, dn); + } + + return retval; +} + +/* + * ldapu_auth_userdn_groupid: + * Description: + * Similar to ldapu_auth_userdn_groupdn but first maps the groupid to a + * full group DN before calling ldapu_auth_userdn_groupdn. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * userdn User's full DN + * groupid Group's name + * base basedn (where to start the search) + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user is member of the group + * LDAPU_FAILED if user is not a member of the group + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_userdn_groupid (LDAP *ld, const char *userdn, + const char *groupid, const char *base) +{ + int retval; + char *groupdn; + + /* First find groupdn for the given groupid and + then call ldapu_auth_userdn_groupdn */ + retval = ldapu_find_groupdn(ld, groupid, base, &groupdn); + + if (retval == LDAPU_SUCCESS) { + retval = ldapu_auth_userdn_groupdn(ld, userdn, groupdn, base); + ldap_memfree(groupdn); + } + + return retval; +} + + +LDAPUStr_t *ldapu_str_alloc (const int size) +{ + LDAPUStr_t *lstr = (LDAPUStr_t *)ldapu_malloc(sizeof(LDAPUStr_t)); + + if (!lstr) return 0; + lstr->size = size < 0 ? 1024 : size; + lstr->str = (char *)ldapu_malloc(lstr->size*sizeof(char)); + lstr->len = 0; + lstr->str[lstr->len] = 0; + + return lstr; +} + + +void ldapu_str_free (LDAPUStr_t *lstr) +{ + if (lstr) { + if (lstr->str) ldapu_free(lstr->str); + ldapu_free((void *)lstr); + } +} + + +int ldapu_str_append(LDAPUStr_t *lstr, const char *arg) +{ + int arglen = strlen(arg); + int len = lstr->len + arglen; + + if (len >= lstr->size) { + /* realloc some more */ + lstr->size += arglen > 4095 ? arglen+1 : 4096; + lstr->str = (char *)ldapu_realloc(lstr->str, lstr->size); + if (!lstr->str) return LDAPU_ERR_OUT_OF_MEMORY; + } + + memcpy((void *)&(lstr->str[lstr->len]), (void *)arg, arglen); + lstr->len += arglen; + lstr->str[lstr->len] = 0; + return LDAPU_SUCCESS; +} + + +/* + * ldapu_auth_userdn_groupids_recurse: + * Description: + * Checks if the user is member of the given comma separated list of + * group names. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * filter filter to use in the search + * groupids some representation of group names. Example, + * a comma separated names in a string, hash + * table, etc. This function doesn't need to + * know the name of the groups. It calls the + * following function to check if one of the + * groups returned by the search is in the list. + * grpcmpfn group name comparison function. + * base basedn (where to start the search) + * recurse_cnt recursion count to detect circular groups + * group_out if successful, pointer to the user's group + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user is member of one of the groups + * LDAPU_FAILED if user is not a member of the group + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +static int ldapu_auth_userdn_groupids_recurse (LDAP *ld, const char *filter, + void *groupids, + LDAPU_GroupCmpFn_t grpcmpfn, + const char *base, + int recurse_cnt, + char **group_out) +{ + LDAPMessage *res = 0; + const char *attrs[] = { "CN", 0 }; + int attrsonly = 0; + LDAPMessage *entry; + int rv; + int retval; + int i; + int done; + + if (recurse_cnt >= 30) + return LDAPU_ERR_CIRCULAR_GROUPS; + + /* Perform the ldap lookup */ + retval = ldapu_find(ld, base, LDAP_SCOPE_SUBTREE, filter, attrs, + attrsonly, &res); + + if (retval != LDAPU_SUCCESS && retval != LDAPU_ERR_MULTIPLE_MATCHES ) { + /* user is not a member of any group */ + if (res) ldap_msgfree(res); + return retval; + } + + retval = LDAPU_FAILED; + done = 0; + + /* check if one of the matched groups is one of the given groups */ + for (entry = ldap_first_entry(ld, res); entry != NULL && !done; + entry = ldap_next_entry(ld, entry)) + { + struct berval **bvals; + + if ((bvals = ldap_get_values_len(ld, entry, "CN")) == NULL) { + /* This shouldn't happen */ + retval = LDAPU_ERR_MISSING_ATTR_VAL; + continue; + } + + /* "CN" may have multiple values */ + /* Check each value of "CN" against the 'groupids' */ + for ( i = 0; bvals[i] != NULL; i++ ) { + rv = (*grpcmpfn)(groupids, bvals[i]->bv_val, bvals[i]->bv_len); + if (rv == LDAPU_SUCCESS) { + char *group = (char *)ldapu_malloc(bvals[i]->bv_len+1); + + if (!group) { + retval = LDAPU_ERR_OUT_OF_MEMORY; + } + else { + strncpy(group, bvals[i]->bv_val, bvals[i]->bv_len); + group[bvals[i]->bv_len] = 0; + *group_out = group; + retval = LDAPU_SUCCESS; + } + done = 1; /* exit from the outer loop too */ + break; + } + } + + ldap_value_free_len(bvals); + } + + if (retval == LDAPU_FAILED) { + /* None of the matched groups is in 'groupids' */ + /* Perform the nested group membership check */ + LDAPUStr_t *filter1; + LDAPUStr_t *filter2; + char *rfilter = 0; + int rlen; + /* Finally we need a filter which looks like: + (| (& (objectclass=groupofuniquenames) + (| (uniquemember=<grp1dn>)(uniquemember=<grp2dn>) ...)) + (& (objectclass=groupofnames) + (| (member=<grp1dn>)(member=<grp2dn>) ...))) + Construct 2 sub-filters first as follows: + (uniquemember=<grp1dn>)(uniquemember=<grp2dn>)... AND + (member=<grp1dn>)(member=<grp2dn>)... + Then insert them in the main filter. + */ + filter1 = ldapu_str_alloc(1024); + filter2 = ldapu_str_alloc(1024); + if (!filter1 || !filter2) return LDAPU_ERR_OUT_OF_MEMORY; + rv = LDAPU_SUCCESS; + + for (entry = ldap_first_entry(ld, res); entry != NULL; + entry = ldap_next_entry(ld, entry)) + { + char *dn = ldap_get_dn(ld, entry); + if (((rv = ldapu_str_append(filter1, "(uniquemember=")) + != LDAPU_SUCCESS) || + ((rv = ldapu_str_append(filter1, dn)) != LDAPU_SUCCESS) || + ((rv = ldapu_str_append(filter1, ")")) != LDAPU_SUCCESS) || + ((rv = ldapu_str_append(filter2, "(member=")) + != LDAPU_SUCCESS) || + ((rv = ldapu_str_append(filter2, dn)) != LDAPU_SUCCESS) || + ((rv = ldapu_str_append(filter2, ")")) != LDAPU_SUCCESS)) + { + ldap_memfree(dn); + break; + } + ldap_memfree(dn); + } + + if (rv != LDAPU_SUCCESS) { + /* something went wrong in appending to filter1 or filter2 */ + ldapu_str_free(filter1); + ldapu_str_free(filter2); + retval = rv; + } + else { + /* Insert the 2 filters in the main filter */ + rlen = filter1->len + filter2->len + + strlen("(| (& (objectclass=groupofuniquenames)" + "(| ))" + "(& (objectclass=groupofnames)" + "(| )))") + 1; + rfilter = (char *)ldapu_malloc(rlen); + if (!rfilter) return LDAPU_ERR_OUT_OF_MEMORY; + sprintf(rfilter, + "(| (& (objectclass=groupofuniquenames)" + "(| %s))" + "(& (objectclass=groupofnames)" + "(| %s)))", + filter1->str, filter2->str); + ldapu_str_free(filter1); + ldapu_str_free(filter2); + retval = ldapu_auth_userdn_groupids_recurse(ld, rfilter, groupids, + grpcmpfn, base, + ++recurse_cnt, + group_out); + ldapu_free(rfilter); + } + + } + + if (res) ldap_msgfree(res); + return retval; +} + +/* + * ldapu_auth_userdn_groupids: + * Description: + * Checks if the user is member of the given comma separated list of + * group names. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * userdn User's full DN + * groupids some representation of group names. Example, + * a comma separated names in a string, hash + * table, etc. This function doesn't need to + * know the name of the groups. It calls the + * following function to check if one of the + * groups returned by the search is in the list. + * grpcmpfn group name comparison function. + * base basedn (where to start the search) + * group_out if successful, pointer to the user's group + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user is member of one of the groups + * LDAPU_FAILED if user is not a member of the group + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_userdn_groupids (LDAP *ld, const char *userdn, + void *groupids, + LDAPU_GroupCmpFn_t grpcmpfn, + const char *base, + char **group_out) +{ + char *filter; + int len; + int rv; + + *group_out = 0; + /* allocate a big enough filter */ + /* The filter looks like: + (| (& (objectclass=groupofuniquenames)(uniquemember=<userdn>)) + (& (objectclass=groupofnames)(member=<userdn>))) + */ + + len = 2 * strlen(userdn) + 1 + + strlen("(| (& (objectclass=groupofuniquenames)(uniquemember=))" + "(& (objectclass=groupofnames)(member=)))"); + filter = (char *)ldapu_malloc(len); + + if (!filter) return LDAPU_ERR_OUT_OF_MEMORY; + + sprintf(filter, "(| (& (objectclass=groupofuniquenames)(uniquemember=%s))" + "(& (objectclass=groupofnames)(member=%s)))", + userdn, userdn); + + rv = ldapu_auth_userdn_groupids_recurse(ld, filter, groupids, + grpcmpfn, base, + 0, group_out); + + ldapu_free(filter); + return rv; +} + + +/* + * ldapu_auth_userdn_attrfilter: + * Description: + * Checks if the user's entry has the given attributes + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * userdn User's full DN + * attrfilter attribute filter + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user is member of the group + * LDAPU_FAILED if user is not a member of the group + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_userdn_attrfilter (LDAP *ld, const char *userdn, + const char *attrfilter) +{ + const char *base = userdn; + int scope = LDAP_SCOPE_BASE; + const char *filter = attrfilter; + const char **attrs = default_search_attrs; + int attrsonly = default_search_attrsonly; + LDAPMessage *res = 0; + int retval; + + retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, &res); + + if (res) ldapu_msgfree(ld, res); + + return retval; +} + +/* + * ldapu_auth_uid_attrfilter: + * Description: + * Checks if the user's entry has the given attributes. First maps + the uid to userdn. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * uid User's name + * attrfilter attribute filter + * base basedn (where to start the search) + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user is member of the group + * LDAPU_FAILED if user is not a member of the group + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_uid_attrfilter (LDAP *ld, const char *uid, const char *attrfilter, + const char *base) +{ + int scope = LDAP_SCOPE_SUBTREE; + char filter[ BUFSIZ ]; + const char **attrs = default_search_attrs; + int attrsonly = default_search_attrsonly; + LDAPMessage *res = 0; + int retval; + + /* setup filter as (& (uid=<uid>) (attrfilter)) */ + if (*attrfilter == '(') + sprintf(filter, "(& (uid=%s) %s)", uid, attrfilter); + else + sprintf(filter, "(& (uid=%s) (%s))", uid, attrfilter); + + retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, &res); + + if (res) ldapu_msgfree(ld, res); + + return retval; +} + +/* + * ldapu_auth_userdn_password: + * Description: + * Checks the user's password against LDAP by binding using the + * userdn and the password. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * userdn User's full DN + * password User's password (clear text) + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user credentials are valid + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_userdn_password (LDAP *ld, const char *userdn, const char *password) +{ + LDAPMessage *res = 0; + int retval; + + DBG_PRINT2("\tuserdn:\t\"%s\"\n", userdn); + DBG_PRINT2("\tpassword:\t\"%s\"\n", password); + + retval = ldap_simple_bind_s(ld, userdn, password); + + if (retval != LDAP_SUCCESS) + { + DBG_PRINT2("ldap_simple_bind_s: %s\n", ldap_err2string(retval)); + return(retval); + } + + return LDAPU_SUCCESS; +} + +/* + * ldapu_auth_uid_password: + * Description: + * First converts the uid to userdn and calls + * ldapu_auth_userdn_password. + * Arguments: + * ld Pointer to LDAP (assumes connection has been + * established and the client has called the + * appropriate bind routine) + * uid User's name + * password User's password (clear text) + * Return Values: (same as ldapu_find) + * LDAPU_SUCCESS if user credentials are valid + * <rv> if error, where <rv> can be passed to + * ldap_err2string to get an error string. + */ +int ldapu_auth_uid_password (LDAP *ld, const char *uid, + const char *password, const char *base) +{ + int retval; + char *dn; + + /* First find userdn for the given uid and + then call ldapu_auth_userdn_password */ + retval = ldapu_find_userdn(ld, uid, base, &dn); + + if (retval == LDAPU_SUCCESS) { + retval = ldapu_auth_userdn_password(ld, dn, password); + ldapu_memfree(ld, dn); + } + + return retval; +} + + +/* ldapu_string_set -- + * This function is not tested yet for its usefulness. This is to be used to + * customize the strings used in the LDAP searches performed through + * 'ldaputil'. This could also be extended to setting customized error + * messages (and even i18n equivalent of error messages). + */ +NSAPI_PUBLIC int ldapu_string_set (const int type, const char *filter) +{ + if (!filter || !*filter) return LDAPU_ERR_INVALID_STRING; + + if (type < 0 || type >= LDAPU_STR_MAX_INDEX) + return LDAPU_ERR_INVALID_STRING_INDEX; + + ldapu_strings[type] = strdup(filter); + + if (!ldapu_strings[type]) return LDAPU_ERR_OUT_OF_MEMORY; + + return LDAPU_SUCCESS; +} + + +NSAPI_PUBLIC const char *ldapu_string_get (const int type) +{ + if (type < 0 || type >= LDAPU_STR_MAX_INDEX) + return 0; + + return ldapu_strings[type]; +} |