154925bf6Swillf 254925bf6Swillf /* 354925bf6Swillf * kadmin/ldap_util/kdb5_ldap_policy.c 454925bf6Swillf */ 554925bf6Swillf 6*dd9ccd46S /* 7*dd9ccd46S * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 8*dd9ccd46S * Use is subject to license terms. 9*dd9ccd46S */ 10*dd9ccd46S 1154925bf6Swillf /* Copyright (c) 2004-2005, Novell, Inc. 1254925bf6Swillf * All rights reserved. 1354925bf6Swillf * 1454925bf6Swillf * Redistribution and use in source and binary forms, with or without 1554925bf6Swillf * modification, are permitted provided that the following conditions are met: 1654925bf6Swillf * 1754925bf6Swillf * * Redistributions of source code must retain the above copyright notice, 1854925bf6Swillf * this list of conditions and the following disclaimer. 1954925bf6Swillf * * Redistributions in binary form must reproduce the above copyright 2054925bf6Swillf * notice, this list of conditions and the following disclaimer in the 2154925bf6Swillf * documentation and/or other materials provided with the distribution. 2254925bf6Swillf * * The copyright holder's name is not used to endorse or promote products 2354925bf6Swillf * derived from this software without specific prior written permission. 2454925bf6Swillf * 2554925bf6Swillf * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2654925bf6Swillf * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2754925bf6Swillf * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2854925bf6Swillf * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2954925bf6Swillf * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3054925bf6Swillf * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3154925bf6Swillf * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3254925bf6Swillf * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3354925bf6Swillf * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3454925bf6Swillf * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3554925bf6Swillf * POSSIBILITY OF SUCH DAMAGE. 3654925bf6Swillf */ 3754925bf6Swillf 3854925bf6Swillf /* 3954925bf6Swillf * Create / Delete / Modify / View / List policy objects. 4054925bf6Swillf */ 4154925bf6Swillf 4254925bf6Swillf #include <stdio.h> 4354925bf6Swillf #include <time.h> 4454925bf6Swillf #include <k5-int.h> 4554925bf6Swillf #include <kadm5/admin.h> 4654925bf6Swillf #include <libintl.h> 4754925bf6Swillf #include <locale.h> 4854925bf6Swillf #include "kdb5_ldap_util.h" 4954925bf6Swillf #include "kdb5_ldap_list.h" 5054925bf6Swillf #include "ldap_tkt_policy.h" 5154925bf6Swillf extern time_t get_date(char *); /* kadmin/cli/getdate.o */ 5254925bf6Swillf 5354925bf6Swillf static void print_policy_params(krb5_ldap_policy_params *policyparams, int mask); 5454925bf6Swillf static char *strdur(time_t duration); 5554925bf6Swillf 5654925bf6Swillf extern char *yes; 5754925bf6Swillf extern kadm5_config_params global_params; 58*dd9ccd46S 5954925bf6Swillf static krb5_error_code init_ldap_realm (int argc, char *argv[]) { 6054925bf6Swillf /* This operation is being performed in the context of a realm. So, 6154925bf6Swillf * initialize the realm */ 6254925bf6Swillf int mask = 0; 6354925bf6Swillf krb5_error_code retval = 0; 6454925bf6Swillf kdb5_dal_handle *dal_handle = NULL; 6554925bf6Swillf krb5_ldap_context *ldap_context=NULL; 6654925bf6Swillf 6754925bf6Swillf dal_handle = (kdb5_dal_handle *) util_context->db_context; 6854925bf6Swillf ldap_context = (krb5_ldap_context *) dal_handle->db_context; 6954925bf6Swillf if (!ldap_context) { 7054925bf6Swillf retval = EINVAL; 7154925bf6Swillf goto cleanup; 7254925bf6Swillf } 7354925bf6Swillf 7454925bf6Swillf if (ldap_context->krbcontainer == NULL) { 7554925bf6Swillf retval = krb5_ldap_read_krbcontainer_params (util_context, 7654925bf6Swillf &(ldap_context->krbcontainer)); 7754925bf6Swillf if (retval != 0) { 78*dd9ccd46S /* Solaris Kerberos */ 79*dd9ccd46S com_err(progname, retval, gettext("while reading kerberos container information")); 8054925bf6Swillf goto cleanup; 8154925bf6Swillf } 8254925bf6Swillf } 8354925bf6Swillf 8454925bf6Swillf if (ldap_context->lrparams == NULL) { 8554925bf6Swillf retval = krb5_ldap_read_realm_params(util_context, 8654925bf6Swillf global_params.realm, 8754925bf6Swillf &(ldap_context->lrparams), 8854925bf6Swillf &mask); 8954925bf6Swillf 9054925bf6Swillf if (retval != 0) { 9154925bf6Swillf goto cleanup; 9254925bf6Swillf } 9354925bf6Swillf } 9454925bf6Swillf cleanup: 9554925bf6Swillf return retval; 9654925bf6Swillf } 9754925bf6Swillf 9854925bf6Swillf /* 9954925bf6Swillf * This function will create a ticket policy object with the 10054925bf6Swillf * specified attributes. 10154925bf6Swillf */ 10254925bf6Swillf void 10354925bf6Swillf kdb5_ldap_create_policy(argc, argv) 10454925bf6Swillf int argc; 10554925bf6Swillf char *argv[]; 10654925bf6Swillf { 107*dd9ccd46S /* Solaris Kerberos */ 108*dd9ccd46S char *me = progname; 109*dd9ccd46S 11054925bf6Swillf krb5_error_code retval = 0; 11154925bf6Swillf krb5_ldap_policy_params *policyparams = NULL; 11254925bf6Swillf krb5_boolean print_usage = FALSE; 11354925bf6Swillf krb5_boolean no_msg = FALSE; 11454925bf6Swillf int mask = 0; 11554925bf6Swillf time_t date = 0; 11654925bf6Swillf time_t now = 0; 11754925bf6Swillf int i = 0; 11854925bf6Swillf 11954925bf6Swillf /* Check for number of arguments */ 12054925bf6Swillf if ((argc < 2) || (argc > 16)) { 12154925bf6Swillf goto err_usage; 12254925bf6Swillf } 12354925bf6Swillf 12454925bf6Swillf /* Allocate memory for policy parameters structure */ 12554925bf6Swillf policyparams = (krb5_ldap_policy_params*) calloc(1, sizeof(krb5_ldap_policy_params)); 12654925bf6Swillf if (policyparams == NULL) { 12754925bf6Swillf retval = ENOMEM; 12854925bf6Swillf goto cleanup; 12954925bf6Swillf } 13054925bf6Swillf 13154925bf6Swillf /* Get current time */ 13254925bf6Swillf time (&now); 13354925bf6Swillf 13454925bf6Swillf /* Parse all arguments */ 13554925bf6Swillf for (i = 1; i < argc; i++) { 13654925bf6Swillf if (!strcmp(argv[i], "-maxtktlife")) { 13754925bf6Swillf if (++i > argc - 1) 13854925bf6Swillf goto err_usage; 13954925bf6Swillf 14054925bf6Swillf date = get_date(argv[i]); 14154925bf6Swillf if (date == (time_t)(-1)) { 14254925bf6Swillf retval = EINVAL; 14354925bf6Swillf com_err (me, retval, gettext("while providing time specification")); 14454925bf6Swillf goto err_nomsg; 14554925bf6Swillf } 14654925bf6Swillf 14754925bf6Swillf policyparams->maxtktlife = date - now; 14854925bf6Swillf 14954925bf6Swillf mask |= LDAP_POLICY_MAXTKTLIFE; 15054925bf6Swillf } else if (!strcmp(argv[i], "-maxrenewlife")) { 15154925bf6Swillf if (++i > argc - 1) 15254925bf6Swillf goto err_usage; 15354925bf6Swillf 15454925bf6Swillf date = get_date(argv[i]); 15554925bf6Swillf if (date == (time_t)(-1)) { 15654925bf6Swillf retval = EINVAL; 15754925bf6Swillf com_err (me, retval, gettext("while providing time specification")); 15854925bf6Swillf goto err_nomsg; 15954925bf6Swillf } 16054925bf6Swillf 16154925bf6Swillf policyparams->maxrenewlife = date - now; 16254925bf6Swillf 16354925bf6Swillf mask |= LDAP_POLICY_MAXRENEWLIFE; 16454925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_postdated")) { 16554925bf6Swillf if (*(argv[i]) == '+') 16654925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_POSTDATED); 16754925bf6Swillf else if (*(argv[i]) == '-') 16854925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_POSTDATED; 16954925bf6Swillf else 17054925bf6Swillf goto err_usage; 17154925bf6Swillf 17254925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 17354925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_forwardable")) { 17454925bf6Swillf if (*(argv[i]) == '+') 17554925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_FORWARDABLE); 17654925bf6Swillf else if (*(argv[i]) == '-') 17754925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_FORWARDABLE; 17854925bf6Swillf else 17954925bf6Swillf goto err_usage; 18054925bf6Swillf 18154925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 18254925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_renewable")) { 18354925bf6Swillf if (*(argv[i]) == '+') 18454925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_RENEWABLE); 18554925bf6Swillf else if (*(argv[i]) == '-') 18654925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_RENEWABLE; 18754925bf6Swillf else 18854925bf6Swillf goto err_usage; 18954925bf6Swillf 19054925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 19154925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_proxiable")) { 19254925bf6Swillf if (*(argv[i]) == '+') 19354925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_PROXIABLE); 19454925bf6Swillf else if (*(argv[i]) == '-') 19554925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_PROXIABLE; 19654925bf6Swillf else 19754925bf6Swillf goto err_usage; 19854925bf6Swillf 19954925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 20054925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_dup_skey")) { 20154925bf6Swillf if (*(argv[i]) == '+') 20254925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_DUP_SKEY); 20354925bf6Swillf else if (*(argv[i]) == '-') 20454925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_DUP_SKEY; 20554925bf6Swillf else 20654925bf6Swillf goto err_usage; 20754925bf6Swillf 20854925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 20954925bf6Swillf } else if (!strcmp((argv[i] + 1), "requires_preauth")) { 21054925bf6Swillf if (*(argv[i]) == '+') 21154925bf6Swillf policyparams->tktflags |= KRB5_KDB_REQUIRES_PRE_AUTH; 21254925bf6Swillf else if (*(argv[i]) == '-') 21354925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PRE_AUTH); 21454925bf6Swillf else 21554925bf6Swillf goto err_usage; 21654925bf6Swillf 21754925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 21854925bf6Swillf } else if (!strcmp((argv[i] + 1), "requires_hwauth")) { 21954925bf6Swillf if (*(argv[i]) == '+') 22054925bf6Swillf policyparams->tktflags |= KRB5_KDB_REQUIRES_HW_AUTH; 22154925bf6Swillf else if (*(argv[i]) == '-') 22254925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_HW_AUTH); 22354925bf6Swillf else 22454925bf6Swillf goto err_usage; 22554925bf6Swillf 22654925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 22754925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_svr")) { 22854925bf6Swillf if (*(argv[i]) == '+') 22954925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_SVR); 23054925bf6Swillf else if (*(argv[i]) == '-') 23154925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_SVR; 23254925bf6Swillf else 23354925bf6Swillf goto err_usage; 23454925bf6Swillf 23554925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 23654925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_tgs_req")) { 23754925bf6Swillf if (*(argv[i]) == '+') 23854925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_TGT_BASED); 23954925bf6Swillf else if (*(argv[i]) == '-') 24054925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_TGT_BASED; 24154925bf6Swillf else 24254925bf6Swillf goto err_usage; 24354925bf6Swillf 24454925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 24554925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_tix")) { 24654925bf6Swillf if (*(argv[i]) == '+') 24754925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_ALL_TIX); 24854925bf6Swillf else if (*(argv[i]) == '-') 24954925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_ALL_TIX; 25054925bf6Swillf else 25154925bf6Swillf goto err_usage; 25254925bf6Swillf 25354925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 25454925bf6Swillf } else if (!strcmp((argv[i] + 1), "needchange")) { 25554925bf6Swillf if (*(argv[i]) == '+') 25654925bf6Swillf policyparams->tktflags |= KRB5_KDB_REQUIRES_PWCHANGE; 25754925bf6Swillf else if (*(argv[i]) == '-') 25854925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PWCHANGE); 25954925bf6Swillf else 26054925bf6Swillf goto err_usage; 26154925bf6Swillf 26254925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 26354925bf6Swillf } else if (!strcmp((argv[i] + 1), "password_changing_service")) { 26454925bf6Swillf if (*(argv[i]) == '+') 26554925bf6Swillf policyparams->tktflags |= KRB5_KDB_PWCHANGE_SERVICE; 26654925bf6Swillf else if (*(argv[i]) == '-') 26754925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_PWCHANGE_SERVICE); 26854925bf6Swillf else 26954925bf6Swillf goto err_usage; 27054925bf6Swillf 27154925bf6Swillf mask |= LDAP_POLICY_TKTFLAGS; 27254925bf6Swillf } else { /* Any other argument must be policy DN */ 27354925bf6Swillf /* First check if policy DN is already provided -- 27454925bf6Swillf if so, there's a usage error */ 27554925bf6Swillf if (policyparams->policy != NULL) 27654925bf6Swillf goto err_usage; 27754925bf6Swillf 27854925bf6Swillf /* If not present already, fill up policy DN */ 27954925bf6Swillf policyparams->policy = strdup(argv[i]); 28054925bf6Swillf if (policyparams->policy == NULL) { 28154925bf6Swillf retval = ENOMEM; 28254925bf6Swillf com_err(me, retval, gettext("while creating policy object")); 28354925bf6Swillf goto err_nomsg; 28454925bf6Swillf } 28554925bf6Swillf } 28654925bf6Swillf } 28754925bf6Swillf 28854925bf6Swillf /* policy DN is a mandatory argument. If not provided, print usage */ 28954925bf6Swillf if (policyparams->policy == NULL) 29054925bf6Swillf goto err_usage; 29154925bf6Swillf 29254925bf6Swillf if ((retval = init_ldap_realm (argc, argv))) { 29354925bf6Swillf com_err(me, retval, gettext("while reading realm information")); 29454925bf6Swillf goto err_nomsg; 29554925bf6Swillf } 29654925bf6Swillf 29754925bf6Swillf /* Create object with all attributes provided */ 29854925bf6Swillf if ((retval = krb5_ldap_create_policy(util_context, policyparams, mask)) != 0) 29954925bf6Swillf goto cleanup; 30054925bf6Swillf 30154925bf6Swillf goto cleanup; 30254925bf6Swillf 30354925bf6Swillf err_usage: 30454925bf6Swillf print_usage = TRUE; 30554925bf6Swillf 30654925bf6Swillf err_nomsg: 30754925bf6Swillf no_msg = TRUE; 30854925bf6Swillf 30954925bf6Swillf cleanup: 31054925bf6Swillf /* Clean-up structure */ 31154925bf6Swillf krb5_ldap_free_policy (util_context, policyparams); 31254925bf6Swillf 31354925bf6Swillf if (print_usage) 31454925bf6Swillf db_usage(CREATE_POLICY); 31554925bf6Swillf 31654925bf6Swillf if (retval) { 31754925bf6Swillf if (!no_msg) 31854925bf6Swillf com_err(me, retval, gettext("while creating policy object")); 31954925bf6Swillf 32054925bf6Swillf exit_status++; 32154925bf6Swillf } 32254925bf6Swillf 32354925bf6Swillf return; 32454925bf6Swillf } 32554925bf6Swillf 32654925bf6Swillf 32754925bf6Swillf /* 32854925bf6Swillf * This function will destroy the specified ticket policy 32954925bf6Swillf * object interactively, unless forced through an option. 33054925bf6Swillf */ 33154925bf6Swillf void 33254925bf6Swillf kdb5_ldap_destroy_policy(argc, argv) 33354925bf6Swillf int argc; 33454925bf6Swillf char *argv[]; 33554925bf6Swillf { 336*dd9ccd46S /* Solaris Kerberos */ 337*dd9ccd46S char *me = progname; 338*dd9ccd46S 33954925bf6Swillf krb5_error_code retval = 0; 34054925bf6Swillf krb5_ldap_policy_params *policyparams = NULL; 34154925bf6Swillf krb5_boolean print_usage = FALSE; 34254925bf6Swillf krb5_boolean no_msg = FALSE; 34354925bf6Swillf char *policy = NULL; 34454925bf6Swillf unsigned int mask = 0; 34554925bf6Swillf int force = 0; 34654925bf6Swillf char buf[5] = {0}; 34754925bf6Swillf int i = 0; 34854925bf6Swillf 34954925bf6Swillf if ((argc < 2) || (argc > 3)) { 35054925bf6Swillf goto err_usage; 35154925bf6Swillf } 35254925bf6Swillf 35354925bf6Swillf for (i = 1; i < argc; i++) { 35454925bf6Swillf if (strcmp(argv[i], "-force") == 0) { 35554925bf6Swillf force++; 35654925bf6Swillf } else { /* Any other argument must be policy DN */ 35754925bf6Swillf /* First check if policy DN is already provided -- 35854925bf6Swillf if so, there's a usage error */ 35954925bf6Swillf if (policy != NULL) 36054925bf6Swillf goto err_usage; 36154925bf6Swillf 36254925bf6Swillf /* If not present already, fill up policy DN */ 36354925bf6Swillf policy = strdup(argv[i]); 36454925bf6Swillf if (policy == NULL) { 36554925bf6Swillf retval = ENOMEM; 36654925bf6Swillf com_err(me, retval, gettext("while destroying policy object")); 36754925bf6Swillf goto err_nomsg; 36854925bf6Swillf } 36954925bf6Swillf } 37054925bf6Swillf } 37154925bf6Swillf 37254925bf6Swillf if (policy == NULL) 37354925bf6Swillf goto err_usage; 37454925bf6Swillf 37554925bf6Swillf if (!force) { 37654925bf6Swillf printf(gettext("This will delete the policy object '%s', are you sure?\n"), policy); 37754925bf6Swillf printf(gettext("(type 'yes' to confirm)? ")); 37854925bf6Swillf 37954925bf6Swillf if (fgets(buf, sizeof(buf), stdin) == NULL) { 38054925bf6Swillf retval = EINVAL; 38154925bf6Swillf goto cleanup; 38254925bf6Swillf } 38354925bf6Swillf 38454925bf6Swillf if (strcmp(buf, yes)) { 38554925bf6Swillf exit_status++; 38654925bf6Swillf goto cleanup; 38754925bf6Swillf } 38854925bf6Swillf } 38954925bf6Swillf 39054925bf6Swillf if ((retval = init_ldap_realm (argc, argv))) 39154925bf6Swillf goto err_nomsg; 39254925bf6Swillf 39354925bf6Swillf if ((retval = krb5_ldap_read_policy(util_context, policy, &policyparams, &mask))) 39454925bf6Swillf goto cleanup; 39554925bf6Swillf 39654925bf6Swillf 39754925bf6Swillf if ((retval = krb5_ldap_delete_policy(util_context, policy))) 39854925bf6Swillf goto cleanup; 39954925bf6Swillf 40054925bf6Swillf printf(gettext("** policy object '%s' deleted.\n"), policy); 40154925bf6Swillf goto cleanup; 40254925bf6Swillf 40354925bf6Swillf 40454925bf6Swillf err_usage: 40554925bf6Swillf print_usage = TRUE; 40654925bf6Swillf 40754925bf6Swillf err_nomsg: 40854925bf6Swillf no_msg = TRUE; 40954925bf6Swillf 41054925bf6Swillf cleanup: 41154925bf6Swillf /* Clean-up structure */ 41254925bf6Swillf krb5_ldap_free_policy (util_context, policyparams); 41354925bf6Swillf 41454925bf6Swillf if (policy) { 41554925bf6Swillf free (policy); 41654925bf6Swillf } 41754925bf6Swillf 41854925bf6Swillf if (print_usage) { 41954925bf6Swillf db_usage(DESTROY_POLICY); 42054925bf6Swillf } 42154925bf6Swillf 42254925bf6Swillf if (retval) { 42354925bf6Swillf if (!no_msg) 42454925bf6Swillf com_err(me, retval, gettext("while destroying policy object")); 42554925bf6Swillf 42654925bf6Swillf exit_status++; 42754925bf6Swillf } 42854925bf6Swillf 42954925bf6Swillf return; 43054925bf6Swillf } 43154925bf6Swillf 43254925bf6Swillf 43354925bf6Swillf /* 43454925bf6Swillf * This function will modify the attributes of a given ticket 43554925bf6Swillf * policy object. 43654925bf6Swillf */ 43754925bf6Swillf void 43854925bf6Swillf kdb5_ldap_modify_policy(argc, argv) 43954925bf6Swillf int argc; 44054925bf6Swillf char *argv[]; 44154925bf6Swillf { 442*dd9ccd46S /* Solaris Kerberos */ 443*dd9ccd46S char *me = progname; 444*dd9ccd46S 44554925bf6Swillf krb5_error_code retval = 0; 44654925bf6Swillf krb5_ldap_policy_params *policyparams = NULL; 44754925bf6Swillf krb5_boolean print_usage = FALSE; 44854925bf6Swillf krb5_boolean no_msg = FALSE; 44954925bf6Swillf char *policy = NULL; 45054925bf6Swillf unsigned int in_mask = 0, out_mask = 0; 45154925bf6Swillf time_t date = 0; 45254925bf6Swillf time_t now = 0; 45354925bf6Swillf int i = 0; 45454925bf6Swillf 45554925bf6Swillf /* Check for number of arguments -- minimum is 3 45654925bf6Swillf since atleast one parameter should be given in 45754925bf6Swillf addition to 'modify_policy' and policy DN */ 45854925bf6Swillf if ((argc < 3) || (argc > 16)) { 45954925bf6Swillf goto err_usage; 46054925bf6Swillf } 46154925bf6Swillf 46254925bf6Swillf /* Parse all arguments, only to pick up policy DN (Pass 1) */ 46354925bf6Swillf for (i = 1; i < argc; i++) { 46454925bf6Swillf /* Skip arguments next to 'maxtktlife' 46554925bf6Swillf and 'maxrenewlife' arguments */ 46654925bf6Swillf if (!strcmp(argv[i], "-maxtktlife")) { 46754925bf6Swillf ++i; 46854925bf6Swillf } else if (!strcmp(argv[i], "-maxrenewlife")) { 46954925bf6Swillf ++i; 47054925bf6Swillf } 47154925bf6Swillf /* Do nothing for ticket flag arguments */ 47254925bf6Swillf else if (!strcmp((argv[i] + 1), "allow_postdated") || 47354925bf6Swillf !strcmp((argv[i] + 1), "allow_forwardable") || 47454925bf6Swillf !strcmp((argv[i] + 1), "allow_renewable") || 47554925bf6Swillf !strcmp((argv[i] + 1), "allow_proxiable") || 47654925bf6Swillf !strcmp((argv[i] + 1), "allow_dup_skey") || 47754925bf6Swillf !strcmp((argv[i] + 1), "requires_preauth") || 47854925bf6Swillf !strcmp((argv[i] + 1), "requires_hwauth") || 47954925bf6Swillf !strcmp((argv[i] + 1), "allow_svr") || 48054925bf6Swillf !strcmp((argv[i] + 1), "allow_tgs_req") || 48154925bf6Swillf !strcmp((argv[i] + 1), "allow_tix") || 48254925bf6Swillf !strcmp((argv[i] + 1), "needchange") || 48354925bf6Swillf !strcmp((argv[i] + 1), "password_changing_service")) { 48454925bf6Swillf } else { /* Any other argument must be policy DN */ 48554925bf6Swillf /* First check if policy DN is already provided -- 48654925bf6Swillf if so, there's a usage error */ 48754925bf6Swillf if (policy != NULL) 48854925bf6Swillf goto err_usage; 48954925bf6Swillf 49054925bf6Swillf /* If not present already, fill up policy DN */ 49154925bf6Swillf policy = strdup(argv[i]); 49254925bf6Swillf if (policy == NULL) { 49354925bf6Swillf retval = ENOMEM; 49454925bf6Swillf com_err(me, retval, gettext("while modifying policy object")); 49554925bf6Swillf goto err_nomsg; 49654925bf6Swillf } 49754925bf6Swillf } 49854925bf6Swillf } 49954925bf6Swillf 50054925bf6Swillf if (policy == NULL) 50154925bf6Swillf goto err_usage; 50254925bf6Swillf 50354925bf6Swillf if ((retval = init_ldap_realm (argc, argv))) 50454925bf6Swillf goto cleanup; 50554925bf6Swillf 50654925bf6Swillf retval = krb5_ldap_read_policy(util_context, policy, &policyparams, &in_mask); 50754925bf6Swillf if (retval) { 50854925bf6Swillf com_err(me, retval, gettext("while reading information of policy '%s'"), policy); 50954925bf6Swillf goto err_nomsg; 51054925bf6Swillf } 51154925bf6Swillf 51254925bf6Swillf /* Get current time */ 51354925bf6Swillf time (&now); 51454925bf6Swillf 51554925bf6Swillf /* Parse all arguments, but skip policy DN (Pass 2) */ 51654925bf6Swillf for (i = 1; i < argc; i++) { 51754925bf6Swillf if (!strcmp(argv[i], "-maxtktlife")) { 51854925bf6Swillf if (++i > argc - 1) 51954925bf6Swillf goto err_usage; 52054925bf6Swillf 52154925bf6Swillf date = get_date(argv[i]); 52254925bf6Swillf if (date == (time_t)(-1)) { 52354925bf6Swillf retval = EINVAL; 52454925bf6Swillf com_err (me, retval, gettext("while providing time specification")); 52554925bf6Swillf goto err_nomsg; 52654925bf6Swillf } 52754925bf6Swillf 52854925bf6Swillf policyparams->maxtktlife = date - now; 52954925bf6Swillf 53054925bf6Swillf out_mask |= LDAP_POLICY_MAXTKTLIFE; 53154925bf6Swillf } else if (!strcmp(argv[i], "-maxrenewlife")) { 53254925bf6Swillf if (++i > argc - 1) 53354925bf6Swillf goto err_usage; 53454925bf6Swillf 53554925bf6Swillf date = get_date(argv[i]); 53654925bf6Swillf if (date == (time_t)(-1)) { 53754925bf6Swillf retval = EINVAL; 53854925bf6Swillf com_err (me, retval, gettext("while providing time specification")); 53954925bf6Swillf goto err_nomsg; 54054925bf6Swillf } 54154925bf6Swillf 54254925bf6Swillf policyparams->maxrenewlife = date - now; 54354925bf6Swillf 54454925bf6Swillf out_mask |= LDAP_POLICY_MAXRENEWLIFE; 54554925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_postdated")) { 54654925bf6Swillf if (*(argv[i]) == '+') 54754925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_POSTDATED); 54854925bf6Swillf else if (*(argv[i]) == '-') 54954925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_POSTDATED; 55054925bf6Swillf else 55154925bf6Swillf goto err_usage; 55254925bf6Swillf 55354925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 55454925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_forwardable")) { 55554925bf6Swillf if (*(argv[i]) == '+') 55654925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_FORWARDABLE); 55754925bf6Swillf else if (*(argv[i]) == '-') 55854925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_FORWARDABLE; 55954925bf6Swillf else 56054925bf6Swillf goto err_usage; 56154925bf6Swillf 56254925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 56354925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_renewable")) { 56454925bf6Swillf if (*(argv[i]) == '+') 56554925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_RENEWABLE); 56654925bf6Swillf else if (*(argv[i]) == '-') 56754925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_RENEWABLE; 56854925bf6Swillf else 56954925bf6Swillf goto err_usage; 57054925bf6Swillf 57154925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 57254925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_proxiable")) { 57354925bf6Swillf if (*(argv[i]) == '+') 57454925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_PROXIABLE); 57554925bf6Swillf else if (*(argv[i]) == '-') 57654925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_PROXIABLE; 57754925bf6Swillf else 57854925bf6Swillf goto err_usage; 57954925bf6Swillf 58054925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 58154925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_dup_skey")) { 58254925bf6Swillf if (*(argv[i]) == '+') 58354925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_DUP_SKEY); 58454925bf6Swillf else if (*(argv[i]) == '-') 58554925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_DUP_SKEY; 58654925bf6Swillf else 58754925bf6Swillf goto err_usage; 58854925bf6Swillf 58954925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 59054925bf6Swillf } else if (!strcmp((argv[i] + 1), "requires_preauth")) { 59154925bf6Swillf if (*(argv[i]) == '+') 59254925bf6Swillf policyparams->tktflags |= KRB5_KDB_REQUIRES_PRE_AUTH; 59354925bf6Swillf else if (*(argv[i]) == '-') 59454925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PRE_AUTH); 59554925bf6Swillf else 59654925bf6Swillf goto err_usage; 59754925bf6Swillf 59854925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 59954925bf6Swillf } else if (!strcmp((argv[i] + 1), "requires_hwauth")) { 60054925bf6Swillf if (*(argv[i]) == '+') 60154925bf6Swillf policyparams->tktflags |= KRB5_KDB_REQUIRES_HW_AUTH; 60254925bf6Swillf else if (*(argv[i]) == '-') 60354925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_HW_AUTH); 60454925bf6Swillf else 60554925bf6Swillf goto err_usage; 60654925bf6Swillf 60754925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 60854925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_svr")) { 60954925bf6Swillf if (*(argv[i]) == '+') 61054925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_SVR); 61154925bf6Swillf else if (*(argv[i]) == '-') 61254925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_SVR; 61354925bf6Swillf else 61454925bf6Swillf goto err_usage; 61554925bf6Swillf 61654925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 61754925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_tgs_req")) { 61854925bf6Swillf if (*(argv[i]) == '+') 61954925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_TGT_BASED); 62054925bf6Swillf else if (*(argv[i]) == '-') 62154925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_TGT_BASED; 62254925bf6Swillf else 62354925bf6Swillf goto err_usage; 62454925bf6Swillf 62554925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 62654925bf6Swillf } else if (!strcmp((argv[i] + 1), "allow_tix")) { 62754925bf6Swillf if (*(argv[i]) == '+') 62854925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_ALL_TIX); 62954925bf6Swillf else if (*(argv[i]) == '-') 63054925bf6Swillf policyparams->tktflags |= KRB5_KDB_DISALLOW_ALL_TIX; 63154925bf6Swillf else 63254925bf6Swillf goto err_usage; 63354925bf6Swillf 63454925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 63554925bf6Swillf } else if (!strcmp((argv[i] + 1), "needchange")) { 63654925bf6Swillf if (*(argv[i]) == '+') 63754925bf6Swillf policyparams->tktflags |= KRB5_KDB_REQUIRES_PWCHANGE; 63854925bf6Swillf else if (*(argv[i]) == '-') 63954925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PWCHANGE); 64054925bf6Swillf else 64154925bf6Swillf goto err_usage; 64254925bf6Swillf 64354925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 64454925bf6Swillf } else if (!strcmp((argv[i] + 1), "password_changing_service")) { 64554925bf6Swillf if (*(argv[i]) == '+') 64654925bf6Swillf policyparams->tktflags |= KRB5_KDB_PWCHANGE_SERVICE; 64754925bf6Swillf else if (*(argv[i]) == '-') 64854925bf6Swillf policyparams->tktflags &= (int)(~KRB5_KDB_PWCHANGE_SERVICE); 64954925bf6Swillf else 65054925bf6Swillf goto err_usage; 65154925bf6Swillf 65254925bf6Swillf out_mask |= LDAP_POLICY_TKTFLAGS; 65354925bf6Swillf } else { 65454925bf6Swillf /* Any other argument must be policy DN 65554925bf6Swillf -- skip it */ 65654925bf6Swillf } 65754925bf6Swillf } 65854925bf6Swillf 65954925bf6Swillf /* Modify attributes of object */ 66054925bf6Swillf if ((retval = krb5_ldap_modify_policy(util_context, policyparams, out_mask))) 66154925bf6Swillf goto cleanup; 66254925bf6Swillf 66354925bf6Swillf goto cleanup; 66454925bf6Swillf 66554925bf6Swillf err_usage: 66654925bf6Swillf print_usage = TRUE; 66754925bf6Swillf 66854925bf6Swillf err_nomsg: 66954925bf6Swillf no_msg = TRUE; 67054925bf6Swillf 67154925bf6Swillf cleanup: 67254925bf6Swillf /* Clean-up structure */ 67354925bf6Swillf krb5_ldap_free_policy (util_context, policyparams); 67454925bf6Swillf 67554925bf6Swillf if (policy) 67654925bf6Swillf free (policy); 67754925bf6Swillf 67854925bf6Swillf if (print_usage) 67954925bf6Swillf db_usage(MODIFY_POLICY); 68054925bf6Swillf 68154925bf6Swillf if (retval) { 68254925bf6Swillf if (!no_msg) 68354925bf6Swillf com_err(me, retval, gettext("while modifying policy object")); 68454925bf6Swillf 68554925bf6Swillf exit_status++; 68654925bf6Swillf } 68754925bf6Swillf 68854925bf6Swillf return; 68954925bf6Swillf } 69054925bf6Swillf 69154925bf6Swillf 69254925bf6Swillf /* 69354925bf6Swillf * This function will display information about the given policy object, 69454925bf6Swillf * fetching the information from the LDAP Server. 69554925bf6Swillf */ 69654925bf6Swillf void 69754925bf6Swillf kdb5_ldap_view_policy(argc, argv) 69854925bf6Swillf int argc; 69954925bf6Swillf char *argv[]; 70054925bf6Swillf { 701*dd9ccd46S /* Solaris Kerberos */ 702*dd9ccd46S char *me = progname; 703*dd9ccd46S 70454925bf6Swillf krb5_ldap_policy_params *policyparams = NULL; 70554925bf6Swillf krb5_error_code retval = 0; 70654925bf6Swillf krb5_boolean print_usage = FALSE; 70754925bf6Swillf char *policy = NULL; 70854925bf6Swillf unsigned int mask = 0; 70954925bf6Swillf 71054925bf6Swillf if (argc != 2) { 71154925bf6Swillf goto err_usage; 71254925bf6Swillf } 71354925bf6Swillf 71454925bf6Swillf policy = strdup(argv[1]); 71554925bf6Swillf if (policy == NULL) { 71654925bf6Swillf com_err(me, ENOMEM, gettext("while viewing policy")); 71754925bf6Swillf exit_status++; 71854925bf6Swillf goto cleanup; 71954925bf6Swillf } 72054925bf6Swillf 72154925bf6Swillf if ((retval = init_ldap_realm (argc, argv))) 72254925bf6Swillf goto cleanup; 72354925bf6Swillf 72454925bf6Swillf if ((retval = krb5_ldap_read_policy(util_context, policy, &policyparams, &mask))) { 72554925bf6Swillf com_err(me, retval, gettext("while viewing policy '%s'"), policy); 72654925bf6Swillf exit_status++; 72754925bf6Swillf goto cleanup; 72854925bf6Swillf } 72954925bf6Swillf 73054925bf6Swillf print_policy_params (policyparams, mask); 73154925bf6Swillf 73254925bf6Swillf goto cleanup; 73354925bf6Swillf 73454925bf6Swillf err_usage: 73554925bf6Swillf print_usage = TRUE; 73654925bf6Swillf 73754925bf6Swillf cleanup: 73854925bf6Swillf krb5_ldap_free_policy (util_context, policyparams); 73954925bf6Swillf 74054925bf6Swillf if (policy) 74154925bf6Swillf free (policy); 74254925bf6Swillf 74354925bf6Swillf if (print_usage) { 74454925bf6Swillf db_usage(VIEW_POLICY); 74554925bf6Swillf } 74654925bf6Swillf 74754925bf6Swillf return; 74854925bf6Swillf } 74954925bf6Swillf 75054925bf6Swillf 75154925bf6Swillf /* 75254925bf6Swillf * This function will print the policy object information to the 75354925bf6Swillf * standard output. 75454925bf6Swillf */ 75554925bf6Swillf static void 75654925bf6Swillf print_policy_params(policyparams, mask) 75754925bf6Swillf krb5_ldap_policy_params *policyparams; 75854925bf6Swillf int mask; 75954925bf6Swillf { 76054925bf6Swillf /* Print the policy DN */ 76154925bf6Swillf printf("%25s: %s\n", gettext("Ticket policy"), policyparams->policy); 76254925bf6Swillf 76354925bf6Swillf /* Print max. ticket life and max. renewable life, if present */ 76454925bf6Swillf if (mask & LDAP_POLICY_MAXTKTLIFE) 76554925bf6Swillf printf("%25s: %s\n", gettext("Maximum ticket life"), strdur(policyparams->maxtktlife)); 76654925bf6Swillf if (mask & LDAP_POLICY_MAXRENEWLIFE) 76754925bf6Swillf printf("%25s: %s\n", gettext("Maximum renewable life"), strdur(policyparams->maxrenewlife)); 76854925bf6Swillf 76954925bf6Swillf /* Service flags are printed */ 77054925bf6Swillf printf("%25s: ", gettext("Ticket flags")); 77154925bf6Swillf if (mask & LDAP_POLICY_TKTFLAGS) { 77254925bf6Swillf int ticketflags = policyparams->tktflags; 77354925bf6Swillf 77454925bf6Swillf if (ticketflags & KRB5_KDB_DISALLOW_POSTDATED) 77554925bf6Swillf printf("%s ","DISALLOW_POSTDATED"); 77654925bf6Swillf 77754925bf6Swillf if (ticketflags & KRB5_KDB_DISALLOW_FORWARDABLE) 77854925bf6Swillf printf("%s ","DISALLOW_FORWARDABLE"); 77954925bf6Swillf 78054925bf6Swillf if (ticketflags & KRB5_KDB_DISALLOW_RENEWABLE) 78154925bf6Swillf printf("%s ","DISALLOW_RENEWABLE"); 78254925bf6Swillf 78354925bf6Swillf if (ticketflags & KRB5_KDB_DISALLOW_PROXIABLE) 78454925bf6Swillf printf("%s ","DISALLOW_PROXIABLE"); 78554925bf6Swillf 78654925bf6Swillf if (ticketflags & KRB5_KDB_DISALLOW_DUP_SKEY) 78754925bf6Swillf printf("%s ","DISALLOW_DUP_SKEY"); 78854925bf6Swillf 78954925bf6Swillf if (ticketflags & KRB5_KDB_REQUIRES_PRE_AUTH) 79054925bf6Swillf printf("%s ","REQUIRES_PRE_AUTH"); 79154925bf6Swillf 79254925bf6Swillf if (ticketflags & KRB5_KDB_REQUIRES_HW_AUTH) 79354925bf6Swillf printf("%s ","REQUIRES_HW_AUTH"); 79454925bf6Swillf 79554925bf6Swillf if (ticketflags & KRB5_KDB_DISALLOW_SVR) 79654925bf6Swillf printf("%s ","DISALLOW_SVR"); 79754925bf6Swillf 79854925bf6Swillf if (ticketflags & KRB5_KDB_DISALLOW_TGT_BASED) 79954925bf6Swillf printf("%s ","DISALLOW_TGT_BASED"); 80054925bf6Swillf 80154925bf6Swillf if (ticketflags & KRB5_KDB_DISALLOW_ALL_TIX) 80254925bf6Swillf printf("%s ","DISALLOW_ALL_TIX"); 80354925bf6Swillf 80454925bf6Swillf if (ticketflags & KRB5_KDB_REQUIRES_PWCHANGE) 80554925bf6Swillf printf("%s ","REQUIRES_PWCHANGE"); 80654925bf6Swillf 80754925bf6Swillf if (ticketflags & KRB5_KDB_PWCHANGE_SERVICE) 80854925bf6Swillf printf("%s ","PWCHANGE_SERVICE"); 80954925bf6Swillf } 81054925bf6Swillf printf("\n"); 81154925bf6Swillf 81254925bf6Swillf return; 81354925bf6Swillf } 81454925bf6Swillf 81554925bf6Swillf 81654925bf6Swillf /* 81754925bf6Swillf * This function will list the DNs of policy objects under a specific 81854925bf6Swillf * sub-tree (entire tree by default) 81954925bf6Swillf */ 82054925bf6Swillf void kdb5_ldap_list_policies(argc, argv) 82154925bf6Swillf int argc; 82254925bf6Swillf char *argv[]; 82354925bf6Swillf { 824*dd9ccd46S /* Solaris Kerberos */ 825*dd9ccd46S char *me = progname; 826*dd9ccd46S 82754925bf6Swillf krb5_error_code retval = 0; 82854925bf6Swillf krb5_boolean print_usage = FALSE; 82954925bf6Swillf char *basedn = NULL; 83054925bf6Swillf char **list = NULL; 83154925bf6Swillf char **plist = NULL; 83254925bf6Swillf 83354925bf6Swillf /* Check for number of arguments */ 83454925bf6Swillf if ((argc != 1) && (argc != 3)) { 83554925bf6Swillf goto err_usage; 83654925bf6Swillf } 83754925bf6Swillf 83854925bf6Swillf if ((retval = init_ldap_realm (argc, argv))) 83954925bf6Swillf goto cleanup; 84054925bf6Swillf 84154925bf6Swillf retval = krb5_ldap_list_policy(util_context, basedn, &list); 84254925bf6Swillf if ((retval != 0) || (list == NULL)) 84354925bf6Swillf goto cleanup; 84454925bf6Swillf 84554925bf6Swillf for (plist = list; *plist != NULL; plist++) { 84654925bf6Swillf printf("%s\n", *plist); 84754925bf6Swillf } 84854925bf6Swillf 84954925bf6Swillf goto cleanup; 85054925bf6Swillf 85154925bf6Swillf err_usage: 85254925bf6Swillf print_usage = TRUE; 85354925bf6Swillf 85454925bf6Swillf cleanup: 85554925bf6Swillf if (list != NULL) { 85654925bf6Swillf krb5_free_list_entries (list); 85754925bf6Swillf free (list); 85854925bf6Swillf } 85954925bf6Swillf 86054925bf6Swillf if (basedn) 86154925bf6Swillf free (basedn); 86254925bf6Swillf 86354925bf6Swillf if (print_usage) { 86454925bf6Swillf db_usage(LIST_POLICY); 86554925bf6Swillf } 86654925bf6Swillf 86754925bf6Swillf if (retval) { 86854925bf6Swillf com_err(me, retval, gettext("while listing policy objects")); 86954925bf6Swillf exit_status++; 87054925bf6Swillf } 87154925bf6Swillf 87254925bf6Swillf return; 87354925bf6Swillf } 87454925bf6Swillf 87554925bf6Swillf 87654925bf6Swillf /* Reproduced from kadmin.c, instead of linking 87754925bf6Swillf the entire kadmin.o */ 87854925bf6Swillf static char *strdur(duration) 87954925bf6Swillf time_t duration; 88054925bf6Swillf { 88154925bf6Swillf static char out[50]; 88254925bf6Swillf int neg, days, hours, minutes, seconds; 88354925bf6Swillf 88454925bf6Swillf if (duration < 0) { 88554925bf6Swillf duration *= -1; 88654925bf6Swillf neg = 1; 88754925bf6Swillf } else 88854925bf6Swillf neg = 0; 88954925bf6Swillf days = duration / (24 * 3600); 89054925bf6Swillf duration %= 24 * 3600; 89154925bf6Swillf hours = duration / 3600; 89254925bf6Swillf duration %= 3600; 89354925bf6Swillf minutes = duration / 60; 89454925bf6Swillf duration %= 60; 89554925bf6Swillf seconds = duration; 89654925bf6Swillf snprintf(out, sizeof(out), "%s%d %s %02d:%02d:%02d", neg ? "-" : "", 89754925bf6Swillf days, days == 1 ? gettext("day") : gettext("days"), 89854925bf6Swillf hours, minutes, seconds); 89954925bf6Swillf return out; 90054925bf6Swillf } 901