1 /* tkts.c --- Ticket set handling.
2  * Copyright (C) 2002-2013 Simon Josefsson
3  *
4  * This file is part of Shishi.
5  *
6  * Shishi is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Shishi is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Shishi; if not, see http://www.gnu.org/licenses or write
18  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19  * Floor, Boston, MA 02110-1301, USA
20  *
21  */
22 
23 #include "internal.h"
24 #include <minmax.h>
25 
26 struct Shishi_tkts
27 {
28   Shishi *handle;
29   Shishi_tkt **tkts;
30   int ntkts;
31 };
32 
33 #define TICKET_FILE "tickets"
34 
35 /**
36  * shishi_tkts_default_file_guess:
37  * @handle: Shishi library handle create by shishi_init().
38  *
39  * Guesses the default ticket filename; it is $SHISHI_TICKETS,
40  * $SHISHI_HOME/tickets, or $HOME/.shishi/tickets.
41  *
42  * Return value: Returns default tkts filename as a string that
43  * has to be deallocated with free() by the caller.
44  **/
45 char *
shishi_tkts_default_file_guess(Shishi * handle)46 shishi_tkts_default_file_guess (Shishi * handle)
47 {
48   char *envfile;
49 
50   envfile = getenv ("SHISHI_TICKETS");
51   if (envfile)
52     return xstrdup (envfile);
53 
54   return shishi_cfg_userdirectory_file (handle, TICKET_FILE);
55 }
56 
57 /**
58  * shishi_tkts_default_file:
59  * @handle: Shishi library handle create by shishi_init().
60  *
61  * Get filename of default ticket set.
62  *
63  * Return value: Returns the default ticket set filename used in the
64  * library.  The string is not a copy, so don't modify or deallocate
65  * it.
66  **/
67 const char *
shishi_tkts_default_file(Shishi * handle)68 shishi_tkts_default_file (Shishi * handle)
69 {
70   if (!handle->tktsdefaultfile)
71     {
72       char *p;
73 
74       p = shishi_tkts_default_file_guess (handle);
75       shishi_tkts_default_file_set (handle, p);
76       free (p);
77     }
78 
79   return handle->tktsdefaultfile;
80 }
81 
82 /**
83  * shishi_tkts_default_file_set:
84  * @handle: Shishi library handle create by shishi_init().
85  * @tktsfile: string with new default tkts file name, or
86  *                 NULL to reset to default.
87  *
88  * Set the default ticket set filename used in the library.  The
89  * string is copied into the library, so you can dispose of the
90  * variable immediately after calling this function.
91  **/
92 void
shishi_tkts_default_file_set(Shishi * handle,const char * tktsfile)93 shishi_tkts_default_file_set (Shishi * handle, const char *tktsfile)
94 {
95   free (handle->tktsdefaultfile);
96   if (tktsfile)
97     handle->tktsdefaultfile = xstrdup (tktsfile);
98   else
99     handle->tktsdefaultfile = NULL;
100 }
101 
102 /**
103  * shishi_tkts_default:
104  * @handle: Shishi library handle create by shishi_init().
105  *
106  * Get the default ticket set for library handle.
107  *
108  * Return value: Return the handle global ticket set.
109  **/
110 Shishi_tkts *
shishi_tkts_default(Shishi * handle)111 shishi_tkts_default (Shishi * handle)
112 {
113   if (handle->tkts == NULL &&
114       (shishi_tkts (handle, &handle->tkts) != SHISHI_OK))
115     handle->tkts = NULL;
116 
117   return handle->tkts;
118 }
119 
120 int
shishi_tkts_default_to_file(Shishi_tkts * tkts)121 shishi_tkts_default_to_file (Shishi_tkts * tkts)
122 {
123   return shishi_tkts_to_file (tkts, shishi_tkts_default_file (tkts->handle));
124 }
125 
126 /**
127  * shishi_tkts:
128  * @handle: shishi handle as allocated by shishi_init().
129  * @tkts: output pointer to newly allocated tkts handle.
130  *
131  * Get a new ticket set handle.
132  *
133  * Return value: Returns %SHISHI_OK iff successful.
134  **/
135 int
shishi_tkts(Shishi * handle,Shishi_tkts ** tkts)136 shishi_tkts (Shishi * handle, Shishi_tkts ** tkts)
137 {
138   *tkts = xcalloc (1, sizeof (**tkts));
139 
140   (*tkts)->handle = handle;
141 
142   return SHISHI_OK;
143 }
144 
145 /**
146  * shishi_tkts_done:
147  * @tkts: ticket set handle as allocated by shishi_tkts().
148  *
149  * Deallocates all resources associated with ticket set.  The ticket
150  * set handle must not be used in calls to other shishi_tkts_*()
151  * functions after this.
152  **/
153 void
shishi_tkts_done(Shishi_tkts ** tkts)154 shishi_tkts_done (Shishi_tkts ** tkts)
155 {
156   if (!tkts || !*tkts)
157     return;
158 
159   if ((*tkts)->tkts)
160     free ((*tkts)->tkts);
161   free (*tkts);
162 
163   *tkts = NULL;
164 
165   return;
166 }
167 
168 /**
169  * shishi_tkts_size:
170  * @tkts: ticket set handle as allocated by shishi_tkts().
171  *
172  * Get size of ticket set.
173  *
174  * Return value: Returns number of tickets stored in ticket set.
175  **/
176 int
shishi_tkts_size(Shishi_tkts * tkts)177 shishi_tkts_size (Shishi_tkts * tkts)
178 {
179   return tkts ? tkts->ntkts : -1;
180 }
181 
182 /**
183  * shishi_tkts_nth:
184  * @tkts: ticket set handle as allocated by shishi_tkts().
185  * @ticketno: integer indicating requested ticket in ticket set.
186  *
187  * Get the n:th ticket in ticket set.
188  *
189  * Return value: Returns a ticket handle to the ticketno:th ticket in
190  *   the ticket set, or NULL if ticket set is invalid or ticketno is
191  *   out of bounds.  The first ticket is ticketno 0, the second
192  *   ticketno 1, and so on.
193  **/
194 Shishi_tkt *
shishi_tkts_nth(Shishi_tkts * tkts,int ticketno)195 shishi_tkts_nth (Shishi_tkts * tkts, int ticketno)
196 {
197   if (tkts == NULL || ticketno >= tkts->ntkts)
198     return NULL;
199 
200   return tkts->tkts[ticketno];
201 }
202 
203 /**
204  * shishi_tkts_remove:
205  * @tkts: ticket set handle as allocated by shishi_tkts().
206  * @ticketno: ticket number of ticket in the set to remove.  The first
207  *   ticket is ticket number 0.
208  *
209  * Remove a ticket, indexed by @ticketno, in ticket set.
210  *
211  * Return value: %SHISHI_OK if successful or if @ticketno larger than
212  *   size of ticket set.
213  **/
214 int
shishi_tkts_remove(Shishi_tkts * tkts,int ticketno)215 shishi_tkts_remove (Shishi_tkts * tkts, int ticketno)
216 {
217   if (!tkts)
218     return SHISHI_INVALID_TKTS;
219 
220   if (ticketno >= tkts->ntkts)
221     return SHISHI_OK;
222 
223   if (ticketno < tkts->ntkts)
224     memmove (&tkts->tkts[ticketno], &tkts->tkts[ticketno + 1],
225 	     sizeof (*tkts->tkts) * (tkts->ntkts - ticketno - 1));
226 
227   --tkts->ntkts;
228 
229   if (tkts->ntkts > 0)
230     {
231       tkts->tkts = xrealloc (tkts->tkts, sizeof (*tkts->tkts) * tkts->ntkts);
232     }
233   else
234     {
235       free (tkts->tkts);
236       tkts->tkts = NULL;
237     }
238 
239   return SHISHI_OK;
240 }
241 
242 /**
243  * shishi_tkts_add:
244  * @tkts: ticket set handle as allocated by shishi_tkts().
245  * @tkt: ticket to be added to ticket set.
246  *
247  * Add a ticket to the ticket set.  Only the pointer is stored, so if
248  * you modify @tkt, the ticket in the ticket set will also be
249  * modified.
250  *
251  * Return value: Returns %SHISHI_OK iff successful.
252  **/
253 int
shishi_tkts_add(Shishi_tkts * tkts,Shishi_tkt * tkt)254 shishi_tkts_add (Shishi_tkts * tkts, Shishi_tkt * tkt)
255 {
256   if (!tkt)
257     return SHISHI_INVALID_TICKET;
258 
259   if (tkts->ntkts++ == 0)
260     tkts->tkts = xmalloc (sizeof (*tkts->tkts));
261   else
262     tkts->tkts = xrealloc (tkts->tkts, sizeof (*tkts->tkts) * tkts->ntkts);
263 
264   tkts->tkts[tkts->ntkts - 1] = tkt;
265 
266   return SHISHI_OK;
267 }
268 
269 /**
270  * shishi_tkts_new:
271  * @tkts: ticket set handle as allocated by shishi_tkts().
272  * @ticket: input ticket variable.
273  * @enckdcreppart: input ticket detail variable.
274  * @kdcrep: input KDC-REP variable.
275  *
276  * Allocate a new ticket and add it to the ticket set.
277  *
278  * Note that @ticket, @enckdcreppart and @kdcrep are stored by
279  * reference, so you must not de-allocate them before the ticket is
280  * removed from the ticket set and de-allocated.
281  *
282  * Return value: Returns %SHISHI_OK iff successful.
283  **/
284 int
shishi_tkts_new(Shishi_tkts * tkts,Shishi_asn1 ticket,Shishi_asn1 enckdcreppart,Shishi_asn1 kdcrep)285 shishi_tkts_new (Shishi_tkts * tkts,
286 		 Shishi_asn1 ticket, Shishi_asn1 enckdcreppart,
287 		 Shishi_asn1 kdcrep)
288 {
289   Shishi_tkt *tkt;
290   int res;
291 
292   /* XXX Who will de-allocate these? */
293   tkt = shishi_tkt2 (tkts->handle, ticket, enckdcreppart, kdcrep);
294 
295   res = shishi_tkts_add (tkts, tkt);
296   if (res != SHISHI_OK)
297     {
298       free (tkt);
299       return res;
300     }
301 
302   return SHISHI_OK;
303 }
304 
305 /**
306  * shishi_tkts_read:
307  * @tkts: ticket set handle as allocated by shishi_tkts().
308  * @fh: file descriptor to read from.
309  *
310  * Read tickets from file descriptor and add them to the ticket set.
311  *
312  * Return value: Returns %SHISHI_OK iff successful.
313  **/
314 int
shishi_tkts_read(Shishi_tkts * tkts,FILE * fh)315 shishi_tkts_read (Shishi_tkts * tkts, FILE * fh)
316 {
317   int res;
318 
319   res = SHISHI_OK;
320   while (!feof (fh))
321     {
322       Shishi_asn1 ticket;
323       Shishi_asn1 enckdcreppart;
324       Shishi_asn1 kdcrep;
325 
326       res = shishi_kdcrep_parse (tkts->handle, fh, &kdcrep);
327       if (res != SHISHI_OK)
328 	{
329 	  res = SHISHI_OK;
330 	  break;
331 	}
332 
333       res = shishi_enckdcreppart_parse (tkts->handle, fh, &enckdcreppart);
334       if (res != SHISHI_OK)
335 	break;
336 
337       res = shishi_ticket_parse (tkts->handle, fh, &ticket);
338       if (res != SHISHI_OK)
339 	break;
340 
341       /* XXX Who will de-allocate these? */
342       res = shishi_tkts_new (tkts, ticket, enckdcreppart, kdcrep);
343       if (res != SHISHI_OK)
344 	break;
345 
346       if (VERBOSEASN1 (tkts->handle))
347 	{
348 	  printf ("Read ticket for principal `':\n");
349 	  shishi_kdcrep_print (tkts->handle, stdout, kdcrep);
350 	  shishi_enckdcreppart_print (tkts->handle, stdout, enckdcreppart);
351 	  shishi_ticket_print (tkts->handle, stdout, ticket);
352 	}
353     }
354 
355   return res;
356 }
357 
358 /**
359  * shishi_tkts_from_file:
360  * @tkts: ticket set handle as allocated by shishi_tkts().
361  * @filename: filename to read tickets from.
362  *
363  * Read tickets from file and add them to the ticket set.
364  *
365  * Return value: Returns %SHISHI_OK iff successful.
366  **/
367 int
shishi_tkts_from_file(Shishi_tkts * tkts,const char * filename)368 shishi_tkts_from_file (Shishi_tkts * tkts, const char *filename)
369 {
370   FILE *fh;
371   int res;
372 
373   fh = fopen (filename, "r");
374   if (fh == NULL)
375     return SHISHI_FOPEN_ERROR;
376 
377   res = shishi_tkts_read (tkts, fh);
378   if (res != SHISHI_OK)
379     {
380       fclose (fh);
381       return res;
382     }
383 
384   res = fclose (fh);
385   if (res != 0)
386     return SHISHI_IO_ERROR;
387 
388   return SHISHI_OK;
389 }
390 
391 /**
392  * shishi_tkts_write:
393  * @tkts: ticket set handle as allocated by shishi_tkts().
394  * @fh: file descriptor to write tickets to.
395  *
396  * Write tickets in set to file descriptor.
397  *
398  * Return value: Returns %SHISHI_OK iff successful.
399  **/
400 int
shishi_tkts_write(Shishi_tkts * tkts,FILE * fh)401 shishi_tkts_write (Shishi_tkts * tkts, FILE * fh)
402 {
403   int res;
404   int i;
405 
406   if (!tkts)
407     return SHISHI_INVALID_TKTS;
408 
409   for (i = 0; i < tkts->ntkts; i++)
410     {
411       res = shishi_kdcrep_print
412 	(tkts->handle, fh, shishi_tkt_kdcrep (tkts->tkts[i]));
413       if (res != SHISHI_OK)
414 	{
415 	  shishi_error_printf (tkts->handle,
416 			       "Could not print ticket: %s",
417 			       shishi_error (tkts->handle));
418 	  return res;
419 	}
420 
421       res = shishi_enckdcreppart_print
422 	(tkts->handle, fh, shishi_tkt_enckdcreppart (tkts->tkts[i]));
423       if (res != SHISHI_OK)
424 	{
425 	  shishi_error_printf (tkts->handle,
426 			       "Could not print ticket: %s",
427 			       shishi_error (tkts->handle));
428 	  return res;
429 	}
430 
431       res = shishi_ticket_print (tkts->handle, fh,
432 				 shishi_tkt_ticket (tkts->tkts[i]));
433       if (res != SHISHI_OK)
434 	{
435 	  shishi_error_printf (tkts->handle,
436 			       "Could not print ticket: %s",
437 			       shishi_error (tkts->handle));
438 	  return res;
439 	}
440 
441       fprintf (fh, "\n\n");
442     }
443 
444   return SHISHI_OK;
445 }
446 
447 /**
448  * shishi_tkts_expire:
449  * @tkts: ticket set handle as allocated by shishi_tkts().
450  *
451  * Remove expired tickets from ticket set.
452  *
453  * Return value: Returns %SHISHI_OK iff successful.
454  **/
455 int
shishi_tkts_expire(Shishi_tkts * tkts)456 shishi_tkts_expire (Shishi_tkts * tkts)
457 {
458   int warn = 0;
459   int i = 0;
460 
461   if (!tkts)
462     return SHISHI_INVALID_TKTS;
463 
464   while (i < tkts->ntkts)
465     {
466       if (shishi_tkt_expired_p (tkts->tkts[i]))
467 	{
468 	  warn++;
469 	  shishi_tkts_remove (tkts, i);
470 	}
471       else
472 	i++;
473     }
474 
475   if (VERBOSE (tkts->handle) && warn)
476     shishi_warn (tkts->handle,
477 		 ngettext ("removed %d expired ticket\n",
478 			   "removed %d expired tickets\n", warn), warn);
479 
480   return SHISHI_OK;
481 }
482 
483 /**
484  * shishi_tkts_to_file:
485  * @tkts: ticket set handle as allocated by shishi_tkts().
486  * @filename: filename to write tickets to.
487  *
488  * Write tickets in set to file.
489  *
490  * Return value: Returns %SHISHI_OK iff successful.
491  **/
492 int
shishi_tkts_to_file(Shishi_tkts * tkts,const char * filename)493 shishi_tkts_to_file (Shishi_tkts * tkts, const char *filename)
494 {
495   FILE *fh;
496   int res;
497 
498   fh = fopen (filename, "w");
499   if (fh == NULL)
500     return SHISHI_FOPEN_ERROR;
501 
502   res = shishi_tkts_write (tkts, fh);
503   if (res != SHISHI_OK)
504     {
505       fclose (fh);
506       return res;
507     }
508 
509   res = fclose (fh);
510   if (res != 0)
511     return SHISHI_IO_ERROR;
512 
513   return SHISHI_OK;
514 }
515 
516 /**
517  * shishi_tkts_print_for_service:
518  * @tkts: ticket set handle as allocated by shishi_tkts().
519  * @fh: file descriptor to print to.
520  * @service: service to limit tickets printed to, or NULL.
521  *
522  * Print description of tickets for specified service to file
523  * descriptor.  If service is NULL, all tickets are printed.
524  *
525  * Return value: Returns %SHISHI_OK iff successful.
526  **/
527 int
shishi_tkts_print_for_service(Shishi_tkts * tkts,FILE * fh,const char * service)528 shishi_tkts_print_for_service (Shishi_tkts * tkts, FILE * fh,
529 			       const char *service)
530 {
531   int res;
532   int found;
533   int i;
534 
535   found = 0;
536   for (i = 0; i < shishi_tkts_size (tkts); i++)
537     {
538       Shishi_tkt *tkt = shishi_tkts_nth (tkts, i);
539 
540       if (service)
541 	{
542 	  char *buf;
543 
544 	  res = shishi_tkt_server (tkt, &buf, NULL);
545 	  if (res != SHISHI_OK)
546 	    continue;
547 
548 	  if (strcmp (service, buf) != 0)
549 	    {
550 	      free (buf);
551 	      continue;
552 	    }
553 
554 	  free (buf);
555 	}
556 
557       printf ("\n");
558       shishi_tkt_pretty_print (shishi_tkts_nth (tkts, i), fh);
559       found++;
560     }
561 
562   if (found)
563     {
564       printf (ngettext ("\n%d ticket found.\n", "\n%d tickets found.\n",
565 			found), found);
566     }
567   else
568     {
569       if (service)
570 	printf ("\nNo matching tickets found.\n");
571       else
572 	printf ("\nNo tickets found.\n");
573     }
574 
575   return SHISHI_OK;
576 }
577 
578 /**
579  * shishi_tkts_print:
580  * @tkts: ticket set handle as allocated by shishi_tkts().
581  * @fh: file descriptor to print to.
582  *
583  * Print description of all tickets to file descriptor.
584  *
585  * Return value: Returns %SHISHI_OK iff successful.
586  **/
587 int
shishi_tkts_print(Shishi_tkts * tkts,FILE * fh)588 shishi_tkts_print (Shishi_tkts * tkts, FILE * fh)
589 {
590   return shishi_tkts_print_for_service (tkts, fh, NULL);
591 }
592 
593 /**
594  * shishi_tkt_match_p:
595  * @tkt: ticket to test hints on.
596  * @hint: structure with characteristics of ticket to be found.
597  *
598  * Test if a ticket matches specified hints.
599  *
600  * Return value: Returns 0 iff ticket fails to match given criteria.
601  **/
602 int
shishi_tkt_match_p(Shishi_tkt * tkt,Shishi_tkts_hint * hint)603 shishi_tkt_match_p (Shishi_tkt * tkt, Shishi_tkts_hint * hint)
604 {
605   if (hint->server && !shishi_tkt_server_p (tkt, hint->server))
606     return 0;
607 
608   if (hint->client && !shishi_tkt_client_p (tkt, hint->client))
609     return 0;
610 
611   if (!(hint->flags & SHISHI_TKTSHINTFLAGS_ACCEPT_EXPIRED) &&
612       !shishi_tkt_valid_now_p (tkt))
613     return 0;
614 
615   if ((hint->tktflags & SHISHI_TICKETFLAGS_FORWARDABLE) &&
616       !shishi_tkt_forwardable_p (tkt))
617     return 0;
618 
619   if ((hint->tktflags & SHISHI_TICKETFLAGS_FORWARDED) &&
620       !shishi_tkt_forwarded_p (tkt))
621     return 0;
622 
623   if ((hint->tktflags & SHISHI_TICKETFLAGS_RENEWABLE) &&
624       !shishi_tkt_renewable_p (tkt))
625     return 0;
626 
627   if ((hint->tktflags & SHISHI_TICKETFLAGS_PROXIABLE) &&
628       !shishi_tkt_proxiable_p (tkt))
629     return 0;
630 
631   if ((hint->tktflags & SHISHI_TICKETFLAGS_PROXY) &&
632       !shishi_tkt_proxy_p (tkt))
633     return 0;
634 
635   if (hint->etype && !shishi_tkt_keytype_p (tkt, hint->etype))
636     return 0;
637 
638   return 1;
639 }
640 
641 /**
642  * shishi_tkts_find:
643  * @tkts: ticket set handle as allocated by shishi_tkts().
644  * @hint: structure with characteristics of ticket to be found.
645  *
646  * Search the ticketset sequentially (from ticket number 0 through all
647  * tickets in the set) for a ticket that fits the given
648  * characteristics.  If a ticket is found, the hint->startpos field is
649  * updated to point to the next ticket in the set, so this function
650  * can be called repeatedly with the same hint argument in order to
651  * find all tickets matching a certain criterium.  Note that if
652  * tickets are added to, or removed from, the ticketset during a query
653  * with the same hint argument, the hint->startpos field must be
654  * updated appropriately.
655  *
656  * Here is how you would typically use this function:
657  *
658  *   Shishi_tkts_hint  hint;
659  *
660  *   Shishi_tkt  tkt;
661  *
662  *
663  *   memset(&hint, 0, sizeof(hint));
664  *
665  *   hint.server = "imap/mail.example.org";
666  *
667  *   tkt = shishi_tkts_find (shishi_tkts_default(handle), &hint);
668  *
669  *   if (!tkt)
670  *
671  *     printf("No ticket found...\n");
672  *
673  *   else
674  *
675  *     do_something_with_ticket (tkt);
676  *
677  * Return value: Returns a ticket if found, or NULL if no further
678  *               matching tickets could be found.
679  **/
680 Shishi_tkt *
shishi_tkts_find(Shishi_tkts * tkts,Shishi_tkts_hint * hint)681 shishi_tkts_find (Shishi_tkts * tkts, Shishi_tkts_hint * hint)
682 {
683   int i;
684 
685   if (!tkts)
686     return NULL;
687 
688   if (VERBOSENOISE (tkts->handle))
689     {
690       fprintf (stderr, "Searching tickets... ");
691       if (hint->server)
692 	fprintf (stderr, "server=`%s' ", hint->server);
693       if (hint->client)
694 	fprintf (stderr, "client=`%s' ", hint->client);
695       fprintf (stderr, "\n");
696     }
697 
698   for (i = hint->startpos; i < tkts->ntkts; i++)
699     {
700       if (!shishi_tkt_match_p (tkts->tkts[i], hint))
701 	continue;
702 
703       hint->startpos = i + 1;
704       return tkts->tkts[i];
705     }
706 
707   hint->startpos = i;
708   return NULL;
709 }
710 
711 /**
712  * shishi_tkts_find_for_clientserver:
713  * @tkts: ticket set handle as allocated by shishi_tkts().
714  * @client: client name to find ticket for.
715  * @server: server name to find ticket for.
716  *
717  * Short-hand function for searching the ticket set for a ticket for
718  * the given client and server.  See shishi_tkts_find().
719  *
720  * Return value: Returns a ticket if found, or NULL.
721  **/
722 Shishi_tkt *
shishi_tkts_find_for_clientserver(Shishi_tkts * tkts,const char * client,const char * server)723 shishi_tkts_find_for_clientserver (Shishi_tkts * tkts,
724 				   const char *client, const char *server)
725 {
726   Shishi_tkts_hint hint;
727   Shishi_tkt *tkt;
728 
729   memset (&hint, 0, sizeof (hint));
730   hint.server = (char *) server;
731   hint.client = (char *) client;
732 
733   tkt = shishi_tkts_find (tkts, &hint);
734 
735   return tkt;
736 }
737 
738 /**
739  * shishi_tkts_find_for_server:
740  * @tkts: ticket set handle as allocated by shishi_tkts().
741  * @server: server name to find ticket for.
742  *
743  * Short-hand function for searching the ticket set for a ticket for
744  * the given server using the default client principal.  See
745  * shishi_tkts_find_for_clientserver() and shishi_tkts_find().
746  *
747  * Return value: Returns a ticket if found, or NULL.
748  **/
749 Shishi_tkt *
shishi_tkts_find_for_server(Shishi_tkts * tkts,const char * server)750 shishi_tkts_find_for_server (Shishi_tkts * tkts, const char *server)
751 {
752   return shishi_tkts_find_for_clientserver
753     (tkts, shishi_principal_default (tkts->handle), server);
754 }
755 
756 /* Set flags and times in KDC-REQ based on hint. */
757 static int
act_hint_on_kdcreq(Shishi * handle,Shishi_tkts_hint * hint,Shishi_asn1 kdcreq)758 act_hint_on_kdcreq (Shishi * handle,
759 		    Shishi_tkts_hint * hint, Shishi_asn1 kdcreq)
760 {
761   time_t starttime = hint->starttime ? hint->starttime : time (NULL);
762   time_t endtime = hint->endtime ? hint->endtime :
763     starttime + handle->ticketlife;
764   time_t renew_till = hint->renew_till ? hint->renew_till :
765     starttime + handle->renewlife;
766   int rc;
767 
768   if (hint->starttime)
769     {
770       rc = shishi_asn1_write (handle, kdcreq, "req-body.from",
771 			      shishi_generalize_time (handle, starttime), 0);
772       if (rc != SHISHI_OK)
773 	{
774 	  shishi_error_printf (handle, "Cannot set starttime: %s",
775 			       shishi_strerror (rc));
776 	  return rc;
777 	}
778     }
779 
780   if (hint->endtime)
781     {
782       rc = shishi_asn1_write (handle, kdcreq, "req-body.till",
783 			      shishi_generalize_time (handle, endtime), 0);
784       if (rc != SHISHI_OK)
785 	{
786 	  shishi_error_printf (handle, "Cannot set endtime: %s",
787 			       shishi_strerror (rc));
788 	  return rc;
789 	}
790     }
791 
792   if (hint->tktflags & SHISHI_TICKETFLAGS_FORWARDABLE)
793     {
794       rc = shishi_kdcreq_options_add (handle, kdcreq,
795 				      SHISHI_KDCOPTIONS_FORWARDABLE);
796       if (rc != SHISHI_OK)
797 	goto done;
798     }
799 
800   if (hint->tktflags & SHISHI_TICKETFLAGS_FORWARDED)
801     {
802       rc = shishi_kdcreq_options_add (handle, kdcreq,
803 				      SHISHI_KDCOPTIONS_FORWARDED);
804       if (rc != SHISHI_OK)
805 	goto done;
806     }
807 
808   if (hint->tktflags & SHISHI_TICKETFLAGS_RENEWABLE)
809     {
810       rc = shishi_kdcreq_options_add (handle, kdcreq,
811 				      SHISHI_KDCOPTIONS_RENEWABLE);
812       if (rc != SHISHI_OK)
813 	goto done;
814 
815       rc = shishi_asn1_write (handle, kdcreq, "req-body.rtime",
816 			      shishi_generalize_time (handle, renew_till), 0);
817       if (rc != SHISHI_OK)
818 	{
819 	  shishi_error_printf (handle, "Cannot set renewtill: %s",
820 			       shishi_strerror (rc));
821 	  return rc;
822 	}
823     }
824 
825   if (hint->tktflags & SHISHI_TICKETFLAGS_PROXIABLE)
826     {
827       rc = shishi_kdcreq_options_add (handle, kdcreq,
828 				      SHISHI_KDCOPTIONS_PROXIABLE);
829       if (rc != SHISHI_OK)
830 	goto done;
831     }
832 
833   if (hint->tktflags & SHISHI_TICKETFLAGS_PROXY)
834     {
835       rc = shishi_kdcreq_options_add (handle, kdcreq,
836 				      SHISHI_KDCOPTIONS_PROXY);
837       if (rc != SHISHI_OK)
838 	goto done;
839     }
840 
841 
842   if (hint->etype)
843     {
844       rc = shishi_kdcreq_set_etype (handle, kdcreq, &hint->etype, 1);
845       if (rc != SHISHI_OK)
846 	goto done;
847     }
848 
849   return SHISHI_OK;
850 
851 done:
852   shishi_error_printf (handle, "Cannot set KDC Options: %s",
853 		       shishi_strerror (rc));
854   return rc;
855 }
856 
857 /* Make sure the ticket granting ticket is suitable for the wanted
858    ticket.  E.g., if the wanted ticket should be a PROXY ticket, the
859    ticket granting ticket must be a PROXIABLE ticket for things to
860    work. */
861 static void
set_tgtflags_based_on_hint(Shishi_tkts_hint * tkthint,Shishi_tkts_hint * tgthint)862 set_tgtflags_based_on_hint (Shishi_tkts_hint * tkthint,
863 			    Shishi_tkts_hint * tgthint)
864 {
865   if (tkthint->tktflags & SHISHI_TICKETFLAGS_FORWARDABLE)
866     tgthint->tktflags |= SHISHI_TICKETFLAGS_FORWARDABLE;
867 
868   if (tkthint->tktflags & SHISHI_TICKETFLAGS_FORWARDED)
869     tgthint->tktflags |= SHISHI_TICKETFLAGS_FORWARDABLE;
870 
871   if (tkthint->tktflags & SHISHI_TICKETFLAGS_PROXIABLE)
872     tgthint->tktflags |= SHISHI_TICKETFLAGS_PROXIABLE;
873 
874   if (tkthint->tktflags & SHISHI_TICKETFLAGS_PROXY)
875     tgthint->tktflags |= SHISHI_TICKETFLAGS_PROXIABLE;
876 
877   if (tkthint->tktflags & SHISHI_TICKETFLAGS_RENEWABLE)
878     tgthint->tktflags |= SHISHI_TICKETFLAGS_RENEWABLE;
879 
880   if (tkthint->kdcoptions & SHISHI_KDCOPTIONS_RENEW)
881     tgthint->tktflags |= SHISHI_TICKETFLAGS_RENEWABLE;
882 
883   if (tkthint->endtime)
884     tgthint->endtime = tkthint->endtime;
885 
886   if (tkthint->passwd)
887     tgthint->passwd = tkthint->passwd;
888 
889   if (tkthint->preauthetype)
890     tgthint->preauthetype = tkthint->preauthetype;
891 
892   if (tkthint->preauthsalt)
893     {
894       tgthint->preauthsalt = tkthint->preauthsalt;
895       tgthint->preauthsaltlen = tkthint->preauthsaltlen;
896     }
897 
898   if (tkthint->preauths2kparams)
899     {
900       tgthint->preauths2kparams = tkthint->preauths2kparams;
901       tgthint->preauths2kparamslen = tkthint->preauths2kparamslen;
902     }
903 }
904 
905 /* Pre-authenticate request, based on LOCHINT.  Currently only
906    PA-ENC-TIMESTAMP is supported.  */
907 static int
do_preauth(Shishi_tkts * tkts,Shishi_tkts_hint * lochint,Shishi_as * as)908 do_preauth (Shishi_tkts * tkts, Shishi_tkts_hint * lochint, Shishi_as * as)
909 {
910   int rc = SHISHI_OK;
911 
912   if (lochint->preauthetype)
913     {
914       Shishi_key *key;
915       char *user;
916 
917       /* XXX Don't prompt for password here? */
918 
919       rc = shishi_asreq_clientrealm (tkts->handle, shishi_as_req (as),
920 				     &user, NULL);
921       if (rc != SHISHI_OK)
922 	return rc;
923 
924       if (lochint->passwd == NULL)
925 	{
926 	  rc = shishi_prompt_password (tkts->handle, &lochint->passwd,
927 				       "Enter password for `%s': ", user);
928 	  if (rc != SHISHI_OK)
929 	    return rc;
930 	}
931 
932       if (!lochint->preauthsalt)
933 	{
934 	  rc = shishi_derive_default_salt (tkts->handle, user,
935 					   &lochint->preauthsalt);
936 	  if (rc != SHISHI_OK)
937 	    return rc;
938 
939 	  lochint->preauthsaltlen = strlen (lochint->preauthsalt);
940 	}
941 
942       rc = shishi_key_from_string (tkts->handle, lochint->preauthetype,
943 				   lochint->passwd, strlen (lochint->passwd),
944 				   lochint->preauthsalt,
945 				   lochint->preauthsaltlen,
946 				   lochint->preauths2kparams, &key);
947       if (rc != SHISHI_OK)
948 	return rc;
949 
950       rc = shishi_kdcreq_add_padata_preauth (tkts->handle,
951 					     shishi_as_req (as), key);
952     }
953 
954   return rc;
955 }
956 
957 /* Handle ETYPE-INFO and ETYPE-INFO2 pre-auth data. */
958 static int
recover_preauth_info(Shishi_tkts * tkts,Shishi_as * as,Shishi_tkts_hint * lochint,Shishi_asn1 einfos,bool isinfo2,bool * retry)959 recover_preauth_info (Shishi_tkts * tkts,
960 		      Shishi_as * as,
961 		      Shishi_tkts_hint * lochint,
962 		      Shishi_asn1 einfos, bool isinfo2, bool * retry)
963 {
964   size_t foundpos = SIZE_MAX;
965   size_t i, n;
966   int rc;
967 
968   shishi_verbose (tkts->handle, "Found INFO-ETYPE(2) pre-auth hints");
969 
970   if (VERBOSEASN1 (tkts->handle))
971     {
972       if (isinfo2)
973 	shishi_etype_info2_print (tkts->handle, stdout, einfos);
974       else
975 	shishi_etype_info_print (tkts->handle, stdout, einfos);
976     }
977 
978   if (lochint->preauthetype)
979     {
980       shishi_verbose (tkts->handle, "Pre-auth data already specified");
981       return SHISHI_OK;
982     }
983 
984   rc = shishi_asn1_number_of_elements (tkts->handle, einfos, "", &n);
985   if (rc != SHISHI_OK)
986     return rc;
987 
988   for (i = 1; i <= n; i++)
989     {
990       char *format;
991       int32_t etype;
992 
993       format = xasprintf ("?%d.etype", i);
994       rc = shishi_asn1_read_int32 (tkts->handle, einfos, format, &etype);
995       free (format);
996       if (rc == SHISHI_OK)
997 	{
998 	  size_t j;
999 
1000 	  shishi_verbose (tkts->handle, "Server has etype %d", etype);
1001 
1002 	  for (j = 0; j < tkts->handle->nclientkdcetypes; j++)
1003 	    {
1004 	      if (etype == tkts->handle->clientkdcetypes[j])
1005 		{
1006 		  if (j < foundpos && VERBOSENOISE (tkts->handle))
1007 		    {
1008 		      shishi_verbose (tkts->handle, "New best etype %d",
1009 				      etype);
1010 
1011 		      /* XXX mem leak. */
1012 
1013 		      format = xasprintf ("?%d.salt", i);
1014 		      rc = shishi_asn1_read (tkts->handle, einfos, format,
1015 					     &lochint->preauthsalt,
1016 					     &lochint->preauthsaltlen);
1017 		      free (format);
1018 		      if (rc != SHISHI_OK && rc != SHISHI_ASN1_NO_ELEMENT)
1019 			return rc;
1020 
1021 		      if (isinfo2)
1022 			{
1023 			  format = xasprintf ("?%d.s2kparams", i);
1024 			  rc = shishi_asn1_read (tkts->handle, einfos, format,
1025 						 &lochint->preauths2kparams,
1026 						 &lochint->preauths2kparamslen);
1027 			  free (format);
1028 			  if (rc != SHISHI_OK && rc != SHISHI_ASN1_NO_ELEMENT)
1029 			    return rc;
1030 			}
1031 		    }
1032 
1033 		  foundpos = MIN (foundpos, j);
1034 		}
1035 	    }
1036 	}
1037     }
1038 
1039   if (foundpos != SIZE_MAX)
1040     {
1041       lochint->preauthetype = tkts->handle->clientkdcetypes[foundpos];
1042 
1043       shishi_verbose (tkts->handle, "Best pre-auth etype was %d",
1044 		      lochint->preauthetype);
1045 
1046       *retry = true;
1047     }
1048 
1049   return SHISHI_OK;
1050 }
1051 
1052 /* Called when KDC refused with a NEED_PREAUTH error.  This function
1053    should look at the METHOD-DATA, figure out what kind of pre-auth is
1054    requested, and if it is able to figure out how to recover from the
1055    error, set *RETRY to true and set any hints in LOCHINT that help
1056    do_preauth() compute the proper pre-auth data.  */
1057 static int
recover_preauth(Shishi_tkts * tkts,Shishi_as * as,Shishi_tkts_hint * lochint,bool * retry)1058 recover_preauth (Shishi_tkts * tkts,
1059 		 Shishi_as * as, Shishi_tkts_hint * lochint, bool * retry)
1060 {
1061   Shishi_asn1 krberror = shishi_as_krberror (as);
1062   Shishi_asn1 pas;
1063   size_t i, n;
1064   int rc;
1065 
1066   *retry = false;
1067 
1068   shishi_verbose (tkts->handle, "Server requests pre-auth data");
1069 
1070   rc = shishi_krberror_methoddata (tkts->handle, krberror, &pas);
1071   if (rc != SHISHI_OK)
1072     return rc;
1073 
1074   rc = shishi_asn1_number_of_elements (tkts->handle, pas, "", &n);
1075   if (rc == SHISHI_OK)
1076     {
1077       for (i = 1; i <= n; i++)
1078 	{
1079 	  char *format = xasprintf ("?%d.padata-type", i);
1080 	  int32_t padatatype;
1081 
1082 	  rc = shishi_asn1_read_int32 (tkts->handle, pas, format,
1083 				       &padatatype);
1084 	  free (format);
1085 	  if (rc == SHISHI_OK)
1086 	    {
1087 	      shishi_verbose (tkts->handle, "Looking at pa-type %d",
1088 			      padatatype);
1089 
1090 	      switch (padatatype)
1091 		{
1092 		  /* XXX Don't parse INFO structures if there is a
1093 		     INFO2. */
1094 
1095 		case SHISHI_PA_ETYPE_INFO:
1096 		case SHISHI_PA_ETYPE_INFO2:
1097 		  {
1098 		    char *der;
1099 		    size_t len;
1100 		    Shishi_asn1 einfos;
1101 
1102 		    format = xasprintf ("?%d.padata-value", i);
1103 		    rc = shishi_asn1_read (tkts->handle, pas, format,
1104 					   &der, &len);
1105 		    free (format);
1106 		    if (rc != SHISHI_OK)
1107 		      {
1108 			shishi_error_printf (tkts->handle,
1109 					     "Can't extract PA-DATA value");
1110 			continue;
1111 		      }
1112 
1113 		    if (padatatype == SHISHI_PA_ETYPE_INFO)
1114 		      einfos = shishi_der2asn1_etype_info (tkts->handle,
1115 							   der, len);
1116 		    else
1117 		      einfos = shishi_der2asn1_etype_info2 (tkts->handle,
1118 							    der, len);
1119 		    free (der);
1120 		    if (!einfos)
1121 		      {
1122 			shishi_error_printf (tkts->handle,
1123 					     "Can't DER decode PA-DATA");
1124 			continue;
1125 		      }
1126 
1127 		    rc = recover_preauth_info
1128 		      (tkts, as, lochint, einfos,
1129 		       padatatype == SHISHI_PA_ETYPE_INFO2, retry);
1130 		    if (rc != SHISHI_OK)
1131 		      {
1132 			shishi_error_printf (tkts->handle,
1133 					     "Could not use pre-auth data: %s",
1134 					     shishi_strerror (rc));
1135 			continue;
1136 		      }
1137 
1138 		    shishi_asn1_done (tkts->handle, einfos);
1139 		  }
1140 		  break;
1141 
1142 		default:
1143 		  break;
1144 		}
1145 	    }
1146 	}
1147     }
1148 
1149   shishi_asn1_done (tkts->handle, pas);
1150 
1151   return SHISHI_OK;
1152 }
1153 
1154 /**
1155  * shishi_tkts_get_tgt:
1156  * @tkts: ticket set handle as allocated by shishi_tkts().
1157  * @hint: structure with characteristics of ticket to begot.
1158  *
1159  * Get a ticket granting ticket (TGT) suitable for acquiring ticket
1160  * matching the hint.  I.e., get a TGT for the server realm in the
1161  * hint structure (hint->serverrealm), or the default realm if the
1162  * serverrealm field is NULL.  Can result in AS exchange.
1163  *
1164  * Currently this function do not implement cross realm logic.
1165  *
1166  * This function is used by shishi_tkts_get(), which is probably what
1167  * you really want to use unless you have special needs.
1168  *
1169  * Return value: Returns a ticket granting ticket if successful, or
1170  *   NULL if this function is unable to acquire on.
1171  **/
1172 Shishi_tkt *
shishi_tkts_get_tgt(Shishi_tkts * tkts,Shishi_tkts_hint * hint)1173 shishi_tkts_get_tgt (Shishi_tkts * tkts, Shishi_tkts_hint * hint)
1174 {
1175   Shishi_tkts_hint lochint;
1176   Shishi_as *as;
1177   Shishi_tkt *tgt;
1178   int rc;
1179 
1180   /* XXX cross-realm operation */
1181 
1182   memset (&lochint, 0, sizeof (lochint));
1183   asprintf (&lochint.server, "krbtgt/%s", hint->serverrealm ?
1184 	    hint->serverrealm : shishi_realm_default (tkts->handle));
1185   set_tgtflags_based_on_hint (hint, &lochint);
1186 
1187   tgt = shishi_tkts_find (tkts, &lochint);
1188 
1189   free (lochint.server);
1190   lochint.server = NULL;
1191 
1192   if (tgt)
1193     return tgt;
1194 
1195   if (hint->flags & SHISHI_TKTSHINTFLAGS_NON_INTERACTIVE)
1196     return NULL;
1197 
1198 again:
1199   rc = shishi_as (tkts->handle, &as);
1200   if (rc == SHISHI_OK)
1201     rc = act_hint_on_kdcreq (tkts->handle, &lochint, shishi_as_req (as));
1202   if (rc == SHISHI_OK)
1203     rc = do_preauth (tkts, &lochint, as);
1204   if (rc == SHISHI_OK)
1205     rc = shishi_as_req_build (as);
1206   if (rc == SHISHI_OK)
1207     rc = shishi_as_sendrecv_hint (as, &lochint);
1208   if (rc == SHISHI_OK)
1209     rc = shishi_as_rep_process (as, NULL, lochint.passwd);
1210   if (rc == SHISHI_GOT_KRBERROR
1211       && shishi_krberror_errorcode_fast (tkts->handle,
1212 					 shishi_as_krberror (as))
1213       == SHISHI_KDC_ERR_PREAUTH_REQUIRED)
1214     {
1215       bool retry = false;
1216 
1217       rc = recover_preauth (tkts, as, &lochint, &retry);
1218       if (rc != SHISHI_OK)
1219 	return NULL;
1220 
1221       if (retry)
1222 	{
1223 	  shishi_as_done (as);
1224 	  goto again;
1225 	}
1226 
1227       shishi_error_printf (tkts->handle, "Unsupported pre-auth required");
1228       return NULL;
1229     }
1230   if (rc != SHISHI_OK)
1231     {
1232       shishi_error_printf (tkts->handle,
1233 			   "AS exchange failed: %s\n%s\n",
1234 			   shishi_strerror (rc), shishi_error (tkts->handle));
1235       return NULL;
1236     }
1237 
1238   /* XXX free lochint members */
1239 
1240   tgt = shishi_as_tkt (as);
1241   if (!tgt)
1242     {
1243       shishi_error_printf (tkts->handle, "No ticket in AS-REP");
1244       return NULL;
1245     }
1246 
1247   if (VERBOSENOISE (tkts->handle))
1248     {
1249       printf ("Received ticket granting ticket:\n");
1250       shishi_tkt_pretty_print (tgt, stdout);
1251     }
1252 
1253   rc = shishi_tkts_add (tkts, tgt);
1254   if (rc != SHISHI_OK)
1255     printf ("Could not add ticket: %s", shishi_strerror (rc));
1256 
1257   return tgt;
1258 }
1259 
1260 /**
1261  * shishi_tkts_get_tgs:
1262  * @tkts: ticket set handle as allocated by shishi_tkts().
1263  * @hint: structure with characteristics of ticket to begot.
1264  * @tgt: ticket granting ticket to use.
1265  *
1266  * Get a ticket via TGS exchange using specified ticket granting
1267  * ticket.
1268  *
1269  * This function is used by shishi_tkts_get(), which is probably what
1270  * you really want to use unless you have special needs.
1271  *
1272  * Return value: Returns a ticket if successful, or NULL if this
1273  *   function is unable to acquire on.
1274  **/
1275 Shishi_tkt *
shishi_tkts_get_tgs(Shishi_tkts * tkts,Shishi_tkts_hint * hint,Shishi_tkt * tgt)1276 shishi_tkts_get_tgs (Shishi_tkts * tkts,
1277 		     Shishi_tkts_hint * hint, Shishi_tkt * tgt)
1278 {
1279   Shishi_tgs *tgs;
1280   Shishi_tkt *tkt;
1281   int rc;
1282 
1283   rc = shishi_tgs (tkts->handle, &tgs);
1284   shishi_tgs_tgtkt_set (tgs, tgt);
1285   if (rc == SHISHI_OK)
1286     rc = act_hint_on_kdcreq (tkts->handle, hint, shishi_tgs_req (tgs));
1287   if (rc == SHISHI_OK)
1288     rc = shishi_tgs_set_server (tgs, hint->server);
1289   if (rc == SHISHI_OK)
1290     rc = shishi_tgs_req_build (tgs);
1291   if (rc == SHISHI_OK)
1292     rc = shishi_tgs_sendrecv_hint (tgs, hint);
1293   if (rc == SHISHI_OK)
1294     rc = shishi_tgs_rep_process (tgs);
1295   if (rc != SHISHI_OK)
1296     {
1297       shishi_error_printf (tkts->handle,
1298 			   "TGS exchange failed: %s\n%s\n",
1299 			   shishi_strerror (rc), shishi_error (tkts->handle));
1300       if (rc == SHISHI_GOT_KRBERROR)
1301 	shishi_krberror_pretty_print (tkts->handle, stdout,
1302 				      shishi_tgs_krberror (tgs));
1303       return NULL;
1304     }
1305 
1306   tkt = shishi_tgs_tkt (tgs);
1307   if (!tkt)
1308     {
1309       shishi_error_printf (tkts->handle, "No ticket in TGS-REP?!: %s",
1310 			   shishi_error (tkts->handle));
1311       return NULL;
1312     }
1313 
1314   if (VERBOSENOISE (tkts->handle))
1315     {
1316       printf ("Received ticket:\n");
1317       shishi_tkt_pretty_print (tkt, stdout);
1318     }
1319 
1320   rc = shishi_tkts_add (tkts, tkt);
1321   if (rc != SHISHI_OK)
1322     printf ("Could not add ticket: %s", shishi_strerror (rc));
1323 
1324   return tkt;
1325 }
1326 
1327 /**
1328  * shishi_tkts_get:
1329  * @tkts: ticket set handle as allocated by shishi_tkts().
1330  * @hint: structure with characteristics of ticket to be found.
1331  *
1332  * Get a ticket matching given characteristics.  This function first
1333  * looks in the ticket set for a ticket, then tries to find a
1334  * suitable TGT, possibly via an AS exchange, using
1335  * shishi_tkts_get_tgt(), and then uses that TGT in a TGS exchange to
1336  * get the ticket.
1337  *
1338  * Currently this function does not implement cross realm logic.
1339  *
1340  * Return value: Returns a ticket if found, or NULL if this function
1341  *               is unable to get the ticket.
1342  **/
1343 Shishi_tkt *
shishi_tkts_get(Shishi_tkts * tkts,Shishi_tkts_hint * hint)1344 shishi_tkts_get (Shishi_tkts * tkts, Shishi_tkts_hint * hint)
1345 {
1346   Shishi_tkt *tkt, *tgt;
1347 
1348   /* If we already have a matching ticket, avoid getting a new one. */
1349   hint->startpos = 0;
1350   tkt = shishi_tkts_find (tkts, hint);
1351   if (tkt)
1352     return tkt;
1353 
1354   tgt = shishi_tkts_get_tgt (tkts, hint);
1355   if (!tgt)
1356     {
1357       shishi_error_printf (tkts->handle, "Could not get TGT for ticket.");
1358       return NULL;
1359     }
1360 
1361   if (shishi_tkt_match_p (tgt, hint))
1362     return tgt;
1363 
1364   tkt = shishi_tkts_get_tgs (tkts, hint, tgt);
1365   if (!tkt)
1366     {
1367       shishi_error_printf (tkts->handle, "Could not get ticket using TGT.");
1368       return NULL;
1369     }
1370 
1371   return tkt;
1372 }
1373 
1374 /**
1375  * shishi_tkts_get_for_clientserver:
1376  * @tkts: ticket set handle as allocated by shishi_tkts().
1377  * @client: client name to get ticket for.
1378  * @server: server name to get ticket for.
1379  *
1380  * Short-hand function for getting a ticket for the given client and
1381  * server.  See shishi_tkts_get().
1382  *
1383  * Return value: Returns a ticket if found, or NULL.
1384  **/
1385 Shishi_tkt *
shishi_tkts_get_for_clientserver(Shishi_tkts * tkts,const char * client,const char * server)1386 shishi_tkts_get_for_clientserver (Shishi_tkts * tkts,
1387 				  const char *client, const char *server)
1388 {
1389   Shishi_tkts_hint hint;
1390   Shishi_tkt *tkt;
1391 
1392   memset (&hint, 0, sizeof (hint));
1393   hint.client = (char *) client;
1394   hint.server = (char *) server;
1395 
1396   tkt = shishi_tkts_get (tkts, &hint);
1397 
1398   return tkt;
1399 }
1400 
1401 /**
1402  * shishi_tkts_get_for_server:
1403  * @tkts: ticket set handle as allocated by shishi_tkts().
1404  * @server: server name to get ticket for.
1405  *
1406  * Short-hand function for getting a ticket to the given server and
1407  * for the default principal client.  See shishi_tkts_get().
1408  *
1409  * Return value: Returns a ticket if found, or NULL.
1410  **/
1411 Shishi_tkt *
shishi_tkts_get_for_server(Shishi_tkts * tkts,const char * server)1412 shishi_tkts_get_for_server (Shishi_tkts * tkts, const char *server)
1413 {
1414   return shishi_tkts_get_for_clientserver
1415     (tkts, shishi_principal_default (tkts->handle), server);
1416 }
1417 
1418 /**
1419  * shishi_tkts_get_for_localservicepasswd:
1420  * @tkts: ticket set handle as allocated by shishi_tkts().
1421  * @service: service name to get ticket for.
1422  * @passwd: password for the default client principal.
1423  *
1424  * Short-hand function for getting a ticket to the given
1425  * local service, and for the default principal client.
1426  * The latter's password is given as argument.
1427  * See shishi_tkts_get().
1428  *
1429  * Return value: Returns a ticket if found, or NULL otherwise.
1430  **/
1431 Shishi_tkt *
shishi_tkts_get_for_localservicepasswd(Shishi_tkts * tkts,const char * service,const char * passwd)1432 shishi_tkts_get_for_localservicepasswd (Shishi_tkts * tkts,
1433 					const char *service,
1434 					const char *passwd)
1435 {
1436   Shishi_tkt *tkt;
1437   Shishi_tkts_hint hint;
1438 
1439   memset (&hint, 0, sizeof (hint));
1440   hint.client = (char *) shishi_principal_default (tkts->handle);
1441   hint.server = shishi_server_for_local_service (tkts->handle, service);
1442   hint.passwd = (char *) passwd;
1443 
1444   tkt = shishi_tkts_get (tkts, &hint);
1445 
1446   free (hint.server);
1447 
1448   return tkt;
1449 }
1450