1 #include "stdafx.h" 2 #include "lglobals.h" 3 #include "krb5.h" 4 5 static void 6 FreeTicketList(TicketList** ticketList) 7 { 8 TicketList* tempList = *ticketList, *killList; 9 10 while (tempList) { 11 killList = tempList; 12 tempList = tempList->next; 13 free(killList->service); 14 if (killList->encTypes) 15 free(killList->encTypes); 16 free(killList); 17 } 18 19 *ticketList = NULL; 20 } 21 22 void 23 LeashKRB5FreeTicketInfo(TICKETINFO *ticketinfo) 24 { 25 if (ticketinfo->principal) { 26 free(ticketinfo->principal); 27 ticketinfo->principal = NULL; 28 } 29 if (ticketinfo->ccache_name) { 30 pkrb5_free_string(NULL, ticketinfo->ccache_name); 31 ticketinfo->ccache_name = NULL; 32 } 33 if (ticketinfo->ticket_list) 34 FreeTicketList(&ticketinfo->ticket_list); 35 } 36 37 void 38 LeashKRB5FreeTickets(TICKETINFO **ticketinfolist) 39 { 40 TICKETINFO *ticketinfo = *ticketinfolist, *next; 41 while (ticketinfo) { 42 next = ticketinfo->next; 43 LeashKRB5FreeTicketInfo(ticketinfo); 44 free(ticketinfo); 45 ticketinfo = next; 46 } 47 *ticketinfolist = NULL; 48 } 49 50 /* 51 * LeashKRB5Error() 52 */ 53 int 54 LeashKRB5Error(krb5_error_code rc, LPCSTR FailedFunctionName) 55 { 56 #ifdef USE_MESSAGE_BOX 57 char message[256]; 58 const char *errText; 59 60 errText = perror_message(rc); 61 _snprintf(message, sizeof(message), 62 "%s\n(Kerberos error %ld)\n\n%s failed", 63 errText, 64 rc, 65 FailedFunctionName); 66 message[sizeof(message)-1] = 0; 67 68 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | 69 MB_TASKMODAL | 70 MB_SETFOREGROUND); 71 #endif /* USE_MESSAGE_BOX */ 72 return rc; 73 } 74 75 76 static void 77 etype_string(krb5_enctype enctype, char *buf, size_t buflen) 78 { 79 krb5_error_code retval; 80 81 if ((retval = pkrb5_enctype_to_name(enctype, FALSE, buf, buflen))) { 82 /* XXX if there's an error != EINVAL, I should probably report it */ 83 sprintf_s(buf, buflen, "etype %d", enctype); 84 } 85 } 86 87 88 static void 89 CredToTicketInfo(krb5_creds KRBv5Credentials, TICKETINFO *ticketinfo) 90 { 91 ticketinfo->issued = (DWORD)KRBv5Credentials.times.starttime; 92 ticketinfo->valid_until = (DWORD)KRBv5Credentials.times.endtime; 93 ticketinfo->renew_until = KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE ? 94 (DWORD)KRBv5Credentials.times.renew_till : (DWORD)0; 95 _tzset(); 96 if ( ticketinfo->valid_until - time(0) <= 0L ) 97 ticketinfo->btickets = EXPD_TICKETS; 98 else 99 ticketinfo->btickets = GOOD_TICKETS; 100 } 101 102 static int 103 CredToTicketList(krb5_context ctx, krb5_creds KRBv5Credentials, 104 char *PrincipalName, TicketList ***ticketListTail) 105 { 106 krb5_error_code code = 0; 107 krb5_ticket *tkt=NULL; 108 char *sServerName = NULL; 109 char Buffer[256], sestype[100], tkttype[100]; 110 char *functionName = NULL; 111 TicketList *list = NULL; 112 113 functionName = "krb5_unparse_name()"; 114 code = (*pkrb5_unparse_name)(ctx, KRBv5Credentials.server, &sServerName); 115 if (code) 116 goto cleanup; 117 118 if (!KRBv5Credentials.times.starttime) 119 KRBv5Credentials.times.starttime = KRBv5Credentials.times.authtime; 120 121 memset(Buffer, '\0', sizeof(Buffer)); 122 123 // @fixme: calloc for ptr init 124 list = (TicketList *)calloc(1, sizeof(TicketList)); 125 if (!list) { 126 code = ENOMEM; 127 functionName = "calloc()"; 128 goto cleanup; 129 } 130 list->service = strdup(sServerName); 131 if (!list->service) { 132 code = ENOMEM; 133 functionName = "calloc()"; 134 goto cleanup; 135 } 136 list->issued = (DWORD)KRBv5Credentials.times.starttime; 137 list->valid_until = (DWORD)KRBv5Credentials.times.endtime; 138 if (KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE) 139 list->renew_until = (DWORD)KRBv5Credentials.times.renew_till; 140 else 141 list->renew_until = 0; 142 143 etype_string(KRBv5Credentials.keyblock.enctype, sestype, sizeof(sestype)); 144 if (!pkrb5_decode_ticket(&KRBv5Credentials.ticket, &tkt)) { 145 etype_string(tkt->enc_part.enctype, tkttype, sizeof(tkttype)); 146 wsprintf(Buffer, "Session Key: %s Ticket: %s", sestype, tkttype); 147 pkrb5_free_ticket(ctx, tkt); 148 tkt = NULL; 149 } else { 150 wsprintf(Buffer, "Session Key: %s", sestype); 151 } 152 153 list->encTypes = (char *)calloc(1, strlen(Buffer)+1); 154 if (!list->encTypes) { 155 functionName = "calloc()"; 156 code = ENOMEM; 157 goto cleanup; 158 } 159 strcpy(list->encTypes, Buffer); 160 161 list->flags = KRBv5Credentials.ticket_flags; 162 cleanup: 163 if (code) { 164 LeashKRB5Error(code, functionName); 165 if (list) 166 FreeTicketList(&list); 167 } else { 168 **ticketListTail = list; 169 *ticketListTail = &list->next; 170 } 171 172 if (sServerName != NULL) 173 (*pkrb5_free_unparsed_name)(ctx, sServerName); 174 175 return code; 176 } 177 178 // return 0 if ticketinfo was successfully appended to list, 1 otherwise 179 int 180 do_ccache(krb5_context ctx, 181 krb5_ccache cache, 182 TICKETINFO **ticketInfoTail) 183 { 184 krb5_cc_cursor cur; 185 krb5_creds creds; 186 krb5_principal princ = NULL; 187 krb5_flags flags; 188 krb5_error_code code; 189 char *defname = NULL; 190 char *functionName = NULL; 191 TicketList **ticketListTail; 192 TICKETINFO *ticketinfo = NULL; 193 int retval = 1; 194 195 // Don't need the actual ticket. 196 flags = KRB5_TC_NOTICKET; 197 code = pkrb5_cc_set_flags(ctx, cache, flags); 198 if (code) { 199 if (code == KRB5_FCC_NOFILE || code == KRB5_CC_NOTFOUND) { 200 // Normal behavior; skip cache but suppress error message box 201 code = 0; 202 } else { 203 functionName = "krb5_cc_set_flags"; 204 } 205 goto cleanup; 206 } 207 code = pkrb5_cc_get_principal(ctx, cache, &princ); 208 if (code) { 209 // Normal behavior; skip cache but suppress error message box 210 code = 0; 211 goto cleanup; 212 } 213 code = pkrb5_unparse_name(ctx, princ, &defname); 214 if (code) { 215 functionName = "krb5_unparse_name"; 216 goto cleanup; 217 } 218 code = pkrb5_cc_start_seq_get(ctx, cache, &cur); 219 if (code) { 220 // MSLSA errors here if no TGT is found; suppress error message box 221 code = 0; 222 goto cleanup; 223 } 224 if (*ticketInfoTail) 225 ticketinfo = *ticketInfoTail; 226 else 227 // @fixme: calloc to init pointers 228 ticketinfo = (TICKETINFO *)calloc(1, sizeof(TICKETINFO)); 229 230 if (ticketinfo == NULL) { 231 functionName = "calloc"; 232 code = ENOMEM; 233 goto cleanup; 234 } 235 ticketinfo->next = NULL; 236 ticketinfo->ticket_list = NULL; 237 ticketinfo->principal = strdup(defname); 238 if (ticketinfo->principal == NULL) { 239 functionName = "strdup"; 240 code = ENOMEM; 241 goto cleanup; 242 } 243 code = pkrb5_cc_get_full_name(ctx, cache, &ticketinfo->ccache_name); 244 if (code) { 245 functionName = "krb5_cc_get_full_name"; 246 goto cleanup; 247 } 248 *ticketInfoTail = ticketinfo; 249 ticketListTail = &ticketinfo->ticket_list; 250 while (!(code = pkrb5_cc_next_cred(ctx, cache, &cur, &creds))) { 251 if (!pkrb5_is_config_principal(ctx, creds.server)) { 252 CredToTicketList(ctx, creds, defname, &ticketListTail); 253 CredToTicketInfo(creds, ticketinfo); 254 } 255 pkrb5_free_cred_contents(ctx, &creds); 256 } 257 if (code == KRB5_CC_END) { 258 code = pkrb5_cc_end_seq_get(ctx, cache, &cur); 259 if (code) { 260 functionName = "krb5_cc_end_seq_get"; 261 goto cleanup; 262 } 263 flags = 0; 264 code = pkrb5_cc_set_flags(ctx, cache, flags); 265 if (code) { 266 functionName = "krb5_cc_set_flags"; 267 goto cleanup; 268 } 269 } else { 270 functionName = "krb5_cc_next_cred"; 271 goto cleanup; 272 } 273 cleanup: 274 if (code) 275 LeashKRB5Error(code, functionName); 276 if (ticketinfo) { 277 if (ticketinfo == *ticketInfoTail) 278 retval = 0; 279 else 280 LeashKRB5FreeTickets(&ticketinfo); 281 } 282 if (defname) 283 pkrb5_free_unparsed_name(ctx, defname); 284 if (princ) 285 pkrb5_free_principal(ctx, princ); 286 return retval; 287 } 288 289 290 // 291 // Returns 0 for success, 1 for failure 292 // 293 int 294 do_all_ccaches(krb5_context ctx, TICKETINFO **ticketinfotail) 295 { 296 krb5_error_code code; 297 krb5_ccache cache; 298 krb5_cccol_cursor cursor; 299 int retval = 1; 300 char *functionName = NULL; 301 302 code = pkrb5_cccol_cursor_new(ctx, &cursor); 303 if (code) { 304 functionName = "krb5_cccol_cursor_new"; 305 goto cleanup; 306 } 307 retval = 0; 308 while (!(code = pkrb5_cccol_cursor_next(ctx, cursor, &cache)) && 309 cache != NULL) { 310 // Note that ticketinfotail will be updated here to point to the tail 311 // of the list but the caller of this function will remain with a 312 // pointer to the head. 313 if (do_ccache(ctx, cache, ticketinfotail) == 0) 314 ticketinfotail = &((*ticketinfotail)->next); 315 pkrb5_cc_close(ctx, cache); 316 } 317 if (code) 318 functionName = "krb5_cccol_cursor_next"; 319 pkrb5_cccol_cursor_free(ctx, &cursor); 320 cleanup: 321 if (code) 322 LeashKRB5Error(code, functionName); 323 return retval; 324 } 325 326 void 327 LeashKRB5ListDefaultTickets(TICKETINFO *ticketinfo) 328 { 329 krb5_error_code code; 330 krb5_context ctx = 0; 331 krb5_ccache cache = 0; 332 char *functionName = NULL; 333 334 ticketinfo->btickets = NO_TICKETS; 335 ticketinfo->principal = NULL; 336 ticketinfo->ccache_name = NULL; 337 ticketinfo->next = NULL; 338 ticketinfo->ticket_list = NULL; 339 ticketinfo->renew_until = 0; 340 ticketinfo->valid_until = 0; 341 ticketinfo->issued = 0; 342 343 code = pkrb5_init_context(&ctx); 344 if (code) { 345 functionName = "krb5_init_context"; 346 goto cleanup; 347 } 348 349 code = pkrb5_cc_default(ctx, &cache); 350 if (code) { 351 functionName = "krb5_cc_default"; 352 goto cleanup; 353 } 354 if (cache != NULL) 355 do_ccache(ctx, cache, &ticketinfo); 356 cleanup: 357 if (code) 358 LeashKRB5Error(code, functionName); 359 if (cache) 360 pkrb5_cc_close(ctx, cache); 361 if (ctx) 362 pkrb5_free_context(ctx); 363 } 364 365 366 /* 367 * LeashKRB5ListAllTickets() 368 */ 369 370 void 371 LeashKRB5ListAllTickets(TICKETINFO **ticketinfo) 372 { 373 krb5_error_code code; 374 krb5_context ctx = 0; 375 char *functionName = NULL; 376 377 code = pkrb5_init_context(&ctx); 378 if (code) { 379 functionName = "krb5_init_context"; 380 goto cleanup; 381 } 382 383 do_all_ccaches(ctx, ticketinfo); 384 cleanup: 385 if (code) 386 LeashKRB5Error(code, functionName); 387 if (ctx) 388 pkrb5_free_context(ctx); 389 } 390