From: Ken Raeburn Date: Tue, 18 Jul 2006 00:40:19 +0000 (+0000) Subject: Merge remaining changes from LDAP integration branch X-Git-Tag: krb5-1.6-alpha1~207 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=42d9d6ab320ee3a661fe21472be542acd542d5be;p=krb5.git 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 --- diff --git a/src/Makefile.in b/src/Makefile.in index 32f139b08..423cca4c5 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -4,7 +4,7 @@ thisconfigdir=. myfulldir=. mydir=. # Don't build sample by default: plugins/locate/python -SUBDIRS=util include lib @krb524@ kdc kadmin slave clients \ +SUBDIRS=util include lib @krb524@ kdc kadmin @ldap_plugin_dir@ slave clients \ plugins/kdb/db2 \ appl tests \ config-files gen-manpages diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 8fd2f8d34..62081052b 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -101,6 +101,7 @@ libnover_frag=$srcdir/$ac_config_fragdir/libnover.in AC_SUBST_FILE(libnover_frag) dnl KRB5_AC_PRAGMA_WEAK_REF +WITH_LDAP KRB5_LIB_PARAMS KRB5_AC_INITFINI KRB5_AC_ENABLE_THREADS @@ -1752,3 +1753,40 @@ AC_DEFUN([KRB5_AC_LIBUTIL], UTIL_LIB=-lutil])dnl AC_SUBST(UTIL_LIB) ]) +dnl +dnl +dnl +dnl --with-ldap=value +dnl +AC_DEFUN(WITH_LDAP,[ +AC_ARG_WITH([ldap], +[ --with-ldap compile OpenLDAP database backend module], +[case "$withval" in + OPENLDAP) with_ldap=yes ;; + yes | no) ;; + EDIRECTORY) AC_MSG_ERROR(Option --with-ldap=EDIRECTORY is deprecated; use --with-edirectory instead.) ;; + *) AC_MSG_ERROR(Invalid option value --with-ldap="$withval") ;; +esac], with_ldap=no)dnl +AC_ARG_WITH([edirectory], +[ --with-edirectory compile eDirectory database backend module], +[case "$withval" in + yes | no) ;; + *) AC_MSG_ERROR(Invalid option value --with-edirectory="$withval") ;; +esac], with_edirectory=no)dnl + +if test $with_ldap = yes; then + if test $with_edirectory = yes; then + AC_MSG_ERROR(Cannot enable both OpenLDAP and eDirectory backends; choose one.) + fi + AC_MSG_NOTICE(enabling OpenLDAP database backend module support) + OPENLDAP_PLUGIN=yes +elif test $with_edirectory = yes; then + AC_MSG_NOTICE(enabling eDirectory database backend module support) + OPENLDAP_PLUGIN=yes + AC_DEFINE(HAVE_EDIRECTORY,1,[Define if LDAP KDB interface should assume eDirectory.]) +else + : # neither enabled +dnl AC_MSG_NOTICE(disabling ldap backend module support) +fi +AC_SUBST(OPENLDAP_PLUGIN) +])dnl diff --git a/src/config-files/krb5.conf.M b/src/config-files/krb5.conf.M index 07b5f3a53..8f3ec39b4 100644 --- a/src/config-files/krb5.conf.M +++ b/src/config-files/krb5.conf.M @@ -93,6 +93,12 @@ cross-realm. Entries in the section are used by the client to determine the intermediate realms which may be used in cross-realm authentication. It is also used by the end-service when checking the transited field for trusted intermediate realms. + +.IP [dbdefaults] +Contains default values for database specific parameters. + +.IP [dbmodules] +Contains database specific parameters used by the database library. .PP Each of these sections will be covered in more details in the following sections. @@ -275,6 +281,7 @@ subsection define the properties of that particular realm. For example: ATHENA.MIT.EDU = { admin_server = KERBEROS.MIT.EDU default_domain = MIT.EDU + database_module = ldapconf v4_instance_convert = { mit = mit.edu lithium = lithium.lcs.mit.edu @@ -298,6 +305,10 @@ administrator has not made the information available through DNS. This relation identifies the host where the administration server is running. Typically this is the Master Kerberos server. +.IP database_module +This relation indicates the name of the configuration section under dbmodules +for database specific parameters used by the loadable database library. + .IP default_domain This relation identifies the default domain for which hosts in this realm are assumed to be in. This is needed for translating V4 principal @@ -549,6 +560,95 @@ This feature is not currently supported by DCE. DCE security servers can be used with Kerberized clients and servers, but versions prior to DCE 1.1 did not fill in the transited field, and should be used with caution. + +.SH DATABASE DEFAULT SECTION + +The [dbdefaults] section indicates default values for the database specific parameters. +It can also specify the configuration section under dbmodules for database +specific parameters used by the loadable database library. + +.PP +The following tags are used in this section: +.IP database_module +This relation indicates the name of the configuration section under dbmodules +for database specific parameters used by the loadable database library. + +.IP ldap_kerberos_container_dn +This LDAP specific tag indicates the DN of the container object where the realm +objects will be located. This value is used if no object DN is mentioned in the +configuration section under dbmodules. + +.IP ldap_kdc_dn +This LDAP specific tag indicates the default bind DN for the KDC server. +The KDC server does a login to the directory as this object. This value is used if +no object DN is mentioned in the configuration section under dbmodules. + +.IP ldap_kadmind_dn +This LDAP specific tag indicates the default bind DN for the +Administration server. The Administration server does a login to the directory +as this object. This value is used if no object DN is mentioned in +the configuration section under dbmodules. + +.IP ldap_service_password_file +This LDAP specific tag indicates the file containing the stashed passwords for the +objects used for starting the Kerberos servers. This value is used if no +service password file is mentioned in the configuration section under dbmodules. + +.IP ldap_ssl_port +This LDAP specific tag indicates the value of the SSL port for the LDAP server. +This value is used if no SSL port is mentioned in the configuration section under dbmodules. + +.IP ldap_server +This LDAP specific tag indicates the list of LDAP servers. The list of LDAP servers +is whitespace-separated. The port value can be specified with the server separated by +a colon. This value is used if no LDAP servers are mentioned in the configuration +section under dbmodules. + +.IP ldap_conns_per_server +This LDAP specific tag indicates the number of connections to be maintained per +LDAP server. This value is used if the number of connections per LDAP server are not +mentioned in the configuration section under dbmodules. The default value is 5. + +.SH DATABASE MODULE SECTION +Each tag in the [dbmodules] section of the file names a configuration section +for database specific parameters that can be referred to by a realm. +The value of the tag is a subsection where the relations in that subsection +define the database specific parameters. + +.PP +For each section, the following tags may be specified in the subsection: + +.IP db_library +This tag indicates the name of the loadable database library. +The value should be db2 for db2 database and kldap for LDAP database. + +.IP ldap_kerberos_container_dn +This LDAP specific tag indicates the DN of the container object where the realm +objects will be located. + +.IP ldap_kdc_dn +This LDAP specific tag indicates the bind DN for the KDC server. +The KDC does a login to the directory as this object. + +.IP ldap_kadmind_dn +This LDAP specific tag indicates the bind DN for the Administration server. +The Administration server does a login to the directory +as this object. + +.IP ldap_service_password_file +This LDAP specific tag indicates the file containing the stashed passwords for the +objects used for starting the Kerberos servers. + +.IP ldap_ssl_port +This LDAP specific tag indicates the value of the SSL port for the LDAP server. + +.IP ldap_server +This LDAP specific tag indicates the list of LDAP servers. The list of LDAP servers +is whitespace-separated. The port value can be specified with the server separated by a colon. + +.IP ldap_conns_per_server +This LDAP specific tag indicates the number of connections to be maintained per +LDAP server. .SH FILES /etc/krb5.conf .SH SEE ALSO diff --git a/src/configure.in b/src/configure.in index ca4830cdc..cf93187ce 100644 --- a/src/configure.in +++ b/src/configure.in @@ -900,12 +900,29 @@ fi if test -n "$KRB4_LIB"; then K5_GEN_MAKEFILE(lib/krb4) fi +dnl +dnl +ldap_plugin_dir="" +ldap_lib="" +if test -n "$OPENLDAP_PLUGIN"; then + AC_CHECK_HEADERS(ldap.h lber.h) + if test $ac_cv_header_ldap_h = no || test $ac_cv_header_lber_h = no; then + AC_ERROR(OpenLDAP headers missing) + fi + AC_CONFIG_SUBDIRS(plugins/kdb/ldap/libkdb_ldap) + K5_GEN_MAKEFILE(plugins/kdb/ldap) + K5_GEN_MAKEFILE(plugins/kdb/ldap/ldap_util) + ldap_plugin_dir=plugins/kdb/ldap +fi +AC_SUBST(ldap_plugin_dir) + AC_CONFIG_SUBDIRS(lib/apputils plugins/kdb/db2 appl tests) dnl if false; then AC_CHECK_HEADERS(Python.h python2.3/Python.h) AC_CONFIG_SUBDIRS(plugins/locate/python) fi + AC_CONFIG_FILES(krb5-config, [chmod +x krb5-config]) V5_AC_OUTPUT_MAKEFILE(. diff --git a/src/kadmin/cli/kadmin.M b/src/kadmin/cli/kadmin.M index d9d6abda1..214d722ed 100644 --- a/src/kadmin/cli/kadmin.M +++ b/src/kadmin/cli/kadmin.M @@ -15,7 +15,7 @@ kadmin \- Kerberos V5 database administration program .B kadmin.local [\fB\-r\fP \fIrealm\fP] [\fB\-p\fP \fIprincipal\fP] [\fB\-q\fP \fIquery\fP] .br -[\fB\-d\fP \fIdbname\fP] [\fB\-e \fI"enc:salt ..."\fP] [\fB-m\fP] +[\fB\-d\fP \fIdbname\fP] [\fB\-e \fI"enc:salt ..."\fP] [\fB-m\fP] [\fB\-x\fP \fIdb_args\fP] .ad b .SH DESCRIPTION .B kadmin @@ -28,8 +28,10 @@ and .B kadmin.local provide identical functionalities; the difference is that .B kadmin.local -runs on the master KDC and does not use Kerberos to authenticate to the -database. Except as explicitly noted otherwise, this man page will use +runs on the master KDC if the database is db2 and +does not use Kerberos to authenticate to the +database. Except as explicitly noted otherwise, +this man page will use .B kadmin to refer to both versions. .B kadmin @@ -58,7 +60,7 @@ has determined the principal name, it requests a Kerberos service ticket from the KDC, and uses that service ticket to authenticate to KADM5. .PP -The local client +If the database is db2, the local client .BR kadmin.local , is intended to run directly on the master KDC without Kerberos authentication. The local version provides all of the functionality of @@ -68,6 +70,7 @@ except for database dump and load, which is now provided by the .IR kdb5_util (8) utility. .PP +If the database is LDAP, kadmin.local need not be run on the KDC. .SH OPTIONS .TP \fB\-r\fP \fIrealm\fP @@ -130,6 +133,7 @@ and then exit. This can be useful for writing scripts. .TP \fB\-d\fP \fIdbname\fP Specifies the name of the Kerberos database. +This option does not apply to the LDAP database. .TP \fB\-s\fP \fIadmin_server[:port]\fP Specifies the admin server which kadmin should contact. @@ -147,6 +151,31 @@ Force use of old AUTH_GSSAPI authentication flavor. .TP .B \-N Prevent fallback to AUTH_GSSAPI authentication flavor. +.TP +\fB\-x\fP \fIdb_args\fP +Specifies the database specific arguments. + +Options supported for LDAP database are: +.sp +.nf +.RS 14 +\-x port= +specifies the secure port number where the LDAP server is listening. + +\-x host= +specifies the host on which the LDAP server is running. +The should be the same as the host name set in the LDAP server certificate. + +\-x binddn= +specifies the DN of the object used by the administration server to bind to the LDAP server. +This object should have the read rights on the realm container and write rights on the subtree +that is referenced by the realm. + +\-x bindpwd= +specifies the password for the above mentioned binddn. It is recommended not to use this option. +Instead, the password can be stashed using the stashsrvpw command of kdb5_ldap_util. +.RE +.fi .SH DATE FORMAT Various commands in kadmin can take a variety of date formats, specifying durations or absolute times. Examples of valid formats are: @@ -195,6 +224,23 @@ and The options are: .RS .TP +\fB\-x\fP \fIdb_princ_args\fP +Denotes the database specific options. The options for LDAP database are: +.sp +.nf +.RS +\-x userdn= +Specifies the user object with which the Kerberos user principal is to be associated. + +\-x containerdn= +Specifies the container object under which the Kerberos service principal is to be created. + +\-x tktpolicydn= +Associates a ticket policy object to the Kerberos principal. + +.RE +.fi +.TP \fB\-expire\fP \fIexpdate\fP expiration date of the principal .TP @@ -365,6 +411,15 @@ Enter password for principal tlyu/admin@BLEEP.COM: Re-enter password for principal tlyu/admin@BLEEP.COM: Principal "tlyu/admin@BLEEP.COM" created. kadmin: + +kadmin: addprinc -x userdn=cn=mwm_user,o=org mwm_user +WARNING: no policy specified for "mwm_user@BLEEP.COM"; +defaulting to no policy. +Enter password for principal mwm_user@BLEEP.COM: +Re-enter password for principal mwm_user@BLEEP.COM: +Principal "mwm_user@BLEEP.COM" created. +kadmin: + .TP ERRORS: KADM5_AUTH_ADD (requires "add" privilege) @@ -383,7 +438,7 @@ option is given. This command requires the .I delete privilege. Aliased to -.BR delprinc . +.BR delprinc. .sp .nf .RS @@ -414,10 +469,18 @@ will clear the current policy of a principal. This command requires the .I modify privilege. Aliased to .BR modprinc . -.sp -.nf .RS .TP +\fB\-x\fP \fIdb_princ_args\fP +Denotes the database specific options. The options for LDAP database are: +.sp +.nf +.RS +\-x tktpolicydn= +Associates a ticket policy object to the Kerberos principal. +.RE +.fi +.TP ERRORS: KADM5_AUTH_MODIFY (requires "modify" privilege) KADM5_UNK_PRINC (principal does not exist) @@ -457,7 +520,7 @@ daemons earlier than krb5\-1.2. Keeps the previous kvno's keys around. There is no easy way to delete the old keys, and this flag is usually not necessary except perhaps for TGS keys. Don't use this flag unless you -know what you're doing. +know what you're doing. This option is not supported for the LDAP database. .nf .TP EXAMPLE: @@ -569,10 +632,14 @@ sets the minimum length of a password sets the minimum number of character classes allowed in a password .TP \fB\-history\fP \fInumber\fP -sets the number of past keys kept for a principal +sets the number of past keys kept for a principal. This option is not supported for LDAP database .sp .nf .TP +EXAMPLES: +kadmin: add_policy -maxlife "2 days" -minlength 5 cn=guests,o=org +kadmin: +.TP ERRORS: KADM5_AUTH_ADD (requires the add privilege) KADM5_DUP (policy already exists) @@ -678,6 +745,8 @@ kadmin: .RE .fi .TP +Note: All the policy names are in the form of DN for LDAP database. +.TP \fBktadd\fP [\fB\-k\fP \fIkeytab\fP] [\fB\-q\fP] [\fB\-e\fP \fIkeysaltlist\fP] .br [\fIprincipal\fP | \fB\-glob\fP \fIprinc-exp\fP] [\fI...\fP] @@ -762,6 +831,9 @@ will exit with an error if this file does .I not exist. .TP +.B Note: +The above three files are specific to db2 database. +.TP kadm5.acl file containing list of principals and their .B kadmin diff --git a/src/kadmin/server/kadmind.M b/src/kadmin/server/kadmind.M index 3d359be3c..6e4cb5252 100644 --- a/src/kadmin/server/kadmind.M +++ b/src/kadmin/server/kadmind.M @@ -3,12 +3,13 @@ kadmind \- KADM5 administration server .SH SYNOPSIS .B kadmind -[\fB-r\fP \fIrealm\fP] [\fB\-m\fP] [\fB\-nofork\fP] [\fB\-port\fP +[\fB\-x\fP \fIdb_args\fP] [\fB-r\fP \fIrealm\fP] [\fB\-m\fP] [\fB\-nofork\fP] [\fB\-port\fP \fIport-number\fP] .SH DESCRIPTION -This command starts the KADM5 administration server. The administration -server runs on the master Kerberos server, which stores the KDC -principal database and the KADM5 policy database. +This command starts the KADM5 administration server. If the database is db2, +the administration server runs on the master Kerberos server, which stores the KDC +prinicpal database and the KADM5 policy database. If the database is LDAP, +the administration server and the KDC server need not run on the same machine. .B Kadmind accepts remote requests to administer the information in these databases. Remote requests are sent, for example, by @@ -54,6 +55,34 @@ section below. After the server begins running, it puts itself in the background and disassociates itself from its controlling terminal. .SH OPTIONS +.TP +\fB\-x\fP \fIdb_args\fP +specifies the database specific arguments. + +Options supported for LDAP database are: +.sp +.nf +.RS 12 +\-x nconns= +specifies the number of connections to be maintained per LDAP server. + +\-x port= +specifies the secure port number where the LDAP server is listening. + +\-x host= +specifies the host on which the LDAP server is running. +The should be the same as the host name set in the LDAP server certificate. + +\-x binddn= +specifies the DN of the object used by the administration server to bind to the LDAP server. +This object should have the read rights on the realm container and write rights on the subtree +that is referenced by the realm. + +\-x bindpwd= +specifies the password for the above mentioned binddn. It is recommended not to use this option. +Instead, the password can be stashed using the stashsrvpw command of kdb5_ldap_util. +.RE +.fi .TP \fB\-r\fP \fIrealm\fP specifies the default realm that kadmind will serve; if it is not @@ -226,6 +255,9 @@ will exit with an error if this file does .I not exist. .TP +.B Note: +The above three files are specific to db2 database. +.TP kadm5.acl file containing list of principals and their .B kadmin @@ -240,4 +272,6 @@ kadm5.dict file containing dictionary of strings explicitly disallowed as passwords. .SH SEE ALSO -kpasswd(1), kadmin(8), kdb5_util(8), kadm5_export(8), kadm5_import(8) +kpasswd(1), kadmin(8), kdb5_util(8), kadm5_export(8), kadm5_import(8), +kdb5_ldap_util(8) + diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c index 6ebe3ee76..1efdf078b 100644 --- a/src/kadmin/server/ovsec_kadmd.c +++ b/src/kadmin/server/ovsec_kadmd.c @@ -318,7 +318,7 @@ int main(int argc, char *argv[]) &global_server_handle)) != KADM5_OK) { const char *e_txt = krb5_get_error_message (context, ret); krb5_klog_syslog(LOG_ERR, "%s while initializing, aborting", - e_txt); + e_txt); fprintf(stderr, "%s: %s while initializing, aborting\n", whoami, e_txt); krb5_klog_close(context); @@ -847,6 +847,7 @@ void reset_db(void) { #ifdef notdef kadm5_ret_t ret; + char *errmsg; if (ret = kadm5_flush(global_server_handle)) { krb5_klog_syslog(LOG_ERR, "FATAL ERROR! %s while flushing databases. " @@ -1164,7 +1165,7 @@ void do_schpw(int s1, kadm5_config_params *params) interoperate if the client is single-homed. */ if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - char *errmsg = krb5_get_error_message (context, errno); + const char *errmsg = krb5_get_error_message (context, errno); krb5_klog_syslog(LOG_ERR, "cannot create connecting socket: %s", errmsg); fprintf(stderr, "Cannot create connecting socket: %s", diff --git a/src/kdc/krb5kdc.M b/src/kdc/krb5kdc.M index d6f69b645..180656b42 100644 --- a/src/kdc/krb5kdc.M +++ b/src/kdc/krb5kdc.M @@ -27,6 +27,9 @@ krb5kdc \- Kerberos V5 KDC .SH SYNOPSIS .B krb5kdc [ +.B \-x +.I db_args +] [ .B \-d .I dbname ] [ @@ -56,6 +59,36 @@ is the Kerberos version 5 Authentication Service and Key Distribution Center (AS/KDC). .PP The +.B \-x +.I db_args +option specifies the database specific arguments. + +Options supported for LDAP database are: +.sp +.nf +.RS 8 +\-x nconns= +specifies the number of connections to be maintained per LDAP server. + +\-x port= +specifies the secure port number where the LDAP server is listening. + +\-x host= +specifies the host on which the LDAP server is running. +The should be the same as the host name set in the LDAP server certificate. + +\-x binddn= +specifies the DN of the object used by the KDC server to bind to the LDAP server. +This object should have the rights to read the realm container and the subtree that is referenced +by the realm. + +\-x bindpwd= +specifies the password for the above mentioned binddn. It is recommended not to use this option. +Instead, the password can be stashed using the stashsrvpw command of kdb5_ldap_util. +.RE +.fi +.PP +The .B \-r .I realm option specifies the realm for which the server should provide service; @@ -68,6 +101,7 @@ The .I dbname option specifies the name under which the principal database can be found; by default the database is in DEFAULT_DBM_FILE. +This option does not apply to the LDAP database. .PP The .B \-k @@ -147,7 +181,7 @@ options specified on the command line. See the .I kdc.conf(5) description for further details. .SH SEE ALSO -krb5(3), kdb5_util(8), kdc.conf(5) +krb5(3), kdb5_util(8), kdc.conf(5), kdb5_ldap_util(8) .SH BUGS It should fork and go into the background when it finishes reading the diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h index 6f0da7935..b64e9e7fc 100644 --- a/src/lib/kadm5/admin.h +++ b/src/lib/kadm5/admin.h @@ -88,6 +88,10 @@ typedef long kadm5_ret_t; #define KADM5_FAIL_AUTH_COUNT 0x010000 #define KADM5_KEY_DATA 0x020000 #define KADM5_TL_DATA 0x040000 +#ifdef notyet /* Novell */ +#define KADM5_CPW_FUNCTION 0x080000 +#define KADM5_RANDKEY_USED 0x100000 +#endif /* all but KEY_DATA and TL_DATA */ #define KADM5_PRINCIPAL_NORMAL_MASK 0x01ffff @@ -123,6 +127,9 @@ typedef long kadm5_ret_t; #define KADM5_CONFIG_OLD_AUTH_GSSAPI 0x100000 #define KADM5_CONFIG_NO_AUTH 0x200000 #define KADM5_CONFIG_AUTH_NOFALLBACK 0x400000 +#ifdef notyet /* Novell */ +#define KADM5_CONFIG_KPASSWD_SERVER 0x800000 +#endif /* * permission bits */ @@ -212,6 +219,9 @@ typedef struct _kadm5_config_params { int kpasswd_port; char * admin_server; +#ifdef notyet /* Novell */ /* ABI change? */ + char * kpasswd_server; +#endif char * dbname; char * admin_dbname; diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c index d59a7cf76..ca9a653af 100644 --- a/src/lib/kdb/kdb5.c +++ b/src/lib/kdb/kdb5.c @@ -384,8 +384,9 @@ kdb_load_library(krb5_context kcontext, char *lib_name, db_library * lib) if (vftabl_addrs[0] == NULL) { /* No plugins! */ status = KRB5_KDB_DBTYPE_NOTFOUND; - krb5_set_error_message (kcontext, status, - "Unable to find requested database type"); + krb5_set_error_message (kcontext, status, + _("Unable to find requested database module '%s': plugin symbol 'kdb_function_table' not found"), + lib_name); goto clean_n_exit; } diff --git a/src/lib/krb5/error_tables/kdb5_err.et b/src/lib/krb5/error_tables/kdb5_err.et index 79a7c961e..d6014acec 100644 --- a/src/lib/krb5/error_tables/kdb5_err.et +++ b/src/lib/krb5/error_tables/kdb5_err.et @@ -72,5 +72,9 @@ ec KRB5_KDB_DBTYPE_NOTFOUND, "Unable to find requested database type" ec KRB5_KDB_DBTYPE_NOSUP, "Database type not supported" ec KRB5_KDB_DBTYPE_INIT, "Database library failed to initialize" ec KRB5_KDB_SERVER_INTERNAL_ERR, "Server error" +ec KRB5_KDB_ACCESS_ERROR, "Unable to access Kerberos database" +ec KRB5_KDB_INTERNAL_ERROR, "Kerberos database internal error" +ec KRB5_KDB_CONSTRAINT_VIOLATION, "Kerberos database constraints violated" + end 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 + + * ldap_exp.c: Include k5-int.h before testing HAVE_UNISTD_H. + +2006-03-21 Ken Raeburn + + * Makefile.in (SHLIB_EXPDEPS, SHLIB_EXPLIBS): Add kdb_ldap + and support libraries. + +2006-03-17 Ken Raeburn + + * 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 + + * 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 + + * ldap_err.h (LDAP_ERR_BASE, MAX_NEG, LDAP_TO_KDB_ERR): Unused + macros deleted. + +2006-03-07 Ken Raeburn + + * 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 + + * 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 +#endif +#include +#include +#include +#include +#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 + + * getdate.c: Deleted. + * Makefile.in ($(PROG)): Link against getdate.o from cli + directory. + +2006-03-17 Ken Raeburn + + * 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 +#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 +#include +#include +#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 +#include +#include +#include "kdb5_ldap_util.h" +#include "kdb5_ldap_list.h" +#include + +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/' ... */ + 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 +#include +#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 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_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 +#include + +#include +#include +#include +#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 + + * kdb_ldap.c, kdb_ldap_conn.c: Include autoconf.h before testing + HAVE_UNISTD_H. + +2006-03-22 Ken Raeburn + + * 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 + + * Makefile.in (SHLIB_EXPDEPS, SHLIB_EXPLIBS): Add kdb5 library. + (LIBMAJOR): Bump to 1. + +2006-03-20 Ken Raeburn + + * 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 + + * 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 +#endif + +#include +#include "kdb_ldap.h" +#include "ldap_misc.h" +#include + +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 +#include +#include +#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 +#endif + +#include "ldap_main.h" +#include "ldap_service_stash.h" +#include + +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: \0 */ + 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 +#include +#include +#include +#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 +#include +#include +#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 +#include +#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 && eleserver_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<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; treelrparams->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 +#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; treelrparams->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 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; ln_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; ln_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 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; kbv_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; jprinc->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; isuppenctypes[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; isuppsalttypes[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 +#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}\0 */ + /*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 + * = + * := {HEX} + * + * 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 +#include +#include +#include + +#ifdef HAVE_MEMORY_H +#include +#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