Home | History | Annotate | Download | only in krb
      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 */
    136 
    137 #ifndef HAVE_STRFTIME
    138 #undef strftime
    139 #define strftime my_strftime
    140 static size_t strftime (char *, size_t, const char *, const struct tm *);
    141 #endif
    142 
    143 #ifdef HAVE_STRPTIME
    144 #ifdef NEED_STRPTIME_PROTO
    145 extern char *strptime (const char *, const char *,
    146 			    struct tm *)
    147 #ifdef __cplusplus
    148     throw()
    149 #endif
    150     ;
    151 #endif
    152 #else /* HAVE_STRPTIME */
    153 #undef strptime
    154 #define strptime my_strptime
    155 static char *strptime (const char *, const char *, struct tm *);
    156 #endif
    157 
    158 krb5_error_code KRB5_CALLCONV
    159 krb5_string_to_timestamp(char *string, krb5_timestamp *timestampp)
    160 {
    161     int i;
    162     struct tm timebuf;
    163     time_t now, ret_time;
    164     char *s;
    165     static const char * const atime_format_table[] = {
    166 	"%Y%m%d%H%M%S",		/* yyyymmddhhmmss		*/
    167 	"%Y.%m.%d.%H.%M.%S",	/* yyyy.mm.dd.hh.mm.ss		*/
    168 	"%y%m%d%H%M%S",		/* yymmddhhmmss			*/
    169 	"%y.%m.%d.%H.%M.%S",	/* yy.mm.dd.hh.mm.ss		*/
    170 	"%y%m%d%H%M",		/* yymmddhhmm			*/
    171 	"%H%M%S",		/* hhmmss			*/
    172 	"%H%M",			/* hhmm				*/
    173 	"%T",			/* hh:mm:ss			*/
    174 	"%R",			/* hh:mm			*/
    175 	/* The following not really supported unless native strptime present */
    176 	"%x:%X",		/* locale-dependent short format */
    177 	"%d-%b-%Y:%T",		/* dd-month-yyyy:hh:mm:ss	*/
    178 	"%d-%b-%Y:%R"		/* dd-month-yyyy:hh:mm		*/
    179     };
    180     static const int atime_format_table_nents =
    181 	sizeof(atime_format_table)/sizeof(atime_format_table[0]);
    182 
    183 
    184     now = time((time_t *) NULL);
    185     for (i=0; i<atime_format_table_nents; i++) {
    186         /* We reset every time throughout the loop as the manual page
    187 	 * indicated that no guarantees are made as to preserving timebuf
    188 	 * when parsing fails
    189 	 */
    190 #ifdef HAVE_LOCALTIME_R
    191 	(void) localtime_r(&now, &timebuf);
    192 #else
    193 	memcpy(&timebuf, localtime(&now), sizeof(timebuf));
    194 #endif
    195 	/*LINTED*/
    196 	if ((s = strptime(string, atime_format_table[i], &timebuf))
    197 	    && (s != string)) {
    198  	    /* See if at end of buffer - otherwise partial processing */
    199 	    while(*s != 0 && isspace((int) *s)) s++;
    200 	    if (*s != 0)
    201 	        continue;
    202 	    if (timebuf.tm_year <= 0)
    203 		continue;	/* clearly confused */
    204 	    ret_time = mktime(&timebuf);
    205 	    if (ret_time == (time_t) -1)
    206 		continue;	/* clearly confused */
    207 	    *timestampp = (krb5_timestamp) ret_time;
    208 	    return 0;
    209 	}
    210     }
    211     return(EINVAL);
    212 }
    213 
    214 krb5_error_code KRB5_CALLCONV
    215 krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen)
    216 {
    217     int ret;
    218     time_t timestamp2 = timestamp;
    219     struct tm tmbuf;
    220     const char *fmt = "%c"; /* This is to get around gcc -Wall warning that
    221 			       the year returned might be two digits */
    222 
    223 #ifdef HAVE_LOCALTIME_R
    224     (void) localtime_r(&timestamp2, &tmbuf);
    225 #else
    226     memcpy(&tmbuf, localtime(&timestamp2), sizeof(tmbuf));
    227 #endif
    228     ret = strftime(buffer, buflen, fmt, &tmbuf);
    229     if (ret == 0 || ret == buflen)
    230 	return(ENOMEM);
    231     return(0);
    232 }
    233 
    234 krb5_error_code KRB5_CALLCONV
    235 krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen, char *pad)
    236 {
    237     struct tm	*tmp;
    238     size_t i;
    239     size_t	ndone;
    240     time_t timestamp2 = timestamp;
    241     struct tm tmbuf;
    242 
    243     static const char * const sftime_format_table[] = {
    244 	"%c",			/* Default locale-dependent date and time */
    245 	"%d %b %Y %T",		/* dd mon yyyy hh:mm:ss			*/
    246 	"%x %X",		/* locale-dependent short format	*/
    247 	"%d/%m/%Y %R"		/* dd/mm/yyyy hh:mm			*/
    248     };
    249     static const int sftime_format_table_nents =
    250 	sizeof(sftime_format_table)/sizeof(sftime_format_table[0]);
    251 
    252 #ifdef HAVE_LOCALTIME_R
    253     tmp = localtime_r(&timestamp2, &tmbuf);
    254 #else
    255     memcpy((tmp = &tmbuf), localtime(&timestamp2), sizeof(tmbuf));
    256 #endif
    257     ndone = 0;
    258     for (i=0; i<sftime_format_table_nents; i++) {
    259 	if ((ndone = strftime(buffer, buflen, sftime_format_table[i], tmp)))
    260 	    break;
    261     }
    262     if (!ndone) {
    263 #define sftime_default_len	2+1+2+1+4+1+2+1+2+1
    264 	if (buflen >= sftime_default_len) {
    265 	    sprintf(buffer, "%02d/%02d/%4d %02d:%02d",
    266 		    tmp->tm_mday, tmp->tm_mon+1, 1900+tmp->tm_year,
    267 		    tmp->tm_hour, tmp->tm_min);
    268 	    ndone = strlen(buffer);
    269 	}
    270     }
    271     if (ndone && pad) {
    272 	for (i=ndone; i<buflen-1; i++)
    273 	    buffer[i] = *pad;
    274 	buffer[buflen-1] = '\0';
    275     }
    276     return((ndone) ? 0 : ENOMEM);
    277 }
    278 
    279 /* Solaris Kerberos */
    281 #ifdef SUNW_INC_DEAD_CODE
    282 /* relative time (delta-t) conversions */
    283 
    284 /* string->deltat is in deltat.y */
    285 
    286 krb5_error_code KRB5_CALLCONV
    287 krb5_deltat_to_string(krb5_deltat deltat, char *buffer, size_t buflen)
    288 {
    289     int			days, hours, minutes, seconds;
    290     krb5_deltat		dt;
    291 
    292     /*
    293      * We want something like ceil(log10(2**(nbits-1))) + 1.  That log
    294      * value is log10(2)*(nbits-1) or log10(2**8)*(nbits-1)/8.  So,
    295      * 2.4... is log10(256), rounded up.  Add one to handle leading
    296      * minus, and one more to force int cast to round the value up.
    297      * This doesn't include room for a trailing nul.
    298      *
    299      * This will break if bytes are more than 8 bits.
    300      */
    301 #define MAX_CHARS_FOR_INT_TYPE(TYPE)	((int) (2 + 2.408241 * sizeof (TYPE)))
    302     char tmpbuf[MAX_CHARS_FOR_INT_TYPE(int) * 4 + 8];
    303 
    304     days = (int) (deltat / (24*3600L));
    305     dt = deltat % (24*3600L);
    306     hours = (int) (dt / 3600);
    307     dt %= 3600;
    308     minutes = (int) (dt / 60);
    309     seconds = (int) (dt % 60);
    310 
    311     memset (tmpbuf, 0, sizeof (tmpbuf));
    312     if (days == 0)
    313 	sprintf(buffer, "%d:%02d:%02d", hours, minutes, seconds);
    314     else if (hours || minutes || seconds)
    315 	sprintf(buffer, "%d %s %02d:%02d:%02d", days,
    316 		(days > 1) ? "days" : "day",
    317 		hours, minutes, seconds);
    318     else
    319 	sprintf(buffer, "%d %s", days,
    320 		(days > 1) ? "days" : "day");
    321     if (tmpbuf[sizeof(tmpbuf)-1] != 0)
    322 	/* Something must be very wrong with my math above, or the
    323 	   assumptions going into it...  */
    324 	abort ();
    325     if (strlen (tmpbuf) > buflen)
    326 	return ENOMEM;
    327     else
    328 	strncpy (buffer, tmpbuf, buflen);
    329     return 0;
    330 }
    331 #endif /* SUNW_INC_DEAD_CODE */
    332 
    333 #undef __P
    334 #define __P(X) X
    335 
    336 #if !defined (HAVE_STRFTIME) || !defined (HAVE_STRPTIME)
    337 #undef _CurrentTimeLocale
    338 #define _CurrentTimeLocale (&dummy_locale_info)
    339 
    340 struct dummy_locale_info_t {
    341     char d_t_fmt[15];
    342     char t_fmt_ampm[12];
    343     char t_fmt[9];
    344     char d_fmt[9];
    345     char day[7][10];
    346     char abday[7][4];
    347     char mon[12][10];
    348     char abmon[12][4];
    349     char am_pm[2][3];
    350 };
    351 static const struct dummy_locale_info_t dummy_locale_info = {
    352     "%a %b %d %X %Y",		/* %c */
    353     "%I:%M:%S %p",		/* %r */
    354     "%H:%M:%S",			/* %X */
    355     "%m/%d/%y",			/* %x */
    356     { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
    357       "Saturday" },
    358     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
    359     { "January", "February", "March", "April", "May", "June",
    360       "July", "August", "September", "October", "November", "December" },
    361     { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    362       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
    363     { "AM", "PM" },
    364 };
    365 #undef  TM_YEAR_BASE
    366 #define TM_YEAR_BASE 1900
    367 #endif
    368 
    369 #ifndef HAVE_STRFTIME
    370 #undef  DAYSPERLYEAR
    371 #define DAYSPERLYEAR 366
    372 #undef  DAYSPERNYEAR
    373 #define DAYSPERNYEAR 365
    374 #undef  DAYSPERWEEK
    375 #define DAYSPERWEEK 7
    376 #undef  isleap
    377 #define isleap(N)	((N % 4) == 0 && (N % 100 != 0 || N % 400 == 0))
    378 #undef  tzname
    379 #define tzname my_tzname
    380 static const char *const tzname[2] = { 0, 0 };
    381 #undef  tzset
    382 #define tzset()
    383 
    384 #include "strftime.c"
    385 #endif
    386 
    387 #ifndef HAVE_STRPTIME
    388 #include "strptime.c"
    389 #endif
    390