Imported Upstream version 1.20.1
[platform/upstream/krb5.git] / src / lib / krb5 / krb / str_conv.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/str_conv.c - Convert between strings and krb5 data types */
3 /*
4  * Copyright 1995, 1999, 2007 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26
27 /*
28  * Table of contents:
29  *
30  * String decoding:
31  * ----------------
32  * krb5_string_to_salttype()    - Convert string to salttype (krb5_int32)
33  * krb5_string_to_timestamp()   - Convert string to krb5_timestamp.
34  * krb5_string_to_deltat()      - Convert string to krb5_deltat.
35  *
36  * String encoding:
37  * ----------------
38  * krb5_salttype_to_string()    - Convert salttype (krb5_int32) to string.
39  * krb5_timestamp_to_string()   - Convert krb5_timestamp to string.
40  * krb5_timestamp_to_sfstring() - Convert krb5_timestamp to short filled string
41  * krb5_deltat_to_string()      - Convert krb5_deltat to string.
42  */
43
44 #include "k5-int.h"
45 #include <ctype.h>
46
47 /* Salt type conversions */
48
49 /*
50  * Local data structures.
51  */
52 struct salttype_lookup_entry {
53     krb5_int32          stt_enctype;            /* Salt type number */
54     const char *        stt_name;               /* Salt type name */
55 };
56
57 /*
58  * Lookup tables.
59  */
60
61 #include "kdb.h"
62 static const struct salttype_lookup_entry salttype_table[] = {
63     { KRB5_KDB_SALTTYPE_NORMAL,     "normal"     },
64     { KRB5_KDB_SALTTYPE_NOREALM,    "norealm",   },
65     { KRB5_KDB_SALTTYPE_ONLYREALM,  "onlyrealm", },
66     { KRB5_KDB_SALTTYPE_SPECIAL,    "special",   },
67 };
68 static const int salttype_table_nents = sizeof(salttype_table)/
69     sizeof(salttype_table[0]);
70
71 krb5_error_code KRB5_CALLCONV
72 krb5_string_to_salttype(char *string, krb5_int32 *salttypep)
73 {
74     int i;
75     int found;
76
77     found = 0;
78     for (i=0; i<salttype_table_nents; i++) {
79         if (!strcasecmp(string, salttype_table[i].stt_name)) {
80             found = 1;
81             *salttypep = salttype_table[i].stt_enctype;
82             break;
83         }
84     }
85     return((found) ? 0 : EINVAL);
86 }
87
88 /*
89  * Internal datatype to string routines.
90  *
91  * These routines return 0 for success, EINVAL for invalid parameter, ENOMEM
92  * if the supplied buffer/length will not contain the output.
93  */
94 krb5_error_code KRB5_CALLCONV
95 krb5_salttype_to_string(krb5_int32 salttype, char *buffer, size_t buflen)
96 {
97     int i;
98     const char *out;
99
100     out = (char *) NULL;
101     for (i=0; i<salttype_table_nents; i++) {
102         if (salttype ==  salttype_table[i].stt_enctype) {
103             out = salttype_table[i].stt_name;
104             break;
105         }
106     }
107     if (out) {
108         if (strlcpy(buffer, out, buflen) >= buflen)
109             return(ENOMEM);
110         return(0);
111     }
112     else
113         return(EINVAL);
114 }
115
116 /* (absolute) time conversions */
117
118 #ifdef HAVE_STRPTIME
119 #ifdef NEED_STRPTIME_PROTO
120 extern char *strptime (const char *, const char *,
121                        struct tm *)
122 #ifdef __cplusplus
123     throw()
124 #endif
125     ;
126 #endif
127 #else /* HAVE_STRPTIME */
128 #undef strptime
129 #define strptime my_strptime
130 static char *strptime (const char *, const char *, struct tm *);
131 #endif
132
133 #ifndef HAVE_LOCALTIME_R
134 static inline struct tm *
135 localtime_r(const time_t *t, struct tm *buf)
136 {
137     struct tm *tm = localtime(t);
138     if (tm == NULL)
139         return NULL;
140     *buf = *tm;
141     return buf;
142 }
143 #endif
144
145 krb5_error_code KRB5_CALLCONV
146 krb5_string_to_timestamp(char *string, krb5_timestamp *timestampp)
147 {
148     int i;
149     struct tm timebuf, timebuf2;
150     time_t now, ret_time;
151     char *s;
152     static const char * const atime_format_table[] = {
153         "%Y%m%d%H%M%S",         /* yyyymmddhhmmss               */
154         "%Y.%m.%d.%H.%M.%S",    /* yyyy.mm.dd.hh.mm.ss          */
155         "%y%m%d%H%M%S",         /* yymmddhhmmss                 */
156         "%y.%m.%d.%H.%M.%S",    /* yy.mm.dd.hh.mm.ss            */
157         "%y%m%d%H%M",           /* yymmddhhmm                   */
158         "%H%M%S",               /* hhmmss                       */
159         "%H%M",                 /* hhmm                         */
160         "%T",                   /* hh:mm:ss                     */
161         "%R",                   /* hh:mm                        */
162         /* The following not really supported unless native strptime present */
163         "%x:%X",                /* locale-dependent short format */
164         "%d-%b-%Y:%T",          /* dd-month-yyyy:hh:mm:ss       */
165         "%d-%b-%Y:%R"           /* dd-month-yyyy:hh:mm          */
166     };
167     static const int atime_format_table_nents =
168         sizeof(atime_format_table)/sizeof(atime_format_table[0]);
169
170
171     now = time((time_t *) NULL);
172     if (localtime_r(&now, &timebuf2) == NULL)
173         return EINVAL;
174     for (i=0; i<atime_format_table_nents; i++) {
175         /* We reset every time throughout the loop as the manual page
176          * indicated that no guarantees are made as to preserving timebuf
177          * when parsing fails
178          */
179         timebuf = timebuf2;
180         if ((s = strptime(string, atime_format_table[i], &timebuf))
181             && (s != string)) {
182             /* See if at end of buffer - otherwise partial processing */
183             while(*s != 0 && isspace((int) *s)) s++;
184             if (*s != 0)
185                 continue;
186             if (timebuf.tm_year <= 0)
187                 continue;       /* clearly confused */
188             ret_time = mktime(&timebuf);
189             if (ret_time == (time_t) -1)
190                 continue;       /* clearly confused */
191             *timestampp = (krb5_timestamp) ret_time;
192             return 0;
193         }
194     }
195     return(EINVAL);
196 }
197
198 krb5_error_code KRB5_CALLCONV
199 krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen)
200 {
201     size_t ret;
202     time_t timestamp2 = ts2tt(timestamp);
203     struct tm tmbuf;
204     const char *fmt = "%c"; /* This is to get around gcc -Wall warning that
205                                the year returned might be two digits */
206
207     if (localtime_r(&timestamp2, &tmbuf) == NULL)
208         return(ENOMEM);
209     ret = strftime(buffer, buflen, fmt, &tmbuf);
210     if (ret == 0 || ret == buflen)
211         return(ENOMEM);
212     return(0);
213 }
214
215 krb5_error_code KRB5_CALLCONV
216 krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen, char *pad)
217 {
218     struct tm   *tmp;
219     size_t i;
220     size_t      ndone;
221     time_t timestamp2 = ts2tt(timestamp);
222     struct tm tmbuf;
223
224     static const char * const sftime_format_table[] = {
225         "%c",                   /* Default locale-dependent date and time */
226         "%d %b %Y %T",          /* dd mon yyyy hh:mm:ss                 */
227         "%x %X",                /* locale-dependent short format        */
228         "%x %T",                /* locale-dependent date + hh:mm:ss     */
229         "%x %R",                /* locale-dependent date + hh:mm        */
230         "%Y-%m-%dT%H:%M:%S",    /* ISO 8601 date + time                 */
231         "%Y-%m-%dT%H:%M",       /* ISO 8601 date + hh:mm                */
232         "%Y%m%d%H%M%S",         /* ISO 8601 date + time, basic          */
233         "%Y%m%d%H%M"            /* ISO 8601 date + hh:mm, basic         */
234     };
235     static const unsigned int sftime_format_table_nents =
236         sizeof(sftime_format_table)/sizeof(sftime_format_table[0]);
237
238     tmp = localtime_r(&timestamp2, &tmbuf);
239     if (tmp == NULL)
240         return errno;
241     ndone = 0;
242     for (i=0; i<sftime_format_table_nents; i++) {
243         if ((ndone = strftime(buffer, buflen, sftime_format_table[i], tmp)))
244             break;
245     }
246     if (ndone && pad) {
247         for (i=ndone; i<buflen-1; i++)
248             buffer[i] = *pad;
249         buffer[buflen-1] = '\0';
250     }
251     return((ndone) ? 0 : ENOMEM);
252 }
253
254 /* relative time (delta-t) conversions */
255
256 /* string->deltat is in deltat.y */
257
258 krb5_error_code KRB5_CALLCONV
259 krb5_deltat_to_string(krb5_deltat deltat, char *buffer, size_t buflen)
260 {
261     int                 days, hours, minutes, seconds;
262     krb5_deltat         dt;
263
264     days = (int) (deltat / (24*3600L));
265     dt = deltat % (24*3600L);
266     hours = (int) (dt / 3600);
267     dt %= 3600;
268     minutes = (int) (dt / 60);
269     seconds = (int) (dt % 60);
270
271     if (days == 0)
272         snprintf(buffer, buflen, "%d:%02d:%02d", hours, minutes, seconds);
273     else if (hours || minutes || seconds)
274         snprintf(buffer, buflen, "%d %s %02d:%02d:%02d", days,
275                  (days > 1) ? "days" : "day",
276                  hours, minutes, seconds);
277     else
278         snprintf(buffer, buflen, "%d %s", days,
279                  (days > 1) ? "days" : "day");
280     return 0;
281 }
282
283 #undef __P
284 #define __P(X) X
285
286 #ifndef HAVE_STRPTIME
287 #undef _CurrentTimeLocale
288 #define _CurrentTimeLocale (&dummy_locale_info)
289
290 struct dummy_locale_info_t {
291     char d_t_fmt[15];
292     char t_fmt_ampm[12];
293     char t_fmt[9];
294     char d_fmt[9];
295     char day[7][10];
296     char abday[7][4];
297     char mon[12][10];
298     char abmon[12][4];
299     char am_pm[2][3];
300 };
301 static const struct dummy_locale_info_t dummy_locale_info = {
302     "%a %b %d %X %Y",           /* %c */
303     "%I:%M:%S %p",              /* %r */
304     "%H:%M:%S",                 /* %X */
305     "%m/%d/%y",                 /* %x */
306     { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
307       "Saturday" },
308     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
309     { "January", "February", "March", "April", "May", "June",
310       "July", "August", "September", "October", "November", "December" },
311     { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
312       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
313     { "AM", "PM" },
314 };
315 #undef  TM_YEAR_BASE
316 #define TM_YEAR_BASE 1900
317
318 #include "strptime.c"
319 #endif