1/*
2 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7/*
8 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
9 *
10 *	Openvision retains the copyright to derivative works of
11 *	this source code.  Do *NOT* create a derivative of this
12 *	source code before consulting with your legal department.
13 *	Do *NOT* integrate *ANY* of this source code into another
14 *	product before consulting with your legal department.
15 *
16 *	For further information, read the top-level Openvision
17 *	copyright which is contained in the top-level MIT Kerberos
18 *	copyright.
19 *
20 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
21 *
22 */
23
24
25/*
26 * lib/kadm/str_conv.c
27 *
28 * Copyright 1995 by the Massachusetts Institute of Technology.
29 * All Rights Reserved.
30 *
31 * Export of this software from the United States of America may
32 *   require a specific license from the United States Government.
33 *   It is the responsibility of any person or organization contemplating
34 *   export to obtain such a license before exporting.
35 *
36 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
37 * distribute this software and its documentation for any purpose and
38 * without fee is hereby granted, provided that the above copyright
39 * notice appear in all copies and that both that copyright notice and
40 * this permission notice appear in supporting documentation, and that
41 * the name of M.I.T. not be used in advertising or publicity pertaining
42 * to distribution of the software without specific, written prior
43 * permission.  Furthermore if you modify this software you must label
44 * your software as modified software and not distribute it in such a
45 * fashion that it might be confused with the original M.I.T. software.
46 * M.I.T. makes no representations about the suitability of
47 * this software for any purpose.  It is provided "as is" without express
48 * or implied warranty.
49 *
50 */
51
52/*
53 * str_conv.c - Convert between strings and Kerberos internal data.
54 */
55
56/*
57 * Table of contents:
58 *
59 * String decoding:
60 * ----------------
61 * krb5_string_to_flags()	- Convert string to krb5_flags.
62 *
63 * String encoding:
64 * ----------------
65 * krb5_flags_to_string()	- Convert krb5_flags to string.
66 */
67
68#include "k5-int.h"
69#include "admin_internal.h"
70#include "adm_proto.h"
71
72/*
73 * Local data structures.
74 */
75struct flags_lookup_entry {
76    krb5_flags		fl_flags;		/* Flag			*/
77    krb5_boolean	fl_sense;		/* Sense of the flag	*/
78    const char *	fl_specifier;		/* How to recognize it	*/
79    const char *	fl_output;		/* How to spit it out	*/
80};
81
82/*
83 * Local strings
84 */
85
86static const char default_tupleseps[]   = ", \t";
87static const char default_ksaltseps[]   = ":.";
88
89/* Keytype strings */
90/* Flags strings */
91static const char flags_pdate_in[]	= "postdateable";
92static const char flags_fwd_in[]	= "forwardable";
93static const char flags_tgtbased_in[]	= "tgt-based";
94static const char flags_renew_in[]	= "renewable";
95static const char flags_proxy_in[]	= "proxiable";
96static const char flags_dup_skey_in[]	= "dup-skey";
97static const char flags_tickets_in[]	= "allow-tickets";
98static const char flags_preauth_in[]	= "preauth";
99static const char flags_hwauth_in[]	= "hwauth";
100static const char flags_pwchange_in[]	= "pwchange";
101static const char flags_service_in[]	= "service";
102static const char flags_pwsvc_in[]	= "pwservice";
103static const char flags_md5_in[]	= "md5";
104static const char flags_pdate_out[]	= "Not Postdateable";
105static const char flags_fwd_out[]	= "Not Forwardable";
106static const char flags_tgtbased_out[]	= "No TGT-based requests";
107static const char flags_renew_out[]	= "Not renewable";
108static const char flags_proxy_out[]	= "Not proxiable";
109static const char flags_dup_skey_out[]	= "No DUP_SKEY requests";
110static const char flags_tickets_out[]	= "All Tickets Disallowed";
111static const char flags_preauth_out[]	= "Preauthorization required";
112static const char flags_hwauth_out[]	= "HW Authorization required";
113static const char flags_pwchange_out[]	= "Password Change required";
114static const char flags_service_out[]	= "Service Disabled";
115static const char flags_pwsvc_out[]	= "Password Changing Service";
116static const char flags_md5_out[]	= "RSA-MD5 supported";
117static const char flags_default_neg[]	= "-";
118static const char flags_default_sep[]	= " ";
119
120/*
121 * Lookup tables.
122 */
123
124static const struct flags_lookup_entry flags_table[] = {
125/* flag				sense	input specifier	   output string     */
126/*----------------------------- -------	------------------ ------------------*/
127{ KRB5_KDB_DISALLOW_POSTDATED,	0,	flags_pdate_in,	   flags_pdate_out   },
128{ KRB5_KDB_DISALLOW_FORWARDABLE,0,	flags_fwd_in,	   flags_fwd_out     },
129{ KRB5_KDB_DISALLOW_TGT_BASED,	0,	flags_tgtbased_in, flags_tgtbased_out},
130{ KRB5_KDB_DISALLOW_RENEWABLE,	0,	flags_renew_in,	   flags_renew_out   },
131{ KRB5_KDB_DISALLOW_PROXIABLE,	0,	flags_proxy_in,	   flags_proxy_out   },
132{ KRB5_KDB_DISALLOW_DUP_SKEY,	0,	flags_dup_skey_in, flags_dup_skey_out},
133{ KRB5_KDB_DISALLOW_ALL_TIX,	0,	flags_tickets_in,  flags_tickets_out },
134{ KRB5_KDB_REQUIRES_PRE_AUTH,	1,	flags_preauth_in,  flags_preauth_out },
135{ KRB5_KDB_REQUIRES_HW_AUTH,	1,	flags_hwauth_in,   flags_hwauth_out  },
136{ KRB5_KDB_REQUIRES_PWCHANGE,	1,	flags_pwchange_in, flags_pwchange_out},
137{ KRB5_KDB_DISALLOW_SVR,	0,	flags_service_in,  flags_service_out },
138{ KRB5_KDB_PWCHANGE_SERVICE,	1,	flags_pwsvc_in,	   flags_pwsvc_out   },
139{ KRB5_KDB_SUPPORT_DESMD5,	1,	flags_md5_in,	   flags_md5_out     }
140};
141static const int flags_table_nents = sizeof(flags_table)/
142				     sizeof(flags_table[0]);
143
144
145krb5_error_code
146krb5_string_to_flags(string, positive, negative, flagsp)
147    char	* string;
148    const char	* positive;
149    const char	* negative;
150    krb5_flags	* flagsp;
151{
152    int 	i;
153    int 	found;
154    const char	*neg;
155    size_t	nsize, psize;
156    int		cpos;
157    int		sense;
158
159    found = 0;
160    /* We need to have a way to negate it. */
161    neg = (negative) ? negative : flags_default_neg;
162    nsize = strlen(neg);
163    psize = (positive) ? strlen(positive) : 0;
164
165    cpos = 0;
166    sense = 1;
167    /* First check for positive or negative sense */
168    if (!strncasecmp(neg, string, nsize)) {
169	sense = 0;
170	cpos += (int) nsize;
171    }
172    else if (psize && !strncasecmp(positive, string, psize)) {
173	cpos += (int) psize;
174    }
175
176    for (i=0; i<flags_table_nents; i++) {
177	if (!strcasecmp(&string[cpos], flags_table[i].fl_specifier)) {
178	    found = 1;
179	    if (sense == (int) flags_table[i].fl_sense)
180		*flagsp |= flags_table[i].fl_flags;
181	    else
182		*flagsp &= ~flags_table[i].fl_flags;
183
184	    break;
185	}
186    }
187    return((found) ? 0 : EINVAL);
188}
189
190krb5_error_code
191krb5_flags_to_string(flags, sep, buffer, buflen)
192    krb5_flags	flags;
193    const char	* sep;
194    char	* buffer;
195    size_t	buflen;
196{
197    int			i;
198    krb5_flags		pflags;
199    const char		*sepstring;
200    char		*op;
201    int			initial;
202    krb5_error_code	retval;
203
204    retval = 0;
205    op = buffer;
206    pflags = 0;
207    initial = 1;
208    sepstring = (sep) ? sep : flags_default_sep;
209    /* Blast through the table matching all we can */
210    for (i=0; i<flags_table_nents; i++) {
211	if (flags & flags_table[i].fl_flags) {
212	    /* Found a match, see if it'll fit into the output buffer */
213	    if ((op+strlen(flags_table[i].fl_output)+strlen(sepstring)) <
214		(buffer + buflen)) {
215		if (!initial) {
216		    strcpy(op, sep);
217		    op += strlen(sep);
218		}
219		initial = 0;
220		strcpy(op, flags_table[i].fl_output);
221		op += strlen(flags_table[i].fl_output);
222	    }
223	    else {
224		retval = ENOMEM;
225		break;
226	    }
227	    /* Keep track of what we matched */
228	    pflags |= flags_table[i].fl_flags;
229	}
230    }
231    if (!retval) {
232	/* See if there's any leftovers */
233	if (flags & ~pflags)
234	    retval = EINVAL;
235	else if (initial)
236	    *buffer = '\0';
237    }
238    return(retval);
239}
240
241krb5_error_code
242krb5_input_flag_to_string(flag, buffer, buflen)
243    int		flag;
244    char	* buffer;
245    size_t	buflen;
246{
247    if(flag < 0 || flag >= flags_table_nents) return ENOENT; /* End of list */
248    if(strlen(flags_table[flag].fl_specifier) > buflen) return ENOMEM;
249    strcpy(buffer, flags_table[flag].fl_specifier);
250    return  0;
251}
252
253/*
254 * krb5_keysalt_is_present()	- Determine if a key/salt pair is present
255 *				  in a list of key/salt tuples.
256 *
257 *	Salttype may be negative to indicate a search for only a enctype.
258 */
259krb5_boolean
260krb5_keysalt_is_present(ksaltlist, nksalts, enctype, salttype)
261    krb5_key_salt_tuple	*ksaltlist;
262    krb5_int32		nksalts;
263    krb5_enctype	enctype;
264    krb5_int32		salttype;
265{
266    krb5_boolean	foundit;
267    int			i;
268
269    foundit = 0;
270    if (ksaltlist) {
271	for (i=0; i<nksalts; i++) {
272	    if ((ksaltlist[i].ks_enctype == enctype) &&
273		((ksaltlist[i].ks_salttype == salttype) ||
274		 (salttype < 0))) {
275		foundit = 1;
276		break;
277	    }
278	}
279    }
280    return(foundit);
281}
282
283/*
284 * krb5_string_to_keysalts()	- Convert a string representation to a list
285 *				  of key/salt tuples.
286 */
287krb5_error_code
288krb5_string_to_keysalts(string, tupleseps, ksaltseps, dups, ksaltp, nksaltp)
289    char		*string;
290    const char		*tupleseps;
291    const char		*ksaltseps;
292    krb5_boolean	dups;
293    krb5_key_salt_tuple	**ksaltp;
294    krb5_int32		*nksaltp;
295{
296    krb5_error_code	kret;
297    char 		*kp, *sp, *ep;
298    char		sepchar, trailchar;
299    krb5_enctype	ktype;
300    krb5_int32		stype;
301    krb5_key_salt_tuple	*savep;
302    const char		*tseplist;
303    const char		*ksseplist;
304    const char		*septmp;
305    size_t		len;
306
307    kret = 0;
308    kp = string;
309    tseplist = (tupleseps) ? tupleseps : default_tupleseps;
310    ksseplist = (ksaltseps) ? ksaltseps : default_ksaltseps;
311    while (kp) {
312	/* Attempt to find a separator */
313	ep = (char *) NULL;
314	if (*tseplist) {
315	    septmp = tseplist;
316	    for (ep = strchr(kp, (int) *septmp);
317		 *(++septmp) && !ep;
318		 ep = strchr(kp, (int) *septmp));
319	}
320
321	if (ep) {
322	    trailchar = *ep;
323	    *ep = '\0';
324	    ep++;
325	}
326	/*
327	 * kp points to something (hopefully) of the form:
328	 *	<enctype><ksseplist><salttype>
329	 *	or
330	 *	<enctype>
331	 */
332	sp = (char *) NULL;
333	/* Attempt to find a separator */
334	septmp = ksseplist;
335	for (sp = strchr(kp, (int) *septmp);
336	     *(++septmp) && !sp;
337	     sp = strchr(kp, (int)*septmp)); /* Solaris Kerberos */
338
339	if (sp) {
340	    /* Separate enctype from salttype */
341	    sepchar = *sp;
342	    *sp = '\0';
343	    sp++;
344	}
345	else
346	    stype = -1;
347
348	/*
349	 * Attempt to parse enctype and salttype.  If we parse well
350	 * then make sure that it specifies a unique key/salt combo
351	 */
352	if (!(kret = krb5_string_to_enctype(kp, &ktype)) &&
353	    (!sp || !(kret = krb5_string_to_salttype(sp, &stype))) &&
354	    (dups ||
355	     !krb5_keysalt_is_present(*ksaltp, *nksaltp, ktype, stype))) {
356
357	    /* Squirrel away old keysalt array */
358	    savep = *ksaltp;
359	    len = (size_t) *nksaltp;
360
361	    /* Get new keysalt array */
362	    *ksaltp = (krb5_key_salt_tuple *)
363		malloc((len + 1) * sizeof(krb5_key_salt_tuple));
364	    if (*ksaltp) {
365
366		/* Copy old keysalt if appropriate */
367		if (savep) {
368		    memcpy(*ksaltp, savep,
369			   len * sizeof(krb5_key_salt_tuple));
370		    krb5_xfree(savep);
371		}
372
373		/* Save our values */
374		(*ksaltp)[(*nksaltp)].ks_enctype = ktype;
375		(*ksaltp)[(*nksaltp)].ks_salttype = stype;
376		(*nksaltp)++;
377	    }
378	    else {
379		*ksaltp = savep;
380		break;
381	    }
382	}
383	/*
384	 * Solaris Kerberos
385	 * If the string did not yield a valid enctype/keysalt
386	 * just ignore it and continue on.  MIT kerberos stops
387	 * searching when if finds an unknown string.
388	 */
389	if (sp)
390	    sp[-1] = sepchar;
391	if (ep)
392	    ep[-1] = trailchar;
393	kp = ep;
394
395	/* Skip over extra separators - like spaces */
396	if (kp && *tseplist) {
397	  septmp = tseplist;
398	  while(*septmp && *kp) {
399	    if(*septmp == *kp) {
400	      /* Increment string - reset separator list */
401	      kp++;
402	      septmp = tseplist;
403	    } else {
404	      septmp++;
405	    }
406	  }
407	  if (!*kp) kp = NULL;
408	}
409    } /* while kp */
410    return(kret);
411}
412
413/*
414 * krb5_keysalt_iterate()	- Do something for each unique key/salt
415 *				  combination.
416 *
417 * If ignoresalt set, then salttype is ignored.
418 */
419krb5_error_code
420krb5_keysalt_iterate(ksaltlist, nksalt, ignoresalt, iterator, arg)
421    krb5_key_salt_tuple	*ksaltlist;
422    krb5_int32		nksalt;
423    krb5_boolean	ignoresalt;
424    krb5_error_code	(*iterator) (krb5_key_salt_tuple *, krb5_pointer);
425    krb5_pointer	arg;
426{
427    int			i;
428    krb5_error_code	kret;
429    krb5_key_salt_tuple	scratch;
430
431    kret = 0;
432    for (i=0; i<nksalt; i++) {
433	scratch.ks_enctype = ksaltlist[i].ks_enctype;
434	scratch.ks_salttype = (ignoresalt) ? -1 : ksaltlist[i].ks_salttype;
435	if (!krb5_keysalt_is_present(ksaltlist,
436				     i,
437				     scratch.ks_enctype,
438				     scratch.ks_salttype)) {
439	    kret = (*iterator)(&scratch, arg);
440	    if (kret)
441		break;
442	}
443    }
444    return(kret);
445}
446