xref: /freebsd/crypto/krb5/src/windows/leash/KrbListTickets.cpp (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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