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