1 /* 2 * Copyright 2005 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 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 static const struct salttype_lookup_entry salttype_table[] = { 74 /* salt type input specifier output string */ 75 /*----------------------------- --------------- ---------------*/ 76 { KRB5_KDB_SALTTYPE_NORMAL, "normal", "Version 5" }, 77 { KRB5_KDB_SALTTYPE_V4, "v4", "Version 4" }, 78 { KRB5_KDB_SALTTYPE_NOREALM, "norealm", "Version 5 - No Realm" }, 79 { KRB5_KDB_SALTTYPE_ONLYREALM, "onlyrealm", "Version 5 - Realm Only" }, 80 { KRB5_KDB_SALTTYPE_SPECIAL, "special", "Special" }, 81 { KRB5_KDB_SALTTYPE_AFS3, "afs3", "AFS version 3" } 82 }; 83 static const int salttype_table_nents = sizeof(salttype_table)/ 84 sizeof(salttype_table[0]); 85 86 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 87 krb5_string_to_salttype(string, salttypep) 88 char FAR * string; 89 krb5_int32 FAR * salttypep; 90 { 91 int i; 92 int found; 93 94 found = 0; 95 for (i=0; i<salttype_table_nents; i++) { 96 if (!strcasecmp(string, salttype_table[i].stt_specifier)) { 97 found = 1; 98 *salttypep = salttype_table[i].stt_enctype; 99 break; 100 } 101 } 102 return((found) ? 0 : EINVAL); 103 } 104 105 /* 106 * Internal datatype to string routines. 107 * 108 * These routines return 0 for success, EINVAL for invalid parameter, ENOMEM 109 * if the supplied buffer/length will not contain the output. 110 */ 111 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 112 krb5_salttype_to_string(salttype, buffer, buflen) 113 krb5_int32 salttype; 114 char FAR * buffer; 115 size_t buflen; 116 { 117 int i; 118 const char *out; 119 120 out = (char *) NULL; 121 for (i=0; i<salttype_table_nents; i++) { 122 if (salttype == salttype_table[i].stt_enctype) { 123 out = salttype_table[i].stt_output; 124 break; 125 } 126 } 127 if (out) { 128 if (buflen > strlen(out)) 129 strcpy(buffer, out); 130 else 131 out = (char *) NULL; 132 return((out) ? 0 : ENOMEM); 133 } 134 else 135 return(EINVAL); 136 } 137 138 /* (absolute) time conversions */ 139 140 #ifndef HAVE_STRFTIME 141 #undef strftime 142 #define strftime my_strftime 143 static size_t strftime (char *, size_t, const char *, const struct tm *); 144 #endif 145 146 #ifndef HAVE_STRPTIME 147 #undef strptime 148 #define strptime my_strptime 149 static char *strptime (const char *, const char *, struct tm *); 150 #endif 151 152 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 153 krb5_string_to_timestamp(string, timestampp) 154 char FAR * string; 155 krb5_timestamp FAR * timestampp; 156 { 157 int i,found; 158 struct tm timebuf, nowbuf; 159 time_t now; 160 char *s; 161 static const char * const atime_format_table[] = { 162 "%Y" "%m%d%H" "%M" "%S",/* yyyymmddhhmmss */ 163 "%Y.%m.%d.%H.%M.%S", /* yyyy.mm.dd.hh.mm.ss */ 164 "%y%m%d%H" "%M" "%S", /* yymmddhhmmss */ 165 "%y.%m.%d.%H.%M.%S", /* yy.mm.dd.hh.mm.ss */ 166 "%y%m%d%H" "%M", /* yymmddhhmm */ 167 "%H" "%M" "%S", /* hhmmss */ 168 "%H" "%M", /* hhmm */ 169 "%T", /* hh:mm:ss */ 170 "%R", /* hh:mm */ 171 /* The following not really supported unless native strptime present */ 172 "%x:%X", /* locale-dependent short format */ 173 "%d-%b-%Y:%T", /* dd-month-yyyy:hh:mm:ss */ 174 "%d-%b-%Y:%R" /* dd-month-yyyy:hh:mm */ 175 }; 176 static const int atime_format_table_nents = 177 sizeof(atime_format_table)/sizeof(atime_format_table[0]); 178 179 found = 0; 180 for (i=0; i<atime_format_table_nents; i++) { 181 s = strptime(string, atime_format_table[i], &timebuf); 182 /* make sure the entire string was parsed */ 183 if (s && (*s == '\0')) { 184 /* If only time and no date was provided, assume today */ 185 if ((timebuf.tm_mday == 0) && (timebuf.tm_mon == 0) && 186 (timebuf.tm_year == 0)) { 187 now = time((time_t *) NULL); 188 (void) memcpy(&nowbuf, localtime(&now), sizeof(timebuf)); 189 timebuf.tm_mday = nowbuf.tm_mday; 190 timebuf.tm_mon = nowbuf.tm_mon; 191 timebuf.tm_year = nowbuf.tm_year; 192 } 193 found = 1; 194 break; 195 } 196 } 197 if (found) { 198 if ((*timestampp = (krb5_timestamp) mktime(&timebuf)) != -1) { 199 if (timebuf.tm_isdst == 1) { 200 *timestampp -= (timezone - altzone); 201 } 202 return (0); 203 } 204 } 205 return(EINVAL); 206 } 207 208 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 209 krb5_timestamp_to_string(timestamp, buffer, buflen) 210 krb5_timestamp timestamp; 211 char FAR * buffer; 212 size_t buflen; 213 { 214 int ret; 215 time_t timestamp2 = timestamp; 216 217 ret = strftime(buffer, buflen, "%c", localtime(×tamp2)); 218 if (ret == 0 || ret == buflen) 219 return(ENOMEM); 220 return(0); 221 } 222 223 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 224 krb5_timestamp_to_sfstring(timestamp, buffer, buflen, pad) 225 krb5_timestamp timestamp; 226 char FAR * buffer; 227 size_t buflen; 228 char FAR * pad; 229 { 230 struct tm *tmp; 231 size_t i; 232 size_t ndone; 233 time_t timestamp2 = timestamp; 234 235 static const char * const sftime_format_table[] = { 236 "%c", /* Default locale-dependent date and time */ 237 "%d %b %Y %T", /* dd mon yyyy hh:mm:ss */ 238 "%x %X", /* locale-dependent short format */ 239 "%d/%m/%Y %R" /* dd/mm/yyyy hh:mm */ 240 }; 241 static const int sftime_format_table_nents = 242 sizeof(sftime_format_table)/sizeof(sftime_format_table[0]); 243 244 tmp = localtime(×tamp2); 245 ndone = 0; 246 for (i=0; i<sftime_format_table_nents; i++) { 247 if ((ndone = strftime(buffer, buflen, sftime_format_table[i], tmp))) 248 break; 249 } 250 if (!ndone) { 251 #define sftime_default_len 2+1+2+1+4+1+2+1+2+1 252 if (buflen >= sftime_default_len) { 253 sprintf(buffer, "%02d/%02d/%4d %02d:%02d", 254 tmp->tm_mday, tmp->tm_mon+1, 1900+tmp->tm_year, 255 tmp->tm_hour, tmp->tm_min); 256 ndone = strlen(buffer); 257 } 258 } 259 if (ndone && pad) { 260 for (i=ndone; i<buflen-1; i++) 261 buffer[i] = *pad; 262 buffer[buflen-1] = '\0'; 263 } 264 return((ndone) ? 0 : ENOMEM); 265 } 266 267 #ifdef SUNW_INC_DEAD_CODE 268 /* relative time (delta-t) conversions */ 269 270 /* string->deltat is in deltat.y */ 271 272 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 273 krb5_deltat_to_string(deltat, buffer, buflen) 274 krb5_deltat deltat; 275 char FAR * buffer; 276 size_t buflen; 277 { 278 int days, hours, minutes, seconds; 279 krb5_deltat dt; 280 281 /* 282 * We want something like ceil(log10(2**(nbits-1))) + 1. That log 283 * value is log10(2)*(nbits-1) or log10(2**8)*(nbits-1)/8. So, 284 * 2.4... is log10(256), rounded up. Add one to handle leading 285 * minus, and one more to force int cast to round the value up. 286 * This doesn't include room for a trailing nul. 287 * 288 * This will break if bytes are more than 8 bits. 289 */ 290 #define MAX_CHARS_FOR_INT_TYPE(TYPE) ((int) (2 + 2.408241 * sizeof (TYPE))) 291 char tmpbuf[MAX_CHARS_FOR_INT_TYPE(int) * 4 + 8]; 292 293 days = (int) (deltat / (24*3600L)); 294 dt = deltat % (24*3600L); 295 hours = (int) (dt / 3600); 296 dt %= 3600; 297 minutes = (int) (dt / 60); 298 seconds = (int) (dt % 60); 299 300 memset (tmpbuf, 0, sizeof (tmpbuf)); 301 if (days == 0) 302 sprintf(buffer, "%d:%02d:%02d", hours, minutes, seconds); 303 else if (hours || minutes || seconds) 304 sprintf(buffer, "%d %s %02d:%02d:%02d", days, 305 (days > 1) ? "days" : "day", 306 hours, minutes, seconds); 307 else 308 sprintf(buffer, "%d %s", days, 309 (days > 1) ? "days" : "day"); 310 if (tmpbuf[sizeof(tmpbuf)-1] != 0) 311 /* Something must be very wrong with my math above, or the 312 assumptions going into it... */ 313 abort (); 314 if (strlen (tmpbuf) > buflen) 315 return ENOMEM; 316 else 317 strncpy (buffer, tmpbuf, buflen); 318 return 0; 319 } 320 #endif /* SUNW_INC_DEAD_CODE */ 321 322 #undef __P 323 #define __P(X) X 324 325 #if !defined (HAVE_STRFTIME) || !defined (HAVE_STRPTIME) 326 #undef _CurrentTimeLocale 327 #define _CurrentTimeLocale (&dummy_locale_info) 328 329 struct dummy_locale_info_t { 330 char d_t_fmt[15]; 331 char t_fmt_ampm[12]; 332 char t_fmt[9]; 333 char d_fmt[9]; 334 char day[7][10]; 335 char abday[7][4]; 336 char mon[12][10]; 337 char abmon[12][4]; 338 char am_pm[2][3]; 339 }; 340 static const struct dummy_locale_info_t dummy_locale_info = { 341 "%a %b %d %X %Y", /* %c */ 342 "%I:%M:%S %p", /* %r */ 343 "%H:%M:%S", /* %X */ 344 "%m/%d/%y", /* %x */ 345 { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 346 "Saturday" }, 347 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }, 348 { "January", "February", "March", "April", "May", "June", 349 "July", "August", "September", "October", "November", "December" }, 350 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 351 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }, 352 { "AM", "PM" }, 353 }; 354 #undef TM_YEAR_BASE 355 #define TM_YEAR_BASE 1900 356 #endif 357 358 #ifndef HAVE_STRFTIME 359 #undef DAYSPERLYEAR 360 #define DAYSPERLYEAR 366 361 #undef DAYSPERNYEAR 362 #define DAYSPERNYEAR 365 363 #undef DAYSPERWEEK 364 #define DAYSPERWEEK 7 365 #undef isleap 366 #define isleap(N) ((N % 4) == 0 && (N % 100 != 0 || N % 400 == 0)) 367 #undef tzname 368 #define tzname my_tzname 369 static const char *const tzname[2] = { 0, 0 }; 370 #undef tzset 371 #define tzset() 372 373 #include "strftime.c" 374 #endif 375 376 #ifndef HAVE_STRPTIME 377 #include "strptime.c" 378 #endif 379