diff options
| author | Ken Raeburn <raeburn@mit.edu> | 2006-07-18 00:40:19 +0000 |
|---|---|---|
| committer | Ken Raeburn <raeburn@mit.edu> | 2006-07-18 00:40:19 +0000 |
| commit | 42d9d6ab320ee3a661fe21472be542acd542d5be (patch) | |
| tree | ab3049772f6c2cceaf8956cf0a1172e0f6ddc12a /src/plugins/kdb/ldap | |
| parent | 6eb696bf5669ec60b55927d974b48bbadc62bc66 (diff) | |
| download | krb5-42d9d6ab320ee3a661fe21472be542acd542d5be.tar.gz krb5-42d9d6ab320ee3a661fe21472be542acd542d5be.tar.xz krb5-42d9d6ab320ee3a661fe21472be542acd542d5be.zip | |
Merge remaining changes from LDAP integration branch
svn+ssh://svn.mit.edu/krb5/branches/ldap-integ@18333.
* plugins/kdb/ldap: New directory.
* aclocal.m4 (WITH_LDAP): New macro.
(CONFIG_RULES): Invoke it.
* configure.in: Test ldap option, maybe configure and generate makefiles for
new directories, and set and substitute ldap_plugin_dir.
* Makefile.in (SUBDIRS): Add @ldap_plugin_dir@.
* kdc/krb5kdc.M, kadmin/server/kadmind.M, kadmin/cli/kadmin.M,
config-files/krb5.conf.M: Document LDAP changes (new options, config file
entries, etc).
* lib/kdb/kdb5.c (kdb_load_library): Put more info in error message.
* lib/kadm5/admin.h (KADM5_CPW_FUNCTION, KADM5_RANDKEY_USED,
KADM5_CONFIG_PASSWD_SERVER): New macros, disabled for now.
(struct _kadm5_config_params): New field kpasswd_server, commented out for now.
* lib/krb5/error_tables/kdb5_err.et: Add error codes KRB5_KDB_ACCESS_ERROR,
KRB5_KDB_INTERNAL_ERROR, KRB5_KDB_CONSTRAINT_VIOLATION.
ticket: 2935
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18334 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/plugins/kdb/ldap')
54 files changed, 20682 insertions, 0 deletions
diff --git a/src/plugins/kdb/ldap/ChangeLog b/src/plugins/kdb/ldap/ChangeLog new file mode 100644 index 000000000..9766515e0 --- /dev/null +++ b/src/plugins/kdb/ldap/ChangeLog @@ -0,0 +1,51 @@ +2006-04-08 Ken Raeburn <raeburn@mit.edu> + + * ldap_exp.c: Include k5-int.h before testing HAVE_UNISTD_H. + +2006-03-21 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in (SHLIB_EXPDEPS, SHLIB_EXPLIBS): Add kdb_ldap + and support libraries. + +2006-03-17 Ken Raeburn <raeburn@mit.edu> + + * Most files moved to lib/kdb_ldap. + * Makefile.in: Updated. + * kldap.exports: Only export the one symbol now defined. + + * ldap_misc.c (format_d): New function. + (krb5_add_int_arr_mem_ldap_mod, krb5_add_int_mem_ldap_mod): Use it + instead of asprintf. + + * Makefile.in: Remove all references to DB library. + (MODULE_INSTALL_DIR): Define. + +2006-03-16 Ken Raeburn <raeburn@mit.edu> + + * ldap_exp.c: Wrap all functions with mutex protection. + + * configure.in: Don't link against db library on AIX. If the + "lber" library is not found, then warn about that, not about the + ldap library. + +2006-03-14 Ken Raeburn <raeburn@mit.edu> + + * ldap_err.h (LDAP_ERR_BASE, MAX_NEG, LDAP_TO_KDB_ERR): Unused + macros deleted. + +2006-03-07 Ken Raeburn <raeburn@mit.edu> + + * kdb_ldap.h (HNDL_LOCK, HNDL_UNLOCK): Remove unneeded trailing + semicolon. + (timezone): Remove unused declaration. + (STORE16_INT, STORE32_INT, UNSTORE16_INT, UNSTORE32_INT): Use + inline functions already defined in k5-int.h. + +2006-01-29 Sam Hartman <hartmans@mit.edu> + + * ldap_exp.c (krb5_db_vftabl_kldap): Remove thread safe flag + + * ldap_err.c: Ignore LDAP_X_ERROR if not supported by version of OpenLDAP in use + + * ldap_principal2.c: Accept LDAP_OPT_ERROR_NUMBER as a less-preferred synonym for LDAP_OPT_RESULT_CODE + diff --git a/src/plugins/kdb/ldap/Makefile.in b/src/plugins/kdb/ldap/Makefile.in new file mode 100644 index 000000000..b7378bd5b --- /dev/null +++ b/src/plugins/kdb/ldap/Makefile.in @@ -0,0 +1,64 @@ +thisconfigdir=../../.. +myfulldir=plugins/kdb/ldap +mydir=plugins/kdb/ldap +BUILDTOP=$(REL)..$(S)..$(S).. +KRB5_RUN_ENV = @KRB5_RUN_ENV@ +KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ; +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) +DEFS = +MODULE_INSTALL_DIR = $(KRB5_DB_MODULE_DIR) + +LOCAL_SUBDIRS= libkdb_ldap ldap_util + +LOCALINCLUDES = -I../../../lib/kdb -I$(srcdir)/../../../lib/kdb \ + -I$(srcdir)/libkdb_ldap + +LIBBASE=kldap +LIBMAJOR=0 +LIBMINOR=0 +SO_EXT=.so +RELDIR=../plugins/kdb/ldap +# Depends on libk5crypto and libkrb5 +# Also on gssrpc, for xdr stuff. +SHLIB_EXPDEPS = \ + $(TOPLIBD)/libkdb_ldap$(SHLIBEXT) \ + $(GSSRPC_DEPLIBS) \ + $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ + $(TOPLIBD)/libkrb5$(SHLIBEXT) \ + $(TOPLIBD)/lib$(SUPPORT_LIBNAME)$(SHLIBEXT) +SHLIB_EXPLIBS= -lkdb_ldap $(GSSRPC_LIBS) -lkrb5 -lcom_err -lk5crypto -lkrb5support $(LIBS) +SHLIB_DIRS=-L$(TOPLIBD) +SHLIB_RDIRS=$(KRB5_LIBDIR) + +$(TOPLIBD)/libkdb_ldap$(SHLIBEXT): all-recurse + +SRCS= $(srcdir)/ldap_exp.c + +STOBJLISTS=OBJS.ST +STLIBOBJS= ldap_exp.o + +all-unix:: $(LIBBASE)$(SO_EXT) +install-unix:: install-libs +clean-unix:: clean-libs clean-libobjs + +# @libnover_frag@ +# @libobj_frag@ + +# +++ Dependency line eater +++ +# +# Makefile dependencies follow. This must be the last section in +# the Makefile.in file +# +ldap_exp.so ldap_exp.po $(OUTPRE)ldap_exp.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h $(srcdir)/libkdb_ldap/kdb_ldap.h \ + $(srcdir)/libkdb_ldap/ldap_krbcontainer.h $(srcdir)/libkdb_ldap/ldap_principal.h \ + $(srcdir)/libkdb_ldap/ldap_pwd_policy.h $(srcdir)/libkdb_ldap/ldap_realm.h \ + $(srcdir)/libkdb_ldap/ldap_tkt_policy.h ldap_exp.c diff --git a/src/plugins/kdb/ldap/kldap.exports b/src/plugins/kdb/ldap/kldap.exports new file mode 100644 index 000000000..f2b7c1119 --- /dev/null +++ b/src/plugins/kdb/ldap/kldap.exports @@ -0,0 +1 @@ +kdb_function_table diff --git a/src/plugins/kdb/ldap/ldap_exp.c b/src/plugins/kdb/ldap/ldap_exp.c new file mode 100644 index 000000000..15aea0a60 --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_exp.c @@ -0,0 +1,85 @@ +/* + * lib/kdb/kdb_ldap/ldap_exp.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "k5-int.h" +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdio.h> +#include <errno.h> +#include <utime.h> +#include <kdb5.h> +#include "kdb_ldap.h" +#include "ldap_principal.h" +#include "ldap_pwd_policy.h" + +/* + * Exposed API + */ + +kdb_vftabl kdb_function_table = { + 1, /* major version number 1 */ + 0, /* minor version number 0 */ + /* init_library */ krb5_ldap_lib_init, + /* fini_library */ krb5_ldap_lib_cleanup, + /* init_module */ krb5_ldap_open, + /* fini_module */ krb5_ldap_close, + /* db_create */ NULL, + /* db_destroy */ NULL, + /* db_get_age */ krb5_ldap_db_get_age, + /* db_set_option */ NULL, + /* db_lock */ NULL, + /* db_unlock */ NULL, + /* db_get_principal */ krb5_ldap_get_principal, + /* db_free_principal */ krb5_ldap_free_principal, + /* db_put_principal */ krb5_ldap_put_principal, + /* db_delete_principal */ krb5_ldap_delete_principal, + /* db_iterate */ krb5_ldap_iterate, + /* db_create_policy */ krb5_ldap_create_password_policy, + /* db_get_policy */ krb5_ldap_get_password_policy, + /* db_put_policy */ krb5_ldap_put_password_policy, + /* db_iter_policy */ krb5_ldap_iterate_password_policy, + /* db_delete_policy */ krb5_ldap_delete_password_policy, + /* db_free_policy */ krb5_ldap_free_password_policy, + /* db_supported_realms */ NULL, + /* db_free_supported_realms */ NULL, + /* errcode_2_string */ NULL, + /* db_alloc */ krb5_ldap_alloc, + /* db_free */ krb5_ldap_free, + /* set_master_key */ krb5_ldap_set_mkey, + /* get_master_key */ krb5_ldap_get_mkey, + /* setup_master_key_name */ NULL, + /* store_master_key */ NULL, + /* fetch_master_key */ NULL /* krb5_ldap_fetch_mkey */, + /* verify_master_key */ NULL /* krb5_ldap_verify_master_key */, + /* Search enc type */ NULL, + /* Change pwd */ NULL + +}; diff --git a/src/plugins/kdb/ldap/ldap_util/ChangeLog b/src/plugins/kdb/ldap/ldap_util/ChangeLog new file mode 100644 index 000000000..b72a851c2 --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/ChangeLog @@ -0,0 +1,12 @@ +2006-04-08 Ken Raeburn <raeburn@mit.edu> + + * getdate.c: Deleted. + * Makefile.in ($(PROG)): Link against getdate.o from cli + directory. + +2006-03-17 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in (LOCALINCLUDES): Look for kdb ldap headers in new + location. + (KDB_DEP_LIB): Refer to kdb ldap library under new name. + diff --git a/src/plugins/kdb/ldap/ldap_util/Makefile.in b/src/plugins/kdb/ldap/ldap_util/Makefile.in new file mode 100644 index 000000000..7d3956f7a --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/Makefile.in @@ -0,0 +1,28 @@ +thisconfigdir=../../../.. +myfulldir=plugins/kdb/ldap/ldap_util +mydir=plugins/kdb/ldap/ldap_util +BUILDTOP=$(REL)..$(S)..$(S)..$(S).. +DEFINES = -DKDB4_DISABLE +DEFS= +LOCALINCLUDES = -I. @KRB4_INCLUDES@ -I$(srcdir)/../libkdb_ldap -I$(SRCTOP)/lib/kdb +PROG_LIBPATH=-L$(TOPLIBD) $(KRB4_LIBPATH) +PROG_RPATH=$(KRB5_LIBDIR) +#KDB_DEP_LIB=$(DL_LIB) $(THREAD_LINKOPTS) +KDB_DEP_LIB=$(DL_LIB) -lkdb_ldap $(THREAD_LINKOPTS) + +PROG = kdb5_ldap_util +OBJS = kdb5_ldap_util.o kdb5_ldap_list.o kdb5_ldap_realm.o kdb5_ldap_policy.o kdb5_ldap_services.o + +GETDATE = ../../../../kadmin/cli/getdate.o + +all:: $(PROG) + +$(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB4COMPAT_DEPLIBS) $(GETDATE) + $(CC_LINK) -o $(PROG) $(OBJS) $(GETDATE) \ + $(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB4COMPAT_LIBS) + +install:: + $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG) + +clean:: + $(RM) $(PROG) $(OBJS) diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_list.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_list.c new file mode 100644 index 000000000..733b7ab81 --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_list.c @@ -0,0 +1,289 @@ +/* + * kadmin/ldap_util/kdb5_ldap_list.c + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +/* + * Miscellaneous functions for managing the string and integer lists + */ + +#include <k5-int.h> +#include "kdb5_ldap_list.h" + +/* + * Counts the number of entries in the given array of strings + */ +int list_count_str_array(char **list) +{ + int i = 0; + + if (list == NULL) + return 0; + + for (i = 0; *list != NULL; list++) { + i++; + } + + return i; +} + + +/* + * Counts the number of entries in the given array of integers + */ +int list_count_int_array(int *list) +{ + int i = 0; + + if (list == NULL) + return 0; + + for (i = 0; *list != END_OF_LIST; list++) { + i++; + } + + return i; +} + + +/* + * Frees the entries in a given list and not the list pointer + */ +void krb5_free_list_entries(list) + char **list; +{ + if (list == NULL) + return; + for(; *list != NULL; list++) { + free(*list); + *list = NULL; + } + + return; +} + + +/* + * Tokenize the given string based on the delimiter provided + * and return the result as a list + */ +krb5_error_code +krb5_parse_list(buffer, delimiter, list) + char *buffer; + char *delimiter; + char **list; +{ + char *str = NULL; + char *token = NULL; + char *ptrptr = NULL; + char **plist = list; + krb5_error_code retval = 0; + int count = 0; + + if ((buffer == NULL) || (list == NULL) || (delimiter == NULL)) { + return EINVAL; + } + + str = strdup(buffer); + if (str == NULL) + return ENOMEM; + + token = strtok_r(str, delimiter, &ptrptr); + for (count = 1; ((token != NULL) && (count < MAX_LIST_ENTRIES)); + plist++, count++) { + *plist = strdup(token); + if (*plist == NULL) { + retval = ENOMEM; + goto cleanup; + } + token = strtok_r(NULL, delimiter, &ptrptr); + } + *plist = NULL; + +cleanup: + if(str) { + free(str); + str = NULL; + } + if (retval) + krb5_free_list_entries(list); + + return retval; +} + + +int compare_int(m1, m2) + const void *m1; + const void *m2; +{ + int mi1 = *(const int *)m1; + int mi2 = *(const int *)m2; + + return (mi1 - mi2); +} + + +/* + * Modifies the destination list to contain or not to contain the + * entries present in the source list, depending on the mode + * (ADD or DELETE). + */ +void list_modify_str_array(destlist, sourcelist, mode) + char ***destlist; + const char **sourcelist; + int mode; +{ + char **dlist = NULL, **tmplist = NULL; + const char **slist = NULL; + int dcount = 0, scount = 0, copycount = 0; + int found = 0; + + if ((destlist == NULL) || (*destlist == NULL) || (sourcelist == NULL)) + return; + + /* We need to add every entry present in the source list to + * the destination list */ + if (mode == LIST_MODE_ADD) { + /* Traverse throught the end of destlist for appending */ + for(dlist = *destlist, dcount = 0; *dlist != NULL; + dlist++, dcount++) { + ; /* NULL statement */ + } + /* Count the number of entries in the source list */ + for(slist = sourcelist, scount = 0; *slist != NULL; + slist++, scount++) { + ; /* NULL statement */ + } + /* Reset the slist pointer to the start of source list */ + slist = sourcelist; + + /* Now append the source list to the existing destlist */ + if ((dcount + scount) < MAX_LIST_ENTRIES) + copycount = scount; + else + /* Leave the last entry for list terminator(=NULL) */ + copycount = (MAX_LIST_ENTRIES -1) - dcount; + + memcpy(dlist, slist, (sizeof(char *) * copycount)); + dlist += copycount; + *dlist = NULL; + } + else if (mode == LIST_MODE_DELETE) { + /* We need to delete every entry present in the source list + * from the destination list */ + for(slist = sourcelist; *slist != NULL; slist++) { + for(dlist = *destlist; *dlist != NULL; dlist++) { + found = 0; /* value not found */ + /* DN is case insensitive string */ + if (strcasecmp(*dlist, *slist) == 0) { + found = 1; + free(*dlist); + /* Advance the rest of the entries by one */ + for(tmplist = dlist; *tmplist != NULL; tmplist++) { + *tmplist = *(tmplist+1); + } + break; + } + } + } + } + + return; +} + + +/* + * Modifies the destination list to contain or not to contain the + * entries present in the source list, depending on the mode + * (ADD or DELETE). where the list is array of integers. + */ +int list_modify_int_array(destlist, sourcelist, mode) + int *destlist; + const int *sourcelist; + int mode; +{ + int *dlist = NULL, *tmplist = NULL; + const int *slist = NULL; + int dcount = 0, scount = 0, copycount = 0; + int tcount = 0; + + if ((destlist == NULL) || (sourcelist == NULL)) + return 0; + + /* We need to add every entry present in the source list to the + * destination list */ + if (mode == LIST_MODE_ADD) { + /* Traverse throught the end of destlist for appending */ + for(dlist = destlist, dcount = 0; *dlist != END_OF_LIST; + dlist++, dcount++) + ; /* NULL statement */ + + /* Count the number of entries in the source list */ + for(slist = sourcelist, scount = 0; *slist != END_OF_LIST; + slist++, scount++) + ; /* NULL statement */ + + /* Reset the slist pointer to the start of source list */ + slist = sourcelist; + + /* Now append the source list to the existing destlist */ + if ((dcount + scount) < MAX_LIST_ENTRIES) + copycount = scount; + else + /* Leave the last entry for list terminator(=NULL) */ + copycount = (MAX_LIST_ENTRIES -1) - dcount; + + memcpy(dlist, slist, (sizeof(int) * copycount)); + dlist += copycount; + *dlist = END_OF_LIST; + tcount = dcount + copycount; + } + else if (mode == LIST_MODE_DELETE) { + /* We need to delete every entry present in the source list from + * the destination list */ + for(slist = sourcelist; *slist != END_OF_LIST; slist++) { + for(dlist = destlist; *dlist != END_OF_LIST; dlist++) { + if (*dlist == *slist) { + /* Advance the rest of the entries by one */ + for(tmplist = dlist; *tmplist != END_OF_LIST; tmplist++) { + *tmplist = *(tmplist+1); + } + break; + } + } + } + /* count the number of entries */ + for(dlist = destlist, tcount = 0; *dlist != END_OF_LIST; dlist++) { + tcount++; + } + } + + return tcount; +} + diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_list.h b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_list.h new file mode 100644 index 000000000..b6402e592 --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_list.h @@ -0,0 +1,47 @@ + +/* + * kadmin/ldap_util/kdb5_ldap_list.h + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + + +#define MAX_LIST_ENTRIES 64 +#define END_OF_LIST -1 /* End of List */ +#define LIST_DELIMITER ":" /* List entry separator */ +#define LIST_MODE_ADD 0x701 /* Add to the List */ +#define LIST_MODE_DELETE 0x702 /* Delete from the list */ +#define MAX_LEN_LIST_ENTRY 512 /* Max len of an entry */ + +extern krb5_error_code krb5_parse_list(char *buffer, char *delimiter, char **list); +extern void krb5_free_list_entries(char **list); +extern void list_modify_str_array(char ***destlist, const char **sourcelist, int mode); +extern int list_modify_int_array(int *destlist, const int *sourcelist, int mode); +extern int list_count_str_array(char **list); +extern int list_count_int_array(int *list); +extern int compare_int(const void*, const void *); diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.c new file mode 100644 index 000000000..71d4863aa --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.c @@ -0,0 +1,870 @@ +/* + * kadmin/ldap_util/kdb5_ldap_policy.c + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +/* + * Create / Delete / Modify / View / List policy objects. + */ + +#include <stdio.h> +#include <time.h> +#include <k5-int.h> +#include "kdb5_ldap_util.h" +#include "kdb5_ldap_list.h" +#include "ldap_tkt_policy.h" + +static void print_policy_params(krb5_ldap_policy_params *policyparams, int mask); +static char *strdur(time_t duration); + +/* get_date() function used from src/kadmin/ldap_util/getdate.c */ + +extern char *yes; + + +/* + * This function will create a ticket policy object with the + * specified attributes. + */ +void +kdb5_ldap_create_policy(argc, argv) + int argc; + char *argv[]; +{ + char *me = argv[0]; + krb5_error_code retval = 0; + krb5_ldap_policy_params *policyparams = NULL; + krb5_boolean print_usage = FALSE; + krb5_boolean no_msg = FALSE; + int mask = 0; + time_t date = 0; + time_t now = 0; + int i = 0; + + /* Check for number of arguments */ + if ((argc < 2) || (argc > 16)) { + goto err_usage; + } + + /* Allocate memory for policy parameters structure */ + policyparams = (krb5_ldap_policy_params*) calloc(1, sizeof(krb5_ldap_policy_params)); + if (policyparams == NULL) { + retval = ENOMEM; + goto cleanup; + } + + /* Get current time */ + time (&now); + + /* Parse all arguments */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-maxtktlife")) { + if (++i > argc - 1) + goto err_usage; + + date = get_date(argv[i], NULL); + if (date == (time_t)(-1)) { + retval = EINVAL; + com_err (me, retval, "while providing time specification"); + goto err_nomsg; + } + + policyparams->maxtktlife = date - now; + + mask |= LDAP_POLICY_MAXTKTLIFE; + } + else if (!strcmp(argv[i], "-maxrenewlife")) { + if (++i > argc - 1) + goto err_usage; + + date = get_date(argv[i], NULL); + if (date == (time_t)(-1)) { + retval = EINVAL; + com_err (me, retval, "while providing time specification"); + goto err_nomsg; + } + + policyparams->maxrenewlife = date - now; + + mask |= LDAP_POLICY_MAXRENEWLIFE; + } + else if (!strcmp((argv[i] + 1), "allow_postdated")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_POSTDATED); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_POSTDATED; + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_forwardable")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_FORWARDABLE); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_FORWARDABLE; + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_renewable")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_RENEWABLE); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_RENEWABLE; + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_proxiable")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_PROXIABLE); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_PROXIABLE; + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_dup_skey")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_DUP_SKEY); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_DUP_SKEY; + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "requires_preauth")) { + if (*(argv[i]) == '+') + policyparams->tktflags |= KRB5_KDB_REQUIRES_PRE_AUTH; + else if (*(argv[i]) == '-') + policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PRE_AUTH); + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "requires_hwauth")) { + if (*(argv[i]) == '+') + policyparams->tktflags |= KRB5_KDB_REQUIRES_HW_AUTH; + else if (*(argv[i]) == '-') + policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_HW_AUTH); + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_svr")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_SVR); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_SVR; + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_tgs_req")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_TGT_BASED); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_TGT_BASED; + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_tix")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_ALL_TIX); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_ALL_TIX; + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "needchange")) { + if (*(argv[i]) == '+') + policyparams->tktflags |= KRB5_KDB_REQUIRES_PWCHANGE; + else if (*(argv[i]) == '-') + policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PWCHANGE); + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "password_changing_service")) { + if (*(argv[i]) == '+') + policyparams->tktflags |= KRB5_KDB_PWCHANGE_SERVICE; + else if (*(argv[i]) == '-') + policyparams->tktflags &= (int)(~KRB5_KDB_PWCHANGE_SERVICE); + else + goto err_usage; + + mask |= LDAP_POLICY_TKTFLAGS; + } + else { /* Any other argument must be policy DN */ + /* First check if policy DN is already provided -- + if so, there's a usage error */ + if (policyparams->policydn != NULL) + goto err_usage; + + /* If not present already, fill up policy DN */ + policyparams->policydn = strdup(argv[i]); + if (policyparams->policydn == NULL) { + retval = ENOMEM; + com_err(me, retval, "while creating policy object"); + goto err_nomsg; + } + } + } + + /* policy DN is a mandatory argument. If not provided, print usage */ + if (policyparams->policydn == NULL) + goto err_usage; + + /* Create object with all attributes provided */ + if ((retval = krb5_ldap_create_policy(util_context, policyparams, mask)) != 0) + goto cleanup; + + goto cleanup; + +err_usage: + print_usage = TRUE; + +err_nomsg: + no_msg = TRUE; + +cleanup: + /* Clean-up structure */ + krb5_ldap_free_policy (util_context, policyparams); + + if (print_usage) + db_usage(CREATE_POLICY); + + if (retval) { + if (!no_msg) + com_err(me, retval, "while creating policy object"); + + exit_status++; + } + + return; +} + + +/* + * This function will destroy the specified ticket policy + * object interactively, unless forced through an option. + */ +void +kdb5_ldap_destroy_policy(argc, argv) + int argc; + char *argv[]; +{ + char *me = argv[0]; + krb5_error_code retval = 0; + krb5_ldap_policy_params *policyparams = NULL; + krb5_boolean print_usage = FALSE; + krb5_boolean no_msg = FALSE; + char *policydn = NULL; + int mask = 0; + int force = 0; + char buf[5] = {0}; + int i = 0; + + if ((argc < 2) || (argc > 3)) { + goto err_usage; + } + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-force") == 0) { + force++; + } + else { /* Any other argument must be policy DN */ + /* First check if policy DN is already provided -- + if so, there's a usage error */ + if (policydn != NULL) + goto err_usage; + + /* If not present already, fill up policy DN */ + policydn = strdup(argv[i]); + if (policydn == NULL) { + retval = ENOMEM; + com_err(me, retval, "while destroying policy object"); + goto err_nomsg; + } + } + } + + if (policydn == NULL) + goto err_usage; + + if (!force) { + printf("This will delete the policy object '%s', are you sure?\n", policydn); + printf("(type 'yes' to confirm)? "); + + if (fgets(buf, sizeof(buf), stdin) == NULL) { + retval = EINVAL; + goto cleanup; + } + + if (strcmp(buf, yes)) { + exit_status++; + goto cleanup; + } + } + + if ((retval = krb5_ldap_read_policy(util_context, policydn, &policyparams, &mask))) + goto cleanup; + + + if ((retval = krb5_ldap_delete_policy(util_context, policydn, policyparams,&mask))) + goto cleanup; + + printf("** policy object '%s' deleted.\n", policydn); + goto cleanup; + + +err_usage: + print_usage = TRUE; + +err_nomsg: + no_msg = TRUE; + +cleanup: + /* Clean-up structure */ + krb5_ldap_free_policy (util_context, policyparams); + + if (policydn) { + free (policydn); + } + + if (print_usage) { + db_usage(DESTROY_POLICY); + } + + if (retval) { + if (!no_msg) + com_err(me, retval, "while destroying policy object"); + + exit_status++; + } + + return; +} + + +/* + * This function will modify the attributes of a given ticket + * policy object. + */ +void +kdb5_ldap_modify_policy(argc, argv) + int argc; + char *argv[]; +{ + char *me = argv[0]; + krb5_error_code retval = 0; + krb5_ldap_policy_params *policyparams = NULL; + krb5_boolean print_usage = FALSE; + krb5_boolean no_msg = FALSE; + char *policydn = NULL; + int in_mask = 0, out_mask = 0; + time_t date = 0; + time_t now = 0; + int i = 0; + + /* Check for number of arguments -- minimum is 3 + since atleast one parameter should be given in + addition to 'modify_policy' and policy DN */ + if ((argc < 3) || (argc > 16)) { + goto err_usage; + } + + /* Parse all arguments, only to pick up policy DN (Pass 1) */ + for (i = 1; i < argc; i++) { + /* Skip arguments next to 'maxtktlife' + and 'maxrenewlife' arguments */ + if (!strcmp(argv[i], "-maxtktlife")) { + ++i; + } + else if (!strcmp(argv[i], "-maxrenewlife")) { + ++i; + } + /* Do nothing for ticket flag arguments */ + else if (!strcmp((argv[i] + 1), "allow_postdated") || + !strcmp((argv[i] + 1), "allow_forwardable") || + !strcmp((argv[i] + 1), "allow_renewable") || + !strcmp((argv[i] + 1), "allow_proxiable") || + !strcmp((argv[i] + 1), "allow_dup_skey") || + !strcmp((argv[i] + 1), "requires_preauth") || + !strcmp((argv[i] + 1), "requires_hwauth") || + !strcmp((argv[i] + 1), "allow_svr") || + !strcmp((argv[i] + 1), "allow_tgs_req") || + !strcmp((argv[i] + 1), "allow_tix") || + !strcmp((argv[i] + 1), "needchange") || + !strcmp((argv[i] + 1), "password_changing_service")) { + } + else { /* Any other argument must be policy DN */ + /* First check if policy DN is already provided -- + if so, there's a usage error */ + if (policydn != NULL) + goto err_usage; + + /* If not present already, fill up policy DN */ + policydn = strdup(argv[i]); + if (policydn == NULL) { + retval = ENOMEM; + com_err(me, retval, "while modifying policy object"); + goto err_nomsg; + } + } + } + + if (policydn == NULL) + goto err_usage; + + retval = krb5_ldap_read_policy(util_context, policydn, &policyparams, &in_mask); + if (retval) { + com_err(me, retval, "while reading information of policy '%s'", policydn); + goto err_nomsg; + } + + /* Get current time */ + time (&now); + + /* Parse all arguments, but skip policy DN (Pass 2) */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-maxtktlife")) { + if (++i > argc - 1) + goto err_usage; + + date = get_date(argv[i], NULL); + if (date == (time_t)(-1)) { + retval = EINVAL; + com_err (me, retval, "while providing time specification"); + goto err_nomsg; + } + + policyparams->maxtktlife = date - now; + + out_mask |= LDAP_POLICY_MAXTKTLIFE; + } + else if (!strcmp(argv[i], "-maxrenewlife")) { + if (++i > argc - 1) + goto err_usage; + + date = get_date(argv[i], NULL); + if (date == (time_t)(-1)) { + retval = EINVAL; + com_err (me, retval, "while providing time specification"); + goto err_nomsg; + } + + policyparams->maxrenewlife = date - now; + + out_mask |= LDAP_POLICY_MAXRENEWLIFE; + } + else if (!strcmp((argv[i] + 1), "allow_postdated")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_POSTDATED); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_POSTDATED; + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_forwardable")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_FORWARDABLE); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_FORWARDABLE; + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_renewable")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_RENEWABLE); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_RENEWABLE; + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_proxiable")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_PROXIABLE); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_PROXIABLE; + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_dup_skey")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_DUP_SKEY); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_DUP_SKEY; + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "requires_preauth")) { + if (*(argv[i]) == '+') + policyparams->tktflags |= KRB5_KDB_REQUIRES_PRE_AUTH; + else if (*(argv[i]) == '-') + policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PRE_AUTH); + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "requires_hwauth")) { + if (*(argv[i]) == '+') + policyparams->tktflags |= KRB5_KDB_REQUIRES_HW_AUTH; + else if (*(argv[i]) == '-') + policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_HW_AUTH); + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_svr")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_SVR); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_SVR; + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_tgs_req")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_TGT_BASED); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_TGT_BASED; + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "allow_tix")) { + if (*(argv[i]) == '+') + policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_ALL_TIX); + else if (*(argv[i]) == '-') + policyparams->tktflags |= KRB5_KDB_DISALLOW_ALL_TIX; + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "needchange")) { + if (*(argv[i]) == '+') + policyparams->tktflags |= KRB5_KDB_REQUIRES_PWCHANGE; + else if (*(argv[i]) == '-') + policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PWCHANGE); + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else if (!strcmp((argv[i] + 1), "password_changing_service")) { + if (*(argv[i]) == '+') + policyparams->tktflags |= KRB5_KDB_PWCHANGE_SERVICE; + else if (*(argv[i]) == '-') + policyparams->tktflags &= (int)(~KRB5_KDB_PWCHANGE_SERVICE); + else + goto err_usage; + + out_mask |= LDAP_POLICY_TKTFLAGS; + } + else { + /* Any other argument must be policy DN + -- skip it */ + } + } + + /* Modify attributes of object */ + if ((retval = krb5_ldap_modify_policy(util_context, policyparams, out_mask))) + goto cleanup; + + goto cleanup; + +err_usage: + print_usage = TRUE; + +err_nomsg: + no_msg = TRUE; + +cleanup: + /* Clean-up structure */ + krb5_ldap_free_policy (util_context, policyparams); + + if (policydn) + free (policydn); + + if (print_usage) + db_usage(MODIFY_POLICY); + + if (retval) { + if (!no_msg) + com_err(me, retval, "while modifying policy object"); + + exit_status++; + } + + return; +} + + +/* + * This function will display information about the given policy object, + * fetching the information from the LDAP Server. + */ +void +kdb5_ldap_view_policy(argc, argv) + int argc; + char *argv[]; +{ + char *me = argv[0]; + krb5_ldap_policy_params *policyparams = NULL; + krb5_error_code retval = 0; + krb5_boolean print_usage = FALSE; + char *policydn = NULL; + int mask = 0; + + if (argc != 2) { + goto err_usage; + } + + policydn = strdup(argv[1]); + if (policydn == NULL) { + com_err(me, ENOMEM, "while viewing policy"); + exit_status++; + goto cleanup; + } + + if ((retval = krb5_ldap_read_policy(util_context, policydn, &policyparams, &mask))) { + com_err(me, retval, "while viewing policy '%s'", policydn ); + exit_status++; + goto cleanup; + } + + print_policy_params (policyparams, mask); + + goto cleanup; + +err_usage: + print_usage = TRUE; + +cleanup: + krb5_ldap_free_policy (util_context, policyparams); + + if (policydn) + free (policydn); + + if (print_usage) { + db_usage(VIEW_POLICY); + } + + return; +} + + +/* + * This function will print the policy object information to the + * standard output. + */ +static void +print_policy_params(policyparams, mask) + krb5_ldap_policy_params *policyparams; + int mask; +{ + /* Print the policy DN */ + printf("%25s: %s\n", "Ticket policy", policyparams->policydn); + + /* Print max. ticket life and max. renewable life, if present */ + if (mask & LDAP_POLICY_MAXTKTLIFE) + printf("%25s: %s\n", "Maximum ticket life", strdur(policyparams->maxtktlife)); + if (mask & LDAP_POLICY_MAXRENEWLIFE) + printf("%25s: %s\n", "Maximum renewable life", strdur(policyparams->maxrenewlife)); + + /* Service flags are printed */ + printf("%25s: ", "Ticket flags"); + if (mask & LDAP_POLICY_TKTFLAGS) { + int ticketflags = policyparams->tktflags; + + if (ticketflags & KRB5_KDB_DISALLOW_POSTDATED) + printf("%s ","DISALLOW_POSTDATED"); + + if (ticketflags & KRB5_KDB_DISALLOW_FORWARDABLE) + printf("%s ","DISALLOW_FORWARDABLE"); + + if (ticketflags & KRB5_KDB_DISALLOW_RENEWABLE) + printf("%s ","DISALLOW_RENEWABLE"); + + if (ticketflags & KRB5_KDB_DISALLOW_PROXIABLE) + printf("%s ","DISALLOW_PROXIABLE"); + + if (ticketflags & KRB5_KDB_DISALLOW_DUP_SKEY) + printf("%s ","DISALLOW_DUP_SKEY"); + + if (ticketflags & KRB5_KDB_REQUIRES_PRE_AUTH) + printf("%s ","REQUIRES_PRE_AUTH"); + + if (ticketflags & KRB5_KDB_REQUIRES_HW_AUTH) + printf("%s ","REQUIRES_HW_AUTH"); + + if (ticketflags & KRB5_KDB_DISALLOW_SVR) + printf("%s ","DISALLOW_SVR"); + + if (ticketflags & KRB5_KDB_DISALLOW_TGT_BASED) + printf("%s ","DISALLOW_TGT_BASED"); + + if (ticketflags & KRB5_KDB_DISALLOW_ALL_TIX) + printf("%s ","DISALLOW_ALL_TIX"); + + if (ticketflags & KRB5_KDB_REQUIRES_PWCHANGE) + printf("%s ","REQUIRES_PWCHANGE"); + + if (ticketflags & KRB5_KDB_PWCHANGE_SERVICE) + printf("%s ","PWCHANGE_SERVICE"); + } + printf("\n"); + + return; +} + + +/* + * This function will list the DNs of policy objects under a specific + * sub-tree (entire tree by default) + */ +void kdb5_ldap_list_policies(argc, argv) + int argc; + char *argv[]; +{ + char *me = argv[0]; + krb5_error_code retval = 0; + krb5_boolean print_usage = FALSE; + char *basedn = NULL; + char **list = NULL; + char **plist = NULL; + + /* Check for number of arguments */ + if ((argc != 1) && (argc != 3)) { + goto err_usage; + } + + /* Parse base DN argument if present */ + if (argc == 3) { + if (strcmp(argv[1], "-basedn")) + goto err_usage; + + basedn = strdup(argv[2]); + if (basedn == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + + retval = krb5_ldap_list_policy(util_context, basedn, &list); + if ((retval != 0) || (list == NULL)) + goto cleanup; + + for (plist = list; *plist != NULL; plist++) { + printf("%s\n", *plist); + } + + goto cleanup; + +err_usage: + print_usage = TRUE; + +cleanup: + if (list != NULL) { + krb5_free_list_entries (list); + free (list); + } + + if (basedn) + free (basedn); + + if (print_usage) { + db_usage(LIST_POLICY); + } + + if (retval) { + com_err(me, retval, "while listing policy objects"); + exit_status++; + } + + return; +} + + +/* Reproduced from kadmin.c, instead of linking + the entire kadmin.o */ +static char *strdur(duration) + time_t duration; +{ + static char out[50]; + int neg, days, hours, minutes, seconds; + + if (duration < 0) { + duration *= -1; + neg = 1; + } else + neg = 0; + days = duration / (24 * 3600); + duration %= 24 * 3600; + hours = duration / 3600; + duration %= 3600; + minutes = duration / 60; + duration %= 60; + seconds = duration; + sprintf(out, "%s%d %s %02d:%02d:%02d", neg ? "-" : "", + days, days == 1 ? "day" : "days", + hours, minutes, seconds); + return out; +} + diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.h b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.h new file mode 100644 index 000000000..105b0a06b --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.h @@ -0,0 +1,37 @@ +/* + * kadmin/ldap_util/kdb5_ldap_policy.h + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + + +extern void kdb5_ldap_create_policy(int argc, char **argv); +extern void kdb5_ldap_destroy_policy(int argc, char **argv); +extern void kdb5_ldap_modify_policy(int argc, char **argv); +extern void kdb5_ldap_view_policy(int argc, char **argv); +extern void kdb5_ldap_list_policies(int argc, char **argv); diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c new file mode 100644 index 000000000..1e597b7c5 --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c @@ -0,0 +1,2609 @@ +/* + * kadmin/ldap_util/kdb5_ldap_realm.c + * + * Copyright 1990,1991,2001, 2002 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +/* + * Create / Modify / Destroy / View / List realm(s) + */ + +#include <stdio.h> +#include <k5-int.h> +#include <kadm5/admin.h> +#include "kdb5_ldap_util.h" +#include "kdb5_ldap_list.h" +#include <ldap_principal.h> + +char *yes = "yes\n"; /* \n to compare against result of fgets */ +krb5_key_salt_tuple def_kslist = {ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL}; + +struct realm_info rblock = { + KRB5_KDB_MAX_LIFE, + KRB5_KDB_MAX_RLIFE, + KRB5_KDB_EXPIRATION, + KRB5_KDB_DEF_FLAGS, + (krb5_keyblock *) NULL, + 1, + &def_kslist +}; + +krb5_data tgt_princ_entries[] = { + {0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME}, + {0, 0, 0} }; + +krb5_data db_creator_entries[] = { + {0, sizeof("db_creation")-1, "db_creation"} }; + + +static krb5_principal_data db_create_princ = { + 0, /* magic number */ + {0, 0, 0}, /* krb5_data realm */ + db_creator_entries, /* krb5_data *data */ + 1, /* int length */ + KRB5_NT_SRV_INST /* int type */ +}; + +extern char *mkey_password; +extern char *progname; +extern kadm5_config_params global_params; + +static void print_realm_params(krb5_ldap_realm_params *rparams, int mask); +static int kdb_ldap_create_principal (krb5_context context, krb5_principal + princ, enum ap_op op, struct realm_info *pblock); + + +static char *strdur(time_t duration); +static int get_ticket_policy(krb5_ldap_realm_params *rparams, int *i, char *argv[],int argc); + + +static int get_ticket_policy(rparams,i,argv,argc) + krb5_ldap_realm_params *rparams; + int *i; + char *argv[]; + int argc; +{ + time_t date; + time_t now; + time(&now); + int mask = 0; + krb5_error_code retval = 0; + krb5_boolean no_msg = FALSE; + + krb5_boolean print_usage = FALSE; + char *me = argv[0]; + if (!strcmp(argv[*i], "-maxtktlife")) { + if (++(*i) > argc-1) + goto err_usage; + date = get_date(argv[*i], NULL); + if (date == (time_t)(-1)) { + retval = EINVAL; + com_err (me, retval, "while providing time specification"); + goto err_nomsg; + } + rparams->max_life = date-now; + mask |= LDAP_REALM_MAXTICKETLIFE; + } + + + else if (!strcmp(argv[*i], "-maxrenewlife")) { + if (++(*i) > argc-1) + goto err_usage; + + date = get_date(argv[*i], NULL); + if (date == (time_t)(-1)) { + retval = EINVAL; + com_err (me, retval, "while providing time specification"); + goto err_nomsg; + } + rparams->max_renewable_life = date-now; + mask |= LDAP_REALM_MAXRENEWLIFE; + } + else if (!strcmp((argv[*i] + 1), "allow_postdated")) { + if (*(argv[*i]) == '+') + rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_POSTDATED); + else if (*(argv[*i]) == '-') + rparams->tktflags |= KRB5_KDB_DISALLOW_POSTDATED; + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "allow_forwardable")) { + if (*(argv[*i]) == '+') + rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_FORWARDABLE); + + else if (*(argv[*i]) == '-') + rparams->tktflags |= KRB5_KDB_DISALLOW_FORWARDABLE; + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "allow_renewable")) { + if (*(argv[*i]) == '+') + rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_RENEWABLE); + else if (*(argv[*i]) == '-') + rparams->tktflags |= KRB5_KDB_DISALLOW_RENEWABLE; + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "allow_proxiable")) { + if (*(argv[*i]) == '+') + rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_PROXIABLE); + else if (*(argv[*i]) == '-') + rparams->tktflags |= KRB5_KDB_DISALLOW_PROXIABLE; + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "allow_dup_skey")) { + if (*(argv[*i]) == '+') + rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_DUP_SKEY); + else if (*(argv[*i]) == '-') + rparams->tktflags |= KRB5_KDB_DISALLOW_DUP_SKEY; + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + + else if (!strcmp((argv[*i] + 1), "requires_preauth")) { + if (*(argv[*i]) == '+') + rparams->tktflags |= KRB5_KDB_REQUIRES_PRE_AUTH; + else if (*(argv[*i]) == '-') + rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PRE_AUTH); + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "requires_hwauth")) { + if (*(argv[*i]) == '+') + rparams->tktflags |= KRB5_KDB_REQUIRES_HW_AUTH; + else if (*(argv[*i]) == '-') + rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_HW_AUTH); + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "allow_svr")) { + if (*(argv[*i]) == '+') + rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_SVR); + else if (*(argv[*i]) == '-') + rparams->tktflags |= KRB5_KDB_DISALLOW_SVR; + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "allow_tgs_req")) { + if (*(argv[*i]) == '+') + rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_TGT_BASED); + else if (*(argv[*i]) == '-') + rparams->tktflags |= KRB5_KDB_DISALLOW_TGT_BASED; + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "allow_tix")) { + if (*(argv[*i]) == '+') + rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_ALL_TIX); + else if (*(argv[*i]) == '-') + rparams->tktflags |= KRB5_KDB_DISALLOW_ALL_TIX; + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "needchange")) { + if (*(argv[*i]) == '+') + rparams->tktflags |= KRB5_KDB_REQUIRES_PWCHANGE; + else if (*(argv[*i]) == '-') + rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PWCHANGE); + else + goto err_usage; + + mask |= LDAP_REALM_KRBTICKETFLAGS; + } + else if (!strcmp((argv[*i] + 1), "password_changing_service")) { + if (*(argv[*i]) == '+') + rparams->tktflags |= KRB5_KDB_PWCHANGE_SERVICE; + else if (*(argv[*i]) == '-') + rparams->tktflags &= (int)(~KRB5_KDB_PWCHANGE_SERVICE); + else + goto err_usage; + + mask |=LDAP_REALM_KRBTICKETFLAGS; + } +err_usage: + print_usage = TRUE; + +err_nomsg: + no_msg = TRUE; + + return mask; +} + +/* + * This function will create a realm on the LDAP Server, with + * the specified attributes. + */ +void kdb5_ldap_create(argc, argv) + int argc; + char *argv[]; +{ + krb5_error_code retval = 0; + krb5_keyblock master_keyblock; + krb5_ldap_realm_params *rparams = NULL; + krb5_principal master_princ = NULL; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_boolean realm_obj_created = FALSE; + krb5_boolean create_complete = FALSE; + krb5_boolean print_usage = FALSE; + krb5_boolean no_msg = FALSE; + char *oldsubtree = NULL; + char pw_str[1024]; + int do_stash = 0; + int i = 0, j = 0; + int mask = 0, ret_mask = 0; + char *me = argv[0]; +#ifdef HAVE_EDIRECTORY + int rightsmask = 0; +#endif + + memset(&master_keyblock, 0, sizeof(master_keyblock)); + + rparams = (krb5_ldap_realm_params *)malloc( + sizeof(krb5_ldap_realm_params)); + if (rparams == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams, 0, sizeof(krb5_ldap_realm_params)); + + /* Parse the arguments */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-subtree")) { + if (++i > argc-1) + goto err_usage; + rparams->subtree = strdup(argv[i]); + if (rparams->subtree == NULL) { + retval = ENOMEM; + goto cleanup; + } + mask |= LDAP_REALM_SUBTREE; + } + else if (!strcmp(argv[i], "-sscope")) { + if (++i > argc-1) + goto err_usage; + /* Possible values for search scope are + * one (or 1) and sub (or 2) + */ + if (!strcasecmp(argv[i], "one")) { + rparams->search_scope = 1; + } + else if (!strcasecmp(argv[i], "sub")) { + rparams->search_scope = 2; + } + else { + rparams->search_scope = atoi(argv[i]); + if ((rparams->search_scope != 1) && + (rparams->search_scope != 2)) { + com_err(argv[0], EINVAL, + "invalid search scope while creating realm '%s'", + global_params.realm); + goto err_nomsg; + } + } + mask |= LDAP_REALM_SEARCHSCOPE; + } +#ifdef HAVE_EDIRECTORY + else if (!strcmp(argv[i], "-kdcdn")) { + if (++i > argc-1) + goto err_usage; + rparams->kdcservers = (char **)malloc( + sizeof(char *) * MAX_LIST_ENTRIES); + if (rparams->kdcservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->kdcservers, 0, sizeof(char*)*MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + rparams->kdcservers))) { + goto cleanup; + } + mask |= LDAP_REALM_KDCSERVERS; + } + else if (!strcmp(argv[i], "-admindn")) { + if (++i > argc-1) + goto err_usage; + rparams->adminservers = (char **)malloc( + sizeof(char *) * MAX_LIST_ENTRIES); + if (rparams->adminservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->adminservers, 0, sizeof(char*)*MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + rparams->adminservers))) { + goto cleanup; + } + mask |= LDAP_REALM_ADMINSERVERS; + } + else if (!strcmp(argv[i], "-pwddn")) { + if (++i > argc-1) + goto err_usage; + rparams->passwdservers = (char **)malloc( + sizeof(char *) * MAX_LIST_ENTRIES); + if (rparams->passwdservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->passwdservers, 0, sizeof(char*)*MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + rparams->passwdservers))) { + goto cleanup; + } + mask |= LDAP_REALM_PASSWDSERVERS; + } +#endif + else if (!strcmp(argv[i], "-enctypes")) { + char *tlist[MAX_LIST_ENTRIES] = {NULL}; + + if (++i > argc-1) + goto err_usage; + rparams->suppenctypes = (krb5_enctype *)malloc( + sizeof(krb5_enctype) * MAX_LIST_ENTRIES); + if (rparams->suppenctypes == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->suppenctypes, 0, sizeof(krb5_enctype) * MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, tlist)) != 0) { + goto cleanup; + } + for(j = 0; tlist[j] != NULL; j++) { + if ((retval = krb5_string_to_enctype(tlist[j], + &rparams->suppenctypes[j]))) { + com_err(argv[0], retval, "Invalid encryption type '%s'", + tlist[j]); + krb5_free_list_entries(tlist); + goto err_nomsg; + } + } + rparams->suppenctypes[j] = END_OF_LIST; + qsort(rparams->suppenctypes, (size_t)j, sizeof(krb5_enctype), + compare_int); + mask |= LDAP_REALM_SUPPENCTYPE; + krb5_free_list_entries(tlist); + } + else if (!strcmp(argv[i], "-defenctype")) { + if (++i > argc-1) + goto err_usage; + if ((retval = krb5_string_to_enctype(argv[i], + &rparams->defenctype))) { + com_err(argv[0], retval, "'%s' specified for defenctype, " + "while creating realm '%s'", + argv[i], global_params.realm); + goto err_nomsg; + } + mask |= LDAP_REALM_DEFENCTYPE; + } + else if (!strcmp(argv[i], "-salttypes")) { + char *tlist[MAX_LIST_ENTRIES] = {NULL}; + + if (++i > argc-1) + goto err_usage; + rparams->suppsalttypes = (krb5_int32 *)malloc( + sizeof(krb5_int32) * MAX_LIST_ENTRIES); + if (rparams->suppsalttypes == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->suppsalttypes, 0, sizeof(krb5_int32) * MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, tlist))) { + goto cleanup; + } + for(j = 0; tlist[j] != NULL; j++) { + if ((retval = krb5_string_to_salttype(tlist[j], + &rparams->suppsalttypes[j]))) { + com_err(argv[0], retval, "'%s' specified for salttypes, " + "while creating realm '%s'", + tlist[j], global_params.realm); + krb5_free_list_entries(tlist); + goto err_nomsg; + } + } + rparams->suppsalttypes[j] = END_OF_LIST; + qsort(rparams->suppsalttypes, (size_t)j, sizeof(krb5_int32), + compare_int); + mask |= LDAP_REALM_SUPPSALTTYPE; + krb5_free_list_entries(tlist); + } + else if (!strcmp(argv[i], "-defsalttype")) { + if (++i > argc-1) + goto err_usage; + if ((retval = krb5_string_to_salttype(argv[i], + &rparams->defsalttype))) { + com_err(argv[0], retval, "'%s' specified for defsalttype, " + "while creating realm '%s'", + argv[i], global_params.realm); + goto err_nomsg; + } + mask |= LDAP_REALM_DEFSALTTYPE; + } + else if (!strcmp(argv[i], "-s")) { + do_stash = 1; + } + else if ((ret_mask= get_ticket_policy(rparams,&i,argv,argc)) !=0) + { + mask|=ret_mask; + } + + else { + printf("'%s' is an invalid option\n", argv[i]); + goto err_usage; + } + } + + /* If the default enctype/salttype is not provided, use the + * default values and also add to the list of supported + * enctypes/salttype + */ + if ( !(mask & LDAP_REALM_DEFENCTYPE) && (rparams != NULL)) { + rparams->defenctype = ENCTYPE_DES3_CBC_SHA1; + mask |= LDAP_REALM_DEFENCTYPE; + printf("Default enctype not specified: \"des3-cbc-sha1\" " + "will be added as the default enctype and to the " + "list of supported enctypes.\n"); + + /* Now, add this to the list of supported enctypes. The + * duplicate values will be removed in DAL-LDAP + */ + if (mask & LDAP_REALM_SUPPENCTYPE) { + for (i=0; rparams->suppenctypes[i] != END_OF_LIST; i++) + ; + assert (i < END_OF_LIST - 1); + rparams->suppenctypes[i] = ENCTYPE_DES3_CBC_SHA1; + rparams->suppenctypes[i + 1] = END_OF_LIST; + } + } + + if ( !(mask & LDAP_REALM_DEFSALTTYPE) && (rparams != NULL)) { + rparams->defsalttype = KRB5_KDB_SALTTYPE_NORMAL; + mask |= LDAP_REALM_DEFSALTTYPE; + printf("Default salttype not specified: \"normal\" will be " + "added as the default salttype and to the list of " + "supported salttypes.\n"); + + /* Now, add this to the list of supported salttypes. The + * duplicate values will be removed in DAL-LDAP + */ + if (mask & LDAP_REALM_SUPPSALTTYPE) { + for (i=0; rparams->suppsalttypes[i] != END_OF_LIST; i++) + ; + assert (i < END_OF_LIST - 1); + rparams->suppsalttypes[i] = KRB5_KDB_SALTTYPE_NORMAL; + rparams->suppsalttypes[i + 1] = END_OF_LIST; + } + } + + rblock.max_life = global_params.max_life; + rblock.max_rlife = global_params.max_rlife; + rblock.expiration = global_params.expiration; + rblock.flags = global_params.flags; + rblock.nkslist = global_params.num_keysalts; + rblock.kslist = global_params.keysalts; + + krb5_princ_set_realm_data(util_context, &db_create_princ, global_params.realm); + krb5_princ_set_realm_length(util_context, &db_create_princ, strlen(global_params.realm)); + + printf("Initializing database for realm '%s'\n", global_params.realm); + + if (!mkey_password) { + unsigned int pw_size; + printf("You will be prompted for the database Master Password.\n"); + printf("It is important that you NOT FORGET this password.\n"); + fflush(stdout); + + pw_size = sizeof (pw_str); + memset(pw_str, 0, pw_size); + + retval = krb5_read_password(util_context, KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2, + pw_str, &pw_size); + if (retval) { + com_err(argv[0], retval, "while reading master key from keyboard"); + goto err_nomsg; + } + mkey_password = pw_str; + } + + rparams->mkey.enctype = global_params.enctype; + /* We are sure that 'mkey_password' is a regular string ... */ + rparams->mkey.length = strlen(mkey_password) + 1; + rparams->mkey.contents = (krb5_octet *)strdup(mkey_password); + if (rparams->mkey.contents == NULL) { + retval = ENOMEM; + goto cleanup; + } + + rparams->realm_name = strdup(global_params.realm); + if (rparams->realm_name == NULL) { + retval = ENOMEM; + com_err(argv[0], ENOMEM, "while creating realm '%s'", + global_params.realm); + goto err_nomsg; + } + + dal_handle = (kdb5_dal_handle *) util_context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + if (!ldap_context) { + retval = EINVAL; + goto cleanup; + } + + /* read the kerberos container */ + if ((retval=krb5_ldap_read_krbcontainer_params (util_context, + &(ldap_context->krbcontainer))) == KRB5_KDB_NOENTRY) { + /* Prompt the user for entering the DN of Kerberos container */ + char krb_location[MAX_KRB_CONTAINER_LEN]; + krb5_ldap_krbcontainer_params kparams; + int krb_location_len = 0; + memset(&kparams, 0, sizeof(kparams)); + + /* Read the kerberos container location from configuration file */ + if (ldap_context->conf_section) { + if ((retval=profile_get_string(util_context->profile, + KDB_MODULE_SECTION, ldap_context->conf_section, + "ldap_kerberos_container_dn", NULL, + &kparams.DN)) != 0) { + goto cleanup; + } + } + if (kparams.DN == NULL) { + if ((retval=profile_get_string(util_context->profile, + KDB_MODULE_DEF_SECTION, + "ldap_kerberos_container_dn", NULL, + NULL, &kparams.DN)) != 0) { + goto cleanup; + } + } + + printf("\nKerberos container is missing. Creating now...\n"); + if (kparams.DN == NULL) { +#ifdef HAVE_EDIRECTORY + printf("Enter DN of Kerberos container [cn=Kerberos,cn=Security]: "); +#else + printf("Enter DN of Kerberos container: "); +#endif + if (fgets(krb_location, MAX_KRB_CONTAINER_LEN, stdin) != NULL) { + /* Remove the newline character at the end */ + krb_location_len = strlen(krb_location); + if ((krb_location[krb_location_len - 1] == '\n') || + (krb_location[krb_location_len - 1] == '\r')) { + krb_location[krb_location_len - 1] = '\0'; + krb_location_len--; + } + /* If the user has not given any input, take the default location */ + else if (krb_location[0] == '\0') + kparams.DN = NULL; + else + kparams.DN = krb_location; + } + else + kparams.DN = NULL; + } + + /* create the kerberos container */ + retval = krb5_ldap_create_krbcontainer(util_context, + ((kparams.DN != NULL) ? &kparams : NULL)); + if (retval) + goto cleanup; + + retval = krb5_ldap_read_krbcontainer_params(util_context, + &(ldap_context->krbcontainer)); + if (retval) { + com_err(argv[0], retval, "while reading kerberos container information"); + goto cleanup; + } + } + else if (retval) { + com_err(argv[0], retval, "while reading kerberos container information"); + goto cleanup; + } + + if ((retval = krb5_ldap_create_realm(util_context, + /* global_params.realm, */ rparams, mask))) { + goto cleanup; + } + + /* We just created the Realm container. Here starts our transaction tracking */ + realm_obj_created = TRUE; + + if ((retval = krb5_ldap_read_realm_params(util_context, + global_params.realm, + &(ldap_context->lrparams), + &mask))) { + com_err(argv[0], retval, "while reading information of realm '%s'", + global_params.realm); + goto err_nomsg; + } + ldap_context->lrparams->realm_name = strdup(global_params.realm); + if (ldap_context->lrparams->realm_name == NULL) { + retval = ENOMEM; + goto cleanup; + } + + /* assemble & parse the master key name */ + if ((retval = krb5_db_setup_mkey_name(util_context, + global_params.mkey_name, + global_params.realm, + 0, &master_princ))) { + com_err(argv[0], retval, "while setting up master key name"); + goto err_nomsg; + } + + /* Obtain master key from master password */ + { + krb5_data master_salt, pwd; + + pwd.data = mkey_password; + pwd.length = strlen(mkey_password); + retval = krb5_principal2salt(util_context, master_princ, &master_salt); + if (retval) { + com_err(argv[0], retval, "while calculating master key salt"); + goto err_nomsg; + } + + retval = krb5_c_string_to_key(util_context, rparams->mkey.enctype, + &pwd, &master_salt, &master_keyblock); + + if (master_salt.data) + free(master_salt.data); + + if (retval) { + com_err(argv[0], retval, "while transforming master key from password"); + goto err_nomsg; + } + + } + + rblock.key = &master_keyblock; + ldap_context->lrparams->mkey = master_keyblock; + ldap_context->lrparams->mkey.contents = (krb5_octet *) malloc + (master_keyblock.length); + if (ldap_context->lrparams->mkey.contents == NULL) { + retval = ENOMEM; + goto cleanup; + } + memcpy (ldap_context->lrparams->mkey.contents, master_keyblock.contents, + master_keyblock.length); + + /* Create special principals inside the realm subtree */ + { + char princ_name[MAX_PRINC_SIZE], localname[MAXHOSTNAMELEN]; + struct hostent *hp = NULL; + krb5_principal_data tgt_princ = { + 0, /* magic number */ + {0, 0, 0}, /* krb5_data realm */ + tgt_princ_entries, /* krb5_data *data */ + 2, /* int length */ + KRB5_NT_SRV_INST /* int type */ + }; + krb5_principal p; + + krb5_princ_set_realm_data(util_context, &tgt_princ, global_params.realm); + krb5_princ_set_realm_length(util_context, &tgt_princ, strlen(global_params.realm)); + krb5_princ_component(util_context, &tgt_princ,1)->data = global_params.realm; + krb5_princ_component(util_context, &tgt_princ,1)->length = strlen(global_params.realm); + + oldsubtree = ldap_context->lrparams->subtree; + ldap_context->lrparams->subtree = strdup(ldap_context->lrparams->realmdn); + if (ldap_context->lrparams->subtree == NULL) { + retval = ENOMEM; + goto cleanup; + } + + /* Create 'K/M' ... */ + rblock.flags |= KRB5_KDB_DISALLOW_ALL_TIX; + if ((retval = kdb_ldap_create_principal(util_context, master_princ, MASTER_KEY, &rblock))) { + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + + /* Create 'krbtgt' ... */ + rblock.flags = 0; /* reset the flags */ + if ((retval = kdb_ldap_create_principal(util_context, &tgt_princ, TGT_KEY, &rblock))) { + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + + /* Create 'kadmin/admin' ... */ + snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_ADMIN_SERVICE, global_params.realm); + if ((retval = krb5_parse_name(util_context, princ_name, &p))) { + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED; + if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY, &rblock))) { + krb5_free_principal(util_context, p); + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + krb5_free_principal(util_context, p); + + /* Create 'kadmin/changepw' ... */ + snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_CHANGEPW_SERVICE, global_params.realm); + if ((retval = krb5_parse_name(util_context, princ_name, &p))) { + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED | + KRB5_KDB_PWCHANGE_SERVICE; + if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY, &rblock))) { + krb5_free_principal(util_context, p); + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + krb5_free_principal(util_context, p); + + /* Create 'kadmin/history' ... */ + snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_HIST_PRINCIPAL, global_params.realm); + if ((retval = krb5_parse_name(util_context, princ_name, &p))) { + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + rblock.flags = 0; + if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY, &rblock))) { + krb5_free_principal(util_context, p); + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + krb5_free_principal(util_context, p); + + /* Create 'kadmin/<hostname>' ... */ + if (gethostname(localname, sizeof(localname))) { + retval = errno; + com_err(argv[0], retval, "gethostname, while adding entries to the database"); + goto err_nomsg; + } + hp = gethostbyname(localname); + if (hp == NULL) { + retval = errno; + com_err(argv[0], retval, "gethostbyname, while adding entries to the database"); + goto err_nomsg; + } + assert (sizeof(princ_name) >= MAXHOSTNAMELEN + 8); + /* snprintf(princ_name, MAXHOSTNAMELEN + 8, "kadmin/%s", hp->h_name); */ + snprintf(princ_name, sizeof(princ_name), "kadmin/%s@%s", hp->h_name, global_params.realm); + if ((retval = krb5_parse_name(util_context, princ_name, &p))) { + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + + rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED; + if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY, &rblock))) { + krb5_free_principal(util_context, p); + com_err(argv[0], retval, "while adding entries to the database"); + goto err_nomsg; + } + krb5_free_principal(util_context, p); + + if (ldap_context->lrparams->subtree != NULL) + free(ldap_context->lrparams->subtree); + ldap_context->lrparams->subtree = oldsubtree; + oldsubtree = NULL; + } + +#ifdef HAVE_EDIRECTORY + if( (mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) || + (mask & LDAP_REALM_PASSWDSERVERS) ) { + + printf("Changing rights for the service object. Please wait ... "); + fflush(stdout); + + rightsmask =0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + if ( (rparams != NULL) && (rparams->kdcservers != NULL) ) { + for ( i=0; (rparams->kdcservers[i] != NULL); i++) { + if((retval=krb5_ldap_add_service_rights( util_context, + LDAP_KDC_SERVICE, rparams->kdcservers[i], + rparams->realm_name, rparams->subtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + if ( (rparams != NULL) && (rparams->adminservers != NULL) ) { + for ( i=0; (rparams->adminservers[i] != NULL); i++) { + if((retval=krb5_ldap_add_service_rights( util_context, + LDAP_ADMIN_SERVICE, rparams->adminservers[i], + rparams->realm_name, rparams->subtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + if( (rparams != NULL) && (rparams->passwdservers != NULL) ) { + for ( i=0; (rparams->passwdservers[i] != NULL); i++) { + if((retval=krb5_ldap_add_service_rights( util_context, + LDAP_PASSWD_SERVICE, rparams->passwdservers[i], + rparams->realm_name, rparams->subtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + + printf("done\n"); + } +#endif + /* The Realm creation is completed. Here is the end of transaction */ + create_complete = TRUE; + + /* Stash the master key only if '-s' option is specified */ + if (do_stash || global_params.mask & KADM5_CONFIG_STASH_FILE) { + retval = krb5_def_store_mkey(util_context, + global_params.stash_file, + master_princ, + &master_keyblock, NULL); + if (retval) { + com_err(argv[0], errno, "while storing key"); + printf("Warning: couldn't stash master key.\n"); + } + } + + goto cleanup; + + +err_usage: + print_usage = TRUE; + +err_nomsg: + no_msg = TRUE; + +cleanup: + /* If the Realm creation is not complete, do the roll-back here */ + if ((realm_obj_created) && (!create_complete)) + krb5_ldap_delete_realm(util_context, global_params.realm); + + if (rparams) + krb5_ldap_free_realm_params(rparams); + + memset (pw_str, 0, sizeof (pw_str)); + + if (oldsubtree) + ldap_context->lrparams->subtree = oldsubtree; + + if (print_usage) + db_usage(CREATE_REALM); + + if (retval) { + if (!no_msg) { + com_err(argv[0], retval, "while creating realm '%s'", + global_params.realm); + } + exit_status++; + } + + return; +} + + +/* + * This function will modify the attributes of a given realm object + */ +void kdb5_ldap_modify(argc, argv) + int argc; + char *argv[]; +{ + krb5_error_code retval; + krb5_ldap_realm_params *rparams = NULL; + krb5_boolean print_usage = FALSE; + krb5_boolean no_msg = FALSE; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context=NULL; + int i = 0, j = 0; + int mask = 0, rmask = 0, ret_mask = 0; + char *list[MAX_LIST_ENTRIES]; + int tlist[MAX_LIST_ENTRIES] = {0}; + int newenctypes = 0, newsalttypes = 0; + int existing_entries = 0, list_entries = 0; +#ifdef HAVE_EDIRECTORY + int newkdcdn = 0, newadmindn = 0, newpwddn = 0; + char **tempstr = NULL; + char **oldkdcdns = NULL; + char **oldadmindns = NULL; + char **oldpwddns = NULL; + char **newkdcdns = NULL; + char **newadmindns = NULL; + char **newpwddns = NULL; + char *oldsubtree = NULL; + int rightsmask = 0; + int subtree_changed = 0; +#endif + char *me = argv[0]; + + dal_handle = (kdb5_dal_handle *) util_context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + if (!(ldap_context)) { + retval = EINVAL; + goto cleanup; + } + + if((retval = krb5_ldap_read_krbcontainer_params(util_context, + &(ldap_context->krbcontainer)))) { + com_err(argv[0], retval, "while reading Kerberos container information"); + goto err_nomsg; + } + + retval = krb5_ldap_read_realm_params(util_context, + global_params.realm, &rparams, &rmask); + if (retval) + goto cleanup; + + /* Parse the arguments */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-subtree")) { + if (++i > argc-1) + goto err_usage; + + if (rmask & LDAP_REALM_SUBTREE) { + if( rparams->subtree ) { +#ifdef HAVE_EDIRECTORY + oldsubtree = strdup(rparams->subtree); + if( oldsubtree == NULL ) { + retval = ENOMEM; + goto cleanup; + } +#endif + free(rparams->subtree); + } + } + rparams->subtree = strdup(argv[i]); + if (rparams->subtree == NULL) { + retval = ENOMEM; + goto cleanup; + } + mask |= LDAP_REALM_SUBTREE; + } + else if (!strcmp(argv[i], "-sscope")) { + if (++i > argc-1) + goto err_usage; + /* Possible values for search scope are + * one (or 1) and sub (or 2) + */ + if (strcasecmp(argv[i], "one") == 0) { + rparams->search_scope = 1; + } + else if (strcasecmp(argv[i], "sub") == 0) { + rparams->search_scope = 2; + } + else { + rparams->search_scope = atoi(argv[i]); + if ((rparams->search_scope != 1) && + (rparams->search_scope != 2)) { + retval = EINVAL; + com_err(argv[0], retval, + "specified for search scope while modifying information of realm '%s'", + global_params.realm); + goto err_nomsg; + } + } + mask |= LDAP_REALM_SEARCHSCOPE; + } +#ifdef HAVE_EDIRECTORY + else if (!strcmp(argv[i], "-kdcdn")) { + if (++i > argc-1) + goto err_usage; + + if ((rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers)) { + if (!oldkdcdns) { + /* Store the old kdc dns list for removing rights */ + oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldkdcdns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j=0; rparams->kdcservers[j] != NULL; j++) { + oldkdcdns[j] = strdup(rparams->kdcservers[j]); + if (oldkdcdns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldkdcdns[j] = NULL; + } + + krb5_free_list_entries(rparams->kdcservers); + free(rparams->kdcservers); + } + + rparams->kdcservers = (char **)malloc( + sizeof(char *) * MAX_LIST_ENTRIES); + if (rparams->kdcservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->kdcservers, 0, sizeof(char *)*MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + rparams->kdcservers))) { + goto cleanup; + } + mask |= LDAP_REALM_KDCSERVERS; + /* Going to replace the existing value by this new value. Hence + * setting flag indicating that add or clear options will be ignored + */ + newkdcdn = 1; + } + else if (!strcmp(argv[i], "-clearkdcdn")) { + if (++i > argc-1) + goto err_usage; + if ((!newkdcdn) && (rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers)) { + if (!oldkdcdns) { + /* Store the old kdc dns list for removing rights */ + oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldkdcdns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j=0; rparams->kdcservers[j] != NULL; j++) { + oldkdcdns[j] = strdup(rparams->kdcservers[j]); + if (oldkdcdns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldkdcdns[j] = NULL; + } + + memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) { + goto cleanup; + } + list_modify_str_array(&rparams->kdcservers, (const char **)list, + LIST_MODE_DELETE); + mask |= LDAP_REALM_KDCSERVERS; + krb5_free_list_entries(list); + } + } + else if (!strcmp(argv[i], "-addkdcdn")) { + if (++i > argc-1) + goto err_usage; + if (!newkdcdn) { + if ((rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers) && (!oldkdcdns)) { + /* Store the old kdc dns list for removing rights */ + oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldkdcdns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j = 0; rparams->kdcservers[j] != NULL; j++) { + oldkdcdns[j] = strdup(rparams->kdcservers[j]); + if (oldkdcdns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldkdcdns[j] = NULL; + } + + memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) { + goto cleanup; + } + existing_entries = list_count_str_array(rparams->kdcservers); + list_entries = list_count_str_array(list); + if (rmask & LDAP_REALM_KDCSERVERS) { + tempstr = (char **)realloc( + rparams->kdcservers, + sizeof(char *) * (existing_entries+list_entries+1)); + if (tempstr == NULL) { + retval = ENOMEM; + goto cleanup; + } + rparams->kdcservers = tempstr; + } + else { + rparams->kdcservers = (char **)malloc(sizeof(char *) * (list_entries+1)); + if (rparams->kdcservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->kdcservers, 0, sizeof(char *) * (list_entries+1)); + } + list_modify_str_array(&rparams->kdcservers, (const char **)list, + LIST_MODE_ADD); + mask |= LDAP_REALM_KDCSERVERS; + } + } + else if (!strcmp(argv[i], "-admindn")) { + if (++i > argc-1) + goto err_usage; + + if ((rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers)) { + if (!oldadmindns) { + /* Store the old admin dns list for removing rights */ + oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldadmindns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j=0; rparams->adminservers[j] != NULL; j++) { + oldadmindns[j] = strdup(rparams->adminservers[j]); + if (oldadmindns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldadmindns[j] = NULL; + } + + krb5_free_list_entries(rparams->adminservers); + free(rparams->adminservers); + } + + rparams->adminservers = (char **)malloc( + sizeof(char *) * MAX_LIST_ENTRIES); + if (rparams->adminservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->adminservers, 0, sizeof(char *)*MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + rparams->adminservers))) { + goto cleanup; + } + mask |= LDAP_REALM_ADMINSERVERS; + /* Going to replace the existing value by this new value. Hence + * setting flag indicating that add or clear options will be ignored + */ + newadmindn = 1; + } + else if (!strcmp(argv[i], "-clearadmindn")) { + if (++i > argc-1) + goto err_usage; + + if ((!newadmindn) && (rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers)) { + if (!oldadmindns) { + /* Store the old admin dns list for removing rights */ + oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldadmindns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j=0; rparams->adminservers[j] != NULL; j++) { + oldadmindns[j] = strdup(rparams->adminservers[j]); + if (oldadmindns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldadmindns[j] = NULL; + } + + memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) { + goto cleanup; + } + list_modify_str_array(&rparams->adminservers, (const char **)list, + LIST_MODE_DELETE); + mask |= LDAP_REALM_ADMINSERVERS; + krb5_free_list_entries(list); + } + } + else if (!strcmp(argv[i], "-addadmindn")) { + if (++i > argc-1) + goto err_usage; + if (!newadmindn) { + if ((rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers) && (!oldadmindns)) { + /* Store the old admin dns list for removing rights */ + oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldadmindns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j=0; rparams->adminservers[j] != NULL; j++) { + oldadmindns[j] = strdup(rparams->adminservers[j]); + if (oldadmindns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldadmindns[j] = NULL; + } + + memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) { + goto cleanup; + } + existing_entries = list_count_str_array(rparams->adminservers); + list_entries = list_count_str_array(list); + if (rmask & LDAP_REALM_ADMINSERVERS) { + tempstr = (char **)realloc( + rparams->adminservers, + sizeof(char *) * (existing_entries+list_entries+1)); + if (tempstr == NULL) { + retval = ENOMEM; + goto cleanup; + } + rparams->adminservers = tempstr; + } + else { + rparams->adminservers = (char **)malloc(sizeof(char *) * (list_entries+1)); + if (rparams->adminservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->adminservers, 0, sizeof(char *) * (list_entries+1)); + } + list_modify_str_array(&rparams->adminservers, (const char **)list, + LIST_MODE_ADD); + mask |= LDAP_REALM_ADMINSERVERS; + } + } + else if (!strcmp(argv[i], "-pwddn")) { + if (++i > argc-1) + goto err_usage; + + if ((rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers)) { + if (!oldpwddns) { + /* Store the old pwd dns list for removing rights */ + oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldpwddns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j=0; rparams->passwdservers[j] != NULL; j++) { + oldpwddns[j] = strdup(rparams->passwdservers[j]); + if (oldpwddns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldpwddns[j] = NULL; + } + + krb5_free_list_entries(rparams->passwdservers); + free(rparams->passwdservers); + } + + rparams->passwdservers = (char **)malloc( + sizeof(char *) * MAX_LIST_ENTRIES); + if (rparams->passwdservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->passwdservers, 0, sizeof(char *)*MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + rparams->passwdservers))) { + goto cleanup; + } + mask |= LDAP_REALM_PASSWDSERVERS; + /* Going to replace the existing value by this new value. Hence + * setting flag indicating that add or clear options will be ignored + */ + newpwddn = 1; + } + else if (!strcmp(argv[i], "-clearpwddn")) { + if (++i > argc-1) + goto err_usage; + + if ((!newpwddn) && (rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers)) { + if (!oldpwddns) { + /* Store the old pwd dns list for removing rights */ + oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldpwddns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j=0; rparams->passwdservers[j] != NULL; j++) { + oldpwddns[j] = strdup(rparams->passwdservers[j]); + if (oldpwddns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldpwddns[j] = NULL; + } + + memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) { + goto cleanup; + } + list_modify_str_array(&rparams->passwdservers, (const char**)list, + LIST_MODE_DELETE); + mask |= LDAP_REALM_PASSWDSERVERS; + krb5_free_list_entries(list); + } + } + else if (!strcmp(argv[i], "-addpwddn")) { + if (++i > argc-1) + goto err_usage; + if (!newpwddn) { + if ((rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers) && (!oldpwddns)) { + /* Store the old pwd dns list for removing rights */ + oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldpwddns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j=0; rparams->passwdservers[j] != NULL; j++) { + oldpwddns[j] = strdup(rparams->passwdservers[j]); + if (oldpwddns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldpwddns[j] = NULL; + } + + memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES); + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) { + goto cleanup; + } + existing_entries = list_count_str_array(rparams->passwdservers); + list_entries = list_count_str_array(list); + if (rmask & LDAP_REALM_PASSWDSERVERS) { + tempstr = (char **)realloc( + rparams->passwdservers, + sizeof(char *) * (existing_entries+list_entries+1)); + if (tempstr == NULL) { + retval = ENOMEM; + goto cleanup; + } + rparams->passwdservers = tempstr; + } + else { + rparams->passwdservers = (char **)malloc(sizeof(char *) * (list_entries+1)); + if (rparams->passwdservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(rparams->passwdservers, 0, sizeof(char *) * (list_entries+1)); + } + list_modify_str_array(&rparams->passwdservers, (const char**)list, + LIST_MODE_ADD); + mask |= LDAP_REALM_PASSWDSERVERS; + } + } +#endif + else if (!strcmp(argv[i], "-enctypes")) { + if (++i > argc-1) + goto err_usage; + if (rmask & LDAP_REALM_SUPPENCTYPE) + free(rparams->suppenctypes); + rparams->suppenctypes = (krb5_enctype *)malloc( + sizeof(krb5_enctype) * MAX_LIST_ENTRIES); + if (rparams->suppenctypes == NULL) { + retval = ENOMEM; + goto cleanup; + } + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + for(j = 0; list[j] != NULL; j++) { + if ((retval = krb5_string_to_enctype(list[j], + &rparams->suppenctypes[j]))) { + com_err(argv[0], retval, "'%s' specified for enctypes, " + "while modifying information of realm '%s'", + list[j], global_params.realm); + goto err_nomsg; + } + } + rparams->suppenctypes[j] = END_OF_LIST; + qsort(rparams->suppenctypes, (size_t)j, sizeof(krb5_enctype), + compare_int); + mask |= LDAP_REALM_SUPPENCTYPE; + /* Going to replace the existing value by this new value. Hence + * setting flag indicating that add or clear options will be ignored + */ + newenctypes = 1; + krb5_free_list_entries(list); + } + else if (!strcmp(argv[i], "-clearenctypes")) { + if (++i > argc-1) + goto err_usage; + if ((!newenctypes) && (rparams->suppenctypes != NULL)) { + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + memset(tlist, END_OF_LIST, sizeof(int) * MAX_LIST_ENTRIES); + for(j = 0; list[j] != NULL; j++) { + if ((retval = krb5_string_to_enctype(list[j], &tlist[j]))) { + com_err(argv[0], retval, "'%s' specified for clearenctypes, " + "while modifying information of realm '%s'", + list[j], global_params.realm); + goto err_nomsg; + } + } + tlist[j] = END_OF_LIST; + j = list_modify_int_array(rparams->suppenctypes, (const int*)tlist, + LIST_MODE_DELETE); + qsort(rparams->suppenctypes, (size_t)j, sizeof(krb5_enctype), + compare_int); + mask |= LDAP_REALM_SUPPENCTYPE; + krb5_free_list_entries(list); + } + } + else if (!strcmp(argv[i], "-addenctypes")) { + if (++i > argc-1) + goto err_usage; + if (!newenctypes) { + int *tmp; + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + existing_entries = list_count_int_array(rparams->suppenctypes); + list_entries = list_count_str_array(list); + + tmp = (krb5_enctype *) realloc (rparams->suppenctypes, + sizeof(krb5_enctype) * (existing_entries+list_entries+1)); + if (tmp == NULL) { + retval = ENOMEM; + goto cleanup; + } + rparams->suppenctypes = tmp; + + for(j = 0; list[j] != NULL; j++) { + if ((retval = krb5_string_to_enctype(list[j], &tlist[j]))) { + com_err(argv[0], retval, "'%s' specified for addenctypes, " + "while modifying information of realm '%s'", + list[j], global_params.realm); + goto err_nomsg; + } + } + tlist[j] = END_OF_LIST; + + j = list_modify_int_array(rparams->suppenctypes, (const int*)tlist, + LIST_MODE_ADD); + qsort(rparams->suppenctypes, (size_t)j, sizeof(krb5_enctype), + compare_int); + mask |= LDAP_REALM_SUPPENCTYPE; + krb5_free_list_entries(list); + } + } + else if (!strcmp(argv[i], "-defenctype")) { + if (++i > argc-1) + goto err_usage; + if ((retval = krb5_string_to_enctype(argv[i], + &rparams->defenctype))) { + com_err(argv[0], retval, "'%s' specified for defenctype, " + "while modifying information of realm '%s'", + argv[i], global_params.realm); + goto err_nomsg; + } + mask |= LDAP_REALM_DEFENCTYPE; + } + else if (!strcmp(argv[i], "-salttypes")) { + if (++i > argc-1) + goto err_usage; + if (rmask & LDAP_REALM_SUPPSALTTYPE) + free(rparams->suppsalttypes); + rparams->suppsalttypes = (krb5_int32 *)malloc( + sizeof(krb5_int32) * MAX_LIST_ENTRIES); + if (rparams->suppsalttypes == NULL) { + retval = ENOMEM; + goto cleanup; + } + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + for(j = 0; list[j] != NULL; j++) { + if ((retval = krb5_string_to_salttype(list[j], + &rparams->suppsalttypes[j]))) { + com_err(argv[0], retval, "'%s' specified for salttypes, " + "while modifying information of realm '%s'", + list[j], global_params.realm); + goto err_nomsg; + } + } + rparams->suppsalttypes[j] = END_OF_LIST; + qsort(rparams->suppsalttypes, (size_t)j, sizeof(krb5_int32), + compare_int); + mask |= LDAP_REALM_SUPPSALTTYPE; + /* Going to replace the existing value by this new value. Hence + * setting flag indicating that add or clear options will be ignored + */ + newsalttypes = 1; + krb5_free_list_entries(list); + } + else if (!strcmp(argv[i], "-clearsalttypes")) { + if (++i > argc-1) + goto err_usage; + if ((!newsalttypes) && (rparams->suppsalttypes != NULL)) { + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + for(j = 0; list[j] != NULL; j++) { + if ((retval = krb5_string_to_salttype(list[j], &tlist[j]))) { + com_err(argv[0], retval, "'%s' specified for clearsalttypes, " + "while modifying information of realm '%s'", + list[j], global_params.realm); + goto err_nomsg; + } + } + tlist[j] = END_OF_LIST; + j = list_modify_int_array(rparams->suppsalttypes, (const int*)tlist, + LIST_MODE_DELETE); + qsort(rparams->suppsalttypes, (size_t)j, sizeof(krb5_int32), + compare_int); + mask |= LDAP_REALM_SUPPSALTTYPE; + krb5_free_list_entries(list); + } + } + else if (!strcmp(argv[i], "-addsalttypes")) { + if (++i > argc-1) + goto err_usage; + if (!newsalttypes) { + int *tmp; + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + existing_entries = list_count_int_array(rparams->suppsalttypes); + list_entries = list_count_str_array(list); + + tmp = (krb5_int32 *) realloc (rparams->suppsalttypes, + sizeof(krb5_int32) * (existing_entries+list_entries+1)); + if (tmp == NULL) { + retval = ENOMEM; + goto cleanup; + } + rparams->suppsalttypes = tmp; + + for(j = 0; list[j] != NULL; j++) { + if ((retval = krb5_string_to_salttype(list[j], &tlist[j]))) { + com_err(argv[0], retval, "'%s' specified for addsalttypes, " + "while modifying information of realm '%s'", + list[j], global_params.realm); + goto err_nomsg; + } + } + tlist[j] = END_OF_LIST; + j = list_modify_int_array(rparams->suppsalttypes, (const int*)tlist, + LIST_MODE_ADD); + qsort(rparams->suppsalttypes, (size_t)j, sizeof(krb5_int32), + compare_int); + mask |= LDAP_REALM_SUPPSALTTYPE; + krb5_free_list_entries(list); + } + } + else if (!strcmp(argv[i], "-defsalttype")) { + if (++i > argc-1) + goto err_usage; + if ((retval = krb5_string_to_salttype(argv[i], + &rparams->defsalttype))) { + com_err(argv[0], retval, "'%s' specified for defsalttype, " + "while modifying information of realm '%s'", + argv[i], global_params.realm); + goto err_nomsg; + } + mask |= LDAP_REALM_DEFSALTTYPE; + } + else if ((ret_mask= get_ticket_policy(rparams,&i,argv,argc)) !=0) + { + mask|=ret_mask; + } + else { + printf("'%s' is an invalid option\n", argv[i]); + goto err_usage; + } + } + + if ((retval = krb5_ldap_modify_realm(util_context, + /* global_params.realm, */ rparams, mask))) { + goto cleanup; + } + +#ifdef HAVE_EDIRECTORY + if( (mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_KDCSERVERS) || + (mask & LDAP_REALM_ADMINSERVERS) || (mask & LDAP_REALM_PASSWDSERVERS)) { + + printf("Changing rights for the service object. Please wait ... "); + fflush(stdout); + + if( !(mask & LDAP_REALM_SUBTREE) ) { + if( rparams->subtree != NULL ) { + oldsubtree = strdup(rparams->subtree); + if( oldsubtree == NULL ) { + retval = ENOMEM; + goto cleanup; + } + } + } + + if( (mask & LDAP_REALM_SUBTREE) ) { + if( (oldsubtree && !rparams->subtree) || + (!oldsubtree && rparams->subtree) || + (strcmp( oldsubtree, rparams->subtree) != 0) ) { + subtree_changed = 1; + } + } + + if( (mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_KDCSERVERS) ) { + + newkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (newkdcdns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ( (rparams != NULL) && (rparams->kdcservers != NULL) ) { + for (j=0; rparams->kdcservers[j]!= NULL; j++) { + newkdcdns[j] = strdup(rparams->kdcservers[j]); + if (newkdcdns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + newkdcdns[j] = NULL; + } + + if( !subtree_changed ) { + disjoint_members( oldkdcdns, newkdcdns); + } + else { /* Only the subtree was changed. Remove the rights on the old subtree. */ + if (!(mask & LDAP_REALM_KDCSERVERS)) { + + oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldkdcdns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ( (rparams != NULL) && (rparams->kdcservers != NULL) ) { + for (j=0; rparams->kdcservers[j]!= NULL; j++) { + oldkdcdns[j] = strdup(rparams->kdcservers[j]); + if (oldkdcdns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldkdcdns[j] = NULL; + } + } + } + + rightsmask =0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + /* Remove the rights on the old subtree */ + if ( oldkdcdns ) { + for ( i=0; (oldkdcdns[i] != NULL); i++) { + if((retval=krb5_ldap_delete_service_rights(util_context, + LDAP_KDC_SERVICE, oldkdcdns[i], + rparams->realm_name, oldsubtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + + rightsmask =0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + if ( newkdcdns ) { + for ( i=0; (newkdcdns[i] != NULL); i++) { + + if((retval=krb5_ldap_add_service_rights(util_context, + LDAP_KDC_SERVICE, newkdcdns[i], rparams->realm_name, + rparams->subtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + } + + if( (mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_ADMINSERVERS) ) { + + newadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (newadmindns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ( (rparams != NULL) && (rparams->adminservers != NULL) ) { + for (j=0; rparams->adminservers[j]!= NULL; j++) { + newadmindns[j] = strdup(rparams->adminservers[j]); + if (newadmindns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + newadmindns[j] = NULL; + } + + if( !subtree_changed ) { + disjoint_members( oldadmindns, newadmindns); + } + else { /* Only the subtree was changed. Remove the rights on the old subtree. */ + if (!(mask & LDAP_REALM_ADMINSERVERS)) { + + oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldadmindns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ( (rparams != NULL) && (rparams->adminservers != NULL) ) { + for (j=0; rparams->adminservers[j]!= NULL; j++) { + oldadmindns[j] = strdup(rparams->adminservers[j]); + if (oldadmindns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldadmindns[j] = NULL; + } + } + } + + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + /* Remove the rights on the old subtree */ + if ( oldadmindns ) { + for ( i=0; (oldadmindns[i] != NULL); i++) { + + if((retval=krb5_ldap_delete_service_rights( util_context, + LDAP_ADMIN_SERVICE, oldadmindns[i], + rparams->realm_name, oldsubtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + /* Add rights on the new subtree for all the kdc dns */ + if ( newadmindns ) { + for ( i=0; (newadmindns[i] != NULL); i++) { + + if((retval=krb5_ldap_add_service_rights( util_context, + LDAP_ADMIN_SERVICE, newadmindns[i], + rparams->realm_name, rparams->subtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + } + + + if( (mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_PASSWDSERVERS) ) { + + newpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (newpwddns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ( (rparams != NULL) && (rparams->passwdservers != NULL) ) { + for (j=0; rparams->passwdservers[j]!= NULL; j++) { + newpwddns[j] = strdup(rparams->passwdservers[j]); + if (newpwddns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + newpwddns[j] = NULL; + } + + if( !subtree_changed ) { + disjoint_members( oldpwddns, newpwddns); + } + else { /* Only the subtree was changed. Remove the rights on the old subtree. */ + if (!(mask & LDAP_REALM_ADMINSERVERS)) { + + oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldpwddns == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ( (rparams != NULL) && (rparams->passwdservers != NULL) ) { + for (j=0; rparams->passwdservers[j]!= NULL; j++) { + oldpwddns[j] = strdup(rparams->passwdservers[j]); + if (oldpwddns[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldpwddns[j] = NULL; + } + } + } + + rightsmask =0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + /* Remove the rights on the old subtree */ + if ( oldpwddns ) { + for ( i=0; (oldpwddns[i] != NULL); i++) { + if((retval = krb5_ldap_delete_service_rights( util_context, + LDAP_PASSWD_SERVICE, oldpwddns[i], + rparams->realm_name, oldsubtree, rightsmask))) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + + rightsmask =0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + /* Add rights on the new subtree for all the kdc dns */ + if ( newpwddns ) { + for ( i=0; (newpwddns[i] != NULL); i++) { + if((retval = krb5_ldap_add_service_rights( util_context, + LDAP_PASSWD_SERVICE, newpwddns[i], + rparams->realm_name, rparams->subtree, rightsmask))) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + goto err_nomsg; + } + } + } + } + + printf("done\n"); + } +#endif + + goto cleanup; + +err_usage: + print_usage = TRUE; + +err_nomsg: + no_msg = TRUE; + +cleanup: + krb5_ldap_free_realm_params(rparams); + +#ifdef HAVE_EDIRECTORY + if (oldkdcdns) { + for ( i=0; oldkdcdns[i] != NULL; i++) + free(oldkdcdns[i]); + free(oldkdcdns); + } + if (oldpwddns) { + for ( i=0; oldpwddns[i] != NULL; i++) + free(oldpwddns[i]); + free(oldpwddns); + } + if (oldadmindns) { + for ( i=0; oldadmindns[i] != NULL; i++) + free(oldadmindns[i]); + free(oldadmindns); + } + if (newkdcdns) { + for ( i=0; newkdcdns[i] != NULL; i++) + free(newkdcdns[i]); + free(newkdcdns); + } + if (newpwddns) { + for ( i=0; newpwddns[i] != NULL; i++) + free(newpwddns[i]); + free(newpwddns); + } + if (newadmindns) { + for ( i=0; newadmindns[i] != NULL; i++) + free(newadmindns[i]); + free(newadmindns); + } + if (oldsubtree) + free(oldsubtree); +#endif + if (print_usage) { + db_usage(MODIFY_REALM); + } + + if (retval) { + if (!no_msg) + com_err(argv[0], retval, "while modifying information of realm '%s'", + global_params.realm); + exit_status++; + } + + return; +} + + + +/* + * This function displays the attributes of a Realm + */ +void kdb5_ldap_view(argc, argv) + int argc; + char *argv[]; +{ + krb5_ldap_realm_params *rparams = NULL; + krb5_error_code retval = 0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + int mask = 0; + + dal_handle = (kdb5_dal_handle *) util_context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + if (!(ldap_context)) { + retval = EINVAL; + com_err(argv[0], retval, "while initializing database"); + exit_status++; + return; + } + + /* Read the kerberos container information */ + if ((retval = krb5_ldap_read_krbcontainer_params(util_context, + &(ldap_context->krbcontainer))) != 0) { + com_err(argv[0], retval, "while reading kerberos container information"); + exit_status++; + return; + } + + if ((retval = krb5_ldap_read_realm_params(util_context, + global_params.realm, &rparams, &mask)) || (!rparams)) { + com_err(argv[0], retval, "while reading information of realm '%s'", + global_params.realm); + exit_status++; + return; + } + print_realm_params(rparams, mask); + krb5_ldap_free_realm_params(rparams); + + return; +} + +static char *strdur(duration) + time_t duration; +{ + static char out[50]; + int neg, days, hours, minutes, seconds; + + if (duration < 0) { + duration *= -1; + neg = 1; + } else + neg = 0; + days = duration / (24 * 3600); + duration %= 24 * 3600; + hours = duration / 3600; + duration %= 3600; + minutes = duration / 60; + duration %= 60; + seconds = duration; + sprintf(out, "%s%d %s %02d:%02d:%02d", neg ? "-" : "", + days, days == 1 ? "day" : "days", + hours, minutes, seconds); + return out; +} + +/* + * This function prints the attributes of a given realm to the + * standard output. + */ +static void print_realm_params(krb5_ldap_realm_params *rparams, int mask) +{ + char buff[BUFF_LEN] = {0}; + char **slist = NULL; + int *tmplist = NULL; + krb5_error_code retval = 0; + int num_entry_printed = 0; + + /* Print the Realm Attributes on the standard output */ + printf("%25s: %-50s\n", "Realm Name", global_params.realm); + if (mask & LDAP_REALM_SUBTREE) + printf("%25s: %-50s\n", "Subtree", rparams->subtree); + if (mask & LDAP_REALM_SEARCHSCOPE) { + if ((rparams->search_scope != 1) && + (rparams->search_scope != 2)) { + printf("%25s: %-50s\n", "SearchScope", "Invalid !"); + } + else { + printf("%25s: %-50s\n", "SearchScope", + (rparams->search_scope == 1) ? "ONE" : "SUB"); + } + } + if (mask & LDAP_REALM_KDCSERVERS) { + printf("%25s:", "KDC Services"); + if (rparams->kdcservers != NULL) { + num_entry_printed = 0; + for(slist = rparams->kdcservers; *slist != NULL; slist++) { + if (num_entry_printed) + printf(" %25s %-50s\n", " ", *slist); + else + printf(" %-50s\n", *slist); + num_entry_printed++; + } + } + if (num_entry_printed == 0) + printf("\n"); + } + if (mask & LDAP_REALM_ADMINSERVERS) { + printf("%25s:", "Admin Services"); + if (rparams->adminservers != NULL) { + num_entry_printed = 0; + for(slist = rparams->adminservers; *slist != NULL; slist++) { + if (num_entry_printed) + printf(" %25s %-50s\n", " ", *slist); + else + printf(" %-50s\n", *slist); + num_entry_printed++; + } + } + if (num_entry_printed == 0) + printf("\n"); + } + if (mask & LDAP_REALM_PASSWDSERVERS) { + printf("%25s:", "Passwd Services"); + if (rparams->passwdservers != NULL) { + num_entry_printed = 0; + for(slist = rparams->passwdservers; *slist != NULL; slist++) { + if (num_entry_printed) + printf(" %25s %-50s\n", " ", *slist); + else + printf(" %-50s\n", *slist); + num_entry_printed++; + } + } + if (num_entry_printed == 0) + printf("\n"); + } + if (mask & LDAP_REALM_SUPPENCTYPE) { + printf("%25s:", "Supported Enc Types"); + if (rparams->suppenctypes != NULL) { + num_entry_printed = 0; + for(tmplist = rparams->suppenctypes; *tmplist != END_OF_LIST; + tmplist++) { + retval = krb5_enctype_to_string(*tmplist, buff, BUFF_LEN); + if (retval == 0) { + if (num_entry_printed) + printf(" %25s %-50s\n", " ", buff); + else + printf(" %-50s\n", buff); + num_entry_printed++; + } + } + } + if (num_entry_printed == 0) + printf("\n"); + } + if (mask & LDAP_REALM_DEFENCTYPE) { + retval = krb5_enctype_to_string(rparams->defenctype, buff, BUFF_LEN); + if (retval == 0) { + printf("%25s: %-50s\n", "Default Enc Type", buff); + } + } + if (mask & LDAP_REALM_SUPPSALTTYPE) { + printf("%25s:", "Supported Salt Types"); + if (rparams->suppsalttypes != NULL) { + num_entry_printed = 0; + for(tmplist = rparams->suppsalttypes; *tmplist != END_OF_LIST; + tmplist++) { + retval = krb5_salttype_to_string(*tmplist, buff, BUFF_LEN); + if (retval == 0) { + if (num_entry_printed) + printf(" %25s %-50s\n", " ", buff); + else + printf(" %-50s\n", buff); + num_entry_printed++; + } + } + } + if (num_entry_printed == 0) + printf("\n"); + } + if (mask & LDAP_REALM_MAXTICKETLIFE) { + printf("%25s:", "Maximum Ticket Life"); + printf(" %s \n", strdur(rparams->max_life)); + } + + if (mask & LDAP_REALM_MAXRENEWLIFE) { + printf("%25s:", "Maximum Renewable Life"); + printf(" %s \n", strdur(rparams->max_renewable_life)); + } + printf("%25s: ", "Ticket flags"); + if (mask & LDAP_POLICY_TKTFLAGS) { + int ticketflags = rparams->tktflags; + + if (ticketflags & KRB5_KDB_DISALLOW_POSTDATED) + printf("%s ","DISALLOW_POSTDATED"); + + if (ticketflags & KRB5_KDB_DISALLOW_FORWARDABLE) + printf("%s ","DISALLOW_FORWARDABLE"); + + if (ticketflags & KRB5_KDB_DISALLOW_RENEWABLE) + printf("%s ","DISALLOW_RENEWABLE"); + + if (ticketflags & KRB5_KDB_DISALLOW_PROXIABLE) + printf("%s ","DISALLOW_PROXIABLE"); + + if (ticketflags & KRB5_KDB_DISALLOW_DUP_SKEY) + printf("%s ","DISALLOW_DUP_SKEY"); + + if (ticketflags & KRB5_KDB_REQUIRES_PRE_AUTH) + printf("%s ","REQUIRES_PRE_AUTH"); + + if (ticketflags & KRB5_KDB_REQUIRES_HW_AUTH) + printf("%s ","REQUIRES_HW_AUTH"); + + if (ticketflags & KRB5_KDB_DISALLOW_SVR) + printf("%s ","DISALLOW_SVR"); + + if (ticketflags & KRB5_KDB_DISALLOW_TGT_BASED) + printf("%s ","DISALLOW_TGT_BASED"); + + if (ticketflags & KRB5_KDB_DISALLOW_ALL_TIX) + printf("%s ","DISALLOW_ALL_TIX"); + + if (ticketflags & KRB5_KDB_REQUIRES_PWCHANGE) + printf("%s ","REQUIRES_PWCHANGE"); + + if (ticketflags & KRB5_KDB_PWCHANGE_SERVICE) + printf("%s ","PWCHANGE_SERVICE"); + } + + if (mask & LDAP_REALM_DEFSALTTYPE) { + retval = krb5_salttype_to_string(rparams->defsalttype, buff, BUFF_LEN); + if (retval == 0) { + printf("\n%25s: %-50s\n", "Default Salt Type", buff); + } + } + /* if (mask & LDAP_REALM_POLICYREFERENCE) + printf("%25s: %-50s\n", "Policy Reference", rparams->policyreference);*/ + + + return; +} + + + +/* + * This function lists the Realm(s) present under the Kerberos container + * on the LDAP Server. + */ +void kdb5_ldap_list(argc, argv) + int argc; + char *argv[]; +{ + char **list = NULL; + char **plist = NULL; + krb5_error_code retval = 0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + + dal_handle = (kdb5_dal_handle *)util_context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + if (!(ldap_context)) { + retval = EINVAL; + exit_status++; + return; + } + + /* Read the kerberos container information */ + if ((retval = krb5_ldap_read_krbcontainer_params(util_context, + &(ldap_context->krbcontainer))) != 0) { + com_err(argv[0], retval, "while reading kerberos container information"); + exit_status++; + return; + } + + retval = krb5_ldap_list_realm(util_context, &list); + if (retval != 0) { + krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer); + ldap_context->krbcontainer = NULL; + com_err (argv[0], retval, "while listing realms"); + exit_status++; + return; + } + /* This is to handle the case of realm not present */ + if (list == NULL) { + krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer); + ldap_context->krbcontainer = NULL; + return; + } + + for(plist = list; *plist != NULL; plist++) { + printf("%s\n", *plist); + } + krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer); + ldap_context->krbcontainer = NULL; + krb5_free_list_entries(list); + free(list); + + return; +} + + +/* + * This function creates service principals when + * creating the realm object. + */ +static int +kdb_ldap_create_principal (context, princ, op, pblock) + krb5_context context; + krb5_principal princ; + enum ap_op op; + struct realm_info *pblock; +{ + int retval=0, currlen=0, princtype = 2 /* Service Principal */; + unsigned char *curr=NULL; + krb5_tl_data *tl_data=NULL; + krb5_db_entry entry; + int nentry=1; + long mask = 0; + krb5_keyblock key; + int kvno = 0; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context=NULL; + + if ((pblock == NULL) || (context == NULL)) { + retval = EINVAL; + goto cleanup; + } + dal_handle = (kdb5_dal_handle *) context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + if (!(ldap_context)) { + retval = EINVAL; + goto cleanup; + } + + memset(&entry, 0, sizeof(entry)); + + tl_data = malloc(sizeof(*tl_data)); + if (tl_data == NULL) { + retval = ENOMEM; + goto cleanup; + } + memset(tl_data, 0, sizeof(*tl_data)); + tl_data->tl_data_length = 1 + 2 + 2 + 1 + 2 + 4; + tl_data->tl_data_type = 7; /* KDB_TL_USER_INFO */ + curr = tl_data->tl_data_contents = malloc(tl_data->tl_data_length); + if (tl_data->tl_data_contents == NULL) { + retval = ENOMEM; + goto cleanup; + } + + memset(curr, 1, 1); /* Passing the mask as principal type */ + curr += 1; + currlen = 2; + STORE16_INT(curr, currlen); + curr += currlen; + STORE16_INT(curr, princtype); + curr += currlen; + + mask |= KDB_PRINCIPAL; + mask |= KDB_ATTRIBUTES ; + mask |= KDB_MAX_LIFE ; + mask |= KDB_MAX_RLIFE ; + mask |= KDB_PRINC_EXPIRE_TIME ; + mask |= KDB_KEY_DATA; + + entry.tl_data = tl_data; + entry.n_tl_data += 1; + entry.attributes = pblock->flags; + entry.max_life = pblock->max_life; + entry.max_renewable_life = pblock->max_rlife; + entry.expiration = pblock->expiration; + entry.mask = mask; + if ((retval = krb5_copy_principal(context, princ, &entry.princ))) + goto cleanup; + + /* Allocate memory for storing the key */ + if ((entry.key_data = (krb5_key_data *) malloc( + (sizeof(krb5_key_data)*(entry.n_key_data + 1)))) == NULL) { + retval = ENOMEM; + goto cleanup; + } + + memset(entry.key_data + entry.n_key_data, 0, sizeof(krb5_key_data)); + entry.n_key_data++; + + switch (op) + { + case TGT_KEY: + retval = krb5_c_make_random_key(context, 16, &key) ; + if( retval ) { + goto cleanup; + } + + kvno = 1; /* New key is getting set */ + retval = krb5_dbekd_encrypt_key_data(context, + &ldap_context->lrparams->mkey, + &key, NULL, kvno, + &entry.key_data[entry.n_key_data - 1]); + if( retval ) { + goto cleanup; + } + krb5_free_keyblock_contents(context, &key); + break; + + case MASTER_KEY: + kvno = 1; /* New key is getting set */ + retval = krb5_dbekd_encrypt_key_data(context, pblock->key, + &ldap_context->lrparams->mkey, NULL, kvno, + &entry.key_data[entry.n_key_data - 1]); + if( retval ) { + goto cleanup; + } + break; + + case NULL_KEY: + default: + break; + } /* end of switch */ + + retval = krb5_ldap_put_principal(context, &entry, &nentry, NULL); + if( retval ) { + com_err(NULL, retval, "while adding entries to database"); + goto cleanup; + } + + cleanup: + krb5_dbe_free_contents( context, &entry); + return retval; +} + + +/* + * This function destroys the realm object and the associated principals + */ +void +kdb5_ldap_destroy(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + int optchar = 0; + char buf[5] = {0}; + krb5_error_code retval = 0; + int force = 0; + int mask = 0; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context = NULL; +#ifdef HAVE_EDIRECTORY + int i = 0, rightsmask = 0; + krb5_ldap_realm_params *rparams = NULL; +#endif + + optind = 1; + while ((optchar = getopt(argc, argv, "f")) != -1) { + switch(optchar) { + case 'f': + force++; + break; + case '?': + default: + db_usage(DESTROY_REALM); + return; + /*NOTREACHED*/ + } + } + + if (!force) { + printf("Deleting KDC database of '%s', are you sure?\n", global_params.realm); + printf("(type 'yes' to confirm)? "); + if (fgets(buf, sizeof(buf), stdin) == NULL) { + exit_status++; + return; + } + if (strcmp(buf, yes)) { + exit_status++; + return; + } + printf("OK, deleting database of '%s'...\n", global_params.realm); + } + + dal_handle = (kdb5_dal_handle *)util_context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + if (!(ldap_context)) { + com_err(argv[0], EINVAL, "while initializing database"); + exit_status++; + return; + } + + /* Read the kerberos container from the LDAP Server */ + if ((retval = krb5_ldap_read_krbcontainer_params(util_context, + &(ldap_context->krbcontainer))) != 0) { + com_err(argv[0], retval, "while reading kerberos container information"); + exit_status++; + return; + } + + /* Read the Realm information from the LDAP Server */ + if ((retval = krb5_ldap_read_realm_params(util_context, global_params.realm, + &(ldap_context->lrparams), &mask)) != 0) { + com_err(argv[0], retval, "while reading realm information"); + exit_status++; + return; + } + +#ifdef HAVE_EDIRECTORY + if( (mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) || + (mask & LDAP_REALM_PASSWDSERVERS) ) { + + printf("Changing rights for the service object. Please wait ... "); + fflush(stdout); + + rparams = ldap_context->lrparams; + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + if ( (rparams != NULL) && (rparams->kdcservers != NULL) ) { + for ( i=0; (rparams->kdcservers[i] != NULL); i++) { + if((retval = krb5_ldap_delete_service_rights( util_context, + LDAP_KDC_SERVICE, rparams->kdcservers[i], + rparams->realm_name, rparams->subtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + return; + } + } + } + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + if ( (rparams != NULL) && (rparams->adminservers != NULL) ) { + for ( i=0; (rparams->adminservers[i] != NULL); i++) { + if((retval = krb5_ldap_delete_service_rights( util_context, + LDAP_ADMIN_SERVICE, rparams->adminservers[i], + rparams->realm_name, rparams->subtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + return; + } + } + } + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + if( (rparams != NULL) && (rparams->passwdservers != NULL) ) { + for ( i=0; (rparams->passwdservers[i] != NULL); i++) { + if((retval = krb5_ldap_delete_service_rights( util_context, + LDAP_PASSWD_SERVICE, rparams->passwdservers[i], + rparams->realm_name, rparams->subtree, rightsmask )) != 0) { + printf("failed\n"); + com_err(argv[0], retval, "while assigning rights to '%s'", + rparams->realm_name); + return; + } + } + } + printf("done\n"); + } +#endif + /* Delete the realm container and all the associated principals */ + retval = krb5_ldap_delete_realm(util_context, global_params.realm); + if (retval) { + com_err(argv[0], retval, "deleting database of '%s'", global_params.realm); + exit_status++; + return; + } + + printf("** Database of '%s' destroyed.\n", global_params.realm); + + return; +} diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.h b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.h new file mode 100644 index 000000000..1a0ea9ccb --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.h @@ -0,0 +1,63 @@ +/* + * kadmin/ldap_util/kdb5_ldap_realm.h + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#define MAX_KRB_CONTAINER_LEN 256 + +#define BUFF_LEN 64 /* Max len of enctype string */ +#define MAX_PRINC_SIZE 256 + +enum ap_op { + NULL_KEY, /* setup null keys */ + MASTER_KEY, /* use master key as new key */ + TGT_KEY /* special handling for tgt key */ +}; + +struct realm_info { + krb5_deltat max_life; + krb5_deltat max_rlife; + krb5_timestamp expiration; + krb5_flags flags; + krb5_keyblock *key; + krb5_int32 nkslist; + krb5_key_salt_tuple *kslist; +}; + +struct iterate_args { + krb5_context ctx; + struct realm_info *rblock; + krb5_db_entry *dbentp; +}; + +extern void kdb5_ldap_create (int argc, char **argv); +extern void kdb5_ldap_destroy (int argc, char **argv); +extern void kdb5_ldap_modify (int argc, char **argv); +extern void kdb5_ldap_view (int argc, char **argv); +extern void kdb5_ldap_list (int argc, char **argv); diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c new file mode 100644 index 000000000..69e3b7694 --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c @@ -0,0 +1,2181 @@ +/* + * kadmin/ldap_util/kdb5_ldap_services.c + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +/* + * Create / Delete / Modify / View / List service objects. + */ + +/* + * Service objects have rights over realm objects and principals. The following + * functions manage the service objects. + */ + +#include <stdio.h> +#include <k5-int.h> +#include "kdb5_ldap_util.h" +#include "kdb5_ldap_list.h" + +#ifdef HAVE_EDIRECTORY + +krb5_error_code +rem_service_entry_from_file( int argc, + char *argv[], + char *file_name, + char *service_object ); + +extern char *yes; +extern krb5_boolean db_inited; + +static int process_host_list(char **host_list, int servicetype) +{ + krb5_error_code retval = 0; + char *pchr = NULL; + char host_str[MAX_LEN_LIST_ENTRY] = "", proto_str[PROTOCOL_STR_LEN + 1] = "", port_str[PORT_STR_LEN + 1] = ""; + int j = 0; + + /* Protocol and port number processing */ + for (j = 0; host_list[j]; j++) { + /* Look for one hash */ + if ((pchr = strchr(host_list[j], HOST_INFO_DELIMITER))) { + unsigned int hostname_len = pchr - host_list[j]; + + /* Check input for buffer overflow */ + if (hostname_len >= MAX_LEN_LIST_ENTRY) { + retval = EINVAL; + goto cleanup; + } + + /* First copy off the host name portion */ + strncpy (host_str, host_list[j], hostname_len); + + /* Parse for the protocol string and translate to number */ + strncpy (proto_str, pchr + 1, PROTOCOL_STR_LEN); + if (!strcmp(proto_str, "udp")) + sprintf (proto_str, "%d", PROTOCOL_NUM_UDP); + else if (!strcmp(proto_str, "tcp")) + sprintf (proto_str, "%d", PROTOCOL_NUM_TCP); + else + proto_str[0] = '\0'; /* Make the string null if invalid */ + + /* Look for one more hash */ + if ((pchr = strchr(pchr + 1, HOST_INFO_DELIMITER))) { + /* Parse for the port string and check if it is numeric */ + strncpy (port_str, pchr + 1, PORT_STR_LEN); + if (!strtol(port_str, NULL, 10)) /* Not a valid number */ + port_str[0] = '\0'; + } + else + port_str[0] = '\0'; + } + else { /* We have only host name */ + strncpy (host_str, host_list[j], MAX_LEN_LIST_ENTRY - 1); + proto_str[0] = '\0'; + port_str[0] = '\0'; + } + + /* Now, based on service type, fill in suitable protocol + and port values if they are absent or not matching */ + if (servicetype == LDAP_KDC_SERVICE) { + if (proto_str[0] == '\0') + sprintf (proto_str, "%d", PROTOCOL_DEFAULT_KDC); + + if (port_str[0] == '\0') + sprintf (port_str, "%d", PORT_DEFAULT_KDC); + } + else if (servicetype == LDAP_ADMIN_SERVICE) { + if (proto_str[0] == '\0') + sprintf (proto_str, "%d", PROTOCOL_DEFAULT_ADM); + else if (strcmp(proto_str, "1")) { + sprintf (proto_str, "%d", PROTOCOL_DEFAULT_ADM); + + /* Print warning message */ + printf ("Admin Server supports only TCP protocol, hence setting that\n"); + } + + if (port_str[0] == '\0') + sprintf (port_str, "%d", PORT_DEFAULT_ADM); + } + else if (servicetype == LDAP_PASSWD_SERVICE) { + if (proto_str[0] == '\0') + sprintf (proto_str, "%d", PROTOCOL_DEFAULT_PWD); + else if (strcmp(proto_str, "0")) { + sprintf (proto_str, "%d", PROTOCOL_DEFAULT_PWD); + + /* Print warning message */ + printf ("Password Server supports only UDP protocol, hence setting that\n"); + } + + if (port_str[0] == '\0') + sprintf (port_str, "%d", PORT_DEFAULT_PWD); + } + + /* Finally form back the string */ + free (host_list[j]); + host_list[j] = (char*) malloc(sizeof(char) * + (strlen(host_str) + strlen(proto_str) + strlen(port_str) + 2 + 1)); + if (host_list[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + snprintf (host_list[j], strlen(host_str) + strlen(proto_str) + strlen(port_str) + 2 + 1, + "%s#%s#%s", host_str, proto_str, port_str); + } + +cleanup: + return retval; +} + + +/* + * Given a realm name, this function will convert it to a DN by appending the + * Kerberos container location. + */ +static krb5_error_code +convert_realm_name2dn_list(list, krbcontainer_loc) + char **list; + const char *krbcontainer_loc; +{ + krb5_error_code retval = 0; + char temp_str[MAX_DN_CHARS] = "\0"; + char *temp_node = NULL; + int i = 0; + + if (list == NULL) { + return EINVAL; + } + + for (i = 0; (list[i] != NULL) && (i < MAX_LIST_ENTRIES); i++) { + /* Restrict copying to max. length to avoid buffer overflow */ + snprintf (temp_str, MAX_DN_CHARS, "cn=%s,%s", list[i], krbcontainer_loc); + + /* Make copy of string to temporary node */ + temp_node = strdup(temp_str); + if (list[i] == NULL) { + retval = ENOMEM; + goto cleanup; + } + + /* On success, free list node and attach new one */ + free (list[i]); + list[i] = temp_node; + temp_node = NULL; + } + +cleanup: + return retval; +} + + +/* + * This function will create a service object on the LDAP Server, with the + * specified attributes. + */ +void kdb5_ldap_create_service(argc, argv) + int argc; + char *argv[]; +{ + char *me = argv[0]; + krb5_error_code retval = 0; + krb5_ldap_service_params *srvparams = NULL; + krb5_boolean print_usage = FALSE; + krb5_boolean no_msg = FALSE; + int mask = 0; + char **extra_argv = NULL; + int extra_argc = 0; + int i = 0; + krb5_ldap_realm_params *rparams = NULL; + int rmask = 0; + int rightsmask =0; + char **temprdns = NULL; + char *realmName = NULL; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_boolean service_obj_created = FALSE; + + /* Check for number of arguments */ + if ((argc < 3) || (argc > 10)) { + exit_status++; + goto err_usage; + } + + /* Allocate memory for service parameters structure */ + srvparams = (krb5_ldap_service_params*) calloc(1, sizeof(krb5_ldap_service_params)); + if (srvparams == NULL) { + retval = ENOMEM; + goto cleanup; + } + + dal_handle = (kdb5_dal_handle *) util_context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + + /* Allocate memory for extra arguments to be used for setting + password -- it's OK to allocate as much as the total number + of arguments */ + extra_argv = (char **) calloc((unsigned int)argc, sizeof(char*)); + if (extra_argv == NULL) { + retval = ENOMEM; + goto cleanup; + } + + /* Set first of the extra arguments as the program name */ + extra_argv[0] = me; + extra_argc++; + + /* Read Kerberos container info, to construct realm DN from name + * and for assigning rights + */ + if ((retval = krb5_ldap_read_krbcontainer_params(util_context, + &(ldap_context->krbcontainer)))) { + com_err(me, retval, "while reading Kerberos container information"); + goto cleanup; + } + + /* Parse all arguments */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-kdc")) { + srvparams->servicetype = LDAP_KDC_SERVICE; + } + else if (!strcmp(argv[i], "-admin")) { + srvparams->servicetype = LDAP_ADMIN_SERVICE; + } + else if (!strcmp(argv[i], "-pwd")) { + srvparams->servicetype = LDAP_PASSWD_SERVICE; + } + else if (!strcmp(argv[i], "-servicehost")) { + if (++i > argc - 1) + goto err_usage; + + srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES, + sizeof(char *)); + if (srvparams->krbhostservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + srvparams->krbhostservers))) { + goto cleanup; + } + + if ((retval = process_host_list (srvparams->krbhostservers, + srvparams->servicetype))) { + goto cleanup; + } + + mask |= LDAP_SERVICE_HOSTSERVER; + } + else if (!strcmp(argv[i], "-realm")) { + if (++i > argc - 1) + goto err_usage; + + srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES, + sizeof(char *)); + if (srvparams->krbrealmreferences == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + srvparams->krbrealmreferences))) { + goto cleanup; + } + + /* Convert realm names to realm DNs */ + if ((retval = convert_realm_name2dn_list( + srvparams->krbrealmreferences, + ldap_context->krbcontainer->DN))) { + goto cleanup; + } + + mask |= LDAP_SERVICE_REALMREFERENCE; + } + /* If argument is none of the above and beginning with '-', + * it must be related to password -- collect it + * to pass onto kdb5_ldap_set_service_password() + */ + else if (*(argv[i]) == '-') { + /* Checking for options of setting the password for the + * service (by using 'setsrvpw') is not modular. --need to + * have a common function that can be shared with 'setsrvpw' + */ + if (!strcmp(argv[i], "-randpw")) { + extra_argv[extra_argc] = argv[i]; + extra_argc++; + } + else if (!strcmp(argv[i], "-fileonly")) { + extra_argv[extra_argc] = argv[i]; + extra_argc++; + } + /* For '-f' option alone, pick up the following argument too */ + else if (!strcmp(argv[i], "-f")) { + extra_argv[extra_argc] = argv[i]; + extra_argc++; + + if (++i > argc - 1) + goto err_usage; + + extra_argv[extra_argc] = argv[i]; + extra_argc++; + } + else { /* Any other option is invalid */ + exit_status++; + goto err_usage; + } + } + else { /* Any other argument must be service DN */ + /* First check if service DN is already provided -- + * if so, there's a usage error + */ + if (srvparams->servicedn != NULL) { + com_err(me, EINVAL, "while creating service object"); + goto err_usage; + } + + /* If not present already, fill up service DN */ + srvparams->servicedn = strdup(argv[i]); + if (srvparams->servicedn == NULL) { + com_err(me, ENOMEM, "while creating service object"); + goto err_nomsg; + } + } + } + + /* No point in proceeding further if service DN value is not available */ + if (srvparams->servicedn == NULL) { + com_err(me, EINVAL, "while creating service object"); + goto err_usage; + } + + if (srvparams->servicetype == 0) { /* Not provided and hence not set */ + com_err(me, EINVAL, "while creating service object"); + goto err_usage; + } + + /* Create object with all attributes provided */ + if ((retval = krb5_ldap_create_service(util_context, srvparams, mask))) + goto cleanup; + + service_obj_created = TRUE; + + /* ** NOTE ** srvparams structure should not be modified, as it is + * used for deletion of the service object in case of any failures + * from now on. + */ + + /* Set password too */ + if (extra_argc >= 1) { + /* Set service DN as the last argument */ + extra_argv[extra_argc] = strdup(srvparams->servicedn); + extra_argc++; + + if( (retval = kdb5_ldap_set_service_password(extra_argc, extra_argv)) != 0 ) + { + goto err_nomsg; + } + } + /* Rights assignment */ + if( mask & LDAP_SERVICE_REALMREFERENCE ) { + + printf("%s","Changing rights for the service object. Please wait ... "); + fflush(stdout); + + rightsmask =0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + + if( (srvparams != NULL) && (srvparams->krbrealmreferences != NULL) ) { + for ( i=0; (srvparams->krbrealmreferences[i] != NULL); i++) { + + /* Get the realm name, not the dn */ + temprdns = ldap_explode_dn(srvparams->krbrealmreferences[i], 1); + + if( temprdns[0] == NULL ) { + retval = EINVAL; + goto cleanup; + } + + realmName = strdup(temprdns[0]); + if( realmName == NULL ) { + retval = ENOMEM; + goto cleanup; + } + + if((retval = krb5_ldap_read_realm_params(util_context, + realmName, &rparams, &rmask))) { + com_err(me, retval, "while reading information of realm '%s'", + realmName); + goto cleanup; + } + + if((retval = krb5_ldap_add_service_rights(util_context, + srvparams->servicetype, srvparams->servicedn, + realmName, rparams->subtree, rightsmask))) { + printf("failed\n"); + com_err(me, retval, "while assigning rights '%s'", + srvparams->servicedn); + goto cleanup; + } + + if( rparams ) + krb5_ldap_free_realm_params(rparams); + } + } + printf("done\n"); + } + goto cleanup; + +err_usage: + print_usage = TRUE; + +err_nomsg: + no_msg = TRUE; + +cleanup: + + if ((retval != 0) && (service_obj_created == TRUE)) + { + /* This is for deleting the service object if something goes + * wrong in creating the service object + */ + + /* srvparams is populated from the user input and should be correct as + * we were successful in creating a service object. Reusing the same + */ + krb5_ldap_delete_service(util_context, srvparams, srvparams->servicedn); + } + + /* Clean-up structure */ + krb5_ldap_free_service (util_context, srvparams); + + if (extra_argv) { + free (extra_argv); + extra_argv = NULL; + } + if ( realmName ) { + free(realmName); + realmName = NULL; + } + if (print_usage) + db_usage (CREATE_SERVICE); + + if (retval) { + if (!no_msg) + com_err(me, retval, "while creating service object"); + + exit_status++; + } + + return; +} + + +/* + * This function will modify the attributes of a given service + * object on the LDAP Server + */ +void kdb5_ldap_modify_service(argc, argv) + int argc; + char *argv[]; +{ + char *me = argv[0]; + krb5_error_code retval = 0; + krb5_ldap_service_params *srvparams = NULL; + krb5_boolean print_usage = FALSE; + krb5_boolean no_msg = FALSE; + char *servicedn = NULL; + int i = 0; + int in_mask = 0, out_mask = 0; + int srvhost_flag = 0, realmdn_flag = 0; + char **list = NULL; + int existing_entries = 0, new_entries = 0; + char **temp_ptr = NULL; + krb5_ldap_realm_params *rparams = NULL; + int j = 0; + int rmask = 0; + int rightsmask =0; + char **oldrealmrefs = NULL; + char **newrealmrefs = NULL; + char **temprdns = NULL; + char *realmName = NULL; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context=NULL; + + /* Check for number of arguments */ + if ((argc < 3) || (argc > 10)) { + exit_status++; + goto err_usage; + } + + dal_handle = (kdb5_dal_handle *) util_context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + + /* Parse all arguments, only to pick up service DN (Pass 1) */ + for (i = 1; i < argc; i++) { + /* Skip arguments next to 'servicehost' + and 'realmdn' arguments */ + if (!strcmp(argv[i], "-servicehost")) { + ++i; + } + else if (!strcmp(argv[i], "-clearservicehost")) { + ++i; + } + else if (!strcmp(argv[i], "-addservicehost")) { + ++i; + } + else if (!strcmp(argv[i], "-realm")) { + ++i; + } + else if (!strcmp(argv[i], "-clearrealm")) { + ++i; + } + else if (!strcmp(argv[i], "-addrealm")) { + ++i; + } + else { /* Any other argument must be service DN */ + /* First check if service DN is already provided -- + if so, there's a usage error */ + if (servicedn != NULL) { + com_err(me, EINVAL, "while modifying service object"); + goto err_usage; + } + + /* If not present already, fill up service DN */ + servicedn = strdup(argv[i]); + if (servicedn == NULL) { + com_err(me, ENOMEM, "while modifying service object"); + goto err_nomsg; + } + } + } + + /* No point in proceeding further if service DN value is not available */ + if (servicedn == NULL) { + com_err(me, EINVAL, "while modifying service object"); + goto err_usage; + } + + retval = krb5_ldap_read_service(util_context, servicedn, &srvparams, &in_mask); + if (retval) { + com_err(argv[0], retval, "while reading information of service '%s'", + servicedn); + goto err_nomsg; + } + + /* Read Kerberos container info, to construct realm DN from name + * and for assigning rights + */ + if ((retval = krb5_ldap_read_krbcontainer_params(util_context, + &(ldap_context->krbcontainer)))) { + com_err(me, retval, "while reading Kerberos container information"); + goto cleanup; + } + + /* Parse all arguments, but skip the service DN (Pass 2) */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-servicehost")) { + if (++i > argc - 1) + goto err_usage; + + /* Free the old list if available */ + if (srvparams->krbhostservers) { + krb5_free_list_entries (srvparams->krbhostservers); + free (srvparams->krbhostservers); + } + + srvparams->krbhostservers = (char **)calloc(MAX_LIST_ENTRIES, + sizeof(char *)); + if (srvparams->krbhostservers == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + srvparams->krbhostservers))) { + goto cleanup; + } + + if ((retval = process_host_list (srvparams->krbhostservers, + srvparams->servicetype))) { + goto cleanup; + } + + out_mask |= LDAP_SERVICE_HOSTSERVER; + + /* Set flag to ignore 'add' and 'clear' */ + srvhost_flag = 1; + } + else if (!strcmp(argv[i], "-clearservicehost")) { + if (++i > argc - 1) + goto err_usage; + + if (!srvhost_flag) { + /* If attribute doesn't exist, don't permit 'clear' option */ + if ((in_mask & LDAP_SERVICE_HOSTSERVER) == 0) { + /* Send out some proper error message here */ + com_err(me, EINVAL, "service host list is empty\n"); + goto err_nomsg; + } + + /* Allocate list for processing */ + list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (list == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + if ((retval = process_host_list (list, srvparams->servicetype))) { + goto cleanup; + } + + list_modify_str_array(&(srvparams->krbhostservers), + (const char**)list, LIST_MODE_DELETE); + + out_mask |= LDAP_SERVICE_HOSTSERVER; + + /* Clean up */ + free (list); + list = NULL; + } + } + else if (!strcmp(argv[i], "-addservicehost")) { + if (++i > argc - 1) + goto err_usage; + + if (!srvhost_flag) { + /* Allocate list for processing */ + list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (list == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + if ((retval = process_host_list (list, srvparams->servicetype))) { + goto cleanup; + } + + /* Call list_modify_str_array() only if host server attribute + * exists already --Actually, it's better to handle this + * within list_modify_str_array() + */ + if (in_mask & LDAP_SERVICE_HOSTSERVER) { + /* Re-size existing list */ + existing_entries = list_count_str_array(srvparams->krbhostservers); + new_entries = list_count_str_array(list); + temp_ptr = (char **) realloc(srvparams->krbhostservers, + sizeof(char *) * (existing_entries + new_entries + 1)); + if (temp_ptr == NULL) { + retval = ENOMEM; + goto cleanup; + } + srvparams->krbhostservers = temp_ptr; + + list_modify_str_array(&(srvparams->krbhostservers), + (const char**)list, LIST_MODE_ADD); + + /* Clean up */ + free (list); + list = NULL; + } + else + srvparams->krbhostservers = list; + + out_mask |= LDAP_SERVICE_HOSTSERVER; + } + } + else if (!strcmp(argv[i], "-realm")) { + if (++i > argc - 1) + goto err_usage; + + if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences)) { + if (!oldrealmrefs) { + /* Store the old realm list for removing rights */ + oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldrealmrefs == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { + oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); + if (oldrealmrefs[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldrealmrefs[j] = NULL; + } + + /* Free the old list if available */ + krb5_free_list_entries (srvparams->krbrealmreferences); + free (srvparams->krbrealmreferences); + } + + srvparams->krbrealmreferences = (char **)calloc(MAX_LIST_ENTRIES, + sizeof(char *)); + if (srvparams->krbrealmreferences == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, + srvparams->krbrealmreferences))) { + goto cleanup; + } + + /* Convert realm names to realm DNs */ + if ((retval = convert_realm_name2dn_list( + srvparams->krbrealmreferences, + ldap_context->krbcontainer->DN))) { + goto cleanup; + } + + out_mask |= LDAP_SERVICE_REALMREFERENCE; + + /* Set flag to ignore 'add' and 'clear' */ + realmdn_flag = 1; + } + else if (!strcmp(argv[i], "-clearrealm")) { + if (++i > argc - 1) + goto err_usage; + + if (!realmdn_flag) { + /* If attribute doesn't exist, don't permit 'clear' option */ + if (((in_mask & LDAP_SERVICE_REALMREFERENCE) == 0) || (srvparams->krbrealmreferences == NULL)) { + /* Send out some proper error message here */ + goto err_nomsg; + } + + if (!oldrealmrefs) { + /* Store the old realm list for removing rights */ + oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldrealmrefs == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { + oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); + if (oldrealmrefs[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldrealmrefs[j] = NULL; + } + + /* Allocate list for processing */ + list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (list == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + /* Convert realm names to realm DNs */ + if ((retval = convert_realm_name2dn_list(list, + ldap_context->krbcontainer->DN))) { + goto cleanup; + } + + list_modify_str_array(&(srvparams->krbrealmreferences), + (const char**)list, LIST_MODE_DELETE); + + out_mask |= LDAP_SERVICE_REALMREFERENCE; + + /* Clean up */ + free (list); + list = NULL; + } + } + else if (!strcmp(argv[i], "-addrealm")) { + if (++i > argc - 1) + goto err_usage; + + if (!realmdn_flag) { + /* Allocate list for processing */ + list = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (list == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + /* Convert realm names to realm DNs */ + if ((retval = convert_realm_name2dn_list(list, + ldap_context->krbcontainer->DN))) { + goto cleanup; + } + + if ((in_mask & LDAP_SERVICE_REALMREFERENCE) && (srvparams->krbrealmreferences) && (!oldrealmrefs)) { + /* Store the old realm list for removing rights */ + oldrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (oldrealmrefs == NULL) { + retval = ENOMEM; + goto cleanup; + } + + for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { + oldrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); + if (oldrealmrefs[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + oldrealmrefs[j] = NULL; + } + + /* Call list_modify_str_array() only if realm DN attribute + * exists already -- Actually, it's better to handle this + * within list_modify_str_array() */ + if (in_mask & LDAP_SERVICE_REALMREFERENCE) { + /* Re-size existing list */ + existing_entries = list_count_str_array( + srvparams->krbrealmreferences); + new_entries = list_count_str_array(list); + temp_ptr = (char **) realloc(srvparams->krbrealmreferences, + sizeof(char *) * (existing_entries + new_entries + 1)); + if (temp_ptr == NULL) { + retval = ENOMEM; + goto cleanup; + } + srvparams->krbrealmreferences = temp_ptr; + + list_modify_str_array(&(srvparams->krbrealmreferences), + (const char**)list, LIST_MODE_ADD); + + /* Clean up */ + free (list); + list = NULL; + } + else + srvparams->krbrealmreferences = list; + + out_mask |= LDAP_SERVICE_REALMREFERENCE; + } + } + else { + /* Any other argument must be service DN + -- skip it */ + } + } + + /* Modify attributes of object */ + if ((retval = krb5_ldap_modify_service(util_context, srvparams, out_mask))) + goto cleanup; + + /* Service rights modification code */ + if (out_mask & LDAP_SERVICE_REALMREFERENCE) { + + printf("%s","Changing rights for the service object. Please wait ... "); + fflush(stdout); + + newrealmrefs = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); + if (newrealmrefs == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((srvparams != NULL) && (srvparams->krbrealmreferences != NULL)) { + for (j = 0; srvparams->krbrealmreferences[j] != NULL; j++) { + newrealmrefs[j] = strdup(srvparams->krbrealmreferences[j]); + if (newrealmrefs[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + newrealmrefs[j] = NULL; + } + disjoint_members(oldrealmrefs, newrealmrefs); + + /* Delete the rights for the given service, on each of the realm + * container & subtree in the old realm reference list. + */ + if (oldrealmrefs) { + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + + for (i = 0; (oldrealmrefs[i] != NULL); i++) { + /* Get the realm name, not the dn */ + temprdns = ldap_explode_dn(oldrealmrefs[i], 1); + + if (temprdns[0] == NULL) { + retval = EINVAL; + goto cleanup; + } + + realmName = strdup(temprdns[0]); + if (realmName == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_ldap_read_realm_params(util_context, + realmName, &rparams, &rmask))) { + com_err(me, retval, "while reading information of realm '%s'", + realmName); + goto err_nomsg; + } + + if ((retval = krb5_ldap_delete_service_rights(util_context, + srvparams->servicetype, srvparams->servicedn, + realmName, rparams->subtree, rightsmask))) { + printf("failed\n"); + com_err(me, retval, "while assigning rights '%s'", + srvparams->servicedn); + goto err_nomsg; + } + + if (rparams) + krb5_ldap_free_realm_params(rparams); + } + } + + /* Add the rights for the given service, on each of the realm + * container & subtree in the new realm reference list. + */ + if (newrealmrefs) { + rightsmask = 0; + rightsmask |= LDAP_REALM_RIGHTS; + rightsmask |= LDAP_SUBTREE_RIGHTS; + + for (i = 0; (newrealmrefs[i] != NULL); i++) { + /* Get the realm name, not the dn */ + temprdns = ldap_explode_dn(newrealmrefs[i], 1); + + if (temprdns[0] == NULL) { + retval = EINVAL; + goto cleanup; + } + + realmName = strdup(temprdns[0]); + if (realmName == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ((retval = krb5_ldap_read_krbcontainer_params(util_context, + &(ldap_context->krbcontainer)))) { + com_err(me, retval, + "while reading Kerberos container information"); + goto cleanup; + } + + if ((retval = krb5_ldap_read_realm_params(util_context, + realmName, &rparams, &rmask))) { + com_err(me, retval, "while reading information of realm '%s'", + realmName); + goto err_nomsg; + } + + if ((retval = krb5_ldap_add_service_rights(util_context, + srvparams->servicetype, srvparams->servicedn, + realmName, rparams->subtree, rightsmask))) { + printf("failed\n"); + com_err(me, retval, "while assigning rights '%s'", + srvparams->servicedn); + goto err_nomsg; + } + + if (rparams) { + krb5_ldap_free_realm_params(rparams); + rparams = NULL; + } + } + printf("done\n"); + } + } + goto cleanup; + +err_usage: + print_usage = TRUE; + +err_nomsg: + no_msg = TRUE; + +cleanup: + /* Clean-up structure */ + krb5_ldap_free_service(util_context, srvparams); + + if (servicedn) + free(servicedn); + + if (list) { + free(list); + list = NULL; + } + + if (oldrealmrefs) { + for (i = 0; oldrealmrefs[i] != NULL; i++) + free(oldrealmrefs[i]); + free(oldrealmrefs); + } + + if (newrealmrefs) { + for (i = 0; newrealmrefs[i] != NULL; i++) + free(newrealmrefs[i]); + free(newrealmrefs); + } + if (realmName) { + free(realmName); + realmName = NULL; + } + + if (print_usage) + db_usage(MODIFY_SERVICE); + + if (retval) { + if (!no_msg) + com_err(me, retval, "while modifying service object"); + exit_status++; + } + + return; +} + + +/* + * This function will delete the entry corresponding to the service object + * from the service password file. + */ +static krb5_error_code +rem_service_entry_from_file(argc, argv, file_name, service_object) +int argc; +char *argv[]; +char *file_name; +char *service_object; +{ + int st = EINVAL; + char *me = argv[0]; + char *tmp_file = NULL; + int tmpfd = -1; + FILE *pfile = NULL; + unsigned int len = 0; + char line[MAX_LEN]={0}; + mode_t omask = umask(077); + + /* Check for permissions on the password file */ + if (access(file_name, W_OK) == -1) { + /* If the specified file itself is not there, no need to show error */ + if (errno == ENOENT) { + st=0; + goto cleanup; + } + else { + com_err(me, errno, "while deleting entry from file %s", file_name); + goto cleanup; + } + } + + /* Create a temporary file which contains all the entries except the + entry for the given service dn */ + pfile = fopen(file_name, "r+"); + if (pfile == NULL) { + com_err(me, errno, "while deleting entry from file %s", file_name); + goto cleanup; + } + + /* Create a new file with the extension .tmp */ + tmp_file = (char *)malloc(strlen(file_name) + 4 + 1); + if (tmp_file == NULL) { + com_err(me, ENOMEM, "while deleting entry from file"); + fclose(pfile); + goto cleanup; + } + snprintf (tmp_file, strlen(file_name) + 4 + 1, "%s%s", file_name, ".tmp"); + + + tmpfd = creat(tmp_file, S_IRUSR|S_IWUSR); + umask(omask); + if (tmpfd == -1) { + com_err(me, errno, "while deleting entry from file\n"); + fclose(pfile); + goto cleanup; + } + + /* Copy only those lines which donot have the specified service dn */ + while(fgets(line, MAX_LEN, pfile) != NULL) { + if (( strstr(line, service_object) != NULL ) && + ( line[strlen(service_object)] == '#')) { + continue; + } + else { + len = strlen(line); + if (write(tmpfd, line, len) != len) { + com_err(me, errno, "while deleting entry from file\n"); + close(tmpfd); + unlink(tmp_file); + fclose(pfile); + goto cleanup; + } + } + } + + fclose(pfile); + if (unlink(file_name) == 0) { + link(tmp_file, file_name); + } + else { + com_err(me, errno, "while deleting entry from file\n"); + } + unlink(tmp_file); + + st=0; + + cleanup: + + if(tmp_file) + free(tmp_file); + + return st; +} + + +/* + * This function will delete the service object from the LDAP Server + * and unlink the references to the Realm objects (if any) + */ +void +kdb5_ldap_destroy_service(argc, argv) + int argc; + char *argv[]; +{ + int i = 0; + char buf[5] = {0}; + krb5_error_code retval = EINVAL; + int force = 0; + char *servicedn = NULL; + char *stashfilename = NULL; + int mask = 0; + krb5_ldap_service_params *lserparams = NULL; + krb5_boolean print_usage = FALSE; + + if ((argc < 2) || (argc > 5)) { + exit_status++; + goto err_usage; + } + + for( i=1; i < argc; i++) { + + if(strcmp(argv[i],"-force")==0) { + force++; + } + else if(strcmp(argv[i],"-f")==0) { + if(argv[i+1]) { + stashfilename=strdup(argv[i+1]); + if(stashfilename == NULL) { + com_err(argv[0], ENOMEM, "while destroying service"); + exit_status++; + goto cleanup; + } + i++; + } + else { + exit_status++; + goto err_usage; + } + } + else { + if((argv[i]) && ( servicedn == NULL) ){ + servicedn=strdup(argv[i]); + if(servicedn == NULL) { + com_err(argv[0], ENOMEM, "while destroying service"); + exit_status++; + goto cleanup; + } + } + else { + exit_status++; + goto err_usage; + } + } + } + + if(!servicedn) { + exit_status++; + goto err_usage; + } + + if (!force) { + printf("This will delete the service object '%s', are you sure?\n", servicedn); + printf("(type 'yes' to confirm)? "); + if (fgets(buf, sizeof(buf), stdin) == NULL) { + exit_status++; + goto cleanup;; + } + if (strcmp(buf, yes)) { + exit_status++; + goto cleanup; + } + } + + if ((retval = krb5_ldap_read_service( util_context, servicedn, + &lserparams, &mask))) { + com_err(argv[0], retval, "while destroying service '%s'",servicedn ); + exit_status++; + goto cleanup; + } + + retval = krb5_ldap_delete_service(util_context, lserparams, servicedn); + + if (retval) { + com_err(argv[0], retval, "while destroying service '%s'", servicedn); + exit_status++; + goto cleanup; + } + + if(stashfilename == NULL) { + stashfilename = strdup(DEF_SERVICE_PASSWD_FILE); + if(stashfilename == NULL) { + com_err(argv[0], ENOMEM, "while destroying service"); + exit_status++; + goto cleanup; + } + } + printf("** service object '%s' deleted.\n", servicedn); + retval = rem_service_entry_from_file(argc, argv, stashfilename, servicedn ); + + if(retval) + printf("** error removing service object entry '%s' from password file.\n", + servicedn); + + goto cleanup; + + + err_usage: + print_usage = TRUE; + + cleanup: + + if(lserparams) { + krb5_ldap_free_service(util_context, lserparams); + } + + if(servicedn) { + free(servicedn); + } + + if(stashfilename) { + free(stashfilename); + } + + if(print_usage) { + db_usage(DESTROY_SERVICE); + } + + return; +} + + +/* + * This function will display information about the given service object + */ +void kdb5_ldap_view_service(argc, argv) + int argc; + char *argv[]; +{ + krb5_ldap_service_params *lserparams = NULL; + krb5_error_code retval = 0; + char *servicedn = NULL; + int mask = 0; + krb5_boolean print_usage = FALSE; + + if (!(argc == 2)) { + exit_status++; + goto err_usage; + } + + servicedn=strdup(argv[1]); + if(servicedn == NULL) { + com_err(argv[0], ENOMEM, "while viewing service"); + exit_status++; + goto cleanup; + } + + if ((retval = krb5_ldap_read_service( util_context, servicedn, &lserparams, &mask))) { + com_err(argv[0], retval, "while viewing service '%s'",servicedn ); + exit_status++; + goto cleanup; + } + + print_service_params(lserparams, mask); + + goto cleanup; + + err_usage: + print_usage = TRUE; + + cleanup: + + if(lserparams) { + krb5_ldap_free_service(util_context, lserparams); + } + + if(servicedn) + free(servicedn); + + if(print_usage) { + db_usage(VIEW_SERVICE); + } + + return; +} + + +/* + * This function will list the DNs of kerberos services present on + * the LDAP Server under a specific sub-tree (entire tree by default) + */ +void kdb5_ldap_list_services(argc, argv) + int argc; + char *argv[]; +{ + char *me = argv[0]; + krb5_error_code retval = 0; + char *basedn = NULL; + char **list = NULL; + char **plist = NULL; + krb5_boolean print_usage = FALSE; + + /* Check for number of arguments */ + if ((argc != 1) && (argc != 3)) { + exit_status++; + goto err_usage; + } + + /* Parse base DN argument if present */ + if (argc == 3) { + if (strcmp(argv[1], "-basedn")) { + retval = EINVAL; + goto err_usage; + } + + basedn = strdup(argv[2]); + if (basedn == NULL) { + com_err(me, ENOMEM, "while listing services"); + exit_status++; + goto cleanup; + } + } + + retval = krb5_ldap_list_services(util_context, basedn, &list); + if((retval != 0) || (list == NULL)) { + exit_status++; + goto cleanup; + } + + for(plist = list; *plist != NULL; plist++) { + printf("%s\n", *plist); + } + + goto cleanup; + +err_usage: + print_usage = TRUE; + +cleanup: + if (list != NULL) { + krb5_free_list_entries (list); + free (list); + } + + if (basedn) + free (basedn); + + if (print_usage) { + db_usage(LIST_SERVICE); + } + + if (retval) { + com_err(me, retval, "while listing policy objects"); + exit_status++; + } + + return; +} + + +/* + * This function will print the service object information + * to the standard output + */ +static void +print_service_params(lserparams, mask) + krb5_ldap_service_params *lserparams; + int mask; +{ + int i=0; + + /* Print the service dn */ + printf("%20s%-20s\n","Service dn: ",lserparams->servicedn); + + /* Print the service type of the object to be read */ + if( lserparams->servicetype == LDAP_KDC_SERVICE ) { + printf("%20s%-20s\n","Service type: ","kdc"); + } + else if( lserparams->servicetype == LDAP_ADMIN_SERVICE ) { + printf("%20s%-20s\n","Service type: ","admin"); + } + else if( lserparams->servicetype == LDAP_PASSWD_SERVICE ) { + printf("%20s%-20s\n","Service type: ","pwd"); + } + + /* Print the host server values */ + printf("%20s\n","Service host list: "); + if ( mask & LDAP_SERVICE_HOSTSERVER ) { + for ( i=0; lserparams->krbhostservers[i] != NULL; ++i ) { + printf("%20s%-50s\n","",lserparams->krbhostservers[i]); + } + } + + /* Print the realm reference dn values */ + printf("%20s\n","Realm DN list: "); + if ( mask & LDAP_SERVICE_REALMREFERENCE ) { + for ( i=0; lserparams && lserparams->krbrealmreferences && lserparams->krbrealmreferences[i] != NULL; ++i ) { + printf("%20s%-50s\n","",lserparams->krbrealmreferences[i]); + } + } + + return; +} + + +/* + * This function will generate random password of length(RANDOM_PASSWD_LEN) + * + * + * INPUT: + * ctxt - context + * + * OUTPUT: + * RANDOM_PASSWD_LEN length random password + */ +static int generate_random_password(krb5_context ctxt, char **randpwd, unsigned int *passlen) +{ + char *random_pwd = NULL; + int ret = 0; + krb5_data data; + int i=0; + /*int len = 0;*/ + + /* setting random password length in the range 16-32 */ + srand((unsigned int)(time(0) ^ getpid())); + + data.length = RANDOM_PASSWD_LEN; + random_pwd = (char *)malloc(data.length + 1); + if (random_pwd == NULL) { + com_err("setsrvpw", ENOMEM, "while generating random password"); + return ENOMEM; + } + memset(random_pwd, 0, data.length + 1); + data.data = random_pwd; + + ret = krb5_c_random_make_octets(ctxt, &data); + if(ret) { + com_err("setsrvpw", ret, "Error generating random password"); + free(random_pwd); + return ret; + } + + for (i=0; i<data.length; i++) + { + /* restricting to ascii chars. Need to change this when 8.8 supports */ + if ((unsigned char)random_pwd[i] > 127) + { + random_pwd[i] = (unsigned char)random_pwd[i] % 128; + } + else if (random_pwd[i] == 0) + { + random_pwd[i] = (rand()/(RAND_MAX/127 + 1))+1; + } + } + + *randpwd = random_pwd; + *passlen = data.length; + + return 0; +} + + +/* + * This function will set the password of the service object in the directory + * and/or the specified service password file. + * + * + * INPUT: + * argc - contains the number of arguments for this sub-command + * argv - array of arguments for this sub-command + * + * OUTPUT: + * void + */ +int +kdb5_ldap_set_service_password(argc, argv) + int argc; + char **argv; +{ + krb5_ldap_context *lparams = NULL; + char *file_name = NULL; + char *tmp_file = NULL; + char *me = argv[0]; + int filelen = 0; + int random_passwd = 0; + int set_dir_pwd = 1; + krb5_boolean db_init_local = FALSE; + char *service_object = NULL; + char *passwd = NULL; + char *prompt1 = NULL; + char *prompt2 = NULL; + unsigned int passwd_len = 0; + krb5_error_code errcode = -1; + int retval = 0, i = 0; + unsigned int len = 0; + krb5_boolean print_usage = FALSE; + FILE *pfile = NULL; + char *str = NULL; + char line[MAX_LEN]; + kdb5_dal_handle *dal_handle = NULL; + struct data encrypted_passwd = {0, NULL}; + + /* The arguments for setsrv password should contain the service object DN + * and options to specify whether the password should be updated in file only + * or both file and directory. So the possible combination of arguments are: + * setsrvpw servicedn wherein argc is 2 + * setsrvpw -fileonly servicedn wherein argc is 3 + * setsrvpw -randpw servicedn wherein argc is 3 + * setsrvpw -f filename servicedn wherein argc is 4 + * setsrvpw -fileonly -f filename servicedn wherein argc is 5 + * setsrvpw -randpw -f filename servicedn wherein argc is 5 + */ + if ((argc < 2) || (argc > 5)) { + print_usage = TRUE; + goto cleanup; + } + + dal_handle = (kdb5_dal_handle *)util_context->db_context; + lparams = (krb5_ldap_context *) dal_handle->db_context; + + if (lparams == NULL) { + printf("%s: Invalid LDAP handle\n", me); + goto cleanup; + } + + /* Parse the arguments */ + for(i = 1; i < argc -1 ; i++) { + if (strcmp(argv[i], "-randpw") == 0) { + random_passwd = 1; + } + else if (strcmp(argv[i], "-fileonly") == 0) { + set_dir_pwd = 0; + } + else if (strcmp(argv[i], "-f") == 0) { + if (argv[++i] == NULL) { + print_usage = TRUE; + goto cleanup; + } + + file_name = strdup(argv[i]); + if (file_name == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + goto cleanup; + } + /* Verify if the file location has the proper file name + * for eg, if the file location is a directory like /home/temp/, + * we reject it. + */ + filelen = strlen(file_name); + if ((filelen == 0) || (file_name[filelen-1] == '/')) { + printf("%s: Filename not specified for setting service object password\n", me); + print_usage = TRUE; + goto cleanup; + } + } + else { + printf("%s: Invalid option specified for \"setsrvpw\" command\n", me); + print_usage = TRUE; + goto cleanup; + } + } + + if (i != argc-1) { + print_usage = TRUE; + goto cleanup; + } + + service_object = strdup(argv[i]); + if (service_object == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + goto cleanup; + } + + if (strlen(service_object) == 0) { + printf("%s: Service object not specified for \"setsrvpw\" command\n", me); + print_usage = TRUE; + goto cleanup; + } + + if (service_object[0] == '-') { + print_usage = TRUE; + goto cleanup; + } + + if (file_name == NULL) { + file_name = strdup(DEF_SERVICE_PASSWD_FILE); + if (file_name == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + goto cleanup; + } + } + + if (set_dir_pwd) { + if ( db_inited == FALSE ) { + if ((errcode = krb5_ldap_db_init(util_context, lparams))) { + com_err(me, errcode, "while initializing database"); + goto cleanup; + } + db_init_local = TRUE; + } + } + + if (random_passwd) { + if (!set_dir_pwd) { + printf("%s: Invalid option specified for \"setsrvpw\" command\n", me); + print_usage = TRUE; + goto cleanup; + } + else { + /* Generate random password */ + + if ((errcode = generate_random_password(util_context, &passwd, &passwd_len))) { + printf("%s: Failed to set service object password\n", me); + goto cleanup; + } + passwd_len = strlen(passwd); + } + } + else { + /* Get the service object password from the terminal */ + passwd = (char *)malloc(MAX_SERVICE_PASSWD_LEN + 1); + if (passwd == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + goto cleanup; + } + memset(passwd, 0, MAX_SERVICE_PASSWD_LEN + 1); + passwd_len = MAX_SERVICE_PASSWD_LEN; + + len = strlen(service_object); + /* size of allocation=strlen of servicedn + strlen("Password for \" \"")=20 */ + prompt1 = (char *)malloc(len + 20); + if (prompt1 == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + goto cleanup; + } + sprintf(prompt1, "Password for \"%s\"", service_object); + + /* size of allocation=strlen of servicedn + strlen("Re-enter Password for \" \"")=30 */ + prompt2 = (char *)malloc(len + 30); + if (prompt2 == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + free(prompt1); + goto cleanup; + } + sprintf(prompt2, "Re-enter password for \"%s\"", service_object); + + retval = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len); + free(prompt1); + free(prompt2); + if (retval) { + com_err(me, retval, "while setting service object password"); + memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); + goto cleanup; + } + if (passwd_len == 0) { + printf("%s: Invalid password\n", me); + memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); + goto cleanup; + } + passwd_len = strlen(passwd); + } + + /* Hex the password */ + { + krb5_data pwd, hex; + pwd.length = passwd_len; + pwd.data = passwd; + + errcode = tohex(pwd, &hex); + if (errcode != 0) { + if(hex.length != 0) + free(hex.data); + com_err(me, errcode, "Failed to convert the password to hex"); + goto cleanup; + } + /* Password = {CRYPT}<encrypted password>:<encrypted key> */ + encrypted_passwd.value = (unsigned char *)malloc(strlen(service_object) + + 1 + 5 + hex.length + 2); + if (encrypted_passwd.value == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + memset(passwd, 0, passwd_len); + free(hex.data); + goto cleanup; + } + encrypted_passwd.value[strlen(service_object) + + 1 + 5 + hex.length + 1] = '\0'; + sprintf((char *)encrypted_passwd.value, "%s#{HEX}%s\n", service_object, hex.data); + encrypted_passwd.len = strlen((char *)encrypted_passwd.value); + } + + /* We should check if the file exists and we have permission to write into that file */ + if (access(file_name, W_OK) == -1) { + if (errno == ENOENT) { + mode_t omask; + int fd = -1; + + printf("File does not exist. Creating the file %s...\n", file_name ); + omask = umask(077); + fd = creat(file_name, S_IRUSR|S_IWUSR); + umask(omask); + if (fd == -1) { + com_err(me, errno, "Error creating file %s", file_name); + memset(passwd, 0, passwd_len); + goto cleanup; + } + close(fd); + } + else { + com_err(me, errno, "Unable to access the file %s", file_name); + memset(passwd, 0, passwd_len); + goto cleanup; + } + } + + if (set_dir_pwd) { + if ((errcode = krb5_ldap_set_service_passwd(util_context, service_object, passwd)) != 0) { + com_err(me, errcode, "Failed to set password for service object %s", service_object); + memset(passwd, 0, passwd_len); + goto cleanup; + } + } + + memset(passwd, 0, passwd_len); + + + /* TODO: file lock for the service password file */ + /* set password in the file */ + pfile = fopen(file_name, "r+"); + if (pfile == NULL) { + com_err(me, errno, "Failed to open file %s", file_name); + goto cleanup; + } + + while(fgets(line, MAX_LEN, pfile) != NULL) { + if ((str = strstr(line, service_object)) != NULL) { + if(line[strlen(service_object)] == '#') { + break; + } + str = NULL; + } + } + if (str == NULL) { + if(feof(pfile)) { + /* If the service object dn is not present in the service password file */ + if (fwrite(encrypted_passwd.value, (unsigned int)encrypted_passwd.len, 1, pfile) != 1) { + com_err(me, errno, "Failed to write service object password to file"); + goto cleanup; + } + } + else { + com_err(me, errno, "Error reading service object password file"); + goto cleanup; + } + fclose(pfile); + pfile = NULL; + } + else { + /* Password entry for the service object is already present in the file */ + /* Delete the existing entry and add the new entry */ + FILE *newfile = NULL; + mode_t omask; + + /* Create a new file with the extension .tmp */ + tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1)); + if (tmp_file == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + goto cleanup; + } + sprintf(tmp_file,"%s.%s",file_name,"tmp"); + + omask = umask(077); + newfile = fopen(tmp_file, "w+"); + umask(omask); + if (newfile == NULL) { + com_err(me, errno, "Error creating file %s", tmp_file); + goto cleanup; + } + + + fseek(pfile, 0, SEEK_SET); + while(fgets(line, MAX_LEN, pfile) != NULL) { + if (((str = strstr(line, service_object)) != NULL) && (line[strlen(service_object)] == '#')) { + if (fprintf(newfile, "%s", encrypted_passwd.value) < 0) { + com_err(me, errno, "Failed to write service object password to file"); + fclose(newfile); + unlink(tmp_file); + goto cleanup; + } + } + else { + len = strlen(line); + if (fprintf(newfile, "%s", line) < 0) { + com_err(me, errno, "Failed to write service object password to file"); + fclose(newfile); + unlink(tmp_file); + goto cleanup; + } + } + } + + if(!feof(pfile)) { + com_err(me, errno, "Error reading service object password file"); + fclose(newfile); + unlink(tmp_file); + goto cleanup; + } + + /* TODO: file lock for the service password file */ + fclose(pfile); + pfile = NULL; + + fclose(newfile); + newfile = NULL; + + if (unlink(file_name) == 0) { + link(tmp_file, file_name); + } + else { + com_err(me, errno, "Failed to write service object password to file"); + unlink(tmp_file); + goto cleanup; + } + unlink(tmp_file); + } + errcode = 0; + +cleanup: + if (db_init_local) + krb5_ldap_close(util_context); + + if (service_object) + free(service_object); + + if (file_name) + free(file_name); + + if (passwd) + free(passwd); + + if (encrypted_passwd.value) + free(encrypted_passwd.value); + + if (pfile) + fclose(pfile); + + if (tmp_file) + free(tmp_file); + + if (print_usage) + db_usage(SET_SRV_PW); + + return errcode; +} + +#else /* #ifdef HAVE_EDIRECTORY */ + +/* + * Convert the user supplied password into hexadecimal and stash it. Only a + * little more secure than storing plain password in the file ... + */ +int +kdb5_ldap_stash_service_password(argc, argv) + int argc; + char **argv; +{ + int ret = 0; + unsigned int passwd_len = 0; + char *me = argv[0]; + char *service_object = NULL; + char *file_name = NULL, *tmp_file = NULL; + char passwd[MAX_SERVICE_PASSWD_LEN]; + char *str = NULL; + char line[MAX_LEN]; + FILE *pfile = NULL; + krb5_boolean print_usage = FALSE; + krb5_data hexpasswd = {0, 0, NULL}; + + /* + * Format: + * stashsrvpw [-f filename] service_dn + * where + * 'service_dn' is the DN of the service object + * 'filename' is the path of the stash file + */ + if (argc != 2 && argc != 4) { + print_usage = TRUE; + goto cleanup; + } + + if (argc == 4) { + /* Find the stash file name */ + if (strcmp (argv[1], "-f") == 0) { + file_name = strdup (argv[2]); + service_object = strdup (argv[3]); + } else if (strcmp (argv[2], "-f") == 0) { + file_name = strdup (argv[3]); + service_object = strdup (argv[1]); + } else { + print_usage = TRUE; + goto cleanup; + } + if (file_name == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + goto cleanup; + } + } else { /* argc == 2 */ + char *section; + + service_object = strdup (argv[1]); + if (service_object == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + goto cleanup; + } + + /* Pick up the stash-file name from krb5.conf */ + profile_get_string( util_context->profile, KDB_REALM_SECTION, + util_context->default_realm, KDB_MODULE_POINTER, NULL, §ion ); + + if(section == NULL) { + profile_get_string( util_context->profile, KDB_MODULE_DEF_SECTION, + KDB_MODULE_POINTER, NULL, NULL, §ion); + if(section == NULL) { + /* Stash file path neither in krb5.conf nor on command line */ + file_name = strdup(DEF_SERVICE_PASSWD_FILE); + goto done; + } + } + + profile_get_string (util_context->profile, KDB_MODULE_SECTION, section, + "ldap_service_password_file", NULL, &file_name); + } +done: + + /* Get password from user */ + { + char prompt1[256], prompt2[256]; + + /* Get the service object password from the terminal */ + memset(passwd, 0, sizeof (passwd)); + passwd_len = sizeof (passwd); + + /* size of prompt = strlen of servicedn + strlen("Password for \" \"") */ + assert (sizeof (prompt1) > (strlen (service_object) + + sizeof ("Password for \" \""))); + sprintf(prompt1, "Password for \"%s\"", service_object); + + /* size of prompt = strlen of servicedn + strlen("Re-enter Password for \" \"") */ + assert (sizeof (prompt2) > (strlen (service_object) + + sizeof ("Re-enter Password for \" \""))); + sprintf(prompt2, "Re-enter password for \"%s\"", service_object); + + ret = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len); + if (ret != 0) { + com_err(me, ret, "while setting service object password"); + memset(passwd, 0, sizeof (passwd)); + goto cleanup; + } + + if (passwd_len == 0) { + printf("%s: Invalid password\n", me); + memset(passwd, 0, MAX_SERVICE_PASSWD_LEN); + goto cleanup; + } + } + + /* Convert the password to hexadecimal */ + { + krb5_data pwd; + + pwd.length = passwd_len; + pwd.data = passwd; + + ret = tohex(pwd, &hexpasswd); + if(ret != 0){ + if(hexpasswd.length != 0) + free(hexpasswd.data); + com_err(me, ret, "Failed to convert the password to hexadecimal"); + goto cleanup; + } + } + + /* TODO: file lock for the service passowrd file */ + + /* set password in the file */ + pfile = fopen(file_name, "a+"); + if (pfile == NULL) { + com_err(me, errno, "Failed to open file %s: %s", file_name, + strerror (errno)); + goto cleanup; + } + rewind (pfile); + + while (fgets (line, MAX_LEN, pfile) != NULL) { + if ((str = strstr (line, service_object)) != NULL) { + /* White spaces not allowed */ + if (line [strlen (service_object)] == '#') + break; + str = NULL; + } + } + + if (str == NULL) { + if(feof(pfile)) { + /* If the service object dn is not present in the service password file */ + if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) { + com_err(me, errno, "Failed to write service object password to file"); + fclose(pfile); + goto cleanup; + } + } + else { + com_err(me, errno, "Error reading service object password file"); + fclose(pfile); + goto cleanup; + } + fclose(pfile); + } else { + /* + * Password entry for the service object is already present in the file + * Delete the existing entry and add the new entry + */ + FILE *newfile; + + mode_t omask; + + /* Create a new file with the extension .tmp */ + tmp_file = (char *) malloc(sizeof(char) * (strlen(file_name) + 4 + 1)); + if (tmp_file == NULL) { + com_err(me, ENOMEM, "while setting service object password"); + fclose(pfile); + goto cleanup; + } + sprintf(tmp_file,"%s.%s",file_name,"tmp"); + + omask = umask(077); + newfile = fopen(tmp_file, "w"); + umask (omask); + if (newfile == NULL) { + com_err(me, errno, "Error creating file %s", tmp_file); + fclose(pfile); + goto cleanup; + } + + fseek(pfile, 0, SEEK_SET); + while(fgets(line, MAX_LEN, pfile) != NULL) { + if (((str = strstr(line, service_object)) != NULL) && + (line[strlen(service_object)] == '#')) { + if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) { + com_err(me, errno, "Failed to write service object password to file"); + fclose(newfile); + unlink(tmp_file); + fclose(pfile); + goto cleanup; + } + } else { + if (fprintf (newfile, "%s", line) < 0) { + com_err(me, errno, "Failed to write service object password to file"); + fclose(newfile); + unlink(tmp_file); + fclose(pfile); + goto cleanup; + } + } + } + + if(!feof(pfile)) { + com_err(me, errno, "Error reading service object password file"); + fclose(newfile); + unlink(tmp_file); + fclose(pfile); + goto cleanup; + } + + /* TODO: file lock for the service passowrd file */ + + fclose(pfile); + fclose(newfile); + + ret = rename(tmp_file, file_name); + if (ret != 0) { + com_err(me, errno, "Failed to write service object password to " + "file"); + goto cleanup; + } + } + ret = 0; + +cleanup: + + if (service_object) + free(service_object); + + if (file_name) + free(file_name); + + if (tmp_file) + free(tmp_file); + + if (print_usage) + usage(); +/* db_usage(STASH_SRV_PW); */ + + return ret; +} + +#endif /* #ifdef HAVE_EDIRECTORY */ diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.h b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.h new file mode 100644 index 000000000..e10a055bc --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.h @@ -0,0 +1,71 @@ +/* + * kadmin/ldap_util/kdb5_services.h + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_misc.h" + +#define MAX_DN_CHARS 256 +#define HOST_INFO_DELIMITER '#' +#define PROTOCOL_STR_LEN 3 +#define PROTOCOL_NUM_UDP 0 +#define PROTOCOL_NUM_TCP 1 +#define PROTOCOL_DEFAULT_KDC PROTOCOL_NUM_UDP +#define PROTOCOL_DEFAULT_ADM PROTOCOL_NUM_TCP +#define PROTOCOL_DEFAULT_PWD PROTOCOL_NUM_UDP +#define PORT_STR_LEN 5 +#define PORT_DEFAULT_KDC 88 +#define PORT_DEFAULT_ADM 749 +#define PORT_DEFAULT_PWD 464 + +#define MAX_LEN 1024 +#define MAX_SERVICE_PASSWD_LEN 256 +#define RANDOM_PASSWD_LEN 128 + +#define DEF_SERVICE_PASSWD_FILE "/usr/local/var/service_passwd" + +struct data{ + int len; + unsigned char *value; +}; + +extern int enc_password(struct data pwd, struct data *enc_key, struct data *enc_pass); +extern int tohex(krb5_data, krb5_data *); + +extern void kdb5_ldap_create_service (int argc, char **argv); +extern void kdb5_ldap_modify_service (int argc, char **argv); +extern void kdb5_ldap_destroy_service(int argc, char **argv); +extern void kdb5_ldap_list_services(int argc, char **argv); +extern void kdb5_ldap_view_service(int argc, char **argv); +extern int kdb5_ldap_set_service_password(int argc, char **argv); +extern void kdb5_ldap_set_service_certificate(int argc, char **argv); +extern void print_service_params(krb5_ldap_service_params *lserparams, int mask); +extern krb5_error_code convert_realm_name2dn_list(char **list, const char *krbcontainer_loc); +extern int kdb5_ldap_stash_service_password(int argc, char **argv); + diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.M b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.M new file mode 100644 index 000000000..20dc3e726 --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.M @@ -0,0 +1,977 @@ +.TH KDB5_LDAP_UTIL 8 +.SH NAME +kdb5_ldap_util \- Kerberos Configuration Utility +.SH SYNOPSIS +.B kdb5_ldap_util +[\fB\-D\fP\ \fIuser_dn\fP [\fB\-w\fP\ \fIpasswd\fP]] +[\fB\-h\fP\ \fIldap_server\fP] [\fB\-p\fP\ \fIldap_port\fP] +.I command +.I [command_options] +.SH DESCRIPTION +.B kdb5_ldap_util +allows an administrator to manage realms, Kerberos services and ticket policies. +.SH COMMAND-LINE OPTIONS +.TP +\fB\-D\fP\ \fIuser_dn\fP +Specifies the Distinguished name (DN) of the user who has sufficient rights to +perform the operation on the LDAP server. +.TP +\fB\-w\fP\ \fIpasswd\fP +Specifies the password of +.IR user_dn . +This option is not recommended. +.TP +\fB\-h\fP\ \fIldap_server\fP +Specifies the hostname or IP address of the server hosting the LDAP service for +a Kerberos realm. +.TP +\fB\-p\fP\ \fIldap_port\fP +Specifies the SSL port number of the LDAP server. +.SH COMMANDS +.TP +\fBcreate\fP [\fB\-subtree\fP\ \fIsubtree_dn\fP] [\fB\-sscope\fP\ \fIsearch_scope\fP] [\fB\-enctypes\fP\ \fIsupported_enc_types\fP] [\fB\-defenctype\fP\ \fIdefault_enc_type\fP] [\fB\-salttypes\fP\ \fIsupported_salt_types\fP] [\fB\-defsalttype\fP\ \fIdefault_salt_type\fP] [\fB\-k\fP\ \fImkeytype\fP] [\fB\-m\fP|\fB\-P\fP\ \fIpassword\fP|\fB\-sf\fP\ \fIstashfilename\fP] [\fB\-r\fP\ \fIrealm\fP] [\fB\-kdcdn\fP\ \fIkdc_service_list\fP] [\fB\-admindn\fP\ \fIadmin_service_list\fP] [\fB\-pwddn\fP\ \fIpasswd_service_list\fP] [\fB\-maxtktlife\fP\ \fImax_ticket_life\fP] [\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP] [\fIticket_flags\fP] +Creates realm in directory. Options: +.RS +.TP +\fB\-subtree\fP\ \fIsubtree_dn\fP +Specifies the subtree where principals and other Kerberos objects in the realm are placed. +.TP +\fB\-sscope\fP\ \fIsearch_scope\fP +Specifies the scope for searching the principals under the +.IR subtree . +The possible values are 1 or one (one level), 2 or sub (subtree). +.TP +\fB\-enctypes\fP\ \fIsupported_enc_types\fP +Specifies the encryption types supported by the realm. This is a colon-separated list. +.TP +\fB\-defenctype\fP\ \fIdefault_enc_type\fP +Specifies the default encryption type for the realm. This is also a part of supported enctypes list. +.TP +\fB\-salttypes\fP\ \fIsupported_salt_types\fP +Specifies the salt types supported by the realm. This is a colon-separated list. +.TP +\fB\-defsalttype\fP\ \fIdefault_salt_type\fP +Specifies the default salt types for the realm. +.TP +\fB\-k\fP\ \fImkeytype\fP +Specifies the key type of the master key in the database; the default is +that given in +.IR kdc.conf . +.TP +\fB\-m\fP +Specifies that the master database password should be read from the TTY +rather than fetched from a file on the disk. +.TP +\fB\-P\fP\ \fIpassword\fP +Specifies the master database password. This option is not recommended. +.TP +\fB\-sf\fP\ \fIstashfilename\fP +Specifies the stash file of the master database password. +.TP +\fB\-maxtktlife\fP\ \fImax_ticket_life\fP +Specifies maximum ticket life for principals in this realm. +.TP +\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP +Specifies maximum renewable life of tickets for principals in this realm. +.TP +\fIticket_flags\fP +Specifies the ticket flags. If this option is not specified, by default, none of the flags are +set. This means all the ticket options will be allowed and no restriction will be set. + +The various flags are: +.TP +{\fB\-\fP|\fB+\fP}\fBallow_postdated\fP +.B -allow_postdated +prohibits principals from obtaining postdated tickets. (Sets the +.SM KRB5_KDB_DISALLOW_POSTDATED +flag.) +.B +allow_postdated +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_forwardable\fP +.B -allow_forwardable +prohibits principals from obtaining forwardable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_FORWARDABLE +flag.) +.B +allow_forwardable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_renewable\fP +.B -allow_renewable +prohibits principals from obtaining renewable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_RENEWABLE +flag.) +.B +allow_renewable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_proxiable\fP +.B -allow_proxiable +prohibits principals from obtaining proxiable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_PROXIABLE +flag.) +.B +allow_proxiable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_dup_skey\fP +.B -allow_dup_skey +Disables user-to-user authentication for principals by prohibiting +principals from obtaining a session key for another user. (Sets the +.SM KRB5_KDB_DISALLOW_DUP_SKEY +flag.) +.B +allow_dup_skey +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBrequires_preauth\fP +.B +requires_preauth +requires principals to preauthenticate before being allowed to +kinit. (Sets the +.SM KRB5_KDB_REQUIRES_PRE_AUTH +flag.) +.B -requires_preauth +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBrequires_hwauth\fP +.B +requires_hwauth +requires principals to preauthenticate using a hardware device +before being allowed to kinit. (Sets the +.SM KRB5_KDB_REQUIRES_HW_AUTH +flag.) +.B -requires_hwauth +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_svr\fP +.B -allow_svr +prohibits the issuance of service tickets for principals. (Sets the +.SM KRB5_KDB_DISALLOW_SVR +flag.) +.B +allow_svr +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_tgs_req\fP +.B \-allow_tgs_req +specifies that a Ticket-Granting Service (TGS) request for a service +ticket for principals is not permitted. This option is useless for +most things. +.B +allow_tgs_req +clears this flag. The default is +.BR +allow_tgs_req . +In effect, +.B \-allow_tgs_req +sets the +.SM KRB5_KDB_DISALLOW_TGT_BASED +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_tix\fP +.B \-allow_tix +forbids the issuance of any tickets for principals. +.B +allow_tix +clears this flag. The default is +.BR +allow_tix . +In effect, +.B \-allow_tix +sets the +.SM KRB5_KDB_DISALLOW_ALL_TIX +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBneedchange\fP +.B +needchange +sets a flag in attributes field to force a password change; +.B \-needchange +clears it. The default is +.BR \-needchange . +In effect, +.B +needchange +sets the +.SM KRB5_KDB_REQUIRES_PWCHANGE +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBpassword_changing_service\fP +.B +password_changing_service +sets a flag in the attributes field marking principal as a password change +service principal (useless for most things). +.B \-password_changing_service +clears the flag. This flag intentionally has a long name. The default +is +.BR \-password_changing_service . +In effect, +.B +password_changing_service +sets the +.SM KRB5_KDB_PWCHANGE_SERVICE +flag on principals in the database. +.TP +\fB\-r\fP\ \fIrealm\fP +Specifies the Kerberos realm of the database; by default the realm +returned by +.IR krb5_default_local_realm (3) +is used. +.TP +.B Command Options Specific to eDirectory +.TP +\fB\-kdcdn\fP\ \fIkdc_service_list\fP +Specifies the list of KDC service objects serving the realm. The list contains the DNs of the KDC +service objects separated by colon(:). +.TP +\fB\-admindn\fP\ \fIadmin_service_list\fP +Specifies the list of Administration service objects serving the realm. The list contains the DNs +of the Administration service objects separated by colon(:). +.TP +\fB\-pwddn\fP\ \fIpasswd_service_list\fP +Specifies the list of Password service objects serving the realm. The list contains the DNs of the +Password service objects separated by colon(:). +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org -h ldap-server1.mit.edu +create -sscope SUB -enctypes des-cbc-crc:des3-cbc-sha1 +-defenctype des3-cbc-sha1 -salttypes normal:afs3 -defsalttype normal +-r ATHENA.MIT.EDU\fP +.nf +Password for "cn=admin,o=org": +Initializing database for realm 'ATHENA.MIT.EDU' +You will be prompted for the database Master Password. +It is important that you NOT FORGET this password. +Enter KDC database master key: +Re-enter KDC database master key to verify: +.fi +.RE + +.TP +\fBmodify\fP [\fB\-subtree\fP\ \fIsubtree_dn\fP] [\fB\-sscope\fP\ \fIsearch_scope\fP] [\fB\-enctypes\fP\ \fIsupported_enc_types\fP | [\fB\-clearenctypes\fP\ \fIenc_type_list\fP] [\fB\-addenctypes\fP\ \fIenc_type_list\fP]] [\fB\-defenctype\fP\ \fIdefault_enc_type\fP] [\fB\-salttypes\fP\ \fIsupported_salt_types\fP | [\fB\-clearsalttypes\fP\ \fIsalt_type_list\fP] [\fB\-addsalttypes\fP\ \fIsalt_type_list\fP]] [\fB\-defsalttype\fP\ \fIdefault_salt_type\fP] [\fB\-r\fP\ \fIrealm\fP] [\fB\-kdcdn\fP\ \fIkdc_service_list\fP | [\fB\-clearkdcdn\fP\ \fIkdc_service_list\fP] [\fB\-addkdcdn\fP\ \fIkdc_service_list\fP]] [\fB\-admindn\fP\ \fIadmin_service_list\fP | [\fB\-clearadmindn\fP\ \fIadmin_service_list\fP] [\fB\-addadmindn\fP\ \fIadmin_service_list\fP]] [\fB\-pwddn\fP\ \fIpasswd_service_list\fP | [\fB\-clearpwddn\fP\ \fIpasswd_service_list\fP] [\fB\-addpwddn\fP\ \fIpasswd_service_list\fP]] [\fB\-maxtktlife\fP\ \fImax_ticket_life\fP] [\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP] [\fIticket_flags\fP] + +Modifies the attributes of a realm. Options: +.RS +.TP +\fB\-subtree\fP\ \fIsubtree_dn\fP +Specifies the subtree containing principals and other Kerberos objects in the realm. +.TP +\fB\-sscope\fP\ \fIsearch_scope\fP +Specifies the scope for searching the principals under the +.IR subtree . +The possible values are 1 or one (one level), 2 or sub (subtree). +.TP +\fB\-enctypes\fP\ \fIsupported_enc_types\fP +Specifies the encryption types supported by the realm. This is a colon-separated list. +.TP +\fB\-clearenctypes\fP\ \fIenc_type_list\fP +Specifies the encryption types that need to be removed from the supported encryption types +of the realm. This is a colon-separated list. +.TP +\fB\-addenctypes\fP\ \fIenc_type_list\fP +Specifies the encryption types that need to be added to the supported encryption types of the +realm. This is a colon-separated list. +.TP +\fB\-defenctype\fP\ \fIdefault_enc_type\fP +Specifies the default encryption type for the realm. +.TP +\fB\-salttypes\fP\ \fIsupported_salt_types\fP +Specifies the salt types supported by the realm. This is a colon-separated list. +.TP +\fB\-clearsalttypes\fP\ \fIsalt_type_list\fP +Specifies the salt types that need to be removed from the supported salt types of the realm. +This is a colon-separated list. +.TP +\fB\-addsalttypes\fP\ \fIsalt_type_list\fP +Specifies the salt types that need to be added to the supported salt types of the realm. This +is a colon-separated list. +.TP +\fB\-defsalttype\fP\ \fIdefault_salt_type\fP +Specifies the default salt type for the realm. +.TP +\fB\-maxtktlife\fP\ \fImax_ticket_life\fP +Specifies maximum ticket life for principals in this realm. +.TP +\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP +Specifies maximum renewable life of tickets for principals in this realm. +.TP +\fIticket_flags\fP +Specifies the ticket flags. If this option is not specified, by default, none of the flags are +set. This means all the ticket options will be allowed and no restriction will be set. + +The various flags are: +.TP +{\fB\-\fP|\fB+\fP}\fBallow_postdated\fP +.B -allow_postdated +prohibits principals from obtaining postdated tickets. (Sets the +.SM KRB5_KDB_DISALLOW_POSTDATED +flag.) +.B +allow_postdated +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_forwardable\fP +.B -allow_forwardable +prohibits principals from obtaining forwardable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_FORWARDABLE +flag.) +.B +allow_forwardable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_renewable\fP +.B -allow_renewable +prohibits principals from obtaining renewable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_RENEWABLE +flag.) +.B +allow_renewable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_proxiable\fP +.B -allow_proxiable +prohibits principals from obtaining proxiable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_PROXIABLE +flag.) +.B +allow_proxiable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_dup_skey\fP +.B -allow_dup_skey +Disables user-to-user authentication for principals by prohibiting +principals from obtaining a session key for another user. (Sets the +.SM KRB5_KDB_DISALLOW_DUP_SKEY +flag.) +.B +allow_dup_skey +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBrequires_preauth\fP +.B +requires_preauth +requires principals to preauthenticate before being allowed to +kinit. (Sets the +.SM KRB5_KDB_REQUIRES_PRE_AUTH +flag.) +.B -requires_preauth +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBrequires_hwauth\fP +.B +requires_hwauth +requires principals to preauthenticate using a hardware device +before being allowed to kinit. (Sets the +.SM KRB5_KDB_REQUIRES_HW_AUTH +flag.) +.B -requires_hwauth +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_svr\fP +.B -allow_svr +prohibits the issuance of service tickets for principals. (Sets the +.SM KRB5_KDB_DISALLOW_SVR +flag.) +.B +allow_svr +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_tgs_req\fP +.B \-allow_tgs_req +specifies that a Ticket-Granting Service (TGS) request for a service +ticket for principals is not permitted. This option is useless for +most things. +.B +allow_tgs_req +clears this flag. The default is +.BR +allow_tgs_req . +In effect, +.B \-allow_tgs_req +sets the +.SM KRB5_KDB_DISALLOW_TGT_BASED +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_tix\fP +.B \-allow_tix +forbids the issuance of any tickets for principals. +.B +allow_tix +clears this flag. The default is +.BR +allow_tix . +In effect, +.B \-allow_tix +sets the +.SM KRB5_KDB_DISALLOW_ALL_TIX +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBneedchange\fP +.B +needchange +sets a flag in attributes field to force a password change; +.B \-needchange +clears it. The default is +.BR \-needchange . +In effect, +.B +needchange +sets the +.SM KRB5_KDB_REQUIRES_PWCHANGE +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBpassword_changing_service\fP +.B +password_changing_service +sets a flag in the attributes field marking principal as a password change +service principal (useless for most things). +.B \-password_changing_service +clears the flag. This flag intentionally has a long name. The default +is +.BR \-password_changing_service . +In effect, +.B +password_changing_service +sets the +.SM KRB5_KDB_PWCHANGE_SERVICE +flag on principals in the database. +.TP +\fB\-r\fP\ \fIrealm\fP +Specifies the Kerberos realm of the database; by default the realm +returned by +.IR krb5_default_local_realm (3) +is used. +.TP +.B Command Options Specific to eDirectory +.TP +\fB\-kdcdn\fP\ \fIkdc_service_list\fP +Specifies the list of KDC service objects serving the realm. The list contains the DNs of the KDC +service objects separated by a colon (:). +.TP +\fB\-clearkdcdn\fP\ \fIkdc_service_list\fP +Specifies the list of KDC service objects that need to be removed from the existing list. The list contains +the DNs of the KDC service objects separated by a colon (:). +.TP +\fB\-addkdcdn\fP\ \fIkdc_service_list\fP +Specifies the list of KDC service objects that need to be added to the existing list. The list contains the +DNs of the KDC service objects separated by a colon (:). +.TP +\fB\-admindn\fP\ \fIadmin_service_list\fP +Specifies the list of Administration service objects serving the realm. The list contains the DNs +of the Administration service objects separated by a colon (:). +.TP +\fB\-clearadmindn\fP\ \fIadmin_service_list\fP +Specifies the list of Administration service objects that need to be removed from the existing list. The list +contains the DNs of the Administration service objects separated by a colon (:). +.TP +\fB\-addadmindn\fP\ \fIadmin_service_list\fP +Specifies the list of Administration service objects that need to be added to the existing list. The list +contains the DNs of the Administration service objects separated by a colon (:). +.TP +\fB\-pwddn\fP\ \fIpasswd_service_list\fP +Specifies the list of Password service objects serving the realm. The list contains the DNs of the +Password service objects separated by a colon (:). +.TP +\fB\-clearpwddn\fP\ \fIpasswd_service_list\fP +Specifies the list of Password service objects that need to be removed from the existing list. The list +contains the DNs of the Password service objects separated by a colon (:). +.TP +\fB\-addpwddn\fP\ \fIpasswd_service_list\fP +Specifies the list of Password service objects that need to be added to the existing list. The list contains +the DNs of the Password service objects separated by a colon (:). +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org modify -sscope ONE -enctypes +des3-hmac-sha1:des-cbc-md5 -defenctype des3-hmac-sha1 -addsalttypes v4:special +-r ATHENA.MIT.EDU \fP +.nf +Password for "cn=admin,o=org": +.fi +.RE +.TP +\fBview\fP [\fB\-r\fP\ \fIrealm\fP] +Displays the attributes of a realm. Options: +.RS +.TP +\fB\-r\fP\ \fIrealm\fP +Specifies the Kerberos realm of the database; by default the realm returned by +.IR krb5_default_local_realm (3) +is used. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org view -r ATHENA.MIT.EDU\fP +.nf +Password for "cn=admin,o=org": + Realm Name: ATHENA.MIT.EDU + Subtree: ou=users,o=org + SearchScope: ONE + Supported Enc Types: DES cbc mode with RSA-MD5 + Triple DES cbc mode with HMAC/sha1 + Default Enc Type: Triple DES cbc mode with HMAC/sha1 + Supported Salt Types: Version 5 + Version 4 + Special + AFS version 3 + Default Salt Type: Version 5 + Maximum ticket life: 0 days 01:00:00 + Maximum renewable life: 0 days 10:00:00 + Ticket flags: DISALLOW_FORWARDABLE REQUIRES_PWCHANGE +.fi +.RE +.TP +\fBdestroy\fP [\fB-f\fP] [\fB\-r\fP\ \fIrealm\fP] +Destroys an existing realm. Options: +.RS +.TP +\fB\-f\fP +If specified, will not prompt the user for confirmation. +.TP +\fB\-r\fP\ \fIrealm\fP +Specifies the Kerberos realm of the database; by default the realm returned by +.IR krb5_default_local_realm (3) +is used. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org -h ldap-server1.mit.edu destroy -r ATHENA.MIT.EDU\fP +.nf +Password for "cn=admin,o=org": +Deleting KDC database of 'ATHENA.MIT.EDU', are you sure? +(type 'yes' to confirm)? yes +OK, deleting database of 'ATHENA.MIT.EDU'... +.fi +.RE +.TP +\fBlist\fP + +Lists the name of realms. +.RS +.nf +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org list\fP +Password for "cn=admin,o=org": +ATHENA.MIT.EDU +MYREALM +MEDIA-LAB.MIT.EDU +.fi +.RE +.TP +\fBstashsrvpw\fP [\fB\-f\fP\ \fIfilename\fP] \fIservicedn\fP +Allows an administrator to store the password for service object in a file so that KDC, Administration, and +Password server can use it to authenticate to the LDAP server. Options: +.RS +.TP +\fB\-f\fP\ \fIfilename\fP +Specifies the complete path of the service password file. By default, /usr/local/var/service_passwd is used. +.TP +\fIservicedn\fP +Specifies Distinguished name (DN) of the service object whose password is to be stored in file. +.TP +EXAMPLE: +\fBkdb5_ldap_util stashsrvpw -f /home/andrew/conf_keyfile cn=service-kdc,o=org\fP +.nf +Password for "cn=service-kdc,o=org": +Re-enter password for "cn=service-kdc,o=org": +.fi +.RE +.TP +\fBcreate_policy\fP [\fB\-maxtktlife\fP\ \fImax_ticket_life\fP] [\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP] [\fIticket_flags\fP] \fIpolicy_dn\fP +Creates a ticket policy in directory. Options: +.RS +.TP +\fB\-maxtktlife\fP\ \fImax_ticket_life\fP +Specifies maximum ticket life for principals. +.TP +\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP +Specifies maximum renewable life of tickets for principals. +.TP +\fIticket_flags\fP +Specifies the ticket flags. If this option is not specified, by default, none of the flags are +set. This means all the ticket options will be allowed and no restriction will be set. + +The various flags are: +.TP +{\fB\-\fP|\fB+\fP}\fBallow_postdated\fP +.B -allow_postdated +prohibits principals from obtaining postdated tickets. (Sets the +.SM KRB5_KDB_DISALLOW_POSTDATED +flag.) +.B +allow_postdated +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_forwardable\fP +.B -allow_forwardable +prohibits principals from obtaining forwardable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_FORWARDABLE +flag.) +.B +allow_forwardable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_renewable\fP +.B -allow_renewable +prohibits principals from obtaining renewable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_RENEWABLE +flag.) +.B +allow_renewable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_proxiable\fP +.B -allow_proxiable +prohibits principals from obtaining proxiable tickets. (Sets the +.SM KRB5_KDB_DISALLOW_PROXIABLE +flag.) +.B +allow_proxiable +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_dup_skey\fP +.B -allow_dup_skey +Disables user-to-user authentication for principals by prohibiting +principals from obtaining a session key for another user. (Sets the +.SM KRB5_KDB_DISALLOW_DUP_SKEY +flag.) +.B +allow_dup_skey +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBrequires_preauth\fP +.B +requires_preauth +requires principals to preauthenticate before being allowed to +kinit. (Sets the +.SM KRB5_KDB_REQUIRES_PRE_AUTH +flag.) +.B -requires_preauth +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBrequires_hwauth\fP +.B +requires_hwauth +requires principals to preauthenticate using a hardware device +before being allowed to kinit. (Sets the +.SM KRB5_KDB_REQUIRES_HW_AUTH +flag.) +.B -requires_hwauth +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_svr\fP +.B -allow_svr +prohibits the issuance of service tickets for principals. (Sets the +.SM KRB5_KDB_DISALLOW_SVR +flag.) +.B +allow_svr +clears this flag. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_tgs_req\fP +.B \-allow_tgs_req +specifies that a Ticket-Granting Service (TGS) request for a service +ticket for principals is not permitted. This option is useless for +most things. +.B +allow_tgs_req +clears this flag. The default is +.BR +allow_tgs_req . +In effect, +.B \-allow_tgs_req +sets the +.SM KRB5_KDB_DISALLOW_TGT_BASED +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBallow_tix\fP +.B \-allow_tix +forbids the issuance of any tickets for principals. +.B +allow_tix +clears this flag. The default is +.BR +allow_tix . +In effect, +.B \-allow_tix +sets the +.SM KRB5_KDB_DISALLOW_ALL_TIX +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBneedchange\fP +.B +needchange +sets a flag in attributes field to force a password change; +.B \-needchange +clears it. The default is +.BR \-needchange . +In effect, +.B +needchange +sets the +.SM KRB5_KDB_REQUIRES_PWCHANGE +flag on principals in the database. +.TP +{\fB\-\fP|\fB+\fP}\fBpassword_changing_service\fP +.B +password_changing_service +sets a flag in the attributes field marking principal as a password change +service principal (useless for most things). +.B \-password_changing_service +clears the flag. This flag intentionally has a long name. The default +is +.BR \-password_changing_service . +In effect, +.B +password_changing_service +sets the +.SM KRB5_KDB_PWCHANGE_SERVICE +flag on principals in the database. +.TP +\fIpolicy_dn\fP +Specifies Distinguished name (DN) of the policy. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org -h ldap-server1.mit.edu -p 636 create_policy -maxtktlife "1 day" -maxrenewlife "1 week" -allow_postdated +needchange -allow_forwardable cn=tktpolicy,o=org\fP +.nf +Password for "cn=admin,o=org": +.fi +.RE +.TP +\fBmodify_policy\fP [\fB\-maxtktlife\fP\ \fImax_ticket_life\fP] [\fB\-maxrenewlife\fP\ \fImax_renewable_ticket_life\fP] [\fIticket_flags\fP] \fIpolicy_dn\fP +Modifies the attributes of a ticket policy. Options are same as +.B create_policy. +.RS +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org -h ldap-server1.mit.edu -p 636 modify_policy -maxtktlife "60 minutes" -maxrenewlife "10 hours" +allow_postdated -requires_preauth cn=tktpolicy,o=org\fP +.nf +Password for "cn=admin,o=org": +.fi +.RE +.TP +\fBview_policy\fP \fIpolicy_dn\fP +Displays the attributes of a ticket policy. Options: +.RS +.TP +\fIpolicy_dn\fP +Specifies Distinguished name (DN) of the policy. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org -h ldap-server1.mit.edu -p 636 view_policy cn=tktpolicy,o=org\fP +.nf +Password for "cn=admin,o=org": + Ticket policy: cn=tktpolicy,o=org + Maximum ticket life: 0 days 01:00:00 + Maximum renewable life: 0 days 10:00:00 + Ticket flags: DISALLOW_FORWARDABLE REQUIRES_PWCHANGE +.fi +.RE +.TP +\fBdestroy_policy\fP [\fB\-force\fP] \fIpolicy_dn\fP +Destroys an existing ticket policy. Options: +.RS +.TP +\fB\-force\fP +Forces the deletion of the policy object. If not specified, will be prompted for confirmation while deleting the policy. Enter +.B yes +to confirm the deletion. +.TP +\fIpolicy_dn\fP +Specifies Distinguished name (DN) of the policy. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org -h ldap-server1.mit.edu -p 636 destroy_policy cn=tktpolicy,o=org\fP +.nf +Password for "cn=admin,o=org": +This will delete the policy object 'cn=tktpolicy,o=org', are you sure? +(type 'yes' to confirm)? yes +** policy object 'cn=tktpolicy,o=org' deleted. +.fi +.RE +.TP +\fBlist_policy\fP [\fB\-basedn\fP\ \fIbase_dn\fP] +Lists the name of ticket policies under a given base in directory. Options: +.RS +.TP +\fI\-basedn\fP\ \fIbase_dn\fP +Specifies the base DN for searching the policies, limiting the search to a particular subtree. If this option +is not provided, LDAP Server specific search base will be used. +For eg, in the case of OpenLDAP, value of +.B defaultsearchbase +from +.I slapd.conf +file will be used, where as in the case of eDirectory, the default value +for the base DN is +.B Root. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org -h ldap-server1.mit.edu -p 636 list_policy +-basedn o=org\fP +.nf +Password for "cn=admin,o=org": +cn=tktpolicy,o=org +cn=tktpolicy2,o=org +cn=tktpolicy3,o=org +.fi +.RE + +.TP +.B Commands Specific to eDirectory +.TP +\fBsetsrvpw\fP [\fB\-randpw\fP|\fB\-fileonly\fP] [\fB\-f\fP\ \fIfilename\fP] \fIservice_dn\fP +Allows an administrator to set password for service objects such as KDC, Administration, and Password server in +eDirectory and store them in a file. The +.I -fileonly +option stores the password in a file and not in the eDirectory object. Options: +.RS +.TP +\fB\-randpw \fP +Generates and sets a random password. This options can be specified to store the password both in eDirectory and a file. The +.I -fileonly +option can not be used if +.I -randpw +option is already specified. +.TP +\fB\-fileonly\fP +Stores the password only in a file and not in eDirectory. The +.I -randpw +option can not be used when +.I -fileonly +options is specified. +.TP +\fB\-f\fP\ \fIfilename\fP +Specifies complete path of the service password file. By default, /usr/local/var/service_passwd is used. +.TP +\fIservice_dn\fP +Specifies Distinguished name (DN) of the service object whose password is to be set. +.TP +EXAMPLE: +\fBkdb5_ldap_util setsrvpw -D cn=admin,o=org setsrvpw -fileonly -f /home/andrew/conf_keyfile +cn=service-kdc,o=org\fP +.nf +Password for "cn=admin,o=org": +Password for "cn=service-kdc,o=org": +Re-enter password for "cn=service-kdc,o=org": +.fi +.RE +.TP +\fBcreate_service\fP {\fB\-kdc|\-admin|\-pwd\fP} [\fB\-servicehost\fP\ \fIservice_host_list\fP] [\fB\-realm\fP\ \fIrealm_list\fP] [\fB\-randpw|\-fileonly\fP] [\fB\-f\fP\ \fIfilename\fP] \fIservice_dn\fP +Creates a service in directory and assigns appropriate rights. Options: +.RS +.TP +\fB\-kdc\fP +Specifies the service is a KDC service +.TP +\fB\-admin\fP +Specifies the service is a Administration service +.TP +\fB\-pwd\fP +Specifies the service is a Password service +.TP +\fB\-servicehost\fP\ \fIservice_host_list\fP +Specifies the list of entries separated by a colon (:). Each entry consists of the hostname or IP +address of the server hosting the service, transport protocol, and the port number of +the service separated by a pound sign (#). +For example, +server1#tcp#88:server2#udp#89. +.TP +\fB\-realm\fP\ \fIrealm_list\fP +Specifies the list of realms that can be serviced by Kerberos. The list contains the name of the realms +separated by a colon (:). +.TP +\fB\-randpw \fP +Generates and sets a random password. This options can be specified to store the password both in eDirectory and a file. The +.I -fileonly +option can not be used if +.I -randpw +option is already specified. +.TP +\fB\-fileonly\fP +Stores the password only in a file and not in eDirectory. The +.I -randpw +option can not be used when +.I -fileonly +options is specified. +.TP +\fB\-f\fP\ \fIfilename\fP +Specifies the complete path of the file where the service object password is stashed. +.TP +\fIservice_dn\fP +Specifies Distinguished name (DN) of the Kerberos service to be created. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org create_service -kdc -randpw -f /home/andrew/conf_keyfile cn=service-kdc,o=org\fP +.nf +Password for "cn=admin,o=org": +File does not exist. Creating the file /home/andrew/conf_keyfile... +.fi +.RE +.TP +\fBmodify_service\fP [\fB\-servicehost\fP\ \fIservice_host_list\fP | [\fB\-clearservicehost\fP\ \fIservice_host_list\fP] [\fB\-addservicehost\fP\ \fIservice_host_list\fP]] [\fB\-realm\fP\ \fIrealm_list\fP | [\fB\-clearrealm\fP\ \fIrealm_list\fP] [\fB\-addrealm\fP\ \fIrealm_list\fP]] \fIservice_dn\fP +Modifies the attributes of a service and assigns appropriate rights. Options: +.RS +.TP +\fB\-servicehost\fP\ \fIservice_host_list\fP +Specifies the list of entries separated by a colon (:). Each entry consists of a host name +or IP Address of the Server hosting the service, transport protocol, and port +number of the service separated by a pound sign (#). +For example, +server1#tcp#88:server2#udp#89 +.TP +\fB\-clearservicehost\fP\ \fIservice_host_list\fP +Specifies the list of servicehost entries to be removed from the existing list separated by colon (:). Each entry consists of a host name or IP Address of the server +hosting the service, transport protocol, and port number of the service separated +by a pound sign (#). +.TP +\fB\-addservicehost\fP\ \fIservice_host_list\fP +Specifies the list of servicehost entries to be added to the existing list separated by colon (:). Each entry consists of a host name or IP Address of the +server hosting the service, transport protocol, and port number of the service +separated by a pound sign (#). +.TP +\fB\-realm\fP\ \fIrealm_list\fP +Specifies the list of realms that are associated with this service. The list contains the name of +the realms separated by a colon (:). +.TP +\fB\-clearrealm\fP\ \fIrealm_list\fP +Specifies the list of realms to be removed from the existing list. The list contains the name of +the realms separated by a colon (:). +.TP +\fB\-addrealm\fP\ \fIrealm_list\fP +Specifies the list of realms to be added to the existing list. The list contains the name of the +realms separated by a colon (:). +.TP +\fIservice_dn\fP +Specifies Distinguished name (DN) of the Kerberos service to be modified. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org modify_service -realm ATHENA.MIT.EDU +cn=service-kdc,o=org\fP +.nf +Password for "cn=admin,o=org": +Changing rights for the service object. Please wait ... done +.fi +.RE +.TP +\fBview_service\fP \fIservice_dn\fP +Displays the attributes of a service. Options: +.RS +.TP +\fIservice_dn\fP +Specifies Distinguished name (DN) of the Kerberos service to be viewed. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org view_service cn=service-kdc,o=org\fP +.nf +Password for "cn=admin,o=org": + Service dn: cn=service-kdc,o=org + Service type: kdc + Service host list: + Realm DN list: cn=ATHENA.MIT.EDU,cn=Kerberos,cn=Security +.fi +.RE +.TP +\fBdestroy_service\fP [\fB\-force\fP] [\fB\-f\fP\ \fIstashfilename\fP] \fIservice_dn\fP +Destroys an existing service. Options: +.RS +.TP +\fB\-force\fP +If specified, will not prompt for user's confirmation, instead will force destruction of the service. +.TP +\fB\-f\fP\ \fIstashfilename\fP +Specifies the complete path of the service password file from where the entry corresponding to the +.I service_dn +needs to be removed. +.TP +\fIservice_dn\fP +Specifies Distinguished name (DN) of the Kerberos service to be destroyed. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org destroy_service cn=service-kdc,o=org\fP +.nf +Password for "cn=admin,o=org": +This will delete the service object 'cn=service-kdc,o=org', are you sure? +(type 'yes' to confirm)? yes +** service object 'cn=service-kdc,o=org' deleted. +.fi +.RE +.TP +\fBlist_service\fP [\fB\-basedn\fP\ \fIbase_dn\fP] +Lists the name of services under a given base in directory. Options: +.RS +.TP +\fB\-basedn\fP\ \fIbase_dn\fP +Specifies the base DN for searching the policies, limiting the search to a particular subtree. If this option +is not provided, LDAP Server specific search base will be used. +For eg, in the case of OpenLDAP, value of +.B defaultsearchbase +from +.I slapd.conf +file will be used, where as in the case of eDirectory, the default value +for the base DN is +.B Root. +.TP +EXAMPLE: +\fBkdb5_ldap_util -D cn=admin,o=org list_service\fP +.nf +Password for "cn=admin,o=org": +cn=service-kdc,o=org +cn=service-adm,o=org +cn=service-pwd,o=org +.fi +.RE +.SH SEE ALSO +kadmin(8) diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.c new file mode 100644 index 000000000..889151531 --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.c @@ -0,0 +1,655 @@ +/* + * kadmin/ldap_util/kdb5_ldap_util.c + * + * (C) Copyright 1990,1991, 1996 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Edit a KDC database. + */ + +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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 <stdio.h> +#include <time.h> + +#include <k5-int.h> +#include <kadm5/admin.h> +#include <adm_proto.h> +#include "kdb5_ldap_util.h" + +typedef void (*cmd_func)(int, char **); +int cmd_index(char *name); + +char *mkey_password = 0; +int exit_status = 0; +krb5_context util_context; +kadm5_config_params global_params; +krb5_boolean db_inited = FALSE; + +char *progname; +krb5_boolean manual_mkey = FALSE; + +/* + * This function prints the usage of kdb5_ldap_util, which is + * the LDAP configuration utility. + */ +void usage() +{ + fprintf(stderr, "Usage: " +"kdb5_util [-D user_dn [-w passwd]] [-h ldap_server] [-p ldap_port]\n" +"\tcmd [cmd_options]\n" + +/* Create realm */ +"create [-subtree subtree_dn] [-sscope search_scope]\n" +#ifdef HAVE_EDIRECTORY +"\t\t[-kdcdn kdc_service_list] [-admindn admin_service_list]\n" +"\t\t[-pwddn passwd_service_list]\n" +#endif +"\t\t[-enctypes supported_enc_types] [-defenctype default_enc_type]\n" +"\t\t[-salttypes supported_salt_types] [-defsalttype default_salt_type]\n" +"\t\t[-m|-P password|-sf stashfilename] [-k mkeytype]\n" +"\t\t[-maxtktlife max_ticket_life] [-maxrenewlife max_renewable_ticket_life]\n" +"\t\t[ticket_flags] [-r realm]\n" + +/* modify realm */ +"modify [-subtree subtree_dn] [-sscope search_scope]\n" +#ifdef HAVE_EDIRECTORY +"\t\t[-kdcdn kdc_service_list |\n" +"\t\t[-clearkdcdn kdc_service_list] [-addkdcdn kdc_service_list]]\n" +"\t\t[-admindn admin_service_list | [-clearadmindn admin_service_list]\n" +"\t\t[-addadmindn admin_service_list]] [-pwddn passwd_service_list |\n" +"\t\t[-clearpwddn passwd_service_list] [-addpwddn passwd_service_list]]\n" +#endif +"\t\t[-enctypes supported_enc_types | [-clearenctypes enc_type_list]\n" +"\t\t[-addenctypes enc_type_list]] [-defenctype default_enc_type]\n" +"\t\t[-salttypes supported_salt_types | [-clearsalttypes salt_type_list]\n" +"\t\t[-addsalttypes salt_type_list]] [-defsalttype default_salt_type]\n" +"\t\t[-maxtktlife max_ticket_life] [-maxrenewlife max_renewable_ticket_life]\n" +"\t\t[ticket_flags] [-r realm]\n" +/* View realm */ +"view [-r realm]\n" + +/* Destroy realm */ +"destroy [-f] [-r realm]\n" + +/* List realms */ +"list\n" + +#ifdef HAVE_EDIRECTORY +/* Create Service */ +"create_service {-kdc|-admin|-pwd} [-servicehost service_host_list]\n" +"\t\t[-realm realm_list] \n" +"\t\t[-randpw|-fileonly] [-f filename] service_dn\n" + +/* Modify service */ +"modify_service [-servicehost service_host_list |\n" +"\t\t[-clearservicehost service_host_list]\n" +"\t\t[-addservicehost service_host_list]]\n" +"\t\t[-realm realm_list | [-clearrealm realm_list]\n" +"\t\t[-addrealm realm_list]] service_dn\n" + +/* View Service */ +"view_service service_dn\n" + +/* Destroy Service */ +"destroy_service [-force] [-f stashfilename] service_dn\n" + +/* List services */ +"list_service [-basedn base_dn]\n" + +/* Set Service password */ +"setsrvpw [-randpw|-fileonly] [-f filename] service_dn\n" + +#else + +/* Stash the service password */ +"stashsrvpw [-f filename] service_dn\n" + +#endif + +/* Create policy */ +"create_policy [-maxtktlife max_ticket_life]\n" +"\t\t[-maxrenewlife max_renewable_ticket_life] [ticket_flags] policy_dn\n" + +/* Modify policy */ +"modify_policy [-maxtktlife max_ticket_life]\n" +"\t\t[-maxrenewlife max_renewable_ticket_life] [ticket_flags] policy_dn\n" + +/* View policy */ +"view_policy policy_dn\n" + +/* Destroy policy */ +"destroy_policy [-force] policy_dn\n" + +/* List policies */ +"list_policy [-basedn base_dn]\n" + +); +} + +void db_usage (int type) { + /* + * This should print usage of 'type' command. For now, we will print usage + * of all commands. + */ + usage (); +} + +/* The help messages for all sub-commands should be in the + * same order as listed in this table. + */ +static struct _cmd_table { + char *name; + cmd_func func; + int opendb; +} cmd_table[] = { + {"create", kdb5_ldap_create, 1}, + {"modify", kdb5_ldap_modify, 1}, + {"view", kdb5_ldap_view, 1}, + {"destroy", kdb5_ldap_destroy, 1}, + {"list", kdb5_ldap_list, 1}, +#ifdef HAVE_EDIRECTORY + {"create_service", kdb5_ldap_create_service, 1}, + {"modify_service", kdb5_ldap_modify_service, 1}, + {"view_service", kdb5_ldap_view_service, 1}, + {"destroy_service", kdb5_ldap_destroy_service, 1}, + {"list_service",kdb5_ldap_list_services,1}, + {"setsrvpw", kdb5_ldap_set_service_password, 0}, +#else + {"stashsrvpw", kdb5_ldap_stash_service_password, 0}, +#endif + {"create_policy", kdb5_ldap_create_policy, 1}, + {"modify_policy", kdb5_ldap_modify_policy, 1}, + {"view_policy", kdb5_ldap_view_policy, 1}, + {"destroy_policy", kdb5_ldap_destroy_policy, 1}, + {"list_policy", kdb5_ldap_list_policies, 1}, + {NULL, NULL, 0}, +}; + + +/* + * The function cmd_lookup returns the structure matching the + * command name and returns NULL if nothing matches. + */ +static struct _cmd_table *cmd_lookup(name) + char *name; +{ + int i; + + for (i = 0; cmd_table[i].name != NULL; i++) + if (strcmp(cmd_table[i].name, name) == 0) + return &cmd_table[i]; + + return NULL; +} + + +/* + * The function cmd_index provides the offset of the command + * in the command table, which can be used to get the corresponding + * help from the help message table. + */ +int cmd_index(name) + char *name; +{ + int i; + + if (name == NULL) + return -1; + + for (i = 0; cmd_table[i].name != NULL; i++) + if (strcmp(cmd_table[i].name, name) == 0) + return i; + + return -1; +} + +static void extended_com_err_fn (const char *myprog, errcode_t code, + const char *fmt, va_list args) +{ + const char *emsg; + emsg = krb5_get_error_message (util_context, code); + fprintf (stderr, "%s: %s ", myprog, emsg); + krb5_free_error_message (util_context, emsg); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); +} + +int main(argc, argv) + int argc; + char *argv[]; +{ + struct _cmd_table *cmd = NULL; + char *koptarg = NULL, **cmd_argv = NULL; + int cmd_argc = 0; + krb5_error_code retval; + int usage_print = 0; + int gp_is_static = 1; + krb5_error_code db_retval = 1; + char *bind_dn = NULL; + char *passwd = NULL; + char *ldap_server = NULL; + char *ldap_port = NULL; + unsigned int ldapmask = 0; + unsigned int passwd_len = 0; + char *prompt = NULL; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context=NULL; + char *value = NULL, *conf_section = NULL; + krb5_boolean realm_name_required = FALSE; + krb5_boolean print_help_message = FALSE; + + retval = krb5_init_context(&util_context); + set_com_err_hook(extended_com_err_fn); + if (retval) { + com_err (progname, retval, "while initializing Kerberos code"); + exit_status++; + goto cleanup; + } + + progname = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]); + + cmd_argv = (char **) malloc(sizeof(char *)*argc); + if (cmd_argv == NULL) { + com_err(progname, ENOMEM, "while creating sub-command arguments"); + exit_status++; + goto cleanup; + } + memset(cmd_argv, 0, sizeof(char *)*argc); + cmd_argc = 1; + + memset(&global_params, 0, sizeof(kadm5_config_params)); + + argv++; argc--; + while (*argv) { + if (strcmp(*argv, "--help") == 0) { + print_help_message = TRUE; + } + if (strcmp(*argv, "-P") == 0 && ARG_VAL) { + mkey_password = koptarg; + manual_mkey = TRUE; + } else if (strcmp(*argv, "-r") == 0 && ARG_VAL) { + global_params.realm = koptarg; + global_params.mask |= KADM5_CONFIG_REALM; + /* not sure this is really necessary */ + if ((retval = krb5_set_default_realm(util_context, + global_params.realm))) { + com_err(progname, retval, "while setting default realm name"); + exit_status++; + goto cleanup; + } + } else if (strcmp(*argv, "-k") == 0 && ARG_VAL) { + if (krb5_string_to_enctype(koptarg, &global_params.enctype)) + com_err(argv[0], 0, "%s is an invalid enctype", koptarg); + else + global_params.mask |= KADM5_CONFIG_ENCTYPE; + } else if (strcmp(*argv, "-M") == 0 && ARG_VAL) { + global_params.mkey_name = koptarg; + global_params.mask |= KADM5_CONFIG_MKEY_NAME; + } else if (strcmp(*argv, "-sf") == 0 && ARG_VAL) { + global_params.stash_file = koptarg; + global_params.mask |= KADM5_CONFIG_STASH_FILE; + } else if (strcmp(*argv, "-m") == 0) { + manual_mkey = TRUE; + global_params.mkey_from_kbd = 1; + global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; + } else if (strcmp(*argv, "-D") == 0 && ARG_VAL) { + bind_dn = koptarg; + if (bind_dn == NULL) { + com_err(progname, ENOMEM, "while reading ldap parameters"); + exit_status++; + goto cleanup; + } + ldapmask |= CMD_LDAP_D; + } else if (strcmp(*argv, "-w") == 0 && ARG_VAL) { + passwd = strdup(koptarg); + if (passwd == NULL) { + com_err(progname, ENOMEM, "while reading ldap parameters"); + exit_status++; + goto cleanup; + } + ldapmask |= CMD_LDAP_W; + } else if (strcmp(*argv, "-h") == 0 && ARG_VAL) { + ldap_server = koptarg; + if (ldap_server == NULL) { + com_err(progname, ENOMEM, "while reading ldap parameters"); + exit_status++; + goto cleanup; + } + ldapmask |= CMD_LDAP_H; + } else if (strcmp(*argv, "-p") == 0 && ARG_VAL) { + ldap_port = koptarg; + if (ldap_port == NULL) { + com_err(progname, ENOMEM, "while reading ldap parameters"); + exit_status++; + goto cleanup; + } + ldapmask |= CMD_LDAP_P; + } else if (cmd_lookup(*argv) != NULL) { + if (cmd_argv[0] == NULL) + cmd_argv[0] = *argv; + else { + free(cmd_argv); + cmd_argv = NULL; + usage(); + goto cleanup; + } + } else { + cmd_argv[cmd_argc++] = *argv; + } + argv++; argc--; + } + + if (cmd_argv[0] == NULL) { + free(cmd_argv); + cmd_argv = NULL; + usage(); + goto cleanup; + } + + /* if we need to print the help message (because of --help option) + * we will print the help corresponding to the sub-command. + */ + if (print_help_message) { + char *cmd_name = cmd_argv[0]; + free(cmd_argv); + cmd_argv = NULL; + usage(); + goto cleanup; + } + + /* We need to check for the presence of default realm name only in + * the case of realm related operations like create, destroy etc. + */ + if ((strcmp(cmd_argv[0], "create") == 0) || + (strcmp(cmd_argv[0], "destroy") == 0) || + (strcmp(cmd_argv[0], "modify") == 0) || + (strcmp(cmd_argv[0], "view") == 0) + ) { + realm_name_required = TRUE; + } + + if( !util_context->default_realm ) { + char *temp = NULL; + retval = krb5_get_default_realm(util_context, &temp); + if( retval ) { + if (realm_name_required) { + com_err (progname, retval, "while getting default realm"); + exit_status++; + goto cleanup; + } + } + else + util_context->default_realm = temp; + } + /* If we have the realm name, we can safely say that + * realm_name is required so that we don't neglect any information. + */ + else + realm_name_required = TRUE; + + retval = profile_get_string( util_context->profile, KDB_REALM_SECTION, + util_context->default_realm, KDB_MODULE_POINTER, + NULL, + &value ); + + if(!(value)) { + retval = profile_get_string( util_context->profile, KDB_MODULE_DEF_SECTION, + KDB_MODULE_POINTER, NULL, + NULL, + &value ); + if(!(value)) { + if (util_context->default_realm) + conf_section = strdup( util_context->default_realm ); + } + else { + conf_section = strdup(value); + free(value); + } + } + else { + conf_section = strdup(value); + free(value); + } + + if (realm_name_required) { + retval = kadm5_get_config_params(util_context, 1, + &global_params, &global_params); + if (retval) { + com_err(argv[0], retval, "while retreiving configuration parameters"); + exit_status++; + goto cleanup; + } + gp_is_static = 0; + } + + if ((retval = krb5_ldap_lib_init()) != 0) { + com_err(argv[0], retval, "while initializing error handling"); + exit_status++; + goto cleanup; + } + + /* Initialize the ldap context */ + ldap_context = calloc(sizeof(krb5_ldap_context), 1); + if (ldap_context == NULL) { + com_err(argv[0], ENOMEM, "while initializing ldap handle"); + exit_status++; + goto cleanup; + } + + /* If LDAP parameters are specified, replace them with the values from config */ + if (ldapmask & CMD_LDAP_D) { + /* If password is not specified, prompt for it */ + if (passwd == NULL) { + passwd = (char *)malloc(MAX_PASSWD_LEN); + if (passwd == NULL) { + com_err(argv[0], ENOMEM, "while retrieving ldap configuration"); + exit_status++; + goto cleanup; + } + prompt = (char *)malloc(MAX_PASSWD_PROMPT_LEN); + if (prompt == NULL) { + free(passwd); + passwd = NULL; + com_err(argv[0], ENOMEM, "while retrieving ldap configuration"); + exit_status++; + goto cleanup; + } + memset(passwd, 0, sizeof(passwd)); + passwd_len = MAX_PASSWD_LEN - 1; + snprintf(prompt, MAX_PASSWD_PROMPT_LEN, "Password for \"%s\"", bind_dn); + + db_retval = krb5_read_password(util_context, prompt, NULL, passwd, &passwd_len); + + if ((db_retval) || (passwd_len == 0)) { + com_err(argv[0], ENOMEM, "while retrieving ldap configuration"); + free(passwd); + passwd = NULL; + exit_status++; + goto cleanup; + } + } + + ldap_context->bind_pwd = passwd; + } + + /* If ldaphost is specified, release entry filled by configuration & use this */ + if (ldapmask & CMD_LDAP_H) { + + ldap_context->server_info_list = (krb5_ldap_server_info **) calloc (2, sizeof (krb5_ldap_server_info *)) ; + if (ldap_context->server_info_list == NULL) { + com_err(argv[0], ENOMEM, "while initializing server list"); + exit_status++; + goto cleanup; + } + + ldap_context->server_info_list[0] = (krb5_ldap_server_info *) calloc (1, sizeof (krb5_ldap_server_info)); + if (ldap_context->server_info_list[0] == NULL) { + com_err(argv[0], ENOMEM, "while initializing server list"); + exit_status++; + goto cleanup; + } + + ldap_context->server_info_list[0]->server_status = NOTSET; + + ldap_context->server_info_list[0]->server_name = strdup(ldap_server); + if (ldap_context->server_info_list[0]->server_name == NULL) { + com_err(argv[0], ENOMEM, "while initializing server list"); + exit_status++; + goto cleanup; + } + } + /* If ldapport is specified, release entry filled by configuration & use this*/ + if (ldapmask & CMD_LDAP_P) { + ldap_context->port = atoi(ldap_port); + } + if (bind_dn) { + ldap_context->bind_dn = strdup(bind_dn); + if (ldap_context->bind_dn == NULL) { + com_err(argv[0], ENOMEM, "while retrieving ldap configuration"); + exit_status++; + goto cleanup; + } + } else + ldap_context->bind_dn = NULL; + + ldap_context->service_type = SERVICE_DN_TYPE_CLIENT; + + if(realm_name_required) { + if ((global_params.enctype != ENCTYPE_UNKNOWN) && + (!krb5_c_valid_enctype(global_params.enctype))) { + com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP, + "while setting up enctype %d", global_params.enctype); + } + } + + cmd = cmd_lookup(cmd_argv[0]); + + /* Setup DAL handle to access the database */ + dal_handle = calloc( (size_t)1, sizeof(kdb5_dal_handle) ); + if( dal_handle == NULL ) { + goto cleanup; + } + dal_handle->db_context = ldap_context; + util_context->db_context = (void *) dal_handle; + + db_retval = krb5_ldap_read_server_params(util_context, conf_section, KRB5_KDB_SRV_TYPE_OTHER); + if (db_retval) { + com_err(argv[0], db_retval, "while reading ldap configuration"); + exit_status++; + goto cleanup; + } + + if (cmd->opendb) { + db_retval = krb5_ldap_db_init( util_context, ldap_context); + if (db_retval) { + com_err(progname, db_retval, "while initializing database"); + exit_status++; + goto cleanup; + } + db_inited = TRUE; + } + (*cmd->func)(cmd_argc, cmd_argv); + + goto cleanup; + +cleanup: + if (passwd) + memset(passwd, 0, sizeof(passwd)); + if (ldap_context && ldap_context->bind_pwd) + memset(ldap_context->bind_pwd, 0, sizeof(ldap_context->bind_pwd)); + + if (util_context) { + if (gp_is_static == 0) + kadm5_free_config_params(util_context, &global_params); + krb5_ldap_close(util_context); + krb5_free_context(util_context); + } + + if (cmd_argv) + free(cmd_argv); + if (prompt) + free(prompt); + if (conf_section) + free(conf_section); + if (dal_handle) + free(dal_handle); + + if (usage_print) { + usage(); + } + + return exit_status; +} + diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.h b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.h new file mode 100644 index 000000000..f2c49a57e --- /dev/null +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.h @@ -0,0 +1,78 @@ +/* + * kadmin/ldap_util/kdb5_ldap_util.h + */ + +/* 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 + * documentation and/or other materials provided with the distribution. + * * 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 "kdb_ldap.h" +#include "kdb5_ldap_realm.h" +#include "kdb5_ldap_services.h" +#include "kdb5_ldap_policy.h" + +#define MAIN_HELP -1 +#define CREATE_REALM 1 +#define MODIFY_REALM 2 +#define VIEW_REALM 3 +#define DESTROY_REALM 4 +#define LIST_REALM 5 + +#ifdef HAVE_EDIRECTORY +# define CREATE_SERVICE 6 +# define MODIFY_SERVICE 7 +# define VIEW_SERVICE 8 +# define DESTROY_SERVICE 9 +# define LIST_SERVICE 10 +# define SET_SRV_PW 16 +#else +# define STASH_SRV_PW 17 +#endif + +#define CREATE_POLICY 11 +#define MODIFY_POLICY 12 +#define VIEW_POLICY 13 +#define DESTROY_POLICY 14 +#define LIST_POLICY 15 + +extern int exit_status; +extern krb5_context util_context; + +extern void usage(); +extern void db_usage(int); + +#define ARG_VAL (--argc > 0 ? (koptarg = *(++argv)) : (char *)(usage(MAIN_HELP), NULL)) + +/* Following are the bitmaps that indicate which of the options among -D, -w, -h, -p & -t + * were specified on the command line. + */ +#define CMD_LDAP_D 0x1 /* set if -D option is specified */ +#define CMD_LDAP_W 0x2 /* set if -w option is specified */ +#define CMD_LDAP_H 0x4 /* set if -h option is specified */ +#define CMD_LDAP_P 0x8 /* set if -p option is specified */ + +#define MAX_PASSWD_LEN 1024 +#define MAX_PASSWD_PROMPT_LEN 276 /* max_dn_size(=256) + strlen("Password for \" \"")=20 */ diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ChangeLog b/src/plugins/kdb/ldap/libkdb_ldap/ChangeLog new file mode 100644 index 000000000..d8553db18 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ChangeLog @@ -0,0 +1,37 @@ +2006-04-08 Ken Raeburn <raeburn@mit.edu> + + * kdb_ldap.c, kdb_ldap_conn.c: Include autoconf.h before testing + HAVE_UNISTD_H. + +2006-03-22 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in (DEFS): Define a bunch of macros for local renaming + of symbol names duplicated in libkdb5 and exported from there. + +2006-03-21 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in (SHLIB_EXPDEPS, SHLIB_EXPLIBS): Add kdb5 library. + (LIBMAJOR): Bump to 1. + +2006-03-20 Ken Raeburn <raeburn@mit.edu> + + * ldap_misc.c (krb5_ldap_get_keysalt_tuples): Unused function + deleted. + (LDAP_DEFAULT_ENCTYPE, LDAP_DEFAULT_SALTTYPE): Macros deleted. + * kdb_ldap.h (krb5_ldap_get_keysalt_tuples): Don't declare it. + +2006-03-17 Ken Raeburn <raeburn@mit.edu> + + * configure.in, kdb_ldap.c, kdb_ldap_conn.c, kdb_xdr.c, kdb_xdr.h, + kerberos.ldif, kerberos.schema, ldap_err.c, ldap_err.h, + ldap_fetch_mkey.c, ldap_handle.c, ldap_handle.h, + ldap_krbcontainer.c, ldap_krbcontainer.h, ldap_main.h, + ldap_misc.c, ldap_misc.h, ldap_principal2.c, ldap_principal.c, + ldap_principal.h, ldap_pwd_policy.c, ldap_pwd_policy.h, + ldap_realm.c, ldap_realm.h, ldap_service_rights.c, + ldap_services.c, ldap_services.h, ldap_service_stash.c, + ldap_service_stash.h, ldap_tkt_policy.c, ldap_tkt_policy.h, + princ_xdr.c, princ_xdr.h: Moved from plugins/kdb/kdb_ldap. + * libkdb_ldap.exports: Copied and updated. + * Makefile.in: Copied and updated to build a shared library. + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/Makefile.in b/src/plugins/kdb/ldap/libkdb_ldap/Makefile.in new file mode 100644 index 000000000..1b650c530 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/Makefile.in @@ -0,0 +1,280 @@ +thisconfigdir=. +myfulldir=plugins/kdb/ldap/libkdb_ldap +mydir=. +BUILDTOP=$(REL)..$(S)..$(S)..$(S).. +KRB5_RUN_ENV = @KRB5_RUN_ENV@ +KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ; +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) +# Lots of ugliness here because of duplicated symbol names. +# Can I just punt the duplicates and import from libkdb5, or +# is keeping them separate important? +DEFINES = \ + -Dkrb5_dbe_lookup_last_pwd_change=kdb_ldap_dbe_lookup_last_pwd_change \ + -Dkrb5_dbe_lookup_mod_princ_data=kdb_ldap_dbe_lookup_mod_princ_data \ + -Dkrb5_dbe_lookup_tl_data=kdb_ldap_dbe_lookup_tl_data \ + -Dkrb5_dbe_update_last_pwd_change=kdb_ldap_dbe_update_last_pwd_change \ + -Dkrb5_dbe_update_mod_princ_data=kdb_ldap_dbe_update_mod_princ_data \ + -Dkrb5_dbe_update_tl_data=kdb_ldap_dbe_update_tl_data +DEFS= + +LOCALINCLUDES = -I$(SRCTOP)/lib/kdb + +LIBBASE=kdb_ldap +LIBMAJOR=1 +LIBMINOR=0 +RELDIR=../plugins/kdb/ldap/libkdb_ldap +# Depends on libk5crypto and libkrb5 +# Also on gssrpc, for xdr stuff. +SHLIB_EXPDEPS = \ + $(GSSRPC_DEPLIBS) \ + $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ + $(SUPPORT_DEPLIB) \ + $(TOPLIBD)/libkrb5$(SHLIBEXT) +SHLIB_EXPLIBS= $(GSSRPC_LIBS) -lkrb5 -lk5crypto $(SUPPORT_LIB) -lldap -llber $(LIBS) +SHLIB_DIRS=-L$(TOPLIBD) +SHLIB_RDIRS=$(KRB5_LIBDIR) + +SRCS= $(srcdir)/kdb_ldap.c \ + $(srcdir)/kdb_ldap_conn.c \ + $(srcdir)/ldap_realm.c \ + $(srcdir)/ldap_krbcontainer.c \ + $(srcdir)/ldap_principal.c \ + $(srcdir)/ldap_principal2.c \ + $(srcdir)/ldap_pwd_policy.c \ + $(srcdir)/ldap_misc.c \ + $(srcdir)/ldap_handle.c \ + $(srcdir)/ldap_tkt_policy.c \ + $(srcdir)/ldap_services.c \ + $(srcdir)/ldap_service_rights.c \ + $(srcdir)/princ_xdr.c \ + $(srcdir)/ldap_fetch_mkey.c \ + $(srcdir)/ldap_service_stash.c \ + $(srcdir)/kdb_xdr.c \ + $(srcdir)/ldap_err.c + +STOBJLISTS=OBJS.ST +STLIBOBJS= kdb_ldap.o \ + kdb_ldap_conn.o \ + ldap_realm.o \ + ldap_krbcontainer.o \ + ldap_principal.o \ + ldap_principal2.o \ + ldap_pwd_policy.o \ + ldap_misc.o \ + ldap_handle.o \ + ldap_tkt_policy.o \ + ldap_services.o \ + ldap_service_rights.o \ + princ_xdr.o \ + ldap_fetch_mkey.o \ + ldap_service_stash.o \ + kdb_xdr.o \ + ldap_err.o + +all-unix:: all-liblinks +install-unix:: install-libs +clean-unix:: clean-liblinks clean-libobjs clean-libs + +# @lib_frag@ +# @libobj_frag@ + +# +++ Dependency line eater +++ +# +# Makefile dependencies follow. This must be the last section in +# the Makefile.in file +# +kdb_ldap.so kdb_ldap.po $(OUTPRE)kdb_ldap.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.c kdb_ldap.h ldap_err.h \ + ldap_krbcontainer.h ldap_misc.h ldap_realm.h ldap_services.h +kdb_ldap_conn.so kdb_ldap_conn.po $(OUTPRE)kdb_ldap_conn.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h kdb_ldap_conn.c \ + ldap_handle.h ldap_krbcontainer.h ldap_main.h ldap_misc.h \ + ldap_realm.h ldap_service_stash.h ldap_services.h +ldap_realm.so ldap_realm.po $(OUTPRE)ldap_realm.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_handle.h \ + ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_principal.h \ + ldap_realm.c ldap_realm.h ldap_services.h ldap_tkt_policy.h +ldap_krbcontainer.so ldap_krbcontainer.po $(OUTPRE)ldap_krbcontainer.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_handle.h \ + ldap_krbcontainer.c ldap_krbcontainer.h ldap_main.h \ + ldap_misc.h ldap_realm.h ldap_services.h +ldap_principal.so ldap_principal.po $(OUTPRE)ldap_principal.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ + $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/auth_gss.h \ + $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/clnt.h \ + $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/rpc.h \ + $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/svc.h \ + $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/types.h \ + $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_handle.h \ + ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_principal.c \ + ldap_principal.h ldap_realm.h ldap_services.h ldap_tkt_policy.h \ + princ_xdr.h +ldap_principal2.so ldap_principal2.po $(OUTPRE)ldap_principal2.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ + $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/auth_gss.h \ + $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/clnt.h \ + $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/rpc.h \ + $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/svc.h \ + $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/types.h \ + $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_handle.h \ + ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_principal.h \ + ldap_principal2.c ldap_pwd_policy.h ldap_realm.h ldap_services.h \ + ldap_tkt_policy.h princ_xdr.h +ldap_pwd_policy.so ldap_pwd_policy.po $(OUTPRE)ldap_pwd_policy.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_handle.h \ + ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_pwd_policy.c \ + ldap_pwd_policy.h ldap_realm.h ldap_services.h +ldap_misc.so ldap_misc.po $(OUTPRE)ldap_misc.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_krbcontainer.h \ + ldap_misc.c ldap_misc.h ldap_realm.h ldap_services.h +ldap_handle.so ldap_handle.po $(OUTPRE)ldap_handle.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_handle.c ldap_handle.h \ + ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_realm.h \ + ldap_services.h +ldap_tkt_policy.so ldap_tkt_policy.po $(OUTPRE)ldap_tkt_policy.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_handle.h \ + ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_realm.h \ + ldap_services.h ldap_tkt_policy.c ldap_tkt_policy.h +ldap_services.so ldap_services.po $(OUTPRE)ldap_services.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_handle.h \ + ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_realm.h \ + ldap_services.c ldap_services.h +ldap_service_rights.so ldap_service_rights.po $(OUTPRE)ldap_service_rights.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_err.h ldap_handle.h \ + ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_realm.h \ + ldap_service_rights.c ldap_services.h +princ_xdr.so princ_xdr.po $(OUTPRE)princ_xdr.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \ + $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/auth_gss.h \ + $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/clnt.h \ + $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/rpc.h \ + $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/svc.h \ + $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/types.h \ + $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_krbcontainer.h \ + ldap_principal.h ldap_realm.h ldap_tkt_policy.h princ_xdr.c \ + princ_xdr.h +ldap_fetch_mkey.so ldap_fetch_mkey.po $(OUTPRE)ldap_fetch_mkey.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_fetch_mkey.c \ + ldap_handle.h ldap_krbcontainer.h ldap_main.h ldap_misc.h \ + ldap_realm.h ldap_services.h +ldap_service_stash.so ldap_service_stash.po $(OUTPRE)ldap_service_stash.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/kdb/kdb5.h kdb_ldap.h ldap_handle.h ldap_krbcontainer.h \ + ldap_main.h ldap_misc.h ldap_realm.h ldap_service_stash.c \ + ldap_service_stash.h ldap_services.h +kdb_xdr.so kdb_xdr.po $(OUTPRE)kdb_xdr.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h \ + $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \ + $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \ + $(SRCTOP)/include/kdb.h $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + kdb_xdr.c kdb_xdr.h +ldap_err.so ldap_err.po $(OUTPRE)ldap_err.$(OBJEXT): \ + $(BUILDTOP)/include/kdb5_err.h $(COM_ERR_DEPS) ldap_err.c \ + ldap_err.h diff --git a/src/plugins/kdb/ldap/libkdb_ldap/configure.in b/src/plugins/kdb/ldap/libkdb_ldap/configure.in new file mode 100644 index 000000000..6e280232e --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/configure.in @@ -0,0 +1,26 @@ +K5_AC_INIT(configure.in) +CONFIG_RULES +AC_CHECK_HEADERS(unistd.h) +AC_TYPE_MODE_T +AC_TYPE_OFF_T + +AC_CHECK_FUNCS(srand48 srand srandom umask) + +OPENLDAP=1 +AC_CHECK_HEADERS([ldap.h], :, [OPENLDAP=0; AC_MSG_WARN([ldap.h not found])]) +AC_CHECK_HEADERS([lber.h], :, [OPENLDAP=0; AC_MSG_WARN([lber.h not found])]) +AC_CHECK_LIB(ldap, ldap_init, :, [OPENLDAP=0; AC_MSG_WARN([libldap not found])]) +AC_CHECK_LIB(lber, ber_init, :, [OPENLDAP=0; AC_MSG_WARN([liblber not found])]) + +if test "$OPENLDAP" = "0"; then + AC_ERROR("OPENLDAP libraries missing Skipping openldap database module") +fi + + +KRB5_RUN_FLAGS +dnl The following is for check... +KRB5_BUILD_PROGRAM +KRB5_BUILD_LIBOBJS +KRB5_BUILD_LIBRARY_WITH_DEPS +dnl +V5_AC_OUTPUT_MAKEFILE diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c new file mode 100644 index 000000000..358bf152f --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c @@ -0,0 +1,490 @@ +/* + * lib/kdb/kdb_ldap/kdb_ldap.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "autoconf.h" +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <ctype.h> +#include "kdb_ldap.h" +#include "ldap_misc.h" +#include <kdb5.h> + +static krb5_error_code +krb5_ldap_get_db_opt( char *input, char **opt, char **val ) +{ + char *pos = strchr(input, '='); + + *val = NULL; + if (pos == NULL) + { + *opt = strdup(input); + if (*opt == NULL) + { + return ENOMEM; + } + } + else + { + int len = pos - input; + *opt = malloc((unsigned) len + 1); + if (!*opt) + { + return ENOMEM; + } + memcpy(*opt, input, (unsigned) len); + /* ignore trailing blanks */ + while (isblank((*opt)[len-1])) + --len; + (*opt)[len] = '\0'; + + pos += 1; /* move past '=' */ + while (isblank(*pos)) /* ignore leading blanks */ + pos += 1; + if (*pos != '\0') { + *val = strdup (pos); + if (!*val) + { + free (*opt); + return ENOMEM; + } + } + } + return (0); + +} + + +/* + * ldap get age + */ +krb5_error_code +krb5_ldap_db_get_age(context, db_name, age) + krb5_context context; + char *db_name; + time_t *age; +{ + time (age); + return 0; +} + +/* + * read startup information - kerberos and realm container + */ +krb5_error_code +krb5_ldap_read_startup_information(krb5_context context) +{ + krb5_error_code retval = 0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + int mask=0; + + SETUP_CONTEXT(); + if ((retval=krb5_ldap_read_krbcontainer_params(context, &(ldap_context->krbcontainer)))) { + prepend_err_str (context, "Unable to read Kerberos container", retval, retval); + goto cleanup; + } + + if ((retval=krb5_ldap_read_realm_params(context, context->default_realm, &(ldap_context->lrparams), &mask))) { + prepend_err_str (context, "Unable to read Realm", retval, retval); + goto cleanup; + } + + cleanup: + return retval; +} + + +/* Function to check if a LDAP server supports the SASL external mechanism + *Return values: + * 0 => supports + * 1 => does not support + * 2 => don't know + */ +#define ERR_MSG1 "Unable to check if SASL EXTERNAL mechanism is supported by LDAP server. Proceeding anyway ..." +#define ERR_MSG2 "SASL EXTERNAL mechanism not supported by LDAP server. Can't perform certificate-based bind." + +int +has_sasl_external_mech(context, ldap_server) + krb5_context context; + char *ldap_server; +{ + int i=0, flag=0, ret=0, retval=0; + char *attrs[]={"supportedSASLMechanisms", NULL}, **values=NULL; + LDAP *ld=NULL; + LDAPMessage *msg=NULL, *res=NULL; + + ld = ldap_open(ldap_server, 389); /* Should the port number be configurable ? */ + if(ld == NULL){ + krb5_set_error_message(context, 2, "%s", ERR_MSG1); + ret = 2; /* Don't know */ + goto cleanup; + } + + /* Anonymous bind */ + retval = ldap_simple_bind_s(ld, NULL, NULL); + if(retval != LDAP_SUCCESS){ + krb5_set_error_message(context, 2, "%s", ERR_MSG1); + ret = 2; /* Don't know */ + goto cleanup; + } + + retval = ldap_search_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, &res); + if(retval != LDAP_SUCCESS){ + krb5_set_error_message(context, 2, "%s", ERR_MSG1); + ret = 2; /* Don't know */ + goto cleanup; + } + + msg = ldap_first_message(ld, res); + if(msg == NULL){ + krb5_set_error_message(context, 2, "%s", ERR_MSG1); + ret = 2; /* Don't know */ + goto cleanup; + } + + values = ldap_get_values(ld, msg, "supportedSASLMechanisms"); + if(values == NULL){ + krb5_set_error_message(context, 1, "%s", ERR_MSG2); + ret = 1; /* Not supported */ + goto cleanup; + } + + for(i = 0; values[i] != NULL; i++){ + if(strcmp(values[i], "EXTERNAL")) + continue; + flag = 1; + } + + if(flag != 1){ + krb5_set_error_message(context, 1, "%s", ERR_MSG2); + ret = 1; /* Not supported */ + goto cleanup; + } + +cleanup: + + if(values != NULL) + ldap_value_free(values); + + if(res != NULL) + ldap_msgfree(res); + + if(ld != NULL) + ldap_unbind_s(ld); + + return ret; +} + +void * krb5_ldap_alloc( krb5_context context, void *ptr, size_t size ) +{ + return realloc(ptr, size); +} + +void krb5_ldap_free( krb5_context context, void *ptr ) + +{ + free(ptr); +} + +krb5_error_code krb5_ldap_open( krb5_context context, + char *conf_section, + char **db_args, + int mode ) +{ + krb5_error_code status = 0; + char **t_ptr = db_args; + krb5_ldap_context *ldap_context=NULL; + int srv_cnt = 0; + kdb5_dal_handle *dal_handle=NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + ldap_context = calloc(1, sizeof(krb5_ldap_context)); + if (ldap_context == NULL) + { + status = ENOMEM; + goto clean_n_exit; + } + + + while ( t_ptr && *t_ptr ) + { + char *opt = NULL, *val = NULL; + + if( (status = krb5_ldap_get_db_opt( *t_ptr, &opt, &val )) != 0 ) + { + goto clean_n_exit; + } + if( opt && !strcmp( opt, "binddn" ) ) + { + if( ldap_context->bind_dn ) + { + free (opt); + free (val); + status = EINVAL; + krb5_set_error_message (context, status, "'binddn' missing"); + goto clean_n_exit; + } + if( val == NULL ) + { + status = EINVAL; + krb5_set_error_message (context, status, "'binddn' value missing"); + free(opt); + goto clean_n_exit; + } + ldap_context->bind_dn = strdup(val); + if (ldap_context->bind_dn == NULL) { + free (opt); + free (val); + status = ENOMEM; + goto clean_n_exit; + } + } + else if( opt && !strcmp( opt, "nconns" ) ) + { + if( ldap_context->max_server_conns ) + { + free (opt); + free (val); + status = EINVAL; + krb5_set_error_message (context, status, "'nconns' missing"); + goto clean_n_exit; + } + if( val == NULL ) + { + status = EINVAL; + krb5_set_error_message (context, status, "'nconns' value missing"); + free(opt); + goto clean_n_exit; + } + ldap_context->max_server_conns = atoi(val) ? atoi(val) : DEFAULT_CONNS_PER_SERVER; + } + else if( opt && !strcmp( opt, "bindpwd" ) ) + { + if( ldap_context->bind_pwd ) + { + free (opt); + free (val); + status = EINVAL; + krb5_set_error_message (context, status, "'bindpwd' missing"); + goto clean_n_exit; + } + if( val == NULL ) + { + status = EINVAL; + krb5_set_error_message (context, status, "'bindpwd' value missing"); + free(opt); + goto clean_n_exit; + } + ldap_context->bind_pwd = strdup(val); + if (ldap_context->bind_pwd == NULL) { + free (opt); + free (val); + status = ENOMEM; + goto clean_n_exit; + } + } + else if( opt && !strcmp( opt, "host" ) ) + { + char *port = NULL; + + if( val == NULL ) + { + status = EINVAL; + krb5_set_error_message (context, status, "'host' value missing"); + free(opt); + goto clean_n_exit; + } + if (ldap_context->server_info_list == NULL) + ldap_context->server_info_list = (krb5_ldap_server_info **) calloc (SERV_COUNT+1, sizeof (krb5_ldap_server_info *)) ; + + if (ldap_context->server_info_list == NULL) { + free (opt); + free (val); + status = ENOMEM; + goto clean_n_exit; + } + + ldap_context->server_info_list[srv_cnt] = (krb5_ldap_server_info *) calloc (1, sizeof (krb5_ldap_server_info)); + if (ldap_context->server_info_list[srv_cnt] == NULL) { + free (opt); + free (val); + status = ENOMEM; + goto clean_n_exit; + } + + ldap_context->server_info_list[srv_cnt]->server_status = NOTSET; + + val = strtok_r(val, ":", &port); + ldap_context->server_info_list[srv_cnt]->server_name = strdup(val); + if (ldap_context->server_info_list[srv_cnt]->server_name == NULL) { + free (opt); + free (val); + status = ENOMEM; + goto clean_n_exit; + } + + if (port) { + ldap_context->server_info_list[srv_cnt]->port = atoi(port); + } + srv_cnt++; + } + else if( opt && !strcmp( opt, "port" ) ) + { + if( ldap_context->port ) + { + free (opt); + free (val); + status = EINVAL; + krb5_set_error_message (context, status, "'port' missing"); + goto clean_n_exit; + } + if( val == NULL ) + { + status = EINVAL; + krb5_set_error_message (context, status, "'port' value missing"); + free(opt); + goto clean_n_exit; + } + ldap_context->port = atoi(val); + } + else if( opt && !strcmp( opt, "cert" ) ) + { + if( val == NULL ) + { + status = EINVAL; + krb5_set_error_message (context, status, "'cert' value missing"); + free(opt); + goto clean_n_exit; + } + + if( ldap_context->root_certificate_file == NULL ) + { + ldap_context->root_certificate_file = strdup(val); + if (ldap_context->root_certificate_file == NULL) { + free (opt); + free (val); + status = ENOMEM; + goto clean_n_exit; + } + } + else + { + void *tmp=NULL; + char *oldstr = NULL; + unsigned int len=0; + + oldstr = strdup(ldap_context->root_certificate_file); + if (oldstr == NULL) + { + free (opt); + free (val); + status = ENOMEM; + goto clean_n_exit; + } + + tmp = ldap_context->root_certificate_file; + len = strlen(ldap_context->root_certificate_file) + 2 + strlen(val); + ldap_context->root_certificate_file = realloc(ldap_context->root_certificate_file, + len); + if (ldap_context->root_certificate_file == NULL) { + free (tmp); + free (opt); + free (val); + status = ENOMEM; + goto clean_n_exit; + } + memset(ldap_context->root_certificate_file, 0, len); + sprintf(ldap_context->root_certificate_file,"%s %s", oldstr, val); + free (oldstr); + } + } + /* ignore hash argument. Might have been passed from create */ + else + { + status = EINVAL; + krb5_set_error_message (context, status, "unknown option \'%s\'", + opt?opt:val); + free(opt); + free(val); + goto clean_n_exit; + } + + free(opt); + free(val); + t_ptr++; + } + + dal_handle = (kdb5_dal_handle *) context->db_context; + dal_handle->db_context = ldap_context; + status = krb5_ldap_read_server_params(context, conf_section, mode & 0x0300); + if (status) { + ldap_context = NULL; + dal_handle->db_context = NULL; + prepend_err_str (context, "Error reading LDAP server params: ", status, status); + goto clean_n_exit; + } + if ((status=krb5_ldap_db_init( context, ldap_context)) != 0) { + goto clean_n_exit; + } + + if ((status=krb5_ldap_read_startup_information(context)) != 0) { + goto clean_n_exit; + } + + clean_n_exit: + /* may be clearing up is not required db_fini might do it for us, check out */ + if (status) { + krb5_ldap_close(context); + } + return status; +} + +#include "ldap_err.h" +int +set_ldap_error (krb5_context ctx, int st, int op) +{ + int translated_st = translate_ldap_error(st, op); + krb5_set_error_message(ctx, translated_st, "%s", ldap_err2string(st)); + return translated_st; +} + +void +prepend_err_str (krb5_context ctx, const char *str, krb5_error_code err, + krb5_error_code oerr) +{ + const char *omsg; + if (oerr == 0) oerr = err; + omsg = krb5_get_error_message (ctx, err); + krb5_set_error_message (ctx, err, "%s %s", str, omsg); +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h new file mode 100644 index 000000000..888fed0c5 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h @@ -0,0 +1,262 @@ +/* + * lib/kdb/kdb_ldap/kdb_ldap.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +/* */ +#ifndef _KDB_LDAP_H +#define _KDB_LDAP_H 1 + +#include <ldap.h> +#include <k5-thread.h> +#include <kdb5.h> +#include "k5-int.h" +#include "ldap_krbcontainer.h" +#include "ldap_realm.h" + +extern struct timeval timelimit; + +#define SERV_COUNT 100 +#define DEFAULT_CONNS_PER_SERVER 5 +#define REALM_READ_REFRESH_INTERVAL (5 * 60) + +#ifdef HAVE_EDIRECTORY +#define SECURITY_CONTAINER "cn=Security" +#define KERBEROS_CONTAINER "cn=Kerberos,cn=Security" +#endif + +#define NEG(val) (val <0) ? abs(val) : -val ; +#define MAXINTLEN 10 + +#define IGNORE_STATUS 0 +#define CHECK_STATUS 1 + +#define SETUP_CONTEXT() if (context == NULL || context->db_context == NULL \ + || ((kdb5_dal_handle *)context->db_context)->db_context == NULL) { \ + return EINVAL; \ + } \ + dal_handle = (kdb5_dal_handle *)context->db_context; \ + ldap_context = (krb5_ldap_context *) dal_handle->db_context; \ + if (ldap_context == NULL || ldap_context->server_info_list == NULL) \ + return KRB5_KDB_DBNOTINITED; + +#define GET_HANDLE() ld = NULL; \ + st = krb5_ldap_request_handle_from_pool(ldap_context, &ldap_server_handle); \ + if (st != 0) { \ + prepend_err_str(context, "LDAP handle unavailable: ", KRB5_KDB_ACCESS_ERROR, st); \ + st = KRB5_KDB_ACCESS_ERROR; \ + goto cleanup; \ + } \ + ld = ldap_server_handle->ldap_handle; + +extern int set_ldap_error (krb5_context ctx, int st, int op); +extern void prepend_err_str (krb5_context ctx, const char *s, krb5_error_code err, krb5_error_code oerr); + +#define LDAP_SEARCH(base, scope, filter, attrs) LDAP_SEARCH_1(base, scope, filter, attrs, CHECK_STATUS) + +#define LDAP_SEARCH_1(base, scope, filter, attrs, status_check) \ + do { \ + st = ldap_search_ext_s(ld, base, scope, filter, attrs, 0, NULL, NULL, &timelimit, LDAP_NO_LIMIT, &result); \ + if (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR) { \ + tempst = krb5_ldap_rebind(ldap_context, &ldap_server_handle); \ + if (ldap_server_handle) \ + ld = ldap_server_handle->ldap_handle; \ + } \ + }while (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR && tempst == 0); \ + \ + if (status_check != IGNORE_STATUS) { \ + if (tempst != 0) { \ + prepend_err_str(context, "LDAP handle unavailable: ", KRB5_KDB_ACCESS_ERROR, st); \ + st = KRB5_KDB_ACCESS_ERROR; \ + goto cleanup; \ + } \ + if (st != LDAP_SUCCESS) { \ + st = set_ldap_error(context, st, OP_SEARCH); \ + goto cleanup; \ + } \ + } + + +#define CHECK_CLASS_VALIDITY(st, mask, str) \ + if (st != 0 || mask == 0) { \ + if (st == 0 && mask == 0) { \ + st = set_ldap_error(context, LDAP_OBJECT_CLASS_VIOLATION, OP_SEARCH); \ + } \ + prepend_err_str(context, str, st, st); \ + goto cleanup; \ + } + +#define CHECK_NULL(ptr) if (ptr == NULL) { \ + st = ENOMEM; \ + goto cleanup; \ + } + +#define STORE16_INT(ptr, val) store_16_be(val, ptr) +#define STORE32_INT(ptr, val) store_32_be(val, ptr) +#define UNSTORE16_INT(ptr, val) (val = load_16_be(ptr)) +#define UNSTORE32_INT(ptr, val) (val = load_32_be(ptr)) + +#define KRB5_CONF_KDC_BIND_DN "ldap_kdc_dn" +#define KRB5_CONF_ADMIN_BIND_DN "ldap_kadmind_dn" +#define KRB5_CONF_PWD_BIND_DN "ldap_passwd_dn" + +#define KDB_TL_USER_INFO 0x7ffe + +#define KDB_TL_PRINCTYPE 0x01 +#define KDB_TL_PRINCCOUNT 0x02 +#define KDB_TL_USERDN 0x03 +#define KDB_TL_KEYINFO 0x04 +#define KDB_TL_MASK 0x05 +#define KDB_TL_CONTAINERDN 0x06 +#define KDB_TL_TKTPOLICYDN 0x07 + + +#define CHECK_LDAP_HANDLE(lcontext) if (!(ldap_context \ + && ldap_context->server_info_list)) { \ + return KRB5_KDB_DBNOTINITED; \ + } + +#define HNDL_LOCK(lcontext) k5_mutex_lock(&lcontext->hndl_lock) +#define HNDL_UNLOCK(lcontext) k5_mutex_unlock(&lcontext->hndl_lock) + +/* To be used later */ +typedef struct _krb5_ldap_certificates{ + char *certificate; + int certtype; +}krb5_ldap_certificates; + +/* ldap server info structure */ + +typedef enum _server_type {PRIMARY, SECONDARY} krb5_ldap_server_type; + +typedef enum _server_status {OFF, ON, NOTSET} krb5_ldap_server_status; + +typedef struct _krb5_ldap_server_info krb5_ldap_server_info; + +typedef struct _krb5_ldap_server_handle{ + int msgid; + LDAP *ldap_handle; + krb5_boolean server_info_update_pending; + krb5_ldap_server_info *server_info; + struct _krb5_ldap_server_handle *next; + +}krb5_ldap_server_handle; + +struct _krb5_ldap_server_info { + krb5_ldap_server_type server_type; + krb5_ldap_server_status server_status; + krb5_ui_4 num_conns; + krb5_ldap_server_handle *ldap_server_handles; + time_t downtime; + char *server_name; + krb5_ui_4 port; + char *root_certificate_file; + struct _krb5_ldap_server_info *next; +}; + + +/* ldap server structure */ + +typedef enum {SERVICE_DN_TYPE_SERVER, SERVICE_DN_TYPE_CLIENT} krb5_ldap_servicetype; + +typedef struct _krb5_ldap_context { + krb5_ldap_servicetype service_type; + krb5_ldap_server_info **server_info_list; + krb5_ui_4 max_server_conns; + krb5_ui_4 port; + char *conf_section; + char *bind_dn; + char *bind_pwd; + char *service_password_file; + char *root_certificate_file; + char *service_cert_path; + char *service_cert_pass; + krb5_ldap_certificates **certificates; + krb5_ui_4 cert_count; /* certificate count */ + k5_mutex_t hndl_lock; + krb5_ldap_krbcontainer_params *krbcontainer; + krb5_ldap_realm_params *lrparams; +} krb5_ldap_context; + + +typedef struct { + int nkey; + struct berval **keys; +}KEY; + +#define k5ldap_inited(c) (c && c->db_context \ + && ((kdb5_dal_handle*)c->db_context)->db_context \ + && ((krb5_ldap_context *) ((kdb5_dal_handle*)c->db_context)->db_context)) + + +/* misc functions */ + +krb5_error_code +krb5_ldap_db_init(krb5_context, krb5_ldap_context *); + +krb5_error_code +krb5_ldap_db_single_init(krb5_ldap_context *); + +krb5_error_code +krb5_ldap_rebind(krb5_ldap_context *, krb5_ldap_server_handle **); + +krb5_error_code +krb5_ldap_db_get_age(krb5_context, char *, time_t *); + +krb5_error_code +krb5_ldap_lib_init(); + +krb5_error_code +krb5_ldap_lib_cleanup(void); + +void * +krb5_ldap_alloc( krb5_context kcontext, void *ptr, size_t size ); + +void +krb5_ldap_free( krb5_context kcontext, void *ptr ); + +krb5_error_code +krb5_ldap_get_mkey(krb5_context, krb5_keyblock **); + +krb5_error_code +krb5_ldap_set_mkey(krb5_context, char *, krb5_keyblock *); + +krb5_error_code +krb5_ldap_open( krb5_context , char *, + char **db_args, + int mode ); +krb5_error_code +krb5_ldap_close( krb5_context ); + +krb5_error_code +krb5_ldap_read_startup_information(krb5_context ); + +int +has_sasl_external_mech(krb5_context, char *); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c new file mode 100644 index 000000000..b0902d23c --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c @@ -0,0 +1,355 @@ +/* + * lib/kdb/kdb_ldap/kdb_ldap_conn.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "autoconf.h" +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "ldap_main.h" +#include "ldap_service_stash.h" +#include <kdb5.h> + +static krb5_error_code +krb5_validate_ldap_context(krb5_context context, krb5_ldap_context *ldap_context) +{ + krb5_error_code st=0; + unsigned char *password=NULL; + + if (ldap_context->bind_dn == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "LDAP bind dn value missing "); + goto err_out; + } + + if (ldap_context->bind_pwd == NULL && ldap_context->service_password_file == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "LDAP bind password value missing "); + goto err_out; + } + + if (ldap_context->bind_pwd == NULL && ldap_context->service_password_file != + NULL && ldap_context->service_cert_path == NULL) { + if ((st=krb5_ldap_readpassword(context, ldap_context, &password)) != 0) { + prepend_err_str(context, "Error reading password from stash: ", st, st); + goto err_out; + } + + /* Check if the returned 'password' is actually the path of a certificate */ + if (!strncmp("{FILE}", (char *)password, 6)) { + /* 'password' format: <path>\0<password> */ + ldap_context->service_cert_path = strdup((char *)password + strlen("{FILE}")); + if (password[strlen((char *)password) + 1] == '\0') + ldap_context->service_cert_pass = NULL; + else + ldap_context->service_cert_pass = strdup((char *)password + + strlen((char *)password) + 1); + free(password); + } else { + ldap_context->bind_pwd = (char *)password; + if (ldap_context->bind_pwd == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "Error reading password from stash"); + goto err_out; + } + } + } + + /* NULL password not allowed */ + if (ldap_context->bind_pwd != NULL && strlen(ldap_context->bind_pwd) == 0) { + st = EINVAL; + krb5_set_error_message(context, st, "Service password length is zero"); + goto err_out; + } + +err_out: + return st; +} + +/* + * Internal Functions called by init functions. + */ + +static krb5_error_code +krb5_ldap_bind(ldap_context, ldap_server_handle) + krb5_ldap_context *ldap_context; + krb5_ldap_server_handle *ldap_server_handle; +{ + krb5_error_code st=0; + struct berval bv={0, NULL}, *servercreds=NULL; + + if(ldap_context->service_cert_path != NULL){ + /* Certificate based bind (SASL EXTERNAL mechanism) */ + + st = ldap_sasl_bind_s(ldap_server_handle->ldap_handle, + NULL, /* Authenticating dn */ + "EXTERNAL", /* Method used for authentication */ + &bv, + NULL, + NULL, + &servercreds); + + if (st == LDAP_SASL_BIND_IN_PROGRESS) { + st = ldap_sasl_bind_s( ldap_server_handle->ldap_handle, + NULL, + "EXTERNAL", + servercreds, + NULL, + NULL, + &servercreds); + } + } else { + /* password based simple bind */ + st = ldap_simple_bind_s(ldap_server_handle->ldap_handle, + ldap_context->bind_dn, + ldap_context->bind_pwd); + } + return st; +} + +static krb5_error_code +krb5_ldap_initialize(ldap_context, server_info) + krb5_ldap_context *ldap_context; + krb5_ldap_server_info *server_info; +{ + int port=0; + krb5_error_code st=0; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + if (server_info->port) + port = server_info->port; + else if (ldap_context->port) + port = ldap_context->port; + else + port = LDAPS_PORT; + + + ldap_server_handle = calloc(1, sizeof(krb5_ldap_server_handle)); + if (ldap_server_handle == NULL) { + st = ENOMEM; + goto err_out; + } + + /* ldap init */ + if((ldap_server_handle->ldap_handle=ldap_init(server_info->server_name, + port)) == NULL) { + st = KRB5_KDB_ACCESS_ERROR; + krb5_set_error_message (0, st, "%s", strerror(errno)); + goto err_out; + } + + if ((st=krb5_ldap_bind(ldap_context, ldap_server_handle)) == 0) { + ldap_server_handle->server_info_update_pending = FALSE; + server_info->server_status = ON; + krb5_update_ldap_handle(ldap_server_handle, server_info); + } else { + krb5_set_error_message (0, KRB5_KDB_ACCESS_ERROR, "%s", + ldap_err2string(st)); + st = KRB5_KDB_ACCESS_ERROR; + server_info->server_status = OFF; + time(&server_info->downtime); + /* ldap_unbind_s(ldap_server_handle->ldap_handle); */ + free(ldap_server_handle); + } + +err_out: + return st; +} + +/* + * initialization for data base routines. + */ + +krb5_error_code +krb5_ldap_db_init(krb5_context context, krb5_ldap_context *ldap_context) +{ + krb5_error_code st=0; + krb5_boolean sasl_mech_supported=TRUE; + int cnt=0, version=LDAP_VERSION3, tlsoption=LDAP_OPT_X_TLS_HARD; + struct timeval local_timelimit = {10,0}; + + if ((st=krb5_validate_ldap_context(context, ldap_context)) != 0) + goto err_out; + + ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &version); + ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &local_timelimit); + ldap_set_option(NULL, LDAP_OPT_X_TLS, &tlsoption); + + HNDL_LOCK(ldap_context); + while (ldap_context->server_info_list[cnt] != NULL) { + krb5_ldap_server_info *server_info=NULL; + + server_info = ldap_context->server_info_list[cnt]; + + if (server_info->server_status == NOTSET) { + int conns=0; + + /* + * Check if the server has to perform certificate-based authentication + */ + if(ldap_context->service_cert_path != NULL){ + /* Find out if the server supports SASL EXTERNAL mechanism */ + if(has_sasl_external_mech(context, server_info->server_name) == 1){ + cnt++; + sasl_mech_supported = FALSE; + continue; /* Check the next LDAP server */ + } + sasl_mech_supported = TRUE; + } + + krb5_clear_error_message(context); + + for (conns=0; conns < ldap_context->max_server_conns; ++conns) { + if ((st=krb5_ldap_initialize(ldap_context, server_info)) != 0) + break; + } /* for (conn= ... */ + + if (server_info->server_status == ON) + break; /* server init successful, so break */ + } + ++cnt; + } + HNDL_UNLOCK(ldap_context); + + err_out: + if (sasl_mech_supported == FALSE) { + st = KRB5_KDB_ACCESS_ERROR; + krb5_set_error_message (context, st, "Certificate based authentication requested but " + "not supported by LDAP servers"); + } + return (st); +} + + +/* + * get a single handle. Do not lock the mutex + */ + +krb5_error_code +krb5_ldap_db_single_init(krb5_ldap_context *ldap_context) +{ + krb5_error_code st=0; + int cnt=0; + krb5_ldap_server_info *server_info=NULL; + + while (ldap_context->server_info_list[cnt] != NULL) { + server_info = ldap_context->server_info_list[cnt]; + if ((server_info->server_status == NOTSET || server_info->server_status == ON)) { + if (server_info->num_conns < ldap_context->max_server_conns-1) { + st = krb5_ldap_initialize(ldap_context, server_info); + if (st == LDAP_SUCCESS) + goto cleanup; + } + } + ++cnt; + } + + /* If we are here, try to connect to all the servers */ + + cnt = 0; + while (ldap_context->server_info_list[cnt] != NULL) { + server_info = ldap_context->server_info_list[cnt]; + st = krb5_ldap_initialize(ldap_context, server_info); + if (st == LDAP_SUCCESS) + goto cleanup; + ++cnt; + } + cleanup: + return (st); +} + +krb5_error_code +krb5_ldap_rebind(ldap_context, ldap_server_handle) + krb5_ldap_context *ldap_context; + krb5_ldap_server_handle **ldap_server_handle; +{ + krb5_ldap_server_handle *handle = *ldap_server_handle; + int port=0; + + if (handle->server_info->port) + port = handle->server_info->port; + else if (ldap_context->port) + port = ldap_context->port; + else + port = LDAPS_PORT; + + if ((handle->ldap_handle=ldap_init(handle->server_info->server_name, port)) == NULL + || krb5_ldap_bind(ldap_context, handle) != LDAP_SUCCESS) + return krb5_ldap_request_next_handle_from_pool(ldap_context, ldap_server_handle); + return LDAP_SUCCESS; +} + +/* + * DAL API functions + */ +krb5_error_code krb5_ldap_lib_init() +{ + return 0; +} + +krb5_error_code krb5_ldap_lib_cleanup() +{ + /* right now, no cleanup required */ + return 0; +} + + + +krb5_error_code +krb5_ldap_close( krb5_context context) +{ + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + + if (context == NULL || + context->db_context == NULL || + ((kdb5_dal_handle *)context->db_context)->db_context == NULL) + return 0; + + dal_handle = (kdb5_dal_handle *) context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + dal_handle->db_context = NULL; + + if (ldap_context == NULL) + return 0; + + krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer); + ldap_context->krbcontainer = NULL; + + krb5_ldap_free_realm_params(ldap_context->lrparams); + ldap_context->lrparams = NULL; + + krb5_ldap_free_server_params(ldap_context); + + return 0; +} + + + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c new file mode 100644 index 000000000..1f0462967 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c @@ -0,0 +1,229 @@ +/* + * lib/kdb/kdb_ldap/kdb_xdr.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include <k5-int.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include "kdb_xdr.h" + +#define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n))) + +krb5_error_code +krb5_dbe_update_tl_data(context, entry, new_tl_data) + krb5_context context; + krb5_db_entry * entry; + krb5_tl_data * new_tl_data; +{ + krb5_tl_data * tl_data; + krb5_octet * tmp; + + /* copy the new data first, so we can fail cleanly if malloc() + fails */ + + if ((tmp = (krb5_octet *) malloc(new_tl_data->tl_data_length)) == NULL) + return(ENOMEM); + + /* Find an existing entry of the specified type and point at + it, or NULL if not found */ + + for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) + if (tl_data->tl_data_type == new_tl_data->tl_data_type) + break; + + /* if necessary, chain a new record in the beginning and point at it */ + + if (!tl_data) { + if ((tl_data = (krb5_tl_data *) calloc(1, sizeof(krb5_tl_data))) + == NULL) { + free(tmp); + return(ENOMEM); + } + tl_data->tl_data_next = entry->tl_data; + entry->tl_data = tl_data; + entry->n_tl_data++; + } + + /* fill in the record */ + + if (tl_data->tl_data_contents) + free(tl_data->tl_data_contents); + + tl_data->tl_data_type = new_tl_data->tl_data_type; + tl_data->tl_data_length = new_tl_data->tl_data_length; + tl_data->tl_data_contents = tmp; + memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length); + + return(0); +} + +krb5_error_code +krb5_dbe_lookup_tl_data(context, entry, ret_tl_data) + krb5_context context; + krb5_db_entry * entry; + krb5_tl_data * ret_tl_data; +{ + krb5_tl_data *tl_data; + + for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { + if (tl_data->tl_data_type == ret_tl_data->tl_data_type) { + *ret_tl_data = *tl_data; + return(0); + } + } + + /* if the requested record isn't found, return zero bytes. + if it ever means something to have a zero-length tl_data, + this code and its callers will have to be changed */ + + ret_tl_data->tl_data_length = 0; + ret_tl_data->tl_data_contents = NULL; + return(0); +} + +krb5_error_code +krb5_dbe_update_last_pwd_change(context, entry, stamp) + krb5_context context; + krb5_db_entry * entry; + krb5_timestamp stamp; +{ + krb5_tl_data tl_data; + krb5_octet buf[4]; /* this is the encoded size of an int32 */ + + tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; + tl_data.tl_data_length = sizeof(buf); + krb5_kdb_encode_int32((krb5_int32) stamp, buf); + tl_data.tl_data_contents = buf; + + return(krb5_dbe_update_tl_data(context, entry, &tl_data)); +} + +krb5_error_code +krb5_dbe_lookup_last_pwd_change(context, entry, stamp) + krb5_context context; + krb5_db_entry * entry; + krb5_timestamp * stamp; +{ + krb5_tl_data tl_data; + krb5_error_code code; + krb5_int32 tmp; + + tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; + + if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) + return(code); + + if (tl_data.tl_data_length != 4) { + *stamp = 0; + return(0); + } + + krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); + + *stamp = (krb5_timestamp) tmp; + + return(0); +} + +/* it seems odd that there's no function to remove a tl_data, but if + I need one, I'll add one */ + +krb5_error_code +krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ) + krb5_context context; + krb5_db_entry * entry; + krb5_timestamp mod_date; + krb5_const_principal mod_princ; +{ + krb5_tl_data tl_data; + + krb5_error_code retval = 0; + krb5_octet * nextloc = 0; + char * unparse_mod_princ = 0; + unsigned int unparse_mod_princ_size; + + if ((retval = krb5_unparse_name(context, mod_princ, + &unparse_mod_princ))) + return(retval); + + unparse_mod_princ_size = strlen(unparse_mod_princ) + 1; + + if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4)) + == NULL) { + free(unparse_mod_princ); + return(ENOMEM); + } + + tl_data.tl_data_type = KRB5_TL_MOD_PRINC; + tl_data.tl_data_length = unparse_mod_princ_size + 4; + tl_data.tl_data_contents = nextloc; + + /* Mod Date */ + krb5_kdb_encode_int32(mod_date, nextloc); + + /* Mod Princ */ + memcpy(nextloc+4, unparse_mod_princ, unparse_mod_princ_size); + + retval = krb5_dbe_update_tl_data(context, entry, &tl_data); + + free(unparse_mod_princ); + free(nextloc); + + return(retval); +} + +krb5_error_code +krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ) + krb5_context context; + krb5_db_entry * entry; + krb5_timestamp * mod_time; + krb5_principal * mod_princ; +{ + krb5_tl_data tl_data; + krb5_error_code code; + + tl_data.tl_data_type = KRB5_TL_MOD_PRINC; + + if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) + return(code); + + if ((tl_data.tl_data_length < 5) || + (tl_data.tl_data_contents[tl_data.tl_data_length-1] != '\0')) + return(KRB5_KDB_TRUNCATED_RECORD); + + /* Mod Date */ + krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time); + + /* Mod Princ */ + if ((code = krb5_parse_name(context, + (const char *) (tl_data.tl_data_contents+4), + mod_princ))) + return(code); + + return(0); +} + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.h b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.h new file mode 100644 index 000000000..bd01ead27 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.h @@ -0,0 +1,34 @@ +#ifndef _KDB2_XDR_H +#define _KDB2_XDR_H + +#include "kdb.h" + +krb5_error_code +krb5_encode_princ_dbkey( krb5_context context, + krb5_data *key, + krb5_const_principal principal); + +krb5_error_code +krb5_decode_princ_contents( krb5_context context, + krb5_data * content, + krb5_db_entry * entry); + +void +krb5_dbe_free_contents( krb5_context context, + krb5_db_entry * entry); + +krb5_error_code +krb5_encode_princ_contents( krb5_context context, + krb5_data * content, + krb5_db_entry * entry); + + +void +krb5_free_princ_dbkey( krb5_context context, + krb5_data *key); + +void +krb5_free_princ_contents( krb5_context context, + krb5_data *contents); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif b/src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif new file mode 100644 index 000000000..258eeaba8 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif @@ -0,0 +1,888 @@ +# Novell Kerberos Schema Definitions +# Novell Inc. +# 1800 South Novell Place +# Provo, UT 84606 +# +# VeRsIoN=1.3 +# CoPyRiGhT=(c) Copyright 2005, Novell, Inc. All rights reserved +# +# OIDs: +# joint-iso-ccitt(2) +# country(16) +# us(840) +# organization(1) +# Novell(113719) +# applications(1) +# kerberos(301) +# Kerberos Attribute Type(4) +# specific attribute definitions +# Kerberos Attribute Syntax(5) +# specific syntax definitions +# Kerberos Object Class(6) +# specific class definitions +# Kerberos LDAP Extensions (100) +# specific extensions + +######################################################################## +# Revision History # +######################################################################## +# +# 1.0 - 04/2004 +# +# - First version +# +# 1.1 - 01/2005 +# +# - Added 3 new attributes: +# krbContainerReference +# krbPrincNamingAttr +# krbAdmServers +# +# - Added 2 new classes: +# krbContainerRefAux +# krbAdmService +# +# - Removed 2 attributes: +# krbLogFile (2.16.840.1.113719.1.301.4.12) +# krbReplayCacheFile (2.16.840.1.113719.1.301.4.13) +# +# - Added 'organization', 'organizationalUnit', 'country', +# 'locality' and 'domain' to the containment list for +# "krbContainer". Earlier, it had only 'SASSecurity'. +# +# - Removed the optional attributes "krbLogFile" and +# "krbReplayCacheFile" from "krbService" class. +# +# - Added "krbAdmServers" and "krbPrincNamingAttr" as +# optional attributes to "krbRealmContainer" class. +# +# - Removed the flag "X-NDS_NOT_SCHED_SYNC_IMMEDIATE" for +# "krbPrincipalExpiration" +# +# - Removed the flags "X-NDS_NOT_SCHED_SYNC_IMMEDIATE" and +# "X-NDS_PUBLIC_READ" for "krbTicketFlags" +# +# - Removed the flag "X-NDS_PUBLIC_READ" for "krbServiceFlags" +# +# - Modified the comments for: +# krbPrincipalType +# krbSecretKey +# krbUPEnabled +# krbRealmReferences +# krbSubTree +# krbKdcServers +# krbPwdServers +# krbSupportedEncTypes +# krbSupportedSaltTypes +# krbMasterKey +# krbHostServer +# krbSearchScope +# krbService +# krbPolicyAux +# krbTicketFlags +# krbServiceFlags +# +# 1.2 - 04/2005 +# +# - Removed the flag "X-NDS_PUBLIC_READ" for: +# krbMaxTicketLife +# krbMaxRenewableAge +# krbRealmReferences +# krbLdapServers +# krbKdcServers +# krbPwdServers +# krbSupportedEncTypes +# krbSupportedSaltTypes +# krbDefaultEncType +# krbDefaultSaltType +# krbHostServer +# krbContainerReference +# krbAdmServers +# +# - Changed the syntax for "krbLdapServers" from +# 1.3.6.1.4.1.1466.115.121.1.12 (Distinguished Name) to +# 1.3.6.1.4.1.1466.115.121.1.15 (Case Ignore String) +# +# 1.3 - 04/2005 +# +# - Added 6 new attributes: +# krbMaxPwdLife +# krbMinPwdLife +# krbPwdMinDiffChars +# krbPwdMinLength +# krbPwdHistoryLength +# krbPwdPolicyRefCount +# krbPwdPolicyReference +# +# - Added 2 new classes: +# krbPwdPolicy +# krbPwdPolicyRefAux +######################################################################## + + +######################################################################## +# Attribute Type Definitions # +######################################################################## + +##### This is the principal name in the RFC 1510 specified format + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.1 + NAME 'krbPrincipalName' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### This is the foreign principal name in the RFC 1510 specified format + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.2 + NAME 'krbForeignPrincipalName' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### This specifies the type of the principal, the types could be any of +##### the following, (refer RFC 1510) +##### NT_UNKNOWN 0 +##### NT_PRINCIPAL 1 +##### NT_SRV_INST 2 +##### NT_SRV_HST 3 +##### NT_SRV_XHST 4 +##### NT_UID 5 +##### The following is a special principal type as explained, +##### This is used for X.500 principal names, coded as a Base-64 encoding of the +##### ASN.1 representation of the distinguished X.500 name. This Base-64 encoding +##### should be the first element of the principal name (that has only one element) +##### This constant corresponds to the NT-X500-PRINCIPAL principal type that is +##### specified in the latest PK INIT IETF draft. +##### X500_PRINCIPAL 6 + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.3 + NAME 'krbPrincipalType' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### This attribute holds the principal's secret key that is encrypted with +##### the master key. +##### The attribute holds data as follows, +##### First 2 bytes Length of principal name (princNameLength) +##### Next 2 bytes Current version of the principal key +##### Next 2 bytes Version of the master key used to encrypt this principal key +##### Next 4 bytes Time when password was last chaged +##### Next 2 bytes Number of keys for the principal (noOfKeys) +##### Next 2 bytes Key type of the first key +##### Next 2 bytes Length of the first key (keyLength[1]) +##### Next 2 bytes Salt type of the first key +##### Next 2 bytes Salt Length of the first key (saltLength[1]) +##### ... ... (other principals...) +##### Next 2 bytes Key type of the last key (There will be "noOfKeys" keys) +##### Next 2 bytes Length of the last key (keyLength[noOfKeys]) +##### Next 2 bytes Salt type of the last key (There will be "noOfKeys" keys) +##### Next 2 bytes Salt Length of the last key (saltLength[noOfKeys]) +##### Principal name (of princNameLength) +##### Principal's first key (of keyLength[1]) +##### Principal's first salt (of saltLength[1]) +##### ... ... (other principals...) +##### Principal's last key (of keyLength[noOfKeys]) +##### Principal's last salt (saltLength[noOfKeys]) +##### The byte encoding is in the big endian format. + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.4 + NAME 'krbSecretKey' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40) + + +##### This flag is used to find whether Universal Password is to be used +##### as kerberos password. +##### TRUE, if UP is to be used as the kerberos password. +##### FALSE, if UP and the kerberos password are different. + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.5 + NAME 'krbUPEnabled' + DESC 'Boolean' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### The time at which the principal expires + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.6 + NAME 'krbPrincipalExpiration' + EQUALITY generalizedTimeMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE) + + +##### FDN pointing to a Kerberos Policy object + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.7 + NAME 'krbPolicyReference' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### The krbTicketFlags attribute holds information about the kerberos flags for a principal +##### The flags as per RFC 1510 are, +##### DISALLOW_POSTDATED 0x00000001 +##### DISALLOW_FORWARDABLE 0x00000002 +##### DISALLOW_TGT_BASED 0x00000004 +##### DISALLOW_RENEWABLE 0x00000008 +##### DISALLOW_PROXIABLE 0x00000010 +##### DISALLOW_DUP_SKEY 0x00000020 +##### DISALLOW_ALL_TIX 0x00000040 +##### REQUIRES_PRE_AUTH 0x00000080 +##### REQUIRES_HW_AUTH 0x00000100 +##### REQUIRES_PWCHANGE 0x00000200 +##### DISALLOW_SVR 0x00001000 +##### PWCHANGE_SERVICE 0x00002000 + + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.8 + NAME 'krbTicketFlags' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE) + + +##### The maximum ticket lifetime for a principal in seconds + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.9 + NAME 'krbMaxTicketLife' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Maximum renewable lifetime for a principal's ticket in seconds + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.10 + NAME 'krbMaxRenewableAge' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### This is a set of flags that a Kerberos server requires to enable/disable +##### support of certain features. +##### The flags are as follows, +##### AUTO_RESTART (1 << 0) +##### CHECK_ADDRESSES (1 << 1) +##### SUPPORT_V4 (1 << 2) +##### USE_PRI_PORT (1 << 3) +##### USE_SEC_PORT (1 << 4) +##### USE_TCP (1 << 5) +##### UNIXTIME_OLD_PATYPE (1 << 6) + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.11 + NAME 'krbServiceFlags' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Forward reference to the Realm object. +##### (FDN of the krbRealmContainer object). +##### Example: cn=ACME.COM, cn=Kerberos, cn=Security + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.14 + NAME 'krbRealmReferences' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### List of LDAP servers that kerberos servers can contact. +##### The attribute holds data in the following format, +##### HostName-or-IPAddress#Port +##### Where, "#" is a delimiter. +##### Examples: acme.com#636, 164.164.164.164#1636 +##### +##### The values of this attribute need to be updated, when +##### the LDAP servers listed here are renamed, moved or deleted. + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.15 + NAME 'krbLdapServers' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Forward reference to an entry that starts a sub-tree +##### where principals and other kerberos objects in the realm are configured. +##### Example: ou=acme, ou=pq, o=xyz + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.16 + NAME 'krbSubTree' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### A set of forward references to the KDC Service objects. +##### (FDNs of the krbKdcService objects). +##### Example: cn=kdc - server 1, ou=uvw, o=xyz + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.17 + NAME 'krbKdcServers' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### A set of forward references to the Password Service objects. +##### (FDNs of the krbPwdService objects). +##### Example: cn=kpasswdd - server 1, ou=uvw, o=xyz + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.18 + NAME 'krbPwdServers' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### List of encryption types supported by the Realm. +##### The supported encryption types are, +##### DES_CBC_CRC 0x0001 +##### DES_CBC_MD4 0x0002 +##### DES_CBC_MD5 0x0003 +##### DES_CBC_RAW 0x0004 +##### DES3_CBC_SHA 0x0005 +##### DES3_CBC_RAW 0x0006 +##### DES_HMAC_SHA1 0x0008 +##### DES3_CBC_SHA1 0x0010 +##### AES128_CTS_HMAC_SHA1_96 0x0011 +##### AES256_CTS_HMAC_SHA1_96 0x0012 +##### ARCFOUR_HMAC 0x0017 +##### ARCFOUR_HMAC_EXP 0x0018 + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.19 + NAME 'krbSupportedEncTypes' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### List of salt types supported by the Realm. +##### The supported salt types are, +##### NORMAL 0 +##### V4 1 +##### NOREALM 2 +##### ONLYREALM 3 +##### SPECIAL 4 +##### AFS3 5 + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.20 + NAME 'krbSupportedSaltTypes' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Default encryption type supported by the Realm. + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.21 + NAME 'krbDefaultEncType' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Default salt type supported by the Realm. + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.22 + NAME 'krbDefaultSaltType' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### This attribute holds the kerberos master key. +##### The encryption type used for generating the key will be the strongest available with NICI. +##### This attribute will be encrypted with Tree Key and stored. +##### The attribute holds data as follows, +##### First 2 bytes holds the version of the master key, +##### Next 2 bytes holds the encryption type, +##### Next 4 bytes holds the key length, +##### Followed by the key. +##### The byte encoding is in the big endian format. + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.23 + NAME 'krbMasterKey' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40) + + +##### This attribute holds the Host Name or the ip address, +##### transport protocol and ports of the kerberos service host +##### The format is host_name-or-ip_address#protocol#port +##### Protocol can be 0 or 1. 0 is for UDP. 1 is for TCP. + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.24 + NAME 'krbHostServer' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### This attribute holds the scope for searching the principals +##### under krbSubTree attribute of krbRealmContainer +##### The value can either be 1 (ONE) or 2 (SUB_TREE). + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.25 + NAME 'krbSearchScope' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### FDNs pointing to Kerberos Service principals + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.26 + NAME 'krbPrincipalReferences' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) + + +##### FDN pointing to the Kerberos container in the tree +##### If this attribute is not present, then the default +##### value is cn=Kerberos,cn=Security + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.27 + NAME 'krbContainerReference' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### This attribute specifies which attribute of the user objects +##### be used as the principal name component for Kerberos. +##### The allowed values are cn, sn, uid, givenname, fullname. + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.28 + NAME 'krbPrincNamingAttr' + DESC 'String' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### A set of forward references to the Administration Service objects. +##### (FDNs of the krbAdmService objects). +##### Example: cn=kadmindd - server 1, ou=uvw, o=xyz + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.29 + NAME 'krbAdmServers' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Maximum lifetime of a principal's password + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.30 + NAME 'krbMaxPwdLife' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Minimum lifetime of a principal's password + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.31 + NAME 'krbMinPwdLife' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Minimum number of character clases allowed in a password + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.32 + NAME 'krbPwdMinDiffChars' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Minimum length of the password + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.33 + NAME 'krbPwdMinLength' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Number of previous versions of passwords that are stored + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.34 + NAME 'krbPwdHistoryLength' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### Number of principals that refer to this policy + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.35 + NAME 'krbPwdPolicyRefCount' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### FDN pointing to a Kerberos Password Policy object + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.36 + NAME 'krbPwdPolicyReference' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1') + + +##### The time at which the principal's password expires + +dn: cn=schema +changetype: modify +add: attributetypes +attributetypes: ( 2.16.840.1.113719.1.301.4.37 + NAME 'krbPasswordExpiration' + EQUALITY generalizedTimeMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE) + + +######################################################################## +# Object Class Definitions # +######################################################################## + +#### This is a kerberos container for all the realms in a tree. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.1 + NAME 'krbContainer' + SUP top + MUST ( cn ) + MAY ( krbPolicyReference) + X-NDS_NAMING ( 'cn' ) + X-NDS_CONTAINMENT ( 'SASSecurity' 'organization' 'organizationalUnit' 'country' 'locality' 'domain' )) + + +##### The krbRealmContainer is created per realm and holds realm specific data. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.2 + NAME 'krbRealmContainer' + SUP top + MUST ( cn ) + MAY ( krbMasterKey $ krbUPEnabled $ krbSubTree $ krbSearchScope $ krbLdapServers $ krbSupportedEncTypes $ krbSupportedSaltTypes $ krbDefaultEncType $ krbDefaultSaltType $ krbPolicyReference $ krbKdcServers $ krbPwdServers $ krbAdmServers $ krbPrincNamingAttr ) + X-NDS_NAMING ( 'cn' ) + X-NDS_CONTAINMENT ( 'krbContainer' )) + + +##### An instance of a class derived from krbService is created per +##### kerberos authentication or administration server in an realm and holds +##### references to the realm objects. These references is used to further read +##### realm specific data to service AS/TGS requests. Additionally this object +##### contains some server specific data like pathnames and ports that the +##### server uses. This is the identity the kerberos server logs in with. A key +##### pair for the same is created and the kerberos server logs in with the same. +##### +##### krbKdcService, krbAdmService and krbPwdService derive from this class. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.3 + NAME 'krbService' + ABSTRACT + SUP ( top $ Server $ ndsLoginProperties ) + MUST ( cn ) + MAY ( krbHostServer $ krbServiceFlags $ krbRealmReferences ) + X-NDS_NAMING 'cn' + X-NDS_CONTAINMENT ( 'organization' 'organizationalUnit' 'country' 'locality' 'domain' 'krbRealmContainer' ) + X-NDS_NOT_CONTAINER '1') + + +##### Representative object for the KDC server to log onto eDirectory +##### and have a connection Id to access Kerberos data and have the required ACL's + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.4 + NAME 'krbKdcService' + SUP ( krbService ) + X-NDS_NOT_CONTAINER '1') + + +##### Representative object for the Kerberos Password server to log into eDirectory +##### and have a connection Id to access Kerberos data and have the required ACL's + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.5 + NAME 'krbPwdService' + SUP ( krbService ) + X-NDS_NOT_CONTAINER '1') + + +##### The krbPolicyAux holds Kerberos ticket policy attributes. +##### This class can be attached to a principal object or realm object. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.6 + NAME 'krbPolicyAux' + AUXILIARY + MAY ( krbTicketFlags $ krbMaxTicketLife $ krbMaxRenewableAge )) + + +##### The krbPolicy object is an effective policy that is associated with a realm or a principal + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.7 + NAME 'krbPolicy' + SUP top + MUST ( cn ) + X-NDS_NAMING 'cn' + X-NDS_CONTAINMENT ( 'organization' 'organizationalUnit' 'domain' 'country' 'locality' ) + X-NDS_NOT_CONTAINER '1') + +###### The principal data auxiliary class. Holds principal information +###### and is used to store principal information for Users and any services. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.8 + NAME 'krbPrincipalAux' + AUXILIARY + MAY ( krbPrincipalName $ krbUPEnabled $ krbSecretKey $ krbPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration ) ) + + +###### This object is created to hold principals of type other than USER. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.9 + NAME 'krbPrincipal' + SUP ( top ) + MUST ( krbPrincipalName ) + MAY ( krbPrincipalType ) + X-NDS_NAMING 'krbPrincipalName' + X-NDS_CONTAINMENT ( 'organization' 'organizationalUnit' 'domain' 'krbRealmContainer' 'country' 'locality' ) + X-NDS_NOT_CONTAINER '1') + + +###### The foreign principal data auxiliary class. Holds all foreign principal information +###### and is used to store foreign principal information for Users. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.10 + NAME 'krbForeignPrincipalAux' + AUXILIARY + MAY krbForeignPrincipalName ) + +###### The principal references auxiliary class. Holds all principals referred +###### from a service + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.11 + NAME 'krbPrincRefAux' + AUXILIARY + MAY krbPrincipalReferences ) + + +###### Kerberos container references auxiliary class. Holds the location +###### of the Kerberos container object within an eDirectory tree. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.12 + NAME 'krbContainerRefAux' + AUXILIARY + MAY krbContainerReference ) + + +##### Representative object for the Kerberos Administration server to log into eDirectory +##### and have a connection Id to access Kerberos data and have the required ACL's + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.13 + NAME 'krbAdmService' + SUP ( krbService ) + X-NDS_NOT_CONTAINER '1') + + +##### The krbPwdPolicy object is a template password policy that +##### can be applied to principals when they are created. +##### These policy attributes will be in effect, when the Kerberos +##### passwords are different from users' passwords (UP). + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.14 + NAME 'krbPwdPolicy' + SUP top + MUST ( cn ) + X-NDS_NAMING 'cn' + X-NDS_CONTAINMENT ( 'organization' 'organizationalUnit' 'domain' 'country' 'locality' ) + MAY ( krbMaxPwdLife $ krbMinPwdLife $ krbPwdMinDiffChars $ krbPwdMinLength $ krbPwdHistoryLength $ krbPwdPolicyRefCount) + X-NDS_NOT_CONTAINER '1') + + +###### The password policy reference auxiliary class. +###### Holds the DN of the password policy object. This is to be attached to principals. + +dn: cn=schema +changetype: modify +add: objectclasses +objectClasses: ( 2.16.840.1.113719.1.301.6.15 + NAME 'krbPwdPolicyRefAux' + AUXILIARY + MAY ( krbPwdPolicyReference ) ) + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema b/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema new file mode 100644 index 000000000..4f3a0fb9d --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema @@ -0,0 +1,695 @@ +# Novell Kerberos Schema Definitions +# Novell Inc. +# 1800 South Novell Place +# Provo, UT 84606 +# +# VeRsIoN=1.3 +# CoPyRiGhT=(c) Copyright 2005, Novell, Inc. All rights reserved +# +# OIDs: +# joint-iso-ccitt(2) +# country(16) +# us(840) +# organization(1) +# Novell(113719) +# applications(1) +# kerberos(301) +# Kerberos Attribute Type(4) +# specific attribute definitions +# Kerberos Attribute Syntax(5) +# specific syntax definitions +# Kerberos Object Class(6) +# specific class definitions +# Kerberos LDAP Extensions (100) +# specific extensions + +######################################################################## +# Attribute Type Definitions # +######################################################################## + +##### This is the principal name in the RFC 1510 specified format + +attributetype ( + 2.16.840.1.113719.1.301.4.1 + NAME 'krbPrincipalName' + EQUALITY caseExactIA5Match + SUBSTR caseExactSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + ) + +##### This is the foreign principal name in the RFC 1510 specified format + +attributetype ( + 2.16.840.1.113719.1.301.4.2 + NAME 'krbForeignPrincipalName' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + ) + + +##### This specifies the type of the principal, the types could be any of +##### the following, (refer RFC 1510) +##### NT_UNKNOWN 0 +##### NT_PRINCIPAL 1 +##### NT_SRV_INST 2 +##### NT_SRV_HST 3 +##### NT_SRV_XHST 4 +##### NT_UID 5 +##### The following is a special principal type as explained, +##### This is used for X.500 principal names, coded as a Base-64 encoding of the +##### ASN.1 representation of the distinguished X.500 name. This Base-64 encoding +##### should be the first element of the principal name (that has only one element) +##### This constant corresponds to the NT-X500-PRINCIPAL principal type that is +##### specified in the latest PK INIT IETF draft. +##### X500_PRINCIPAL 6 + +attributetype ( + 2.16.840.1.113719.1.301.4.3 + NAME 'krbPrincipalType' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### This attribute holds the principal's secret key that is encrypted with +##### the master key. +##### The attribute holds data as follows, +##### First 2 bytes Length of principal name (princNameLength) +##### Next 2 bytes Current version of the principal key +##### Next 2 bytes Version of the master key used to encrypt this principal key +##### Next 4 bytes Time when password was last chaged +##### Next 2 bytes Number of keys for the principal (noOfKeys) +##### Next 2 bytes Key type of the first key +##### Next 2 bytes Length of the first key (keyLength[1]) +##### Next 2 bytes Salt type of the first key +##### Next 2 bytes Salt Length of the first key (saltLength[1]) +##### ... ... (other principals...) +##### Next 2 bytes Key type of the last key (There will be "noOfKeys" keys) +##### Next 2 bytes Length of the last key (keyLength[noOfKeys]) +##### Next 2 bytes Salt type of the last key (There will be "noOfKeys" keys) +##### Next 2 bytes Salt Length of the last key (saltLength[noOfKeys]) +##### Principal name (of princNameLength) +##### Principal's first key (of keyLength[1]) +##### Principal's first salt (of saltLength[1]) +##### ... ... (other principals...) +##### Principal's last key (of keyLength[noOfKeys]) +##### Principal's last salt (saltLength[noOfKeys]) +##### The byte encoding is in the big endian format. + +attributetype ( + 2.16.840.1.113719.1.301.4.4 + NAME 'krbSecretKey' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 + ) + + +##### This flag is used to find whether Universal Password is to be used +##### as kerberos password. +##### TRUE, if UP is to be used as the kerberos password. +##### FALSE, if UP and the kerberos password are different. + +attributetype ( + 2.16.840.1.113719.1.301.4.5 + NAME 'krbUPEnabled' + DESC 'Boolean' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + SINGLE-VALUE + ) + + +##### The time at which the principal expires + +attributetype ( + 2.16.840.1.113719.1.301.4.6 + NAME 'krbPrincipalExpiration' + EQUALITY generalizedTimeMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE + ) + + +##### FDN pointing to a Kerberos Policy object + +attributetype ( + 2.16.840.1.113719.1.301.4.7 + NAME 'krbPolicyReference' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + ) + +##### The time at which the principal's password expires +# should be moved to the end of the attributes' list + +attributetype ( + 2.16.840.1.113719.1.301.4.37 + NAME 'krbPasswordExpiration' + EQUALITY generalizedTimeMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 + SINGLE-VALUE + ) + +##### The krbTicketFlags attribute holds information about the kerberos flags for a principal +##### The flags as per RFC 1510 are, +##### DISALLOW_POSTDATED 0x00000001 +##### DISALLOW_FORWARDABLE 0x00000002 +##### DISALLOW_TGT_BASED 0x00000004 +##### DISALLOW_RENEWABLE 0x00000008 +##### DISALLOW_PROXIABLE 0x00000010 +##### DISALLOW_DUP_SKEY 0x00000020 +##### DISALLOW_ALL_TIX 0x00000040 +##### REQUIRES_PRE_AUTH 0x00000080 +##### REQUIRES_HW_AUTH 0x00000100 +##### REQUIRES_PWCHANGE 0x00000200 +##### DISALLOW_SVR 0x00001000 +##### PWCHANGE_SERVICE 0x00002000 + + +attributetype ( + 2.16.840.1.113719.1.301.4.8 + NAME 'krbTicketFlags' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### The maximum ticket lifetime for a principal in seconds + +attributetype ( + 2.16.840.1.113719.1.301.4.9 + NAME 'krbMaxTicketLife' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### Maximum renewable lifetime for a principal's ticket in seconds + +attributetype ( + 2.16.840.1.113719.1.301.4.10 + NAME 'krbMaxRenewableAge' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### This is a set of flags that a Kerberos server requires to enable/disable +##### support of certain features. +##### The flags are as follows, +##### AUTO_RESTART (1 << 0) +##### CHECK_ADDRESSES (1 << 1) +##### SUPPORT_V4 (1 << 2) +##### USE_PRI_PORT (1 << 3) +##### USE_SEC_PORT (1 << 4) +##### USE_TCP (1 << 5) +##### UNIXTIME_OLD_PATYPE (1 << 6) + +attributetype ( + 2.16.840.1.113719.1.301.4.11 + NAME 'krbServiceFlags' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### Forward reference to the Realm object. +##### (FDN of the krbRealmContainer object). +##### Example: cn=ACME.COM, cn=Kerberos, cn=Security + +attributetype ( + 2.16.840.1.113719.1.301.4.14 + NAME 'krbRealmReferences' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + ) + + +##### List of LDAP servers that kerberos servers can contact. +##### The attribute holds data in the following format, +##### HostName-or-IPAddress#Port +##### Where, "#" is a delimiter. +##### Examples: acme.com#636, 164.164.164.164#1636 +##### +##### The values of this attribute need to be updated, when +##### the LDAP servers listed here are renamed, moved or deleted. + +attributetype ( + 2.16.840.1.113719.1.301.4.15 + NAME 'krbLdapServers' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + ) + + +##### Forward reference to an entry that starts a sub-tree +##### where principals and other kerberos objects in the realm are configured. +##### Example: ou=acme, ou=pq, o=xyz + +attributetype ( + 2.16.840.1.113719.1.301.4.16 + NAME 'krbSubTree' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + ) + + +##### A set of forward references to the KDC Service objects. +##### (FDNs of the krbKdcService objects). +##### Example: cn=kdc - server 1, ou=uvw, o=xyz + +attributetype ( + 2.16.840.1.113719.1.301.4.17 + NAME 'krbKdcServers' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + ) + + +##### A set of forward references to the Password Service objects. +##### (FDNs of the krbPwdService objects). +##### Example: cn=kpasswdd - server 1, ou=uvw, o=xyz + +attributetype ( + 2.16.840.1.113719.1.301.4.18 + NAME 'krbPwdServers' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + ) + + +##### List of encryption types supported by the Realm. +##### The supported encryption types are, +##### DES_CBC_CRC 0x0001 +##### DES_CBC_MD4 0x0002 +##### DES_CBC_MD5 0x0003 +##### DES_CBC_RAW 0x0004 +##### DES3_CBC_SHA 0x0005 +##### DES3_CBC_RAW 0x0006 +##### DES_HMAC_SHA1 0x0008 +##### DES3_CBC_SHA1 0x0010 +##### AES128_CTS_HMAC_SHA1_96 0x0011 +##### AES256_CTS_HMAC_SHA1_96 0x0012 +##### ARCFOUR_HMAC 0x0017 +##### ARCFOUR_HMAC_EXP 0x0018 + +attributetype ( + 2.16.840.1.113719.1.301.4.19 + NAME 'krbSupportedEncTypes' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + ) + + +##### List of salt types supported by the Realm. +##### The supported salt types are, +##### NORMAL 0 +##### V4 1 +##### NOREALM 2 +##### ONLYREALM 3 +##### SPECIAL 4 +##### AFS3 5 + +attributetype ( + 2.16.840.1.113719.1.301.4.20 + NAME 'krbSupportedSaltTypes' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + ) + + +##### Default encryption type supported by the Realm. + +attributetype ( + 2.16.840.1.113719.1.301.4.21 + NAME 'krbDefaultEncType' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### Default salt type supported by the Realm. + +attributetype ( + 2.16.840.1.113719.1.301.4.22 + NAME 'krbDefaultSaltType' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### This attribute holds the kerberos master key. +##### The encryption type used for generating the key will be the strongest available with NICI. +##### This attribute will be encrypted with Tree Key and stored. +##### The attribute holds data as follows, +##### First 2 bytes holds the version of the master key, +##### Next 2 bytes holds the encryption type, +##### Next 4 bytes holds the key length, +##### Followed by the key. +##### The byte encoding is in the big endian format. + +attributetype ( + 2.16.840.1.113719.1.301.4.23 + NAME 'krbMasterKey' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 + ) + + +##### This attribute holds the Host Name or the ip address, +##### transport protocol and ports of the kerberos service host +##### The format is host_name-or-ip_address#protocol#port +##### Protocol can be 0 or 1. 0 is for UDP. 1 is for TCP. + +attributetype ( + 2.16.840.1.113719.1.301.4.24 + NAME 'krbHostServer' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + ) + + +##### This attribute holds the scope for searching the principals +##### under krbSubTree attribute of krbRealmContainer +##### The value can either be 1 (ONE) or 2 (SUB_TREE). + +attributetype ( + 2.16.840.1.113719.1.301.4.25 + NAME 'krbSearchScope' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### FDNs pointing to Kerberos Service principals + +attributetype ( + 2.16.840.1.113719.1.301.4.26 + NAME 'krbPrincipalReferences' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + ) + + +##### FDN pointing to the Kerberos container in the tree +##### If this attribute is not present, then the default +##### value is cn=Kerberos,cn=Security + +attributetype ( + 2.16.840.1.113719.1.301.4.27 + NAME 'krbContainerReference' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + ) + + +##### This attribute specifies which attribute of the user objects +##### be used as the principal name component for Kerberos. +##### The allowed values are cn, sn, uid, givenname, fullname. + +attributetype ( + 2.16.840.1.113719.1.301.4.28 + NAME 'krbPrincNamingAttr' + DESC 'String' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE + ) + + +##### A set of forward references to the Administration Service objects. +##### (FDNs of the krbAdmService objects). +##### Example: cn=kadmindd - server 1, ou=uvw, o=xyz + +attributetype ( + 2.16.840.1.113719.1.301.4.29 + NAME 'krbAdmServers' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + ) + + +##### Maximum lifetime of a principal's password + +attributetype ( + 2.16.840.1.113719.1.301.4.30 + NAME 'krbMaxPwdLife' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### Minimum lifetime of a principal's password + +attributetype ( + 2.16.840.1.113719.1.301.4.31 + NAME 'krbMinPwdLife' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### Minimum number of character clases allowed in a password + +attributetype ( + 2.16.840.1.113719.1.301.4.32 + NAME 'krbPwdMinDiffChars' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### Minimum length of the password + +attributetype ( + 2.16.840.1.113719.1.301.4.33 + NAME 'krbPwdMinLength' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### Number of previous versions of passwords that are stored + +attributetype ( + 2.16.840.1.113719.1.301.4.34 + NAME 'krbPwdHistoryLength' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### Number of principals that refer to this policy + +attributetype ( + 2.16.840.1.113719.1.301.4.35 + NAME 'krbPwdPolicyRefCount' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + + +##### FDN pointing to a Kerberos Password Policy object + +attributetype ( + 2.16.840.1.113719.1.301.4.36 + NAME 'krbPwdPolicyReference' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + ) + +##### Ticket Policy Reference Count + +attributetype ( 2.16.840.1.113719.1.301.4.38 + NAME 'krbPolicyRefCount' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE + ) + +######################################################################## +# Object Class Definitions # +######################################################################## + +#### This is a kerberos container for all the realms in a tree. + +objectClass ( + 2.16.840.1.113719.1.301.6.1 + NAME 'krbContainer' + SUP top + MUST ( cn ) + MAY ( krbPolicyReference) + ) + +##### The krbRealmContainer is created per realm and holds realm specific data. + +objectClass ( + 2.16.840.1.113719.1.301.6.2 + NAME 'krbRealmContainer' + SUP top + MUST ( cn ) + MAY ( krbMasterKey $ krbUPEnabled $ krbSubTree $ krbSearchScope $ krbLdapServers $ krbSupportedEncTypes $ krbSupportedSaltTypes $ krbDefaultEncType $ krbDefaultSaltType $ krbPolicyReference $ krbKdcServers $ krbPwdServers $ krbAdmServers $ krbPrincNamingAttr ) + ) + + +##### An instance of a class derived from krbService is created per +##### kerberos authentication or administration server in an realm and holds +##### references to the realm objects. These references is used to further read +##### realm specific data to service AS/TGS requests. Additionally this object +##### contains some server specific data like pathnames and ports that the +##### server uses. This is the identity the kerberos server logs in with. A key +##### pair for the same is created and the kerberos server logs in with the same. +##### +##### krbKdcService, krbAdmService and krbPwdService derive from this class. + +objectClass ( + 2.16.840.1.113719.1.301.6.3 + NAME 'krbService' + ABSTRACT + SUP ( top ) + MUST ( cn ) + MAY ( krbHostServer $ krbServiceFlags $ krbRealmReferences $ userPassword ) + ) + +##### Representative object for the KDC server to log onto eDirectory +##### and have a connection Id to access Kerberos data and have the required ACL's + +objectClass ( + 2.16.840.1.113719.1.301.6.4 + NAME 'krbKdcService' + SUP ( krbService ) + ) + + +##### Representative object for the Kerberos Password server to log into eDirectory +##### and have a connection Id to access Kerberos data and have the required ACL's + +objectClass ( + 2.16.840.1.113719.1.301.6.5 + NAME 'krbPwdService' + SUP ( krbService ) + ) + +##### The krbPolicyAux holds Kerberos ticket policy attributes. +##### This class can be attached to a principal object or realm object. + +objectClass ( + 2.16.840.1.113719.1.301.6.6 + NAME 'krbPolicyAux' + AUXILIARY + MAY ( krbTicketFlags $ krbMaxTicketLife $ krbMaxRenewableAge ) + ) + + +##### The krbPolicy object is an effective policy that is associated with a realm or a principal + +objectClass ( + 2.16.840.1.113719.1.301.6.7 + NAME 'krbPolicy' + SUP top + MUST ( cn ) + MAY ( krbPolicyRefCount ) + ) + +###### The principal data auxiliary class. Holds principal information +###### and is used to store principal information for Users and any services. + +objectClass ( + 2.16.840.1.113719.1.301.6.8 + NAME 'krbPrincipalAux' + AUXILIARY + MAY ( krbPrincipalName $ krbUPEnabled $ krbSecretKey $ krbPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration ) + ) + + +###### This object is created to hold principals of type other than USER. + +objectClass ( + 2.16.840.1.113719.1.301.6.9 + NAME 'krbPrincipal' + SUP ( top ) + MUST ( krbPrincipalName ) + MAY ( krbPrincipalType ) + ) + +###### The foreign principal data auxiliary class. Holds all foreign principal information +###### and is used to store foreign principal information for Users. + +objectClass ( + 2.16.840.1.113719.1.301.6.10 + NAME 'krbForeignPrincipalAux' + AUXILIARY + MAY krbForeignPrincipalName + ) + +###### The principal references auxiliary class. Holds all principals referred +###### from a service + +objectClass ( + 2.16.840.1.113719.1.301.6.11 + NAME 'krbPrincRefAux' + AUXILIARY + MAY krbPrincipalReferences + ) + + +###### Kerberos container references auxiliary class. Holds the location +###### of the Kerberos container object within an eDirectory tree. + +objectClass ( + 2.16.840.1.113719.1.301.6.12 + NAME 'krbContainerRefAux' + AUXILIARY + MAY krbContainerReference + ) + + +##### Representative object for the Kerberos Administration server to log into eDirectory +##### and have a connection Id to access Kerberos data and have the required ACL's + +objectClass ( + 2.16.840.1.113719.1.301.6.13 + NAME 'krbAdmService' + SUP ( krbService ) + ) + +##### The krbPwdPolicy object is a template password policy that +##### can be applied to principals when they are created. +##### These policy attributes will be in effect, when the Kerberos +##### passwords are different from users' passwords (UP). + +objectClass ( + 2.16.840.1.113719.1.301.6.14 + NAME 'krbPwdPolicy' + SUP top + MUST ( cn ) + MAY ( krbMaxPwdLife $ krbMinPwdLife $ krbPwdMinDiffChars $ krbPwdMinLength $ krbPwdHistoryLength $ krbPwdPolicyRefCount) + ) + +###### The password policy reference auxiliary class. +###### Holds the DN of the password policy object. This is to be attached to principals. + +objectClass ( + 2.16.840.1.113719.1.301.6.15 + NAME 'krbPwdPolicyRefAux' + AUXILIARY + MAY ( krbPwdPolicyReference ) + ) + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_err.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_err.c new file mode 100644 index 000000000..e10c5dbf0 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_err.c @@ -0,0 +1,168 @@ +#include <ldap.h> +#include <errno.h> +#include <kdb5_err.h> +#include "ldap_err.h" +#ifndef LDAP_X_ERROR +#define LDAP_X_ERROR(x) (0) +#endif + + +/* + * The possible KDB errors are + * 1. KRB5_KDB_UK_RERROR + * 2. KRB5_KDB_UK_SERROR + * 3. KRB5_KDB_NOENTRY + * 4. KRB5_KDB_TRUNCATED_RECORD + * 5. KRB5_KDB_UNAUTH + * 6. KRB5_KDB_DB_CORRUPT + * 7. KRB5_KDB_ACCESS_ERROR (NEW) + * 8. KRB5_KDB_INTERNAL_ERROR (NEW) + * 9. KRB5_KDB_SERVER_INTERNAL_ERR (NEW) + * 10. KRB5_KDB_CONSTRAINT_VIOLATION (NEW) + * + */ + +/* + * op : + * 0 => not specified + * OP_INIT => ldap_init + * OP_BIND => ldap_bind + * OP_UNBIND => ldap_unbind + * OP_ADD => ldap_add + * OP_MOD => ldap_modify + * OP_DEL => ldap_delete + * OP_SEARCH => ldap_search + * OP_CMP => ldap_compare + * OP_ABANDON => ldap_abandon + */ + +int translate_ldap_error(int err, int op){ + + switch (err) { + case LDAP_SUCCESS: + return 0; + + case LDAP_OPERATIONS_ERROR: + /* LDAP_OPERATIONS_ERROR: Indicates an internal error. The server is + * unable to respond with a more specific error and is also unable + * to properly respond to a request */ + case LDAP_UNAVAILABLE_CRITICAL_EXTENSION: + /* LDAP server was unable to satisfy a request because one or more + * critical extensions were not available */ + /* This might mean that the schema was not extended ... */ + case LDAP_UNDEFINED_TYPE: + /* The attribute specified in the modify or add operation does not + * exist in the LDAP server's schema. */ + return KRB5_KDB_INTERNAL_ERROR; + + + case LDAP_INAPPROPRIATE_MATCHING: + /* The matching rule specified in the search filter does not match a + * rule defined for the attribute's syntax */ + return KRB5_KDB_UK_RERROR; + + case LDAP_CONSTRAINT_VIOLATION: + /* The attribute value specified in a modify, add, or modify DN + * operation violates constraints placed on the attribute */ + case LDAP_TYPE_OR_VALUE_EXISTS: + /* The attribute value specified in a modify or add operation + * already exists as a value for that attribute */ + return KRB5_KDB_UK_SERROR; + + case LDAP_INVALID_SYNTAX: + /* The attribute value specified in an add, compare, or modify + * operation is an unrecognized or invalid syntax for the attribute */ + if (op == OP_ADD || op == OP_MOD) + return KRB5_KDB_UK_SERROR; + else /* OP_CMP */ + return KRB5_KDB_UK_RERROR; + + /* Ensure that the following don't occur in the DAL-LDAP code. + * Don't rely on the LDAP server to catch it */ + case LDAP_SASL_BIND_IN_PROGRESS: + /* This is not an error. So, this function should not be called */ + case LDAP_COMPARE_FALSE: + case LDAP_COMPARE_TRUE: + /* LDAP_COMPARE_FALSE and LDAP_COMPARE_TRUE are not errors. This + * function should not be invoked for them */ + case LDAP_RESULTS_TOO_LARGE: /* CLDAP */ + case LDAP_TIMELIMIT_EXCEEDED: + case LDAP_SIZELIMIT_EXCEEDED: + return KRB5_KDB_SERVER_INTERNAL_ERR; + + case LDAP_INVALID_DN_SYNTAX: + /* The syntax of the DN is incorrect */ + return EINVAL; + + case LDAP_PROTOCOL_ERROR: + /* LDAP_PROTOCOL_ERROR: Indicates that the server has received an + * invalid or malformed request from the client */ + case LDAP_CONFIDENTIALITY_REQUIRED: + + /* Bind problems ... */ + case LDAP_AUTH_METHOD_NOT_SUPPORTED: +// case LDAP_STRONG_AUTH_NOT_SUPPORTED: // Is this a bind error ? + case LDAP_INAPPROPRIATE_AUTH: + case LDAP_INVALID_CREDENTIALS: + case LDAP_UNAVAILABLE: + return KRB5_KDB_ACCESS_ERROR; + + case LDAP_STRONG_AUTH_REQUIRED: + if (op == OP_BIND) /* the LDAP server accepts only strong authentication. */ + return KRB5_KDB_ACCESS_ERROR; + else /* Client requested an operation such that requires strong authentication */ + return KRB5_KDB_CONSTRAINT_VIOLATION; + + case LDAP_REFERRAL: + return KRB5_KDB_NOENTRY; + + case LDAP_ADMINLIMIT_EXCEEDED: + /* An LDAP server limit set by an administrative authority has been + * exceeded */ + return KRB5_KDB_CONSTRAINT_VIOLATION; + case LDAP_UNWILLING_TO_PERFORM: + /* The LDAP server cannot process the request because of + * server-defined restrictions */ + return KRB5_KDB_CONSTRAINT_VIOLATION; + + + case LDAP_NO_SUCH_ATTRIBUTE: + /* Indicates that the attribute specified in the modify or compare + * operation does not exist in the entry */ + if (op == OP_MOD) + return KRB5_KDB_UK_SERROR; + else /* OP_CMP */ + return KRB5_KDB_TRUNCATED_RECORD; + + + case LDAP_ALIAS_DEREF_PROBLEM: + /* Either the client does not have access rights to read the aliased + * object's name or dereferencing is not allowed */ + case LDAP_PROXY_AUTHZ_FAILURE: // Is this correct ? + case LDAP_INSUFFICIENT_ACCESS: + /* Caller does not have sufficient rights to perform the requested + * operation */ + return KRB5_KDB_UNAUTH; + + case LDAP_LOOP_DETECT: + /* Client discovered an alias or referral loop */ + return KRB5_KDB_DB_CORRUPT; + + default: + + if (LDAP_NAME_ERROR (err)) + return KRB5_KDB_NOENTRY; + + if (LDAP_SECURITY_ERROR (err)) + return KRB5_KDB_UNAUTH; + + if (LDAP_SERVICE_ERROR (err) || LDAP_API_ERROR (err) || LDAP_X_ERROR (err)) + return KRB5_KDB_ACCESS_ERROR; + + if (LDAP_UPDATE_ERROR(err)) + return KRB5_KDB_UK_SERROR; + + /* LDAP_OTHER */ + return KRB5_KDB_SERVER_INTERNAL_ERR; + } +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_err.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_err.h new file mode 100644 index 000000000..f83e583dd --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_err.h @@ -0,0 +1,12 @@ +#define OP_INIT 1 +#define OP_BIND 2 +#define OP_UNBIND 3 +#define OP_ADD 4 +#define OP_MOD 5 +#define OP_DEL 6 +#define OP_SEARCH 7 +#define OP_CMP 8 +#define OP_ABANDON 9 + + +int translate_ldap_error(int err, int op); diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_fetch_mkey.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_fetch_mkey.c new file mode 100644 index 000000000..795358296 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_fetch_mkey.c @@ -0,0 +1,100 @@ +/* + * lib/kdb/kdb_ldap/ldap_fetch_mkey.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" +#include "kdb_ldap.h" + +/* + * get the master key from the database specific context + */ + +krb5_error_code +krb5_ldap_get_mkey (context, key) + krb5_context context; + krb5_keyblock **key; + +{ + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + dal_handle = (kdb5_dal_handle *) context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + + if ( ldap_context == NULL || ldap_context->lrparams == NULL) + return KRB5_KDB_DBNOTINITED; + + *key = &ldap_context->lrparams->mkey; + return 0; +} + + +/* + * set the master key into the database specific context + */ + +krb5_error_code +krb5_ldap_set_mkey (context, pwd, key) + krb5_context context; + char *pwd; + krb5_keyblock *key; +{ + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_realm_params *r_params = NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + dal_handle = (kdb5_dal_handle *) context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + + if ( ldap_context == NULL || ldap_context->lrparams == NULL) + return KRB5_KDB_DBNOTINITED; + + r_params = ldap_context->lrparams; + + if (r_params->mkey.contents) { + free (r_params->mkey.contents); + r_params->mkey.contents=NULL; + } + + r_params->mkey.magic = key->magic; + r_params->mkey.enctype = key->enctype; + r_params->mkey.length = key->length; + r_params->mkey.contents = malloc(key->length); + if (r_params->mkey.contents == NULL) + return ENOMEM; + + memcpy(r_params->mkey.contents, key->contents, key->length); + return 0; +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.c new file mode 100644 index 000000000..4cc945f4a --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.c @@ -0,0 +1,274 @@ +/* + * lib/kdb/kdb_ldap/ldap_handle.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" + + +#ifdef ASYNC_BIND + +/* + * Update the server info structure. In case of an asynchronous bind, + * this function is called to check the bind status. A flag + * server_info_upate_pending is refered before calling this function. + * This function sets the server_status to either ON or OFF and + * sets the server_info_udpate_pending to OFF. + * Do not lock the mutex here. The caller should lock it + */ + +static krb5_error_code +krb5_update_server_info(ldap_server_handle, server_info) + krb5_ldap_server_handle *ldap_server_handle; + krb5_ldap_server_info *server_info; +{ + krb5_error_code st=0; + struct timeval ztime={0, 0}; + LDAPMessage *result=NULL; + + if (ldap_server_handle == NULL || server_info == NULL) + return -1; + + while (st == 0) { + st = ldap_result(ldap_server_handle->ldap_handle, ldap_server_handle->msgid, + LDAP_MSG_ALL, &ztime, &result); + switch (st) { + case -1: + server_info->server_status = OFF; + time(&server_info->downtime); + break; + + case 0: + continue; + break; + + case LDAP_RES_BIND: + if ((st=ldap_result2error(ldap_server_handle->ldap_handle, result, 1)) == LDAP_SUCCESS) { + server_info->server_status = ON; + } else { +/* ?? */ krb5_set_error_message(0, 0, "%s", ldap_err2string(st)); + server_info->server_status = OFF; + time(&server_info->downtime); + } + ldap_msgfree(result); + break; + default: + ldap_msgfree(result); + continue; + break; + } + } + ldap_server_handle->server_info_update_pending = FALSE; + return 0; +} +#endif + +/* + * Return ldap server handle from the pool. If the pool is exhausted return NULL. + * Do not lock the mutex, caller should lock it + */ + +static krb5_ldap_server_handle * +krb5_get_ldap_handle(ldap_context) + krb5_ldap_context *ldap_context; +{ + krb5_ldap_server_handle *ldap_server_handle=NULL; + krb5_ldap_server_info *ldap_server_info=NULL; + int cnt=0; + + while (ldap_context->server_info_list[cnt] != NULL) { + ldap_server_info = ldap_context->server_info_list[cnt]; + if (ldap_server_info->server_status != OFF) { + if (ldap_server_info->ldap_server_handles != NULL) { + ldap_server_handle = ldap_server_info->ldap_server_handles; + ldap_server_info->ldap_server_handles = ldap_server_handle->next; + break; +#ifdef ASYNC_BIND + if (ldap_server_handle->server_info_update_pending == TRUE) { + krb5_update_server_info(context, ldap_server_handle, + ldap_server_info); + } + + if (ldap_server_info->server_status == ON) { + ldap_server_info->ldap_server_handles = ldap_server_handle->next; + break; + } else + ldap_server_handle = NULL; +#endif + } + } + ++cnt; + } + return ldap_server_handle; +} + +/* + * This is called incase krb5_get_ldap_handle returns NULL. + * Try getting a single connection (handle) and return the same by + * calling krb5_get_ldap_handle function. + * Do not lock the mutex here. The caller should lock it + */ + +static krb5_ldap_server_handle * +krb5_retry_get_ldap_handle(ldap_context, st) + krb5_ldap_context *ldap_context; + krb5_error_code *st; +{ + krb5_ldap_server_handle *ldap_server_handle=NULL; + + if ((*st=krb5_ldap_db_single_init(ldap_context)) != 0) + return NULL; + + ldap_server_handle = krb5_get_ldap_handle(ldap_context); + return ldap_server_handle; +} + +/* + * Put back the ldap server handle to the front of the list of handles of the + * ldap server info structure. + * Do not lock the mutex here. The caller should lock it. + */ + +static krb5_error_code +krb5_put_ldap_handle(ldap_server_handle) + krb5_ldap_server_handle *ldap_server_handle; +{ + + if (ldap_server_handle == NULL) + return 0; + + ldap_server_handle->next = ldap_server_handle->server_info->ldap_server_handles; + ldap_server_handle->server_info->ldap_server_handles = ldap_server_handle; + return 0; +} + +/* + * Add a new ldap server handle structure to the server info structure. + * This function name can be changed to krb5_insert_ldap_handle. + * Do not lock the mutex here. The caller should lock it + */ + +krb5_error_code +krb5_update_ldap_handle(ldap_server_handle, server_info) + krb5_ldap_server_handle *ldap_server_handle; + krb5_ldap_server_info *server_info; +{ + + if (ldap_server_handle == NULL || server_info == NULL) + return 0; + + ldap_server_handle->next = server_info->ldap_server_handles; + server_info->ldap_server_handles = ldap_server_handle; + server_info->num_conns++; + ldap_server_handle->server_info = server_info; + return 0; +} + +/* + * Free up all the ldap server handles of the server info. + * This function is called when the ldap server returns LDAP_SERVER_DOWN. + */ + +static krb5_error_code +krb5_ldap_cleanup_handles(ldap_server_info) + krb5_ldap_server_info *ldap_server_info; +{ + krb5_ldap_server_handle *ldap_server_handle = NULL; + + while (ldap_server_info->ldap_server_handles != NULL) { + ldap_server_handle = ldap_server_info->ldap_server_handles; + ldap_server_info->ldap_server_handles = ldap_server_handle->next; + /* ldap_unbind_s(ldap_server_handle); */ + free (ldap_server_handle); + ldap_server_handle = NULL; + } + return 0; +} + +/* + * wrapper function called from outside to get a handle. + */ + +krb5_error_code +krb5_ldap_request_handle_from_pool(ldap_context, ldap_server_handle) + krb5_ldap_context *ldap_context; + krb5_ldap_server_handle **ldap_server_handle; +{ + krb5_error_code st=0; + + *ldap_server_handle = NULL; + + HNDL_LOCK(ldap_context); + if (((*ldap_server_handle)=krb5_get_ldap_handle(ldap_context)) == NULL) + (*ldap_server_handle)=krb5_retry_get_ldap_handle(ldap_context, &st); + HNDL_UNLOCK(ldap_context); + return st; +} + +/* + * wrapper function wrapper called to get the next ldap server handle, when the current + * ldap server handle returns LDAP_SERVER_DOWN. + */ + +krb5_error_code +krb5_ldap_request_next_handle_from_pool(ldap_context, ldap_server_handle) + krb5_ldap_context *ldap_context; + krb5_ldap_server_handle **ldap_server_handle; +{ + krb5_error_code st=0; + + HNDL_LOCK(ldap_context); + (*ldap_server_handle)->server_info->server_status = OFF; + time(&(*ldap_server_handle)->server_info->downtime); + krb5_put_ldap_handle(*ldap_server_handle); + krb5_ldap_cleanup_handles((*ldap_server_handle)->server_info); + + if (((*ldap_server_handle)=krb5_get_ldap_handle(ldap_context)) == NULL) + (*ldap_server_handle)=krb5_retry_get_ldap_handle(ldap_context, &st); + HNDL_UNLOCK(ldap_context); + return st; +} + +/* + * wrapper function to call krb5_put_ldap_handle. + */ + +void +krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle) + krb5_ldap_context *ldap_context; + krb5_ldap_server_handle *ldap_server_handle; +{ + + if (ldap_server_handle != NULL) { + HNDL_LOCK(ldap_context); + krb5_put_ldap_handle(ldap_server_handle); + HNDL_UNLOCK(ldap_context); + } + return; +} + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.h new file mode 100644 index 000000000..a3b0885f4 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.h @@ -0,0 +1,46 @@ +/* + * lib/kdb/kdb_ldap/ldap_handle.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef _LDAP_HANDLE_H_ +#define _LDAP_HANDLE_H_ + +krb5_error_code +krb5_update_ldap_handle(krb5_ldap_server_handle *, krb5_ldap_server_info *); + +krb5_error_code +krb5_ldap_request_handle_from_pool(krb5_ldap_context *, krb5_ldap_server_handle **); + +krb5_error_code +krb5_ldap_request_next_handle_from_pool(krb5_ldap_context *, krb5_ldap_server_handle **); + +void +krb5_ldap_put_handle_to_pool(krb5_ldap_context *, krb5_ldap_server_handle *); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c new file mode 100644 index 000000000..35e81cd4e --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c @@ -0,0 +1,203 @@ +/* + * lib/kdb/kdb_ldap/ldap_krbcontainer.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" +#include "kdb_ldap.h" +#include "ldap_err.h" + +char *policyrefattribute[] = {"krbPolicyReference",NULL}; +char *krbcontainerrefattr[] = {"krbContainerReference", NULL}; + +/* + * Free the krb5_ldap_krbcontainer_params + */ + +void +krb5_ldap_free_krbcontainer_params(krb5_ldap_krbcontainer_params *cparams) +{ + if(cparams == NULL) + return; + + if (cparams->policyreference) + krb5_xfree(cparams->policyreference); + + if (cparams->parent) + krb5_xfree(cparams->parent); + + if (cparams->DN) + krb5_xfree(cparams->DN); + + krb5_xfree(cparams); + + return; +} + +/* + * Read the kerberos container. Kerberos container dn is read from the krb5.conf file. + * In case of eDirectory, if the dn is not present in the conf file, refer Security Container + * to fetch the dn information. + * + * Reading kerberos container includes reading the policyreference attribute and the policy + * object to read the attributes associated with it. + */ + +krb5_error_code +krb5_ldap_read_krbcontainer_params( krb5_context context, + krb5_ldap_krbcontainer_params **cparamp) + +{ + krb5_error_code st=0, tempst=0; + LDAP *ld=NULL; + LDAPMessage *result=NULL, *ent=NULL; + krb5_ldap_krbcontainer_params *cparams=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + cparams =(krb5_ldap_krbcontainer_params *) malloc(sizeof(krb5_ldap_krbcontainer_params)); + CHECK_NULL(cparams); + memset((char *) cparams, 0, sizeof(krb5_ldap_krbcontainer_params)); + + /* read kerberos containter location from [dbmodules] section of krb5.conf file */ + if (ldap_context->conf_section) { + if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, ldap_context->conf_section, + "ldap_kerberos_container_dn", NULL, + &cparams->DN)) != 0) { + krb5_set_error_message(context, st, "Error reading kerberos container location " + "from krb5.conf"); + goto cleanup; + } + } + + /* read kerberos containter location from [dbdefaults] section of krb5.conf file */ + if (cparams->DN == NULL) { + if ((st=profile_get_string(context->profile, KDB_MODULE_DEF_SECTION, + "ldap_kerberos_container_dn", NULL, + NULL, &cparams->DN)) != 0) { + krb5_set_error_message(context, st, "Error reading kerberos container location " + "from krb5.conf"); + goto cleanup; + } + } + +#ifndef HAVE_EDIRECTORY +/* + * In case eDirectory, we can fall back to security container if the kerberos container location + * is missing in the conf file. In openldap we will have to return an error. + */ + if (cparams->DN == NULL) { + st = KRB5_KDB_SERVER_INTERNAL_ERR; + krb5_set_error_message(context, st, "Kerberos container location not specified"); + goto cleanup; + } +#endif + + if (cparams->DN != NULL) { + /* NOTE: krbmaxtktlife, krbmaxrenewableage ... present on Kerberos Container is + * not read + */ + LDAP_SEARCH_1(cparams->DN, LDAP_SCOPE_BASE, "(objectclass=krbContainer)", policyrefattribute, IGNORE_STATUS); + if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_OBJECT) { + st = set_ldap_error(context, st, OP_SEARCH); + goto cleanup; + } + + if (st == LDAP_NO_SUCH_OBJECT) { + st = KRB5_KDB_NOENTRY; + goto cleanup; + } + } + +#ifdef HAVE_EDIRECTORY + /* + * If the kerberos location in the conf file is missing or invalid, fall back to the + * security container. If the kerberos location in the security container is also missing + * then fall back to the default value + */ + if ((cparams->DN == NULL) || (st == LDAP_NO_SUCH_OBJECT)) { + /* + * kerberos container can be anywhere. locate it by reading the security + * container to find the location. + */ + LDAP_SEARCH(SECURITY_CONTAINER, LDAP_SCOPE_BASE, NULL, krbcontainerrefattr); + if ((ent = ldap_first_entry(ld, result)) != NULL) { + if ((st=krb5_ldap_get_string(ld, ent, "krbcontainerreference", + &(cparams->DN), NULL)) != 0) + goto cleanup; + if (cparams->DN == NULL) { + cparams->DN = strdup(KERBEROS_CONTAINER); + CHECK_NULL(cparams->DN); + } + } + ldap_msgfree(result); + + /* NOTE: krbmaxtktlife, krbmaxrenewableage ... attributes present on + * Kerberos Container is not read + */ + LDAP_SEARCH(cparams->DN, LDAP_SCOPE_BASE, "(objectclass=krbContainer)", policyrefattribute); + } +#endif + + if ((ent = ldap_first_entry(ld, result))) { + if ((st=krb5_ldap_get_string(ld, ent, "krbpolicyreference", + &(cparams->policyreference), NULL)) != 0) + goto cleanup; + } + ldap_msgfree(result); + + if (cparams->policyreference != NULL) { + LDAP_SEARCH_1(cparams->policyreference, LDAP_SCOPE_BASE, NULL, policy_attributes, IGNORE_STATUS); + if (st != LDAP_SUCCESS && st!= LDAP_NO_SUCH_OBJECT) { + st = set_ldap_error(context, st, OP_SEARCH); + goto cleanup; + } + st = LDAP_SUCCESS; /* reset the return status in case it is LDAP_NO_SUCH_OBJECT */ + + ent=ldap_first_entry(ld, result); + if (ent != NULL) { + krb5_ldap_get_value(ld, ent, "krbmaxtktlife", &(cparams->max_life)); + krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", &(cparams->max_renewable_life)); + krb5_ldap_get_value(ld, ent, "krbticketflags", &(cparams->tktflags)); + } + ldap_msgfree(result); + } + *cparamp=cparams; + + cleanup: + if(st != 0) { + krb5_ldap_free_krbcontainer_params(cparams); + *cparamp=NULL; + } + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.h new file mode 100644 index 000000000..4d1b4e4e5 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.h @@ -0,0 +1,54 @@ +/* + * lib/kdb/kdb_ldap/ldap_krbcontainer.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef _LDAP_KRBCONTAINER_H_ +#define _LDAP_KRBCONTAINER_H_ 1 + +/* kerberos container structure */ + +typedef struct _krb5_ldap_krbcontainer_params { + char *parent; + char *DN; + char *policyreference; + krb5_int32 max_life; + krb5_int32 max_renewable_life; + krb5_int32 tktflags; +} krb5_ldap_krbcontainer_params; + +void +krb5_ldap_free_krbcontainer_params(krb5_ldap_krbcontainer_params *); + +krb5_error_code +krb5_ldap_read_krbcontainer_params(krb5_context , krb5_ldap_krbcontainer_params **); + +krb5_error_code +krb5_ldap_create_krbcontainer(krb5_context, const krb5_ldap_krbcontainer_params *); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_main.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_main.h new file mode 100644 index 000000000..95a837929 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_main.h @@ -0,0 +1,38 @@ +/* + * lib/kdb/kdb_ldap/ldap_main.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef LDAP_MAIN_H +#define LDAP_MAIN_H 1 + +#include "kdb_ldap.h" +#include "ldap_misc.h" +#include "ldap_handle.h" + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c new file mode 100644 index 000000000..153a3c63e --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c @@ -0,0 +1,1471 @@ +/* + * lib/kdb/kdb_ldap/ldap_misc.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 <string.h> +#include <time.h> +#include "kdb_ldap.h" +#include "ldap_misc.h" +#include "ldap_err.h" + +/* + * This function reads the parameters from the krb5.conf file. The parameters read here are + * DAL-LDAP specific attributes. Some of these are ldap_port, ldap_server .... + * + */ +krb5_error_code +krb5_ldap_read_server_params(context, conf_section, srv_type) + krb5_context context; + char *conf_section; + int srv_type; +{ + char *tempval=NULL, *save_ptr=NULL; + const char *delims="\t\n\f\v\r ,"; + krb5_error_code st=0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_info ***server_info=NULL; + + dal_handle = (kdb5_dal_handle *) context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + + /* copy the conf_section into ldap_context for later use */ + if (conf_section) { + ldap_context->conf_section = strdup (conf_section); + if (ldap_context->conf_section == NULL) { + st = ENOMEM; + goto cleanup; + } + } + + /* initialize the mutexs and condition variable */ + /* this portion logically doesn't fit here should be moved appropriately */ + + /* this mutex is used in ldap reconnection pool */ + if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0) { + st = KRB5_KDB_SERVER_INTERNAL_ERR; +// st = -1; +// krb5_ldap_dal_err_funcp(context, krb5_err_have_str, st, +// "k5_mutex_init failed"); + goto cleanup; + } + + /* if max_server_conns is not set read it from database module section of conf file + * this parameter defines maximum ldap connections per ldap server + */ + if (ldap_context->max_server_conns == 0) { + if ((st=profile_get_integer(context->profile, KDB_MODULE_SECTION, conf_section, + "ldap_conns_per_server", 0, + (int *) &ldap_context->max_server_conns)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_conns_per_server' " + "attribute"); + goto cleanup; + } + } + + /* if ldap port is not set read it from database module section of conf file */ + if (ldap_context->port == 0) { + if ((st=profile_get_integer(context->profile, KDB_MODULE_SECTION, conf_section, + "ldap_ssl_port", 0, + (int *) &ldap_context->port)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_ssl_port' attribute"); + goto cleanup; + } + } + + /* if the bind dn is not set read it from the database module section of conf file + * this paramter is populated by one of the KDC, ADMIN or PASSWD dn to be used to connect + * to LDAP server. the srv_type decides which dn to read. + */ + if( ldap_context->bind_dn == NULL ) { + + if (srv_type == KRB5_KDB_SRV_TYPE_KDC) { + if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, + "ldap_kdc_dn", NULL, &ldap_context->bind_dn)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_kdc_dn' attribute"); + goto cleanup; + } + } + else if (srv_type == KRB5_KDB_SRV_TYPE_ADMIN) { + if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, + "ldap_kadmind_dn", NULL, &ldap_context->bind_dn)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_kadmind_dn' attribute"); + goto cleanup; + } + } + else if (srv_type == KRB5_KDB_SRV_TYPE_PASSWD) { + if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, + "ldap_kpasswdd_dn", NULL, &ldap_context->bind_dn)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_kpasswdd_dn' attribute"); + goto cleanup; + } + } + } + + /* read service_password_file parameter from database module section of conf file + * this file contains stashed passwords of the KDC, ADMIN and PASSWD dns. + */ + if (ldap_context->service_password_file == NULL) { + if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, + "ldap_service_password_file", NULL, + &ldap_context->service_password_file)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_service_password_file' attribute"); + goto cleanup; + } + } + + /* if root certificate file is not set read it from database module section of conf file + * this is the trusted root certificate of the Directory. + */ + if (ldap_context->root_certificate_file == NULL) { + if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, + "ldap_root_certificate_file", NULL, + &ldap_context->root_certificate_file)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_root_certificate_file' attribute"); + goto cleanup; + } + } + + /* if the ldap server parameter is not set read the list of ldap servers:port from the + * database module section of the conf file + */ + + if (ldap_context->server_info_list == NULL) { + unsigned int ele=0; + + server_info = &(ldap_context->server_info_list); + *server_info = (krb5_ldap_server_info **) calloc (SERV_COUNT+1, + sizeof (krb5_ldap_server_info *)); + + if (*server_info == NULL) { + st = ENOMEM; + goto cleanup; + } + + if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, + "ldap_servers", NULL, &tempval)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_servers' attribute"); + goto cleanup; + } + + if (tempval == NULL) { + + (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1, + sizeof(krb5_ldap_server_info)); + + (*server_info)[ele]->server_name = strdup("localhost"); + if ((*server_info)[ele]->server_name == NULL) { + st = ENOMEM; + goto cleanup; + } + (*server_info)[ele]->server_status = NOTSET; + } else { + char *port=NULL, *server=NULL, *item=NULL; + + item = strtok_r(tempval,delims,&save_ptr); + while(item != NULL && ele<SERV_COUNT){ + (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1, + sizeof(krb5_ldap_server_info)); + if ((*server_info)[ele] == NULL) { + st = ENOMEM; + goto cleanup; + } + server=strtok_r(item, ":", &port); + + (*server_info)[ele]->server_name = strdup(server); + if ((*server_info)[ele]->server_name == NULL) { + st = ENOMEM; + goto cleanup; + } + + if (port) { + (*server_info)[ele]->port = atoi(port); + } + (*server_info)[ele]->server_status = NOTSET; + item = strtok_r(NULL,delims,&save_ptr); + ++ele; + } + profile_release_string(tempval); + } + } + + /* the same set of all the above parameters can be obtained from the dbdefaults section of + * conf file. Here read the missing parameters from [dbdefaults] section */ + + if (ldap_context->max_server_conns == 0) { + if ((st=profile_get_integer(context->profile, KDB_MODULE_DEF_SECTION, + "ldap_conns_per_server", NULL, DEFAULT_CONNS_PER_SERVER, + (int *) &ldap_context->max_server_conns)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_conns_per_server' attribute"); + goto cleanup; + } + } + + if (ldap_context->max_server_conns < 2) { + st = EINVAL; + krb5_set_error_message (context, st, "Minimum connections required per server is 2"); + goto cleanup; + } + + if (ldap_context->port == 0) { + if ((st=profile_get_integer(context->profile, KDB_MODULE_DEF_SECTION, "ldap_ssl_port", + NULL, LDAPS_PORT, &ldap_context->port)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_ssl_port' attribute"); + goto cleanup; + } + } + + if( ldap_context->bind_dn == NULL ) { + if (srv_type == KRB5_KDB_SRV_TYPE_KDC) { + if ((st=profile_get_string(context->profile, KDB_MODULE_DEF_SECTION, "ldap_kdc_dn", + NULL, NULL, &ldap_context->bind_dn)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_kdc_dn' attribute"); + goto cleanup; + } + } + else if (srv_type == KRB5_KDB_SRV_TYPE_ADMIN) { + if ((st=profile_get_string(context->profile, KDB_MODULE_DEF_SECTION, + "ldap_kadmind_dn", NULL, NULL, + &ldap_context->bind_dn)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_kadmind_dn' attribute"); + goto cleanup; + } + } + else if (srv_type == KRB5_KDB_SRV_TYPE_PASSWD) { + if ((st=profile_get_string(context->profile, KDB_MODULE_DEF_SECTION, + "ldap_kpasswdd_dn", NULL, NULL, + &ldap_context->bind_dn)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_kpasswdd_dn' attribute"); + goto cleanup; + } + } + } + + /* read service_password_file value */ + if (ldap_context->service_password_file == NULL) { + if ((st=profile_get_string(context->profile, KDB_MODULE_DEF_SECTION, + "ldap_service_password_file", NULL, NULL, + &ldap_context->service_password_file)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_service_passwd_file' attribute"); + goto cleanup; + } + } + + /* read root certificate file value */ + if (ldap_context->root_certificate_file == NULL) { + if ((st=profile_get_string(context->profile, KDB_MODULE_DEF_SECTION, + "ldap_root_certificate_file", NULL, NULL, + &ldap_context->root_certificate_file)) != 0) { + krb5_set_error_message (context, st, "Error reading 'ldap_root_certificate_file' attribute"); + goto cleanup; + } + } + + cleanup: + return(st); +} + +/* + * This function frees the krb5_ldap_context structure members. + */ + +krb5_error_code +krb5_ldap_free_server_params(ldap_context) + krb5_ldap_context *ldap_context; +{ + int i=0; + krb5_ldap_server_handle *ldap_server_handle=NULL, *next_ldap_server_handle=NULL; + + if (ldap_context == NULL) + return 0; + + /* free all ldap servers list and the ldap handles associated with the ldap server */ + if(ldap_context->server_info_list) { + while (ldap_context->server_info_list[i]) { + if (ldap_context->server_info_list[i]->server_name) { + free (ldap_context->server_info_list[i]->server_name); + } + if (ldap_context->server_info_list[i]->root_certificate_file) { + free (ldap_context->server_info_list[i]->root_certificate_file); + } + if (ldap_context->server_info_list[i]->ldap_server_handles) { + ldap_server_handle = ldap_context->server_info_list[i]->ldap_server_handles; + while (ldap_server_handle) { + ldap_unbind_s(ldap_server_handle->ldap_handle); + ldap_server_handle->ldap_handle = NULL; + next_ldap_server_handle = ldap_server_handle->next; + krb5_xfree(ldap_server_handle); + ldap_server_handle = next_ldap_server_handle; + } + } + krb5_xfree(ldap_context->server_info_list[i]); + i++; + } + krb5_xfree(ldap_context->server_info_list); + } + + if (ldap_context->conf_section != NULL) { + krb5_xfree(ldap_context->conf_section); + ldap_context->conf_section = NULL; + } + + if (ldap_context->bind_dn != NULL) { + krb5_xfree(ldap_context->bind_dn); + ldap_context->bind_dn = NULL; + } + + if (ldap_context->bind_pwd != NULL) { + krb5_xfree(ldap_context->bind_pwd); + ldap_context->bind_pwd = NULL; + } + + if (ldap_context->service_password_file != NULL) { + krb5_xfree(ldap_context->service_password_file); + ldap_context->service_password_file = NULL; + } + + if (ldap_context->root_certificate_file != NULL) { + krb5_xfree(ldap_context->root_certificate_file); + ldap_context->root_certificate_file = NULL; + } + + if (ldap_context->service_cert_path != NULL) { + krb5_xfree(ldap_context->service_cert_path); + ldap_context->service_cert_path = NULL; + } + + if (ldap_context->service_cert_pass != NULL) { + krb5_xfree(ldap_context->service_cert_pass); + ldap_context->service_cert_pass = NULL; + } + + if (ldap_context->certificates) { + i=0; + while (ldap_context->certificates[i] != NULL) { + krb5_xfree(ldap_context->certificates[i]->certificate); + krb5_xfree(ldap_context->certificates[i]); + ++i; + } + krb5_xfree(ldap_context->certificates); + } + + k5_mutex_destroy(&ldap_context->hndl_lock); + + krb5_xfree(ldap_context); + return(0); +} + + +/* + * check to see if the principal belongs to the default realm. + * The default realm is present in the krb5_ldap_context structure. + * The principal has a realm portion. This realm portion is compared with the default realm + * to check whether the principal belong to the default realm. + * Return 0 if principal belongs to default realm else 1. + */ + +krb5_error_code +is_principal_in_realm(ldap_context, searchfor) + krb5_ldap_context *ldap_context; + krb5_const_principal searchfor; +{ + int defrealmlen=0; + char *defrealm=NULL; + +#define FIND_MAX(a,b) ((a) > (b) ? (a) : (b)) + + defrealmlen = strlen(ldap_context->lrparams->realm_name); + defrealm = ldap_context->lrparams->realm_name; + + /* care should be taken for inter-realm principals as the default realm can exist in the + * realm part of the principal name or can also exist in the second portion of the name part. + * However, if the default realm exist in the second part of the principal portion, then the + * first portion of the principal name SHOULD be "krbtgt". All this check is done in the + * immediate block. + */ + if (searchfor->length == 2) + if ((strncasecmp(searchfor->data[0].data, "krbtgt", + FIND_MAX(searchfor->data[0].length, strlen("krbtgt"))) == 0) && + (strncasecmp(searchfor->data[1].data, defrealm, + FIND_MAX(searchfor->data[1].length, defrealmlen)) == 0)) + return 0; + + /* first check the length, if they are not equal, then they are not same */ + if (strlen(defrealm) != searchfor->realm.length) + return 1; + + /* if the length is equal, check for the contents */ + if (strncmp(defrealm, searchfor->realm.data, + searchfor->realm.length) != 0) + return 1; + /* if we are here, then the realm portions match, return 0 */ + return 0; +} + + +/* + * Deduce the subtree information from the context. A realm can have atmost 2 subtrees. + * 1. the Realm container + * 2. the actual subtree associated with the Realm + * + * However, there are some conditions to be considered to deduce the actual subtree/s associated + * with the realm. The conditions are as follows + * 1. If the subtree information of the Realm is [Root] or NULL (that is internal a [Root]) then + * the realm has only one subtree i.e [Root], i.e. whole of the tree. + * 2. If the subtree information of the Realm is missing/absent, then the realm has only one + * i.e. the Realm container. NOTE: In call cases Realm container SHOULD be the one among the + * subtrees or the only one subtree. + * 3. The subtree information of the realm is overlapping the realm container of the realm, then + * the realm has only one subtree and it is the subtree information associated with the realm. + */ +krb5_error_code +krb5_get_subtree_info(ldap_context, subtreearr, ntree) + krb5_ldap_context *ldap_context; + char **subtreearr; + unsigned int *ntree; +{ + int lendiff=0; + char *subtree=NULL, *realm_cont_dn=NULL; + + subtree = ldap_context->lrparams->subtree; + realm_cont_dn = ldap_context->lrparams->realmdn; + + /* + * if subtree attribute value is [Root] of the tree which is represented by a "" + * (null) string, set the ntree value as 1 and do not fill the subtreearr value. + * In eDirectory the [Root] can be represented as a "" (null) string, however this + * representation throws a "No such object" error in OpenLDAP. + * Representing [Root] of the tree as NULL pointer (i.e. no value) works in both case. + */ + if (subtree == NULL || strcasecmp(subtree, "") == 0) { + *ntree = 1; + return 0; + } + + /* + * the subtree attribute value of the realm can be same as the realm container or can + * even overlap. If the check is successful, then the subtree attribute value alone is + * copied to the subtreearr array and the ntree value is set to 1. + */ + lendiff = strlen(realm_cont_dn) - strlen(subtree); + if (lendiff >= 0 && (strcasecmp(realm_cont_dn+lendiff, subtree)==0)) { + subtreearr[0] = strdup(subtree); + if (subtreearr[0] == NULL) + return ENOMEM; + *ntree = 1; + return 0; + } + + /* + * if the subtree attribute value of the realm and the realm container are different, + * then both of the values are copied to subtreearr and ntree value is set to 2. + */ + subtreearr[0] = strdup(realm_cont_dn); + if (subtreearr[0] == NULL) + return ENOMEM; + subtreearr[1] = strdup(subtree); + if (subtreearr[1] == NULL) { + if (subtreearr[0]) + free (subtreearr[0]); + return ENOMEM; + } + *ntree = 2; + return 0; +} + +/* + * This function appends the content with a type into the tl_data structure. Based on the type + * the length of the content is either pre-defined or computed from the content. + * Returns 0 in case of success and 1 if the type associated with the content is undefined. + */ + +krb5_error_code +store_tl_data(tl_data, tl_type, value) + krb5_tl_data *tl_data; + int tl_type; + void *value; +{ + unsigned int currlen=0, tldatalen=0; + char *curr=NULL; + void *reallocptr=NULL; + + tl_data->tl_data_type = KDB_TL_USER_INFO; + switch(tl_type) + { + case KDB_TL_PRINCCOUNT: + case KDB_TL_PRINCTYPE: + case KDB_TL_MASK: + { + int *iptr = (int *)value; + int ivalue = *iptr; + + currlen = tl_data->tl_data_length; + tl_data->tl_data_length += 1 + 2 + 2; + /* allocate required memory */ + reallocptr = tl_data->tl_data_contents; + tl_data->tl_data_contents = realloc(tl_data->tl_data_contents, + tl_data->tl_data_length); + if (tl_data->tl_data_contents == NULL) { + if (reallocptr) + free (reallocptr); + return ENOMEM; + } + curr = (char *) (tl_data->tl_data_contents + currlen); + + /* store the tl_type value */ + memset(curr, tl_type, 1); + curr += 1; + /* store the content length */ + tldatalen = 2; + STORE16_INT(curr, tldatalen); + curr += 2; + /* store the content */ + STORE16_INT(curr, ivalue); + curr += 2; + break; + } + + case KDB_TL_USERDN: + case KDB_TL_TKTPOLICYDN: + { + char *cptr = (char *)value; + + currlen = tl_data->tl_data_length; + tl_data->tl_data_length += 1 + 2 + strlen(cptr); + /* allocate required memory */ + reallocptr = tl_data->tl_data_contents; + tl_data->tl_data_contents = realloc(tl_data->tl_data_contents, + tl_data->tl_data_length); + if (tl_data->tl_data_contents == NULL) { + if (reallocptr) + free (reallocptr); + return ENOMEM; + } + curr = (char *) (tl_data->tl_data_contents + currlen); + + /* store the tl_type value */ + memset(curr, tl_type, 1); + curr += 1; + /* store the content length */ + tldatalen = strlen(cptr); + STORE16_INT(curr, tldatalen); + curr += 2; + /* store the content */ + memcpy(curr, cptr, tldatalen); + curr += tldatalen; + break; + } + + case KDB_TL_KEYINFO: + { + struct berval *key = (struct berval *)value; + + currlen = tl_data->tl_data_length; + tl_data->tl_data_length += 1 + 2 + key->bv_len; + /* allocate required memory */ + reallocptr = tl_data->tl_data_contents; + tl_data->tl_data_contents = realloc(tl_data->tl_data_contents, + tl_data->tl_data_length); + if (tl_data->tl_data_contents == NULL) { + if (reallocptr) + free (reallocptr); + return ENOMEM; + } + curr = (char *) (tl_data->tl_data_contents + currlen); + + /* store the tl_type value */ + memset(curr, tl_type, 1); + curr += 1; + /* store the content length */ + tldatalen = key->bv_len; + STORE16_INT(curr, tldatalen); + curr += 2; + /* store the content */ + memcpy(curr, key->bv_val, key->bv_len); + curr += tldatalen; + break; + } + + default: + return 1; + + } + return 0; +} + +/* + * This function scans the tl_data structure to get the value of a type defined by the tl_type + * (second parameter). The tl_data structure has all the data in the tl_data_contents member. + * The format of the tl_data_contents is as follows. + * The first byte defines the type of the content that follows. The next 2 bytes define the + * size n (in terms of bytes) of the content that follows. The next n bytes define the content + * itself. + */ + +krb5_error_code +decode_tl_data(tl_data, tl_type, data) + krb5_tl_data *tl_data; + int tl_type; + void **data; +{ + int subtype=0, i=0, limit=10; + unsigned int sublen=0; + unsigned char *curr=NULL; + int *intptr=NULL; + long *longptr=NULL; + char *DN=NULL; + krb5_boolean keyfound=FALSE; + KEY *secretkey = NULL; + + *data = NULL; + + curr = tl_data->tl_data_contents; + while(curr < (tl_data->tl_data_contents + tl_data->tl_data_length)) { + + /* get the type of the content */ + subtype = (int) curr[0]; + /* forward by 1 byte*/ + curr += 1; + + if (subtype == tl_type) { + switch(subtype) { + + case KDB_TL_PRINCCOUNT: + case KDB_TL_PRINCTYPE: + case KDB_TL_MASK: + /* get the length of the content */ + UNSTORE16_INT(curr, sublen); + /* forward by 2 bytes */ + curr += 2; + /* get the actual content */ + if (sublen == 2) { + /* intptr = malloc(sublen); */ + intptr = malloc(sizeof(krb5_int32)); + if (intptr == NULL) + return ENOMEM; + memset(intptr, 0, sublen); + UNSTORE16_INT(curr, (*intptr)); + *data = intptr; + } else { + longptr = malloc(sublen); + if (longptr == NULL) + return ENOMEM; + memset(longptr, 0, sublen); + UNSTORE32_INT(curr, (*longptr)); + *data = longptr; + } + curr += sublen; + return 0; + break; + + case KDB_TL_CONTAINERDN: + case KDB_TL_USERDN: + case KDB_TL_TKTPOLICYDN: + /* get the length of the content */ + UNSTORE16_INT(curr, sublen); + /* forward by 2 bytes */ + curr += 2; + DN = malloc (sublen + 1); + if (DN == NULL) + return ENOMEM; + memcpy(DN, curr, sublen); + DN[sublen] = 0; + *data = DN; + curr += sublen; + return 0; + break; + + case KDB_TL_KEYINFO: + /* get the length of the content */ + keyfound = TRUE; + UNSTORE16_INT(curr, sublen); + /* forward by 2 bytes */ + curr += 2; + if (secretkey == NULL) { + secretkey = malloc(sizeof(*secretkey)); + if (secretkey == NULL) + return ENOMEM; + secretkey->nkey = 0; + secretkey->keys = NULL; + secretkey->keys = realloc(secretkey->keys, + sizeof(*(secretkey->keys)) * (limit)); + if (secretkey->keys == NULL) + return ENOMEM; + memset(secretkey->keys, 0, sizeof (*(secretkey->keys)) * (limit)); + } + if ( i == limit-1) { + limit *= 2; + secretkey->keys = realloc(secretkey->keys, + sizeof(*(secretkey->keys)) * (limit)); + if (secretkey->keys == NULL) + return ENOMEM; + memset(secretkey->keys+i, 0, sizeof (*(secretkey->keys)) * (limit-i)); + } + + secretkey->keys[i] = malloc (sizeof(struct berval)); + if (secretkey->keys[i] == NULL) + return ENOMEM; + + secretkey->keys[i]->bv_len = sublen; + secretkey->keys[i]->bv_val = malloc (sublen); + if (secretkey->keys[i]->bv_val == NULL) + return ENOMEM; + + memcpy(secretkey->keys[i]->bv_val, curr, sublen); + secretkey->nkey = ++i; + *data = secretkey; + curr += sublen; + break; + } + } else { + /* move to the current content block */ + UNSTORE16_INT(curr, sublen); + curr += 2 + sublen; + } + } + if (tl_type == KDB_TL_KEYINFO) { + if (keyfound) + return 0; + else + return EINVAL; + } + return EINVAL; +} + +/* + * wrapper routines for decode_tl_data + */ +static krb5_error_code +krb5_get_int_from_tl_data(context, entries, type, intval) + krb5_context context; + krb5_db_entry *entries; + int type; + int *intval; +{ + krb5_error_code st=0; + krb5_tl_data tl_data; + void *voidptr=NULL; + int *intptr=NULL; + + tl_data.tl_data_type = KDB_TL_USER_INFO; + if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0) + goto cleanup; + + if (decode_tl_data(&tl_data, type, &voidptr) == 0) { + intptr = (int *) voidptr; + *intval = *intptr; + free(intptr); + } + + cleanup: + return st; +} + +/* + * get the mask representing the attributes set on the directory object (user, policy ...) + */ +krb5_error_code +krb5_get_attributes_mask(context, entries, mask) + krb5_context context; + krb5_db_entry *entries; + int *mask; +{ + return krb5_get_int_from_tl_data(context, entries, KDB_TL_MASK, mask); +} + +krb5_error_code +krb5_get_princ_type(context, entries, ptype) + krb5_context context; + krb5_db_entry *entries; + int *ptype; +{ + return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCTYPE, ptype); +} + +krb5_error_code +krb5_get_princ_count(context, entries, pcount) + krb5_context context; + krb5_db_entry *entries; + int *pcount; +{ + return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCCOUNT, pcount); +} + +krb5_error_code +krb5_get_secretkeys(context, entries, secretkey) + krb5_context context; + krb5_db_entry *entries; + KEY **secretkey; +{ + krb5_error_code st=0; + krb5_tl_data tl_data; + void *voidptr=NULL; + + tl_data.tl_data_type = KDB_TL_USER_INFO; + if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0) + goto cleanup; + + if (decode_tl_data(&tl_data, KDB_TL_KEYINFO, &voidptr) == 0) { + *secretkey = (KEY *) voidptr; + } + + cleanup: + return st; +} + +static krb5_error_code +krb5_get_str_from_tl_data(context, entries, type, strval) + krb5_context context; + krb5_db_entry *entries; + int type; + char **strval; +{ + krb5_error_code st=0; + krb5_tl_data tl_data; + void *voidptr=NULL; + + if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN && type != KDB_TL_TKTPOLICYDN) { + st = EINVAL; + goto cleanup; + } + + tl_data.tl_data_type = KDB_TL_USER_INFO; + if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0) + goto cleanup; + + if (decode_tl_data(&tl_data, type, &voidptr) == 0) { + *strval = (char *) voidptr; + } + + cleanup: + return st; +} + +krb5_error_code +krb5_get_userdn(context, entries, userdn) + krb5_context context; + krb5_db_entry *entries; + char **userdn; +{ + *userdn = NULL; + return krb5_get_str_from_tl_data(context, entries, KDB_TL_USERDN, userdn); +} + +krb5_error_code +krb5_get_containerdn(context, entries, containerdn) + krb5_context context; + krb5_db_entry *entries; + char **containerdn; +{ + *containerdn = NULL; + return krb5_get_str_from_tl_data(context, entries, KDB_TL_CONTAINERDN, containerdn); +} + +krb5_error_code +krb5_get_policydn(context, entries, policydn) + krb5_context context; + krb5_db_entry *entries; + char **policydn; +{ + *policydn = NULL; + return krb5_get_str_from_tl_data(context, entries, KDB_TL_TKTPOLICYDN, policydn); +} +/* + * This function reads the attribute values (if the attribute is non-null) from the dn. + * The read attribute values is compared aganist the attrvalues passed to the function + * and a bit mask is set for all the matching attributes (attributes existing in both list). + * The bit to be set is selected such that the index of the attribute in the attrvalues + * parameter is the position of the bit. + * For ex: the first element in the attrvalues is present in both list shall set the LSB of the + * bit mask. + * + * In case if either the attribute or the attrvalues parameter to the function is NULL, then + * the existence of the object is considered and appropriate status is returned back + */ + +krb5_error_code +checkattributevalue (ld, dn, attribute, attrvalues, mask) + LDAP *ld; + char *dn; + char *attribute; + char **attrvalues; + int *mask; +{ + int st=0, one=1; + char **values=NULL, *attributes[2] = {NULL}; + LDAPMessage *result=NULL, *entry=NULL; + + if (strlen(dn) == 0) + return LDAP_NO_SUCH_OBJECT; + + attributes[0] = attribute; + + /* read the attribute values from the dn */ + if((st = ldap_search_ext_s( ld, + dn, + LDAP_SCOPE_BASE, + 0, + attributes, + 0, + NULL, + NULL, + &timelimit, + LDAP_NO_LIMIT, + &result)) != LDAP_SUCCESS) { + st = set_ldap_error(0, st, OP_SEARCH); + return st; + } + + /* + * If the attribute/attrvalues is NULL, then check for the existence of the object alone + */ + if (attribute == NULL || attrvalues == NULL) + goto cleanup; + + /* reset the bit mask */ + *mask = 0; + + if((entry=ldap_first_entry(ld, result)) != NULL) { + /* read the attribute values */ + if((values=ldap_get_values(ld, entry, attribute)) != NULL) { + int i,j; + + /* compare the read attribute values with the attrvalues array and set the + * appropriate bit mask + */ + for(j=0; attrvalues[j]; ++j) { + for(i=0; values[i]; ++i) { + if(strcasecmp(values[i], attrvalues[j]) == 0) { + *mask |= (one<<j); + break; + } + } + } + ldap_value_free(values); + } + } + + cleanup: + ldap_msgfree(result); + return st; +} + + +/* + * This function updates a single attribute with a single value of a specified dn. + * This function is mainly used to update krbRealmReferences, krbKdcServers, krbAdminServers... + * when KDC, ADMIN, PASSWD servers are associated with some realms or vice versa. + */ + +krb5_error_code +updateAttribute (ld, dn, attribute, value) + LDAP *ld; + char *dn; + char *attribute; + char *value; +{ + int st=0; + LDAPMod modAttr, *mods[2]={NULL}; + char *values[2]={NULL}; + + values[0] = value; + + /* data to update the {attr,attrval} combination */ + memset(&modAttr, 0, sizeof(modAttr)); + modAttr.mod_type = attribute; + modAttr.mod_op = LDAP_MOD_ADD; + modAttr.mod_values = values; + mods[0] = &modAttr; + + /* ldap modify operation */ + st = ldap_modify_s(ld, dn, mods); + + /* if the {attr,attrval} combination is already present return a success + * LDAP_ALREADY_EXISTS is for single-valued attribute + * LDAP_TYPE_OR_VALUE_EXISTS is for multi-valued attribute + */ + if (st == LDAP_ALREADY_EXISTS || st == LDAP_TYPE_OR_VALUE_EXISTS) + st = 0; + + if (st != 0) { + st = set_ldap_error (0, st, OP_MOD); + } + + return st; +} + +/* + * This function deletes a single attribute with a single value of a specified dn. + * This function is mainly used to delete krbRealmReferences, krbKdcServers, krbAdminServers... + * when KDC, ADMIN, PASSWD servers are disassociated with some realms or vice versa. + */ + +krb5_error_code +deleteAttribute (ld, dn, attribute, value) + LDAP *ld; + char *dn; + char *attribute; + char *value; +{ + krb5_error_code st=0; + LDAPMod modAttr, *mods[2]={NULL}; + char *values[2]={NULL}; + + values[0] = value; + + /* data to delete the {attr,attrval} combination */ + memset(&modAttr, 0, sizeof(modAttr)); + modAttr.mod_type = attribute; + modAttr.mod_op = LDAP_MOD_DELETE; + modAttr.mod_values = values; + mods[0] = &modAttr; + + /* ldap modify operation */ + st = ldap_modify_s(ld, dn, mods); + + /* if either the attribute or the attribute value is missing return a success */ + if (st == LDAP_NO_SUCH_ATTRIBUTE || st == LDAP_UNDEFINED_TYPE) + st = 0; + + if (st != 0) { + st = set_ldap_error (0, st, OP_MOD); + } + + return st; +} + + +/* + * This function takes in 2 string arrays, compares them to remove the matching entries. + * The first array is the original list and the second array is the modified list. Removing + * the matching entries will result in a reduced array, where the left over first array elements + * are the deleted entries and the left over second array elements are the added entries. + * These additions and deletions has resulted in the modified second array. + */ + +krb5_error_code +disjoint_members(src, dest) + char **src; + char **dest; +{ + int i=0, j=0, slen=0, dlen=0; + + /* validate the input parameters */ + if (src == NULL || dest == NULL) + return 0; + + /* compute the first array length */ + for (i=0;src[i]; ++i) + ; + + /* return if the length is 0 */ + if (i==0) + return 0; + + /* index of the last element and also the length of the array */ + slen = i-1; + + /* compute the second array length */ + for (i=0;dest[i]; ++i) + ; + + /* return if the length is 0 */ + if (i==0) + return 0; + + /* index of the last element and also the length of the array */ + dlen = i-1; + + /* check for the similar elements and delete them from both the arrays */ + for(i=0; src[i]; ++i) { + + for(j=0; dest[j]; ++j) { + + /* if the element are same */ + if (strcasecmp(src[i], dest[j]) == 0) { + /* if the matched element is in the middle, then copy the last element to + * the matched index. + */ + if (i != slen) { + free (src[i]); + src[i] = src[slen]; + src[slen] = NULL; + } else { + /* if the matched element is the last, free it and set it to NULL */ + free (src[i]); + src[i] = NULL; + } + /* reduce the array length by 1 */ + slen -= 1; + + /* repeat the same processing for the second array too */ + if (j != dlen) { + free(dest[j]); + dest[j] = dest[dlen]; + dest[dlen] = NULL; + } else { + free(dest[j]); + dest[j] = NULL; + } + dlen -=1; + + /* the source array is reduced by 1, so reduce the index variable used for + * source array by 1. No need to adjust the second array index variable as + * it is reset while entering the inner loop + */ + i -= 1; + break; + } + } + } + return 0; +} + +/* + * This function replicates the contents of the src array for later use. Mostly the contents + * of the src array is obtained from a ldap_search operation and the contents are required + * for later use. + */ + +krb5_error_code +copy_arrays(src, dest, count) + char **src; + char ***dest; + int count; +{ + krb5_error_code st=0; + int i=0; + + /* validate the input parameters */ + if (src == NULL || dest == NULL) + return 0; + + /* allocate memory for the dest array */ + *dest = (char **) calloc((unsigned) count+1, sizeof(char *)); + if (*dest == NULL) { + st = ENOMEM; + goto cleanup; + } + + /* copy the members from src to dest array. */ + for (i=0; i < count && src[i] != NULL; ++i) { + (*dest)[i] = strdup(src[i]); + if ((*dest)[i] == NULL) { + st = ENOMEM; + goto cleanup; + } + } + + cleanup: + /* in case of error free up everything and return */ + if (st != 0) { + if (*dest != NULL) { + for(i=0; (*dest)[i]; ++i) { + free ((*dest)[i]); + (*dest)[i] = NULL; + } + free (*dest); + *dest = NULL; + } + } + return st; +} + +static krb5_error_code +getepochtime(strtime, epochtime) + char *strtime; + krb5_timestamp *epochtime; +{ + struct tm tme; + + memset(&tme, 0, sizeof(tme)); + if (strptime(strtime,"%Y%m%d%H%M%SZ", &tme) == NULL) { + *epochtime = 0; + return EINVAL; + } + *epochtime = krb5int_gmt_mktime(&tme); + return 0; +} + +/* + * krb5_ldap_get_value() - get the integer value of the attribute + * Returns, 0 if the attribute is present, 1 if the attribute is missing. + * The retval is 0 if the attribute is missing. + */ + +krb5_error_code +krb5_ldap_get_value(ld, ent, attribute, retval) + LDAP *ld; + LDAPMessage *ent; + char *attribute; + int *retval; +{ + char **values=NULL; + + *retval = 0; + values=ldap_get_values(ld, ent, attribute); + if (values != NULL) { + if (values[0] != NULL) + *retval = atoi(values[0]); + ldap_value_free(values); + return 0; + } + return 1; +} + +/* + * krb5_ldap_get_string() - Returns the first string of the attribute. Intended to + * + * + */ +krb5_error_code +krb5_ldap_get_string(ld, ent, attribute, retstr, attr_present) + LDAP *ld; + LDAPMessage *ent; + char *attribute; + char **retstr; + krb5_boolean *attr_present; +{ + char **values=NULL; + krb5_error_code st=0; + + *retstr = NULL; + if (attr_present != NULL) + *attr_present = FALSE; + + values=ldap_get_values(ld, ent, attribute); + if (values != NULL) { + if (values[0] != NULL) { + if (attr_present!= NULL) + *attr_present = TRUE; + *retstr = strdup(values[0]); + if (*retstr == NULL) + st = ENOMEM; + } + ldap_value_free(values); + } + return st; +} + +krb5_error_code +krb5_ldap_get_time(ld, ent, attribute, rettime, attr_present) + LDAP *ld; + LDAPMessage *ent; + char *attribute; + krb5_timestamp *rettime; + krb5_boolean *attr_present; +{ + char **values=NULL; + krb5_error_code st=0; + + *rettime = 0; + *attr_present = FALSE; + + values=ldap_get_values(ld, ent, attribute); + if (values != NULL) { + if (values[0] != NULL) { + *attr_present = TRUE; + st = getepochtime(values[0], rettime); + } + ldap_value_free(values); + } + return st; +} + +/* + * Function to allocate, set the values of LDAPMod structure. The LDAPMod structure is then + * added to the array at the ind + */ + +krb5_error_code +krb5_add_member(mods, count) + LDAPMod ***mods; + int *count; +{ + int i=0; + LDAPMod **lmods=NULL; + + if ((*mods) != NULL) { + for (;(*mods)[i] != NULL; ++i) + ; + } + lmods = (LDAPMod **) realloc((*mods), (2+i) * sizeof(LDAPMod *)); + if (lmods == NULL) + return ENOMEM; + + *mods = lmods; + (*mods)[i+1] = NULL; + (*mods)[i] = (LDAPMod *) calloc(1, sizeof (LDAPMod)); + if ((*mods)[i] == NULL) + return ENOMEM; + *count = i; + return 0; +} + +krb5_error_code +krb5_add_str_mem_ldap_mod(mods, attribute, op, values) + LDAPMod ***mods; + char *attribute; + int op; + char **values; + +{ + int i=0, j=0; + krb5_error_code st=0; + + if ((st=krb5_add_member(mods, &i)) != 0) + return st; + + (*mods)[i]->mod_type = strdup(attribute); + if ((*mods)[i]->mod_type == NULL) + return ENOMEM; + (*mods)[i]->mod_op = op; + + if (values != NULL) { + for (j=0; values[j] != NULL; ++j) + ; + (*mods)[i]->mod_values = malloc (sizeof(char *) * (j+1)); + if ((*mods)[i]->mod_values == NULL) + return ENOMEM; + + for (j=0; values[j] != NULL; ++j) { + (*mods)[i]->mod_values[j] = strdup(values[j]); + if ((*mods)[i]->mod_values[j] == NULL) + return ENOMEM; + } + (*mods)[i]->mod_values[j] = NULL; + } + return 0; +} + +krb5_error_code +krb5_add_ber_mem_ldap_mod(mods, attribute, op, ber_values) + LDAPMod ***mods; + char *attribute; + int op; + struct berval **ber_values; + +{ + int i=0, j=0; + krb5_error_code st=0; + + if ((st=krb5_add_member(mods, &i)) != 0) + return st; + + (*mods)[i]->mod_type = strdup(attribute); + if ((*mods)[i]->mod_type == NULL) + return ENOMEM; + (*mods)[i]->mod_op = op; + + for (j=0; ber_values[j] != NULL; ++j) + ; + (*mods)[i]->mod_bvalues = malloc (sizeof(struct berval *) * (j+1)); + if ((*mods)[i]->mod_bvalues == NULL) + return ENOMEM; + + for (j=0; ber_values[j] != NULL; ++j) { + (*mods)[i]->mod_bvalues[j] = calloc(1, sizeof(struct berval)); + if ((*mods)[i]->mod_bvalues[j] == NULL) + return ENOMEM; + + (*mods)[i]->mod_bvalues[j]->bv_len = ber_values[j]->bv_len; + (*mods)[i]->mod_bvalues[j]->bv_val = malloc((*mods)[i]->mod_bvalues[j]->bv_len); + if ((*mods)[i]->mod_bvalues[j]->bv_val == NULL) + return ENOMEM; + + memcpy((*mods)[i]->mod_bvalues[j]->bv_val, ber_values[j]->bv_val, + ber_values[j]->bv_len); + } + (*mods)[i]->mod_bvalues[j] = NULL; + return 0; +} + +static inline char * +format_d (int val) +{ + char tmpbuf[2+3*sizeof(val)]; + sprintf(tmpbuf, "%d", val); + return strdup(tmpbuf); +} + +krb5_error_code +krb5_add_int_arr_mem_ldap_mod(mods, attribute, op, value) + LDAPMod ***mods; + char *attribute; + int op; + int *value; + +{ + int i=0, j=0; + krb5_error_code st=0; + + if ((st=krb5_add_member(mods, &i)) != 0) + return st; + + (*mods)[i]->mod_type = strdup(attribute); + if ((*mods)[i]->mod_type == NULL) + return ENOMEM; + (*mods)[i]->mod_op = op; + + for (j=0; value[j] != -1; ++j) + ; + + (*mods)[i]->mod_values = malloc(sizeof(char *) * (j+1)); + + for (j=0; value[j] != -1; ++j) { + if (((*mods)[i]->mod_values[j] = format_d(value[j])) == NULL) + return ENOMEM; + } + (*mods)[i]->mod_values[j] = NULL; + return 0; +} + +krb5_error_code +krb5_add_int_mem_ldap_mod(mods, attribute, op, value) + LDAPMod ***mods; + char *attribute; + int op; + int value; + +{ + int i=0; + krb5_error_code st=0; + + if ((st=krb5_add_member(mods, &i)) != 0) + return st; + + (*mods)[i]->mod_type = strdup(attribute); + if ((*mods)[i]->mod_type == NULL) + return ENOMEM; + + (*mods)[i]->mod_op = op; + (*mods)[i]->mod_values = calloc (2, sizeof(char *)); + if (((*mods)[i]->mod_values[0] = format_d(value)) == NULL) + return ENOMEM; + return 0; +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h new file mode 100644 index 000000000..d15b7c70f --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h @@ -0,0 +1,125 @@ +/* + * lib/kdb/kdb_ldap/ldap_misc.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef _HAVE_LDAP_MISC_H +#define _HAVE_LDAP_MISC_H 1 + +#include "ldap_services.h" + +/* misc functions */ + +krb5_error_code +updateAttribute (LDAP *, char *, char *, char *); + +krb5_error_code +deleteAttribute (LDAP *, char *, char *, char *); + +krb5_error_code +populateServers(LDAP *, char **, char ***, char *, char **); + +krb5_error_code +disjoint_members(char **, char **); + +krb5_error_code +is_principal_in_realm(krb5_ldap_context *, krb5_const_principal); + +krb5_error_code +checkattributevalue(LDAP *, char *, char *, char **, int *); + +krb5_error_code +krb5_get_attributes_mask(krb5_context, krb5_db_entry *, int *); + +krb5_error_code +krb5_get_princ_type(krb5_context, krb5_db_entry *, int *); + +krb5_error_code +krb5_get_princ_count(krb5_context, krb5_db_entry *, int *); + +krb5_error_code +krb5_get_secretkeys(krb5_context, krb5_db_entry *, KEY **); + +krb5_error_code +krb5_get_userdn(krb5_context, krb5_db_entry *, char **); + +krb5_error_code +krb5_get_containerdn(krb5_context, krb5_db_entry *, char **); + +krb5_error_code +store_tl_data(krb5_tl_data *, int, void *); + +krb5_error_code +decode_tl_data(krb5_tl_data *, int, void **); + +krb5_error_code +is_principal_in_realm(krb5_ldap_context *, krb5_const_principal); + +krb5_error_code +krb5_get_subtree_info(krb5_ldap_context *, char **, unsigned int *); + +krb5_error_code +krb5_ldap_read_server_params(krb5_context , char *, int); + +krb5_error_code +krb5_ldap_free_server_params(krb5_ldap_context *); + +krb5_error_code +copy_arrays(char **, char ***, int); + +krb5_error_code +krb5_ldap_list(krb5_context, char ***, char *, char *); + +krb5_error_code +krb5_ldap_get_value(LDAP *, LDAPMessage *, char *, int *); + +krb5_error_code +krb5_ldap_get_string(LDAP *, LDAPMessage *, char *, char **, krb5_boolean *); + +krb5_error_code +krb5_ldap_get_time(LDAP *, LDAPMessage *, char *, krb5_timestamp *, krb5_boolean *); + +krb5_error_code +krb5_add_member(LDAPMod ***, int *); + +krb5_error_code +krb5_add_str_mem_ldap_mod(LDAPMod ***, char *, int, char **); + +krb5_error_code +krb5_add_ber_mem_ldap_mod(LDAPMod ***, char *, int, struct berval **); + +krb5_error_code +krb5_add_int_arr_mem_ldap_mod(LDAPMod ***, char *, int, int *); + +krb5_error_code +krb5_add_int_mem_ldap_mod(LDAPMod ***, char *, int , int); + +krb5_error_code +krb5_ldap_free_mod_array(LDAPMod **); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c new file mode 100644 index 000000000..15dcd8dc7 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c @@ -0,0 +1,514 @@ +/* + * lib/kdb/kdb_ldap/ldap_principal.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" +#include "kdb_ldap.h" +#include "ldap_principal.h" +#include "princ_xdr.h" +#include "ldap_err.h" + +struct timeval timelimit = {300, 0}; /* 5 minutes */ +char *principal_attributes[] = { "krbprincipalname", + "objectclass", + "krbsecretkey", + "krbmaxrenewableage", + "krbmaxticketlife", + "krbticketflags", + "krbprincipalexpiration", + "krbpolicyreference", + "krbUpEnabled", + "krbpwdpolicyreference", + "krbpasswordexpiration", +#ifdef HAVE_EDIRECTORY + "loginexpirationtime", + "logindisabled", +#endif + "loginexpirationtime", + "logindisabled", + "modifiersname", + "modifytimestamp", + NULL }; + +static char *attributes_set[] = { "krbmaxrenewableage", + "krbmaxticketlife", + "krbticketflags", + "krbprincipalexpiration", + "krbpolicyreference", + "krbUpEnabled", + "krbpwdpolicyreference", + "krbpasswordexpiration", + "krbsecretkey", + NULL }; + +void +krb5_dbe_free_contents(context, entry) + krb5_context context; + krb5_db_entry *entry; +{ + krb5_tl_data *tl_data_next=NULL; + krb5_tl_data *tl_data=NULL; + int i, j; + + if (entry->e_data) + free(entry->e_data); + if (entry->princ) + krb5_free_principal(context, entry->princ); + for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) { + tl_data_next = tl_data->tl_data_next; + if (tl_data->tl_data_contents) + free(tl_data->tl_data_contents); + free(tl_data); + } + if (entry->key_data) { + for (i = 0; i < entry->n_key_data; i++) { + for (j = 0; j < entry->key_data[i].key_data_ver; j++) { + if (entry->key_data[i].key_data_length[j]) { + if (entry->key_data[i].key_data_contents[j]) { + memset(entry->key_data[i].key_data_contents[j], + 0, + (unsigned) entry->key_data[i].key_data_length[j]); + free (entry->key_data[i].key_data_contents[j]); + } + } + entry->key_data[i].key_data_contents[j] = NULL; + entry->key_data[i].key_data_length[j] = 0; + entry->key_data[i].key_data_type[j] = 0; + } + } + free(entry->key_data); + } + memset(entry, 0, sizeof(*entry)); + return; +} + + +krb5_error_code +krb5_ldap_free_principal(kcontext , entries, nentries) + krb5_context kcontext; + krb5_db_entry *entries; + int nentries; +{ + register int i; + for (i = 0; i < nentries; i++) + krb5_dbe_free_contents(kcontext, &entries[i]); + return 0; +} + + +krb5_error_code +krb5_ldap_iterate(context, match_expr, func, func_arg) + krb5_context context; + char *match_expr; + krb5_error_code (*func) (krb5_pointer, krb5_db_entry *); + krb5_pointer func_arg; +{ + krb5_db_entry entry; + krb5_principal principal; + char *subtree[2]={NULL}, *princ_name=NULL, *realm=NULL, **values=NULL, *filter=NULL; + char *krbprincipal_attr[] = { "krbPrincipalName", NULL }; + unsigned int filterlen=0, tree=0, ntree=1, i=0; + krb5_error_code st=0, tempst=0; + LDAP *ld=NULL; + LDAPMessage *result=NULL, *ent=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + memset(&entry, 0, sizeof(krb5_db_entry)); + SETUP_CONTEXT(); + + realm = ldap_context->lrparams->realm_name; + if (realm == NULL) { + realm = context->default_realm; + if (realm == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "Default realm not set"); + goto cleanup; + } + } + + filterlen = strlen(FILTER) + strlen(match_expr) + 2 + 1; /* 2 for closing brackets */ + filter = malloc (filterlen); + CHECK_NULL(filter); + memset(filter, 0, filterlen); + sprintf(filter, FILTER"%s))", match_expr); + + if ((st = krb5_get_subtree_info(ldap_context, subtree, &ntree)) != 0) + goto cleanup; + + GET_HANDLE(); + + for (tree=0; tree<ntree; ++tree) { + + LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, krbprincipal_attr); + for(ent=ldap_first_entry(ld, result); ent != NULL; ent=ldap_next_entry(ld, ent)) { + if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) { + for(i=0; values[i] != NULL; ++i) { + if (krb5_ldap_parse_principal_name(values[i], &princ_name) != 0) + continue; + if (krb5_parse_name(context, princ_name, &principal) != 0) + continue; + if (is_principal_in_realm(ldap_context, principal) == 0) { + entry.princ = principal; + (*func)(func_arg, &entry); + } + krb5_free_principal(context, principal); + if (princ_name) + free(princ_name); + } + ldap_value_free(values); + } + } /* end of for(ent= ... */ + ldap_msgfree(result); + } /* end of for(tree= ... */ + + cleanup: + if (filter) + free (filter); + + for ( ;ntree; --ntree) + if (subtree[ntree-1]) + free (subtree[ntree-1]); + + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * delete a principal from the directory. + */ +krb5_error_code +krb5_ldap_delete_principal(context, searchfor, nentries) + krb5_context context; + krb5_const_principal searchfor; + int *nentries; /* how many found & deleted */ +{ + char *user=NULL, *DN=NULL, *strval[10] = {NULL}; + LDAPMod **mods=NULL; + LDAP *ld=NULL; + int j=0, ptype=KDB_USER_PRINCIPAL, pcount=0, attrsetmask=0; + krb5_error_code st=0; + krb5_boolean singleentry=FALSE; + KEY *secretkey=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + krb5_db_entry entries; + krb5_boolean more=0; + char * policydn = NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + SETUP_CONTEXT(); + /* get the principal info */ + if ((st=krb5_ldap_get_principal(context, searchfor, &entries, nentries, &more)) != 0 || *nentries == 0) + goto cleanup; + + if (((st=krb5_get_princ_type(context, &entries, &(ptype))) != 0) || + ((st=krb5_get_attributes_mask(context, &entries, &(attrsetmask))) != 0) || + ((st=krb5_get_princ_count(context, &entries, &(pcount))) != 0) || + ((st=krb5_get_userdn(context, &entries, &(DN))) != 0) || + ((st=krb5_get_policydn(context, &entries, &policydn)) != 0) || + ((st=krb5_get_secretkeys(context, &entries, &secretkey)) != 0)) + goto cleanup; + + if (DN == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "DN information missing"); + goto cleanup; + } + + GET_HANDLE(); + + if (ptype == KDB_USER_PRINCIPAL) { + + if(((st=krb5_unparse_name(context, searchfor, &user)) != 0) + || ((st=krb5_ldap_unparse_principal_name(user)) != 0)) + goto cleanup; + + memset(strval, 0, sizeof(strval)); + strval[0] = user; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_DELETE, + strval)) != 0) + goto cleanup; + + singleentry = (pcount == 1) ? TRUE: FALSE; + if (singleentry == FALSE) { + if (secretkey != NULL) { + if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbsecretkey", LDAP_MOD_DELETE | LDAP_MOD_BVALUES, + secretkey->keys)) != 0) + goto cleanup; + } + } else { + /* + * If the Kerberos user principal to be deleted happens to be the last one associated + * with the directory user object, then it is time to delete the other kerberos + * specific attributes like krbmaxticketlife, i.e, unkerberize the directory user. + * From the attrsetmask value, identify the attributes set on the directory user + * object and delete them. + * NOTE: krbsecretkey attribute has per principal entries. There can be chances that the + * other principals' keys are exisiting/left-over. So delete all the values. + */ + while (attrsetmask) { + if (attrsetmask & 1) { + if ((st=krb5_add_str_mem_ldap_mod(&mods, attributes_set[j], LDAP_MOD_DELETE, + NULL)) != 0) + goto cleanup; + } + attrsetmask >>= 1; + ++j; + } + if(policydn != NULL) + { + if ((st = krb5_ldap_change_count(context, policydn,2 ))) + goto cleanup; + + } + + /* the same should be done with the objectclass attributes */ + { + char *attrvalues[] = {"krbpwdpolicyrefaux", "krbpolicyaux", "krbprincipalaux", NULL}; + int p, q, r=0, amask=0; + + if ((st=checkattributevalue(ld, DN, "objectclass", attrvalues, &amask)) != 0) + goto cleanup; + memset(strval, 0, sizeof(strval)); + for(p=1, q=0; p<=4; p<<=1, ++q) + if (p & amask) + strval[r++] = attrvalues[q]; + strval[r] = NULL; + if (r > 0) { + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_DELETE, + strval)) != 0) + goto cleanup; + } + } + } + st=ldap_modify_s(ld, DN, mods); + if (st != LDAP_SUCCESS) { + st = set_ldap_error(context, st, OP_MOD); + goto cleanup; + } + } + else if (ptype == KDB_SERVICE_PRINCIPAL) { + st = ldap_delete_s(ld, DN); + if (st != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_DEL); + goto cleanup; + } + } + + cleanup: + if (user) + free (user); + + if (DN) + free (DN); + + if (secretkey != NULL) { + int i=0; + while (i < secretkey->nkey) { + free (secretkey->keys[i]->bv_val); + free (secretkey->keys[i]); + ++i; + } + free (secretkey->keys); + free (secretkey); + } + + if (st == 0) + krb5_ldap_free_principal(context, &entries, *nentries); + + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * Function: krb5_ldap_unparse_principal_name + * + * Purpose: Removes '\\' that comes before every occurence of '@' + * in the principal name component. + * + * Arguments: + * user_name (input/output) Principal name + * + */ + +krb5_error_code +krb5_ldap_unparse_principal_name(char *user_name) +{ + char *tmp_princ_name=NULL, *princ_name=NULL, *tmp=NULL; + int l=0; + krb5_error_code st=0; + + if(strstr(user_name, "\\@")) + { + + tmp_princ_name = strdup(user_name); + if( !tmp_princ_name ) + { + st = ENOMEM; + goto cleanup; + } + tmp = tmp_princ_name; + + princ_name = (char *) malloc (strlen(user_name)); + if( !princ_name ) + { + st = ENOMEM; + goto cleanup; + } + memset(princ_name, 0, strlen(user_name)); + + l = 0; + while(*tmp_princ_name) + { + if((*tmp_princ_name == '\\') && (*(tmp_princ_name+1) == '@')) + { + tmp_princ_name += 1; + } + else + { + *(princ_name + l) = *tmp_princ_name++; + l++; + } + } + + memset(user_name, 0, strlen(user_name)); + sprintf(user_name, "%s", princ_name); + } + + cleanup: + if (tmp) { + free(tmp); + tmp = NULL; + } + + if (princ_name) { + free(princ_name); + princ_name = NULL; + } + + return st; +} + + +/* + * Function: krb5_ldap_parse_principal_name + * + * Purpose: Inserts '\\' before every occurence of '@' + * in the principal name component. + * + * Arguments: + * i_princ_name (input) Principal name without '\\' + * o_princ_name (output) Principal name with '\\' + * + * Note: The caller has to free the memory allocated for o_princ_name. + */ + +krb5_error_code +krb5_ldap_parse_principal_name(i_princ_name, o_princ_name) + char *i_princ_name; + char **o_princ_name; +{ + char *tmp_princ_name = NULL, *princ_name = NULL, *at_rlm_name = NULL; + int l = 0, m = 0, tmp_princ_name_len = 0, princ_name_len = 0, at_count = 0; + krb5_error_code st = 0; + + at_rlm_name = strrchr(i_princ_name, '@'); + + if(!at_rlm_name) + { + *o_princ_name = strdup(i_princ_name); + if( !o_princ_name ) + { + st = ENOMEM; + goto cleanup; + } + } + else + { + tmp_princ_name_len = at_rlm_name - i_princ_name; + + tmp_princ_name = (char *) malloc ((unsigned) tmp_princ_name_len + 1); + if( !tmp_princ_name ) + { + st = ENOMEM; + goto cleanup; + } + memset(tmp_princ_name, 0, (unsigned) tmp_princ_name_len + 1); + memcpy( tmp_princ_name, i_princ_name, (unsigned) tmp_princ_name_len); + + l = 0; + while(tmp_princ_name[l]) + { + if(tmp_princ_name[l++] == '@') + at_count++; + } + + princ_name_len = strlen(i_princ_name) + at_count + 1; + princ_name = (char *) malloc ((unsigned) princ_name_len); + if( !princ_name ) + { + st = ENOMEM; + goto cleanup; + } + memset(princ_name, 0, (unsigned) princ_name_len); + + l = 0; + m = 0; + while(tmp_princ_name[l]) + { + if(tmp_princ_name[l] == '@'){ + princ_name[m++]='\\'; + } + princ_name[m++]=tmp_princ_name[l++]; + } + strcat(princ_name, at_rlm_name); + + *o_princ_name = princ_name; + } + + cleanup: + + if (tmp_princ_name) { + free(tmp_princ_name); + tmp_princ_name = NULL; + } + + return st; +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h new file mode 100644 index 000000000..65224c8d3 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h @@ -0,0 +1,126 @@ +/* + * lib/kdb/kdb_ldap/ldap_principal.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef _LDAP_PRINCIPAL_H +#define _LDAP_PRINCIPAL_H 1 + +#include "ldap_tkt_policy.h" + +#define KEYHEADER 12 + +#define NOOFKEYS(ptr) ((ptr[10]<<8) | ptr[11]) + +#define PRINCIPALLEN(ptr) ((ptr[0]<<8) | ptr[1]) +#define PRINCIPALNAME(ptr) (ptr + KEYHEADER + (NOOFKEYS(ptr) *8)) + +#define KEYBODY(ptr) PRINCIPALNAME(ptr) + PRINCIPALLEN(ptr) + +#define PKEYVER(ptr) ((ptr[2]<<8) | ptr[3]) +#define MKEYVER(ptr) ((ptr[4]<<8) | ptr[5]) + +#define KEYTYPE(ptr,j) ((ptr[KEYHEADER+(j*8)]<<8) | ptr[KEYHEADER+1+(j*8)]) +#define KEYLENGTH(ptr,j) ((ptr[KEYHEADER+2+(j*8)]<<8) | ptr[KEYHEADER+3+(j*8)]) +#define SALTTYPE(ptr,j) ((ptr[KEYHEADER+4+(j*8)]<<8) | ptr[KEYHEADER+5+(j*8)]) +#define SALTLENGTH(ptr,j) ((ptr[KEYHEADER+6+(j*8)]<<8) | ptr[KEYHEADER+7+(j*8)]) + +#define MAX_KEY_LENGTH 1024 +#define CONTAINERDN_ARG "containerdn" +#define USERDN_ARG "userdn" +#define TKTPOLICYDN_ARG "tktpolicydn" + +#define FILTER "(&(objectclass=krbprincipalaux)(krbprincipalname=" +#define KDB_USER_PRINCIPAL 0x01 +#define KDB_SERVICE_PRINCIPAL 0x02 + +/* krb5_db_entry */ +#define KDB_PRINCIPAL 0x000001 +#define KDB_PRINC_EXPIRE_TIME 0x000002 +#define KDB_PW_EXPIRATION 0x000004 +#define KDB_LAST_PWD_CHANGE 0x000008 +#define KDB_ATTRIBUTES 0x000010 +#define KDB_MAX_LIFE 0x000020 +#define KDB_MOD_TIME 0x000040 +#define KDB_MOD_NAME 0x000080 +#define KDB_KVNO 0x000100 +#define KDB_MKVNO 0x000200 +#define KDB_AUX_ATTRIBUTES 0x000400 +#define KDB_POLICY 0x000800 +#define KDB_POLICY_CLR 0x001000 +#define KDB_MAX_RLIFE 0x002000 +#define KDB_LAST_SUCCESS 0x004000 +#define KDB_LAST_FAILED 0x008000 +#define KDB_FAIL_AUTH_COUNT 0x010000 +#define KDB_KEY_DATA 0x020000 +#define KDB_TL_DATA 0x040000 +#define KDB_CPW_FUNCTION 0x080000 +#define KDB_RANDKEY_USED 0x100000 + +/* these will be consumed only by krb5_ldap_delete_principal*/ +/* these will be set by krb5_ldap_get_principal and fed into the tl_data */ + +#define KDB_MAX_LIFE_ATTR 0x000001 +#define KDB_MAX_RLIFE_ATTR 0x000002 +#define KDB_TKT_FLAGS_ATTR 0x000004 +#define KDB_PRINC_EXPIRE_TIME_ATTR 0x000008 +#define KDB_POL_REF_ATTR 0x000010 +#define KDB_UP_FLAG_ATTR 0x000020 +#define KDB_PWD_POL_REF_ATTR 0x000040 +#define KDB_PWD_EXPIRE_TIME_ATTR 0x000080 +#define KDB_SECRET_KEY 0x000100 +extern struct timeval timeout; +extern char *policyclass[]; + +krb5_error_code +krb5_ldap_put_principal(krb5_context, krb5_db_entry *, int *, char **); + +krb5_error_code +krb5_ldap_get_principal(krb5_context , krb5_const_principal , + krb5_db_entry *,int *, krb5_boolean *); + +krb5_error_code +krb5_ldap_delete_principal(krb5_context, krb5_const_principal, int *); + +krb5_error_code +krb5_ldap_free_principal(krb5_context, krb5_db_entry *, int ); + +krb5_error_code +krb5_ldap_iterate(krb5_context, char *, krb5_error_code (*) (krb5_pointer, krb5_db_entry *), + krb5_pointer/*, int */); + +void +krb5_dbe_free_contents(krb5_context, krb5_db_entry *); + +krb5_error_code +krb5_ldap_unparse_principal_name(char *); + +krb5_error_code +krb5_ldap_parse_principal_name(char *, char **); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c new file mode 100644 index 000000000..6509ff9e7 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c @@ -0,0 +1,1296 @@ +/* + * lib/kdb/kdb_ldap/ldap_principal2.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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" + +extern char* principal_attributes[]; +extern char* max_pwd_life_attr[]; +#if !defined( LDAP_OPT_RESULT_CODE) && defined(LDAP_OPT_ERROR_NUMBER) +#define LDAP_OPT_RESULT_CODE LDAP_OPT_ERROR_NUMBER +#endif + +static krb5_error_code +krb5_decode_krbsecretkey(krb5_context, krb5_db_entry *, struct berval **, krb5_tl_data *); + +static krb5_error_code +krb5_read_tkt_policyreference(krb5_context, krb5_ldap_context *, krb5_db_entry *, char *); + +static char * +getstringtime(krb5_timestamp ); + +/* + * look up a principal in the directory. + */ + +krb5_error_code +krb5_ldap_get_principal(context, searchfor, entries, nentries, more) + krb5_context context; + krb5_const_principal searchfor; + krb5_db_entry *entries; /* filled in */ + int *nentries; /* how much room/how many found */ + krb5_boolean *more; /* are there more? */ +{ + char *user=NULL, *DN=NULL, *filter=NULL, *subtree[2]={NULL}; + unsigned int tree=0, ntrees=1, mask=0, princlen=0; + krb5_error_code tempst=0, st=0; + char **values=NULL, *policydn=NULL, *pwdpolicydn=NULL, *modname=NULL; + krb5_tl_data userinfo_tl_data={0}; + krb5_timestamp modtime=0; + struct berval **bvalues=NULL; + LDAP *ld=NULL; + LDAPMessage *result=NULL, *ent=NULL; + krb5_ldap_context *ldap_context=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + krb5_principal parsed_mod_name=NULL; + krb5_boolean attr_present=FALSE; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + /* set initial values */ + *nentries = 0; + *more = 0; + memset(entries, 0, sizeof(*entries)); + + if (searchfor == NULL) + return EINVAL; + + dal_handle = (kdb5_dal_handle *) context->db_context; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + + CHECK_LDAP_HANDLE(ldap_context); + + if (is_principal_in_realm(ldap_context, searchfor) != 0) { + *more = 0; + krb5_set_error_message (context, st, "Principal does not belong to realm"); + goto cleanup; + } + + if ((st=krb5_unparse_name(context, searchfor, &user)) != 0) + goto cleanup; + + if ((st=krb5_ldap_unparse_principal_name(user)) != 0) + goto cleanup; + + princlen = strlen(FILTER) + strlen(user) + 2 + 1; /* 2 for closing brackets */ + if ((filter=malloc(princlen)) == NULL) { + st = ENOMEM; + goto cleanup; + } + snprintf(filter, princlen, FILTER"%s))", user); + + if ((st = krb5_get_subtree_info(ldap_context, subtree, &ntrees)) != 0) + goto cleanup; + + GET_HANDLE(); + for (tree=0; tree<ntrees && *nentries==0; ++tree) { + + LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes); + for (ent=ldap_first_entry(ld, result); ent != NULL && *nentries == 0; ent=ldap_next_entry(ld, ent)) { + + /* get the associated directory user information */ + if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) { + int i=0, pcount=0, ptype=KDB_USER_PRINCIPAL; + + /* 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 + */ + for (i=0; values[i] != NULL; ++i) { + if (strcasecmp(values[i], user) == 0) { + *nentries = 1; + pcount = ldap_count_values(values); + break; + } + } + ldap_value_free(values); + + if (*nentries == 0) /* no matching principal found */ + continue; + + if ((DN = ldap_get_dn(ld, ent)) == NULL) { + ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st); + st = set_ldap_error (context, st, 0); + goto cleanup; + } + + if ((values=ldap_get_values(ld, ent, "objectclass")) != NULL) { + for(i=0; values[i] != NULL; ++i) + if (strcasecmp(values[i], "krbprincipal") == 0) { + ptype = KDB_SERVICE_PRINCIPAL; + break; + } + ldap_value_free(values); + } + + /* add principalcount, DN and principaltype user information to tl_data */ + if (((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount)) != 0) || + ((st=store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, DN)) != 0) || + ((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE, &ptype)) != 0)) + goto cleanup; + } + + /* populate entries->princ with searchfor value */ + if ((st=krb5_copy_principal(context, searchfor, &(entries->princ))) != 0) + goto cleanup; + + /* read all the kerberos attributes */ + + /* KRBMAXTICKETLIFE */ + if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entries->max_life)) == 0) + mask |= KDB_MAX_LIFE_ATTR; + + /* KRBMAXRENEWABLEAGE */ + if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", &(entries->max_renewable_life)) == 0) + mask |= KDB_MAX_RLIFE_ATTR; + + /* KRBTICKETFLAGS */ + if (krb5_ldap_get_value(ld, ent, "krbticketflags", &(entries->attributes)) == 0) + mask |= KDB_TKT_FLAGS_ATTR; + + /* PRINCIPAL EXPIRATION TIME */ + if ((st=krb5_ldap_get_time(ld, ent, "krbprincipalexpiration", &(entries->expiration), + &attr_present)) != 0) + goto cleanup; + if (attr_present == TRUE) + mask |= KDB_PRINC_EXPIRE_TIME_ATTR; + + /* PASSWORD EXPIRATION TIME */ + if ((st=krb5_ldap_get_time(ld, ent, "krbpasswordexpiration", &(entries->pw_expiration), + &attr_present)) != 0) + goto cleanup; + if (attr_present == TRUE) + mask |= KDB_PWD_EXPIRE_TIME_ATTR; + + /* KRBPOLICYREFERENCE */ + + if ((st=krb5_ldap_get_string(ld, ent, "krbpolicyreference", &policydn, &attr_present)) != 0) + goto cleanup; + + if(attr_present == TRUE){ + if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_TKTPOLICYDN, policydn)) != 0) + goto cleanup; + } + if(!(mask & KDB_MAX_LIFE_ATTR) && !(mask & KDB_MAX_RLIFE_ATTR) && !(mask & KDB_TKT_FLAGS_ATTR)){ + if (attr_present == TRUE) + mask |= KDB_POL_REF_ATTR; + } + + /* KRBPWDPOLICYREFERENCE */ + if ((st=krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn, &attr_present)) != 0) + goto cleanup; + if (attr_present == TRUE) { + krb5_tl_data kadm_tl_data; + + mask |= KDB_PWD_POL_REF_ATTR; + if((st = krb5_update_tl_kadm_data(pwdpolicydn, &kadm_tl_data)) != 0){ + goto cleanup; + } + krb5_dbe_update_tl_data(context, entries, &kadm_tl_data); + } + + /* KRBSECRETKEY */ + if((bvalues=ldap_get_values_len(ld, ent, "krbsecretkey")) != NULL) { + mask |= KDB_SECRET_KEY; + if ((st=krb5_decode_krbsecretkey(context, entries, bvalues, &userinfo_tl_data)) != 0) + goto cleanup; + } + + /* MODIFY TIMESTAMP */ + if ((st=krb5_ldap_get_time(ld, ent, "modifytimestamp", &modtime, &attr_present)) != 0) + goto cleanup; + + /* MODIFIER'S NAME */ + if ((st=krb5_ldap_get_string(ld, ent, "modifiersname", &modname, &attr_present)) != 0) + goto cleanup; + if (attr_present == TRUE) { + if ((st=krb5_parse_name(context, modname, &parsed_mod_name)) != 0) + goto cleanup; + + if ((st=krb5_dbe_update_mod_princ_data(context, entries, modtime, parsed_mod_name)) != 0) + goto cleanup; + } + + /* update the mask of attributes present on the directory object to the tl_data */ + if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask)) != 0) + goto cleanup; + if ((st=krb5_dbe_update_tl_data(context, entries, &userinfo_tl_data)) != 0) + goto cleanup; + +#ifdef HAVE_EDIRECTORY + { + krb5_timestamp expiretime=0; + char *is_login_disabled=NULL; + + /* LOGIN EXPIRATION TIME */ + if ((st=krb5_ldap_get_time(ld, ent, "loginexpirationtime", &expiretime, + &attr_present)) != 0) + goto cleanup; + + if (attr_present == TRUE) { + if ((mask & KDB_PRINC_EXPIRE_TIME_ATTR) == 1) { + if (expiretime < entries->expiration) + entries->expiration = expiretime; + } else { + entries->expiration = expiretime; + } + } + + /* LOGIN DISABLED */ + if ((st=krb5_ldap_get_string(ld, ent, "logindisabled", &is_login_disabled, &attr_present)) != 0) + goto cleanup; + if (attr_present == TRUE) { + if (strcasecmp(is_login_disabled,"TRUE")== 0) + entries->attributes |= KRB5_KDB_DISALLOW_ALL_TIX; + free (is_login_disabled); + } + } +#endif + } + ldap_msgfree(result); + result = NULL; + } /* for(tree=0 ... */ + + /* once done, put back the ldap handle */ + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + ldap_server_handle = NULL; + + /* if principal not found */ + if (*nentries == 0) + goto cleanup; + + if ((st=krb5_read_tkt_policyreference(context, ldap_context, entries, policydn)) !=0) + goto cleanup; + + if (pwdpolicydn) { + osa_policy_ent_t pwdpol; + int cnt=0; + krb5_timestamp last_pw_changed; + krb5_ui_4 pw_max_life; + + memset(&pwdpol, 0, sizeof(pwdpol)); + + if ((st=krb5_ldap_get_password_policy(context, pwdpolicydn, &pwdpol, &cnt)) != 0) + goto cleanup; + pw_max_life = pwdpol->pw_max_life; + free (pwdpol); + + if (pw_max_life > 0) { + if ((st=krb5_dbe_lookup_last_pwd_change(context, entries, &last_pw_changed)) != 0) + goto cleanup; + + if ((mask & KDB_PWD_EXPIRE_TIME_ATTR) == 1) { + if ((last_pw_changed + pw_max_life) < entries->pw_expiration) + entries->pw_expiration = last_pw_changed + pw_max_life; + } else + entries->pw_expiration = last_pw_changed + pw_max_life; + } + } + + cleanup: + ldap_msgfree(result); + + if (*nentries == 0 || st != 0) + krb5_dbe_free_contents(context, entries); + + if (filter) + free (filter); + + if (DN) + ldap_memfree (DN); + + for (; ntrees; --ntrees) + if (subtree[ntrees-1]) + free (subtree[ntrees-1]); + + if (userinfo_tl_data.tl_data_contents) + free(userinfo_tl_data.tl_data_contents); + + if (ldap_server_handle) + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + + if (user) + free(user); + + if (modname) + free(modname); + + if (parsed_mod_name) + krb5_free_principal(context, parsed_mod_name); + + if (pwdpolicydn) + free(pwdpolicydn); + + if (policydn) + free(policydn); + + return st; +} + +typedef struct _xargs_t { + int ptype; + char *dn; + krb5_boolean dn_from_kbd; + char *containerdn; + char *tktpolicydn; +}xargs_t; + +static void +free_xargs(xargs) + xargs_t xargs; +{ + if (xargs.dn) + free (xargs.dn); + if (xargs.containerdn) + free (xargs.containerdn); + if (xargs.tktpolicydn) + free (xargs.tktpolicydn); +} + +static krb5_error_code +process_db_args(context, db_args, xargs) + krb5_context context; + char **db_args; + xargs_t *xargs; +{ + int i=0; + krb5_error_code st=0; + char errbuf[1024]; + char *arg=NULL, *arg_val=NULL; + unsigned int arg_val_len=0; + krb5_boolean uflag=FALSE, cflag=FALSE; + + if (db_args) + { + for (i=0; db_args[i]; ++i) { + arg = strtok_r(db_args[i], "=", &arg_val); + if(strcmp(arg, USERDN_ARG) == 0) { + if (cflag == TRUE) { + st = EINVAL; + krb5_set_error_message(context, st, "'containerdn' and 'userdn' can not both " + "be specified"); + goto cleanup; + } + if (xargs->dn != NULL || xargs->containerdn != NULL) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "%s option not supported", arg); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + if (strcmp(arg_val, "") == 0 || arg_val == NULL) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "%s option value missing", arg); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + arg_val_len = strlen(arg_val) + 1; + xargs->dn = calloc (1, arg_val_len); + if (xargs->dn == NULL) { + st = ENOMEM; + goto cleanup; + } + uflag = TRUE; + xargs->ptype = KDB_USER_PRINCIPAL; + xargs->dn_from_kbd = TRUE; + memcpy(xargs->dn, arg_val, arg_val_len); + } else if (strcmp(arg, CONTAINERDN_ARG) == 0) { + if (uflag == TRUE) { + st = EINVAL; + krb5_set_error_message(context, st, "'containerdn' and 'userdn' can not both " + "be specified"); + goto cleanup; + } + if (xargs->dn != NULL || xargs->containerdn != NULL) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "%s option not supported", arg); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + if (strcmp(arg_val, "") == 0 || arg_val == NULL) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "%s option value missing", arg); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + arg_val_len = strlen(arg_val) + 1; + xargs->containerdn = calloc (1, arg_val_len); + if (xargs->containerdn == NULL) { + st = ENOMEM; + goto cleanup; + } + cflag = TRUE; + xargs->ptype = KDB_SERVICE_PRINCIPAL; + xargs->dn_from_kbd = TRUE; + memcpy(xargs->containerdn, arg_val, arg_val_len); + } else if (strcmp(arg, TKTPOLICYDN_ARG) == 0) { + if (arg_val == NULL) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "%s option value missing", arg); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + arg_val_len = strlen(arg_val) + 1; + xargs->tktpolicydn = calloc (1, arg_val_len); + if (xargs->tktpolicydn == NULL) { + st = ENOMEM; + goto cleanup; + } + memcpy(xargs->tktpolicydn, arg_val, arg_val_len); + + } else { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "unknown option: %s", arg); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + } + } + cleanup: + return st; +} + +krb5_error_code +krb5_ldap_put_principal(context, entries, nentries, db_args) + krb5_context context; + krb5_db_entry *entries; + register int *nentries; /* number of entry structs to update */ + char **db_args; +{ + int i=0, l=0, plen=0; + krb5_error_code st=0, tempst=0; + LDAP *ld=NULL; + LDAPMessage *result=NULL, *ent=NULL; + char *user=NULL, *subtree=NULL; + char **values=NULL, *strval[10]={NULL}, errbuf[1024]; + struct berval **bersecretkey=NULL; + LDAPMod **mods=NULL; + krb5_boolean dnfound=TRUE, tktpolicy_set=FALSE; + krb5_tl_data *tl_data=NULL; + krb5_key_data **keys=NULL; + KEY *oldkeys=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 *oldpolicydn = NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + SETUP_CONTEXT(); + if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL) + return EINVAL; + + /* get ldap handle */ + GET_HANDLE(); + + for (i=0; i < *nentries; ++i, ++entries) { + if (is_principal_in_realm(ldap_context, entries->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 (entries->princ) { + if (((st=krb5_unparse_name(context,entries->princ, &user)) !=0) || + ((st=krb5_ldap_unparse_principal_name(user)) != 0)) + goto cleanup; + plen = strlen(user); + } + xargs.ptype = KDB_SERVICE_PRINCIPAL; + if (((st=krb5_get_princ_type(context, entries, &(xargs.ptype))) != 0) || + ((st=krb5_get_userdn(context, entries, &(xargs.dn))) != 0) || + ((st=krb5_get_secretkeys(context, entries, &oldkeys)) != 0)) + goto cleanup; + + if ((st=process_db_args(context, db_args, &xargs)) != 0) + goto cleanup; + + if (xargs.dn == NULL) { /* creation of service principal */ + if (xargs.ptype == KDB_USER_PRINCIPAL) { + st = EINVAL; + krb5_set_error_message(context, st, "User DN is missing"); + goto cleanup; + } + + /* get the subtree information */ + if (entries->princ->length == 2 && entries->princ->data[0].length == strlen("krbtgt") && + strncmp(entries->princ->data[0].data, "krbtgt", entries->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; + sprintf(errbuf, "'%s' not found: ", xargs.containerdn); + prepend_err_str(context, errbuf, st, ost); + } + goto cleanup; + } + subtree = strdup(xargs.containerdn); + } else if (ldap_context->lrparams->subtree && strlen(ldap_context->lrparams->subtree) != 0) { + subtree = strdup(ldap_context->lrparams->subtree); + } else { + subtree = strdup(ldap_context->lrparams->realmdn); + } + CHECK_NULL(subtree); + + xargs.dn = malloc(strlen("krbprincipalname=") + strlen(user) + strlen(",") + + strlen(subtree) + 1); + CHECK_NULL(xargs.dn); + sprintf(xargs.dn, "krbprincipalname=%s,%s", user, subtree); + + } + + if (xargs.dn_from_kbd == TRUE) { + /* make sure the DN falls in the subtree */ + int tre=0, dnlen=0, subtreelen=0, ntrees=0; + char *subtreelist[2]={NULL}; + krb5_boolean outofsubtree=TRUE; + + /* 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 (xargs.dn); + subtreelen = strlen(subtreelist[tre]); + if ((dnlen > subtreelen) && (strcasecmp((xargs.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; + } + } + + /* check if the DN exists */ + { + char *attributes[]={"krbpolicyreference", NULL}; + + LDAP_SEARCH_1(xargs.dn, LDAP_SCOPE_BASE, 0, attributes,IGNORE_STATUS); + if (st == LDAP_NO_SUCH_OBJECT) { + dnfound = FALSE; + st = LDAP_SUCCESS; + } else if (st == LDAP_SUCCESS) { + ent = ldap_first_entry(ld, result); + if (ent != NULL) { + if ((values=ldap_get_values(ld, ent, "krbpolicyreference")) != NULL) { + tktpolicy_set = TRUE; + ldap_value_free(values); + } + } + ldap_msgfree(result); + } else { + st = set_ldap_error(context, st, OP_SEARCH); + goto cleanup; + } + } + + if (dnfound == FALSE) { /* create a new object */ + if (xargs.ptype == KDB_USER_PRINCIPAL) { + memset(strval, 0, sizeof(strval)); + strval[0] = "inetorgperson"; + strval[1] = "Person"; + strval[2] = "krbprincipalaux"; + strval[3] = "krbpolicyaux"; + strval[4] = "krbpwdpolicyrefaux"; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + values = ldap_explode_dn(xargs.dn, 1); + if (values == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "Invalid DN"); + goto cleanup; + } + memset(strval, 0, sizeof(strval)); + strval[0] = values[0]; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0) { + ldap_value_free(values); + goto cleanup; + } + /* surname is set same as the cn */ + if ((st=krb5_add_str_mem_ldap_mod(&mods, "Surname", LDAP_MOD_ADD, strval)) != 0) { + ldap_value_free(values); + goto cleanup; + } + ldap_value_free(values); + } else { + memset(strval, 0, sizeof(strval)); + strval[0] = "krbprincipal"; + strval[1] = "krbprincipalaux"; + strval[2] = "krbpolicyaux"; + strval[3] = "krbpwdpolicyrefaux"; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + } + } else { /* update the objectclass attribute if any of these is missing */ + char *attrvalues[] = {"krbprincipalaux", "krbpolicyaux", "krbpwdpolicyrefaux", NULL}; + int p, q, r=0, amask=0; + + if ((st=checkattributevalue(ld, xargs.dn, "objectclass", attrvalues, &amask)) != 0) { + st = KRB5_KDB_UK_RERROR; + goto cleanup; + } + memset(strval, 0, sizeof(strval)); + for(p=1, q=0; p<=4; 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 (entries->mask & KDB_MAX_LIFE) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entries->max_life)) != 0) + goto cleanup; + } + + if (entries->mask & KDB_MAX_RLIFE) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE, + entries->max_renewable_life)) != 0) + goto cleanup; + } + + if (entries->mask & KDB_ATTRIBUTES) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE, + entries->attributes)) != 0) + goto cleanup; + } + + if (entries->mask & KDB_PRINCIPAL) { + memset(strval, 0, sizeof(strval)); + strval[0] = user; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + } + + if (entries->mask & KDB_PRINC_EXPIRE_TIME) { + memset(strval, 0, sizeof(strval)); + if ((strval[0]=getstringtime(entries->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 (entries->mask & KDB_PW_EXPIRATION) { + memset(strval, 0, sizeof(strval)); + if ((strval[0]=getstringtime(entries->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 (entries->mask & KDB_POLICY) { + for(tl_data=entries->tl_data; tl_data; tl_data=tl_data->tl_data_next) { + if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) { + memset(&princ_ent, 0, sizeof(princ_ent)); + /* 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 & KDB_POLICY) { + memset(strval, 0, sizeof(strval)); + strval[0] = princ_ent.policy; + 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; + } + } + + if (entries->mask & KDB_POLICY_CLR) { + memset(strval, 0, sizeof(strval)); + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, strval)) != 0) + goto cleanup; + } + + if (entries->mask & KDB_KEY_DATA || entries->mask & KDB_KVNO) { + int kcount=0, zero=0, salttype=0, totalkeys=0; + char *currpos=NULL, *krbsecretkey=NULL; + + /* delete the old keys */ + if (oldkeys) { + if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbsecretkey", LDAP_MOD_DELETE | LDAP_MOD_BVALUES, + oldkeys->keys)) != 0) + goto cleanup; + } + + bersecretkey = malloc (sizeof(struct berval *) * (entries->n_key_data + 1)); + CHECK_NULL(bersecretkey); + memset(bersecretkey, 0, sizeof(struct berval *) * (entries->n_key_data + 1)); + + keys = malloc (sizeof (krb5_key_data *) * entries->n_key_data + 1); + CHECK_NULL(keys); + memset(keys, 0, (sizeof (krb5_key_data *) * entries->n_key_data + 1)); + for (kcount=0; kcount < entries->n_key_data; ++kcount) + keys[kcount] = entries->key_data+kcount; + totalkeys = entries->n_key_data; + + kcount = 0; + while (totalkeys) { + int noofkeys=0, currkvno=0, currkvno_org=0, rlen=0; + krb5_timestamp last_pw_changed=0; + + krbsecretkey = malloc (MAX_KEY_LENGTH); + CHECK_NULL(krbsecretkey); + memset(krbsecretkey, 0, MAX_KEY_LENGTH); + currpos = krbsecretkey; + rlen = MAX_KEY_LENGTH; + + STORE16_INT(currpos, plen); /* principal len */ + currpos +=2; + rlen -=2; + + for (l=0; l < entries->n_key_data; ++l) + if (keys[l] != NULL) { + currkvno = keys[l]->key_data_kvno; + break; + } + + currkvno_org = currkvno; + STORE16_INT(currpos, currkvno); /* principal key version */ + currpos +=2; + rlen -=2; + + memset(currpos, 0, 2); /* master key version */ + currpos +=2; + rlen -=2; + + if ((st=krb5_dbe_lookup_last_pwd_change(context, entries, &last_pw_changed)) != 0) + goto cleanup; + STORE32_INT(currpos, last_pw_changed); /* last pwd change */ + currpos += 4; + rlen -=4; + + for (noofkeys=0; l < entries->n_key_data; ++l) + if (keys[l] && keys[l]->key_data_kvno == currkvno_org) + ++noofkeys; + + STORE16_INT(currpos, noofkeys); /* number of keys */ + currpos +=2; + rlen -=2; + + /* key type, key length, salt type and salt type */ + for (l=0; l<entries->n_key_data; ++l) { + if ( keys[l] && keys[l]->key_data_kvno == currkvno_org) { + STORE16_INT(currpos, keys[l]->key_data_type[0]); + currpos +=2; + rlen -=2; + STORE16_INT(currpos, keys[l]->key_data_length[0]); + currpos +=2; + rlen -=2; + + STORE16_INT(currpos, keys[l]->key_data_type[1]); + currpos +=2; + rlen -=2; + salttype = keys[l]->key_data_type[1]; + if (salttype==KRB5_KDB_SALTTYPE_NOREALM || salttype==KRB5_KDB_SALTTYPE_ONLYREALM) { + STORE16_INT(currpos, zero); + } else { + STORE16_INT(currpos, keys[l]->key_data_length[1]); + } + currpos +=2; + rlen -=2; + } + } + if (plen > rlen) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "Insufficient buffer while storing the key of principal %s", user); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + memcpy(currpos, user, (unsigned int)plen); /* principal name */ + currpos +=plen; + rlen -=plen; + + /* key value, salt value */ + for(l=0; l<entries->n_key_data; ++l) { + if (keys[l] && keys[l]->key_data_kvno == currkvno_org) { + if (keys[l]->key_data_length[0]) { + if (keys[l]->key_data_length[0] > rlen) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "Insufficient buffer while storing the key of principal %s", user); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + memcpy(currpos, keys[l]->key_data_contents[0], keys[l]->key_data_length[0]); + currpos += keys[l]->key_data_length[0]; + rlen -= keys[l]->key_data_length[0]; + } + + salttype = keys[l]->key_data_type[1]; + if (keys[l]->key_data_length[1] && (!(salttype==KRB5_KDB_SALTTYPE_NOREALM + || salttype==KRB5_KDB_SALTTYPE_ONLYREALM))) { + if (keys[l]->key_data_length[1] > rlen) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "Insufficient buffer while storing the key of principal %s", user); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + memcpy(currpos, keys[l]->key_data_contents[1], keys[l]->key_data_length[1]); + currpos += keys[l]->key_data_length[1]; + rlen -= keys[l]->key_data_length[1]; + } + keys[l] = NULL; + } + } + bersecretkey[kcount] = malloc (sizeof (struct berval)); + CHECK_NULL(bersecretkey[kcount]); + bersecretkey[kcount]->bv_len = currpos - krbsecretkey; + bersecretkey[kcount++]->bv_val = krbsecretkey; + totalkeys = totalkeys - noofkeys; + } + if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbsecretkey", + LDAP_MOD_ADD | LDAP_MOD_BVALUES, bersecretkey)) != 0) + goto cleanup; + + if (!(entries->mask & KDB_PRINCIPAL)){ + memset(strval, 0, sizeof(strval)); + if ((strval[0]=getstringtime(entries->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]); + } + } /* Modify Key data ends here */ + + /* Directory specific attribute */ + if (xargs.tktpolicydn != NULL) { + int tmask=0, tkttree = 0, subtreednlen = 0, ntre = 0, tktdnlen = 0; + + char *subtreednlist[2]={NULL}; + krb5_boolean dnoutofsubtree=TRUE; + + if ((st=krb5_get_policydn(context, entries, &oldpolicydn)) != 0) + goto cleanup; + + if (strlen(xargs.tktpolicydn) != 0) { + st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask); + CHECK_CLASS_VALIDITY(st, tmask, "ticket policy object value: "); + + memset(strval, 0, sizeof(strval)); + strval[0] = xargs.tktpolicydn; + if ((st = krb5_get_subtree_info(ldap_context, subtreednlist, &ntre)) != 0) + goto cleanup; + + for( tkttree=0; tkttree<ntre; ++tkttree ) { + if( subtreednlist[tkttree] == NULL || strlen(subtreednlist[tkttree]) == 0 ) { + dnoutofsubtree = FALSE; + break; + } else { + tktdnlen = strlen (xargs.tktpolicydn); + subtreednlen = strlen(subtreednlist[tkttree]); + + if ((tktdnlen > subtreednlen) && (strcasecmp((xargs.tktpolicydn + tktdnlen - subtreednlen), subtreednlist[tkttree]) == 0)) { + dnoutofsubtree = FALSE; + break; + } + } + } + for( tkttree=0; tkttree < ntre; ++tkttree ) { + free( subtreednlist[tkttree] ); + } + if( dnoutofsubtree == TRUE ) { + st = EINVAL; + prepend_err_str(context,"Ticket Policy DN is out of the realm subtree",st,st); + goto cleanup; + } + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpolicyreference", LDAP_MOD_REPLACE, strval)) != 0) + goto cleanup; + if(oldpolicydn != NULL){ + if(strncmp(xargs.tktpolicydn,oldpolicydn,strlen(xargs.tktpolicydn)) != 0) + { + if ((st = krb5_ldap_change_count(context, oldpolicydn,2 ))) + goto cleanup; + } + } + + if ((st = krb5_ldap_change_count(context, xargs.tktpolicydn,1 ))) + goto cleanup; + } else { + /* if xargs.tktpolicydn is a empty string, then delete already existing krbpolicyreference attr */ + if (tktpolicy_set == FALSE) { /* if the attribute is not present then abort */ + st = EINVAL; + prepend_err_str(context,"'ticketpolicydn' empty",st,st); + goto cleanup; + } else { + memset(strval, 0, sizeof(strval)); + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpolicyreference", LDAP_MOD_DELETE, strval)) != 0) + goto cleanup; + } + } + + } + if (dnfound == TRUE) { + if (mods == NULL) { + goto cleanup; + } + st=ldap_modify_s(ld, xargs.dn, mods); + if (st != LDAP_SUCCESS) { + sprintf(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; + } + } + else { + st=ldap_add_s(ld, xargs.dn, mods); + if (st != LDAP_SUCCESS) { + sprintf(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; + } + } + + } + + cleanup: + if (user) + free(user); + + free_xargs(xargs); + + 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); + + if (oldkeys) { + for (l=0; l < oldkeys->nkey; ++l) { + if (oldkeys->keys[l]->bv_val) + free (oldkeys->keys[l]->bv_val); + free (oldkeys->keys[l]); + } + free (oldkeys->keys); + free (oldkeys); + } + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + *nentries = i; + return(st); +} + +static krb5_error_code +krb5_read_tkt_policyreference(context, ldap_context, entries, policydn) + krb5_context context; + krb5_ldap_context *ldap_context; + krb5_db_entry *entries; + char *policydn; +{ + krb5_error_code st=0; + unsigned int mask=0, omask=0; + int tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR); + krb5_ldap_policy_params *tktpoldnparam=NULL; + + if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0) + goto cleanup; + + if ((mask & tkt_mask) != tkt_mask) { + if (policydn != NULL) { + st = krb5_ldap_read_policy(context, policydn, &tktpoldnparam, &omask); + if (st && st != KRB5_KDB_NOENTRY) { + prepend_err_str(context, "Error reading ticket policy. ", st, st); + goto cleanup; + } + + st = 0; /* reset the return status */ + } + + if ((mask & KDB_MAX_LIFE_ATTR) == 0) { + if ((omask & KDB_MAX_LIFE_ATTR) == KDB_MAX_LIFE_ATTR) + entries->max_life = tktpoldnparam->maxtktlife; + else if (ldap_context->lrparams->max_life) + entries->max_life = ldap_context->lrparams->max_life; + else if(ldap_context->krbcontainer->max_life) + entries->max_life = ldap_context->krbcontainer->max_life; + else + entries->max_life = KRB5_KDB_MAX_LIFE; + } + + if ((mask & KDB_MAX_RLIFE_ATTR) == 0) { + if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR) + entries->max_renewable_life = tktpoldnparam->maxrenewlife; + else if (ldap_context->lrparams->max_renewable_life) + entries->max_renewable_life = ldap_context->lrparams->max_renewable_life; + else if(ldap_context->krbcontainer->max_renewable_life) + entries->max_renewable_life = ldap_context->krbcontainer->max_renewable_life; + else + entries->max_renewable_life = KRB5_KDB_MAX_RLIFE; + } + + if ((mask & KDB_TKT_FLAGS_ATTR) == 0) { + if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR) + entries->attributes = tktpoldnparam->tktflags; + else if (ldap_context->lrparams->tktflags) + entries->attributes |= ldap_context->lrparams->tktflags; + else if(ldap_context->krbcontainer->tktflags) + entries->attributes |= ldap_context->krbcontainer->tktflags; + } + krb5_ldap_free_policy(context, tktpoldnparam); + } + + cleanup: + return st; +} + +static krb5_error_code +krb5_decode_krbsecretkey(context, entries, bvalues, userinfo_tl_data) + krb5_context context; + krb5_db_entry *entries; + struct berval **bvalues; + krb5_tl_data *userinfo_tl_data; +{ + char *user=NULL, *ptr=NULL, *pname=NULL, *currentkey=NULL, *currentsalt=NULL; + void *reallocptr=NULL; + int i=0, j=0, k=0, plen=0, noofkeys=0, ist_pkeyver=0, pkeyver=0, mkeyver=0, keylen=0; + krb5_key_data *key_data=NULL; + krb5_error_code st=0; + krb5_timestamp last_pw_changed=0; + + if ((st=krb5_unparse_name(context, entries->princ, &user)) != 0) + goto cleanup; + + for(i=0; bvalues[i] != NULL; ++i) { + + ptr = (char *) bvalues[i]->bv_val; + + /* check the consistency of the key */ + + if(bvalues[i]->bv_len < KEYHEADER) /* key smaller than the header size */ + continue; + + plen = PRINCIPALLEN(ptr); + if (NOOFKEYS(ptr) == 0) + continue; + + keylen = KEYHEADER + (8 * NOOFKEYS(ptr)); + if (bvalues[i]->bv_len < keylen) /* key or salt header info corrupted*/ + continue; + + keylen += plen; + if (bvalues[i]->bv_len < keylen) /* principal info corrupted */ + continue; + + for(k=0; k<NOOFKEYS(ptr); ++k) + keylen += KEYLENGTH(ptr, k) + SALTLENGTH(ptr, k); + + if (bvalues[i]->bv_len < keylen) /* key or salt values corrupted */ + continue; + + pname = PRINCIPALNAME(ptr); /* set pname to principalName field */ + + /* key doesn't belong to the principal */ + if (strncmp(user, pname, (unsigned) plen) != 0) + continue; + + /* Number of Principal Keys */ + noofkeys += NOOFKEYS(ptr); + + if ((st=store_tl_data(userinfo_tl_data, KDB_TL_KEYINFO, bvalues[i])) != 0) + goto cleanup; + + pkeyver = PKEYVER(ptr); /* Principal Key Version */ + mkeyver = MKEYVER(ptr); /* Master Key Version */ + + if (ist_pkeyver == 0 || pkeyver >= ist_pkeyver) { + ist_pkeyver = pkeyver; + /* last password changed */ + last_pw_changed = 0; + last_pw_changed += (ptr[6] & 0xFF) << 24; + last_pw_changed += (ptr[7] & 0xFF) << 16; + last_pw_changed += (ptr[8] & 0xFF) << 8; + last_pw_changed += (ptr[9] & 0xFF) << 0; + + if ((st=krb5_dbe_update_last_pwd_change(context, entries, + last_pw_changed)) != 0) + goto cleanup; + } + + reallocptr = key_data; + key_data = realloc(key_data, (sizeof(*key_data) * noofkeys)); + if (key_data == NULL) { + st = ENOMEM; + goto cleanup; + } + + currentkey = KEYBODY(ptr); + for (k=0; j<noofkeys; ++k, ++j) { + + key_data[j].key_data_ver = 1; + key_data[j].key_data_kvno = pkeyver; + + key_data[j].key_data_type[0] = KEYTYPE(ptr,k); /* get key type */ + key_data[j].key_data_length[0] = KEYLENGTH(ptr,k); /* get key length */ + key_data[j].key_data_type[1] = SALTTYPE(ptr,k); /* get salt type */ + key_data[j].key_data_length[1] = SALTLENGTH(ptr,k); /* get salt length */ + + key_data[j].key_data_contents[0] = malloc(key_data[j].key_data_length[0]); + if (key_data[j].key_data_contents[0] == NULL) { + st = ENOMEM; + goto cleanup; + } + memcpy(key_data[j].key_data_contents[0], currentkey, + key_data[j].key_data_length[0]); + + currentsalt = currentkey + key_data[j].key_data_length[0]; + if (key_data[j].key_data_length[1] != 0) { + + key_data[j].key_data_ver = 2; + key_data[j].key_data_contents[1] = malloc(key_data[j].key_data_length[1]); + if (key_data[j].key_data_contents[1] == NULL) { + st = ENOMEM; + goto cleanup; + } + memcpy(key_data[j].key_data_contents[1], currentsalt, + key_data[j].key_data_length[1]); + + } else if (key_data[j].key_data_type[1] == KRB5_KDB_SALTTYPE_NOREALM || + key_data[j].key_data_type[1] == KRB5_KDB_SALTTYPE_ONLYREALM) { + char *def_realm = NULL; + krb5_data norealmval; + + key_data[j].key_data_ver = 2; + switch(key_data[j].key_data_type[1]) { + case KRB5_KDB_SALTTYPE_ONLYREALM: + def_realm = entries->princ->realm.data; + key_data[j].key_data_length[1] = strlen (def_realm); + key_data[j].key_data_contents[1] = malloc (key_data[j].key_data_length[1]); + if (key_data[j].key_data_contents[1] == NULL) { + st = ENOMEM; + goto cleanup; + } + memcpy(key_data[j].key_data_contents[1], + def_realm, key_data[j].key_data_length[1]); + break; + + case KRB5_KDB_SALTTYPE_NOREALM: + memset(&norealmval, 0, sizeof(krb5_data)); + if ((st = krb5_principal2salt_norealm(context, entries->princ, + &norealmval)) != 0) { + goto cleanup; + } + + key_data[j].key_data_length[1] = norealmval.length; + key_data[j].key_data_contents[1] = (unsigned char *)norealmval.data; + break; + } + } else if (key_data[j].key_data_type[1] == KRB5_KDB_SALTTYPE_V4) { + key_data[j].key_data_contents[1] = NULL; + key_data[j].key_data_ver = 2; + } else { + key_data[j].key_data_contents[1] = NULL; + } + currentkey = currentsalt + key_data[j].key_data_length[1]; + } + entries->n_key_data = noofkeys; + entries->key_data = key_data; + } + + cleanup: + ldap_value_free_len(bvalues); + free (user); + return st; +} + +static char * +getstringtime(epochtime) + krb5_timestamp epochtime; +{ + struct tm tme; + char *strtime=NULL; + time_t posixtime = epochtime; + + strtime = calloc (50, 1); + if (strtime == NULL) + return NULL; + + if (gmtime_r(&posixtime, &tme) == NULL) + return NULL; + + strftime(strtime, 50, "%Y%m%d%H%M%SZ", &tme); + return strtime; +} + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c new file mode 100644 index 000000000..2cbb444e7 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c @@ -0,0 +1,307 @@ +/* + * lib/kdb/kdb_ldap/ldap_pwd_policy.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" +#include "kdb_ldap.h" +#include "ldap_pwd_policy.h" +#include "ldap_err.h" + +static char *password_policy_attributes[] = { "krbmaxpwdlife", "krbminpwdlife", "krbpwdmindiffchars", + "krbpwdminlength", "krbpwdhistorylength", "krbpwdpolicyrefcount", + NULL }; + +/* + * Function to create password policy object. + */ + +krb5_error_code +krb5_ldap_create_password_policy (context, policy) + krb5_context context; + osa_policy_ent_t policy; +{ + krb5_error_code st=0; + LDAP *ld=NULL; + LDAPMod **mods={NULL}; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + char **rdns=NULL, *strval[2]={NULL}; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + /* validate the input parameters */ + if (policy == NULL || policy->name == NULL) + return EINVAL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + /* get the first component of the dn to set the cn attribute */ + rdns = ldap_explode_dn(policy->name, 1); + if (rdns == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "Invalid password policy DN syntax"); + goto cleanup; + } + + strval[0] = rdns[0]; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + strval[0] = "krbPwdPolicy"; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + if (((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxpwdlife", LDAP_MOD_ADD, + (signed) policy->pw_max_life)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbminpwdlife", LDAP_MOD_ADD, + (signed) policy->pw_min_life)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpwdmindiffchars", LDAP_MOD_ADD, + (signed) policy->pw_min_classes)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpwdminlength", LDAP_MOD_ADD, + (signed) policy->pw_min_length)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpwdhistorylength", LDAP_MOD_ADD, + (signed) policy->pw_history_num)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpwdpolicyrefcount", LDAP_MOD_ADD, + (signed) policy->policy_refcnt)) != 0)) + goto cleanup; + + /* password policy object creation */ + if ((st=ldap_add_s(ld, policy->name, mods)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_ADD); + goto cleanup; + } + + cleanup: + if (rdns) + ldap_value_free(rdns); + + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return(st); +} + +/* + * Function to modify password policy object. + */ + +krb5_error_code +krb5_ldap_put_password_policy (context, policy) + krb5_context context; + osa_policy_ent_t policy; +{ + krb5_error_code st=0; + LDAP *ld=NULL; + LDAPMod **mods=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + /* validate the input parameters */ + if (policy == NULL || policy->name == NULL) + return EINVAL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + if (((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxpwdlife", LDAP_MOD_REPLACE, + (signed) policy->pw_max_life)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbminpwdlife", LDAP_MOD_REPLACE, + (signed) policy->pw_min_life)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpwdmindiffchars", LDAP_MOD_REPLACE, + (signed) policy->pw_min_classes)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpwdminlength", LDAP_MOD_REPLACE, + (signed) policy->pw_min_length)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpwdhistorylength", LDAP_MOD_REPLACE, + (signed) policy->pw_history_num)) != 0) + || ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpwdpolicyrefcount", LDAP_MOD_REPLACE, + (signed) policy->policy_refcnt)) != 0)) + goto cleanup; + + /* modify the password policy object. */ + if ((st=ldap_modify_s(ld, policy->name, mods)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + + cleanup: + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return(st); +} + +krb5_error_code +krb5_ldap_get_password_policy (context, name, policy, cnt) + krb5_context context; + char *name; + osa_policy_ent_t *policy; + int *cnt; +{ + krb5_error_code st=0, tempst=0; + LDAP *ld=NULL; + LDAPMessage *result=NULL,*ent=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + /* validate the input parameters */ + if(name == NULL) + return EINVAL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + *cnt = 0; + *(policy) = (osa_policy_ent_t) malloc(sizeof(osa_policy_ent_rec)); + if (*policy == NULL) { + st = ENOMEM; + goto cleanup; + } + memset(*policy, 0, sizeof(osa_policy_ent_rec)); + + LDAP_SEARCH(name, LDAP_SCOPE_BASE, "(objectclass=krbPwdPolicy)", password_policy_attributes); + *cnt = 1; + (*policy)->name = name; + (*policy)->version = 1; + + ent=ldap_first_entry(ld, result); + if (ent != NULL) { + krb5_ldap_get_value(ld, ent, "krbmaxpwdlife", &((*policy)->pw_max_life)); + krb5_ldap_get_value(ld, ent, "krbminpwdlife", &((*policy)->pw_min_life)); + krb5_ldap_get_value(ld, ent, "krbpwdmindiffchars", &((*policy)->pw_min_classes)); + krb5_ldap_get_value(ld, ent, "krbpwdminlength", &((*policy)->pw_min_length)); + krb5_ldap_get_value(ld, ent, "krbpwdhistorylength", &((*policy)->pw_history_num)); + krb5_ldap_get_value(ld, ent, "krbpwdpolicyrefcount", &((*policy)->policy_refcnt)); + } + +cleanup: + ldap_msgfree(result); + if (st != 0) { + if (*policy != NULL) { + free (*policy); + *policy = NULL; + } + } + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + +krb5_error_code +krb5_ldap_delete_password_policy (context, policy) + krb5_context context; + char *policy; +{ + krb5_error_code st=0; + LDAP *ld=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + /* validate the input parameters */ + if(policy == NULL) + return EINVAL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + if((st=ldap_delete_s(ld, policy)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_DEL); + goto cleanup; + } + +cleanup: + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + +krb5_error_code +krb5_ldap_iterate_password_policy(context, match_expr, func, func_arg) + krb5_context context; + char *match_expr; + void (*func) (krb5_pointer, osa_policy_ent_t ); + krb5_pointer func_arg; +{ + osa_policy_ent_rec *entry=NULL; + char *attrs[] = { "cn", NULL }; + krb5_error_code st=0, tempst=0; + LDAP *ld=NULL; + LDAPMessage *result=NULL, *ent=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + char *policy_dn=NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + SETUP_CONTEXT(); + GET_HANDLE(); + + entry = (osa_policy_ent_t) malloc(sizeof(osa_policy_ent_rec)); + CHECK_NULL(entry); + memset(entry, 0, sizeof(osa_policy_ent_rec)); + + LDAP_SEARCH(NULL, LDAP_SCOPE_SUBTREE, "(objectclass=krbpwdpolicy)", attrs); + for(ent=ldap_first_entry(ld, result); ent != NULL; ent=ldap_next_entry(ld, ent)) { + if ((policy_dn=ldap_get_dn(ld, ent)) == NULL) + continue; + entry->name = policy_dn; + (*func)(func_arg, entry); + ldap_memfree(policy_dn); + } + ldap_msgfree(result); + + cleanup: + if (entry) + free (entry); + + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + +void +krb5_ldap_free_password_policy (context, entry) + krb5_context context; + osa_policy_ent_t entry; +{ + if(entry) + free(entry); + return; +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.h new file mode 100644 index 000000000..49fa85ecb --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.h @@ -0,0 +1,54 @@ +/* + * lib/kdb/kdb_ldap/ldap_pwd_policy.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef _LDAP_KRBPWDPOLICY_H_ +#define _LDAP_KRBPWDPOLICY_H_ + +krb5_error_code +krb5_ldap_get_password_policy (krb5_context , char *, osa_policy_ent_t *, int *); + +krb5_error_code +krb5_ldap_create_password_policy (krb5_context , osa_policy_ent_t ); + +krb5_error_code +krb5_ldap_put_password_policy ( krb5_context kcontext, osa_policy_ent_t policy ); + +krb5_error_code +krb5_ldap_delete_password_policy ( krb5_context kcontext, char *policy ); + +krb5_error_code +krb5_ldap_iterate_password_policy(krb5_context, char *, + void (*) (krb5_pointer, osa_policy_ent_t ), + krb5_pointer); + +void +krb5_ldap_free_password_policy( krb5_context kcontext, osa_policy_ent_t entry ); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c new file mode 100644 index 000000000..2ac8219c1 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c @@ -0,0 +1,1650 @@ +/* + * lib/kdb/kdb_ldap/ldap_realm.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" +#include "ldap_realm.h" +#include "ldap_principal.h" +#include "ldap_err.h" + +#define END_OF_LIST -1 +char *realm_attributes[] = {"krbSearchScope","krbSubTree", + "krbMaxTicketLife", "krbMaxRenewableAge", + "krbTicketFlags", "krbDefaultEncType", + "krbDefaultSaltType", "krbUpEnabled", + "krbPolicyReference", "krbSupportedEncTypes", + "krbSupportedSaltTypes", "krbLdapServers", + "krbKdcServers", "krbAdmServers", + "krbPwdServers", NULL}; + + +char *policy_attributes[] = { "krbMaxTicketLife", + "krbMaxRenewableAge", + "krbTicketFlags", + NULL }; + + + +char *policyclass[] = { "krbPolicy", NULL }; +char *kdcclass[] = { "krbKdcService", NULL }; +char *adminclass[] = { "krbAdmService", NULL }; +char *pwdclass[] = { "krbPwdService", NULL }; +char *subtreeclass[] = { "Organization", "OrganizationalUnit", "Domain", + "Country", "Locality", NULL }; + +int supportedenctypes[] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD4, ENCTYPE_DES_CBC_MD5, + ENCTYPE_DES3_CBC_SHA1, ENCTYPE_AES128_CTS_HMAC_SHA1_96, + ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_ARCFOUR_HMAC, -1}; + +int supportedsalttypes[] = { KRB5_KDB_SALTTYPE_NORMAL, KRB5_KDB_SALTTYPE_V4, + KRB5_KDB_SALTTYPE_NOREALM, KRB5_KDB_SALTTYPE_ONLYREALM, + KRB5_KDB_SALTTYPE_SPECIAL, -1}; + + +char *krbContainerRefclass[] = { "krbContainerRefAux", NULL}; + + +static void +ignore_duplicates(int_list) + int *int_list; +{ + int i=0, j=0, scount=0; + + for (i=0; int_list[i] != END_OF_LIST; scount=i++) + ; + + for (i=0; i <= scount; ++i) { + if (i > 0 && int_list[i] == int_list[i-1]) { + for (j=i; j<=scount; ++j) + int_list[j-1] = int_list[j]; + int_list[scount] = END_OF_LIST; + --scount; + --i; + continue; + } + } +} + +/* + * list realms from eDirectory + */ + +/* + * Function to remove all special characters from a string (rfc2254). + * Use whenever exact matching is to be done ... + */ +static char * +ldap_filter_correct (unsigned char *in, unsigned int len) +{ + int i, count; + char *out, *ptr; + + for (i = 0, count = 0; i < len; i++) + switch (in[i]) { + case '*': + case '(': + case ')': + case '\\': + case '\0': + count ++; + } + + out = (char *)malloc((len + (count * 2) + 1) * sizeof (char)); + assert (out != NULL); + memset(out, 0, len + (count * 2) + 1); + + for (i = 0, ptr = out; i < len; i++) + switch (in[i]) { + case '*': + ptr[0] = '\\'; + ptr[1] = '2'; + ptr[2] = 'a'; + ptr += 3; + break; + case '(': + ptr[0] = '\\'; + ptr[1] = '2'; + ptr[2] = '8'; + ptr += 3; + break; + case ')': + ptr[0] = '\\'; + ptr[1] = '2'; + ptr[2] = '9'; + ptr += 3; + break; + case '\\': + ptr[0] = '\\'; + ptr[1] = '5'; + ptr[2] = 'c'; + ptr += 3; + break; + case '\0': + ptr[0] = '\\'; + ptr[1] = '0'; + ptr[2] = '0'; + ptr += 3; + break; + default: + ptr[0] = in[i]; + ptr += 1; + break; + } + + /* ptr[count - 1] = '\0'; */ + + return out; +} + +static int principal_in_realm_2(krb5_principal principal, char *realm) { + /* Cross realm trust ... */ + if (principal->length == 2 && + principal->data[0].length == sizeof ("krbtgt") && + strncasecmp (principal->data[0].data, "krbtgt", sizeof ("krbtgt")) && + principal->data[1].length == strlen (realm) && + strncasecmp (principal->data[1].data, realm, strlen (realm))) + return 0; + + if (strlen(realm) != principal->realm.length) + return 1; + + if (strncasecmp(realm, principal->realm.data, principal->realm.length) != 0) + return 1; + + return 0; +} + +/* + * Lists the realms in the Directory. + */ + +krb5_error_code +krb5_ldap_list_realm(context, realms) + krb5_context context; + char ***realms; +{ + char **values = NULL; + unsigned int i = 0, count = 0; + krb5_error_code st = 0, tempst = 0; + LDAP *ld = NULL; + LDAPMessage *result = NULL, *ent = NULL; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context = NULL; + krb5_ldap_server_handle *ldap_server_handle = NULL; + + SETUP_CONTEXT (); + + /* get the kerberos container DN information */ + if (ldap_context->krbcontainer == NULL) { + if ((st = krb5_ldap_read_krbcontainer_params(context, + &(ldap_context->krbcontainer))) != 0) + goto cleanup; + } + + /* get ldap handle */ + GET_HANDLE (); + + { + char *cn[] = {"cn", NULL}; + LDAP_SEARCH(ldap_context->krbcontainer->DN, + LDAP_SCOPE_ONELEVEL, + "(objectclass=krbRealmContainer)", + cn); + } + + *realms = NULL; + + count = ldap_count_entries (ld, result); + if(count == -1){ + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &st); + st = set_ldap_error (context, st, OP_SEARCH); + goto cleanup; + } + + *realms = calloc(count+1, sizeof (char *)); + CHECK_NULL(*realms); + + for (ent = ldap_first_entry(ld, result), count = 0; ent != NULL; + ent = ldap_next_entry(ld, ent)) { + + if ((values = ldap_get_values (ld, ent, "cn")) != NULL) { + + (*realms)[count] = strdup(values[0]); + CHECK_NULL((*realms)[count]); + count += 1; + + ldap_value_free(values); + } + } /* for (ent= ... */ + ldap_msgfree(result); + + cleanup: + + /* some error, free up all the memory */ + if (st != 0) { + if (*realms) { + for (i=0; (*realms)[i] != NULL; ++i) { + free ((*realms)[i]); + } + free (*realms); + *realms = NULL; + } + } + + /* If there are no elements, still return a NULL terminated array */ + + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * Delete the realm along with the principals belonging to the realm in the Directory. + */ + +krb5_error_code +krb5_ldap_delete_realm (context, lrealm) + krb5_context context; + char *lrealm; +{ + LDAP *ld = NULL; + krb5_error_code st = 0, tempst=0; + char **values=NULL, *subtrees[2]={NULL};; + LDAPMessage *result_arr[3]={NULL}, *result = NULL, *ent = NULL; + krb5_principal principal; + int l=0, ntree=0, i=0, j=0, mask=0; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context = NULL; + krb5_ldap_server_handle *ldap_server_handle = NULL; + krb5_ldap_realm_params *rparam=NULL; + + SETUP_CONTEXT (); + + if (lrealm == NULL) { + st = EINVAL; + krb5_set_error_message (context, st, "Realm information not available"); + goto cleanup; + } + + if ((st=krb5_ldap_read_realm_params(context, lrealm, &rparam, &mask)) != 0) + goto cleanup; + + /* get ldap handle */ + GET_HANDLE (); + + /* delete all the principals belonging to the realm in the tree */ + { + char *attr[] = {"krbprincipalname", NULL}, *realm=NULL, filter[256]; + krb5_ldap_context lcontext; + + realm = ldap_filter_correct (lrealm, strlen (lrealm)); + assert (sizeof (filter) >= sizeof ("(krbprincipalname=)") + + strlen (realm) + 2 /* "*@" */ + 1); + + sprintf (filter, "(krbprincipalname=*@%s)", realm); + free (realm); + + /* LDAP_SEARCH(NULL, LDAP_SCOPE_SUBTREE, filter, attr); */ + memset(&lcontext, 0, sizeof(krb5_ldap_context)); + lcontext.lrparams = rparam; + if ((st=krb5_get_subtree_info(&lcontext, subtrees, &ntree)) != 0) + goto cleanup; + + for (l=0; l < ntree; ++l) { + LDAP_SEARCH(subtrees[l], rparam->search_scope, filter, attr); + result_arr[l] = result; + } + } + + /* NOTE: Here all the principals should be cached and the ldap handle should be freed, + * as a DAL-LDAP interface is called right down here. Caching might be constrained by + * availability of the memory. The caching is not done, however there would be limit + * on the minimum number of handles for a server and it is 2. As the DAL-LDAP is not + * thread-safe this should suffice. + */ + for (j=0; (result=result_arr[j]) != NULL; ++j) { + for(ent = ldap_first_entry (ld, result); ent != NULL; + ent = ldap_next_entry (ld, ent)) { + if ((values = ldap_get_values(ld, ent, "krbPrincipalName")) != NULL) { + for (i = 0; values[i] != NULL; ++i) { + krb5_parse_name(context, values[i], &principal); + if (principal_in_realm_2(principal, lrealm) == 0) { + int nent = 0; + if ((st=krb5_ldap_delete_principal(context, principal, + &nent)) != LDAP_SUCCESS) + goto cleanup; + } + krb5_free_principal(context, principal); + } + ldap_value_free(values); + } + } + ldap_msgfree(result); + } + + /* Delete the realm object */ + if ((st=ldap_delete_s(ld, ldap_context->lrparams->realmdn)) != LDAP_SUCCESS) { + int ost = st; + st = translate_ldap_error (st, OP_DEL); + krb5_set_error_message (context, st, "Realm Delete FAILED: %s", + ldap_err2string(ost)); + } + + cleanup: + for (l=0; l < ntree; ++l) { + if (subtrees[l]) + free (subtrees[l]); + } + krb5_ldap_free_realm_params(rparam); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + +static int compare (const void *i, const void *j) { + if (*(const krb5_int32 *)i > *(const krb5_int32 *)j) + return 1; + + if (*(const krb5_int32 *)i < *(const krb5_int32 *)j) + return -1; + + return 0; +} + + +/* + * Modify the realm attributes in the Directory. + */ + +krb5_error_code +krb5_ldap_modify_realm(context, rparams, mask) + krb5_context context; + krb5_ldap_realm_params *rparams; + int mask; +{ + LDAP *ld=NULL; + krb5_error_code st=0; + char *strval[5]={NULL}; +#ifdef HAVE_EDIRECTORY + char **values=NULL; + char **oldkdcservers=NULL, **oldadminservers=NULL, **oldpasswdservers=NULL; + LDAPMessage *result=NULL, *ent=NULL; + int count=0; + char errbuf[1024]; +#endif + LDAPMod **mods = NULL; + int i=0, oldmask=0, objectmask=0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + if (mask == 0) + return 0; + + if (rparams == NULL) { + st = EINVAL; + return st; + } + + SETUP_CONTEXT (); + + /* Check validity of arguments */ + if (ldap_context->krbcontainer == NULL || + rparams->tl_data == NULL || + rparams->tl_data->tl_data_contents == NULL || + ((mask & LDAP_REALM_SUBTREE) && rparams->subtree == NULL) || + /* This has to be fixed ... */ + ((mask & LDAP_REALM_DEFENCTYPE) && rparams->suppenctypes == NULL) || + ((mask & LDAP_REALM_DEFSALTTYPE) && rparams->suppsalttypes == NULL) || +#ifdef HAVE_EDIRECTORY + ((mask & LDAP_REALM_KDCSERVERS) && rparams->kdcservers == NULL) || + ((mask & LDAP_REALM_ADMINSERVERS) && rparams->adminservers == NULL) || + ((mask & LDAP_REALM_PASSWDSERVERS) && rparams->passwdservers == NULL) || +#endif + 0) { + st = EINVAL; + goto cleanup; + } + + /* get ldap handle */ + GET_HANDLE (); + + /* get the oldmask obtained from the krb5_ldap_read_realm_params */ + { + void *voidptr=NULL; + + if ((st=decode_tl_data(rparams->tl_data, KDB_TL_MASK, &voidptr)) == 0) { + oldmask = *((int *) voidptr); + free (voidptr); + } else { + st = EINVAL; + krb5_set_error_message (context, st, "tl_data not available"); + return st; + } + } + + /* + * Sort the list of salt-types / enc-types ... just to eliminate duplicates + * later. + */ + { + if ((mask & LDAP_REALM_SUPPENCTYPE) && rparams->suppenctypes) { + for (i = 0; rparams->suppenctypes [i] != END_OF_LIST; i++){ + } + qsort ((void *)rparams->suppenctypes, (unsigned) i, sizeof(krb5_int32), compare); + } + if ((mask & LDAP_REALM_SUPPSALTTYPE) && rparams->suppsalttypes) { + for (i = 0; rparams->suppenctypes [i] != END_OF_LIST; i++){ + } + qsort ((void *)rparams->suppsalttypes, (unsigned) i, sizeof(krb5_int32), compare); + } + } + + /* SUBTREE ATTRIBUTE */ + if (mask & LDAP_REALM_SUBTREE) { + if (strlen(rparams->subtree) != 0) { + st = checkattributevalue(ld, rparams->subtree, "Objectclass", subtreeclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "subtree value: "); + } + memset(strval, 0, sizeof(strval)); + strval[0] = rparams->subtree; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtree", LDAP_MOD_REPLACE, + strval)) != 0) + goto cleanup; + } + + /* SEARCHSCOPE ATTRIBUTE */ + if (mask & LDAP_REALM_SEARCHSCOPE) { + if((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_REPLACE, + (rparams->search_scope == LDAP_SCOPE_ONELEVEL + || rparams->search_scope == LDAP_SCOPE_SUBTREE) ? + rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0) + goto cleanup; + } + + if (mask & LDAP_REALM_MAXRENEWLIFE) { + + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_REPLACE, + rparams->max_renewable_life)) != 0) + goto cleanup; + } + + /* krbMaxTicketLife ATTRIBUTE */ + + if (mask & LDAP_REALM_MAXTICKETLIFE) { + + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_REPLACE, + rparams->max_life)) != 0) + goto cleanup; + } + + /* krbTicketFlags ATTRIBUTE */ + + if (mask & LDAP_REALM_KRBTICKETFLAGS) { + + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_REPLACE, + rparams->tktflags)) != 0) + goto cleanup; + } + + + /* DEFENCTYPE ATTRIBUTE */ + if (mask & LDAP_REALM_DEFENCTYPE) { + /* check if the entered enctype is valid */ + if (krb5_c_valid_enctype(rparams->defenctype)) { + + /* check if the defenctype exists in the suppenctypes list */ + for(i = 0; rparams->suppenctypes[i] != END_OF_LIST; ++i) + if (rparams->defenctype == rparams->suppenctypes[i]) + break; + + /* touching the end of list means defenctype is missing */ + if (rparams->suppenctypes[i] == END_OF_LIST) { + st = EINVAL; + krb5_set_error_message (context, st, "Default enctype not in the supported list"); + goto cleanup; + } + + if((st=krb5_add_int_mem_ldap_mod(&mods, "krbdefaultenctype", LDAP_MOD_REPLACE, + rparams->defenctype)) != 0) + goto cleanup; + } else { + st = EINVAL; + krb5_set_error_message (context, st, "Invalid default enctype"); + goto cleanup; + } + } + + /* DEFSALTTYPE ATTRIBUTE */ + if (mask & LDAP_REALM_DEFSALTTYPE) { + /* check if the entered salttype is valid */ + if (rparams->defsalttype>=0 && rparams->defsalttype<6) { + + /* check if the defsalttype exists in the suppsalttypes list */ + for(i = 0; rparams->suppsalttypes[i] != END_OF_LIST; ++i) + if (rparams->defsalttype == rparams->suppsalttypes[i]) + break; + + /* touching the end of the list means defsalttype is missing */ + if (rparams->suppsalttypes[i] == END_OF_LIST) { + st = EINVAL; + krb5_set_error_message (context, st, "Default salttype not in the supported list"); + goto cleanup; + } + + if((st=krb5_add_int_mem_ldap_mod(&mods, "krbdefaultsalttype", + LDAP_MOD_REPLACE, rparams->defsalttype)) != 0) + goto cleanup; + + } else { + st = EINVAL; + krb5_set_error_message (context, st, "Invalid default salttype"); + goto cleanup; + } + } + + /* SUPPSALTTYPE ATTRIBUTE */ + if (mask & LDAP_REALM_SUPPSALTTYPE) { + krb5_boolean flag=FALSE; + + for (i = 0; rparams->suppsalttypes[i] != END_OF_LIST; ++i) { + /* check if the salttypes entered is valid */ + if (!(rparams->suppsalttypes[i]>=0 && rparams->suppsalttypes[i]<6)) { + st = EINVAL; + krb5_set_error_message (context, st, "salttype %d not valid", rparams->suppsalttypes[i]); + goto cleanup; + } + + /* Ensure that the default salt type is supported */ + if ((oldmask & LDAP_REALM_DEFSALTTYPE || + mask & LDAP_REALM_DEFSALTTYPE) && + rparams->defsalttype == rparams->suppsalttypes[i]) + flag = TRUE; + } + + if (flag == FALSE) { /* Default salt type is not supported */ + st = EINVAL; + krb5_set_error_message (context, st, "Default salttype not in the supported list"); + goto cleanup; + } + ignore_duplicates(rparams->suppsalttypes); + + if((st=krb5_add_int_arr_mem_ldap_mod(&mods, "krbsupportedsalttypes", + LDAP_MOD_REPLACE, rparams->suppsalttypes)) != 0) + goto cleanup; + } + + /* SUPPENCTYPE ATTRIBUTE */ + if (mask & LDAP_REALM_SUPPENCTYPE) { + krb5_boolean flag=FALSE; + + for(i=0; rparams->suppenctypes[i] != END_OF_LIST; ++i) { + + /* check if the enctypes entered is valid */ + if (krb5_c_valid_enctype(rparams->suppenctypes[i]) == 0) { + st = EINVAL; + krb5_set_error_message (context, st, "Enctype %d not valid", rparams->suppenctypes[i]); + goto cleanup; + } + + /* Ensure that the default encryption type is supported */ + if ((oldmask & LDAP_REALM_DEFENCTYPE || + mask & LDAP_REALM_DEFENCTYPE) && + rparams->defenctype == rparams->suppenctypes[i]) + flag = TRUE; + } + + if (flag == FALSE) { /* Default encryption type is not supported */ + st = EINVAL; + krb5_set_error_message(context, st, "Default enctype not in the supported list"); + goto cleanup; + } + ignore_duplicates(rparams->suppenctypes); + + if((st=krb5_add_int_arr_mem_ldap_mod(&mods, "krbsupportedenctypes", + LDAP_MOD_REPLACE, rparams->suppenctypes)) != 0) + goto cleanup; + } + +#ifdef HAVE_EDIRECTORY + + /* KDCSERVERS ATTRIBUTE */ + if (mask & LDAP_REALM_KDCSERVERS) { + /* validate the server list */ + for (i=0; rparams->kdcservers[i] != NULL; ++i) { + st = checkattributevalue(ld, rparams->kdcservers[i], "objectClass", kdcclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "kdc service object value: "); + } + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbkdcservers", LDAP_MOD_REPLACE, + rparams->kdcservers)) != 0) + goto cleanup; + } + + /* ADMINSERVERS ATTRIBUTE */ + if (mask & LDAP_REALM_ADMINSERVERS) { + /* validate the server list */ + for (i=0; rparams->adminservers[i] != NULL; ++i) { + st = checkattributevalue(ld, rparams->adminservers[i], "objectClass", adminclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "admin service object value: "); + } + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbadmservers", LDAP_MOD_REPLACE, + rparams->adminservers)) != 0) + goto cleanup; + } + + /* PASSWDSERVERS ATTRIBUTE */ + if (mask & LDAP_REALM_PASSWDSERVERS) { + /* validate the server list */ + for (i=0; rparams->passwdservers[i] != NULL; ++i) { + st = checkattributevalue(ld, rparams->passwdservers[i], "objectClass", pwdclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "password service object value: "); + } + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdservers", LDAP_MOD_REPLACE, + rparams->passwdservers)) != 0) + goto cleanup; + } + + /* + * Read the old values of the krbkdcservers, krbadmservers and + * krbpwdservers. This information is later used to decided the + * deletions/additions to the list. + */ + if (mask & LDAP_REALM_KDCSERVERS || mask & LDAP_REALM_ADMINSERVERS || + mask & LDAP_REALM_PASSWDSERVERS) { + char *servers[] = {"krbKdcServers", "krbAdmServers", "krbPwdServers", NULL}; + + if ((st= ldap_search_s(ld, + rparams->realmdn, + LDAP_SCOPE_BASE, + 0, + servers, + 0, + &result)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_SEARCH); + goto cleanup; + } + + ent = ldap_first_entry(ld, result); + if (ent) { + if ((values=ldap_get_values(ld, ent, "krbKdcServers")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &oldkdcservers, count)) != 0) + goto cleanup; + ldap_value_free(values); + } + + if ((values=ldap_get_values(ld, ent, "krbAdmServers")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &oldadminservers, count)) != 0) + goto cleanup; + ldap_value_free(values); + } + + if ((values=ldap_get_values(ld, ent, "krbPwdServers")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &oldpasswdservers, count)) != 0) + goto cleanup; + ldap_value_free(values); + } + } + ldap_msgfree(result); + } +#endif + + /* Realm modify opearation */ + if ((st=ldap_modify_s(ld, rparams->realmdn, mods)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + +#ifdef HAVE_EDIRECTORY + /* krbRealmReferences attribute is updated here, depending on the additions/deletions + * to the 4 servers' list. + */ + if (mask & LDAP_REALM_KDCSERVERS) { + char **newkdcservers=NULL; + + count = ldap_count_values(rparams->kdcservers); + if ((st=copy_arrays(rparams->kdcservers, &newkdcservers, count)) != 0) + goto cleanup; + + /* find the deletions and additions to the server list */ + if (oldkdcservers && newkdcservers) + disjoint_members(oldkdcservers, newkdcservers); + + /* delete the krbRealmReferences attribute from the servers that are dis-associated. */ + if (oldkdcservers) + for (i=0; oldkdcservers[i]; ++i) + if ((st=deleteAttribute(ld, oldkdcservers[i], "krbRealmReferences", + rparams->realmdn)) != 0) + { + sprintf (errbuf, "Error removing 'krbRealmReferences' from %s: ", + oldkdcservers[i]); + prepend_err_str (context, errbuf, st, st); + goto cleanup; + } + + /* add the krbRealmReferences attribute from the servers that are associated. */ + if (newkdcservers) + for (i=0; newkdcservers[i]; ++i) + if ((st=updateAttribute(ld, newkdcservers[i], "krbRealmReferences", + rparams->realmdn)) != 0) + { + sprintf (errbuf, "Error adding 'krbRealmReferences' to %s: ", + newkdcservers[i]); + prepend_err_str (context, errbuf, st, st); + goto cleanup; + } + + if (newkdcservers) + ldap_value_free(newkdcservers); + } + + if (mask & LDAP_REALM_ADMINSERVERS) { + char **newadminservers=NULL; + + count = ldap_count_values(rparams->adminservers); + if ((st=copy_arrays(rparams->adminservers, &newadminservers, count)) != 0) + goto cleanup; + + /* find the deletions and additions to the server list */ + if (oldadminservers && newadminservers) + disjoint_members(oldadminservers, newadminservers); + + /* delete the krbRealmReferences attribute from the servers that are dis-associated. */ + if (oldadminservers) + for (i=0; oldadminservers[i]; ++i) + if ((st=deleteAttribute(ld, oldadminservers[i], "krbRealmReferences", + rparams->realmdn)) != 0) + { + sprintf(errbuf, "Error removing 'krbRealmReferences' from " + "%s: ", oldadminservers[i]); + prepend_err_str (context, errbuf, st, st); + goto cleanup; + } + + /* add the krbRealmReferences attribute from the servers that are associated. */ + if (newadminservers) + for (i=0; newadminservers[i]; ++i) + if ((st=updateAttribute(ld, newadminservers[i], "krbRealmReferences", + rparams->realmdn)) != 0) + { + sprintf(errbuf, "Error adding 'krbRealmReferences' to %s: ", + newadminservers[i]); + prepend_err_str (context, errbuf, st, st); + goto cleanup; + } + if (newadminservers) + ldap_value_free(newadminservers); + } + + if (mask & LDAP_REALM_PASSWDSERVERS) { + char **newpasswdservers=NULL; + + count = ldap_count_values(rparams->passwdservers); + if ((st=copy_arrays(rparams->passwdservers, &newpasswdservers, count)) != 0) + goto cleanup; + + /* find the deletions and additions to the server list */ + if (oldpasswdservers && newpasswdservers) + disjoint_members(oldpasswdservers, newpasswdservers); + + /* delete the krbRealmReferences attribute from the servers that are dis-associated. */ + if (oldpasswdservers) + for (i=0; oldpasswdservers[i]; ++i) + if ((st=deleteAttribute(ld, oldpasswdservers[i], "krbRealmReferences", + rparams->realmdn)) != 0) + { + sprintf(errbuf, "Error removing 'krbRealmReferences' from " + "%s: ", oldpasswdservers[i]); + prepend_err_str (context, errbuf, st, st); + goto cleanup; + } + + /* add the krbRealmReferences attribute from the servers that are associated. */ + if (newpasswdservers) + for (i=0; newpasswdservers[i]; ++i) + if ((st=updateAttribute(ld, newpasswdservers[i], "krbRealmReferences", + rparams->realmdn)) != 0) + { + sprintf(errbuf, "Error adding 'krbRealmReferences' to %s: ", + newpasswdservers[i]); + prepend_err_str (context, errbuf, st, st); + goto cleanup; + } + if (newpasswdservers) + ldap_value_free(newpasswdservers); + } +#endif + + cleanup: + +#ifdef HAVE_EDIRECTORY + if (oldkdcservers) { + for(i=0; oldkdcservers[i]; ++i) + free(oldkdcservers[i]); + free(oldkdcservers); + } + + if (oldadminservers) { + for(i=0; oldadminservers[i]; ++i) + free(oldadminservers[i]); + free(oldadminservers); + } + + if (oldpasswdservers) { + for(i=0; oldpasswdservers[i]; ++i) + free(oldpasswdservers[i]); + free(oldpasswdservers); + } +#endif + + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + + +/* + * Create the Kerberos container in the Directory + */ + +krb5_error_code +krb5_ldap_create_krbcontainer(context, krbcontparams) + krb5_context context; + const krb5_ldap_krbcontainer_params *krbcontparams; +{ + LDAP *ld=NULL; + char *strval[2]={NULL}, *kerberoscontdn=NULL, **rdns=NULL; + int pmask=0; + LDAPMod **mods = NULL; + krb5_error_code st=0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; +#ifdef HAVE_EDIRECTORY + int crmask=0; +#endif + + SETUP_CONTEXT (); + + /* get ldap handle */ + GET_HANDLE (); + + if (krbcontparams != NULL && krbcontparams->DN != NULL) { + kerberoscontdn = krbcontparams->DN; + } else { + /* If the user has not given, use the default cn=Kerberos,cn=Security */ +#ifdef HAVE_EDIRECTORY + kerberoscontdn = KERBEROS_CONTAINER; +#else + st = EINVAL; + krb5_set_error_message (context, st, "Kerberos Container information is missing"); + goto cleanup; +#endif + } + + strval[0] = "krbContainer"; + strval[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + rdns = ldap_explode_dn(kerberoscontdn, 1); + if (rdns == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "Invalid Kerberos container DN"); + goto cleanup; + } + + strval[0] = rdns[0]; + strval[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + /* check if the policy reference value exists and is of krbpolicyreference object class */ + if (krbcontparams && krbcontparams->policyreference) { + st = checkattributevalue(ld, krbcontparams->policyreference, "objectclass", policyclass, + &pmask); + CHECK_CLASS_VALIDITY(st, pmask, "ticket policy object value: "); + + strval[0] = krbcontparams->policyreference; + strval[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpolicyreference", LDAP_MOD_ADD, + strval)) != 0) + goto cleanup; + } + + /* create the kerberos container */ + if ((st = ldap_add_s(ld, kerberoscontdn, mods)) != LDAP_SUCCESS) { + int ost = st; + st = translate_ldap_error (st, OP_ADD); + krb5_set_error_message (context, st, "Kerberos Container create FAILED: %s", ldap_err2string(ost)); + goto cleanup; + } + +#ifdef HAVE_EDIRECTORY + + /* free the mods array */ + ldap_mods_free(mods, 1); + mods=NULL; + + /* check whether the security container is bound to krbcontainerrefaux object class */ + if ((st=checkattributevalue(ld, SECURITY_CONTAINER, "objectClass", + krbContainerRefclass, &crmask)) != 0) + { + prepend_err_str (context, "Security Container read FAILED: ", st, st); + /* delete Kerberos Container, status ignored intentionally */ + ldap_delete_s(ld, kerberoscontdn); + goto cleanup; + } + + if (crmask == 0) { + /* Security Container is extended with krbcontainerrefaux object class */ + strval[0] = "krbContainerRefAux"; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + } + + strval[0] = kerberoscontdn; + strval[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbcontainerreference", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + /* update the security container with krbContainerReference attribute */ + if ((st=ldap_modify_s(ld, SECURITY_CONTAINER, mods)) != LDAP_SUCCESS) { + int ost = st; + st = translate_ldap_error (st, OP_MOD); + krb5_set_error_message (context, st, "Security Container update FAILED: %s", ldap_err2string(ost)); + /* delete Kerberos Container, status ignored intentionally */ + ldap_delete_s(ld, kerberoscontdn); + goto cleanup; + } +#endif + + cleanup: + + if (rdns) + ldap_value_free (rdns); + + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return(st); +} + + +/* + * Create Realm in eDirectory. This is used by kdb5_util + */ + +krb5_error_code +krb5_ldap_create_realm(context, rparams, mask) + krb5_context context; + krb5_ldap_realm_params *rparams; + int mask; +{ + LDAP *ld=NULL; + krb5_error_code st=0; + char *dn=NULL; + char *strval[4]={NULL}; + LDAPMod **mods = NULL; + int i=0, objectmask=0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; +#ifdef HAVE_EDIRECTORY + char errbuf[1024]; +#endif + char *realm_name; + + SETUP_CONTEXT (); + + /* Check input validity ... */ + if (ldap_context->krbcontainer == NULL || + ldap_context->krbcontainer->DN == NULL || + rparams == NULL || + rparams->realm_name == NULL || + ((mask & LDAP_REALM_SUBTREE) && rparams->subtree == NULL) || + ((mask & LDAP_REALM_POLICYREFERENCE) && rparams->policyreference == NULL) || + ((mask & LDAP_REALM_SUPPSALTTYPE) && rparams->suppsalttypes == NULL) || + ((mask & LDAP_REALM_SUPPENCTYPE) && rparams->suppenctypes == NULL) || +#ifdef HAVE_EDIRECTORY + ((mask & LDAP_REALM_KDCSERVERS) && rparams->kdcservers == NULL) || + ((mask & LDAP_REALM_ADMINSERVERS) && rparams->adminservers == NULL) || + ((mask & LDAP_REALM_PASSWDSERVERS) && rparams->passwdservers == NULL) || +#endif + 0) { + st = EINVAL; + return st; + } + + if (ldap_context->krbcontainer == NULL) { + if ((st = krb5_ldap_read_krbcontainer_params(context, + &(ldap_context->krbcontainer))) != 0) + goto cleanup; + } + + /* get ldap handle */ + GET_HANDLE (); + + realm_name = rparams->realm_name; + + dn = malloc(strlen("cn=") + strlen(realm_name) + strlen(ldap_context->krbcontainer->DN) + 2); + CHECK_NULL(dn); + sprintf(dn, "cn=%s,%s", realm_name, ldap_context->krbcontainer->DN); + + strval[0] = realm_name; + strval[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + strval[0] = "top"; + strval[1] = "krbrealmcontainer"; + strval[2] = "krbpolicyaux"; + strval[3] = NULL; + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + /* SUBTREE ATTRIBUTE */ + if (mask & LDAP_REALM_SUBTREE) { + if (strlen(rparams->subtree) != 0) { + st = checkattributevalue(ld, rparams->subtree, "Objectclass", subtreeclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "realm object value: "); + + } + strval[0] = rparams->subtree; + strval[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtree", LDAP_MOD_ADD, + strval)) != 0) + goto cleanup; + } + + /* SEARCHSCOPE ATTRIBUTE */ + if (mask & LDAP_REALM_SEARCHSCOPE) { + if((st=krb5_add_int_mem_ldap_mod(&mods, "krbsearchscope", LDAP_MOD_ADD, + (rparams->search_scope == LDAP_SCOPE_ONELEVEL + || rparams->search_scope == LDAP_SCOPE_SUBTREE) ? + rparams->search_scope : LDAP_SCOPE_SUBTREE)) != 0) + goto cleanup; + } + if (mask & LDAP_REALM_MAXRENEWLIFE) { + + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxRenewableAge", LDAP_MOD_ADD, + rparams->max_renewable_life)) != 0) + goto cleanup; + } + + /* krbMaxTicketLife ATTRIBUTE */ + + if (mask & LDAP_REALM_MAXTICKETLIFE) { + + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbMaxTicketLife", LDAP_MOD_ADD, + rparams->max_life)) != 0) + goto cleanup; + } + + /* krbTicketFlags ATTRIBUTE */ + + if (mask & LDAP_REALM_KRBTICKETFLAGS) { + + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbTicketFlags", LDAP_MOD_ADD, + rparams->tktflags)) != 0) + goto cleanup; + } + + + /* DEFAULTENCTYPE ATTRIBUTE */ + if (mask & LDAP_REALM_DEFENCTYPE) { + /* check if the entered enctype is valid */ + if (krb5_c_valid_enctype(rparams->defenctype)) { + + /* check if the defenctype exists in the suppenctypes list */ + if (mask & LDAP_REALM_SUPPENCTYPE) { + for(i=0; rparams->suppenctypes[i] != END_OF_LIST; ++i) + if (rparams->defenctype == rparams->suppenctypes[i]) + break; + + if (rparams->suppenctypes[i] == END_OF_LIST) { + st = EINVAL; + krb5_set_error_message (context, st, "Default enctype not in the " + "supported list"); + goto cleanup; + } + } + if((st=krb5_add_int_mem_ldap_mod(&mods, "krbdefaultenctype", LDAP_MOD_ADD, + rparams->defenctype)) != 0) + goto cleanup; + } else { + st = EINVAL; + krb5_set_error_message (context, st, "Default enctype not valid"); + goto cleanup; + } + } + + /* DEFAULTSALTTYPE ATTRIBUTE */ + if (mask & LDAP_REALM_DEFSALTTYPE) { + /* check if the entered salttype is valid */ + if (rparams->defsalttype >=0 && rparams->defsalttype<6) { + + /* check if the defsalttype exists in the suppsalttypes list */ + if (mask & LDAP_REALM_SUPPSALTTYPE) { + for(i=0; rparams->suppsalttypes[i] != END_OF_LIST; ++i) + if (rparams->defsalttype == rparams->suppsalttypes[i]) + break; + + if (rparams->suppsalttypes[i] == END_OF_LIST) { + st = EINVAL; + krb5_set_error_message (context, st, + "Default salttype not in the supported list"); + goto cleanup; + } + } + + if((st=krb5_add_int_mem_ldap_mod(&mods, "krbdefaultsalttype", LDAP_MOD_ADD, + rparams->defsalttype)) != 0) + goto cleanup; + } else { + st = EINVAL; + krb5_set_error_message (context, st, "Default salttype not valid"); + goto cleanup; + } + } + + /* SUPPORTEDSALTTYPE ATTRIBUTE */ + if (mask & LDAP_REALM_SUPPSALTTYPE) { + for(i=0; rparams->suppsalttypes[i] != END_OF_LIST; ++i) { + /* check if the salttypes entered is valid */ + if (!(rparams->suppsalttypes[i]>=0 && rparams->suppsalttypes[i]<6)) { + st = EINVAL; + krb5_set_error_message (context, st, "Salttype %d not valid", + rparams->suppsalttypes[i]); + goto cleanup; + } + } + ignore_duplicates(rparams->suppsalttypes); + + if((st=krb5_add_int_arr_mem_ldap_mod(&mods, "krbsupportedsalttypes", LDAP_MOD_ADD, + rparams->suppsalttypes)) != 0) + goto cleanup; + } else { + /* set all the salt types as the suppsalttypes */ + if((st=krb5_add_int_arr_mem_ldap_mod(&mods, "krbsupportedsalttypes", LDAP_MOD_ADD, + supportedsalttypes)) != 0) + goto cleanup; + } + + /* SUPPORTEDENCTYPE ATTRIBUTE */ + if (mask & LDAP_REALM_SUPPENCTYPE) { + for(i=0; rparams->suppenctypes[i] != -1; ++i) { + + /* check if the enctypes entered is valid */ + if (krb5_c_valid_enctype(rparams->suppenctypes[i]) == 0) { + st = EINVAL; + krb5_set_error_message (context, st, "Enctype %d not valid", + rparams->suppenctypes[i]); + goto cleanup; + } + } + ignore_duplicates(rparams->suppenctypes); + + if((st=krb5_add_int_arr_mem_ldap_mod(&mods, "krbsupportedenctypes", LDAP_MOD_ADD, + rparams->suppenctypes)) != 0) + goto cleanup; + } else { + /* set all the enc types as the suppenctypes */ + if((st=krb5_add_int_arr_mem_ldap_mod(&mods, "krbsupportedenctypes", LDAP_MOD_ADD, + supportedenctypes)) != 0) + goto cleanup; + } + +#ifdef HAVE_EDIRECTORY + + /* KDCSERVERS ATTRIBUTE */ + if (mask & LDAP_REALM_KDCSERVERS) { + /* validate the server list */ + for (i=0; rparams->kdcservers[i] != NULL; ++i) { + st = checkattributevalue(ld, rparams->kdcservers[i], "objectClass", kdcclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "kdc service object value: "); + + } + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbkdcservers", LDAP_MOD_ADD, + rparams->kdcservers)) != 0) + goto cleanup; + } + + /* ADMINSERVERS ATTRIBUTE */ + if (mask & LDAP_REALM_ADMINSERVERS) { + /* validate the server list */ + for (i=0; rparams->adminservers[i] != NULL; ++i) { + st = checkattributevalue(ld, rparams->adminservers[i], "objectClass", adminclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "admin service object value: "); + + } + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbadmservers", LDAP_MOD_ADD, + rparams->adminservers)) != 0) + goto cleanup; + } + + /* PASSWDSERVERS ATTRIBUTE */ + if (mask & LDAP_REALM_PASSWDSERVERS) { + /* validate the server list */ + for (i=0; rparams->passwdservers[i] != NULL; ++i) { + st = checkattributevalue(ld, rparams->passwdservers[i], "objectClass", pwdclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "password service object value: "); + + } + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdservers", LDAP_MOD_ADD, + rparams->passwdservers)) != 0) + goto cleanup; + } +#endif + + /* realm creation operation */ + if ((st=ldap_add_s(ld, dn, mods)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_ADD); + goto cleanup; + } + +#ifdef HAVE_EDIRECTORY + if (mask & LDAP_REALM_KDCSERVERS) + for (i=0; rparams->kdcservers[i]; ++i) + if ((st=updateAttribute(ld, rparams->kdcservers[i], "krbRealmReferences", dn)) != 0) + { + sprintf(errbuf, "Error adding 'krbRealmReferences' to %s: ", + rparams->kdcservers[i]); + prepend_err_str (context, errbuf, st, st); + /* delete Realm, status ignored intentionally */ + ldap_delete_s(ld, dn); + goto cleanup; + } + + if (mask & LDAP_REALM_ADMINSERVERS) + for (i=0; rparams->adminservers[i]; ++i) + if ((st=updateAttribute(ld, rparams->adminservers[i], "krbRealmReferences", dn)) != 0) + { + sprintf(errbuf, "Error adding 'krbRealmReferences' to %s: ", + rparams->adminservers[i]); + prepend_err_str (context, errbuf, st, st); + /* delete Realm, status ignored intentionally */ + ldap_delete_s(ld, dn); + goto cleanup; + } + + if (mask & LDAP_REALM_PASSWDSERVERS) + for (i=0; rparams->passwdservers[i]; ++i) + if ((st=updateAttribute(ld, rparams->passwdservers[i], "krbRealmReferences", dn)) != 0) + { + sprintf(errbuf, "Error adding 'krbRealmReferences' to %s: ", + rparams->passwdservers[i]); + prepend_err_str (context, errbuf, st, st); + /* delete Realm, status ignored intentionally */ + ldap_delete_s(ld, dn); + goto cleanup; + } +#endif + + cleanup: + + if (dn) + free(dn); + + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + +/* + * Read the realm container configuration from eDirectory for the specified realm. + */ + +krb5_error_code +krb5_ldap_read_realm_params(context, lrealm, rlparamp, mask) + krb5_context context; + char *lrealm; + krb5_ldap_realm_params **rlparamp; + int *mask; +{ + char **values=NULL, *krbcontDN=NULL /*, *curr=NULL */; + unsigned int i=0, /* masklen=4, */ count=0; + krb5_error_code st=0, tempst=0; + LDAP *ld=NULL; + LDAPMessage *result=NULL,*ent=NULL; + krb5_ldap_realm_params *rlparams=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + SETUP_CONTEXT (); + + /* validate the input parameter */ + if (lrealm == NULL || + ldap_context->krbcontainer == NULL || + ldap_context->krbcontainer->DN == NULL) { + st = EINVAL; + goto cleanup; + } + + /* read kerberos container, if not read already */ + if (ldap_context->krbcontainer == NULL) { + if ((st = krb5_ldap_read_krbcontainer_params(context, + &(ldap_context->krbcontainer))) != 0) + goto cleanup; + } + /* get ldap handle */ + GET_HANDLE (); + + /* Initialize realm container structure */ + rlparams =(krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params)); + CHECK_NULL(rlparams); + memset((char *) rlparams, 0, sizeof(krb5_ldap_realm_params)); + + /* allocate tl_data structure to store MASK information */ + rlparams->tl_data = malloc (sizeof(krb5_tl_data)); + if (rlparams->tl_data == NULL) { + st = ENOMEM; + goto cleanup; + } + memset((char *) rlparams->tl_data, 0, sizeof(krb5_tl_data)); + rlparams->tl_data->tl_data_type = KDB_TL_USER_INFO; + + /* set the mask parameter to 0 */ + *mask = 0; + + /* set default values */ + rlparams->search_scope = LDAP_SCOPE_SUBTREE; + + krbcontDN = ldap_context->krbcontainer->DN; + + rlparams->realmdn = (char *) malloc(strlen("cn=") + strlen(lrealm) + strlen(krbcontDN) + 2); + if (rlparams->realmdn == NULL) { + st = ENOMEM; + goto cleanup; + } + sprintf(rlparams->realmdn, "cn=%s,%s", lrealm, krbcontDN); + + /* populate the realm name in the structure */ + rlparams->realm_name = strdup(lrealm); + CHECK_NULL(rlparams->realm_name); + + LDAP_SEARCH(rlparams->realmdn, LDAP_SCOPE_BASE, "(objectclass=krbRealmContainer)", realm_attributes); + + ent = ldap_first_entry (ld, result); + if (ent == NULL) { + ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, (void *) &st); +#if 0 + st = translate_ldap_error(st, OP_SEARCH); +#endif + goto cleanup; + } + + /* Read the attributes */ + { + + if((values=ldap_get_values(ld, ent, "krbSubTree")) != NULL) { + rlparams->subtree = strdup(values[0]); + if(rlparams->subtree==NULL) { + st = ENOMEM; + goto cleanup; + } + *mask |= LDAP_REALM_SUBTREE; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbSearchScope")) != NULL) { + rlparams->search_scope=atoi(values[0]); + /* searchscope can be ONE-LEVEL or SUBTREE, else default to SUBTREE */ + if (!(rlparams->search_scope==1 || rlparams->search_scope==2)) + rlparams->search_scope = LDAP_SCOPE_SUBTREE; + *mask |= LDAP_REALM_SEARCHSCOPE; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbMaxTicketLife")) != NULL) { + rlparams->max_life = atoi(values[0]); + *mask |= LDAP_REALM_MAXTICKETLIFE; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbMaxRenewableAge")) != NULL) { + rlparams->max_renewable_life = atoi(values[0]); + *mask |= LDAP_REALM_MAXRENEWLIFE; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbTicketFlags")) != NULL) { + rlparams->tktflags = atoi(values[0]); + *mask |= LDAP_REALM_KRBTICKETFLAGS; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbDefaultEncType")) != NULL) { + rlparams->defenctype = atoi(values[0]); + if (krb5_c_valid_enctype(rlparams->defenctype) == 0) + rlparams->defenctype = ENCTYPE_DES3_CBC_SHA1; + *mask |= LDAP_REALM_DEFENCTYPE; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbDefaultSaltType")) != NULL) { + rlparams->defsalttype = atoi(values[0]); + if (!(rlparams->defsalttype>=0 && rlparams->defsalttype<6)) + rlparams->defsalttype = KRB5_KDB_SALTTYPE_NORMAL; + *mask |= LDAP_REALM_DEFSALTTYPE; + ldap_value_free(values); + } + if((values=ldap_get_values(ld, ent, "krbSupportedEncTypes")) != NULL) { + count = ldap_count_values(values); + rlparams->suppenctypes = malloc (sizeof(krb5_int32) * (count + 1)); + if (rlparams->suppenctypes == NULL) { + st = ENOMEM; + goto cleanup; + } + for(i=0; i<count; ++i) + rlparams->suppenctypes[i] = atoi(values[i]); + rlparams->suppenctypes[count] = -1; + *mask |= LDAP_REALM_SUPPENCTYPE; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbSupportedSaltTypes")) != NULL) { + count = ldap_count_values(values); + rlparams->suppsalttypes = malloc (sizeof(krb5_int32) * (count + 1)); + if (rlparams->suppsalttypes == NULL) { + st = ENOMEM; + goto cleanup; + } + for(i=0; i<count; ++i) + rlparams->suppsalttypes[i] = atoi(values[i]); + rlparams->suppsalttypes[count] = -1; + *mask |= LDAP_REALM_SUPPSALTTYPE; + ldap_value_free(values); + } + +#ifdef HAVE_EDIRECTORY + + if((values=ldap_get_values(ld, ent, "krbKdcServers")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &(rlparams->kdcservers), (int) count)) != 0) + goto cleanup; + *mask |= LDAP_REALM_KDCSERVERS; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbAdmServers")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &(rlparams->adminservers), (int) count)) != 0) + goto cleanup; + *mask |= LDAP_REALM_ADMINSERVERS; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbPwdServers")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &(rlparams->passwdservers), (int) count)) != 0) + goto cleanup; + *mask |= LDAP_REALM_PASSWDSERVERS; + ldap_value_free(values); + } +#endif + } + ldap_msgfree(result); + + /* + * If all of maxtktlife, maxrenewlife and ticketflags are not directly + * available, use the policy dn from the policy reference attribute, if + * available, to fetch the missing. + */ + + if ((!(*mask & LDAP_REALM_MAXTICKETLIFE && *mask & LDAP_REALM_MAXRENEWLIFE && + *mask & LDAP_REALM_KRBTICKETFLAGS)) && rlparams->policyreference) { + + LDAP_SEARCH_1(rlparams->policyreference, LDAP_SCOPE_BASE, NULL, policy_attributes, IGNORE_STATUS); + if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_OBJECT) { + int ost = st; + st = translate_ldap_error (st, OP_SEARCH); + krb5_set_error_message (context, st, "Policy object read failed: %s", ldap_err2string(ost)); + goto cleanup; + } + ent = ldap_first_entry (ld, result); + if (ent != NULL) { + if ((*mask & LDAP_REALM_MAXTICKETLIFE) == 0) { + if((values=ldap_get_values(ld, ent, "krbmaxticketlife")) != NULL) { + rlparams->max_life = atoi(values[0]); + *mask |= LDAP_REALM_MAXTICKETLIFE; + ldap_value_free(values); + } + } + + if ((*mask & LDAP_REALM_MAXRENEWLIFE) == 0) { + if((values=ldap_get_values(ld, ent, "krbmaxrenewableage")) != NULL) { + rlparams->max_renewable_life = atoi(values[0]); + *mask |= LDAP_REALM_MAXRENEWLIFE; + ldap_value_free(values); + } + } + + if ((*mask & LDAP_REALM_KRBTICKETFLAGS) == 0) { + if((values=ldap_get_values(ld, ent, "krbticketflags")) != NULL) { + rlparams->tktflags = atoi(values[0]); + *mask |= LDAP_REALM_KRBTICKETFLAGS; + ldap_value_free(values); + } + } + } + ldap_msgfree(result); + } + + rlparams->mask = *mask; + *rlparamp = rlparams; + st = store_tl_data(rlparams->tl_data, KDB_TL_MASK, mask); + + cleanup: + + /* if there is an error, free allocated structures */ + if(st != 0) { + krb5_ldap_free_realm_params(rlparams); + *rlparamp=NULL; + } + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + Free the krb5_ldap_realm_params. +*/ +void +krb5_ldap_free_realm_params(rparams) + krb5_ldap_realm_params *rparams; +{ + int i=0; + + if(rparams) { + if (rparams->realmdn) + free(rparams->realmdn); + + if (rparams->realm_name) + krb5_xfree(rparams->realm_name); + + if (rparams->subtree) + krb5_xfree(rparams->subtree); + + if (rparams->suppenctypes) + krb5_xfree(rparams->suppenctypes); + + if (rparams->suppsalttypes) + krb5_xfree(rparams->suppsalttypes); + + if (rparams->kdcservers){ + for (i=0; rparams->kdcservers[i]; ++i) + krb5_xfree(rparams->kdcservers[i]); + krb5_xfree(rparams->kdcservers); + } + + if (rparams->adminservers){ + for (i=0; rparams->adminservers[i]; ++i) + krb5_xfree(rparams->adminservers[i]); + krb5_xfree(rparams->adminservers); + } + + if (rparams->passwdservers){ + for (i=0; rparams->passwdservers[i]; ++i) + krb5_xfree(rparams->passwdservers[i]); + krb5_xfree(rparams->passwdservers); + } + + if (rparams->tl_data) { + if (rparams->tl_data->tl_data_contents) + krb5_xfree(rparams->tl_data->tl_data_contents); + krb5_xfree(rparams->tl_data); + } + + if (rparams->mkey.contents) { + memset(rparams->mkey.contents, 0, rparams->mkey.length); + krb5_xfree(rparams->mkey.contents); + } + + krb5_xfree(rparams); + } + return; +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h new file mode 100644 index 000000000..fabc316ca --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h @@ -0,0 +1,99 @@ +/* + * lib/kdb/kdb_ldap/ldap_realm.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef _LDAP_REALM_H +#define _LDAP_REALM_H 1 + +/* realm specific mask */ +#define LDAP_REALM_SUBTREE 0x0001 +#define LDAP_REALM_SEARCHSCOPE 0x0002 +#define LDAP_REALM_DEFENCTYPE 0x0004 +#define LDAP_REALM_DEFSALTTYPE 0x0008 +#define LDAP_REALM_SUPPENCTYPE 0x0010 +#define LDAP_REALM_SUPPSALTTYPE 0x0020 +#define LDAP_REALM_POLICYREFERENCE 0x0040 +#define LDAP_REALM_UPENABLED 0x0080 +#define LDAP_REALM_LDAPSERVERS 0x0100 +#define LDAP_REALM_KDCSERVERS 0x0200 +#define LDAP_REALM_ADMINSERVERS 0x0400 +#define LDAP_REALM_PASSWDSERVERS 0x0800 +#define LDAP_REALM_MAXTICKETLIFE 0x1000 +#define LDAP_REALM_MAXRENEWLIFE 0x2000 +#define LDAP_REALM_KRBTICKETFLAGS 0x4000 + +extern char *policy_attributes[]; + +extern char *realm_attributes[]; + +/* realm container structure */ + +typedef struct _krb5_ldap_realm_params { + char *realmdn; + char *realm_name; + char *subtree; + char *policyreference; + int search_scope; + int upenabled; + krb5_int32 max_life; + krb5_int32 max_renewable_life; + krb5_int32 tktflags; + krb5_enctype defenctype; + krb5_int32 defsalttype; + krb5_enctype *suppenctypes; + krb5_int32 *suppsalttypes; + char **ldapservers; + char **kdcservers; + char **adminservers; + char **passwdservers; + krb5_tl_data *tl_data; + krb5_keyblock mkey; + long mask; +} krb5_ldap_realm_params; + + +krb5_error_code +krb5_ldap_list_realm(krb5_context , char ***); + +krb5_error_code +krb5_ldap_delete_realm(krb5_context, char *); + +krb5_error_code +krb5_ldap_modify_realm(krb5_context, krb5_ldap_realm_params *, int); + +krb5_error_code +krb5_ldap_create_realm(krb5_context, krb5_ldap_realm_params *, int); + +krb5_error_code +krb5_ldap_read_realm_params(krb5_context , char *, krb5_ldap_realm_params **, int *); + +void +krb5_ldap_free_realm_params(krb5_ldap_realm_params *); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c new file mode 100644 index 000000000..296e36d2d --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c @@ -0,0 +1,801 @@ +/* + * lib/kdb/kdb_ldap/ldap_service_rights.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" +#include "ldap_services.h" +#include "ldap_err.h" + +/* NOTE: add appropriate rights for krbpasswordexpiration attribute */ + +#ifdef HAVE_EDIRECTORY + +static char *kdcrights_subtree[][2] = { + {"1#subtree#","#[Entry Rights]"}, + {"2#subtree#","#CN"}, + {"6#subtree#","#ObjectClass"}, + {"2#subtree#","#krbPolicyReference"}, + {"2#subtree#","#krbUPEnabled"}, + {"2#subtree#","#krbHostServer"}, + {"2#subtree#","#krbServiceFlags"}, + {"2#subtree#","#krbRealmReferences"}, + {"2#subtree#","#krbTicketFlags"}, + {"2#subtree#","#krbMaxTicketLife"}, + {"2#subtree#","#krbMaxRenewableAge"}, + {"2#subtree#","#krbPrincipalName"}, + {"6#subtree#","#krbSecretKey"}, + {"2#subtree#","#krbPrincipalExpiration"}, + {"2#subtree#","#krbPwdPolicyReference"}, + {"2#subtree#","#krbMaxPwdLife"}, + {"6#subtree#","#ModifiersName"}, + {"2#subtree#","#PasswordExpirationTime"}, + {"2#subtree#","#PasswordExpirationInterval"}, + {"2#subtree#","#PasswordMinimumLength"}, + {"2#subtree#","#PasswordAllowChange"}, + {"2#subtree#","#LoginDisabled"}, + {"6#subtree#","#LastLoginTime"}, + {"2#subtree#","#LoginExpirationTime"}, + {"6#subtree#","#LoginIntruderAttempts"}, + {"2#subtree#","#IntruderAttemptResetInterval"}, + {"2#subtree#","#LoginIntruderLimit"}, + {"6#subtree#","#LoginIntruderResetTime"}, + {"2#subtree#","#DetectIntruder"}, + {"2#subtree#","#LockoutAfterDetection"}, + {"6#subtree#","#LockedByIntruder"}, + {"2#subtree#","#krbPrincipalReferences"}, + { "", "" } +}; + +static char *adminrights_subtree[][2]={ + {"15#subtree#","#[Entry Rights]"}, + {"6#subtree#","#CN"}, + {"6#subtree#","#ObjectClass"}, + {"6#subtree#","#krbPolicyReference"}, + {"6#subtree#","#krbUPEnabled"}, + {"2#subtree#","#krbHostServer"}, + {"2#subtree#","#krbServiceFlags"}, + {"2#subtree#","#krbRealmReferences"}, + {"6#subtree#","#krbTicketFlags"}, + {"6#subtree#","#krbMaxTicketLife"}, + {"6#subtree#","#krbMaxRenewableAge"}, + {"6#subtree#","#krbPrincipalName"}, + {"6#subtree#","#krbSecretKey"}, + {"6#subtree#","#krbPrincipalExpiration"}, + {"6#subtree#","#ModifiersName"}, + {"6#subtree#","#PasswordExpirationTime"}, + {"2#subtree#","#PasswordExpirationInterval"}, + {"6#subtree#","#PasswordMinimumLength"}, + {"6#subtree#","#PasswordAllowChange"}, + {"6#subtree#","#LoginDisabled"}, + {"2#subtree#","#LastLoginTime"}, + {"2#subtree#","#LoginExpirationTime"}, + {"2#subtree#","#LoginIntruderAttempts"}, + {"6#subtree#","#IntruderAttemptResetInterval"}, + {"6#subtree#","#LoginIntruderLimit"}, + {"6#subtree#","#LoginIntruderResetTime"}, + {"6#subtree#","#DetectIntruder"}, + {"6#subtree#","#LockoutAfterDetection"}, + {"2#subtree#","#LockedByIntruder"}, + {"2#subtree#","#krbPrincipalReferences"}, + {"6#subtree#","#Surname"}, + {"4#subtree#","#passwordManagement"}, + {"6#subtree#","#krbPwdHistoryLength"}, + {"6#subtree#","#krbMinPwdLife"}, + {"6#subtree#","#krbMaxPwdLife"}, + {"6#subtree#","#krbPwdMinDiffChars"}, + {"6#subtree#","#krbPwdMinLength"}, + {"6#subtree#","#krbPwdPolicyRefCount"}, + {"6#subtree#","#krbPwdPolicyReference"}, + { "","" } +}; + +static char *pwdrights_subtree[][2] = { + {"1#subtree#","#[Entry Rights]"}, + {"2#subtree#","#CN"}, + {"2#subtree#","#ObjectClass"}, + {"2#subtree#","#krbPolicyReference"}, + {"2#subtree#","#krbUPEnabled"}, + {"2#subtree#","#krbHostServer"}, + {"2#subtree#","#krbServiceFlags"}, + {"2#subtree#","#krbRealmReferences"}, + {"6#subtree#","#krbTicketFlags"}, + {"2#subtree#","#krbMaxTicketLife"}, + {"2#subtree#","#krbMaxRenewableAge"}, + {"2#subtree#","#krbPrincipalName"}, + {"6#subtree#","#krbSecretKey"}, + {"2#subtree#","#krbPrincipalExpiration"}, + {"4#subtree#","#passwordManagement"}, + {"6#subtree#","#ModifiersName"}, + {"2#subtree#","#krbPwdHistoryLength"}, + {"2#subtree#","#krbMinPwdLife"}, + {"2#subtree#","#krbMaxPwdLife"}, + {"2#subtree#","#krbPwdMinDiffChars"}, + {"2#subtree#","#krbPwdMinLength"}, + {"2#subtree#","#krbPwdPolicyRefCount"}, + {"2#subtree#","#krbPwdPolicyReference"}, + { "", "" } +}; + +static char *kdcrights_realmcontainer[][2]={ + {"1#subtree#","#[Entry Rights]"}, + {"2#subtree#","#CN"}, + {"6#subtree#","#ObjectClass"}, + {"2#subtree#","#krbPolicyReference"}, + {"2#subtree#","#krbMasterKey"}, + {"2#subtree#","#krbUPEnabled"}, + {"2#subtree#","#krbSubTree"}, + {"2#subtree#","#krbSearchScope"}, + {"2#subtree#","#krbLdapServers"}, + {"2#subtree#","#krbSupportedEncTypes"}, + {"2#subtree#","#krbSupportedSaltTypes"}, + {"2#subtree#","#krbDefaultEncType"}, + {"2#subtree#","#krbDefaultSaltType"}, + {"2#subtree#","#krbKdcServers"}, + {"2#subtree#","#krbPwdServers"}, + {"2#subtree#","#krbTicketFlags"}, + {"2#subtree#","#krbMaxTicketLife"}, + {"2#subtree#","#krbMaxRenewableAge"}, + {"2#subtree#","#krbPrincipalName"}, + {"6#subtree#","#krbSecretKey"}, + {"2#subtree#","#krbPrincipalExpiration"}, + {"2#subtree#","#krbPwdPolicyReference"}, + {"2#subtree#","#krbMaxPwdLife"}, + {"6#subtree#","#ModifiersName"}, + {"2#subtree#","#PasswordExpirationTime"}, + {"2#subtree#","#PasswordExpirationInterval"}, + {"2#subtree#","#PasswordMinimumLength"}, + {"2#subtree#","#PasswordAllowChange"}, + {"2#subtree#","#LoginDisabled"}, + {"6#subtree#","#LastLoginTime"}, + {"2#subtree#","#LoginExpirationTime"}, + {"6#subtree#","#LoginIntruderAttempts"}, + {"2#subtree#","#IntruderAttemptResetInterval"}, + {"2#subtree#","#LoginIntruderLimit"}, + {"6#subtree#","#LoginIntruderResetTime"}, + {"2#subtree#","#DetectIntruder"}, + {"2#subtree#","#LockoutAfterDetection"}, + {"6#subtree#","#LockedByIntruder"}, + { "", "" } +}; + + +static char *adminrights_realmcontainer[][2]={ + {"15#subtree#","#[Entry Rights]"}, + {"6#subtree#","#CN"}, + {"6#subtree#","#ObjectClass"}, + {"6#subtree#","#krbPolicyReference"}, + {"2#subtree#","#krbMasterKey"}, + {"6#subtree#","#krbUPEnabled"}, + {"2#subtree#","#krbSubTree"}, + {"2#subtree#","#krbSearchScope"}, + {"2#subtree#","#krbLdapServers"}, + {"2#subtree#","#krbSupportedEncTypes"}, + {"2#subtree#","#krbSupportedSaltTypes"}, + {"2#subtree#","#krbDefaultEncType"}, + {"2#subtree#","#krbDefaultSaltType"}, + {"2#subtree#","#krbKdcServers"}, + {"2#subtree#","#krbPwdServers"}, + {"6#subtree#","#krbTicketFlags"}, + {"6#subtree#","#krbMaxTicketLife"}, + {"6#subtree#","#krbMaxRenewableAge"}, + {"6#subtree#","#krbPrincipalName"}, + {"6#subtree#","#krbSecretKey"}, + {"6#subtree#","#krbPrincipalExpiration"}, + {"6#subtree#","#ModifiersName"}, + {"6#subtree#","#PasswordExpirationTime"}, + {"2#subtree#","#PasswordExpirationInterval"}, + {"6#subtree#","#PasswordMinimumLength"}, + {"6#subtree#","#PasswordAllowChange"}, + {"6#subtree#","#LoginDisabled"}, + {"2#subtree#","#LastLoginTime"}, + {"2#subtree#","#LoginExpirationTime"}, + {"2#subtree#","#LoginIntruderAttempts"}, + {"6#subtree#","#IntruderAttemptResetInterval"}, + {"6#subtree#","#LoginIntruderLimit"}, + {"6#subtree#","#LoginIntruderResetTime"}, + {"6#subtree#","#DetectIntruder"}, + {"6#subtree#","#LockoutAfterDetection"}, + {"2#subtree#","#LockedByIntruder"}, + {"6#subtree#","#Surname"}, + {"6#subtree#","#krbPwdHistoryLength"}, + {"6#subtree#","#krbMinPwdLife"}, + {"6#subtree#","#krbMaxPwdLife"}, + {"6#subtree#","#krbPwdMinDiffChars"}, + {"6#subtree#","#krbPwdMinLength"}, + {"6#subtree#","#krbPwdPolicyRefCount"}, + {"6#subtree#","#krbPwdPolicyReference"}, + { "","" } +}; + + +static char *pwdrights_realmcontainer[][2]={ + {"1#subtree#","#[Entry Rights]"}, + {"2#subtree#","#CN"}, + {"2#subtree#","#ObjectClass"}, + {"2#subtree#","#krbPolicyReference"}, + {"2#subtree#","#krbMasterKey"}, + {"2#subtree#","#krbUPEnabled"}, + {"2#subtree#","#krbSubTree"}, + {"2#subtree#","#krbSearchScope"}, + {"2#subtree#","#krbLdapServers"}, + {"2#subtree#","#krbSupportedEncTypes"}, + {"2#subtree#","#krbSupportedSaltTypes"}, + {"2#subtree#","#krbDefaultEncType"}, + {"2#subtree#","#krbDefaultSaltType"}, + {"2#subtree#","#krbKdcServers"}, + {"2#subtree#","#krbPwdServers"}, + {"6#subtree#","#krbTicketFlags"}, + {"2#subtree#","#krbMaxTicketLife"}, + {"2#subtree#","#krbMaxRenewableAge"}, + {"2#subtree#","#krbPrincipalName"}, + {"6#subtree#","#krbSecretKey"}, + {"2#subtree#","#krbPrincipalExpiration"}, + {"6#subtree#","#ModifiersName"}, + {"2#subtree#","#krbPwdHistoryLength"}, + {"2#subtree#","#krbMinPwdLife"}, + {"2#subtree#","#krbMaxPwdLife"}, + {"2#subtree#","#krbPwdMinDiffChars"}, + {"2#subtree#","#krbPwdMinLength"}, + {"2#subtree#","#krbPwdPolicyRefCount"}, + {"2#subtree#","#krbPwdPolicyReference"}, + { "", "" } +}; + +static char *security_container[][2] = { + {"1#subtree#","#[Entry Rights]"}, + {"2#subtree#","#krbContainerReference"}, + { "", "" } +}; + +static char *kerberos_container[][2] = { + {"1#subtree#","#[Entry Rights]"}, + {"2#subtree#","#krbPolicyReference"}, + { "", "" } +}; + + +/* + * This will set the rights for the Kerberos service objects. + * The function will read the subtree attribute from the specified + * realm name and will the appropriate rights on both the realm + * container and the subtree. The kerberos context passed should + * have a valid ldap handle, with appropriate rights to write acl + * attributes. + * + * krb5_context - IN The Kerberos context with valid ldap handle + * + */ + +krb5_error_code +krb5_ldap_add_service_rights( context, servicetype, serviceobjdn, realmname, subtreeparam, mask) + krb5_context context; + int servicetype; + char *serviceobjdn; + char *realmname; + char *subtreeparam; + int mask; +{ + + int st=0,i=0; + char *realmacls[2]={NULL}, *subtreeacls[2]={NULL}, *seccontacls[2]={NULL}, *krbcontacls[2]={NULL}; + LDAP *ld; + LDAPMod realmclass, subtreeclass, seccontclass, krbcontclass; + LDAPMod *realmarr[3]={NULL}, *subtreearr[3]={NULL}, *seccontarr[3]={NULL}, *krbcontarr[3]={NULL}; + char *realmdn=NULL, *subtree=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + if ((serviceobjdn == NULL) || (realmname == NULL) || (servicetype < 0) || (servicetype > 4) + || (ldap_context->krbcontainer->DN == NULL) ) { + st=-1; + goto cleanup; + } + + /* If the subtree is null, set the value to root */ + if(subtreeparam== NULL) + subtree=strdup(""); + else + subtree=strdup(subtreeparam); + + if( subtree == NULL ) { + st = ENOMEM; + goto cleanup; + } + + /* Set the rights for the service object on the security container */ + seccontclass.mod_op = LDAP_MOD_ADD; + seccontclass.mod_type = "ACL"; + + for (i=0; strcmp(security_container[i][0], "") != 0; i++) { + + seccontacls[0] = (char *)malloc( strlen(security_container[i][0]) + + strlen(serviceobjdn) + + strlen(security_container[i][1]) + 1); + + sprintf( seccontacls[0], "%s%s%s", security_container[i][0], serviceobjdn, + security_container[i][1]); + seccontclass.mod_values = seccontacls; + + seccontarr[0] = &seccontclass; + + st = ldap_modify_ext_s(ld, + SECURITY_CONTAINER, + seccontarr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_TYPE_OR_VALUE_EXISTS && st != LDAP_OTHER) { + free(seccontacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(seccontacls[0]); + } + + + /* Set the rights for the service object on the kerberos container */ + krbcontclass.mod_op = LDAP_MOD_ADD; + krbcontclass.mod_type = "ACL"; + + for (i=0; strcmp(kerberos_container[i][0], "") != 0; i++) { + krbcontacls[0] = (char *)malloc( strlen(kerberos_container[i][0]) + strlen(serviceobjdn) + + strlen(kerberos_container[i][1]) + 1); + sprintf(krbcontacls[0], "%s%s%s", kerberos_container[i][0], serviceobjdn, + kerberos_container[i][1]); + krbcontclass.mod_values = krbcontacls; + + krbcontarr[0] = &krbcontclass; + + st = ldap_modify_ext_s(ld, + ldap_context->krbcontainer->DN, + krbcontarr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_TYPE_OR_VALUE_EXISTS && st != LDAP_OTHER) { + free(krbcontacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(krbcontacls[0]); + } + + /* Set the rights for the realm */ + if (mask & LDAP_REALM_RIGHTS) { + + /* Construct the realm dn from realm name */ + realmdn = (char * )malloc(strlen("cn=") + strlen(realmname) + + strlen(ldap_context->krbcontainer->DN) + 2); + sprintf(realmdn,"cn=%s,%s", realmname, ldap_context->krbcontainer->DN); + + realmclass.mod_op = LDAP_MOD_ADD; + realmclass.mod_type = "ACL"; + + if (servicetype == LDAP_KDC_SERVICE) { + for (i=0; strcmp(kdcrights_realmcontainer[i][0], "") != 0; i++) { + realmacls[0] = (char *)malloc(strlen(kdcrights_realmcontainer[i][0]) + + strlen(serviceobjdn) + + strlen(kdcrights_realmcontainer[i][1]) + 1); + sprintf(realmacls[0], "%s%s%s", kdcrights_realmcontainer[i][0], serviceobjdn, + kdcrights_realmcontainer[i][1]); + realmclass.mod_values = realmacls; + + realmarr[0] = &realmclass; + + st = ldap_modify_ext_s(ld, + realmdn, + realmarr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_TYPE_OR_VALUE_EXISTS && st != LDAP_OTHER) { + free(realmacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(realmacls[0]); + } + } else if(servicetype == LDAP_ADMIN_SERVICE){ + for( i=0; strcmp(adminrights_realmcontainer[i][0], "") != 0; i++) { + realmacls[0] = (char *) malloc(strlen(adminrights_realmcontainer[i][0]) + + strlen(serviceobjdn) + + strlen(adminrights_realmcontainer[i][1]) + 1); + sprintf(realmacls[0], "%s%s%s", adminrights_realmcontainer[i][0], serviceobjdn, + adminrights_realmcontainer[i][1]); + realmclass.mod_values = realmacls; + + realmarr[0] = &realmclass; + + st = ldap_modify_ext_s(ld, + realmdn, + realmarr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_TYPE_OR_VALUE_EXISTS && st != LDAP_OTHER) { + free(realmacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(realmacls[0]); + } + } else if (servicetype == LDAP_PASSWD_SERVICE) { + for (i=0; strcmp(pwdrights_realmcontainer[i][0], "")!=0; i++) { + realmacls[0] = (char *) malloc( strlen(pwdrights_realmcontainer[i][0]) + + strlen(serviceobjdn) + + strlen(pwdrights_realmcontainer[i][1]) + 1); + sprintf( realmacls[0], "%s%s%s", pwdrights_realmcontainer[i][0], serviceobjdn, + pwdrights_realmcontainer[i][1]); + realmclass.mod_values = realmacls; + + realmarr[0] = &realmclass; + + + st = ldap_modify_ext_s(ld, + realmdn, + realmarr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_TYPE_OR_VALUE_EXISTS && st != LDAP_OTHER) { + free(realmacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(realmacls[0]); + } + } + } /* Realm rights settings ends here */ + + + /* Subtree rights to be set */ + if (mask & LDAP_SUBTREE_RIGHTS) { + /* Populate the acl data to be added to the subtree */ + subtreeclass.mod_op = LDAP_MOD_ADD; + subtreeclass.mod_type = "ACL"; + + if (servicetype == LDAP_KDC_SERVICE) { + for (i=0; strcmp(kdcrights_subtree[i][0], "")!=0; i++) { + subtreeacls[0] = (char *) malloc( strlen(kdcrights_subtree[i][0]) + + strlen(serviceobjdn) + + strlen(kdcrights_subtree[i][1]) + 1); + sprintf( subtreeacls[0], "%s%s%s", kdcrights_subtree[i][0], serviceobjdn, + kdcrights_subtree[i][1]); + subtreeclass.mod_values = subtreeacls; + + subtreearr[0] = &subtreeclass; + + st = ldap_modify_ext_s(ld, + subtree, + subtreearr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_TYPE_OR_VALUE_EXISTS && st != LDAP_OTHER) { + free(subtreeacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(subtreeacls[0]); + } + } else if (servicetype == LDAP_ADMIN_SERVICE) { + for (i=0; strcmp(adminrights_subtree[i][0], "")!=0; i++) { + subtreeacls[0] = (char *) malloc(strlen(adminrights_subtree[i][0]) + + strlen(serviceobjdn) + + strlen(adminrights_subtree[i][1]) + 1); + sprintf( subtreeacls[0], "%s%s%s", adminrights_subtree[i][0], serviceobjdn, + adminrights_subtree[i][1]); + subtreeclass.mod_values = subtreeacls; + + subtreearr[0] = &subtreeclass; + + st = ldap_modify_ext_s(ld, + subtree, + subtreearr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st !=LDAP_TYPE_OR_VALUE_EXISTS && st != LDAP_OTHER) { + free(subtreeacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(subtreeacls[0]); + } + } else if (servicetype == LDAP_PASSWD_SERVICE) { + for (i=0; strcmp(pwdrights_subtree[i][0], "") != 0; i++) { + subtreeacls[0] = (char *)malloc( strlen(pwdrights_subtree[i][0]) + + strlen(serviceobjdn) + + strlen(pwdrights_subtree[i][1]) + 1); + sprintf( subtreeacls[0], "%s%s%s", pwdrights_subtree[i][0], serviceobjdn, + pwdrights_subtree[i][1]); + subtreeclass.mod_values = subtreeacls; + + subtreearr[0] = &subtreeclass; + + st = ldap_modify_ext_s(ld, + subtree, + subtreearr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_TYPE_OR_VALUE_EXISTS && st != LDAP_OTHER) { + free(subtreeacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(subtreeacls[0]); + } + } + } /* Subtree rights settings ends here */ + st = 0; + + cleanup: + + if(realmdn) + free(realmdn); + + if(subtree) + free(subtree); + + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + This will set the rights for the Kerberos service objects. + The function will read the subtree attribute from the specified + realm name and will the appropriate rights on both the realm + container and the subtree. The kerberos context passed should + have a valid ldap handle, with appropriate rights to write acl + attributes. + + krb5_context - IN The Kerberos context with valid ldap handle + +*/ + +krb5_error_code +krb5_ldap_delete_service_rights( context, servicetype, serviceobjdn, realmname, subtreeparam, mask) + krb5_context context; + int servicetype; + char *serviceobjdn; + char *realmname; + char *subtreeparam; + int mask; +{ + + int st=0,i=0; + char *realmacls[2] = { NULL }, *subtreeacls[2] = { NULL }; + LDAP *ld; + LDAPMod realmclass, subtreeclass; + LDAPMod *realmarr[3] = { NULL }, *subtreearr[3] = { NULL }; + char *realmdn=NULL; + char *subtree=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + if((serviceobjdn == NULL) || (realmname == NULL) || (servicetype < 0) || (servicetype > 4) + || (ldap_context->krbcontainer->DN == NULL) ) { + st=-1; + goto cleanup; + } + + /* If the subtree is null, set the value to root */ + if(subtreeparam== NULL) + subtree=strdup(""); + else + subtree=strdup(subtreeparam); + + if( subtree == NULL ) { + st = ENOMEM; + goto cleanup; + } + + + /* Set the rights for the realm */ + if( mask & LDAP_REALM_RIGHTS ) { + + /* Construct the realm dn from realm name */ + realmdn = (char *) malloc( strlen("cn=") + strlen(realmname) + + strlen(ldap_context->krbcontainer->DN) + 2 ); + sprintf(realmdn,"cn=%s,%s", realmname, ldap_context->krbcontainer->DN); + + realmclass.mod_op=LDAP_MOD_DELETE; + realmclass.mod_type="ACL"; + + if (servicetype == LDAP_KDC_SERVICE) { + for (i=0; strcmp(kdcrights_realmcontainer[i][0], "") != 0; i++) { + realmacls[0] = (char *) malloc(strlen(kdcrights_realmcontainer[i][0]) + + strlen(serviceobjdn) + + strlen(kdcrights_realmcontainer[i][1]) + 1); + sprintf( realmacls[0], "%s%s%s", kdcrights_realmcontainer[i][0], serviceobjdn, + kdcrights_realmcontainer[i][1]); + realmclass.mod_values= realmacls; + + realmarr[0]=&realmclass; + + st = ldap_modify_ext_s(ld, + realmdn, + realmarr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_ATTRIBUTE) { + free(realmacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(realmacls[0]); + } + } else if (servicetype == LDAP_ADMIN_SERVICE) { + for (i=0; strcmp(adminrights_realmcontainer[i][0], "") != 0; i++) { + realmacls[0] = (char *) malloc( strlen(adminrights_realmcontainer[i][0]) + + strlen(serviceobjdn) + + strlen(adminrights_realmcontainer[i][1]) + 1); + sprintf(realmacls[0], "%s%s%s", adminrights_realmcontainer[i][0], serviceobjdn, + adminrights_realmcontainer[i][1]); + realmclass.mod_values= realmacls; + + realmarr[0]=&realmclass; + + st = ldap_modify_ext_s(ld, + realmdn, + realmarr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_ATTRIBUTE) { + free(realmacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(realmacls[0]); + } + } else if (servicetype == LDAP_PASSWD_SERVICE) { + for (i=0; strcmp(pwdrights_realmcontainer[i][0], "") != 0; i++) { + realmacls[0]=(char *)malloc( strlen(pwdrights_realmcontainer[i][0]) + + strlen(serviceobjdn) + + strlen(pwdrights_realmcontainer[i][1]) + 1); + sprintf( realmacls[0], "%s%s%s", pwdrights_realmcontainer[i][0], serviceobjdn, + pwdrights_realmcontainer[i][1]); + realmclass.mod_values= realmacls; + + realmarr[0]=&realmclass; + + st = ldap_modify_ext_s(ld, + realmdn, + realmarr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_ATTRIBUTE) { + free(realmacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(realmacls[0]); + } + } + + } /* Realm rights setting ends here */ + + + /* Set the rights for the subtree */ + if (mask & LDAP_SUBTREE_RIGHTS) { + + /* Populate the acl data to be added to the subtree */ + subtreeclass.mod_op=LDAP_MOD_DELETE; + subtreeclass.mod_type="ACL"; + + if(servicetype == LDAP_KDC_SERVICE){ + for (i=0; strcmp(kdcrights_subtree[i][0], "")!=0; i++) { + subtreeacls[0] = (char *) malloc( strlen(kdcrights_subtree[i][0]) + + strlen(serviceobjdn) + + strlen(kdcrights_subtree[i][1]) + 1); + sprintf( subtreeacls[0], "%s%s%s", kdcrights_subtree[i][0], serviceobjdn, + kdcrights_subtree[i][1]); + subtreeclass.mod_values= subtreeacls; + + subtreearr[0]=&subtreeclass; + + st = ldap_modify_ext_s(ld, + subtree, + subtreearr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_ATTRIBUTE) { + free(subtreeacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(subtreeacls[0]); + } + } else if (servicetype == LDAP_ADMIN_SERVICE) { + for (i=0; strcmp(adminrights_subtree[i][0], "") != 0; i++) { + subtreeacls[0] = (char *) malloc(strlen(adminrights_subtree[i][0]) + + strlen(serviceobjdn) + + strlen(adminrights_subtree[i][1]) + 1); + sprintf(subtreeacls[0], "%s%s%s", adminrights_subtree[i][0], serviceobjdn, + adminrights_subtree[i][1]); + subtreeclass.mod_values= subtreeacls; + + subtreearr[0]=&subtreeclass; + + st = ldap_modify_ext_s(ld, + subtree, + subtreearr, + NULL, + NULL); + if ( st != LDAP_SUCCESS && st != LDAP_NO_SUCH_ATTRIBUTE) { + free(subtreeacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(subtreeacls[0]); + } + } + else if (servicetype == LDAP_PASSWD_SERVICE) { + for (i=0; strcmp(pwdrights_subtree[i][0], "") != 0; i++) { + subtreeacls[0] = (char *) malloc(strlen(pwdrights_subtree[i][0]) + + strlen(serviceobjdn) + + strlen(pwdrights_subtree[i][1]) + 1); + sprintf(subtreeacls[0], "%s%s%s", pwdrights_subtree[i][0], serviceobjdn, + pwdrights_subtree[i][1]); + subtreeclass.mod_values= subtreeacls; + + subtreearr[0]=&subtreeclass; + + st = ldap_modify_ext_s(ld, + subtree, + subtreearr, + NULL, + NULL); + if (st != LDAP_SUCCESS && st != LDAP_NO_SUCH_ATTRIBUTE) { + free(subtreeacls[0]); + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + free(subtreeacls[0]); + } + } + } /* Subtree rights setting ends here */ + + st = 0; + + cleanup: + + if(realmdn) + free(realmdn); + + if(subtree) + free(subtree); + + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c new file mode 100644 index 000000000..99e7821ce --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c @@ -0,0 +1,253 @@ +/* + * lib/kdb/kdb_ldap/ldap_service_stash.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 <ctype.h> +#include "ldap_main.h" +#include "kdb_ldap.h" +#include "ldap_service_stash.h" + +krb5_error_code +krb5_ldap_readpassword(context, ldap_context, password) + krb5_context context; + krb5_ldap_context *ldap_context; + unsigned char **password; +{ + int entryfound=0; + krb5_error_code st=0; + char line[RECORDLEN]="0", *start=NULL, *file=NULL; + char errbuf[1024]; + FILE *fptr=NULL; + + *password = NULL; + + if (ldap_context->service_password_file) + file = ldap_context->service_password_file; + + /* check whether file exists */ + if (access(file, F_OK) < 0) { + st = errno; + strerror_r(errno, errbuf, sizeof(errbuf)); + krb5_set_error_message (context, st, "%s", errbuf); + goto rp_exit; + } + + /* check read access */ + if (access(file, R_OK) < 0) { + st = errno; + strerror_r(errno, errbuf, sizeof(errbuf)); + krb5_set_error_message (context, st, "%s", errbuf); + goto rp_exit; + } + + if((fptr=fopen(file, "r")) == NULL) { + st = errno; + strerror_r(errno, errbuf, sizeof(errbuf)); + krb5_set_error_message (context, st, "%s", errbuf); + goto rp_exit; + } + + /* get the record from the file */ + while(fgets(line, RECORDLEN, fptr)!= NULL) { + char tmp[RECORDLEN]; + + tmp[0] = '\0'; + /* Handle leading white-spaces */ + for(start = line; isspace(*start); ++start); + + /* Handle comment lines */ + if (*start == '!' || *start == '#') + continue; + sscanf(line, "%*[ \t]%[^#]", tmp); + if(tmp[0] == '\0') + sscanf(line, "%[^#]", tmp); + if(strcasecmp(tmp, ldap_context->bind_dn) == 0) { + entryfound = 1; /* service_dn record found !!! */ + break; + } + } + fclose (fptr); + + if (entryfound == 0) { + st = KRB5_KDB_SERVER_INTERNAL_ERR; + krb5_set_error_message (context, st, "Bind DN entry missing in stash file"); + goto rp_exit; + } + /* replace the \n with \0 */ + start = strchr(line, '\n'); + if (start) + *start = '\0'; + + start = strchr(line, '#'); + if (start == NULL ) { + /* password field missing */ + st = KRB5_KDB_SERVER_INTERNAL_ERR; + krb5_set_error_message (context, st, "Stash file entry corrupt"); + goto rp_exit; + } + ++ start; + /* Extract the plain password / certificate file information */ + { + struct data PT, CT; + + /* Check if the entry has the path of a certificate */ + if(!strncmp(start, "{FILE}", strlen("{FILE}"))) { + /* Set *password = {FILE}<path to cert>\0<cert password> */ + /*ptr = strchr(start, ':'); + if(ptr == NULL){ */ + *password = (unsigned char *)malloc(strlen(start) + 2); + (*password)[strlen(start) + 1] = '\0'; + (*password)[strlen(start)] = '\0'; + strcpy((char *)(*password), start); + goto got_password; + } else { + CT.value = (unsigned char *)start; + CT.len = strlen((char *)CT.value); + st = dec_password(CT, &PT); + if(st != 0){ + goto rp_exit; + } + *password = PT.value; + } + } + got_password: + + rp_exit: + if (st) { + if (*password) + free (*password); + *password = NULL; + } + return st; +} + +/* Encodes a sequence of bytes in hexadecimal */ + +int +tohex(in, ret) + krb5_data in; + krb5_data *ret; +{ + int i=0, j=0, err = 0; + + ret->length = 0; + ret->data = NULL; + + ret->data = (unsigned char *)malloc((unsigned int)in.length * 2 + 1 /*Null termination */); + if (ret->data == NULL) { + err = ENOMEM; + goto cleanup; + } + ret->length = in.length * 2; + ret->data[ret->length] = 0; + + for (i = 0, j = 0; i < in.length; i++, j += 2) { + sprintf((char *)ret->data + j, "%x", in.data[i] >> 4); + sprintf((char *)ret->data + j + 1, "%x", in.data[i] & 0xf); + } + + cleanup: + + if (ret->length == 0) { + free(ret->data); + ret->data = NULL; + } + + return err; +} + +/* The entry in the password file will have the following format + * <FQDN of service> = <secret> + * <secret> := {HEX}<password in hexadecimal> + * + * <password> is the actual eDirectory password of the service + */ + +int dec_password(struct data pwd, struct data *ret){ + int err=0; + int i=0, j=0; + + ret->len = 0; + ret->value = NULL; + + if (pwd.len == 0) { + err = EINVAL; + krb5_set_error_message (0, err, "Password has zero length"); + ret->len = 0; + goto cleanup; + } + + /* Check if it is a hexadecimal encoded password */ + if (pwd.len >= strlen("{HEX}") && + strncmp((char *)pwd.value, "{HEX}", strlen("{HEX}")) == 0) { + + if((pwd.len - strlen("{HEX}")) % 2 != 0){ + /* A hexadecimal encoded password should have even length */ + err = EINVAL; + krb5_set_error_message (0, err, "Password corrupted"); + ret->len = 0; + goto cleanup; + } + ret->value = (unsigned char *)malloc((pwd.len - strlen("{HEX}")) / 2 + 1); + if(ret->value == NULL){ + err = ENOMEM; + ret->len = 0; + goto cleanup; + } + ret->len = (pwd.len - strlen("{HEX}")) / 2; + ret->value[ret->len] = '\0'; + for (i = strlen("{HEX}"), j = 0; i < pwd.len; i += 2, j++) { + int k; + /* Check if it is a hexadecimal number */ + if (isxdigit(pwd.value[i]) == 0 || isxdigit(pwd.value[i + 1]) == 0) { + err = EINVAL; + krb5_set_error_message (0, err, "Not a hexadecimal password"); + ret->len = 0; + goto cleanup; + } + sscanf((char *)pwd.value + i, "%2x", &k); + ret->value[j] = k; + } + goto cleanup; + } else { + err = EINVAL; + krb5_set_error_message (0, err, "Not a hexadecimal password"); + ret->len = 0; + goto cleanup; + } + + cleanup: + + if(ret->len == 0) { + free(ret->value); + ret->value = NULL; + } + return(err); +} + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h new file mode 100644 index 000000000..c51d1a172 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h @@ -0,0 +1,50 @@ +/* + * lib/kdb/kdb_ldap/ldap_service_stash.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef LDAP_SERVICE_STASH_H +#define LDAP_SERVICE_STASH_H 1 + +#define RECORDLEN 1024 +struct data{ + int len; + unsigned char *value; +}; + +int +dec_password(struct data, struct data *); + +krb5_error_code +krb5_ldap_readpassword(krb5_context, krb5_ldap_context *, unsigned char **); + +int +tohex(krb5_data, krb5_data *); + +#endif + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_services.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_services.c new file mode 100644 index 000000000..fa1bdd7b3 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_services.c @@ -0,0 +1,595 @@ +/* + * lib/kdb/kdb_ldap/ldap_services.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" +#include "kdb_ldap.h" +#include "ldap_services.h" +#include "ldap_err.h" + +#if defined(HAVE_EDIRECTORY) + +static char *realmcontclass[] = {"krbRealmContainer", NULL}; + +/* + * create the service object from Directory + */ + +krb5_error_code +krb5_ldap_create_service(context, service, mask) + krb5_context context; + krb5_ldap_service_params *service; + int mask; +{ + int i=0, j=0; + krb5_error_code st=0; + LDAP *ld=NULL; + char **rdns=NULL, *realmattr=NULL, *strval[3]={NULL}; + LDAPMod **mods=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + char errbuf[1024]; + + /* validate the input parameter */ + if (service == NULL || service->servicedn == NULL) { + st = EINVAL; + krb5_set_error_message (context, st, "Service DN NULL"); + goto cleanup; + } + + SETUP_CONTEXT(); + GET_HANDLE(); + + /* identify the class that the object should belong to. This depends on the servicetype */ + memset(strval, 0, sizeof(strval)); + strval[0] = "krbService"; + if (service->servicetype == LDAP_KDC_SERVICE) { + strval[1] = "krbKdcService"; + realmattr = "krbKdcServers"; + } else if (service->servicetype == LDAP_ADMIN_SERVICE) { + strval[1] = "krbAdmService"; + realmattr = "krbAdmServers"; + } else if (service->servicetype == LDAP_PASSWD_SERVICE) { + strval[1] = "krbPwdService"; + realmattr = "krbPwdServers"; + } else { + strval[1] = "krbKdcService"; + realmattr = "krbKdcServers"; + } + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + rdns = ldap_explode_dn(service->servicedn, 1); + if (rdns == NULL) { + st = LDAP_INVALID_DN_SYNTAX; + goto cleanup; + } + memset(strval, 0, sizeof(strval)); + strval[0] = rdns[0]; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + if (mask & LDAP_SERVICE_SERVICEFLAG) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbserviceflags", LDAP_MOD_ADD, + service->krbserviceflags)) != 0) + goto cleanup; + } + + if (mask & LDAP_SERVICE_HOSTSERVER) { + if (service->krbhostservers != NULL) { + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbhostserver", LDAP_MOD_ADD, + service->krbhostservers)) != 0) + goto cleanup; + } else { + st = EINVAL; + krb5_set_error_message (context, st, "'krbhostserver' argument invalid"); + goto cleanup; + } + } + + if (mask & LDAP_SERVICE_REALMREFERENCE) { + if (service->krbrealmreferences != NULL) { + unsigned int realmmask=0; + + /* check for the validity of the values */ + for (j=0; service->krbrealmreferences[j] != NULL; ++j) { + st = checkattributevalue(ld, service->krbrealmreferences[j], "ObjectClass", + realmcontclass, &realmmask); + CHECK_CLASS_VALIDITY(st, realmmask, "realm object value: "); + } + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbrealmreferences", LDAP_MOD_ADD, + service->krbrealmreferences)) != 0) + goto cleanup; + } else { + st = EINVAL; + krb5_set_error_message (context, st, "Server has no 'krbrealmreferences'"); + goto cleanup; + } + } + + /* ldap add operation */ + if ((st=ldap_add_s(ld, service->servicedn, mods)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_ADD); + goto cleanup; + } + + /* + * If the service created has realm/s associated with it, then the realm should be updated + * to have a reference to the service object just created. + */ + if (mask & LDAP_SERVICE_REALMREFERENCE) { + for (i=0; service->krbrealmreferences[i]; ++i) { + if((st=updateAttribute(ld, service->krbrealmreferences[i], realmattr, + service->servicedn)) != 0) { + sprintf (errbuf, "Error adding 'krbRealmReferences' to %s: ", + service->krbrealmreferences[i]); + prepend_err_str (context, errbuf, st, st); + /* delete service object, status ignored intentionally */ + ldap_delete_s(ld, service->servicedn); + goto cleanup; + } + } + } + + cleanup: + + if (rdns) + ldap_value_free (rdns); + + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * modify the service object from Directory + */ + +krb5_error_code +krb5_ldap_modify_service(context, service, mask) + krb5_context context; + krb5_ldap_service_params *service; + int mask; +{ + int i=0, j=0, count=0; + krb5_error_code st=0; + LDAP *ld=NULL; + char **values=NULL, *attr[] = { "krbRealmReferences", NULL}; + char *realmattr=NULL; + char **oldrealmrefs=NULL, **newrealmrefs=NULL; + LDAPMod **mods=NULL; + LDAPMessage *result=NULL, *ent=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + /* validate the input parameter */ + if (service == NULL || service->servicedn == NULL) { + st = EINVAL; + krb5_set_error_message (context, st, "Service DN is NULL"); + goto cleanup; + } + + SETUP_CONTEXT(); + GET_HANDLE(); + + if (mask & LDAP_SERVICE_SERVICEFLAG) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbserviceflags", LDAP_MOD_REPLACE, + service->krbserviceflags)) != 0) + goto cleanup; + } + + if (mask & LDAP_SERVICE_HOSTSERVER) { + if (service->krbhostservers != NULL) { + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbhostserver", LDAP_MOD_REPLACE, + service->krbhostservers)) != 0) + goto cleanup; + } else { + st = EINVAL; + krb5_set_error_message (context, st, "'krbhostserver' value invalid"); + goto cleanup; + } + } + + if (mask & LDAP_SERVICE_REALMREFERENCE) { + if (service->krbrealmreferences != NULL) { + unsigned int realmmask=0; + + /* check for the validity of the values */ + for (j=0; service->krbrealmreferences[j]; ++j) { + st = checkattributevalue(ld, service->krbrealmreferences[j], "ObjectClass", + realmcontclass, &realmmask); + CHECK_CLASS_VALIDITY(st, realmmask, "realm object value: "); + } + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbrealmreferences", LDAP_MOD_REPLACE, + service->krbrealmreferences)) != 0) + goto cleanup; + + + /* get the attribute of the realm to be set */ + if (service->servicetype == LDAP_KDC_SERVICE) + realmattr = "krbKdcServers"; + else if (service->servicetype == LDAP_ADMIN_SERVICE) + realmattr = "krbAdmservers"; + else if (service->servicetype == LDAP_PASSWD_SERVICE) + realmattr = "krbPwdServers"; + else + realmattr = "krbKdcServers"; + + /* read the existing list of krbRealmreferences. this will needed */ + if ((st = ldap_search_s (ld, + service->servicedn, + LDAP_SCOPE_BASE, + 0, + attr, + 0, + &result)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_SEARCH); + goto cleanup; + } + + ent = ldap_first_entry(ld, result); + if (ent) { + if ((values=ldap_get_values(ld, ent, "krbRealmReferences")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &oldrealmrefs, count)) != 0) + goto cleanup; + ldap_value_free(values); + } + } + ldap_msgfree(result); + } else { + st = EINVAL; + krb5_set_error_message (context, st, "'krbRealmReferences' value invalid"); + goto cleanup; + } + } + + /* ldap modify operation */ + if ((st=ldap_modify_s(ld, service->servicedn, mods)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + + /* + * If the service modified had realm/s associations changed, then the realm should be + * updated to reflect the changes. + */ + + if (mask & LDAP_SERVICE_REALMREFERENCE) { + /* get the count of the new list of krbrealmreferences */ + for (i=0; service->krbrealmreferences[i]; ++i) + ; + + /* make a new copy of the krbrealmreferences */ + if ((st=copy_arrays(service->krbrealmreferences, &newrealmrefs, i)) != 0) + goto cleanup; + + /* find the deletions/additions to the list of krbrealmreferences */ + if (disjoint_members(oldrealmrefs, newrealmrefs) != 0) + goto cleanup; + + /* see if some of the attributes have to be deleted */ + if (oldrealmrefs) { + + /* update the dn represented by the attribute that is to be deleted */ + for (i=0; oldrealmrefs[i]; ++i) + if((st=deleteAttribute(ld, oldrealmrefs[i], realmattr, service->servicedn)) != 0) + { + prepend_err_str (context, "Error deleting realm attribute:", st, st); + goto cleanup; + } + } + + /* see if some of the attributes have to be added */ + for (i=0; newrealmrefs[i]; ++i) + if((st=updateAttribute(ld, newrealmrefs[i], realmattr, service->servicedn)) != 0) + { + prepend_err_str (context, "Error updating realm attribute: ", st, st); + goto cleanup; + } + } + + cleanup: + + if (oldrealmrefs) { + for (i=0; oldrealmrefs[i]; ++i) + free (oldrealmrefs[i]); + free (oldrealmrefs); + } + + if (newrealmrefs) { + for (i=0; newrealmrefs[i]; ++i) + free (newrealmrefs[i]); + free (newrealmrefs); + } + + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +krb5_error_code +krb5_ldap_delete_service(context, service, servicedn) + krb5_context context; + krb5_ldap_service_params *service; + char *servicedn; +{ + krb5_error_code st = 0; + LDAP *ld=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + st = ldap_delete_s(ld, servicedn); + if (st != 0) { + st = set_ldap_error (context, st, OP_DEL); + } + + /* NOTE: This should be removed now as the backlinks are going off in OpenLDAP */ + /* time to delete krbrealmreferences. This is only for OpenLDAP */ +#ifndef HAVE_EDIRECTORY + { + int i=0; + char *attr=NULL; + + if (service) { + if (service->krbrealmreferences) { + if (service->servicetype == LDAP_KDC_SERVICE) + attr = "krbkdcservers"; + else if (service->servicetype == LDAP_ADMIN_SERVICE) + attr = "krbadmservers"; + else if (service->servicetype == LDAP_PASSWD_SERVICE) + attr = "krbpwdservers"; + + for (i=0; service->krbrealmreferences[i]; ++i) { + deleteAttribute(ld, service->krbrealmreferences[i], attr, servicedn); + } + } + } + } +#endif + + cleanup: + + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * This function lists service objects from Directory + */ + +krb5_error_code +krb5_ldap_list_services(context, containerdn, services) + krb5_context context; + char *containerdn; + char ***services; +{ + return (krb5_ldap_list(context, services, "krbService", containerdn)); +} + +/* + * This function reads the service object from Directory + */ +krb5_error_code +krb5_ldap_read_service(context, servicedn, service, omask) + krb5_context context; + char *servicedn; + krb5_ldap_service_params **service; + int *omask; +{ + char **values=NULL; + int i=0, count=0, objectmask=0; + krb5_error_code st=0, tempst=0; + LDAPMessage *result=NULL,*ent=NULL; + char *attributes[] = {"krbHostServer", "krbServiceflags", + "krbRealmReferences", "objectclass", NULL}; + char *attrvalues[] = {"krbService", NULL}; + krb5_ldap_service_params *lservice=NULL; + krb5_ldap_context *ldap_context=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + LDAP *ld = NULL; + + /* validate the input parameter */ + if (servicedn == NULL) { + st = EINVAL; + krb5_set_error_message (context, st, "Service DN NULL"); + goto cleanup; + } + + SETUP_CONTEXT(); + GET_HANDLE(); + + *omask = 0; + + /* the policydn object should be of the krbService object class */ + st = checkattributevalue(ld, servicedn, "objectClass", attrvalues, &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "service object value: "); + + /* Initialize service structure */ + lservice =(krb5_ldap_service_params *) calloc(1, sizeof(krb5_ldap_service_params)); + if (lservice == NULL) { + st = ENOMEM; + goto cleanup; + } + + /* allocate tl_data structure to store MASK information */ + lservice->tl_data = calloc (1, sizeof(*lservice->tl_data)); + if (lservice->tl_data == NULL) { + st = ENOMEM; + goto cleanup; + } + lservice->tl_data->tl_data_type = KDB_TL_USER_INFO; + + LDAP_SEARCH(servicedn, LDAP_SCOPE_BASE, "(objectclass=krbService)", attributes); + + lservice->servicedn = strdup(servicedn); + CHECK_NULL(lservice->servicedn); + + ent=ldap_first_entry(ld, result); + if (ent != NULL) { + + if((values=ldap_get_values(ld, ent, "krbServiceFlags")) != NULL) { + lservice->krbserviceflags = atoi(values[0]); + *omask |= LDAP_SERVICE_SERVICEFLAG; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbHostServer")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &(lservice->krbhostservers), count)) != 0) + goto cleanup; + *omask |= LDAP_SERVICE_HOSTSERVER; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "krbRealmReferences")) != NULL) { + count = ldap_count_values(values); + if ((st=copy_arrays(values, &(lservice->krbrealmreferences), count)) != 0) + goto cleanup; + *omask |= LDAP_SERVICE_REALMREFERENCE; + ldap_value_free(values); + } + + if((values=ldap_get_values(ld, ent, "objectClass")) != NULL) { + for (i=0; values[i]; ++i){ + if (strcasecmp(values[i], "krbKdcService") == 0) { + lservice->servicetype = LDAP_KDC_SERVICE; + break; + } + + if (strcasecmp(values[i], "krbAdmService") == 0) { + lservice->servicetype = LDAP_ADMIN_SERVICE; + break; + } + + if (strcasecmp(values[i], "krbPwdService") == 0) { + lservice->servicetype = LDAP_PASSWD_SERVICE; + break; + } + } + ldap_value_free(values); + } + } + ldap_msgfree(result); + + cleanup: + if(st != 0) { + krb5_ldap_free_service(context, lservice); + *service = NULL; + } else { + store_tl_data(lservice->tl_data, KDB_TL_MASK, omask); + *service = lservice; + } + + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + +/* + * This function frees the krb5_ldap_service_params structure members. + */ + +krb5_error_code +krb5_ldap_free_service(context, service) + krb5_context context; + krb5_ldap_service_params *service; +{ + int i=0; + + if (service == NULL) + return 0; + + if (service->servicedn) + free (service->servicedn); + + if (service->krbrealmreferences) { + for (i=0; service->krbrealmreferences[i]; ++i) + free (service->krbrealmreferences[i]); + free (service->krbrealmreferences); + } + + if (service->krbhostservers) { + for (i=0; service->krbhostservers[i]; ++i) + free (service->krbhostservers[i]); + free (service->krbhostservers); + } + + if (service->tl_data) { + if (service->tl_data->tl_data_contents) + free (service->tl_data->tl_data_contents); + free (service->tl_data); + } + + free (service); + return 0; +} + +krb5_error_code +krb5_ldap_set_service_passwd(context, service, passwd) + krb5_context context; + char *service; + char *passwd; +{ + krb5_error_code st=0; + LDAPMod **mods=NULL; + char *password[2] = {NULL}; + LDAP *ld=NULL; + krb5_ldap_context *ldap_context=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + password[0] = passwd; + + SETUP_CONTEXT(); + GET_HANDLE(); + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "userPassword", LDAP_MOD_REPLACE, password)) != 0) + goto cleanup; + + st = ldap_modify_s(ld, service, mods); + if (st) { + st = set_ldap_error (context, st, OP_MOD); + } + + cleanup: + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_services.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_services.h new file mode 100644 index 000000000..d2676a3d4 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_services.h @@ -0,0 +1,97 @@ +/* + * lib/kdb/kdb_ldap/ldap_services.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef _LDAP_SERVICE_H +#define _LDAP_SERVICE_H 1 + +/* service specific mask */ +#define LDAP_SERVICE_SERVICEFLAG 0x0001 +#define LDAP_SERVICE_HOSTSERVER 0x0002 +#define LDAP_SERVICE_REALMREFERENCE 0x0004 + +/* service type mask */ +#define LDAP_KDC_SERVICE 0x0001 +#define LDAP_ADMIN_SERVICE 0x0002 +#define LDAP_PASSWD_SERVICE 0x0004 + +/* rights mask */ +#define LDAP_SUBTREE_RIGHTS 0x0001 +#define LDAP_REALM_RIGHTS 0x0002 + +/* Types of service flags */ +#define SERVICE_FLAGS_AUTO_RESTART 0x0001 +#define SERVICE_FLAGS_CHECK_ADDRESSES 0x0002 +#define SERVICE_FLAGS_UNIXTIME_OLD_PATYPE 0x0004 + +/* Service protocol type */ +#define SERVICE_PROTOCOL_TYPE_UDP "0" +#define SERVICE_PROTOCOL_TYPE_TCP "1" + +typedef struct _krb5_ldap_service_params { + char *servicedn; + int servicetype; + int krbserviceflags; + char **krbhostservers; + char **krbrealmreferences; + krb5_tl_data *tl_data; +} krb5_ldap_service_params; + +#ifdef HAVE_EDIRECTORY + +krb5_error_code +krb5_ldap_read_service( krb5_context, char *, krb5_ldap_service_params **, int *); + +krb5_error_code +krb5_ldap_create_service( krb5_context, krb5_ldap_service_params *,int); + +krb5_error_code +krb5_ldap_modify_service( krb5_context, krb5_ldap_service_params *, int); + +krb5_error_code +krb5_ldap_delete_service( krb5_context, krb5_ldap_service_params *, char *); + +krb5_error_code +krb5_ldap_list_services( krb5_context, char *, char ***); + +krb5_error_code +krb5_ldap_free_service( krb5_context, krb5_ldap_service_params *); + + +krb5_error_code +krb5_ldap_set_service_passwd( krb5_context, char *, char *); + +krb5_error_code +krb5_ldap_add_service_rights( krb5_context, int, char *, char *, char *, int); + +krb5_error_code +krb5_ldap_delete_service_rights( krb5_context, int, char *, char *, char *, int); +#endif + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.c new file mode 100644 index 000000000..f5948786f --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.c @@ -0,0 +1,526 @@ +/* + * lib/kdb/kdb_ldap/ldap_tkt_policy.c + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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 "ldap_main.h" +#include "kdb_ldap.h" +#include "ldap_tkt_policy.h" +#include "ldap_err.h" + +/* Ticket policy object management */ + +/* +* This function changes the value of policyreference count for a particular ticket policy. if flag is 1 it will increment else it will reduce by one +*/ + +krb5_error_code +krb5_ldap_change_count(context ,policydn ,flag) + krb5_context context; + char *policydn; + int flag; +{ + + krb5_error_code st=0; + int objectmask=0; + LDAP *ld=NULL; + char *attrvalues[] = { "krbPolicy", NULL}; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + krb5_ldap_policy_params *policyparams=NULL; + int mask = 0; + + /* validate the input parameters */ + if (policydn == NULL) { + st = EINVAL; + prepend_err_str(context,"Ticket Policy Object information missing",st,st); + goto cleanup; + } + + SETUP_CONTEXT(); + GET_HANDLE(); + + /* the policydn object should be of the krbPolicy object class */ + st = checkattributevalue(ld, policydn, "objectClass", attrvalues, &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); + + /* Initialize ticket policy structure */ + + if ((st = krb5_ldap_read_policy(context, policydn, &policyparams, &mask))) + goto cleanup; + if(flag == 1){ + /*Increment*/ + policyparams->polrefcount +=1; + } + else{ + /*Decrement*/ + if(policyparams->polrefcount >0) + { + policyparams->polrefcount-=1; + } + } + mask |= LDAP_POLICY_COUNT; + + if ((st = krb5_ldap_modify_policy(context, policyparams, mask))) + goto cleanup; + +cleanup: + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + +/* + * create the Ticket policy object in Directory. + */ +krb5_error_code +krb5_ldap_create_policy(context, policy, mask) + krb5_context context; + krb5_ldap_policy_params *policy; + int mask; +{ + krb5_error_code st=0; + LDAP *ld=NULL; + char **rdns=NULL, *strval[3]={NULL}; + LDAPMod **mods=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + /* validate the input parameters */ + if (policy == NULL || policy->policydn==NULL) { + st = EINVAL; + krb5_set_error_message (context, st, "Ticket Policy Object DN missing"); + goto cleanup; + } + + SETUP_CONTEXT(); + GET_HANDLE(); + + rdns = ldap_explode_dn(policy->policydn, 1); + if (rdns == NULL) { + st = LDAP_INVALID_DN_SYNTAX; + goto cleanup; + } + + memset(strval, 0, sizeof(strval)); + strval[0] = rdns[0]; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + memset(strval, 0, sizeof(strval)); + strval[0] = "krbPolicy"; + strval[1] = "krbPolicyaux"; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + if (mask & LDAP_POLICY_MAXTKTLIFE) { + if((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_ADD, + policy->maxtktlife)) != 0) + goto cleanup; + } + + if (mask & LDAP_POLICY_MAXRENEWLIFE) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_ADD, + policy->maxrenewlife)) != 0) + goto cleanup; + } + + if (mask & LDAP_POLICY_TKTFLAGS) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_ADD, + policy->tktflags)) != 0) + goto cleanup; + } + /*ticket policy reference count attribute added with value 0 */ + + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbPolicyRefCount", LDAP_MOD_ADD, + 0)) != 0) + goto cleanup; + + /* ldap add operation */ + if ((st=ldap_add_s(ld, policy->policydn, mods)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_ADD); + goto cleanup; + } + + cleanup: + if (rdns) + ldap_value_free(rdns); + + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * modify the Ticket policy object in Directory. + */ + +krb5_error_code +krb5_ldap_modify_policy(context, policy, mask) + krb5_context context; + krb5_ldap_policy_params *policy; + int mask; +{ + int objectmask=0; + krb5_error_code st=0; + LDAP *ld=NULL; + char *attrvalues[]={"krbPolicy", "krbPolicyAux", NULL}, *strval[2]={NULL}; + LDAPMod **mods=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + /* validate the input parameters */ + if (policy == NULL || policy->policydn==NULL) { + st = EINVAL; + krb5_set_error_message (context, st, "Ticket Policy Object DN missing"); + goto cleanup; + } + + SETUP_CONTEXT(); + GET_HANDLE(); + + /* the policydn object should be of the krbPolicy object class */ + st = checkattributevalue(ld, policy->policydn, "objectClass", attrvalues, &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); + + if ((objectmask & 0x02) == 0) { /* add krbpolicyaux to the object class list */ + memset(strval, 0, sizeof(strval)); + strval[0] = "krbPolicyAux"; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + } + + if (mask & LDAP_POLICY_MAXTKTLIFE) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, + policy->maxtktlife)) != 0) + goto cleanup; + } + + if (mask & LDAP_POLICY_MAXRENEWLIFE) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE, + policy->maxrenewlife)) != 0) + goto cleanup; + } + + if (mask & LDAP_POLICY_TKTFLAGS) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE, + policy->tktflags)) != 0) + goto cleanup; + } + + if (mask & LDAP_POLICY_COUNT) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbpolicyrefcount", LDAP_MOD_REPLACE, + policy->polrefcount)) != 0) + goto cleanup; + } + if ((st=ldap_modify_s(ld, policy->policydn, mods)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } + + cleanup: + ldap_mods_free(mods, 1); + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * Read the policy object from the Directory and populate the krb5_ldap_policy_params + * structure. + */ + +krb5_error_code +krb5_ldap_read_policy(context, policydn, policy, omask) + krb5_context context; + char *policydn; + krb5_ldap_policy_params **policy; + int *omask; +{ + krb5_error_code st=0, tempst=0; + int objectmask=0; + LDAP *ld=NULL; + LDAPMessage *result=NULL,*ent=NULL; + char *attributes[] = { "krbMaxTicketLife", "krbMaxRenewableAge", "krbTicketFlags", "krbPolicyRefCount", NULL}; + char *attrvalues[] = { "krbPolicy", NULL}; + krb5_ldap_policy_params *lpolicy=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + /* validate the input parameters */ + if (policydn == NULL || policy == NULL) { + st = EINVAL; + krb5_set_error_message(context, st, "Ticket Policy Object information missing"); + goto cleanup; + } + + SETUP_CONTEXT(); + GET_HANDLE(); + + /* the policydn object should be of the krbPolicy object class */ + st = checkattributevalue(ld, policydn, "objectClass", attrvalues, &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); + + /* Initialize ticket policy structure */ + lpolicy =(krb5_ldap_policy_params *) malloc(sizeof(krb5_ldap_policy_params)); + CHECK_NULL(lpolicy); + memset(lpolicy, 0, sizeof(krb5_ldap_policy_params)); + + lpolicy->tl_data = calloc (1, sizeof(*lpolicy->tl_data)); + CHECK_NULL(lpolicy->tl_data); + lpolicy->tl_data->tl_data_type = KDB_TL_USER_INFO; + + LDAP_SEARCH(policydn, LDAP_SCOPE_BASE, "(objectclass=krbPolicy)", attributes); + + *omask = 0; + lpolicy->policydn = strdup(policydn); + CHECK_NULL(lpolicy->policydn); + + ent=ldap_first_entry(ld, result); + if (ent != NULL) { + if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", (int *) &(lpolicy->maxtktlife)) == 0) + *omask |= LDAP_POLICY_MAXTKTLIFE; + + if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", (int *) &(lpolicy->maxrenewlife)) == 0) + *omask |= LDAP_POLICY_MAXRENEWLIFE; + + if (krb5_ldap_get_value(ld, ent, "krbticketflags", (int *) &(lpolicy->tktflags)) == 0) + *omask |= LDAP_POLICY_TKTFLAGS; + if (krb5_ldap_get_value(ld, ent, "krbPolicyRefCount", (int *) &(lpolicy->polrefcount)) == 0) + *omask |= LDAP_POLICY_COUNT; + + } + ldap_msgfree(result); + + lpolicy->mask = *omask; + store_tl_data(lpolicy->tl_data, KDB_TL_MASK, omask); + *policy = lpolicy; + + cleanup: + if (st != 0) { + krb5_ldap_free_policy(context, lpolicy); + *policy = NULL; + } + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * function to delete ticket policy object from the directory. Before calling this function krb5_ldap_read_policy + * should be called to check the existence of the object. This serves one major purpose, i.e. if the object to be + * is anything other than the ticket policy object then the krb5_ldap_read_policy returns an error and thus is not + * accidently deleted in this function. + * + * NOTE: Other kerberos objects (user/realm object) might be having references to the + * policy object to be deleted. This situation is not handled here, instead is taken care + * of at all the places where the deleted policy object is read, to ignore a return status + * of LDAP_NO_SUCH_OBJECT and continue. + */ + +krb5_error_code +krb5_ldap_delete_policy(context, policydn, policy, mask) + krb5_context context; + char *policydn; + krb5_ldap_policy_params *policy; + int mask; +{ + krb5_error_code st = 0; + LDAP *ld = NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + if (policy == NULL || policydn==NULL) { + st = EINVAL; + prepend_err_str (context,"Ticket Policy Object DN missing",st,st); + goto cleanup; + } + + + SETUP_CONTEXT(); + GET_HANDLE(); + + + /*checking for policy count for 0 and will not permit delete if it is greater than 0*/ + + if(policy->polrefcount == 0){ + + if ((st=ldap_delete_s(ld, policydn)) != 0) + { + prepend_err_str (context,ldap_err2string(st),st,st); + + goto cleanup; + } + } + else { + st = EINVAL; + prepend_err_str (context,"Delete Failed: One or more Principals associated with the Ticket Policy",st,st); + goto cleanup; + } + +cleanup: + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} + + +/* + * list policy objects from Directory + */ + +krb5_error_code +krb5_ldap_list_policy(context, containerdn, policy) + krb5_context context; + char *containerdn; + char ***policy; +{ + krb5_error_code st=0; + + st = krb5_ldap_list(context, policy, "krbPolicy", containerdn); + + return st; +} + +/* + * Function to free the ticket policy object structure. + * Note: this function assumes that memory of the policy structure is dynamically allocated and hence the whole + * structure is freed up. Care should be taken not to call this function on a static structure + */ + +krb5_error_code +krb5_ldap_free_policy(context, policy) + krb5_context context; + krb5_ldap_policy_params *policy; +{ + + krb5_error_code st=0; + + if (policy == NULL) + return st; + + if (policy->policydn) + free (policy->policydn); + + if (policy->tl_data) { + if (policy->tl_data->tl_data_contents) + free (policy->tl_data->tl_data_contents); + free (policy->tl_data); + } + free (policy); + + return st; +} + +/* + * This function is general object listing routine. It is currently used for ticket policy + * object listing. + */ + +krb5_error_code +krb5_ldap_list(context, list, objectclass, containerdn) + krb5_context context; + char ***list; + char *objectclass; + char *containerdn; +{ + char *filter=NULL, *dn=NULL; + krb5_error_code st=0, tempst=0; + int i=0, count=0, filterlen=0; + LDAP *ld=NULL; + LDAPMessage *result=NULL,*ent=NULL; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_server_handle *ldap_server_handle=NULL; + + SETUP_CONTEXT(); + GET_HANDLE(); + + /* check if the containerdn exists */ + if (containerdn) { + if ((st=checkattributevalue(ld, containerdn, NULL, NULL, NULL)) != 0) { + prepend_err_str (context, "Error reading container object: ", st, st); + goto cleanup; + } + } + + /* set the filter for the search operation */ + filterlen = strlen("(objectclass=") + strlen(objectclass) + 1 + 1; + filter = malloc ((unsigned) filterlen); + if (filter == NULL) { + st = ENOMEM; + goto cleanup; + } + snprintf(filter, (unsigned) filterlen,"(objectclass=%s)",objectclass); + + LDAP_SEARCH(containerdn, LDAP_SCOPE_SUBTREE, filter, NULL); + + count = ldap_count_entries(ld, result); + if (count == -1) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &st); + st = set_ldap_error(context, st, OP_SEARCH); + goto cleanup; + } + *list = (char **) calloc ((unsigned) count+1, sizeof(char *)); + if (*list == NULL) { + st = ENOMEM; + goto cleanup; + } + + for(ent=ldap_first_entry(ld, result), count=0; ent != NULL; ent=ldap_next_entry(ld, ent), ++count) { + if ((dn=ldap_get_dn(ld, ent)) == NULL) + continue; + if (((*list)[count] = strdup(dn)) == NULL) { + ldap_memfree (dn); + st = ENOMEM; + goto cleanup; + } + ldap_memfree(dn); + } + ldap_msgfree(result); + + cleanup: + if (filter) + free (filter); + + /* some error, free up all the memory */ + if (st != 0) { + if (*list) { + for (i=0; (*list)[i]; ++i) + free ((*list)[i]); + free (*list); + *list = NULL; + } + } + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + return st; +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.h new file mode 100644 index 000000000..a5d198777 --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.h @@ -0,0 +1,76 @@ +/* + * lib/kdb/kdb_ldap/ldap_tkt_policy.h + * + * 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 + * documentation and/or other materials provided with the distribution. + * * 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. + */ + +#ifndef _LDAP_POLICY_H +#define _LDAP_POLICY_H 1 + +/* policy specific mask */ + +#define LDAP_POLICY_MAXTKTLIFE 0x0001 +#define LDAP_POLICY_MAXRENEWLIFE 0x0002 +#define LDAP_POLICY_TKTFLAGS 0x0004 +#define LDAP_POLICY_COUNT 0x0008 +/* policy object structure */ + +typedef struct _krb5_ldap_policy_params { + char *policydn; + long mask; + long maxtktlife; + long maxrenewlife; + long tktflags; + long polrefcount; + krb5_tl_data *tl_data; +}krb5_ldap_policy_params; + +krb5_error_code +krb5_ldap_create_policy(krb5_context, krb5_ldap_policy_params *, int); + +krb5_error_code +krb5_ldap_modify_policy(krb5_context, krb5_ldap_policy_params *, int); + +krb5_error_code +krb5_ldap_read_policy(krb5_context, char *, krb5_ldap_policy_params **, int *); + +krb5_error_code +krb5_ldap_delete_policy(krb5_context, char *, krb5_ldap_policy_params *, int); + +krb5_error_code +krb5_ldap_clear_policy(krb5_context, char *); + +krb5_error_code +krb5_ldap_list_policy(krb5_context, char *, char ***); + +krb5_error_code +krb5_ldap_free_policy(krb5_context, krb5_ldap_policy_params *); + +krb5_error_code +krb5_ldap_change_count(krb5_context ,char * , int); + +#endif diff --git a/src/plugins/kdb/ldap/libkdb_ldap/libkdb_ldap.exports b/src/plugins/kdb/ldap/libkdb_ldap/libkdb_ldap.exports new file mode 100644 index 000000000..2e75b7eae --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/libkdb_ldap.exports @@ -0,0 +1,41 @@ +tohex +krb5_ldap_open +krb5_ldap_close +krb5_ldap_db_init +krb5_ldap_lib_init +krb5_ldap_lib_cleanup +krb5_ldap_db_get_age +krb5_ldap_read_server_params +krb5_ldap_put_principal +krb5_ldap_get_principal +krb5_ldap_delete_principal +krb5_ldap_free_principal +krb5_ldap_iterate +krb5_ldap_read_krbcontainer_params +krb5_ldap_list_realm +krb5_ldap_read_realm_params +krb5_ldap_free_realm_params +krb5_ldap_modify_realm +krb5_ldap_create_krbcontainer +krb5_ldap_create_realm +krb5_ldap_delete_realm +krb5_ldap_list_policy +krb5_ldap_free_policy +krb5_ldap_read_policy +krb5_ldap_modify_policy +krb5_ldap_delete_policy +krb5_ldap_create_policy +krb5_ldap_create_password_policy +krb5_ldap_put_password_policy +krb5_ldap_get_password_policy +krb5_ldap_delete_password_policy +krb5_ldap_free_password_policy +krb5_ldap_iterate_password_policy +krb5_dbe_free_contents +krb5_ldap_free_server_params +krb5_ldap_free_krbcontainer_params +krb5_ldap_alloc +krb5_ldap_free +krb5_ldap_set_mkey +krb5_ldap_get_mkey +disjoint_members diff --git a/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c b/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c new file mode 100644 index 000000000..e089c8f7d --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c @@ -0,0 +1,231 @@ +#include "kdb_ldap.h" +#include "ldap_principal.h" +#include "princ_xdr.h" + +bool_t +ldap_xdr_krb5_ui_2(XDR *xdrs, krb5_ui_2 *objp) +{ + unsigned int tmp; + + tmp = (unsigned int) *objp; + + if (!xdr_u_int(xdrs, &tmp)) + return(FALSE); + + *objp = (krb5_ui_2) tmp; + return(TRUE); +} + +bool_t +ldap_xdr_krb5_int16(XDR *xdrs, krb5_int16 *objp) +{ + int tmp; + + tmp = (int) *objp; + + if (!xdr_int(xdrs, &tmp)) + return(FALSE); + + *objp = (krb5_int16) tmp; + return(TRUE); +} + +bool_t +ldap_xdr_nullstring(XDR *xdrs, char **objp) +{ + u_int size; + + if (xdrs->x_op == XDR_ENCODE) { + if (*objp == NULL) + size = 0; + else + size = strlen(*objp) + 1; + } + if (! xdr_u_int(xdrs, &size)) { + return FALSE; + } + switch (xdrs->x_op) { + case XDR_DECODE: + if (size == 0) { + *objp = NULL; + return TRUE; + } else if (*objp == NULL) { + *objp = (char *) mem_alloc(size); + if (*objp == NULL) { + /*errno = ENOMEM;*/ + return FALSE; + } + } + return (xdr_opaque(xdrs, *objp, size)); + + case XDR_ENCODE: + if (size != 0) + return (xdr_opaque(xdrs, *objp, size)); + return TRUE; + + case XDR_FREE: + if (*objp != NULL) + mem_free(*objp, size); + *objp = NULL; + return TRUE; + } + return FALSE; +} + +bool_t +ldap_xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp) +{ + unsigned char tmp; + + tmp = '\0'; /* for purify, else xdr_u_char performs a umr */ + + if (xdrs->x_op == XDR_ENCODE) + tmp = (unsigned char) *objp; + + if (!xdr_u_char(xdrs, &tmp)) + return (FALSE); + + if (xdrs->x_op == XDR_DECODE) + *objp = (krb5_kvno) tmp; + return (TRUE); +} + +bool_t +ldap_xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp) +{ + unsigned int tmp; + + if (!ldap_xdr_krb5_int16(xdrs, &objp->key_data_ver)) + return(FALSE); + if (!ldap_xdr_krb5_int16(xdrs, &objp->key_data_kvno)) + return(FALSE); + if (!ldap_xdr_krb5_int16(xdrs, &objp->key_data_type[0])) + return(FALSE); + if (!ldap_xdr_krb5_int16(xdrs, &objp->key_data_type[1])) + return(FALSE); + if (!ldap_xdr_krb5_ui_2(xdrs, &objp->key_data_length[0])) + return(FALSE); + if (!ldap_xdr_krb5_ui_2(xdrs, &objp->key_data_length[1])) + return(FALSE); + + tmp = (unsigned int) objp->key_data_length[0]; + if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[0], + &tmp, (unsigned int) ~0)) + return FALSE; + + tmp = (unsigned int) objp->key_data_length[1]; + if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[1], + &tmp, (unsigned int) ~0)) + return FALSE; + + /* don't need to copy tmp out, since key_data_length will be set + by the above encoding. */ + return(TRUE); +} + +bool_t +ldap_xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp) +{ + if (!xdr_array(xdrs, (caddr_t *) &objp->key_data, + (u_int *) &objp->n_key_data, (unsigned int) ~0, + sizeof(krb5_key_data), + ldap_xdr_krb5_key_data)) + return (FALSE); + return (TRUE); +} + +bool_t +ldap_xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp) +{ + switch (xdrs->x_op) { + case XDR_ENCODE: + objp->version = OSA_ADB_PRINC_VERSION_1; + /* fall through */ + case XDR_FREE: + if (!xdr_int(xdrs, &objp->version)) + return FALSE; + break; + case XDR_DECODE: + if (!xdr_int(xdrs, &objp->version)) + return FALSE; + if (objp->version != OSA_ADB_PRINC_VERSION_1) + return FALSE; + break; + } + + if (!ldap_xdr_nullstring(xdrs, &objp->policy)) + return (FALSE); + if (!xdr_long(xdrs, &objp->aux_attributes)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->old_key_next)) + return (FALSE); + if (!ldap_xdr_krb5_kvno(xdrs, &objp->admin_history_kvno)) + return (FALSE); + if (!xdr_array(xdrs, (caddr_t *) &objp->old_keys, + (unsigned int *) &objp->old_key_len, (unsigned int) ~0, + sizeof(osa_pw_hist_ent), + ldap_xdr_osa_pw_hist_ent)) + return (FALSE); + return (TRUE); +} + +void +ldap_osa_free_princ_ent(osa_princ_ent_t val) +{ + XDR xdrs; + + xdrmem_create(&xdrs, NULL, 0, XDR_FREE); + + ldap_xdr_osa_princ_ent_rec(&xdrs, val); + free(val); +} + +krb5_error_code +krb5_lookup_tl_kadm_data(krb5_tl_data *tl_data, osa_princ_ent_rec *princ_entry) +{ + + XDR xdrs; + + xdrmem_create(&xdrs, tl_data->tl_data_contents, + tl_data->tl_data_length, XDR_DECODE); + if (! ldap_xdr_osa_princ_ent_rec(&xdrs, princ_entry)) { + xdr_destroy(&xdrs); + return(KADM5_XDR_FAILURE); + } + xdr_destroy(&xdrs); + + return 0; + +} + +krb5_error_code +krb5_update_tl_kadm_data(policy_dn, new_tl_data) + char * policy_dn; + krb5_tl_data * new_tl_data; +{ + XDR xdrs; + osa_princ_ent_t princ_entry; + + if((princ_entry = (osa_princ_ent_t) malloc(sizeof(osa_princ_ent_rec))) == NULL) + return ENOMEM; + + memset(princ_entry, 0, sizeof(osa_princ_ent_rec)); + princ_entry->admin_history_kvno = 2; + princ_entry->aux_attributes = KDB_POLICY; + princ_entry->policy = policy_dn; + + xdralloc_create(&xdrs, XDR_ENCODE); + if(! ldap_xdr_osa_princ_ent_rec(&xdrs, princ_entry)) { + xdr_destroy(&xdrs); + return(KADM5_XDR_FAILURE); + } + new_tl_data->tl_data_type = KRB5_TL_KADM_DATA; + new_tl_data->tl_data_length = xdr_getpos(&xdrs); + new_tl_data->tl_data_contents = (krb5_octet *)xdralloc_getdata(&xdrs); + + /* + xdr_destroy(&xdrs); + ldap_osa_free_princ_ent(princ_entry); + */ + return(0); +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.h b/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.h new file mode 100644 index 000000000..65a03f7dd --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.h @@ -0,0 +1,61 @@ +#ifndef _PRINC_XDR_H +#define _PRINC_XDR_H 1 + +#include <sys/types.h> +#include <krb5.h> +#include <kdb.h> +#include <gssrpc/rpc.h> + +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif + +#define OSA_ADB_PRINC_VERSION_1 0x12345C01 +#define KADM5_XDR_FAILURE (43787575L) + +typedef struct _osa_pw_hist_t { + int n_key_data; + krb5_key_data *key_data; +} osa_pw_hist_ent, *osa_pw_hist_t; + +typedef struct _osa_princ_ent_t { + int version; + char *policy; + long aux_attributes; + unsigned int old_key_len; + unsigned int old_key_next; + krb5_kvno admin_history_kvno; + osa_pw_hist_ent *old_keys; +} osa_princ_ent_rec, *osa_princ_ent_t; + +bool_t +ldap_xdr_krb5_ui_2(XDR *xdrs, krb5_ui_2 *objp); + +bool_t +ldap_xdr_krb5_int16(XDR *xdrs, krb5_int16 *objp); + +bool_t +ldap_xdr_nullstring(XDR *xdrs, char **objp); + +bool_t +ldap_xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp); + +bool_t +ldap_xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp); + +bool_t +ldap_xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp); + +bool_t +ldap_xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp); + +void +ldap_osa_free_princ_ent(osa_princ_ent_t val); + +krb5_error_code +krb5_lookup_tl_kadm_data(krb5_tl_data *tl_data, osa_princ_ent_rec *princ_entry); + +krb5_error_code +krb5_update_tl_kadm_data(char *, krb5_tl_data *); + +#endif |
