From: Ken Raeburn Date: Fri, 6 Oct 2006 23:53:38 +0000 (+0000) Subject: 10/3 patch from Savitha R, part 1, patch-ldap-schema.diff X-Git-Tag: krb5-1.6-alpha1~96 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=ea079b45681b6f36de1aacc176f16cf2ba434aa3;p=krb5.git 10/3 patch from Savitha R, part 1, patch-ldap-schema.diff git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18657 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.c index 8b9227888..60963d2d9 100644 --- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.c +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_policy.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "kdb5_ldap_util.h" #include "kdb5_ldap_list.h" #include "ldap_tkt_policy.h" @@ -45,6 +46,45 @@ static void print_policy_params(krb5_ldap_policy_params *policyparams, int mask) static char *strdur(time_t duration); extern char *yes; +extern kadm5_config_params global_params; + +static krb5_error_code init_ldap_realm (int argc, char *argv[]) { + /* This operation is being performed in the context of a realm. So, + * initialize the realm */ + int mask = 0; + krb5_error_code retval; + 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; + goto cleanup; + } + + if (ldap_context->krbcontainer == NULL) { + retval = krb5_ldap_read_krbcontainer_params (util_context, + &(ldap_context->krbcontainer)); + if (retval != 0) { + com_err(argv[0], retval, "while reading kerberos container information"); + goto cleanup; + } + } + + if (ldap_context->lrparams == NULL) { + retval = krb5_ldap_read_realm_params(util_context, + global_params.realm, + &(ldap_context->lrparams), + &mask); + + if (retval != 0) { + goto cleanup; + } + } +cleanup: + return retval; +} /* * This function will create a ticket policy object with the @@ -221,12 +261,12 @@ kdb5_ldap_create_policy(argc, argv) } 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) + if (policyparams->policy != NULL) goto err_usage; /* If not present already, fill up policy DN */ - policyparams->policydn = strdup(argv[i]); - if (policyparams->policydn == NULL) { + policyparams->policy = strdup(argv[i]); + if (policyparams->policy == NULL) { retval = ENOMEM; com_err(me, retval, "while creating policy object"); goto err_nomsg; @@ -235,9 +275,14 @@ kdb5_ldap_create_policy(argc, argv) } /* policy DN is a mandatory argument. If not provided, print usage */ - if (policyparams->policydn == NULL) + if (policyparams->policy == NULL) goto err_usage; + if ((retval = init_ldap_realm (argc, argv))) { + com_err(me, retval, "while reading realm information"); + goto err_nomsg; + } + /* Create object with all attributes provided */ if ((retval = krb5_ldap_create_policy(util_context, policyparams, mask)) != 0) goto cleanup; @@ -282,7 +327,7 @@ kdb5_ldap_destroy_policy(argc, argv) krb5_ldap_policy_params *policyparams = NULL; krb5_boolean print_usage = FALSE; krb5_boolean no_msg = FALSE; - char *policydn = NULL; + char *policy = NULL; int mask = 0; int force = 0; char buf[5] = {0}; @@ -298,12 +343,12 @@ kdb5_ldap_destroy_policy(argc, argv) } 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) + if (policy != NULL) goto err_usage; /* If not present already, fill up policy DN */ - policydn = strdup(argv[i]); - if (policydn == NULL) { + policy = strdup(argv[i]); + if (policy == NULL) { retval = ENOMEM; com_err(me, retval, "while destroying policy object"); goto err_nomsg; @@ -311,11 +356,11 @@ kdb5_ldap_destroy_policy(argc, argv) } } - if (policydn == NULL) + if (policy == NULL) goto err_usage; if (!force) { - printf("This will delete the policy object '%s', are you sure?\n", policydn); + printf("This will delete the policy object '%s', are you sure?\n", policy); printf("(type 'yes' to confirm)? "); if (fgets(buf, sizeof(buf), stdin) == NULL) { @@ -329,14 +374,17 @@ kdb5_ldap_destroy_policy(argc, argv) } } - if ((retval = krb5_ldap_read_policy(util_context, policydn, &policyparams, &mask))) + if ((retval = init_ldap_realm (argc, argv))) + goto err_nomsg; + + if ((retval = krb5_ldap_read_policy(util_context, policy, &policyparams, &mask))) goto cleanup; - if ((retval = krb5_ldap_delete_policy(util_context, policydn, policyparams, mask))) + if ((retval = krb5_ldap_delete_policy(util_context, policy))) goto cleanup; - printf("** policy object '%s' deleted.\n", policydn); + printf("** policy object '%s' deleted.\n", policy); goto cleanup; @@ -350,8 +398,8 @@ cleanup: /* Clean-up structure */ krb5_ldap_free_policy (util_context, policyparams); - if (policydn) { - free (policydn); + if (policy) { + free (policy); } if (print_usage) { @@ -383,7 +431,7 @@ kdb5_ldap_modify_policy(argc, argv) krb5_ldap_policy_params *policyparams = NULL; krb5_boolean print_usage = FALSE; krb5_boolean no_msg = FALSE; - char *policydn = NULL; + char *policy = NULL; int in_mask = 0, out_mask = 0; time_t date = 0; time_t now = 0; @@ -421,12 +469,12 @@ kdb5_ldap_modify_policy(argc, argv) } 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) + if (policy != NULL) goto err_usage; /* If not present already, fill up policy DN */ - policydn = strdup(argv[i]); - if (policydn == NULL) { + policy = strdup(argv[i]); + if (policy == NULL) { retval = ENOMEM; com_err(me, retval, "while modifying policy object"); goto err_nomsg; @@ -434,12 +482,15 @@ kdb5_ldap_modify_policy(argc, argv) } } - if (policydn == NULL) + if (policy == NULL) goto err_usage; - retval = krb5_ldap_read_policy(util_context, policydn, &policyparams, &in_mask); + if ((retval = init_ldap_realm (argc, argv))) + goto cleanup; + + retval = krb5_ldap_read_policy(util_context, policy, &policyparams, &in_mask); if (retval) { - com_err(me, retval, "while reading information of policy '%s'", policydn); + com_err(me, retval, "while reading information of policy '%s'", policy); goto err_nomsg; } @@ -606,8 +657,8 @@ cleanup: /* Clean-up structure */ krb5_ldap_free_policy (util_context, policyparams); - if (policydn) - free (policydn); + if (policy) + free (policy); if (print_usage) db_usage(MODIFY_POLICY); @@ -636,22 +687,25 @@ kdb5_ldap_view_policy(argc, argv) krb5_ldap_policy_params *policyparams = NULL; krb5_error_code retval = 0; krb5_boolean print_usage = FALSE; - char *policydn = NULL; + char *policy = NULL; int mask = 0; if (argc != 2) { goto err_usage; } - policydn = strdup(argv[1]); - if (policydn == NULL) { + policy = strdup(argv[1]); + if (policy == 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); + if ((retval = init_ldap_realm (argc, argv))) + goto cleanup; + + if ((retval = krb5_ldap_read_policy(util_context, policy, &policyparams, &mask))) { + com_err(me, retval, "while viewing policy '%s'", policy); exit_status++; goto cleanup; } @@ -666,8 +720,8 @@ err_usage: cleanup: krb5_ldap_free_policy (util_context, policyparams); - if (policydn) - free (policydn); + if (policy) + free (policy); if (print_usage) { db_usage(VIEW_POLICY); @@ -687,7 +741,7 @@ print_policy_params(policyparams, mask) int mask; { /* Print the policy DN */ - printf("%25s: %s\n", "Ticket policy", policyparams->policydn); + printf("%25s: %s\n", "Ticket policy", policyparams->policy); /* Print max. ticket life and max. renewable life, if present */ if (mask & LDAP_POLICY_MAXTKTLIFE) @@ -774,6 +828,9 @@ void kdb5_ldap_list_policies(argc, argv) } } + if ((retval = init_ldap_realm (argc, argv))) + goto cleanup; + retval = krb5_ldap_list_policy(util_context, basedn, &list); if ((retval != 0) || (list == NULL)) goto cleanup; diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c index 1f658b423..870f2bd74 100644 --- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c @@ -81,6 +81,9 @@ * Create / Modify / Destroy / View / List realm(s) */ +/* Needed for getting the definition of KRB5_TL_DB_ARGS */ +#define SECURID + #include #include #include @@ -130,7 +133,8 @@ static int kdb_ldap_create_principal (krb5_context context, krb5_principal static char *strdur(time_t duration); static int get_ticket_policy(krb5_ldap_realm_params *rparams, int *i, char *argv[],int argc); - +static krb5_error_code krb5_dbe_update_mod_princ_data_new (krb5_context context, krb5_db_entry *entry, krb5_timestamp mod_date, krb5_const_principal mod_princ); +static krb5_error_code krb5_dbe_update_tl_data_new ( krb5_context context, krb5_db_entry *entry, krb5_tl_data *new_tl_data); static int get_ticket_policy(rparams,i,argv,argc) krb5_ldap_realm_params *rparams; @@ -312,11 +316,12 @@ void kdb5_ldap_create(argc, argv) krb5_boolean create_complete = FALSE; krb5_boolean print_usage = FALSE; krb5_boolean no_msg = FALSE; - char *oldsubtree = NULL; + char *oldcontainerref=NULL; char pw_str[1024]; int do_stash = 0; int i = 0; int mask = 0, ret_mask = 0; + char **list = NULL; #ifdef HAVE_EDIRECTORY int rightsmask = 0; #endif @@ -333,16 +338,50 @@ void kdb5_ldap_create(argc, argv) /* 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 (!strcmp(argv[i], "-subtrees")) { + if (++i > argc-1) + goto err_usage; + + if(strncmp(argv[i], "", strlen(argv[i]))!=0) { + list = (char **) calloc(MAX_LIST_ENTRIES, sizeof(char *)); + memset(list, 0, sizeof(char*)*MAX_LIST_ENTRIES); + if (list == NULL) { + retval = ENOMEM; + goto cleanup; + } + if (( retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) + goto cleanup; + + rparams->subtreecount=0; + while(list[rparams->subtreecount]!=NULL) + (rparams->subtreecount)++; + rparams->subtree = list; + } else if(strncmp(argv[i], "", strlen(argv[i]))==0) { + /* dont allow subtree value to be set at the root(NULL, "") of the tree */ + com_err(argv[0], EINVAL, + "for subtree while creating realm '%s'", + global_params.realm); + goto err_nomsg; + } + rparams->subtree[rparams->subtreecount] = NULL; + mask |= LDAP_REALM_SUBTREE; + } else if (!strcmp(argv[i], "-containerref")) { + if (++i > argc-1) + goto err_usage; + if(strncmp(argv[i], "", strlen(argv[i]))==0) { + /* dont allow containerref value to be set at the root(NULL, "") of the tree */ + com_err(argv[0], EINVAL, + "for container reference while creating realm '%s'", + global_params.realm); + goto err_nomsg; + } + rparams->containerref = strdup(argv[i]); + if (rparams->containerref == NULL) { + retval = ENOMEM; + goto cleanup; + } + mask |= LDAP_REALM_CONTREF; + } else if (!strcmp(argv[i], "-sscope")) { if (++i > argc-1) goto err_usage; /* Possible values for search scope are @@ -634,12 +673,11 @@ void kdb5_ldap_create(argc, argv) 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; + /* The container reference value is set to NULL, to avoid service principals + * getting created within the container reference at realm creation */ + if (ldap_context->lrparams->containerref != NULL) { + oldcontainerref = ldap_context->lrparams->containerref; + ldap_context->lrparams->containerref = NULL; } /* Create 'K/M' ... */ @@ -728,10 +766,10 @@ void kdb5_ldap_create(argc, argv) krb5_free_principal(util_context, temp_p); krb5_free_principal(util_context, p); - if (ldap_context->lrparams->subtree != NULL) - free(ldap_context->lrparams->subtree); - ldap_context->lrparams->subtree = oldsubtree; - oldsubtree = NULL; + if (oldcontainerref != NULL) { + ldap_context->lrparams->containerref = oldcontainerref; + oldcontainerref=NULL; + } } #ifdef HAVE_EDIRECTORY @@ -826,9 +864,6 @@ cleanup: memset (pw_str, 0, sizeof (pw_str)); - if (oldsubtree) - ldap_context->lrparams->subtree = oldsubtree; - if (print_usage) db_usage(CREATE_REALM); @@ -851,17 +886,19 @@ void kdb5_ldap_modify(argc, argv) int argc; char *argv[]; { - krb5_error_code retval; + krb5_error_code retval, st; 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; + int i = 0, j = 0; int mask = 0, rmask = 0, ret_mask = 0; + char **slist = {NULL}; #ifdef HAVE_EDIRECTORY int j = 0; char *list[MAX_LIST_ENTRIES]; + char **slist = {NULL}; int existing_entries = 0, list_entries = 0; int newkdcdn = 0, newadmindn = 0, newpwddn = 0; char **tempstr = NULL; @@ -869,9 +906,10 @@ void kdb5_ldap_modify(argc, argv) char **oldadmindns = NULL; char **oldpwddns = NULL; char **newkdcdns = NULL; + char **newsubtrees = NULL; char **newadmindns = NULL; char **newpwddns = NULL; - char *oldsubtree = NULL; + char **oldsubtrees = {NULL}; int rightsmask = 0; int subtree_changed = 0; #endif @@ -893,32 +931,75 @@ void kdb5_ldap_modify(argc, argv) global_params.realm, &rparams, &rmask); if (retval) goto cleanup; - /* Parse the arguments */ for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-subtree")) { + int k = 0; + if (!strcmp(argv[i], "-subtrees")) { 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; - } + oldsubtrees = (char **) calloc(rparams->subtreecount+1, sizeof(char *)); + memset(oldsubtrees, 0, szeof(char *) * rparams->subtreecount+1); + if (oldsubtrees == NULL) { + retval = ENOMEM; + goto cleanup; + } + for(k=0; rparams->subtree[k]!=NULL && rparams->subtreecount; k++) { + oldsubtrees[k] = strdup(rparams->subtree[k]); + if( oldsubtrees[k] == 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")) { + for(k=0;ksubtreecount && rparams->subtree[k];k++) + free(rparams->subtree[k]); + rparams->subtreecount=0; + } + } + if (strncmp(argv[i] ,"", strlen(argv[i]))!=0) { + slist = (char **) calloc(MAX_LIST_ENTRIES, sizeof(char *)); + memset(slist, 0, sizeof(char*)*MAX_LIST_ENTRIES); + if (slist == NULL) { + retval = ENOMEM; + goto cleanup; + } + if (( retval = krb5_parse_list(argv[i], LIST_DELIMITER, slist))) + goto cleanup; + + rparams->subtreecount=0; + while(slist[rparams->subtreecount]!=NULL) + (rparams->subtreecount)++; + rparams->subtree = slist; + } else if(strncmp(argv[i], "", strlen(argv[i]))==0) { + /* dont allow subtree value to be set at the root(NULL, "") of the tree */ + com_err(argv[0], EINVAL, + "for subtree while modifying realm '%s'", + global_params.realm); + goto err_nomsg; + } + rparams->subtree[rparams->subtreecount] = NULL; + mask |= LDAP_REALM_SUBTREE; + } else if (!strncmp(argv[i], "-containerref", strlen(argv[i]))) { + if (++i > argc-1) + goto err_usage; + if(strncmp(argv[i], "", strlen(argv[i]))==0) { + /* dont allow containerref value to be set at the root(NULL, "") of the tree */ + com_err(argv[0], EINVAL, + "for container reference while modifying realm '%s'", + global_params.realm); + goto err_nomsg; + } + rparams->containerref = strdup(argv[i]); + if (rparams->containerref == NULL) { + retval = ENOMEM; + goto cleanup; + } + mask |= LDAP_REALM_CONTREF; + } else if (!strcmp(argv[i], "-sscope")) { if (++i > argc-1) goto err_usage; /* Possible values for search scope are @@ -1337,20 +1418,50 @@ void kdb5_ldap_modify(argc, argv) if (!(mask & LDAP_REALM_SUBTREE)) { if (rparams->subtree != NULL) { - oldsubtree = strdup(rparams->subtree); - if (oldsubtree == NULL) { - retval = ENOMEM; - goto cleanup; - } + for(i=0; rparams->subtree[i]!=NULL;i++) { + oldsubtrees[i] = strdup(rparams->subtree[i]); + if( oldsubtrees[i] == 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; - } + newsubtrees = (char**) calloc(rparams->subtreecount, sizeof(char*)); + + if (newsubtrees == NULL) { + retval = ENOMEM; + goto cleanup; + } + + if ( (rparams != NULL) && (rparams->subtree != NULL) ) { + for (j=0; jsubtreecount && rparams->subtree[j]!= NULL; j++) { + newsubtrees[j] = strdup(rparams->subtree[j]); + if (newsubtrees[j] == NULL) { + retval = ENOMEM; + goto cleanup; + } + } + newsubtrees[j] = NULL; + } + for(j=0;oldsubtrees[j]!=NULL;j++) { + check_subtree = 1; + for(i=0; ( (oldsubtrees[j] && !rparams->subtree[i]) || + (!oldsubtrees[j] && rparams->subtree[i]))i; i++) { + if(strcasecmp( oldsubtrees[j], rparams->subtree[i]) == 0) { + check_subtree = 0; + continue; + } + } + if (check_subtree != 0) { + subtree_changed=1; + break; + } + } + /* this will return list of the disjoint members */ + disjoint_members( oldsubtrees, newsubtrees); } if ((mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_KDCSERVERS)) { @@ -1374,7 +1485,7 @@ void kdb5_ldap_modify(argc, argv) if (!subtree_changed) { disjoint_members(oldkdcdns, newkdcdns); - } else { /* Only the subtree was changed. Remove the rights on the old subtree. */ + } else { /* Only the subtrees was changed. Remove the rights on the old subtrees. */ if (!(mask & LDAP_REALM_KDCSERVERS)) { oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); @@ -1399,12 +1510,12 @@ void kdb5_ldap_modify(argc, argv) rightsmask =0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; - /* Remove the rights on the old subtree */ + /* Remove the rights on the old subtrees */ 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) { + rparams->realm_name, oldsubtrees, rightsmask)) != 0) { printf("failed\n"); com_err(argv[0], retval, "while assigning rights '%s'", rparams->realm_name); @@ -1452,7 +1563,7 @@ void kdb5_ldap_modify(argc, argv) if (!subtree_changed) { disjoint_members(oldadmindns, newadmindns); - } else { /* Only the subtree was changed. Remove the rights on the old subtree. */ + } else { /* Only the subtrees was changed. Remove the rights on the old subtrees. */ if (!(mask & LDAP_REALM_ADMINSERVERS)) { oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); @@ -1477,13 +1588,13 @@ void kdb5_ldap_modify(argc, argv) rightsmask = 0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; - /* Remove the rights on the old subtree */ + /* Remove the rights on the old subtrees */ 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) { + rparams->realm_name, oldsubtrees, rightsmask)) != 0) { printf("failed\n"); com_err(argv[0], retval, "while assigning rights '%s'", rparams->realm_name); @@ -1533,7 +1644,7 @@ void kdb5_ldap_modify(argc, argv) if (!subtree_changed) { disjoint_members(oldpwddns, newpwddns); - } else { /* Only the subtree was changed. Remove the rights on the old subtree. */ + } else { /* Only the subtrees was changed. Remove the rights on the old subtrees. */ if (!(mask & LDAP_REALM_ADMINSERVERS)) { oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*)); @@ -1558,12 +1669,12 @@ void kdb5_ldap_modify(argc, argv) rightsmask =0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; - /* Remove the rights on the old subtree */ + /* Remove the rights on the old subtrees */ 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))) { + rparams->realm_name, oldsubtrees, rightsmask))) { printf("failed\n"); com_err(argv[0], retval, "while assigning rights '%s'", rparams->realm_name); @@ -1605,6 +1716,7 @@ err_nomsg: cleanup: krb5_ldap_free_realm_params(rparams); + #ifdef HAVE_EDIRECTORY if (oldkdcdns) { for (i=0; oldkdcdns[i] != NULL; i++) @@ -1636,8 +1748,16 @@ cleanup: free(newadmindns[i]); free(newadmindns); } - if (oldsubtree) - free(oldsubtree); + if (oldsubtrees) { + for (i=0;oldsubtrees[i]!=NULL; i++) + free(oldsubtrees[i]); + free(oldsubtrees); + } + if (newsubtrees) { + for (i=0;newsubtrees[i]!=NULL; i++) + free(newsubtrees[i]); + free(oldsubtrees); + } #endif if (print_usage) { db_usage(MODIFY_REALM); @@ -1729,12 +1849,16 @@ static char *strdur(duration) static void print_realm_params(krb5_ldap_realm_params *rparams, int mask) { char **slist = NULL; - int num_entry_printed = 0; + int num_entry_printed = 0, i = 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_SUBTREE) { + for (i=0; rparams->subtree[i]!=NULL; i++) + printf("%25s: %-50s\n", "Subtree", rparams->subtree[i]); + } + if (mask & LDAP_REALM_CONTREF) + printf("%25s: %-50s\n", "Principal Container Reference", rparams->containerref); if (mask & LDAP_REALM_SEARCHSCOPE) { if ((rparams->search_scope != 1) && (rparams->search_scope != 2)) { @@ -1904,6 +2028,123 @@ void kdb5_ldap_list(argc, argv) return; } +/* + * Duplicating the following two functions here because + * 'krb5_dbe_update_tl_data' uses backend specific memory allocation. The catch + * here is that the backend is not initialized - kdb5_ldap_util doesn't go + * through DAL. + * 1. krb5_dbe_update_tl_data + * 2. krb5_dbe_update_mod_princ_data + */ + +/* Start duplicate code ... */ + +static krb5_error_code +krb5_dbe_update_tl_data_new(context, entry, new_tl_data) + krb5_context context; + krb5_db_entry *entry; + krb5_tl_data *new_tl_data; +{ + krb5_tl_data *tl_data = NULL; + krb5_octet *tmp; + + /* copy the new data first, so we can fail cleanly if malloc() + * fails */ +/* + if ((tmp = + (krb5_octet *) krb5_db_alloc(context, NULL, + new_tl_data->tl_data_length)) == NULL) +*/ + 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 */ + + if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */ + 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 *) krb5_db_alloc(context, NULL, + sizeof(krb5_tl_data))) + == NULL) { +*/ + if ((tl_data = (krb5_tl_data *) malloc (sizeof(krb5_tl_data))) == NULL) { + free(tmp); + return (ENOMEM); + } + memset(tl_data, 0, sizeof(krb5_tl_data)); + 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) + krb5_db_free(context, 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); +} + +static krb5_error_code +krb5_dbe_update_mod_princ_data_new(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_new(context, entry, &tl_data); + + free(unparse_mod_princ); + free(nextloc); + + return(retval); +} + +/* End duplicate code */ /* * This function creates service principals when @@ -1971,6 +2212,15 @@ kdb_ldap_create_principal (context, princ, op, pblock) entry.tl_data = tl_data; entry.n_tl_data += 1; + /* Set the creator's name */ + { + krb5_timestamp now; + if ((retval = krb5_timeofday(context, &now))) + goto cleanup; + if ((retval = krb5_dbe_update_mod_princ_data_new(context, &entry, + now, &db_create_princ))) + goto cleanup; + } entry.attributes = pblock->flags; entry.max_life = pblock->max_life; entry.max_renewable_life = pblock->max_rlife; diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.c index d5e7134e4..3cc0f0f91 100644 --- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.c +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util.c @@ -111,7 +111,7 @@ void usage() "\tcmd [cmd_options]\n" /* Create realm */ -"create [-subtree subtree_dn] [-sscope search_scope]\n" +"create [-subtrees subtree_dn_list] [-sscope search_scope] [-containerref container_reference_dn]\n" #ifdef HAVE_EDIRECTORY "\t\t[-kdcdn kdc_service_list] [-admindn admin_service_list]\n" "\t\t[-pwddn passwd_service_list]\n" @@ -121,7 +121,7 @@ void usage() "\t\t[ticket_flags] [-r realm]\n" /* modify realm */ -"modify [-subtree subtree_dn] [-sscope search_scope]\n" +"modify [-subtrees subtree_dn_list] [-sscope search_scope] [-containerref container_reference_dn]\n" #ifdef HAVE_EDIRECTORY "\t\t[-kdcdn kdc_service_list |\n" "\t\t[-clearkdcdn kdc_service_list] [-addkdcdn kdc_service_list]]\n" @@ -173,21 +173,21 @@ void usage() #endif /* Create policy */ -"create_policy [-maxtktlife max_ticket_life]\n" -"\t\t[-maxrenewlife max_renewable_ticket_life] [ticket_flags] policy_dn\n" +"create_policy [-r realm] [-maxtktlife max_ticket_life]\n" +"\t\t[-maxrenewlife max_renewable_ticket_life] [ticket_flags] policy\n" /* Modify policy */ -"modify_policy [-maxtktlife max_ticket_life]\n" -"\t\t[-maxrenewlife max_renewable_ticket_life] [ticket_flags] policy_dn\n" +"modify_policy [-r realm] [-maxtktlife max_ticket_life]\n" +"\t\t[-maxrenewlife max_renewable_ticket_life] [ticket_flags] policy\n" /* View policy */ -"view_policy policy_dn\n" +"view_policy [-r realm] policy\n" /* Destroy policy */ -"destroy_policy [-force] policy_dn\n" +"destroy_policy [-r realm] [-force] policy\n" /* List policies */ -"list_policy [-basedn base_dn]\n" +"list_policy [-r realm]\n" ); } @@ -300,7 +300,7 @@ int main(argc, argv) 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 realm_name_required = TRUE; krb5_boolean print_help_message = FALSE; retval = krb5_init_context(&util_context); @@ -417,12 +417,9 @@ int main(argc, argv) /* 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 ((strcmp(cmd_argv[0], "list") == 0) || + (strcmp(cmd_argv[0], "stashsrvpw") == 0)) { + realm_name_required = FALSE; } if (!util_context->default_realm) { diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h index f9f965c46..a8ec7aa6d 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h +++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h @@ -151,7 +151,7 @@ extern void prepend_err_str (krb5_context ctx, const char *s, krb5_error_code er #define KDB_TL_KEYINFO 0x04 #define KDB_TL_MASK 0x05 #define KDB_TL_CONTAINERDN 0x06 -#define KDB_TL_TKTPOLICYDN 0x07 +#define KDB_TL_LINKDN 0x07 #define CHECK_LDAP_HANDLE(lcontext) if (!(ldap_context \ @@ -280,9 +280,6 @@ krb5_ldap_read_startup_information(krb5_context ); int has_sasl_external_mech(krb5_context, char *); -krb5_error_code -krb5_get_policydn(krb5_context, krb5_db_entry *, char **); - /* DAL functions */ diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c index d784e0ff5..6a9c6b6e2 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c @@ -32,7 +32,7 @@ #include "kdb_ldap.h" #include "ldap_err.h" -char *policyrefattribute[] = {"krbPolicyReference",NULL}; +char *policyrefattribute[] = {"krbTicketPolicyReference",NULL}; char *krbcontainerrefattr[] = {"krbContainerReference", NULL}; /* @@ -169,7 +169,7 @@ krb5_ldap_read_krbcontainer_params(krb5_context context, #endif if ((ent = ldap_first_entry(ld, result))) { - if ((st=krb5_ldap_get_string(ld, ent, "krbpolicyreference", + if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &(cparams->policyreference), NULL)) != 0) goto cleanup; } diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c index f00016239..e37295b84 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c @@ -421,9 +421,9 @@ is_principal_in_realm(ldap_context, searchfor) /* * Deduce the subtree information from the context. A realm can have - * at most 2 subtrees. + * multiple subtrees. * 1. the Realm container - * 2. the actual subtree associated with the Realm + * 2. the actual subtrees 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 @@ -432,7 +432,7 @@ is_principal_in_realm(ldap_context, searchfor) * 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 has only one, i.e., the Realm container. NOTE: In all 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 @@ -442,70 +442,79 @@ is_principal_in_realm(ldap_context, searchfor) krb5_error_code krb5_get_subtree_info(ldap_context, subtreearr, ntree) krb5_ldap_context *ldap_context; - char **subtreearr; + char ***subtreearr; unsigned int *ntree; { - int lendiff=0; - char *subtree=NULL, *realm_cont_dn=NULL; - + int st=0, i=0, subtreecount=0; + int j=0, ncount=0, search_scope=0; + char **subtree=NULL, *realm_cont_dn=NULL; + char **subtarr=NULL; + char *containerref=NULL; + char **newsubtree=NULL; + + containerref = ldap_context->lrparams->containerref; subtree = ldap_context->lrparams->subtree; realm_cont_dn = ldap_context->lrparams->realmdn; + subtreecount = ldap_context->lrparams->subtreecount; + search_scope = ldap_context->lrparams->search_scope; - /* - * 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) { - /* - * XXX WAF to see if I can get around ldapsearch issue with a null base - * which doesn't work in solaris. This should probably be a Solaris - * specific #ifdef but I am not sure what define value to use. - */ - if (realm_cont_dn != NULL) { - subtreearr[0] = strdup(realm_cont_dn); - if (subtreearr[0] == NULL) - return ENOMEM; - } - *ntree = 1; - return 0; + subtarr = (char **) malloc(sizeof(char *) * (subtreecount + 1 /*realm dn*/ + 1 /*containerref*/ + 1)); + if (subtarr == NULL) { + st = ENOMEM; + goto cleanup; } + memset(subtarr, 0, (sizeof(char *) * (subtreecount+1+1+1))); - /* - * 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; + /* get the complete subtree list */ + for (i=0; itl_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; @@ -649,9 +628,10 @@ decode_tl_data(tl_data, tl_type, data) unsigned char *curr=NULL; int *intptr=NULL; long *longptr=NULL; - char *DN=NULL; + char *DN=NULL, **DNarr=NULL; krb5_boolean keyfound=FALSE; KEY *secretkey = NULL; + krb5_error_code st=-1; *data = NULL; @@ -691,12 +671,12 @@ decode_tl_data(tl_data, tl_type, data) *data = longptr; } curr += sublen; - return 0; + st = 0; + return st; 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 */ @@ -708,49 +688,36 @@ decode_tl_data(tl_data, tl_type, data) DN[sublen] = 0; *data = DN; curr += sublen; - return 0; + st = 0; + return st; 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) + case KDB_TL_LINKDN: + if (DNarr == NULL) { + DNarr = calloc(limit, sizeof(char *)); + if (DNarr == 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) + DNarr = realloc(DNarr, sizeof(char *) * (limit)); + if (DNarr == 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) + + /* get the length of the content */ + UNSTORE16_INT(curr, sublen); + /* forward by 2 bytes */ + curr += 2; + DNarr[i] = malloc (sublen + 1); + if (DNarr[i] == NULL) return ENOMEM; - - memcpy(secretkey->keys[i]->bv_val, curr, sublen); - secretkey->nkey = ++i; - *data = secretkey; + memcpy(DNarr[i], curr, sublen); + DNarr[i][sublen] = 0; + ++i; curr += sublen; + *data = DNarr; + st=0; break; } } else { @@ -759,13 +726,7 @@ decode_tl_data(tl_data, tl_type, data) curr += 2 + sublen; } } - if (tl_type == KDB_TL_KEYINFO) { - if (keyfound) - return 0; - else - return EINVAL; - } - return EINVAL; + return st; } /* @@ -829,24 +790,25 @@ krb5_get_princ_count(context, entries, pcount) } krb5_error_code -krb5_get_secretkeys(context, entries, secretkey) +krb5_get_linkdn(context, entries, link_dn) krb5_context context; krb5_db_entry *entries; - KEY **secretkey; + char ***link_dn; { krb5_error_code st=0; krb5_tl_data tl_data; void *voidptr=NULL; - + + *link_dn = 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; + + if (decode_tl_data(&tl_data, KDB_TL_LINKDN, &voidptr) == 0) { + *link_dn = (char **) voidptr; } -cleanup: + cleanup: return st; } @@ -861,7 +823,7 @@ krb5_get_str_from_tl_data(context, entries, type, strval) krb5_tl_data tl_data; void *voidptr=NULL; - if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN && type != KDB_TL_TKTPOLICYDN) { + if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN) { st = EINVAL; goto cleanup; } @@ -898,15 +860,6 @@ krb5_get_containerdn(context, entries, containerdn) 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 @@ -1301,6 +1254,59 @@ krb5_ldap_get_string(ld, ent, attribute, retstr, attr_present) return st; } +/* + * krb5_ldap_get_strings() - Returns all the values + * of the attribute. + */ +krb5_error_code +krb5_ldap_get_strings(ld, ent, attribute, retarr, attr_present) + LDAP *ld; + LDAPMessage *ent; + char *attribute; + char ***retarr; + krb5_boolean *attr_present; +{ + char **values=NULL; + krb5_error_code st=0; + int i=0, count=0; + + *retarr = NULL; + if (attr_present != NULL) + *attr_present = FALSE; + + values=ldap_get_values(ld, ent, attribute); + if (values != NULL) { + if (attr_present != NULL) + *attr_present = TRUE; + + count = ldap_count_values(values); + *retarr = (char **) calloc(count+1, sizeof(char *)); + if (*retarr == NULL) { + st = ENOMEM; + return st; + } + for (i=0; i< count; ++i) { + (*retarr)[i] = strdup(values[i]); + if ((*retarr)[i] == NULL) { + st = ENOMEM; + goto cleanup; + } + } + ldap_value_free(values); + } + +cleanup: + if (st != 0) { + if (*retarr != NULL) { + for (i=0; i< count; ++i) + if ((*retarr)[i] != NULL) + free ((*retarr)[i]); + free (*retarr); + } + } + return st; +} + krb5_error_code krb5_ldap_get_time(ld, ent, attribute, rettime, attr_present) LDAP *ld; @@ -1375,6 +1381,8 @@ krb5_add_str_mem_ldap_mod(mods, attribute, op, values) return ENOMEM; (*mods)[i]->mod_op = op; + (*mods)[i]->mod_values = NULL; + if (values != NULL) { for (j=0; values[j] != NULL; ++j) ; @@ -1550,3 +1558,274 @@ krb5_ldap_release_errcode_string(krb5_context kcontext, const char *msg) { krb5_free_error_message(kcontext, msg); } + + +/* + * Get the number of times an object has been referred to in a realm. this is + * needed to find out if deleting the attribute will cause dangling links. + * + * An LDAP handle may be optionally specified to prevent race condition - there + * are a limited number of LDAP handles. + */ +krb5_error_code +krb5_ldap_get_reference_count (krb5_context context, char *dn, char *refattr, + int *count, LDAP *ld) { + int i, ntrees, st = 0, tempst = 0, gothandle = 0; + char *refcntattr[2]; + char *filter = NULL; + char **subtree = NULL, *ptr = NULL; + kdb5_dal_handle *dal_handle = NULL; + krb5_ldap_context *ldap_context = NULL; + krb5_ldap_server_handle *ldap_server_handle = NULL; + LDAPMessage *result = NULL; + + + if (dn == NULL || refattr == NULL) { + st = EINVAL; + goto cleanup; + } + + SETUP_CONTEXT(); + if (ld == NULL) { + GET_HANDLE(); + gothandle = 1; + } + + refcntattr [0] = refattr; + refcntattr [1] = NULL; + + ptr = ldap_filter_correct (dn, strlen (dn)); + if (ptr == NULL) { + st = ENOMEM; + goto cleanup; + } + + filter = (char *) malloc (strlen (refattr) + strlen (ptr) + 2); + if (filter == NULL) { + st = ENOMEM; + goto cleanup; + } + + sprintf (filter, "%s=%s", refattr, ptr); + + if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0) + goto cleanup; + + for (i = 0, *count = 0; i < ntrees; i++) { + int n; + + LDAP_SEARCH(subtree[i], + LDAP_SCOPE_SUB, + filter, + refcntattr); + n = ldap_count_entries (ld, result); + if (n == -1) { + int ret, errcode = 0; + ret = ldap_parse_result (ld, result, &errcode, NULL, NULL, NULL, NULL, 0); + if (ret != LDAP_SUCCESS) + errcode = ret; + st = translate_ldap_error (errcode, OP_SEARCH); + goto cleanup; + } + + ldap_msgfree(result); + result = NULL; + + *count += n; + } + +cleanup: + if (filter != NULL) + free (filter); + + if (result != NULL) + ldap_msgfree (result); + + if (subtree != NULL) { + for (i = 0; i < ntrees; i++) + free (subtree[i]); + free (subtree); + } + + if (ptr != NULL) + free (ptr); + + if (gothandle == 1) + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + + return st; +} + +/* + * For now, policy objects are expected to be directly under the realm + * container. + */ +krb5_error_code krb5_ldap_policydn_to_name (context, policy_dn, name) + krb5_context context; + char *policy_dn; + char **name; +{ + int len1, len2; + krb5_error_code st = 0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + + SETUP_CONTEXT(); + + if (ldap_context->lrparams->realmdn == NULL) { + st = EINVAL; + goto cleanup; + } + + len1 = strlen (ldap_context->lrparams->realmdn); + len2 = strlen (policy_dn); + if (len1 == 0 || len2 == 0 || len1 > len2) { + st = EINVAL; + goto cleanup; + } + + if (strcmp (ldap_context->lrparams->realmdn, policy_dn + (len2 - len1)) != 0) { + st = EINVAL; + goto cleanup; + } + + { + char *rdn; + LDAPDN dn; + rdn = strndup(policy_dn, len2 - len1 - 1); /* 1 character for ',' */ + + if (ldap_str2dn (rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC) != 0) { + st = EINVAL; + goto cleanup; + } + if (dn[0] == NULL || dn[1] != NULL) + st = EINVAL; + else if (strcasecmp (dn[0][0]->la_attr.bv_val, "cn") != 0) + st = EINVAL; + else + *name = strndup(dn[0][0]->la_value.bv_val, dn[0][0]->la_value.bv_len); + + ldap_memfree (dn); + } +cleanup: + return st; +} + +krb5_error_code krb5_ldap_name_to_policydn (context, name, policy_dn) + krb5_context context; + char *name; + char **policy_dn; +{ + int len; + char *ptr = NULL; + krb5_error_code st = 0; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + + *policy_dn = NULL; + + /* validate the input parameters */ + if(name == NULL) { + st = EINVAL; + goto cleanup; + } + + /* Used for removing policy reference from an object */ + if (name[0] == '\0') { + if ((*policy_dn = strdup ("")) == NULL) + st = ENOMEM; + goto cleanup; + } + + SETUP_CONTEXT(); + + if (ldap_context->lrparams->realmdn == NULL) { + st = EINVAL; + goto cleanup; + } + len = strlen (ldap_context->lrparams->realmdn); + + ptr = ldap_filter_correct (name, strlen (name)); + if (ptr == NULL) { + st = ENOMEM; + goto cleanup; + } + len += strlen (ptr); + + len += sizeof ("cn=") + 3; + + *policy_dn = (char *) malloc (len); + if (*policy_dn == NULL) { + st = ENOMEM; + goto cleanup; + } + + sprintf (*policy_dn, "cn=%s,%s", ptr, ldap_context->lrparams->realmdn); + +cleanup: + if (ptr != NULL) + free (ptr); + return st; +} + +/* remove overlapping and repeated subtree entries from the list of subtrees */ +krb5_error_code remove_overlapping_subtrees( char **listin, char ***listop, int *subtcount, int sscope) +{ + int slen=0, k=0, j=0, lendiff=0; + int count = *subtcount; + char **subtree = *listop; + + slen = count-1; + for (k=0; k<=slen && listin[k]!=NULL ; k++) { + for (j=k+1; j<=slen && listin[j]!=NULL ;j++) { + lendiff = strlen(listin[k]) - strlen(listin[j]); + if (sscope == 2) { + if ((lendiff > 0) && (strcasecmp((listin[k])+lendiff, listin[j])==0)) { + if (k != slen ) { + free(listin[k]); + listin[k] = listin[slen]; + listin[slen] = NULL; + } else { + free(listin[k]); + listin[k] = NULL; + } + slen-=1; + k-=1; + break; + } + else if ((lendiff < 0) && (strcasecmp((listin[j])+lendiff, listin[k])==0)) { + if (j != slen ) { + free(listin[j]); + listin[j] = listin[slen]; + listin[slen]=NULL; + } else { + free(listin[j]); + listin[j] = NULL; + } + slen-=1; + j-=1; + } + } + if ((lendiff == 0) && (strcasecmp(listin[j], listin[k])==0)) { + if (j != slen) { + free(listin[j]); + listin[j] = listin[slen]; + listin[slen]=NULL; + } else { + free(listin[j]); + listin[j] = NULL; + } + slen -=1; + j-=1; + } + } + } + *subtcount=slen+1; + for(k=0; k<*subtcount && listin[k]!=NULL; k++) { + subtree[k] = strdup(listin[k]); + if (subtree[k] == 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 index 954e71ccc..ce9250d5c 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h @@ -63,7 +63,7 @@ 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_get_linkdn(krb5_context, krb5_db_entry *, char ***); krb5_error_code krb5_get_userdn(krb5_context, krb5_db_entry *, char **); @@ -81,7 +81,7 @@ 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_get_subtree_info(krb5_ldap_context *, char ***, unsigned int *); krb5_error_code krb5_ldap_read_server_params(krb5_context , char *, int); @@ -101,6 +101,9 @@ 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_strings(LDAP *, LDAPMessage *, char *, char ***, krb5_boolean *); + krb5_error_code krb5_ldap_get_time(LDAP *, LDAPMessage *, char *, krb5_timestamp *, krb5_boolean *); @@ -122,6 +125,15 @@ krb5_add_int_mem_ldap_mod(LDAPMod ***, char *, int , int); krb5_error_code krb5_ldap_free_mod_array(LDAPMod **); +krb5_error_code +krb5_ldap_get_reference_count (krb5_context, char *, char *, int *, LDAP *); + +krb5_error_code +krb5_ldap_policydn_to_name (krb5_context, char *, char **); + +krb5_error_code +krb5_ldap_name_to_policydn (krb5_context, char *, char **); + krb5_error_code krb5_ldap_get_db_opt(char *, char **, char **); diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c index b0488eb52..ad4fef975 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c @@ -37,34 +37,43 @@ struct timeval timelimit = {300, 0}; /* 5 minutes */ char *principal_attributes[] = { "krbprincipalname", "objectclass", - "krbsecretkey", + "krbprincipalkey", "krbmaxrenewableage", "krbmaxticketlife", "krbticketflags", "krbprincipalexpiration", - "krbpolicyreference", + "krbticketpolicyreference", "krbUpEnabled", "krbpwdpolicyreference", "krbpasswordexpiration", +#ifdef KRBCONF_KDC_MODIFIES_KDB + "krbLastFailedAuth", + "krbLoginFailedCount", + "krbLastSuccessfulAuth", +#endif #ifdef HAVE_EDIRECTORY "loginexpirationtime", "logindisabled", #endif "loginexpirationtime", "logindisabled", - "modifiersname", "modifytimestamp", + "krbLastPwdChange", + "krbExtraData", + "krbObjectReferences", NULL }; static char *attributes_set[] = { "krbmaxrenewableage", "krbmaxticketlife", "krbticketflags", "krbprincipalexpiration", - "krbpolicyreference", + "krbticketpolicyreference", "krbUpEnabled", "krbpwdpolicyreference", "krbpasswordexpiration", - "krbsecretkey", + "krbprincipalkey", + "krblastpwdchange", + "krbextradata", NULL }; void @@ -131,7 +140,7 @@ krb5_ldap_iterate(context, match_expr, func, func_arg) { krb5_db_entry entry; krb5_principal principal; - char *subtree[2]={NULL}, *princ_name=NULL, *realm=NULL, **values=NULL, *filter=NULL; + char **subtree=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; @@ -163,7 +172,7 @@ krb5_ldap_iterate(context, match_expr, func, func_arg) memset(filter, 0, filterlen); sprintf(filter, FILTER"%s))", match_expr); - if ((st = krb5_get_subtree_info(ldap_context, subtree, &ntree)) != 0) + if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntree)) != 0) goto cleanup; GET_HANDLE(); @@ -217,7 +226,7 @@ krb5_ldap_delete_principal(context, searchfor, nentries) 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; + int j=0, ptype=0, pcount=0, attrsetmask=0; krb5_error_code st=0; krb5_boolean singleentry=FALSE; KEY *secretkey=NULL; @@ -226,7 +235,6 @@ krb5_ldap_delete_principal(context, searchfor, nentries) 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); @@ -239,9 +247,7 @@ krb5_ldap_delete_principal(context, searchfor, nentries) 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)) + ((st=krb5_get_userdn(context, &entries, &(DN))) != 0)) goto cleanup; if (DN == NULL) { @@ -252,8 +258,13 @@ krb5_ldap_delete_principal(context, searchfor, nentries) GET_HANDLE(); - if (ptype == KDB_USER_PRINCIPAL) { - + if (ptype == KDB_STANDALONE_PRINCIPAL_OBJECT) { + st = ldap_delete_ext_s(ld, DN, NULL, NULL); + if (st != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_DEL); + goto cleanup; + } + } else { if (((st=krb5_unparse_name(context, searchfor, &user)) != 0) || ((st=krb5_ldap_unparse_principal_name(user)) != 0)) goto cleanup; @@ -267,7 +278,7 @@ krb5_ldap_delete_principal(context, searchfor, nentries) 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, + if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey", LDAP_MOD_DELETE | LDAP_MOD_BVALUES, secretkey->keys)) != 0) goto cleanup; } @@ -290,15 +301,11 @@ krb5_ldap_delete_principal(context, searchfor, nentries) 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}; + char *attrvalues[] = {"krbticketpolicyaux", "krbprincipalaux", NULL}; +// char *attrvalues[] = {"krbpwdpolicyrefaux", "krbticketpolicyaux", "krbprincipalaux", NULL}; int p, q, r=0, amask=0; if ((st=checkattributevalue(ld, DN, "objectclass", attrvalues, &amask)) != 0) @@ -320,12 +327,6 @@ krb5_ldap_delete_principal(context, searchfor, nentries) st = set_ldap_error(context, st, OP_MOD); goto cleanup; } - } else if (ptype == KDB_SERVICE_PRINCIPAL) { - st = ldap_delete_ext_s(ld, DN, NULL, NULL); - if (st != LDAP_SUCCESS) { - st = set_ldap_error (context, st, OP_DEL); - goto cleanup; - } } cleanup: diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h index 65224c8d3..c4f5e93b7 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h @@ -52,12 +52,16 @@ #define MAX_KEY_LENGTH 1024 #define CONTAINERDN_ARG "containerdn" -#define USERDN_ARG "userdn" -#define TKTPOLICYDN_ARG "tktpolicydn" +#define USERDN_ARG "dn" +#define TKTPOLICY_ARG "tktpolicy" +#define LINKDN_ARG "linkdn" + +/* #define FILTER "(&(objectclass=krbprincipalaux)(krbprincipalname=" */ + #define FILTER "(&(|(objectclass=krbprincipalaux)(objectclass=krbprincipal))(krbprincipalname=" -#define FILTER "(&(objectclass=krbprincipalaux)(krbprincipalname=" #define KDB_USER_PRINCIPAL 0x01 #define KDB_SERVICE_PRINCIPAL 0x02 +#define KDB_STANDALONE_PRINCIPAL_OBJECT 0x01 /* krb5_db_entry */ #define KDB_PRINCIPAL 0x000001 @@ -94,6 +98,8 @@ #define KDB_PWD_POL_REF_ATTR 0x000040 #define KDB_PWD_EXPIRE_TIME_ATTR 0x000080 #define KDB_SECRET_KEY 0x000100 +#define KDB_LAST_PWD_CHANGE_ATTR 0x000200 +#define KDB_EXTRA_DATA 0x000400 extern struct timeval timeout; extern char *policyclass[]; diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c index 5f0c30fba..cc59c1fbe 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c @@ -48,11 +48,30 @@ 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 *); +krb5_read_tkt_policy (krb5_context, krb5_ldap_context *, krb5_db_entry *, char *); static char * getstringtime(krb5_timestamp); +static krb5_error_code berval2tl_data (struct berval *in, krb5_tl_data **out) { + *out = (krb5_tl_data *) malloc (sizeof (krb5_tl_data)); + if (*out == NULL) + return ENOMEM; + + (*out)->tl_data_length = in->bv_len - 2; + (*out)->tl_data_contents = (krb5_octet *) malloc + ((*out)->tl_data_length * sizeof (krb5_octet)); + if ((*out)->tl_data_contents == NULL) { + free (*out); + return ENOMEM; + } + + UNSTORE16_INT (in->bv_val, (*out)->tl_data_type); + memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length); + + return 0; +} + /* * look up a principal in the directory. */ @@ -65,12 +84,13 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) int *nentries; /* how much room/how many found */ krb5_boolean *more; /* are there more? */ { - char *user=NULL, *DN=NULL, *filter=NULL, *subtree[2]={NULL}; + char *user=NULL, *DN=NULL, *filter=NULL, **subtree=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; + char **values=NULL, *policydn=NULL, *pwdpolicydn=NULL; + char *polname = NULL, *tktpolname = NULL; + char **link_references=NULL; krb5_tl_data userinfo_tl_data={0}; - krb5_timestamp modtime=0; struct berval **bvalues=NULL; LDAP *ld=NULL; LDAPMessage *result=NULL, *ent=NULL; @@ -115,7 +135,7 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) } snprintf(filter, princlen, FILTER"%s))", user); - if ((st = krb5_get_subtree_info(ldap_context, subtree, &ntrees)) != 0) + if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0) goto cleanup; GET_HANDLE(); @@ -126,7 +146,7 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) /* get the associated directory user information */ if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) { - int i=0, pcount=0, ptype=KDB_USER_PRINCIPAL; + int i=0, pcount=0, kerberos_principal_object_type=0; /* a wild-card in a principal name can return a list of kerberos principals. * Make sure that the correct principal is returned. @@ -153,7 +173,9 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) 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; + kerberos_principal_object_type = KDB_STANDALONE_PRINCIPAL_OBJECT; + if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE, &kerberos_principal_object_type)) != 0) + goto cleanup; break; } ldap_value_free(values); @@ -161,8 +183,7 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) /* 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)) + ((st=store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, DN)) != 0)) goto cleanup; } @@ -172,6 +193,24 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) /* read all the kerberos attributes */ +#ifdef KRBCONF_KDC_MODIFIES_KDB + /* KRBLASTSUCCESSFULAUTH */ + if ((st=krb5_ldap_get_time(ld, ent, "krbLastSuccessfulAuth", &(entries->last_success),&attr_present)) != 0) + goto cleanup; + if (attr_present == TRUE) + mask |= KDB_LAST_SUCCESS; + + /* KRBLASTFAILEDAUTH */ + if ((st=krb5_ldap_get_time(ld, ent, "krbLastFailedAuth", &(entries->last_failed),&attr_present)) != 0) + goto cleanup; + if (attr_present == TRUE) + mask |= KDB_LAST_FAILED; + + /* KRBLOGINFAILEDCOUNT */ + if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount", &(entries->fail_auth_count)) == 0) + mask |= KDB_FAIL_AUTH_COUNT; +#endif + /* KRBMAXTICKETLIFE */ if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entries->max_life)) == 0) mask |= KDB_MAX_LIFE_ATTR; @@ -200,13 +239,13 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) /* KRBPOLICYREFERENCE */ - if ((st=krb5_ldap_get_string(ld, ent, "krbpolicyreference", &policydn, &attr_present)) != 0) + if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn, &attr_present)) != 0) goto cleanup; if (attr_present == TRUE) { - if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_TKTPOLICYDN, policydn)) != 0) + /* Ensure that the policy is inside the realm container */ + if ((st = krb5_ldap_policydn_to_name (context, policydn, &tktpolname)) != 0) goto cleanup; - mask |= KDB_POL_REF_ATTR; } /* KRBPWDPOLICYREFERENCE */ @@ -216,32 +255,69 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) krb5_tl_data kadm_tl_data; mask |= KDB_PWD_POL_REF_ATTR; - if ((st = krb5_update_tl_kadm_data(pwdpolicydn, &kadm_tl_data)) != 0) { + + /* Ensure that the policy is inside the realm container */ + if ((st = krb5_ldap_policydn_to_name (context, pwdpolicydn, &polname)) != 0) + goto cleanup; + + if ((st = krb5_update_tl_kadm_data(polname, &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) { + if ((bvalues=ldap_get_values_len(ld, ent, "krbprincipalkey")) != 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) + /* LAST PASSWORD CHANGE */ + { + krb5_timestamp lstpwdchng=0; + if ((st=krb5_ldap_get_time(ld, ent, "krbLastPwdChange", + &lstpwdchng, &attr_present)) != 0) goto cleanup; + if (attr_present == TRUE) { + if ((st=krb5_dbe_update_last_pwd_change(context, entries, + lstpwdchng))) + goto cleanup; + mask |= KDB_LAST_PWD_CHANGE_ATTR; + } + } - if ((st=krb5_dbe_update_mod_princ_data(context, entries, modtime, parsed_mod_name)) != 0) + /* KRBOBJECTREFERENCES */ + { + int i=0; + if ((st=krb5_ldap_get_strings(ld, ent, "krbobjectreferences", &link_references, &attr_present)) != 0) goto cleanup; + if (link_references != NULL) { + for (i=0; link_references[i] != NULL; ++i) { + if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN, link_references[i])) != 0) + goto cleanup; + } + } + } + + // Set tl_data + { + int i; + struct berval **ber_tl_data = NULL; + krb5_tl_data *ptr = NULL; + + if ((ber_tl_data = ldap_get_values_len (ld, ent, "krbExtraData")) != NULL) { + for (i = 0; ber_tl_data[i] != NULL; i++) { + if ((st = berval2tl_data (ber_tl_data[i] , &ptr)) != 0) + break; + if ((st = krb5_dbe_update_tl_data(context, entries, ptr)) != 0) + break; + } + ldap_value_free_len (ber_tl_data); + if (st != 0) + goto cleanup; + mask |= KDB_EXTRA_DATA; + } } /* update the mask of attributes present on the directory object to the tl_data */ @@ -292,10 +368,11 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) if (*nentries == 0) goto cleanup; - if ((st=krb5_read_tkt_policyreference(context, ldap_context, entries, policydn)) !=0) + if ((st=krb5_read_tkt_policy (context, ldap_context, entries, tktpolname)) !=0) goto cleanup; - if (pwdpolicydn) { + /* We already know that the policy is inside the realm container. */ + if (polname) { osa_policy_ent_t pwdpol; int cnt=0; krb5_timestamp last_pw_changed; @@ -303,7 +380,7 @@ krb5_ldap_get_principal(context, searchfor, entries, nentries, more) memset(&pwdpol, 0, sizeof(pwdpol)); - if ((st=krb5_ldap_get_password_policy(context, pwdpolicydn, &pwdpol, &cnt)) != 0) + if ((st=krb5_ldap_get_password_policy(context, polname, &pwdpol, &cnt)) != 0) goto cleanup; pw_max_life = pwdpol->pw_max_life; free (pwdpol); @@ -332,9 +409,12 @@ cleanup: if (DN) ldap_memfree (DN); - for (; ntrees; --ntrees) - if (subtree[ntrees-1]) - free (subtree[ntrees-1]); + if (subtree) { + for (; ntrees; --ntrees) + if (subtree[ntrees-1]) + free (subtree[ntrees-1]); + free (subtree); + } if (userinfo_tl_data.tl_data_contents) free(userinfo_tl_data.tl_data_contents); @@ -345,24 +425,35 @@ cleanup: if (user) free(user); - if (modname) - free(modname); - if (parsed_mod_name) krb5_free_principal(context, parsed_mod_name); if (pwdpolicydn) free(pwdpolicydn); + if (polname != NULL) + free(polname); + + if (tktpolname != NULL) + free (tktpolname); + if (policydn) free(policydn); return st; } +typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION; +/* + * ptype is creating confusions. Additionally the logic + * surronding ptype is redundunt and can be achevied + * with the help of dn and containerdn members. + * so dropping the ptype member + */ + typedef struct _xargs_t { - int ptype; char *dn; + char *linkdn; krb5_boolean dn_from_kbd; char *containerdn; char *tktpolicydn; @@ -374,6 +465,8 @@ free_xargs(xargs) { if (xargs.dn) free (xargs.dn); + if (xargs.linkdn) + free(xargs.linkdn); if (xargs.containerdn) free (xargs.containerdn); if (xargs.tktpolicydn) @@ -381,102 +474,87 @@ free_xargs(xargs) } static krb5_error_code -process_db_args(context, db_args, xargs) +process_db_args(context, db_args, xargs, optype) krb5_context context; char **db_args; xargs_t *xargs; + OPERATION optype; { int i=0; krb5_error_code st=0; char errbuf[1024]; - char *arg=NULL, *arg_val=NULL; + char *arg=NULL, *arg_val=NULL; + char **dptr=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) { + if (strcmp(arg, TKTPOLICY_ARG) == 0) { + dptr = &xargs->tktpolicydn; + } else { + if (strcmp(arg, USERDN_ARG) == 0) { + if (optype == MODIFY_PRINCIPAL) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "%s option not supported", arg); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + dptr = &xargs->dn; + } else if (strcmp(arg, CONTAINERDN_ARG) == 0) { + if (optype == MODIFY_PRINCIPAL) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "%s option not supported", arg); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + dptr = &xargs->containerdn; + } else if (strcmp(arg, LINKDN_ARG) == 0) { + dptr = &xargs->linkdn; + } else { st = EINVAL; - snprintf(errbuf, sizeof(errbuf), "%s option value missing", arg); + snprintf(errbuf, sizeof(errbuf), "unknown option: %s", 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) { + if (xargs->dn != NULL || xargs->containerdn != NULL || xargs->linkdn != 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) { + if (arg_val == NULL || strlen(arg_val) == 0) { 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 { + if (arg_val == NULL) { st = EINVAL; - snprintf(errbuf, sizeof(errbuf), "unknown option: %s", arg); + 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; + + if (strcmp(arg, TKTPOLICY_ARG) == 0) { + if ((st = krb5_ldap_name_to_policydn (context, arg_val, dptr)) != 0) + goto cleanup; + } else { + *dptr = calloc (1, arg_val_len); + if (*dptr == NULL) { + st = ENOMEM; + goto cleanup; + } + memcpy(*dptr, arg_val, arg_val_len); + } } } + cleanup: return st; } @@ -520,6 +598,24 @@ krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data) { return ret; } +static krb5_error_code tl_data2berval (krb5_tl_data *in, struct berval **out) { + *out = (struct berval *) malloc (sizeof (struct berval)); + if (*out == NULL) + return ENOMEM; + + (*out)->bv_len = in->tl_data_length + 2; + (*out)->bv_val = (char *) malloc ((*out)->bv_len); + if ((*out)->bv_val == NULL) { + free (*out); + return ENOMEM; + } + + STORE16_INT((*out)->bv_val, in->tl_data_type); + memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length); + + return 0; +} + krb5_error_code krb5_ldap_put_principal(context, entries, nentries, db_args) krb5_context context; @@ -527,15 +623,18 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) register int *nentries; /* number of entry structs to update */ char **db_args; { - int i=0, l=0, plen=0; + int i=0, l=0, plen=0, kerberos_principal_object_type=0; krb5_error_code st=0, tempst=0; LDAP *ld=NULL; LDAPMessage *result=NULL, *ent=NULL; - char *user=NULL, *subtree=NULL; + char *user=NULL, *subtree=NULL, *principal_dn=NULL; char **values=NULL, *strval[10]={NULL}, errbuf[1024]; struct berval **bersecretkey=NULL; - LDAPMod **mods=NULL; - krb5_boolean dnfound=TRUE, tktpolicy_set=FALSE; + LDAPMod **mods=NULL, **mod_for_link=NULL; + krb5_boolean dnfound=TRUE, tktpolicy_set=FALSE, create_standalone_prinicipal=FALSE; + krb5_boolean krb_identity_exists=FALSE, establish_links=FALSE; + krb5_boolean extend_object_with_princrefaux=FALSE; + char *standalone_principal_dn=NULL; krb5_tl_data *tl_data=NULL; krb5_key_data **keys=NULL; kdb5_dal_handle *dal_handle=NULL; @@ -543,7 +642,8 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) krb5_ldap_server_handle *ldap_server_handle=NULL; osa_princ_ent_rec princ_ent; xargs_t xargs={0}; - char *oldpolicydn = NULL; + char *polname = NULL; + OPERATION optype; /* Clear the global error string */ krb5_clear_error_message(context); @@ -569,21 +669,29 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) 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)) - goto cleanup; - if ((st=process_db_args(context, db_args, &xargs)) != 0) + /* Identity the type of operation, it can be + * add principal or modify principal. + * hack if the entries->mask has KRB_PRINCIPAL flag set + * then it is a add operation + */ + if (entries->mask & KDB_PRINCIPAL == 1) + optype = ADD_PRINCIPAL; + else + optype = MODIFY_PRINCIPAL; + + if (((st=krb5_get_princ_type(context, entries, &kerberos_principal_object_type)) != 0) || + ((st=krb5_get_userdn(context, entries, &principal_dn)) != 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; - } + if ((st=process_db_args(context, db_args, &xargs, optype)) != 0) + goto cleanup; + /* time to generate the DN information with the help of + * containerdn, principalcontainerreference or + * realmcontainerdn information + */ + if (principal_dn ==NULL && xargs.dn == NULL) { /* creation of standalone principal */ /* get the subtree information */ if (entries->princ->length == 2 && entries->princ->data[0].length == strlen("krbtgt") && strncmp(entries->princ->data[0].data, "krbtgt", entries->princ->data[0].length) == 0) { @@ -600,28 +708,58 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) 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 if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) { + /* + * Here the subtree should be changed with + * principalcontainerreference attribute value + */ + subtree = strdup(ldap_context->lrparams->containerref); } else { subtree = strdup(ldap_context->lrparams->realmdn); } CHECK_NULL(subtree); - xargs.dn = malloc(strlen("krbprincipalname=") + strlen(user) + strlen(",") + - strlen(subtree) + 1); - CHECK_NULL(xargs.dn); - sprintf(xargs.dn, "krbprincipalname=%s,%s", user, subtree); + standalone_principal_dn = malloc(strlen("krbprincipalname=") + strlen(user) + strlen(",") + + strlen(subtree) + 1); + CHECK_NULL(standalone_principal_dn); + sprintf(standalone_principal_dn, "krbprincipalname=%s,%s", user, subtree); + /* + * free subtree when you are done using the subtree + * set the boolean create_standalone_prinicipal to TRUE + */ + create_standalone_prinicipal = TRUE; + free(subtree); + subtree = NULL; } + /* + * If the DN information is presented by the user, time to + * validate the input to ensure that the DN falls under + * any of the subtrees + */ if (xargs.dn_from_kbd == TRUE) { /* make sure the DN falls in the subtree */ int tre=0, dnlen=0, subtreelen=0, ntrees=0; - char *subtreelist[2]={NULL}; + char **subtreelist=NULL; + char *dn=NULL; krb5_boolean outofsubtree=TRUE; + if (xargs.dn != NULL) { + dn = xargs.dn; + } else if (xargs.linkdn != NULL) { + dn = xargs.linkdn; + } else if (standalone_principal_dn != NULL) { + /* + * Even though the standalone_principal_dn is constructed + * within this function, there is the containerdn input + * from the user that can become part of the it. + */ + dn = standalone_principal_dn; + } + /* get the current subtree list */ - if ((st = krb5_get_subtree_info(ldap_context, subtreelist, &ntrees)) != 0) + 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)) { + if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) { outofsubtree = FALSE; break; } @@ -647,87 +785,113 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) 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); + /* + * dn value will be set either by dn, linkdn or the standalone_principal_dn + * In the first 2 cases, the dn should be existing and in the last case we + * are supposed to create the ldap object. so the below should not be + * executed for the last case. + */ + + if (standalone_principal_dn == NULL) { + /* + * If the ldap object is missing, this results in an error. + */ + + /* + * Search for krbprincipalname attribute here. + * This is to find if a kerberos identity is already present + * on the ldap object, in which case adding a kerberos identity + * on the ldap object should result in an error. + */ + char *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL}; + + LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes,IGNORE_STATUS); + if (st == LDAP_SUCCESS) { + ent = ldap_first_entry(ld, result); + if (ent != NULL) { + if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) { + tktpolicy_set = TRUE; + ldap_value_free(values); + } + + if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) { + krb_identity_exists = TRUE; + ldap_value_free(values); + } } + ldap_msgfree(result); + } else { + st = set_ldap_error(context, st, OP_SEARCH); + goto cleanup; } - 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 xargs.dn is set then the request is to add a + * kerberos principal on a ldap object, but if + * there is one already on the ldap object this + * should result in an error. + */ - if ((st=checkattributevalue(ld, xargs.dn, "objectclass", attrvalues, &amask)) != 0) { - st = KRB5_KDB_UK_RERROR; + if (xargs.dn != NULL && krb_identity_exists == TRUE) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "ldap object is already kerberized"); + krb5_set_error_message(context, st, "%s", errbuf); + goto cleanup; + } + + if (xargs.linkdn != NULL) { + /* + * link information can be changed using modprinc. + * However, link information can be changed only on the + * standalone kerberos principal objects. A standalone + * kerberos principal object is of type krbprincipal + * structural objectclass. + * + * NOTE: kerberos principals on an ldap object can't be + * linked to other ldap objects. + */ + if (optype == MODIFY_PRINCIPAL && + kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) { + st = EINVAL; + snprintf(errbuf, sizeof(errbuf), "link information can't be set/updated as the kerberos principal belongs to an ldap object"); + krb5_set_error_message(context, st, "%s", errbuf); goto cleanup; } + establish_links = TRUE; + } + +#ifdef KRBCONF_KDC_MODIFIES_KDB + if ((entries->last_success)!=0) { memset(strval, 0, sizeof(strval)); - for (p=1, q=0; p<=4; p<<=1, ++q) { - if ((p & amask) == 0) - strval[r++] = attrvalues[q]; + if ((strval[0]=getstringtime(entries->last_success)) == NULL) + goto cleanup; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) { + free (strval[0]); + goto cleanup; } - if (r != 0) { - if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) - goto cleanup; + free (strval[0]); + } + + if (entries->last_failed!=0) { + memset(strval, 0, sizeof(strval)); + if ((strval[0]=getstringtime(entries->last_failed)) == NULL) + goto cleanup; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) { + free (strval[0]); + goto cleanup; } + free(strval[0]); } + if (entries->fail_auth_count!=0) { + if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_REPLACE, entries->fail_auth_count)) !=0) + goto cleanup; + } +#endif + 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; @@ -789,7 +953,9 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) if (princ_ent.aux_attributes & KDB_POLICY) { memset(strval, 0, sizeof(strval)); - strval[0] = princ_ent.policy; + if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0) + goto cleanup; + strval[0] = polname; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0) goto cleanup; } else { @@ -800,8 +966,7 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) } 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) + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0) goto cleanup; } @@ -812,7 +977,7 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) bersecretkey = krb5_encode_krbsecretkey (entries->key_data, entries->n_key_data); - if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbsecretkey", + if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey", LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0) goto cleanup; @@ -828,91 +993,169 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) } free (strval[0]); } + + /* Update last password change whenever a new key is set */ + { + krb5_timestamp last_pw_changed; + if ((st=krb5_dbe_lookup_last_pwd_change(context, entries, + &last_pw_changed)) != 0) + goto cleanup; + + memset(strval, 0, sizeof(strval)); + if ((strval[0] = getstringtime(last_pw_changed)) == NULL) + goto cleanup; + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange", + LDAP_MOD_REPLACE, strval)) != 0) { + free (strval[0]); + goto cleanup; + } + free (strval[0]); + } + } /* Modify Key data ends here */ + // Set tl_data + if (entries->tl_data != NULL) { + int count = 0; + struct berval **ber_tl_data = NULL; + krb5_tl_data *ptr; + for (ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) { + if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE +#ifdef SECURID + || ptr->tl_data_type == KRB5_TL_DB_ARGS +#endif + || ptr->tl_data_type == KRB5_TL_KADM_DATA + || ptr->tl_data_type == KDB_TL_USER_INFO) + continue; + count ++; + } + if (count != 0) { + int i; + ber_tl_data = (struct berval **) calloc (count, sizeof (struct + berval*)); + for (i = 0, ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) { + /* Ignore tl_data that are stored in separate directory + * attributes */ + if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE +#ifdef SECURID + || ptr->tl_data_type == KRB5_TL_DB_ARGS +#endif + || ptr->tl_data_type == KRB5_TL_KADM_DATA + || ptr->tl_data_type == KDB_TL_USER_INFO) + continue; + if ((st = tl_data2berval (ptr, &ber_tl_data[i])) != 0) + break; + i++; + } + if (st != 0) { + for (i = 0; ber_tl_data[i] != NULL; i++) { + free (ber_tl_data[i]->bv_val); + free (ber_tl_data[i]); + } + free (ber_tl_data); + goto cleanup; + } + if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData", + LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, + ber_tl_data)) != 0) + goto cleanup; + } + } + /* Directory specific attribute */ if (xargs.tktpolicydn != NULL) { int tmask=0, tkttree = 0, subtreednlen = 0, ntre = 0, tktdnlen = 0; - char *subtreednlist[2]={NULL}; + char **subtreednlist=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) + strval[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 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); + /* if xargs.tktpolicydn is a empty string, then delete + * already existing krbticketpolicyreference attr */ + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0) goto cleanup; - } 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) { + + + if (establish_links == TRUE) { + memset(strval, 0, sizeof(strval)); + strval[0] = xargs.linkdn; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0) goto cleanup; - } - st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL); + } + + /* + * in case mods is NULL then return + * not sure but can happen in a modprinc + * so no need to return an error + * addprinc will atleast have the principal name + * and the keys passed in + */ + if (mods == NULL) + goto cleanup; + + if (create_standalone_prinicipal == TRUE) { + memset(strval, 0, sizeof(strval)); + strval[0] = "krbprincipal"; + strval[1] = "krbprincipalaux"; + strval[2] = "krbTicketPolicyAux"; + + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + + st=ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL); if (st != LDAP_SUCCESS) { - sprintf(errbuf, "User modification failed: %s", ldap_err2string(st)); - st = translate_ldap_error (st, OP_MOD); + 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; } } else { - st=ldap_add_ext_s(ld, xargs.dn, mods, NULL, NULL); + /* + * Here existing ldap object is modified and can be related + * to any attribute, so always ensure that the ldap + * object is extended with all the kerberos related + * objectclasses so that there are no constraint + * violations. + */ + { + char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL}; + int p, q, r=0, amask=0; + + if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn, + "objectclass", attrvalues, &amask)) != 0) { + st = KRB5_KDB_UK_RERROR; + goto cleanup; + } + memset(strval, 0, sizeof(strval)); + for (p=1, q=0; p<=2; p<<=1, ++q) { + if ((p & amask) == 0) + strval[r++] = attrvalues[q]; + } + if (r != 0) { + if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) + goto cleanup; + } + } + if (xargs.dn != NULL) + st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL); + else + st=ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL); if (st != LDAP_SUCCESS) { - sprintf(errbuf, "Principal add failed: %s", ldap_err2string(st)); - st = translate_ldap_error (st, OP_ADD); + 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; } @@ -926,6 +1169,15 @@ cleanup: free_xargs(xargs); + if (standalone_principal_dn) + free(standalone_principal_dn); + + if (principal_dn) + free (principal_dn); + + if (polname != NULL) + free(polname); + if (subtree) free (subtree); @@ -948,11 +1200,11 @@ cleanup: } static krb5_error_code -krb5_read_tkt_policyreference(context, ldap_context, entries, policydn) +krb5_read_tkt_policy (context, ldap_context, entries, policy) krb5_context context; krb5_ldap_context *ldap_context; krb5_db_entry *entries; - char *policydn; + char *policy; { krb5_error_code st=0; unsigned int mask=0, omask=0; @@ -962,49 +1214,44 @@ krb5_read_tkt_policyreference(context, ldap_context, entries, policydn) if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0) goto cleanup; - if ((mask & tkt_mask) == 0) { - 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; - } + if ((mask & tkt_mask) == tkt_mask) + goto cleanup; - st = 0; /* reset the return status */ + if (policy != NULL) { + st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask); + if (st && st != KRB5_KDB_NOENTRY) { + prepend_err_str(context, "Error reading ticket policy. ", st, st); + goto cleanup; } - 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; - } + st = 0; /* reset the return status */ + } - 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_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 + entries->max_life = KRB5_KDB_MAX_LIFE; + } - 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); + 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 + 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; } + krb5_ldap_free_policy(context, tktpoldnparam); cleanup: return st; @@ -1017,12 +1264,10 @@ krb5_decode_krbsecretkey(context, entries, bvalues, userinfo_tl_data) 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; + char *user=NULL; + int i=0, j=0, noofkeys=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; diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c index 7aa78010e..87c576efc 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c @@ -33,9 +33,9 @@ #include "ldap_pwd_policy.h" #include "ldap_err.h" -static char *password_policy_attributes[] = { "krbmaxpwdlife", "krbminpwdlife", "krbpwdmindiffchars", - "krbpwdminlength", "krbpwdhistorylength", "krbpwdpolicyrefcount", - NULL }; +static char *password_policy_attributes[] = { "krbmaxpwdlife", "krbminpwdlife", + "krbpwdmindiffchars", "krbpwdminlength", + "krbpwdhistorylength", NULL }; /* * Function to create password policy object. @@ -52,7 +52,7 @@ krb5_ldap_create_password_policy (context, policy) 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}; + char **rdns=NULL, *strval[2]={NULL}, *policy_dn; /* Clear the global error string */ krb5_clear_error_message(context); @@ -64,8 +64,12 @@ krb5_ldap_create_password_policy (context, policy) SETUP_CONTEXT(); GET_HANDLE(); + st = krb5_ldap_name_to_policydn (context, policy->name, &policy_dn); + if (st != 0) + goto cleanup; + /* get the first component of the dn to set the cn attribute */ - rdns = ldap_explode_dn(policy->name, 1); + rdns = ldap_explode_dn(policy_dn, 1); if (rdns == NULL) { st = EINVAL; krb5_set_error_message(context, st, "Invalid password policy DN syntax"); @@ -89,13 +93,11 @@ krb5_ldap_create_password_policy (context, policy) || ((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)) + (signed) policy->pw_history_num)) != 0)) goto cleanup; /* password policy object creation */ - if ((st=ldap_add_ext_s(ld, policy->name, mods, NULL, NULL)) != LDAP_SUCCESS) { + if ((st=ldap_add_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) { st = set_ldap_error (context, st, OP_ADD); goto cleanup; } @@ -104,6 +106,8 @@ cleanup: if (rdns) ldap_value_free(rdns); + if (policy_dn != NULL) + free (policy_dn); ldap_mods_free(mods, 1); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return(st); @@ -118,6 +122,7 @@ krb5_ldap_put_password_policy (context, policy) krb5_context context; osa_policy_ent_t policy; { + char *policy_dn; krb5_error_code st=0; LDAP *ld=NULL; LDAPMod **mods=NULL; @@ -135,6 +140,10 @@ krb5_ldap_put_password_policy (context, policy) SETUP_CONTEXT(); GET_HANDLE(); + st = krb5_ldap_name_to_policydn (context, policy->name, &policy_dn); + if (st != 0) + goto cleanup; + 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, @@ -144,25 +153,30 @@ krb5_ldap_put_password_policy (context, policy) || ((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)) + (signed) policy->pw_history_num)) != 0)) goto cleanup; /* modify the password policy object. */ - if ((st=ldap_modify_ext_s(ld, policy->name, mods, NULL, NULL)) != LDAP_SUCCESS) { + /* + * This will fail if the 'policy_dn' is anywhere other than under the realm + * container. This is correct behaviour. 'kdb5_ldap_util' will support + * management of only such policy objects. + */ + if ((st=ldap_modify_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) { st = set_ldap_error (context, st, OP_MOD); goto cleanup; } cleanup: + if (policy_dn != NULL) + free (policy_dn); 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_ldap_get_password_policy_from_dn (context, name, policy, cnt) krb5_context context; char *name; osa_policy_ent_t *policy; @@ -205,7 +219,13 @@ krb5_ldap_get_password_policy (context, name, policy, cnt) 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)); + + /* Get the reference count */ + st = krb5_ldap_get_reference_count (context, + name, + "krbPwdPolicyReference", + &(*policy)->policy_refcnt, + ld); } cleanup: @@ -216,15 +236,53 @@ cleanup: *policy = NULL; } } + krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; } +/* + * Convert 'name' into a directory DN and call + * 'krb5_ldap_get_password_policy_from_dn' + */ +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; + char *policy_dn = NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + /* validate the input parameters */ + if(name == NULL) { + st = EINVAL; + goto cleanup; + } + + st = krb5_ldap_name_to_policydn (context, name, &policy_dn); + if (st != 0) + goto cleanup; + + st = krb5_ldap_get_password_policy_from_dn (context, policy_dn, policy, cnt); + free (policy_dn); + if (st == 0) + (*policy)->name = name; + +cleanup: + return st; +} + krb5_error_code krb5_ldap_delete_password_policy (context, policy) krb5_context context; char *policy; { + char *policy_dn = NULL; krb5_error_code st=0; LDAP *ld=NULL; kdb5_dal_handle *dal_handle=NULL; @@ -241,13 +299,20 @@ krb5_ldap_delete_password_policy (context, policy) SETUP_CONTEXT(); GET_HANDLE(); - if ((st=ldap_delete_ext_s(ld, policy, NULL, NULL)) != LDAP_SUCCESS) { + st = krb5_ldap_name_to_policydn (context, policy, &policy_dn); + if (st != 0) + goto cleanup; + + if ((st=ldap_delete_ext_s(ld, policy_dn, NULL, NULL)) != LDAP_SUCCESS) { st = set_ldap_error (context, st, OP_DEL); goto cleanup; } cleanup: krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); + if (policy_dn != NULL) + free (policy_dn); + return st; } @@ -259,14 +324,13 @@ krb5_ldap_iterate_password_policy(context, match_expr, func, func_arg) krb5_pointer func_arg; { osa_policy_ent_rec *entry=NULL; - char *attrs[] = { "cn", NULL }; + char *attrs[] = { "cn", NULL }, *policy=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); @@ -278,13 +342,23 @@ krb5_ldap_iterate_password_policy(context, match_expr, func, func_arg) 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); + if (ldap_context->lrparams->realmdn == NULL) { + st = EINVAL; + goto cleanup; + } + + LDAP_SEARCH(ldap_context->lrparams->realmdn, LDAP_SCOPE_ONELEVEL, "(objectclass=krbpwdpolicy)", attrs); + for(ent=ldap_first_entry(ld, result); ent != NULL; ent=ldap_next_entry(ld, ent)) { + krb5_boolean attr_present; + + st = krb5_ldap_get_string(ld, ent, "cn", &policy, &attr_present); + if (st != 0) + goto cleanup; + if (attr_present == FALSE) + continue; + entry->name = policy; + (*func)(func_arg, entry); + ldap_memfree(policy); } ldap_msgfree(result); diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c index 221b38c65..eac20a4c9 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c @@ -34,11 +34,11 @@ #include "ldap_err.h" #define END_OF_LIST -1 -char *realm_attributes[] = {"krbSearchScope","krbSubTree", +char *realm_attributes[] = {"krbSearchScope","krbSubTrees", "krbPrincContainerRef", "krbMaxTicketLife", "krbMaxRenewableAge", "krbTicketFlags", "krbDefaultEncType", "krbDefaultSaltType", "krbUpEnabled", - "krbPolicyReference", "krbSupportedEncTypes", + "krbTicketPolicyReference", "krbSupportedEncTypes", "krbSupportedSaltTypes", "krbLdapServers", "krbKdcServers", "krbAdmServers", "krbPwdServers", NULL}; @@ -51,12 +51,12 @@ char *policy_attributes[] = { "krbMaxTicketLife", -char *policyclass[] = { "krbPolicy", NULL }; +char *policyclass[] = { "krbTicketPolicy", NULL }; char *kdcclass[] = { "krbKdcService", NULL }; char *adminclass[] = { "krbAdmService", NULL }; char *pwdclass[] = { "krbPwdService", NULL }; -char *subtreeclass[] = { "Organization", "OrganizationalUnit", "Domain", - "Country", "Locality", NULL }; +char *subtreeclass[] = { "Organization", "OrganizationalUnit", "Domain", "krbContainer", + "krbRealmContainer", "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, @@ -99,8 +99,7 @@ ignore_duplicates(int_list) * 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) +char *ldap_filter_correct (unsigned char *in, unsigned int len) { int i, count; char *out, *ptr; @@ -263,7 +262,6 @@ cleanup: return st; } - /* * Delete the realm along with the principals belonging to the realm in the Directory. */ @@ -275,8 +273,8 @@ krb5_ldap_delete_realm (context, 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; + char **values=NULL, **subtrees=NULL, **policy=NULL; + LDAPMessage **result_arr=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; @@ -313,9 +311,15 @@ krb5_ldap_delete_realm (context, lrealm) /* 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) + if ((st=krb5_get_subtree_info(&lcontext, &subtrees, &ntree)) != 0) goto cleanup; + result_arr = (LDAPMessage **) calloc(ntree+1, sizeof(LDAPMessage *)); + if (result_arr == NULL) { + st = ENOMEM; + goto cleanup; + } + for (l=0; l < ntree; ++l) { LDAP_SEARCH(subtrees[l], rparam->search_scope, filter, attr); result_arr[l] = result; @@ -348,6 +352,28 @@ krb5_ldap_delete_realm (context, lrealm) ldap_msgfree(result); } + /* Delete all password policies */ + { + char *attr[] = {NULL}, filter[256]; + + void delete_password_policy (krb5_pointer ptr, osa_policy_ent_t pol) { + krb5_ldap_delete_password_policy (context, pol->name); + } + + krb5_ldap_iterate_password_policy (context, "*", delete_password_policy, NULL); + } + + /* Delete all ticket policies */ + { + if ((st = krb5_ldap_list_policy (context, ldap_context->lrparams->realmdn, &policy)) != 0) { + prepend_err_str (context, "Error reading ticket policy: ", st, st); + goto cleanup; + } + + for (i = 0; policy [i] != NULL; i++) + krb5_ldap_delete_policy(context, policy[i]); + } + /* Delete the realm object */ if ((st=ldap_delete_ext_s(ld, ldap_context->lrparams->realmdn, NULL, NULL)) != LDAP_SUCCESS) { int ost = st; @@ -357,10 +383,20 @@ krb5_ldap_delete_realm (context, lrealm) } cleanup: - for (l=0; l < ntree; ++l) { + if (subtrees) { + for (l=0; l < ntree; ++l) { if (subtrees[l]) free (subtrees[l]); + } + free (subtrees); + } + + if (policy != NULL) { + for (i = 0; policy[i] != NULL; i++) + free (policy[i]); + free (policy); } + krb5_ldap_free_realm_params(rparam); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; @@ -388,8 +424,8 @@ krb5_ldap_modify_realm(context, rparams, mask) int mask; { LDAP *ld=NULL; - krb5_error_code st=0; - char *strval[5]={NULL}; + krb5_error_code st=0, retval=0; + char **strval=NULL, *strvalprc[5]={NULL}; #ifdef HAVE_EDIRECTORY char **values=NULL; char **oldkdcservers=NULL, **oldadminservers=NULL, **oldpasswdservers=NULL; @@ -398,7 +434,7 @@ krb5_ldap_modify_realm(context, rparams, mask) char errbuf[1024]; #endif LDAPMod **mods = NULL; - int i=0, oldmask=0, objectmask=0; + int i=0, oldmask=0, objectmask=0,k=0,part_of_subtree=0; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; @@ -418,6 +454,7 @@ krb5_ldap_modify_realm(context, rparams, mask) rparams->tl_data == NULL || rparams->tl_data->tl_data_contents == NULL || ((mask & LDAP_REALM_SUBTREE) && rparams->subtree == NULL) || + ((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) || /* This has to be fixed ... */ ((mask & LDAP_REALM_DEFENCTYPE) && rparams->suppenctypes == NULL) || ((mask & LDAP_REALM_DEFSALTTYPE) && rparams->suppsalttypes == NULL) || @@ -467,16 +504,35 @@ krb5_ldap_modify_realm(context, rparams, mask) /* 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; + if ( rparams->subtree!=NULL) { + /*replace the subtrees with the present if the subtrees are present*/ + for(k=0;ksubtreecount && rparams->subtree[k]!=NULL;k++) { + if (strlen(rparams->subtree[k]) != 0) { + st = checkattributevalue(ld, rparams->subtree[k], "Objectclass", subtreeclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "subtree value: "); + } + } + strval = rparams->subtree; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_REPLACE, + strval)) != 0) { + goto cleanup; + } + } + } + + /* CONTAINERREF ATTRIBUTE */ + if (mask & LDAP_REALM_CONTREF) { + if (strlen(rparams->containerref) != 0 ) { + st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "container reference value: "); + strvalprc[0] = rparams->containerref; + strvalprc[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_REPLACE, + strvalprc)) != 0) + goto cleanup; + } } /* SEARCHSCOPE ATTRIBUTE */ @@ -728,9 +784,11 @@ krb5_ldap_modify_realm(context, rparams, mask) #endif /* Realm modify opearation */ - if ((st=ldap_modify_ext_s(ld, rparams->realmdn, mods, NULL, NULL)) != LDAP_SUCCESS) { - st = set_ldap_error (context, st, OP_MOD); - goto cleanup; + if (mods != NULL) { + if ((st=ldap_modify_ext_s(ld, rparams->realmdn, mods, NULL, NULL)) != LDAP_SUCCESS) { + st = set_ldap_error (context, st, OP_MOD); + goto cleanup; + } } #ifdef HAVE_EDIRECTORY @@ -932,7 +990,7 @@ krb5_ldap_create_krbcontainer(context, krbcontparams) 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 */ + /* check if the policy reference value exists and is of krbticketpolicyreference object class */ if (krbcontparams && krbcontparams->policyreference) { st = checkattributevalue(ld, krbcontparams->policyreference, "objectclass", policyclass, &pmask); @@ -940,7 +998,7 @@ krb5_ldap_create_krbcontainer(context, krbcontparams) strval[0] = krbcontparams->policyreference; strval[1] = NULL; - if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpolicyreference", LDAP_MOD_ADD, + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_ADD, strval)) != 0) goto cleanup; } @@ -1016,8 +1074,9 @@ krb5_ldap_create_realm(context, rparams, mask) krb5_error_code st=0; char *dn=NULL; char *strval[4]={NULL}; + char *contref[2]={NULL}; LDAPMod **mods = NULL; - int i=0, objectmask=0; + int i=0, objectmask=0, subtreecount=0,k=0, part_of_subtree=0; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; @@ -1034,6 +1093,7 @@ krb5_ldap_create_realm(context, rparams, mask) rparams == NULL || rparams->realm_name == NULL || ((mask & LDAP_REALM_SUBTREE) && rparams->subtree == NULL) || + ((mask & LDAP_REALM_CONTREF) && rparams->containerref == NULL) || ((mask & LDAP_REALM_POLICYREFERENCE) && rparams->policyreference == NULL) || ((mask & LDAP_REALM_SUPPSALTTYPE) && rparams->suppsalttypes == NULL) || ((mask & LDAP_REALM_SUPPENCTYPE) && rparams->suppenctypes == NULL) || @@ -1069,7 +1129,7 @@ krb5_ldap_create_realm(context, rparams, mask) strval[0] = "top"; strval[1] = "krbrealmcontainer"; - strval[2] = "krbpolicyaux"; + strval[2] = "krbticketpolicyaux"; strval[3] = NULL; if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) @@ -1077,17 +1137,34 @@ krb5_ldap_create_realm(context, rparams, mask) /* 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: "); - + if ( rparams->subtree!=NULL) { + subtreecount = rparams->subtreecount; + for (i=0; rparams->subtree[i]!=NULL && isubtree[i]) != 0) { + st = checkattributevalue(ld, rparams->subtree[i], "Objectclass", subtreeclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "realm object value: "); + } + } + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtrees", LDAP_MOD_ADD, + rparams->subtree)) != 0) { + goto cleanup; + } } - strval[0] = rparams->subtree; - strval[1] = NULL; - if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbsubtree", LDAP_MOD_ADD, - strval)) != 0) - goto cleanup; + } + + /* CONTAINER REFERENCE ATTRIBUTE */ + if (mask & LDAP_REALM_CONTREF) { + if (strlen(rparams->containerref) != 0 ) { + st = checkattributevalue(ld, rparams->containerref, "Objectclass", subtreeclass, + &objectmask); + CHECK_CLASS_VALIDITY(st, objectmask, "realm object value: "); + contref[0] = rparams->containerref; + contref[1] = NULL; + if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbPrincContainerRef", LDAP_MOD_ADD, + contref)) != 0) + goto cleanup; + } } /* SEARCHSCOPE ATTRIBUTE */ @@ -1124,110 +1201,6 @@ krb5_ldap_create_realm(context, rparams, mask) } - /* 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 */ @@ -1347,6 +1320,7 @@ krb5_ldap_read_realm_params(context, lrealm, rlparamp, mask) kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; + int valcount=0, x=0; SETUP_CONTEXT (); @@ -1402,6 +1376,15 @@ krb5_ldap_read_realm_params(context, lrealm, rlparamp, mask) LDAP_SEARCH(rlparams->realmdn, LDAP_SCOPE_BASE, "(objectclass=krbRealmContainer)", realm_attributes); + if ((st = ldap_count_entries(ld, result)) == 0) + { + /* This could happen when the DN used to bind and read the realm object + * does not have sufficient rights to read its attributes + */ + st = KRB5_KDB_ACCESS_ERROR; /* return some other error ? */ + goto cleanup; + } + ent = ldap_first_entry (ld, result); if (ent == NULL) { ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, (void *) &st); @@ -1413,17 +1396,35 @@ krb5_ldap_read_realm_params(context, lrealm, rlparamp, mask) /* Read the attributes */ { - - if ((values=ldap_get_values(ld, ent, "krbSubTree")) != NULL) { - rlparams->subtree = strdup(values[0]); - if (rlparams->subtree==NULL) { + if ((values=ldap_get_values(ld, ent, "krbSubTrees")) != NULL) { + rlparams->subtreecount = ldap_count_values(values); + rlparams->subtree = (char **) malloc(sizeof(char *) * (rlparams->subtreecount + 1)); + if (rlparams->subtree == NULL) { st = ENOMEM; goto cleanup; } + for (x=0; xsubtreecount; x++) { + rlparams->subtree[x] = strdup(values[x]); + if (rlparams->subtree[x] == NULL) { + st = ENOMEM; + goto cleanup; + } + } + rlparams->subtree[rlparams->subtreecount] = NULL; *mask |= LDAP_REALM_SUBTREE; ldap_value_free(values); } + if((values=ldap_get_values(ld, ent, "krbPrincContainerRef")) != NULL) { + rlparams->containerref = strdup(values[0]); + if(rlparams->containerref == NULL) { + st = ENOMEM; + goto cleanup; + } + *mask |= LDAP_REALM_CONTREF; + 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 */ @@ -1600,8 +1601,11 @@ krb5_ldap_free_realm_params(rparams) if (rparams->realm_name) krb5_xfree(rparams->realm_name); - if (rparams->subtree) + if (rparams->subtree) { + for (i=0; isubtreecount && rparams->subtree[i] ; i++) + krb5_xfree(rparams->subtree[i]); krb5_xfree(rparams->subtree); + } if (rparams->suppenctypes) krb5_xfree(rparams->suppenctypes); diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h index 9ffd3e86e..3879bf437 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h @@ -47,6 +47,7 @@ #define LDAP_REALM_MAXTICKETLIFE 0x1000 #define LDAP_REALM_MAXRENEWLIFE 0x2000 #define LDAP_REALM_KRBTICKETFLAGS 0x4000 +#define LDAP_REALM_CONTREF 0x8000 extern char *policy_attributes[]; @@ -57,10 +58,12 @@ extern char *realm_attributes[]; typedef struct _krb5_ldap_realm_params { char *realmdn; char *realm_name; - char *subtree; + char **subtree; + char *containerref; char *policyreference; int search_scope; int upenabled; + int subtreecount; krb5_int32 max_life; krb5_int32 max_renewable_life; krb5_int32 tktflags; diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c index 01045ce32..e4a28a5ac 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c @@ -40,7 +40,7 @@ static char *kdcrights_subtree[][2] = { {"1#subtree#","#[Entry Rights]"}, {"2#subtree#","#CN"}, {"6#subtree#","#ObjectClass"}, - {"2#subtree#","#krbPolicyReference"}, + {"2#subtree#","#krbTicketPolicyReference"}, {"2#subtree#","#krbUPEnabled"}, {"2#subtree#","#krbHostServer"}, {"2#subtree#","#krbServiceFlags"}, @@ -49,7 +49,7 @@ static char *kdcrights_subtree[][2] = { {"2#subtree#","#krbMaxTicketLife"}, {"2#subtree#","#krbMaxRenewableAge"}, {"2#subtree#","#krbPrincipalName"}, - {"6#subtree#","#krbSecretKey"}, + {"6#subtree#","#krbPrincipalKey"}, {"2#subtree#","#krbPrincipalExpiration"}, {"2#subtree#","#krbPwdPolicyReference"}, {"2#subtree#","#krbMaxPwdLife"}, @@ -76,7 +76,7 @@ static char *adminrights_subtree[][2]={ {"15#subtree#","#[Entry Rights]"}, {"6#subtree#","#CN"}, {"6#subtree#","#ObjectClass"}, - {"6#subtree#","#krbPolicyReference"}, + {"6#subtree#","#krbTicketPolicyReference"}, {"6#subtree#","#krbUPEnabled"}, {"2#subtree#","#krbHostServer"}, {"2#subtree#","#krbServiceFlags"}, @@ -85,7 +85,7 @@ static char *adminrights_subtree[][2]={ {"6#subtree#","#krbMaxTicketLife"}, {"6#subtree#","#krbMaxRenewableAge"}, {"6#subtree#","#krbPrincipalName"}, - {"6#subtree#","#krbSecretKey"}, + {"6#subtree#","#krbPrincipalKey"}, {"6#subtree#","#krbPrincipalExpiration"}, {"6#subtree#","#ModifiersName"}, {"6#subtree#","#PasswordExpirationTime"}, @@ -110,7 +110,6 @@ static char *adminrights_subtree[][2]={ {"6#subtree#","#krbMaxPwdLife"}, {"6#subtree#","#krbPwdMinDiffChars"}, {"6#subtree#","#krbPwdMinLength"}, - {"6#subtree#","#krbPwdPolicyRefCount"}, {"6#subtree#","#krbPwdPolicyReference"}, { "","" } }; @@ -119,7 +118,7 @@ static char *pwdrights_subtree[][2] = { {"1#subtree#","#[Entry Rights]"}, {"2#subtree#","#CN"}, {"2#subtree#","#ObjectClass"}, - {"2#subtree#","#krbPolicyReference"}, + {"2#subtree#","#krbTicketPolicyReference"}, {"2#subtree#","#krbUPEnabled"}, {"2#subtree#","#krbHostServer"}, {"2#subtree#","#krbServiceFlags"}, @@ -128,7 +127,7 @@ static char *pwdrights_subtree[][2] = { {"2#subtree#","#krbMaxTicketLife"}, {"2#subtree#","#krbMaxRenewableAge"}, {"2#subtree#","#krbPrincipalName"}, - {"6#subtree#","#krbSecretKey"}, + {"6#subtree#","#krbPrincipalKey"}, {"2#subtree#","#krbPrincipalExpiration"}, {"4#subtree#","#passwordManagement"}, {"6#subtree#","#ModifiersName"}, @@ -137,7 +136,6 @@ static char *pwdrights_subtree[][2] = { {"2#subtree#","#krbMaxPwdLife"}, {"2#subtree#","#krbPwdMinDiffChars"}, {"2#subtree#","#krbPwdMinLength"}, - {"2#subtree#","#krbPwdPolicyRefCount"}, {"2#subtree#","#krbPwdPolicyReference"}, { "", "" } }; @@ -146,10 +144,11 @@ static char *kdcrights_realmcontainer[][2]={ {"1#subtree#","#[Entry Rights]"}, {"2#subtree#","#CN"}, {"6#subtree#","#ObjectClass"}, - {"2#subtree#","#krbPolicyReference"}, - {"2#subtree#","#krbMasterKey"}, + {"2#subtree#","#krbTicketPolicyReference"}, + {"2#subtree#","#krbMKey"}, {"2#subtree#","#krbUPEnabled"}, - {"2#subtree#","#krbSubTree"}, + {"2#subtree#","#krbSubTrees"}, + {"2#subtree#","#krbPrincContainerRef"}, {"2#subtree#","#krbSearchScope"}, {"2#subtree#","#krbLdapServers"}, {"2#subtree#","#krbSupportedEncTypes"}, @@ -162,7 +161,7 @@ static char *kdcrights_realmcontainer[][2]={ {"2#subtree#","#krbMaxTicketLife"}, {"2#subtree#","#krbMaxRenewableAge"}, {"2#subtree#","#krbPrincipalName"}, - {"6#subtree#","#krbSecretKey"}, + {"6#subtree#","#krbPrincipalKey"}, {"2#subtree#","#krbPrincipalExpiration"}, {"2#subtree#","#krbPwdPolicyReference"}, {"2#subtree#","#krbMaxPwdLife"}, @@ -189,10 +188,11 @@ static char *adminrights_realmcontainer[][2]={ {"15#subtree#","#[Entry Rights]"}, {"6#subtree#","#CN"}, {"6#subtree#","#ObjectClass"}, - {"6#subtree#","#krbPolicyReference"}, - {"2#subtree#","#krbMasterKey"}, + {"6#subtree#","#krbTicketPolicyReference"}, + {"2#subtree#","#krbMKey"}, {"6#subtree#","#krbUPEnabled"}, - {"2#subtree#","#krbSubTree"}, + {"2#subtree#","#krbSubTrees"}, + {"2#subtree#","#krbPrincContainerRef"}, {"2#subtree#","#krbSearchScope"}, {"2#subtree#","#krbLdapServers"}, {"2#subtree#","#krbSupportedEncTypes"}, @@ -205,7 +205,7 @@ static char *adminrights_realmcontainer[][2]={ {"6#subtree#","#krbMaxTicketLife"}, {"6#subtree#","#krbMaxRenewableAge"}, {"6#subtree#","#krbPrincipalName"}, - {"6#subtree#","#krbSecretKey"}, + {"6#subtree#","#krbPrincipalKey"}, {"6#subtree#","#krbPrincipalExpiration"}, {"6#subtree#","#ModifiersName"}, {"6#subtree#","#PasswordExpirationTime"}, @@ -228,7 +228,6 @@ static char *adminrights_realmcontainer[][2]={ {"6#subtree#","#krbMaxPwdLife"}, {"6#subtree#","#krbPwdMinDiffChars"}, {"6#subtree#","#krbPwdMinLength"}, - {"6#subtree#","#krbPwdPolicyRefCount"}, {"6#subtree#","#krbPwdPolicyReference"}, { "","" } }; @@ -238,10 +237,11 @@ static char *pwdrights_realmcontainer[][2]={ {"1#subtree#","#[Entry Rights]"}, {"2#subtree#","#CN"}, {"2#subtree#","#ObjectClass"}, - {"2#subtree#","#krbPolicyReference"}, - {"2#subtree#","#krbMasterKey"}, + {"2#subtree#","#krbTicketPolicyReference"}, + {"2#subtree#","#krbMKey"}, {"2#subtree#","#krbUPEnabled"}, - {"2#subtree#","#krbSubTree"}, + {"2#subtree#","#krbSubTrees"}, + {"2#subtree#","#krbPrincContainerRef"}, {"2#subtree#","#krbSearchScope"}, {"2#subtree#","#krbLdapServers"}, {"2#subtree#","#krbSupportedEncTypes"}, @@ -254,7 +254,7 @@ static char *pwdrights_realmcontainer[][2]={ {"2#subtree#","#krbMaxTicketLife"}, {"2#subtree#","#krbMaxRenewableAge"}, {"2#subtree#","#krbPrincipalName"}, - {"6#subtree#","#krbSecretKey"}, + {"6#subtree#","#krbPrincipalKey"}, {"2#subtree#","#krbPrincipalExpiration"}, {"6#subtree#","#ModifiersName"}, {"2#subtree#","#krbPwdHistoryLength"}, @@ -262,7 +262,6 @@ static char *pwdrights_realmcontainer[][2]={ {"2#subtree#","#krbMaxPwdLife"}, {"2#subtree#","#krbPwdMinDiffChars"}, {"2#subtree#","#krbPwdMinLength"}, - {"2#subtree#","#krbPwdPolicyRefCount"}, {"2#subtree#","#krbPwdPolicyReference"}, { "", "" } }; @@ -275,7 +274,7 @@ static char *security_container[][2] = { static char *kerberos_container[][2] = { {"1#subtree#","#[Entry Rights]"}, - {"2#subtree#","#krbPolicyReference"}, + {"2#subtree#","#krbTicketPolicyReference"}, { "", "" } }; @@ -298,7 +297,7 @@ krb5_ldap_add_service_rights(context, servicetype, serviceobjdn, realmname, subt int servicetype; char *serviceobjdn; char *realmname; - char *subtreeparam; + char **subtreeparam; int mask; { @@ -307,10 +306,11 @@ krb5_ldap_add_service_rights(context, servicetype, serviceobjdn, realmname, subt 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; + 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; + int subtreecount=0; SETUP_CONTEXT(); GET_HANDLE(); @@ -321,15 +321,29 @@ krb5_ldap_add_service_rights(context, servicetype, serviceobjdn, realmname, subt goto cleanup; } - /* If the subtree is null, set the value to root */ - if (subtreeparam== NULL) - subtree=strdup(""); - else - subtree=strdup(subtreeparam); + subtreecount=ldap_context->lrparams->subtreecount; + subtree = (char **) malloc(sizeof(char *) * (subtreecount + 1)); + if(subtree == NULL) { + st = ENOMEM; + goto cleanup; + } - if (subtree == NULL) { - st = ENOMEM; - goto cleanup; + /* If the subtree is null, set the value to root */ + if(subtreeparam == NULL) { + subtree[0] = strdup(""); + if(subtree[0] == NULL) { + st = ENOMEM; + goto cleanup; + } + } + else { + for (i=0; subtree[i] != NULL && i 4) || (ldap_context->krbcontainer->DN == NULL)) { - st=-1; + st = -1; goto cleanup; } - /* If the subtree is null, set the value to root */ - if (subtreeparam== NULL) - subtree=strdup(""); - else - subtree=strdup(subtreeparam); + subtreecount = 1; + while(subtreeparam[subtreecount]) + subtreecount++; + subtree = (char **) malloc(sizeof(char *) * subtreecount + 1); + if(subtree == NULL) { + st = ENOMEM; + goto cleanup; + } - if (subtree == NULL) { - st = ENOMEM; - goto cleanup; + /* If the subtree is null, set the value to root */ + if(subtreeparam == NULL) { + subtree[0] = strdup(""); + if(subtree[0] == NULL) { + st = ENOMEM; + goto cleanup; + } + } + else { + for(i=0; subtreeparam[i]!=NULL && ipolrefcount +=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. */ @@ -106,36 +46,33 @@ krb5_ldap_create_policy(context, policy, mask) { krb5_error_code st=0; LDAP *ld=NULL; - char **rdns=NULL, *strval[3]={NULL}; + char *strval[3]={NULL}, *policy_dn = 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) { + if (policy == NULL || policy->policy == NULL) { st = EINVAL; - krb5_set_error_message (context, st, "Ticket Policy Object DN missing"); + krb5_set_error_message (context, st, "Ticket Policy Name missing"); goto cleanup; } SETUP_CONTEXT(); GET_HANDLE(); - rdns = ldap_explode_dn(policy->policydn, 1); - if (rdns == NULL) { - st = LDAP_INVALID_DN_SYNTAX; + if ((st = krb5_ldap_name_to_policydn (context, policy->policy, &policy_dn)) != 0) goto cleanup; - } memset(strval, 0, sizeof(strval)); - strval[0] = rdns[0]; + strval[0] = policy->policy; 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"; + strval[0] = "krbTicketPolicy"; + strval[1] = "krbTicketPolicyaux"; if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) goto cleanup; @@ -156,21 +93,16 @@ krb5_ldap_create_policy(context, policy, mask) 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_ext_s(ld, policy->policydn, mods, NULL, NULL)) != LDAP_SUCCESS) { + if ((st=ldap_add_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) { st = set_ldap_error (context, st, OP_ADD); goto cleanup; } cleanup: - if (rdns) - ldap_value_free(rdns); + if (policy_dn != NULL) + free(policy_dn); ldap_mods_free(mods, 1); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); @@ -191,29 +123,33 @@ krb5_ldap_modify_policy(context, policy, mask) int objectmask=0; krb5_error_code st=0; LDAP *ld=NULL; - char *attrvalues[]={"krbPolicy", "krbPolicyAux", NULL}, *strval[2]={NULL}; + char *attrvalues[]={"krbTicketPolicy", "krbTicketPolicyAux", NULL}, *strval[2]={NULL}; + char *policy_dn = 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) { + if (policy == NULL || policy->policy==NULL) { st = EINVAL; - krb5_set_error_message (context, st, "Ticket Policy Object DN missing"); + krb5_set_error_message (context, st, "Ticket Policy Name 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); + if ((st = krb5_ldap_name_to_policydn (context, policy->policy, &policy_dn)) != 0) + goto cleanup; + + /* the policydn object should be of the krbTicketPolicy object class */ + st = checkattributevalue(ld, policy_dn, "objectClass", attrvalues, &objectmask); CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); - if ((objectmask & 0x02) == 0) { /* add krbpolicyaux to the object class list */ + if ((objectmask & 0x02) == 0) { /* add krbticketpolicyaux to the object class list */ memset(strval, 0, sizeof(strval)); - strval[0] = "krbPolicyAux"; + strval[0] = "krbTicketPolicyAux"; if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) goto cleanup; } @@ -236,17 +172,15 @@ krb5_ldap_modify_policy(context, policy, mask) 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_ext_s(ld, policy->policydn, mods, NULL, NULL)) != LDAP_SUCCESS) { + if ((st=ldap_modify_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) { st = set_ldap_error (context, st, OP_MOD); goto cleanup; } cleanup: + if (policy_dn != NULL) + free(policy_dn); + ldap_mods_free(mods, 1); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; @@ -259,9 +193,9 @@ cleanup: */ krb5_error_code -krb5_ldap_read_policy(context, policydn, policy, omask) +krb5_ldap_read_policy(context, policyname, policy, omask) krb5_context context; - char *policydn; + char *policyname; krb5_ldap_policy_params **policy; int *omask; { @@ -269,15 +203,15 @@ krb5_ldap_read_policy(context, policydn, policy, omask) int objectmask=0; LDAP *ld=NULL; LDAPMessage *result=NULL,*ent=NULL; - char *attributes[] = { "krbMaxTicketLife", "krbMaxRenewableAge", "krbTicketFlags", "krbPolicyRefCount", NULL}; - char *attrvalues[] = { "krbPolicy", NULL}; + char *attributes[] = { "krbMaxTicketLife", "krbMaxRenewableAge", "krbTicketFlags", NULL}; + char *attrvalues[] = { "krbTicketPolicy", NULL}, *policy_dn = 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) { + if (policyname == NULL || policy == NULL) { st = EINVAL; krb5_set_error_message(context, st, "Ticket Policy Object information missing"); goto cleanup; @@ -286,8 +220,11 @@ krb5_ldap_read_policy(context, policydn, policy, omask) SETUP_CONTEXT(); GET_HANDLE(); - /* the policydn object should be of the krbPolicy object class */ - st = checkattributevalue(ld, policydn, "objectClass", attrvalues, &objectmask); + if ((st = krb5_ldap_name_to_policydn (context, policyname, &policy_dn)) != 0) + goto cleanup; + + /* the policydn object should be of the krbTicketPolicy object class */ + st = checkattributevalue(ld, policy_dn, "objectClass", attrvalues, &objectmask); CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); /* Initialize ticket policy structure */ @@ -295,15 +232,18 @@ krb5_ldap_read_policy(context, policydn, policy, omask) CHECK_NULL(lpolicy); memset(lpolicy, 0, sizeof(krb5_ldap_policy_params)); + if ((lpolicy->policy = strdup (policyname)) == NULL) { + st = ENOMEM; + goto cleanup; + } + 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); + LDAP_SEARCH(policy_dn, LDAP_SCOPE_BASE, "(objectclass=krbTicketPolicy)", attributes); *omask = 0; - lpolicy->policydn = strdup(policydn); - CHECK_NULL(lpolicy->policydn); ent=ldap_first_entry(ld, result); if (ent != NULL) { @@ -315,9 +255,6 @@ krb5_ldap_read_policy(context, policydn, policy, omask) 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); @@ -351,19 +288,19 @@ cleanup: */ krb5_error_code -krb5_ldap_delete_policy(context, policydn, policy, mask) +krb5_ldap_delete_policy(context, policyname) krb5_context context; - char *policydn; - krb5_ldap_policy_params *policy; - int mask; + char *policyname; { + int refcount = 0; + char *policy_dn = NULL; 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) { + if (policyname == NULL) { st = EINVAL; prepend_err_str (context,"Ticket Policy Object DN missing",st,st); goto cleanup; @@ -373,13 +310,18 @@ krb5_ldap_delete_policy(context, policydn, policy, mask) SETUP_CONTEXT(); GET_HANDLE(); + if ((st = krb5_ldap_name_to_policydn (context, policyname, &policy_dn)) != 0) + goto cleanup; /* Checking for policy count for 0 and will not permit delete if * it is greater than 0. */ - if (policy->polrefcount == 0) { + if ((st = krb5_ldap_get_reference_count (context, policy_dn, + "krbTicketPolicyReference", &refcount, ld)) != 0) + goto cleanup; - if ((st=ldap_delete_ext_s(ld, policydn, NULL, NULL)) != 0) { + if (refcount == 0) { + if ((st=ldap_delete_ext_s(ld, policy_dn, NULL, NULL)) != 0) { prepend_err_str (context,ldap_err2string(st),st,st); goto cleanup; @@ -391,6 +333,8 @@ krb5_ldap_delete_policy(context, policydn, policy, mask) } cleanup: + if (policy_dn != NULL) + free (policy_dn); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; } @@ -406,10 +350,39 @@ krb5_ldap_list_policy(context, containerdn, policy) char *containerdn; char ***policy; { + int i, j, count; + char **list = NULL; + char *policycontainerdn = containerdn; + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; krb5_error_code st=0; - st = krb5_ldap_list(context, policy, "krbPolicy", containerdn); + SETUP_CONTEXT(); + if (policycontainerdn == NULL) { + policycontainerdn = ldap_context->lrparams->realmdn; + } + + if ((st = krb5_ldap_list(context, &list, "krbTicketPolicy", policycontainerdn)) != 0) + goto cleanup; + + for (i = 0; list[i] != NULL; i++); + count = i; + + *policy = (char **) calloc ((unsigned) count + 1, sizeof(char *)); + if (*policy == NULL) { + st = ENOMEM; + goto cleanup; + } + + for (i = 0, j = 0; list[i] != NULL; i++, j++) { + int ret; + ret = krb5_ldap_policydn_to_name (context, list[i], &(*policy)[i]); + if (ret != 0) + j--; + } + +cleanup: return st; } @@ -430,8 +403,8 @@ krb5_ldap_free_policy(context, policy) if (policy == NULL) return st; - if (policy->policydn) - free (policy->policydn); + if (policy->policy) + free (policy->policy); if (policy->tl_data) { if (policy->tl_data->tl_data_contents) diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.h index a5d198777..9a1f2ea11 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.h +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.h @@ -40,12 +40,11 @@ /* policy object structure */ typedef struct _krb5_ldap_policy_params { - char *policydn; + char *policy; long mask; long maxtktlife; long maxrenewlife; long tktflags; - long polrefcount; krb5_tl_data *tl_data; }krb5_ldap_policy_params; @@ -59,7 +58,7 @@ 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_ldap_delete_policy(krb5_context, char *); krb5_error_code krb5_ldap_clear_policy(krb5_context, char *);