155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "kadmin_locl.h"
3555682Smarkm#include <parse_units.h>
3655682Smarkm
3755682Smarkm/*
3855682Smarkm * util.c - functions for parsing, unparsing, and editing different
3955682Smarkm * types of data used in kadmin.
4055682Smarkm */
4155682Smarkm
4290926Snectarstatic int
4390926Snectarget_response(const char *prompt, const char *def, char *buf, size_t len);
4490926Snectar
4555682Smarkm/*
46233294Sstas * attributes
4755682Smarkm */
4855682Smarkm
4955682Smarkmstruct units kdb_attrs[] = {
50178825Sdfr    { "allow-digest",		KRB5_KDB_ALLOW_DIGEST },
51178825Sdfr    { "allow-kerberos4",	KRB5_KDB_ALLOW_KERBEROS4 },
52178825Sdfr    { "trusted-for-delegation",	KRB5_KDB_TRUSTED_FOR_DELEGATION },
53178825Sdfr    { "ok-as-delegate",		KRB5_KDB_OK_AS_DELEGATE },
5455682Smarkm    { "new-princ",		KRB5_KDB_NEW_PRINC },
5555682Smarkm    { "support-desmd5",		KRB5_KDB_SUPPORT_DESMD5 },
5655682Smarkm    { "pwchange-service",	KRB5_KDB_PWCHANGE_SERVICE },
5755682Smarkm    { "disallow-svr",		KRB5_KDB_DISALLOW_SVR },
5855682Smarkm    { "requires-pw-change",	KRB5_KDB_REQUIRES_PWCHANGE },
5955682Smarkm    { "requires-hw-auth",	KRB5_KDB_REQUIRES_HW_AUTH },
6055682Smarkm    { "requires-pre-auth",	KRB5_KDB_REQUIRES_PRE_AUTH },
6155682Smarkm    { "disallow-all-tix",	KRB5_KDB_DISALLOW_ALL_TIX },
6255682Smarkm    { "disallow-dup-skey",	KRB5_KDB_DISALLOW_DUP_SKEY },
6355682Smarkm    { "disallow-proxiable",	KRB5_KDB_DISALLOW_PROXIABLE },
6455682Smarkm    { "disallow-renewable",	KRB5_KDB_DISALLOW_RENEWABLE },
6555682Smarkm    { "disallow-tgt-based",	KRB5_KDB_DISALLOW_TGT_BASED },
6655682Smarkm    { "disallow-forwardable",	KRB5_KDB_DISALLOW_FORWARDABLE },
6755682Smarkm    { "disallow-postdated",	KRB5_KDB_DISALLOW_POSTDATED },
68233294Sstas    { NULL, 0 }
6955682Smarkm};
7055682Smarkm
7155682Smarkm/*
7255682Smarkm * convert the attributes in `attributes' into a printable string
7355682Smarkm * in `str, len'
7455682Smarkm */
7555682Smarkm
7655682Smarkmvoid
7755682Smarkmattributes2str(krb5_flags attributes, char *str, size_t len)
7855682Smarkm{
7955682Smarkm    unparse_flags (attributes, kdb_attrs, str, len);
8055682Smarkm}
8155682Smarkm
8255682Smarkm/*
8355682Smarkm * convert the string in `str' into attributes in `flags'
8455682Smarkm * return 0 if parsed ok, else -1.
8555682Smarkm */
8655682Smarkm
8755682Smarkmint
8855682Smarkmstr2attributes(const char *str, krb5_flags *flags)
8955682Smarkm{
9055682Smarkm    int res;
9155682Smarkm
9255682Smarkm    res = parse_flags (str, kdb_attrs, *flags);
9355682Smarkm    if (res < 0)
9455682Smarkm	return res;
9555682Smarkm    else {
9655682Smarkm	*flags = res;
9755682Smarkm	return 0;
9855682Smarkm    }
9955682Smarkm}
10055682Smarkm
10155682Smarkm/*
10255682Smarkm * try to parse the string `resp' into attributes in `attr', also
10355682Smarkm * setting the `bit' in `mask' if attributes are given and valid.
10455682Smarkm */
10555682Smarkm
10655682Smarkmint
10755682Smarkmparse_attributes (const char *resp, krb5_flags *attr, int *mask, int bit)
10855682Smarkm{
10955682Smarkm    krb5_flags tmp = *attr;
11055682Smarkm
11172445Sassar    if (str2attributes(resp, &tmp) == 0) {
11255682Smarkm	*attr = tmp;
11355682Smarkm	if (mask)
11455682Smarkm	    *mask |= bit;
11555682Smarkm	return 0;
11655682Smarkm    } else if(*resp == '?') {
11755682Smarkm	print_flags_table (kdb_attrs, stderr);
11855682Smarkm    } else {
119178825Sdfr	fprintf (stderr, "Unable to parse \"%s\"\n", resp);
12055682Smarkm    }
12155682Smarkm    return -1;
12255682Smarkm}
12355682Smarkm
12455682Smarkm/*
12555682Smarkm * allow the user to edit the attributes in `attr', prompting with `prompt'
12655682Smarkm */
12755682Smarkm
12855682Smarkmint
12955682Smarkmedit_attributes (const char *prompt, krb5_flags *attr, int *mask, int bit)
13055682Smarkm{
13155682Smarkm    char buf[1024], resp[1024];
13255682Smarkm
13355682Smarkm    if (mask && (*mask & bit))
13455682Smarkm	return 0;
13555682Smarkm
13655682Smarkm    attributes2str(*attr, buf, sizeof(buf));
13755682Smarkm    for (;;) {
13890926Snectar	if(get_response("Attributes", buf, resp, sizeof(resp)) != 0)
13990926Snectar	    return 1;
14072445Sassar	if (resp[0] == '\0')
14172445Sassar	    break;
14255682Smarkm	if (parse_attributes (resp, attr, mask, bit) == 0)
14355682Smarkm	    break;
14455682Smarkm    }
14555682Smarkm    return 0;
14655682Smarkm}
14755682Smarkm
14855682Smarkm/*
14955682Smarkm * time_t
15055682Smarkm * the special value 0 means ``never''
15155682Smarkm */
15255682Smarkm
15355682Smarkm/*
15455682Smarkm * Convert the time `t' to a string representation in `str' (of max
15555682Smarkm * size `len').  If include_time also include time, otherwise just
156233294Sstas * date.
15755682Smarkm */
15855682Smarkm
15955682Smarkmvoid
16055682Smarkmtime_t2str(time_t t, char *str, size_t len, int include_time)
16155682Smarkm{
16255682Smarkm    if(t) {
16355682Smarkm	if(include_time)
16455682Smarkm	    strftime(str, len, "%Y-%m-%d %H:%M:%S UTC", gmtime(&t));
16555682Smarkm	else
16655682Smarkm	    strftime(str, len, "%Y-%m-%d", gmtime(&t));
16755682Smarkm    } else
16855682Smarkm	snprintf(str, len, "never");
16955682Smarkm}
17055682Smarkm
17155682Smarkm/*
17255682Smarkm * Convert the time representation in `str' to a time in `time'.
17355682Smarkm * Return 0 if succesful, else -1.
17455682Smarkm */
17555682Smarkm
17655682Smarkmint
17772445Sassarstr2time_t (const char *str, time_t *t)
17855682Smarkm{
17955682Smarkm    const char *p;
18072445Sassar    struct tm tm, tm2;
18155682Smarkm
18255682Smarkm    memset (&tm, 0, sizeof (tm));
183178825Sdfr    memset (&tm2, 0, sizeof (tm2));
18455682Smarkm
185233294Sstas    while(isspace((unsigned char)*str))
186233294Sstas	str++;
187233294Sstas
188233294Sstas    if (str[0] == '+') {
189233294Sstas	str++;
190233294Sstas	*t = parse_time(str, "month");
191233294Sstas	if (*t < 0)
192233294Sstas	    return -1;
193233294Sstas	*t += time(NULL);
194233294Sstas	return 0;
195233294Sstas    }
196233294Sstas
19755682Smarkm    if(strcasecmp(str, "never") == 0) {
19872445Sassar	*t = 0;
19955682Smarkm	return 0;
20055682Smarkm    }
20155682Smarkm
20272445Sassar    if(strcasecmp(str, "now") == 0) {
20372445Sassar	*t = time(NULL);
20472445Sassar	return 0;
20572445Sassar    }
20672445Sassar
20755682Smarkm    p = strptime (str, "%Y-%m-%d", &tm);
20855682Smarkm
20955682Smarkm    if (p == NULL)
21055682Smarkm	return -1;
21155682Smarkm
212178825Sdfr    while(isspace((unsigned char)*p))
213178825Sdfr	p++;
21455682Smarkm
215178825Sdfr    /* XXX this is really a bit optimistic, we should really complain
216178825Sdfr       if there was a problem parsing the time */
217178825Sdfr    if(p[0] != '\0' && strptime (p, "%H:%M:%S", &tm2) != NULL) {
21872445Sassar	tm.tm_hour = tm2.tm_hour;
21972445Sassar	tm.tm_min  = tm2.tm_min;
22072445Sassar	tm.tm_sec  = tm2.tm_sec;
221178825Sdfr    } else {
222178825Sdfr	/* Do it on the end of the day */
223178825Sdfr	tm.tm_hour = 23;
224178825Sdfr	tm.tm_min  = 59;
225178825Sdfr	tm.tm_sec  = 59;
22672445Sassar    }
22755682Smarkm
22872445Sassar    *t = tm2time (tm, 0);
22955682Smarkm    return 0;
23055682Smarkm}
23155682Smarkm
23255682Smarkm/*
23355682Smarkm * try to parse the time in `resp' storing it in `value'
23455682Smarkm */
23555682Smarkm
23655682Smarkmint
23755682Smarkmparse_timet (const char *resp, krb5_timestamp *value, int *mask, int bit)
23855682Smarkm{
23955682Smarkm    time_t tmp;
24055682Smarkm
24155682Smarkm    if (str2time_t(resp, &tmp) == 0) {
24255682Smarkm	*value = tmp;
24355682Smarkm	if(mask)
24455682Smarkm	    *mask |= bit;
24555682Smarkm	return 0;
246233294Sstas    }
247178825Sdfr    if(*resp != '?')
248178825Sdfr	fprintf (stderr, "Unable to parse time \"%s\"\n", resp);
249178825Sdfr    fprintf (stderr, "Print date on format YYYY-mm-dd [hh:mm:ss]\n");
25055682Smarkm    return -1;
25155682Smarkm}
25255682Smarkm
25355682Smarkm/*
25455682Smarkm * allow the user to edit the time in `value'
25555682Smarkm */
25655682Smarkm
25755682Smarkmint
25855682Smarkmedit_timet (const char *prompt, krb5_timestamp *value, int *mask, int bit)
25955682Smarkm{
26055682Smarkm    char buf[1024], resp[1024];
26155682Smarkm
26255682Smarkm    if (mask && (*mask & bit))
26355682Smarkm	return 0;
26455682Smarkm
26555682Smarkm    time_t2str (*value, buf, sizeof (buf), 0);
26655682Smarkm
26755682Smarkm    for (;;) {
26890926Snectar	if(get_response(prompt, buf, resp, sizeof(resp)) != 0)
26990926Snectar	    return 1;
27055682Smarkm	if (parse_timet (resp, value, mask, bit) == 0)
27155682Smarkm	    break;
27255682Smarkm    }
27355682Smarkm    return 0;
27455682Smarkm}
27555682Smarkm
27655682Smarkm/*
27755682Smarkm * deltat
27855682Smarkm * the special value 0 means ``unlimited''
27955682Smarkm */
28055682Smarkm
28155682Smarkm/*
28255682Smarkm * convert the delta_t value in `t' into a printable form in `str, len'
28355682Smarkm */
28455682Smarkm
28555682Smarkmvoid
28655682Smarkmdeltat2str(unsigned t, char *str, size_t len)
28755682Smarkm{
28872445Sassar    if(t == 0 || t == INT_MAX)
28972445Sassar	snprintf(str, len, "unlimited");
29072445Sassar    else
29155682Smarkm	unparse_time(t, str, len);
29255682Smarkm}
29355682Smarkm
29455682Smarkm/*
29555682Smarkm * parse the delta value in `str', storing result in `*delta'
29655682Smarkm * return 0 if ok, else -1
29755682Smarkm */
29855682Smarkm
29955682Smarkmint
30055682Smarkmstr2deltat(const char *str, krb5_deltat *delta)
30155682Smarkm{
30255682Smarkm    int res;
30355682Smarkm
30455682Smarkm    if(strcasecmp(str, "unlimited") == 0) {
30555682Smarkm	*delta = 0;
30655682Smarkm	return 0;
30755682Smarkm    }
30855682Smarkm    res = parse_time(str, "day");
30955682Smarkm    if (res < 0)
31055682Smarkm	return res;
31155682Smarkm    else {
31255682Smarkm	*delta = res;
31355682Smarkm	return 0;
31455682Smarkm    }
31555682Smarkm}
31655682Smarkm
31755682Smarkm/*
31855682Smarkm * try to parse the string in `resp' into a deltad in `value'
31955682Smarkm * `mask' will get the bit `bit' set if a value was given.
32055682Smarkm */
32155682Smarkm
32255682Smarkmint
32355682Smarkmparse_deltat (const char *resp, krb5_deltat *value, int *mask, int bit)
32455682Smarkm{
32555682Smarkm    krb5_deltat tmp;
32655682Smarkm
32755682Smarkm    if (str2deltat(resp, &tmp) == 0) {
32855682Smarkm	*value = tmp;
32955682Smarkm	if (mask)
33055682Smarkm	    *mask |= bit;
33155682Smarkm	return 0;
33255682Smarkm    } else if(*resp == '?') {
33355682Smarkm	print_time_table (stderr);
33455682Smarkm    } else {
335178825Sdfr	fprintf (stderr, "Unable to parse time \"%s\"\n", resp);
33655682Smarkm    }
33755682Smarkm    return -1;
33855682Smarkm}
33955682Smarkm
34055682Smarkm/*
34155682Smarkm * allow the user to edit the deltat in `value'
34255682Smarkm */
34355682Smarkm
34455682Smarkmint
34555682Smarkmedit_deltat (const char *prompt, krb5_deltat *value, int *mask, int bit)
34655682Smarkm{
34755682Smarkm    char buf[1024], resp[1024];
34855682Smarkm
34955682Smarkm    if (mask && (*mask & bit))
35055682Smarkm	return 0;
35155682Smarkm
35255682Smarkm    deltat2str(*value, buf, sizeof(buf));
35355682Smarkm    for (;;) {
35490926Snectar	if(get_response(prompt, buf, resp, sizeof(resp)) != 0)
35590926Snectar	    return 1;
35655682Smarkm	if (parse_deltat (resp, value, mask, bit) == 0)
35755682Smarkm	    break;
35855682Smarkm    }
35955682Smarkm    return 0;
36055682Smarkm}
36155682Smarkm
36255682Smarkm/*
36355682Smarkm * allow the user to edit `ent'
36455682Smarkm */
36555682Smarkm
36690926Snectarvoid
36790926Snectarset_defaults(kadm5_principal_ent_t ent, int *mask,
36890926Snectar	     kadm5_principal_ent_t default_ent, int default_mask)
36955682Smarkm{
37072445Sassar    if (default_ent
37172445Sassar	&& (default_mask & KADM5_MAX_LIFE)
37272445Sassar	&& !(*mask & KADM5_MAX_LIFE))
37355682Smarkm	ent->max_life = default_ent->max_life;
37455682Smarkm
37572445Sassar    if (default_ent
37672445Sassar	&& (default_mask & KADM5_MAX_RLIFE)
37772445Sassar	&& !(*mask & KADM5_MAX_RLIFE))
37855682Smarkm	ent->max_renewable_life = default_ent->max_renewable_life;
37955682Smarkm
38072445Sassar    if (default_ent
38172445Sassar	&& (default_mask & KADM5_PRINC_EXPIRE_TIME)
38272445Sassar	&& !(*mask & KADM5_PRINC_EXPIRE_TIME))
38355682Smarkm	ent->princ_expire_time = default_ent->princ_expire_time;
38455682Smarkm
38572445Sassar    if (default_ent
38672445Sassar	&& (default_mask & KADM5_PW_EXPIRATION)
38772445Sassar	&& !(*mask & KADM5_PW_EXPIRATION))
38855682Smarkm	ent->pw_expiration = default_ent->pw_expiration;
38955682Smarkm
39072445Sassar    if (default_ent
39172445Sassar	&& (default_mask & KADM5_ATTRIBUTES)
39272445Sassar	&& !(*mask & KADM5_ATTRIBUTES))
39355682Smarkm	ent->attributes = default_ent->attributes & ~KRB5_KDB_DISALLOW_ALL_TIX;
39490926Snectar}
39590926Snectar
39690926Snectarint
39790926Snectaredit_entry(kadm5_principal_ent_t ent, int *mask,
39890926Snectar	   kadm5_principal_ent_t default_ent, int default_mask)
39990926Snectar{
40090926Snectar
40190926Snectar    set_defaults(ent, mask, default_ent, default_mask);
40290926Snectar
40390926Snectar    if(edit_deltat ("Max ticket life", &ent->max_life, mask,
40490926Snectar		    KADM5_MAX_LIFE) != 0)
40590926Snectar	return 1;
406233294Sstas
40790926Snectar    if(edit_deltat ("Max renewable life", &ent->max_renewable_life, mask,
40890926Snectar		    KADM5_MAX_RLIFE) != 0)
40990926Snectar	return 1;
41090926Snectar
41190926Snectar    if(edit_timet ("Principal expiration time", &ent->princ_expire_time, mask,
41290926Snectar		   KADM5_PRINC_EXPIRE_TIME) != 0)
41390926Snectar	return 1;
41490926Snectar
41590926Snectar    if(edit_timet ("Password expiration time", &ent->pw_expiration, mask,
41690926Snectar		   KADM5_PW_EXPIRATION) != 0)
41790926Snectar	return 1;
41890926Snectar
41990926Snectar    if(edit_attributes ("Attributes", &ent->attributes, mask,
42090926Snectar			KADM5_ATTRIBUTES) != 0)
42190926Snectar	return 1;
42290926Snectar
42355682Smarkm    return 0;
42455682Smarkm}
42555682Smarkm
42655682Smarkm/*
42755682Smarkm * Parse the arguments, set the fields in `ent' and the `mask' for the
42855682Smarkm * entries having been set.
42955682Smarkm * Return 1 on failure and 0 on success.
43055682Smarkm */
43155682Smarkm
43255682Smarkmint
433233294Sstasset_entry(krb5_context contextp,
43455682Smarkm	  kadm5_principal_ent_t ent,
43555682Smarkm	  int *mask,
43655682Smarkm	  const char *max_ticket_life,
43755682Smarkm	  const char *max_renewable_life,
43855682Smarkm	  const char *expiration,
43955682Smarkm	  const char *pw_expiration,
44055682Smarkm	  const char *attributes)
44155682Smarkm{
44255682Smarkm    if (max_ticket_life != NULL) {
443233294Sstas	if (parse_deltat (max_ticket_life, &ent->max_life,
44455682Smarkm			  mask, KADM5_MAX_LIFE)) {
445233294Sstas	    krb5_warnx (contextp, "unable to parse `%s'", max_ticket_life);
44655682Smarkm	    return 1;
44755682Smarkm	}
44855682Smarkm    }
44955682Smarkm    if (max_renewable_life != NULL) {
450233294Sstas	if (parse_deltat (max_renewable_life, &ent->max_renewable_life,
45155682Smarkm			  mask, KADM5_MAX_RLIFE)) {
452233294Sstas	    krb5_warnx (contextp, "unable to parse `%s'", max_renewable_life);
45355682Smarkm	    return 1;
45455682Smarkm	}
45555682Smarkm    }
45655682Smarkm
45755682Smarkm    if (expiration) {
458233294Sstas	if (parse_timet (expiration, &ent->princ_expire_time,
45955682Smarkm			mask, KADM5_PRINC_EXPIRE_TIME)) {
460233294Sstas	    krb5_warnx (contextp, "unable to parse `%s'", expiration);
46155682Smarkm	    return 1;
46255682Smarkm	}
46355682Smarkm    }
46455682Smarkm    if (pw_expiration) {
465233294Sstas	if (parse_timet (pw_expiration, &ent->pw_expiration,
46655682Smarkm			 mask, KADM5_PW_EXPIRATION)) {
467233294Sstas	    krb5_warnx (contextp, "unable to parse `%s'", pw_expiration);
46855682Smarkm	    return 1;
46955682Smarkm	}
47055682Smarkm    }
47155682Smarkm    if (attributes != NULL) {
472233294Sstas	if (parse_attributes (attributes, &ent->attributes,
47355682Smarkm			      mask, KADM5_ATTRIBUTES)) {
474233294Sstas	    krb5_warnx (contextp, "unable to parse `%s'", attributes);
47555682Smarkm	    return 1;
47655682Smarkm	}
47755682Smarkm    }
47855682Smarkm    return 0;
47955682Smarkm}
48055682Smarkm
48155682Smarkm/*
48255682Smarkm * Does `string' contain any globing characters?
48355682Smarkm */
48455682Smarkm
48555682Smarkmstatic int
48655682Smarkmis_expression(const char *string)
48755682Smarkm{
48855682Smarkm    const char *p;
48955682Smarkm    int quote = 0;
49055682Smarkm
49155682Smarkm    for(p = string; *p; p++) {
49255682Smarkm	if(quote) {
49355682Smarkm	    quote = 0;
49455682Smarkm	    continue;
49555682Smarkm	}
49655682Smarkm	if(*p == '\\')
49755682Smarkm	    quote++;
498233294Sstas	else if(strchr("[]*?", *p) != NULL)
49955682Smarkm	    return 1;
50055682Smarkm    }
50155682Smarkm    return 0;
50255682Smarkm}
50355682Smarkm
504178825Sdfr/*
505178825Sdfr * Loop over all principals matching exp.  If any of calls to `func'
506178825Sdfr * failes, the first error is returned when all principals are
507178825Sdfr * processed.
508178825Sdfr */
50955682Smarkmint
510233294Sstasforeach_principal(const char *exp_str,
511233294Sstas		  int (*func)(krb5_principal, void*),
51278527Sassar		  const char *funcname,
51355682Smarkm		  void *data)
51455682Smarkm{
515233294Sstas    char **princs = NULL;
516233294Sstas    int num_princs = 0;
51755682Smarkm    int i;
518178825Sdfr    krb5_error_code saved_ret = 0, ret = 0;
51955682Smarkm    krb5_principal princ_ent;
52055682Smarkm    int is_expr;
52155682Smarkm
52255682Smarkm    /* if this isn't an expression, there is no point in wading
52355682Smarkm       through the whole database looking for matches */
524178825Sdfr    is_expr = is_expression(exp_str);
52555682Smarkm    if(is_expr)
526178825Sdfr	ret = kadm5_get_principals(kadm_handle, exp_str, &princs, &num_princs);
52755682Smarkm    if(!is_expr || ret == KADM5_AUTH_LIST) {
52855682Smarkm	/* we might be able to perform the requested opreration even
52955682Smarkm           if we're not allowed to list principals */
53055682Smarkm	num_princs = 1;
53155682Smarkm	princs = malloc(sizeof(*princs));
53255682Smarkm	if(princs == NULL)
53355682Smarkm	    return ENOMEM;
534178825Sdfr	princs[0] = strdup(exp_str);
535233294Sstas	if(princs[0] == NULL){
53655682Smarkm	    free(princs);
53755682Smarkm	    return ENOMEM;
53855682Smarkm	}
53955682Smarkm    } else if(ret) {
54055682Smarkm	krb5_warn(context, ret, "kadm5_get_principals");
54155682Smarkm	return ret;
54255682Smarkm    }
54355682Smarkm    for(i = 0; i < num_princs; i++) {
54455682Smarkm	ret = krb5_parse_name(context, princs[i], &princ_ent);
54555682Smarkm	if(ret){
54655682Smarkm	    krb5_warn(context, ret, "krb5_parse_name(%s)", princs[i]);
54755682Smarkm	    continue;
54855682Smarkm	}
54955682Smarkm	ret = (*func)(princ_ent, data);
550178825Sdfr	if(ret) {
551233294Sstas	    krb5_clear_error_message(context);
55278527Sassar	    krb5_warn(context, ret, "%s %s", funcname, princs[i]);
553178825Sdfr	    if (saved_ret == 0)
554178825Sdfr		saved_ret = ret;
555178825Sdfr	}
55655682Smarkm	krb5_free_principal(context, princ_ent);
55755682Smarkm    }
558178825Sdfr    if (ret == 0 && saved_ret != 0)
559178825Sdfr	ret = saved_ret;
56055682Smarkm    kadm5_free_name_list(kadm_handle, princs, &num_princs);
561178825Sdfr    return ret;
56255682Smarkm}
56355682Smarkm
56455682Smarkm/*
56555682Smarkm * prompt with `prompt' and default value `def', and store the reply
56655682Smarkm * in `buf, len'
56755682Smarkm */
56855682Smarkm
56990926Snectar#include <setjmp.h>
57090926Snectar
57190926Snectarstatic jmp_buf jmpbuf;
57290926Snectar
57390926Snectarstatic void
57490926Snectarinterrupt(int sig)
57590926Snectar{
57690926Snectar    longjmp(jmpbuf, 1);
57790926Snectar}
57890926Snectar
57990926Snectarstatic int
58055682Smarkmget_response(const char *prompt, const char *def, char *buf, size_t len)
58155682Smarkm{
58255682Smarkm    char *p;
58390926Snectar    void (*osig)(int);
58455682Smarkm
58590926Snectar    osig = signal(SIGINT, interrupt);
58690926Snectar    if(setjmp(jmpbuf)) {
58790926Snectar	signal(SIGINT, osig);
588178825Sdfr	fprintf(stderr, "\n");
58990926Snectar	return 1;
59090926Snectar    }
59190926Snectar
592178825Sdfr    fprintf(stderr, "%s [%s]:", prompt, def);
59390926Snectar    if(fgets(buf, len, stdin) == NULL) {
59490926Snectar	int save_errno = errno;
59590926Snectar	if(ferror(stdin))
59690926Snectar	    krb5_err(context, 1, save_errno, "<stdin>");
59790926Snectar	signal(SIGINT, osig);
59890926Snectar	return 1;
59990926Snectar    }
60055682Smarkm    p = strchr(buf, '\n');
60155682Smarkm    if(p)
60255682Smarkm	*p = '\0';
60355682Smarkm    if(strcmp(buf, "") == 0)
60490926Snectar	strlcpy(buf, def, len);
60590926Snectar    signal(SIGINT, osig);
60690926Snectar    return 0;
60755682Smarkm}
60872445Sassar
60972445Sassar/*
61072445Sassar * return [0, 16) or -1
61172445Sassar */
61272445Sassar
61372445Sassarstatic int
61472445Sassarhex2n (char c)
61572445Sassar{
61672445Sassar    static char hexdigits[] = "0123456789abcdef";
61772445Sassar    const char *p;
61872445Sassar
619120945Snectar    p = strchr (hexdigits, tolower((unsigned char)c));
62072445Sassar    if (p == NULL)
62172445Sassar	return -1;
62272445Sassar    else
62372445Sassar	return p - hexdigits;
62472445Sassar}
62572445Sassar
62672445Sassar/*
62772445Sassar * convert a key in a readable format into a keyblock.
62872445Sassar * return 0 iff succesful, otherwise `err' should point to an error message
62972445Sassar */
63072445Sassar
63172445Sassarint
63272445Sassarparse_des_key (const char *key_string, krb5_key_data *key_data,
633178825Sdfr	       const char **error)
63472445Sassar{
63572445Sassar    const char *p = key_string;
63672445Sassar    unsigned char bits[8];
63772445Sassar    int i;
63872445Sassar
63972445Sassar    if (strlen (key_string) != 16) {
640178825Sdfr	*error = "bad length, should be 16 for DES key";
64172445Sassar	return 1;
64272445Sassar    }
64372445Sassar    for (i = 0; i < 8; ++i) {
64472445Sassar	int d1, d2;
64572445Sassar
64672445Sassar	d1 = hex2n(p[2 * i]);
64772445Sassar	d2 = hex2n(p[2 * i + 1]);
64872445Sassar	if (d1 < 0 || d2 < 0) {
649178825Sdfr	    *error = "non-hex character";
65072445Sassar	    return 1;
65172445Sassar	}
65272445Sassar	bits[i] = (d1 << 4) | d2;
65372445Sassar    }
65472445Sassar    for (i = 0; i < 3; ++i) {
65572445Sassar	key_data[i].key_data_ver  = 2;
65672445Sassar	key_data[i].key_data_kvno = 0;
65772445Sassar	/* key */
65872445Sassar	key_data[i].key_data_type[0]     = ETYPE_DES_CBC_CRC;
65972445Sassar	key_data[i].key_data_length[0]   = 8;
66072445Sassar	key_data[i].key_data_contents[0] = malloc(8);
661178825Sdfr	if (key_data[i].key_data_contents[0] == NULL) {
662178825Sdfr	    *error = "malloc";
663178825Sdfr	    return ENOMEM;
664178825Sdfr	}
66572445Sassar	memcpy (key_data[i].key_data_contents[0], bits, 8);
66672445Sassar	/* salt */
66772445Sassar	key_data[i].key_data_type[1]     = KRB5_PW_SALT;
66872445Sassar	key_data[i].key_data_length[1]   = 0;
66972445Sassar	key_data[i].key_data_contents[1] = NULL;
67072445Sassar    }
67172445Sassar    key_data[0].key_data_type[0] = ETYPE_DES_CBC_MD5;
67272445Sassar    key_data[1].key_data_type[0] = ETYPE_DES_CBC_MD4;
67372445Sassar    return 0;
67472445Sassar}
675