xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/str_conv.c (revision 159d09a20817016f09b3ea28d1bdada4a336bb91)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 
7 /*
8  * lib/kadm/str_conv.c
9  *
10  * Copyright 1995, 1999 by the Massachusetts Institute of Technology.
11  * All Rights Reserved.
12  *
13  * Export of this software from the United States of America may
14  *   require a specific license from the United States Government.
15  *   It is the responsibility of any person or organization contemplating
16  *   export to obtain such a license before exporting.
17  *
18  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19  * distribute this software and its documentation for any purpose and
20  * without fee is hereby granted, provided that the above copyright
21  * notice appear in all copies and that both that copyright notice and
22  * this permission notice appear in supporting documentation, and that
23  * the name of M.I.T. not be used in advertising or publicity pertaining
24  * to distribution of the software without specific, written prior
25  * permission.  Furthermore if you modify this software you must label
26  * your software as modified software and not distribute it in such a
27  * fashion that it might be confused with the original M.I.T. software.
28  * M.I.T. makes no representations about the suitability of
29  * this software for any purpose.  It is provided "as is" without express
30  * or implied warranty.
31  *
32  */
33 
34 /*
35  * str_conv.c - Convert between strings and Kerberos internal data.
36  */
37 
38 /*
39  * Table of contents:
40  *
41  * String decoding:
42  * ----------------
43  * krb5_string_to_salttype()	- Convert string to salttype (krb5_int32)
44  * krb5_string_to_timestamp()	- Convert string to krb5_timestamp.
45  * krb5_string_to_deltat()	- Convert string to krb5_deltat.
46  *
47  * String encoding:
48  * ----------------
49  * krb5_salttype_to_string()	- Convert salttype (krb5_int32) to string.
50  * krb5_timestamp_to_string()	- Convert krb5_timestamp to string.
51  * krb5_timestamp_to_sfstring()	- Convert krb5_timestamp to short filled string
52  * krb5_deltat_to_string()	- Convert krb5_deltat to string.
53  */
54 
55 #include "k5-int.h"
56 #include <ctype.h>
57 
58 /* Salt type conversions */
59 
60 /*
61  * Local data structures.
62  */
63 struct salttype_lookup_entry {
64     krb5_int32		stt_enctype;		/* Salt type		*/
65     const char *	stt_specifier;		/* How to recognize it	*/
66     const char *	stt_output;		/* How to spit it out	*/
67 };
68 
69 /*
70  * Lookup tables.
71  */
72 
73 #include "kdb.h"
74 static const struct salttype_lookup_entry salttype_table[] = {
75 /* salt type			input specifier	output string  */
76 /*-----------------------------	--------------- ---------------*/
77 { KRB5_KDB_SALTTYPE_NORMAL,	"normal",	"Version 5"	  },
78 { KRB5_KDB_SALTTYPE_V4,		"v4",		"Version 4"	  },
79 { KRB5_KDB_SALTTYPE_NOREALM,	"norealm",	"Version 5 - No Realm" },
80 { KRB5_KDB_SALTTYPE_ONLYREALM,	"onlyrealm",	"Version 5 - Realm Only" },
81 { KRB5_KDB_SALTTYPE_SPECIAL,	"special",	"Special" },
82 { KRB5_KDB_SALTTYPE_AFS3,	"afs3",		"AFS version 3"    }
83 };
84 static const int salttype_table_nents = sizeof(salttype_table)/
85 					sizeof(salttype_table[0]);
86 
87 krb5_error_code KRB5_CALLCONV
88 krb5_string_to_salttype(char *string, krb5_int32 *salttypep)
89 {
90     int i;
91     int found;
92 
93     found = 0;
94     for (i=0; i<salttype_table_nents; i++) {
95 	if (!strcasecmp(string, salttype_table[i].stt_specifier)) {
96 	    found = 1;
97 	    *salttypep = salttype_table[i].stt_enctype;
98 	    break;
99 	}
100     }
101     return((found) ? 0 : EINVAL);
102 }
103 
104 /*
105  * Internal datatype to string routines.
106  *
107  * These routines return 0 for success, EINVAL for invalid parameter, ENOMEM
108  * if the supplied buffer/length will not contain the output.
109  */
110 krb5_error_code KRB5_CALLCONV
111 krb5_salttype_to_string(krb5_int32 salttype, char *buffer, size_t buflen)
112 {
113     int i;
114     const char *out;
115 
116     out = (char *) NULL;
117     for (i=0; i<salttype_table_nents; i++) {
118 	if (salttype ==  salttype_table[i].stt_enctype) {
119 	    out = salttype_table[i].stt_output;
120 	    break;
121 	}
122     }
123     if (out) {
124 	if (buflen > strlen(out))
125 	    strcpy(buffer, out);
126 	else
127 	    out = (char *) NULL;
128 	return((out) ? 0 : ENOMEM);
129     }
130     else
131 	return(EINVAL);
132 }
133 
134 /* (absolute) time conversions */
135 
136 #ifndef HAVE_STRFTIME
137 #undef strftime
138 #define strftime my_strftime
139 static size_t strftime (char *, size_t, const char *, const struct tm *);
140 #endif
141 
142 #ifdef HAVE_STRPTIME
143 #ifdef NEED_STRPTIME_PROTO
144 extern char *strptime (const char *, const char *,
145 			    struct tm *)
146 #ifdef __cplusplus
147     throw()
148 #endif
149     ;
150 #endif
151 #else /* HAVE_STRPTIME */
152 #undef strptime
153 #define strptime my_strptime
154 static char *strptime (const char *, const char *, struct tm *);
155 #endif
156 
157 krb5_error_code KRB5_CALLCONV
158 krb5_string_to_timestamp(char *string, krb5_timestamp *timestampp)
159 {
160     int i;
161     struct tm timebuf;
162     time_t now, ret_time;
163     char *s;
164     static const char * const atime_format_table[] = {
165 	"%Y%m%d%H%M%S",		/* yyyymmddhhmmss		*/
166 	"%Y.%m.%d.%H.%M.%S",	/* yyyy.mm.dd.hh.mm.ss		*/
167 	"%y%m%d%H%M%S",		/* yymmddhhmmss			*/
168 	"%y.%m.%d.%H.%M.%S",	/* yy.mm.dd.hh.mm.ss		*/
169 	"%y%m%d%H%M",		/* yymmddhhmm			*/
170 	"%H%M%S",		/* hhmmss			*/
171 	"%H%M",			/* hhmm				*/
172 	"%T",			/* hh:mm:ss			*/
173 	"%R",			/* hh:mm			*/
174 	/* The following not really supported unless native strptime present */
175 	"%x:%X",		/* locale-dependent short format */
176 	"%d-%b-%Y:%T",		/* dd-month-yyyy:hh:mm:ss	*/
177 	"%d-%b-%Y:%R"		/* dd-month-yyyy:hh:mm		*/
178     };
179     static const int atime_format_table_nents =
180 	sizeof(atime_format_table)/sizeof(atime_format_table[0]);
181 
182 
183     now = time((time_t *) NULL);
184     for (i=0; i<atime_format_table_nents; i++) {
185         /* We reset every time throughout the loop as the manual page
186 	 * indicated that no guarantees are made as to preserving timebuf
187 	 * when parsing fails
188 	 */
189 #ifdef HAVE_LOCALTIME_R
190 	(void) localtime_r(&now, &timebuf);
191 #else
192 	memcpy(&timebuf, localtime(&now), sizeof(timebuf));
193 #endif
194 	/*LINTED*/
195 	if ((s = strptime(string, atime_format_table[i], &timebuf))
196 	    && (s != string)) {
197  	    /* See if at end of buffer - otherwise partial processing */
198 	    while(*s != 0 && isspace((int) *s)) s++;
199 	    if (*s != 0)
200 	        continue;
201 	    if (timebuf.tm_year <= 0)
202 		continue;	/* clearly confused */
203 	    ret_time = mktime(&timebuf);
204 	    if (ret_time == (time_t) -1)
205 		continue;	/* clearly confused */
206 	    *timestampp = (krb5_timestamp) ret_time;
207 	    return 0;
208 	}
209     }
210     return(EINVAL);
211 }
212 
213 krb5_error_code KRB5_CALLCONV
214 krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen)
215 {
216     int ret;
217     time_t timestamp2 = timestamp;
218     struct tm tmbuf;
219     const char *fmt = "%c"; /* This is to get around gcc -Wall warning that
220 			       the year returned might be two digits */
221 
222 #ifdef HAVE_LOCALTIME_R
223     (void) localtime_r(&timestamp2, &tmbuf);
224 #else
225     memcpy(&tmbuf, localtime(&timestamp2), sizeof(tmbuf));
226 #endif
227     ret = strftime(buffer, buflen, fmt, &tmbuf);
228     if (ret == 0 || ret == buflen)
229 	return(ENOMEM);
230     return(0);
231 }
232 
233 krb5_error_code KRB5_CALLCONV
234 krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen, char *pad)
235 {
236     struct tm	*tmp;
237     size_t i;
238     size_t	ndone;
239     time_t timestamp2 = timestamp;
240     struct tm tmbuf;
241 
242     static const char * const sftime_format_table[] = {
243 	"%c",			/* Default locale-dependent date and time */
244 	"%d %b %Y %T",		/* dd mon yyyy hh:mm:ss			*/
245 	"%x %X",		/* locale-dependent short format	*/
246 	"%d/%m/%Y %R"		/* dd/mm/yyyy hh:mm			*/
247     };
248     static const int sftime_format_table_nents =
249 	sizeof(sftime_format_table)/sizeof(sftime_format_table[0]);
250 
251 #ifdef HAVE_LOCALTIME_R
252     tmp = localtime_r(&timestamp2, &tmbuf);
253 #else
254     memcpy((tmp = &tmbuf), localtime(&timestamp2), sizeof(tmbuf));
255 #endif
256     ndone = 0;
257     for (i=0; i<sftime_format_table_nents; i++) {
258 	if ((ndone = strftime(buffer, buflen, sftime_format_table[i], tmp)))
259 	    break;
260     }
261     if (!ndone) {
262 #define sftime_default_len	2+1+2+1+4+1+2+1+2+1
263 	if (buflen >= sftime_default_len) {
264 	    sprintf(buffer, "%02d/%02d/%4d %02d:%02d",
265 		    tmp->tm_mday, tmp->tm_mon+1, 1900+tmp->tm_year,
266 		    tmp->tm_hour, tmp->tm_min);
267 	    ndone = strlen(buffer);
268 	}
269     }
270     if (ndone && pad) {
271 	for (i=ndone; i<buflen-1; i++)
272 	    buffer[i] = *pad;
273 	buffer[buflen-1] = '\0';
274     }
275     return((ndone) ? 0 : ENOMEM);
276 }
277 
278 /* Solaris Kerberos */
279 #ifdef SUNW_INC_DEAD_CODE
280 /* relative time (delta-t) conversions */
281 
282 /* string->deltat is in deltat.y */
283 
284 krb5_error_code KRB5_CALLCONV
285 krb5_deltat_to_string(krb5_deltat deltat, char *buffer, size_t buflen)
286 {
287     int			days, hours, minutes, seconds;
288     krb5_deltat		dt;
289 
290     /*
291      * We want something like ceil(log10(2**(nbits-1))) + 1.  That log
292      * value is log10(2)*(nbits-1) or log10(2**8)*(nbits-1)/8.  So,
293      * 2.4... is log10(256), rounded up.  Add one to handle leading
294      * minus, and one more to force int cast to round the value up.
295      * This doesn't include room for a trailing nul.
296      *
297      * This will break if bytes are more than 8 bits.
298      */
299 #define MAX_CHARS_FOR_INT_TYPE(TYPE)	((int) (2 + 2.408241 * sizeof (TYPE)))
300     char tmpbuf[MAX_CHARS_FOR_INT_TYPE(int) * 4 + 8];
301 
302     days = (int) (deltat / (24*3600L));
303     dt = deltat % (24*3600L);
304     hours = (int) (dt / 3600);
305     dt %= 3600;
306     minutes = (int) (dt / 60);
307     seconds = (int) (dt % 60);
308 
309     memset (tmpbuf, 0, sizeof (tmpbuf));
310     if (days == 0)
311 	sprintf(buffer, "%d:%02d:%02d", hours, minutes, seconds);
312     else if (hours || minutes || seconds)
313 	sprintf(buffer, "%d %s %02d:%02d:%02d", days,
314 		(days > 1) ? "days" : "day",
315 		hours, minutes, seconds);
316     else
317 	sprintf(buffer, "%d %s", days,
318 		(days > 1) ? "days" : "day");
319     if (tmpbuf[sizeof(tmpbuf)-1] != 0)
320 	/* Something must be very wrong with my math above, or the
321 	   assumptions going into it...  */
322 	abort ();
323     if (strlen (tmpbuf) > buflen)
324 	return ENOMEM;
325     else
326 	strncpy (buffer, tmpbuf, buflen);
327     return 0;
328 }
329 #endif /* SUNW_INC_DEAD_CODE */
330 
331 #undef __P
332 #define __P(X) X
333 
334 #if !defined (HAVE_STRFTIME) || !defined (HAVE_STRPTIME)
335 #undef _CurrentTimeLocale
336 #define _CurrentTimeLocale (&dummy_locale_info)
337 
338 struct dummy_locale_info_t {
339     char d_t_fmt[15];
340     char t_fmt_ampm[12];
341     char t_fmt[9];
342     char d_fmt[9];
343     char day[7][10];
344     char abday[7][4];
345     char mon[12][10];
346     char abmon[12][4];
347     char am_pm[2][3];
348 };
349 static const struct dummy_locale_info_t dummy_locale_info = {
350     "%a %b %d %X %Y",		/* %c */
351     "%I:%M:%S %p",		/* %r */
352     "%H:%M:%S",			/* %X */
353     "%m/%d/%y",			/* %x */
354     { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
355       "Saturday" },
356     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
357     { "January", "February", "March", "April", "May", "June",
358       "July", "August", "September", "October", "November", "December" },
359     { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
360       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
361     { "AM", "PM" },
362 };
363 #undef  TM_YEAR_BASE
364 #define TM_YEAR_BASE 1900
365 #endif
366 
367 #ifndef HAVE_STRFTIME
368 #undef  DAYSPERLYEAR
369 #define DAYSPERLYEAR 366
370 #undef  DAYSPERNYEAR
371 #define DAYSPERNYEAR 365
372 #undef  DAYSPERWEEK
373 #define DAYSPERWEEK 7
374 #undef  isleap
375 #define isleap(N)	((N % 4) == 0 && (N % 100 != 0 || N % 400 == 0))
376 #undef  tzname
377 #define tzname my_tzname
378 static const char *const tzname[2] = { 0, 0 };
379 #undef  tzset
380 #define tzset()
381 
382 #include "strftime.c"
383 #endif
384 
385 #ifndef HAVE_STRPTIME
386 #include "strptime.c"
387 #endif
388