155682Smarkm/*
2178825Sdfr * Copyright (c) 1997 - 2006 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "kadmin_locl.h"
3555682Smarkm#include <parse_units.h>
3655682Smarkm
37178825SdfrRCSID("$Id: util.c 21745 2007-07-31 16:11:25Z lha $");
3855682Smarkm
3955682Smarkm/*
4055682Smarkm * util.c - functions for parsing, unparsing, and editing different
4155682Smarkm * types of data used in kadmin.
4255682Smarkm */
4355682Smarkm
4490926Snectarstatic int
4590926Snectarget_response(const char *prompt, const char *def, char *buf, size_t len);
4690926Snectar
4755682Smarkm/*
4855682Smarkm * attributes
4955682Smarkm */
5055682Smarkm
5155682Smarkmstruct units kdb_attrs[] = {
52178825Sdfr    { "allow-digest",		KRB5_KDB_ALLOW_DIGEST },
53178825Sdfr    { "allow-kerberos4",	KRB5_KDB_ALLOW_KERBEROS4 },
54178825Sdfr    { "trusted-for-delegation",	KRB5_KDB_TRUSTED_FOR_DELEGATION },
55178825Sdfr    { "ok-as-delegate",		KRB5_KDB_OK_AS_DELEGATE },
5655682Smarkm    { "new-princ",		KRB5_KDB_NEW_PRINC },
5755682Smarkm    { "support-desmd5",		KRB5_KDB_SUPPORT_DESMD5 },
5855682Smarkm    { "pwchange-service",	KRB5_KDB_PWCHANGE_SERVICE },
5955682Smarkm    { "disallow-svr",		KRB5_KDB_DISALLOW_SVR },
6055682Smarkm    { "requires-pw-change",	KRB5_KDB_REQUIRES_PWCHANGE },
6155682Smarkm    { "requires-hw-auth",	KRB5_KDB_REQUIRES_HW_AUTH },
6255682Smarkm    { "requires-pre-auth",	KRB5_KDB_REQUIRES_PRE_AUTH },
6355682Smarkm    { "disallow-all-tix",	KRB5_KDB_DISALLOW_ALL_TIX },
6455682Smarkm    { "disallow-dup-skey",	KRB5_KDB_DISALLOW_DUP_SKEY },
6555682Smarkm    { "disallow-proxiable",	KRB5_KDB_DISALLOW_PROXIABLE },
6655682Smarkm    { "disallow-renewable",	KRB5_KDB_DISALLOW_RENEWABLE },
6755682Smarkm    { "disallow-tgt-based",	KRB5_KDB_DISALLOW_TGT_BASED },
6855682Smarkm    { "disallow-forwardable",	KRB5_KDB_DISALLOW_FORWARDABLE },
6955682Smarkm    { "disallow-postdated",	KRB5_KDB_DISALLOW_POSTDATED },
7055682Smarkm    { NULL }
7155682Smarkm};
7255682Smarkm
7355682Smarkm/*
7455682Smarkm * convert the attributes in `attributes' into a printable string
7555682Smarkm * in `str, len'
7655682Smarkm */
7755682Smarkm
7855682Smarkmvoid
7955682Smarkmattributes2str(krb5_flags attributes, char *str, size_t len)
8055682Smarkm{
8155682Smarkm    unparse_flags (attributes, kdb_attrs, str, len);
8255682Smarkm}
8355682Smarkm
8455682Smarkm/*
8555682Smarkm * convert the string in `str' into attributes in `flags'
8655682Smarkm * return 0 if parsed ok, else -1.
8755682Smarkm */
8855682Smarkm
8955682Smarkmint
9055682Smarkmstr2attributes(const char *str, krb5_flags *flags)
9155682Smarkm{
9255682Smarkm    int res;
9355682Smarkm
9455682Smarkm    res = parse_flags (str, kdb_attrs, *flags);
9555682Smarkm    if (res < 0)
9655682Smarkm	return res;
9755682Smarkm    else {
9855682Smarkm	*flags = res;
9955682Smarkm	return 0;
10055682Smarkm    }
10155682Smarkm}
10255682Smarkm
10355682Smarkm/*
10455682Smarkm * try to parse the string `resp' into attributes in `attr', also
10555682Smarkm * setting the `bit' in `mask' if attributes are given and valid.
10655682Smarkm */
10755682Smarkm
10855682Smarkmint
10955682Smarkmparse_attributes (const char *resp, krb5_flags *attr, int *mask, int bit)
11055682Smarkm{
11155682Smarkm    krb5_flags tmp = *attr;
11255682Smarkm
11372445Sassar    if (str2attributes(resp, &tmp) == 0) {
11455682Smarkm	*attr = tmp;
11555682Smarkm	if (mask)
11655682Smarkm	    *mask |= bit;
11755682Smarkm	return 0;
11855682Smarkm    } else if(*resp == '?') {
11955682Smarkm	print_flags_table (kdb_attrs, stderr);
12055682Smarkm    } else {
121178825Sdfr	fprintf (stderr, "Unable to parse \"%s\"\n", resp);
12255682Smarkm    }
12355682Smarkm    return -1;
12455682Smarkm}
12555682Smarkm
12655682Smarkm/*
12755682Smarkm * allow the user to edit the attributes in `attr', prompting with `prompt'
12855682Smarkm */
12955682Smarkm
13055682Smarkmint
13155682Smarkmedit_attributes (const char *prompt, krb5_flags *attr, int *mask, int bit)
13255682Smarkm{
13355682Smarkm    char buf[1024], resp[1024];
13455682Smarkm
13555682Smarkm    if (mask && (*mask & bit))
13655682Smarkm	return 0;
13755682Smarkm
13855682Smarkm    attributes2str(*attr, buf, sizeof(buf));
13955682Smarkm    for (;;) {
14090926Snectar	if(get_response("Attributes", buf, resp, sizeof(resp)) != 0)
14190926Snectar	    return 1;
14272445Sassar	if (resp[0] == '\0')
14372445Sassar	    break;
14455682Smarkm	if (parse_attributes (resp, attr, mask, bit) == 0)
14555682Smarkm	    break;
14655682Smarkm    }
14755682Smarkm    return 0;
14855682Smarkm}
14955682Smarkm
15055682Smarkm/*
15155682Smarkm * time_t
15255682Smarkm * the special value 0 means ``never''
15355682Smarkm */
15455682Smarkm
15555682Smarkm/*
15655682Smarkm * Convert the time `t' to a string representation in `str' (of max
15755682Smarkm * size `len').  If include_time also include time, otherwise just
15855682Smarkm * date.
15955682Smarkm */
16055682Smarkm
16155682Smarkmvoid
16255682Smarkmtime_t2str(time_t t, char *str, size_t len, int include_time)
16355682Smarkm{
16455682Smarkm    if(t) {
16555682Smarkm	if(include_time)
16655682Smarkm	    strftime(str, len, "%Y-%m-%d %H:%M:%S UTC", gmtime(&t));
16755682Smarkm	else
16855682Smarkm	    strftime(str, len, "%Y-%m-%d", gmtime(&t));
16955682Smarkm    } else
17055682Smarkm	snprintf(str, len, "never");
17155682Smarkm}
17255682Smarkm
17355682Smarkm/*
17455682Smarkm * Convert the time representation in `str' to a time in `time'.
17555682Smarkm * Return 0 if succesful, else -1.
17655682Smarkm */
17755682Smarkm
17855682Smarkmint
17972445Sassarstr2time_t (const char *str, time_t *t)
18055682Smarkm{
18155682Smarkm    const char *p;
18272445Sassar    struct tm tm, tm2;
18355682Smarkm
18455682Smarkm    memset (&tm, 0, sizeof (tm));
185178825Sdfr    memset (&tm2, 0, sizeof (tm2));
18655682Smarkm
18755682Smarkm    if(strcasecmp(str, "never") == 0) {
18872445Sassar	*t = 0;
18955682Smarkm	return 0;
19055682Smarkm    }
19155682Smarkm
19272445Sassar    if(strcasecmp(str, "now") == 0) {
19372445Sassar	*t = time(NULL);
19472445Sassar	return 0;
19572445Sassar    }
19672445Sassar
19755682Smarkm    p = strptime (str, "%Y-%m-%d", &tm);
19855682Smarkm
19955682Smarkm    if (p == NULL)
20055682Smarkm	return -1;
20155682Smarkm
202178825Sdfr    while(isspace((unsigned char)*p))
203178825Sdfr	p++;
20455682Smarkm
205178825Sdfr    /* XXX this is really a bit optimistic, we should really complain
206178825Sdfr       if there was a problem parsing the time */
207178825Sdfr    if(p[0] != '\0' && strptime (p, "%H:%M:%S", &tm2) != NULL) {
20872445Sassar	tm.tm_hour = tm2.tm_hour;
20972445Sassar	tm.tm_min  = tm2.tm_min;
21072445Sassar	tm.tm_sec  = tm2.tm_sec;
211178825Sdfr    } else {
212178825Sdfr	/* Do it on the end of the day */
213178825Sdfr	tm.tm_hour = 23;
214178825Sdfr	tm.tm_min  = 59;
215178825Sdfr	tm.tm_sec  = 59;
21672445Sassar    }
21755682Smarkm
21872445Sassar    *t = tm2time (tm, 0);
21955682Smarkm    return 0;
22055682Smarkm}
22155682Smarkm
22255682Smarkm/*
22355682Smarkm * try to parse the time in `resp' storing it in `value'
22455682Smarkm */
22555682Smarkm
22655682Smarkmint
22755682Smarkmparse_timet (const char *resp, krb5_timestamp *value, int *mask, int bit)
22855682Smarkm{
22955682Smarkm    time_t tmp;
23055682Smarkm
23155682Smarkm    if (str2time_t(resp, &tmp) == 0) {
23255682Smarkm	*value = tmp;
23355682Smarkm	if(mask)
23455682Smarkm	    *mask |= bit;
23555682Smarkm	return 0;
236178825Sdfr    }
237178825Sdfr    if(*resp != '?')
238178825Sdfr	fprintf (stderr, "Unable to parse time \"%s\"\n", resp);
239178825Sdfr    fprintf (stderr, "Print date on format YYYY-mm-dd [hh:mm:ss]\n");
24055682Smarkm    return -1;
24155682Smarkm}
24255682Smarkm
24355682Smarkm/*
24455682Smarkm * allow the user to edit the time in `value'
24555682Smarkm */
24655682Smarkm
24755682Smarkmint
24855682Smarkmedit_timet (const char *prompt, krb5_timestamp *value, int *mask, int bit)
24955682Smarkm{
25055682Smarkm    char buf[1024], resp[1024];
25155682Smarkm
25255682Smarkm    if (mask && (*mask & bit))
25355682Smarkm	return 0;
25455682Smarkm
25555682Smarkm    time_t2str (*value, buf, sizeof (buf), 0);
25655682Smarkm
25755682Smarkm    for (;;) {
25890926Snectar	if(get_response(prompt, buf, resp, sizeof(resp)) != 0)
25990926Snectar	    return 1;
26055682Smarkm	if (parse_timet (resp, value, mask, bit) == 0)
26155682Smarkm	    break;
26255682Smarkm    }
26355682Smarkm    return 0;
26455682Smarkm}
26555682Smarkm
26655682Smarkm/*
26755682Smarkm * deltat
26855682Smarkm * the special value 0 means ``unlimited''
26955682Smarkm */
27055682Smarkm
27155682Smarkm/*
27255682Smarkm * convert the delta_t value in `t' into a printable form in `str, len'
27355682Smarkm */
27455682Smarkm
27555682Smarkmvoid
27655682Smarkmdeltat2str(unsigned t, char *str, size_t len)
27755682Smarkm{
27872445Sassar    if(t == 0 || t == INT_MAX)
27972445Sassar	snprintf(str, len, "unlimited");
28072445Sassar    else
28155682Smarkm	unparse_time(t, str, len);
28255682Smarkm}
28355682Smarkm
28455682Smarkm/*
28555682Smarkm * parse the delta value in `str', storing result in `*delta'
28655682Smarkm * return 0 if ok, else -1
28755682Smarkm */
28855682Smarkm
28955682Smarkmint
29055682Smarkmstr2deltat(const char *str, krb5_deltat *delta)
29155682Smarkm{
29255682Smarkm    int res;
29355682Smarkm
29455682Smarkm    if(strcasecmp(str, "unlimited") == 0) {
29555682Smarkm	*delta = 0;
29655682Smarkm	return 0;
29755682Smarkm    }
29855682Smarkm    res = parse_time(str, "day");
29955682Smarkm    if (res < 0)
30055682Smarkm	return res;
30155682Smarkm    else {
30255682Smarkm	*delta = res;
30355682Smarkm	return 0;
30455682Smarkm    }
30555682Smarkm}
30655682Smarkm
30755682Smarkm/*
30855682Smarkm * try to parse the string in `resp' into a deltad in `value'
30955682Smarkm * `mask' will get the bit `bit' set if a value was given.
31055682Smarkm */
31155682Smarkm
31255682Smarkmint
31355682Smarkmparse_deltat (const char *resp, krb5_deltat *value, int *mask, int bit)
31455682Smarkm{
31555682Smarkm    krb5_deltat tmp;
31655682Smarkm
31755682Smarkm    if (str2deltat(resp, &tmp) == 0) {
31855682Smarkm	*value = tmp;
31955682Smarkm	if (mask)
32055682Smarkm	    *mask |= bit;
32155682Smarkm	return 0;
32255682Smarkm    } else if(*resp == '?') {
32355682Smarkm	print_time_table (stderr);
32455682Smarkm    } else {
325178825Sdfr	fprintf (stderr, "Unable to parse time \"%s\"\n", resp);
32655682Smarkm    }
32755682Smarkm    return -1;
32855682Smarkm}
32955682Smarkm
33055682Smarkm/*
33155682Smarkm * allow the user to edit the deltat in `value'
33255682Smarkm */
33355682Smarkm
33455682Smarkmint
33555682Smarkmedit_deltat (const char *prompt, krb5_deltat *value, int *mask, int bit)
33655682Smarkm{
33755682Smarkm    char buf[1024], resp[1024];
33855682Smarkm
33955682Smarkm    if (mask && (*mask & bit))
34055682Smarkm	return 0;
34155682Smarkm
34255682Smarkm    deltat2str(*value, buf, sizeof(buf));
34355682Smarkm    for (;;) {
34490926Snectar	if(get_response(prompt, buf, resp, sizeof(resp)) != 0)
34590926Snectar	    return 1;
34655682Smarkm	if (parse_deltat (resp, value, mask, bit) == 0)
34755682Smarkm	    break;
34855682Smarkm    }
34955682Smarkm    return 0;
35055682Smarkm}
35155682Smarkm
35255682Smarkm/*
35355682Smarkm * allow the user to edit `ent'
35455682Smarkm */
35555682Smarkm
35690926Snectarvoid
35790926Snectarset_defaults(kadm5_principal_ent_t ent, int *mask,
35890926Snectar	     kadm5_principal_ent_t default_ent, int default_mask)
35955682Smarkm{
36072445Sassar    if (default_ent
36172445Sassar	&& (default_mask & KADM5_MAX_LIFE)
36272445Sassar	&& !(*mask & KADM5_MAX_LIFE))
36355682Smarkm	ent->max_life = default_ent->max_life;
36455682Smarkm
36572445Sassar    if (default_ent
36672445Sassar	&& (default_mask & KADM5_MAX_RLIFE)
36772445Sassar	&& !(*mask & KADM5_MAX_RLIFE))
36855682Smarkm	ent->max_renewable_life = default_ent->max_renewable_life;
36955682Smarkm
37072445Sassar    if (default_ent
37172445Sassar	&& (default_mask & KADM5_PRINC_EXPIRE_TIME)
37272445Sassar	&& !(*mask & KADM5_PRINC_EXPIRE_TIME))
37355682Smarkm	ent->princ_expire_time = default_ent->princ_expire_time;
37455682Smarkm
37572445Sassar    if (default_ent
37672445Sassar	&& (default_mask & KADM5_PW_EXPIRATION)
37772445Sassar	&& !(*mask & KADM5_PW_EXPIRATION))
37855682Smarkm	ent->pw_expiration = default_ent->pw_expiration;
37955682Smarkm
38072445Sassar    if (default_ent
38172445Sassar	&& (default_mask & KADM5_ATTRIBUTES)
38272445Sassar	&& !(*mask & KADM5_ATTRIBUTES))
38355682Smarkm	ent->attributes = default_ent->attributes & ~KRB5_KDB_DISALLOW_ALL_TIX;
38490926Snectar}
38590926Snectar
38690926Snectarint
38790926Snectaredit_entry(kadm5_principal_ent_t ent, int *mask,
38890926Snectar	   kadm5_principal_ent_t default_ent, int default_mask)
38990926Snectar{
39090926Snectar
39190926Snectar    set_defaults(ent, mask, default_ent, default_mask);
39290926Snectar
39390926Snectar    if(edit_deltat ("Max ticket life", &ent->max_life, mask,
39490926Snectar		    KADM5_MAX_LIFE) != 0)
39590926Snectar	return 1;
39690926Snectar
39790926Snectar    if(edit_deltat ("Max renewable life", &ent->max_renewable_life, mask,
39890926Snectar		    KADM5_MAX_RLIFE) != 0)
39990926Snectar	return 1;
40090926Snectar
40190926Snectar    if(edit_timet ("Principal expiration time", &ent->princ_expire_time, mask,
40290926Snectar		   KADM5_PRINC_EXPIRE_TIME) != 0)
40390926Snectar	return 1;
40490926Snectar
40590926Snectar    if(edit_timet ("Password expiration time", &ent->pw_expiration, mask,
40690926Snectar		   KADM5_PW_EXPIRATION) != 0)
40790926Snectar	return 1;
40890926Snectar
40990926Snectar    if(edit_attributes ("Attributes", &ent->attributes, mask,
41090926Snectar			KADM5_ATTRIBUTES) != 0)
41190926Snectar	return 1;
41290926Snectar
41355682Smarkm    return 0;
41455682Smarkm}
41555682Smarkm
41655682Smarkm/*
41755682Smarkm * Parse the arguments, set the fields in `ent' and the `mask' for the
41855682Smarkm * entries having been set.
41955682Smarkm * Return 1 on failure and 0 on success.
42055682Smarkm */
42155682Smarkm
42255682Smarkmint
42355682Smarkmset_entry(krb5_context context,
42455682Smarkm	  kadm5_principal_ent_t ent,
42555682Smarkm	  int *mask,
42655682Smarkm	  const char *max_ticket_life,
42755682Smarkm	  const char *max_renewable_life,
42855682Smarkm	  const char *expiration,
42955682Smarkm	  const char *pw_expiration,
43055682Smarkm	  const char *attributes)
43155682Smarkm{
43255682Smarkm    if (max_ticket_life != NULL) {
43355682Smarkm	if (parse_deltat (max_ticket_life, &ent->max_life,
43455682Smarkm			  mask, KADM5_MAX_LIFE)) {
43555682Smarkm	    krb5_warnx (context, "unable to parse `%s'", max_ticket_life);
43655682Smarkm	    return 1;
43755682Smarkm	}
43855682Smarkm    }
43955682Smarkm    if (max_renewable_life != NULL) {
44055682Smarkm	if (parse_deltat (max_renewable_life, &ent->max_renewable_life,
44155682Smarkm			  mask, KADM5_MAX_RLIFE)) {
44255682Smarkm	    krb5_warnx (context, "unable to parse `%s'", max_renewable_life);
44355682Smarkm	    return 1;
44455682Smarkm	}
44555682Smarkm    }
44655682Smarkm
44755682Smarkm    if (expiration) {
44855682Smarkm	if (parse_timet (expiration, &ent->princ_expire_time,
44955682Smarkm			mask, KADM5_PRINC_EXPIRE_TIME)) {
45055682Smarkm	    krb5_warnx (context, "unable to parse `%s'", expiration);
45155682Smarkm	    return 1;
45255682Smarkm	}
45355682Smarkm    }
45455682Smarkm    if (pw_expiration) {
45555682Smarkm	if (parse_timet (pw_expiration, &ent->pw_expiration,
45655682Smarkm			 mask, KADM5_PW_EXPIRATION)) {
45755682Smarkm	    krb5_warnx (context, "unable to parse `%s'", pw_expiration);
45855682Smarkm	    return 1;
45955682Smarkm	}
46055682Smarkm    }
46155682Smarkm    if (attributes != NULL) {
46255682Smarkm	if (parse_attributes (attributes, &ent->attributes,
46355682Smarkm			      mask, KADM5_ATTRIBUTES)) {
46455682Smarkm	    krb5_warnx (context, "unable to parse `%s'", attributes);
46555682Smarkm	    return 1;
46655682Smarkm	}
46755682Smarkm    }
46855682Smarkm    return 0;
46955682Smarkm}
47055682Smarkm
47155682Smarkm/*
47255682Smarkm * Does `string' contain any globing characters?
47355682Smarkm */
47455682Smarkm
47555682Smarkmstatic int
47655682Smarkmis_expression(const char *string)
47755682Smarkm{
47855682Smarkm    const char *p;
47955682Smarkm    int quote = 0;
48055682Smarkm
48155682Smarkm    for(p = string; *p; p++) {
48255682Smarkm	if(quote) {
48355682Smarkm	    quote = 0;
48455682Smarkm	    continue;
48555682Smarkm	}
48655682Smarkm	if(*p == '\\')
48755682Smarkm	    quote++;
48855682Smarkm	else if(strchr("[]*?", *p) != NULL)
48955682Smarkm	    return 1;
49055682Smarkm    }
49155682Smarkm    return 0;
49255682Smarkm}
49355682Smarkm
494178825Sdfr/*
495178825Sdfr * Loop over all principals matching exp.  If any of calls to `func'
496178825Sdfr * failes, the first error is returned when all principals are
497178825Sdfr * processed.
498178825Sdfr */
49955682Smarkmint
500178825Sdfrforeach_principal(const char *exp_str,
50155682Smarkm		  int (*func)(krb5_principal, void*),
50278527Sassar		  const char *funcname,
50355682Smarkm		  void *data)
50455682Smarkm{
50555682Smarkm    char **princs;
50655682Smarkm    int num_princs;
50755682Smarkm    int i;
508178825Sdfr    krb5_error_code saved_ret = 0, ret = 0;
50955682Smarkm    krb5_principal princ_ent;
51055682Smarkm    int is_expr;
51155682Smarkm
51255682Smarkm    /* if this isn't an expression, there is no point in wading
51355682Smarkm       through the whole database looking for matches */
514178825Sdfr    is_expr = is_expression(exp_str);
51555682Smarkm    if(is_expr)
516178825Sdfr	ret = kadm5_get_principals(kadm_handle, exp_str, &princs, &num_princs);
51755682Smarkm    if(!is_expr || ret == KADM5_AUTH_LIST) {
51855682Smarkm	/* we might be able to perform the requested opreration even
51955682Smarkm           if we're not allowed to list principals */
52055682Smarkm	num_princs = 1;
52155682Smarkm	princs = malloc(sizeof(*princs));
52255682Smarkm	if(princs == NULL)
52355682Smarkm	    return ENOMEM;
524178825Sdfr	princs[0] = strdup(exp_str);
52555682Smarkm	if(princs[0] == NULL){
52655682Smarkm	    free(princs);
52755682Smarkm	    return ENOMEM;
52855682Smarkm	}
52955682Smarkm    } else if(ret) {
53055682Smarkm	krb5_warn(context, ret, "kadm5_get_principals");
53155682Smarkm	return ret;
53255682Smarkm    }
53355682Smarkm    for(i = 0; i < num_princs; i++) {
53455682Smarkm	ret = krb5_parse_name(context, princs[i], &princ_ent);
53555682Smarkm	if(ret){
53655682Smarkm	    krb5_warn(context, ret, "krb5_parse_name(%s)", princs[i]);
53755682Smarkm	    continue;
53855682Smarkm	}
53955682Smarkm	ret = (*func)(princ_ent, data);
540178825Sdfr	if(ret) {
541178825Sdfr	    krb5_clear_error_string(context);
54278527Sassar	    krb5_warn(context, ret, "%s %s", funcname, princs[i]);
543178825Sdfr	    if (saved_ret == 0)
544178825Sdfr		saved_ret = ret;
545178825Sdfr	}
54655682Smarkm	krb5_free_principal(context, princ_ent);
54755682Smarkm    }
548178825Sdfr    if (ret == 0 && saved_ret != 0)
549178825Sdfr	ret = saved_ret;
55055682Smarkm    kadm5_free_name_list(kadm_handle, princs, &num_princs);
551178825Sdfr    return ret;
55255682Smarkm}
55355682Smarkm
55455682Smarkm/*
55555682Smarkm * prompt with `prompt' and default value `def', and store the reply
55655682Smarkm * in `buf, len'
55755682Smarkm */
55855682Smarkm
55990926Snectar#include <setjmp.h>
56090926Snectar
56190926Snectarstatic jmp_buf jmpbuf;
56290926Snectar
56390926Snectarstatic void
56490926Snectarinterrupt(int sig)
56590926Snectar{
56690926Snectar    longjmp(jmpbuf, 1);
56790926Snectar}
56890926Snectar
56990926Snectarstatic int
57055682Smarkmget_response(const char *prompt, const char *def, char *buf, size_t len)
57155682Smarkm{
57255682Smarkm    char *p;
57390926Snectar    void (*osig)(int);
57455682Smarkm
57590926Snectar    osig = signal(SIGINT, interrupt);
57690926Snectar    if(setjmp(jmpbuf)) {
57790926Snectar	signal(SIGINT, osig);
578178825Sdfr	fprintf(stderr, "\n");
57990926Snectar	return 1;
58090926Snectar    }
58190926Snectar
582178825Sdfr    fprintf(stderr, "%s [%s]:", prompt, def);
58390926Snectar    if(fgets(buf, len, stdin) == NULL) {
58490926Snectar	int save_errno = errno;
58590926Snectar	if(ferror(stdin))
58690926Snectar	    krb5_err(context, 1, save_errno, "<stdin>");
58790926Snectar	signal(SIGINT, osig);
58890926Snectar	return 1;
58990926Snectar    }
59055682Smarkm    p = strchr(buf, '\n');
59155682Smarkm    if(p)
59255682Smarkm	*p = '\0';
59355682Smarkm    if(strcmp(buf, "") == 0)
59490926Snectar	strlcpy(buf, def, len);
59590926Snectar    signal(SIGINT, osig);
59690926Snectar    return 0;
59755682Smarkm}
59872445Sassar
59972445Sassar/*
60072445Sassar * return [0, 16) or -1
60172445Sassar */
60272445Sassar
60372445Sassarstatic int
60472445Sassarhex2n (char c)
60572445Sassar{
60672445Sassar    static char hexdigits[] = "0123456789abcdef";
60772445Sassar    const char *p;
60872445Sassar
609120945Snectar    p = strchr (hexdigits, tolower((unsigned char)c));
61072445Sassar    if (p == NULL)
61172445Sassar	return -1;
61272445Sassar    else
61372445Sassar	return p - hexdigits;
61472445Sassar}
61572445Sassar
61672445Sassar/*
61772445Sassar * convert a key in a readable format into a keyblock.
61872445Sassar * return 0 iff succesful, otherwise `err' should point to an error message
61972445Sassar */
62072445Sassar
62172445Sassarint
62272445Sassarparse_des_key (const char *key_string, krb5_key_data *key_data,
623178825Sdfr	       const char **error)
62472445Sassar{
62572445Sassar    const char *p = key_string;
62672445Sassar    unsigned char bits[8];
62772445Sassar    int i;
62872445Sassar
62972445Sassar    if (strlen (key_string) != 16) {
630178825Sdfr	*error = "bad length, should be 16 for DES key";
63172445Sassar	return 1;
63272445Sassar    }
63372445Sassar    for (i = 0; i < 8; ++i) {
63472445Sassar	int d1, d2;
63572445Sassar
63672445Sassar	d1 = hex2n(p[2 * i]);
63772445Sassar	d2 = hex2n(p[2 * i + 1]);
63872445Sassar	if (d1 < 0 || d2 < 0) {
639178825Sdfr	    *error = "non-hex character";
64072445Sassar	    return 1;
64172445Sassar	}
64272445Sassar	bits[i] = (d1 << 4) | d2;
64372445Sassar    }
64472445Sassar    for (i = 0; i < 3; ++i) {
64572445Sassar	key_data[i].key_data_ver  = 2;
64672445Sassar	key_data[i].key_data_kvno = 0;
64772445Sassar	/* key */
64872445Sassar	key_data[i].key_data_type[0]     = ETYPE_DES_CBC_CRC;
64972445Sassar	key_data[i].key_data_length[0]   = 8;
65072445Sassar	key_data[i].key_data_contents[0] = malloc(8);
651178825Sdfr	if (key_data[i].key_data_contents[0] == NULL) {
652178825Sdfr	    *error = "malloc";
653178825Sdfr	    return ENOMEM;
654178825Sdfr	}
65572445Sassar	memcpy (key_data[i].key_data_contents[0], bits, 8);
65672445Sassar	/* salt */
65772445Sassar	key_data[i].key_data_type[1]     = KRB5_PW_SALT;
65872445Sassar	key_data[i].key_data_length[1]   = 0;
65972445Sassar	key_data[i].key_data_contents[1] = NULL;
66072445Sassar    }
66172445Sassar    key_data[0].key_data_type[0] = ETYPE_DES_CBC_MD5;
66272445Sassar    key_data[1].key_data_type[0] = ETYPE_DES_CBC_MD4;
66372445Sassar    return 0;
66472445Sassar}
665