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
krb5_string_to_salttype(char * string,krb5_int32 * salttypep)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
krb5_salttype_to_string(krb5_int32 salttype,char * buffer,size_t buflen)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
krb5_string_to_timestamp(char * string,krb5_timestamp * timestampp)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
krb5_timestamp_to_string(krb5_timestamp timestamp,char * buffer,size_t buflen)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(×tamp2, &tmbuf);
224 #else
225 memcpy(&tmbuf, localtime(×tamp2), 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
krb5_timestamp_to_sfstring(krb5_timestamp timestamp,char * buffer,size_t buflen,char * pad)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(×tamp2, &tmbuf);
253 #else
254 memcpy((tmp = &tmbuf), localtime(×tamp2), 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
krb5_deltat_to_string(krb5_deltat deltat,char * buffer,size_t buflen)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