1 #include "stdafx.h"
2 #include "lglobals.h"
3 #include "krb5.h"
4
5 static void
FreeTicketList(TicketList ** ticketList)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
LeashKRB5FreeTicketInfo(TICKETINFO * ticketinfo)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
LeashKRB5FreeTickets(TICKETINFO ** ticketinfolist)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
LeashKRB5Error(krb5_error_code rc,LPCSTR FailedFunctionName)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
etype_string(krb5_enctype enctype,char * buf,size_t buflen)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
CredToTicketInfo(krb5_creds KRBv5Credentials,TICKETINFO * ticketinfo)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
CredToTicketList(krb5_context ctx,krb5_creds KRBv5Credentials,char * PrincipalName,TicketList *** ticketListTail)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
do_ccache(krb5_context ctx,krb5_ccache cache,TICKETINFO ** ticketInfoTail)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
do_all_ccaches(krb5_context ctx,TICKETINFO ** ticketinfotail)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
LeashKRB5ListDefaultTickets(TICKETINFO * ticketinfo)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
LeashKRB5ListAllTickets(TICKETINFO ** ticketinfo)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