1 /* tkts.c Ticket set handling.
2 * Copyright (C) 2002, 2003 Simon Josefsson
4 * This file is part of Shishi.
6 * Shishi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Shishi is distributed in the hope that it will be useful,
12 * but 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.
16 * You should have received a copy of the GNU General Public License
17 * along with Shishi; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * shishi_tkts_default_file_guess:
34 * Guesses the default ticket filename; it is $HOME/.shishi/tickets.
36 * Return value: Returns default tkts filename as a string that
37 * has to be deallocated with free() by the caller.
40 shishi_tkts_default_file_guess (void)
45 home
= getenv ("HOME");
50 shishi_asprintf (&p
, "%s%s", home
, TICKET_FILE
);
56 * shishi_tkts_default_file:
57 * @handle: Shishi library handle create by shishi_init().
59 * Return value: Returns the default ticket set filename used in the
60 * library. (Not a copy of it, so don't modify or deallocate it.)
63 shishi_tkts_default_file (Shishi
* handle
)
65 if (!handle
->tktsdefaultfile
)
69 p
= shishi_tkts_default_file_guess ();
70 shishi_tkts_default_file_set (handle
, p
);
74 return handle
->tktsdefaultfile
;
78 * shishi_tkts_default_file_set:
79 * @handle: Shishi library handle create by shishi_init().
80 * @tktsfile: string with new default tkts file name, or
81 * NULL to reset to default.
83 * Set the default ticket set filename used in the library. The
84 * string is copied into the library, so you can dispose of the
85 * variable immediately after calling this function.
88 shishi_tkts_default_file_set (Shishi
* handle
, const char *tktsfile
)
90 if (handle
->tktsdefaultfile
)
91 free (handle
->tktsdefaultfile
);
93 handle
->tktsdefaultfile
= strdup (tktsfile
);
95 handle
->tktsdefaultfile
= NULL
;
99 * shishi_tkts_default:
100 * @handle: Shishi library handle create by shishi_init().
102 * Return value: Return the handle global ticket set.
105 shishi_tkts_default (Shishi
* handle
)
107 if (handle
->tkts
== NULL
&&
108 (shishi_tkts (handle
, &handle
->tkts
) != SHISHI_OK
))
115 shishi_tkts_default_to_file (Shishi_tkts
* tkts
)
117 shishi_tkts_to_file (tkts
, shishi_tkts_default_file (tkts
->handle
));
122 * @handle: shishi handle as allocated by shishi_init().
123 * @tkts: output pointer to newly allocated tkts handle.
125 * Return value: Returns %SHISHI_OK iff successful.
128 shishi_tkts (Shishi
* handle
, Shishi_tkts
** tkts
)
130 *tkts
= malloc (sizeof (**tkts
));
132 return SHISHI_MALLOC_ERROR
;
133 memset (*tkts
, 0, sizeof (**tkts
));
135 (*tkts
)->handle
= handle
;
142 * @tkts: ticket set handle as allocated by shishi_tkts().
144 * Deallocates all resources associated with ticket set. The ticket
145 * set handle must not be used in calls to other shishi_tkts_*()
146 * functions after this.
149 shishi_tkts_done (Shishi_tkts
** tkts
)
167 * @tkts: ticket set handle as allocated by shishi_tkts().
169 * Return value: Returns number of tickets stored in ticket set.
172 shishi_tkts_size (Shishi_tkts
* tkts
)
179 * @tkts: ticket set handle as allocated by shishi_tkts().
180 * @ticketno: integer indicating requested ticket in ticket set.
182 * Return value: Returns a ticket handle to the ticketno:th ticket in
183 * the ticket set, or NULL if ticket set is invalid or ticketno is out
184 * of bounds. The first ticket is ticketno 0, the second ticketno 1,
188 shishi_tkts_nth (Shishi_tkts
* tkts
, int ticketno
)
190 if (tkts
== NULL
|| ticketno
>= tkts
->ntkts
)
193 return tkts
->tkts
[ticketno
];
197 * shishi_tkts_remove:
198 * @tkts: ticket set handle as allocated by shishi_tkts().
199 * @ticketnum: ticket number of ticket in the set to remove. The
200 * first ticket is ticket number 0.
202 * Return value: Returns SHISHI_OK if succesful or if ticketno
203 * larger than size of ticket set.
206 shishi_tkts_remove (Shishi_tkts
* tkts
, int ticketno
)
209 return SHISHI_INVALID_TKTS
;
211 if (ticketno
>= tkts
->ntkts
)
214 if (ticketno
< tkts
->ntkts
)
215 memmove (&tkts
->tkts
[ticketno
], &tkts
->tkts
[ticketno
+ 1],
216 sizeof (*tkts
->tkts
) * (tkts
->ntkts
- ticketno
- 1));
222 tkts
->tkts
= realloc (tkts
->tkts
, sizeof (*tkts
->tkts
) * tkts
->ntkts
);
223 if (tkts
->tkts
== NULL
)
224 return SHISHI_MALLOC_ERROR
;
238 * @tkts: ticket set handle as allocated by shishi_tkts().
239 * @ticket: ticket to be added to ticket set.
241 * Return value: Returns SHISHI_OK iff succesful.
244 shishi_tkts_add (Shishi_tkts
* tkts
, Shishi_tkt
* tkt
)
247 return SHISHI_INVALID_TICKET
;
249 if (tkts
->ntkts
++ == 0)
250 tkts
->tkts
= malloc (sizeof (*tkts
->tkts
));
252 tkts
->tkts
= realloc (tkts
->tkts
, sizeof (*tkts
->tkts
) * tkts
->ntkts
);
253 if (tkts
->tkts
== NULL
)
254 return SHISHI_MALLOC_ERROR
;
256 tkts
->tkts
[tkts
->ntkts
- 1] = tkt
;
263 * @tkts: ticket set handle as allocated by shishi_tkts().
264 * @ticket: input ticket variable.
265 * @enckdcreppart: input ticket detail variable.
266 * @kdcrep: input KDC-REP variable.
268 * Allocate a new ticket and add it to the ticket set.
270 * Return value: Returns SHISHI_OK iff succesful.
273 shishi_tkts_new (Shishi_tkts
* tkts
,
274 Shishi_asn1 ticket
, Shishi_asn1 enckdcreppart
,
280 tkt
= shishi_tkt2 (tkts
->handle
, ticket
, enckdcreppart
, kdcrep
);
282 return SHISHI_MALLOC_ERROR
;
284 res
= shishi_tkts_add (tkts
, tkt
);
285 if (res
!= SHISHI_OK
)
296 * @tkts: ticket set handle as allocated by shishi_tkts().
297 * @fh: file descriptor to read from.
299 * Read tickets from file descriptor and add them to the ticket set.
301 * Return value: Returns SHISHI_OK iff succesful.
304 shishi_tkts_read (Shishi_tkts
* tkts
, FILE * fh
)
312 Shishi_asn1 enckdcreppart
;
315 res
= shishi_kdcrep_parse (tkts
->handle
, fh
, &kdcrep
);
316 if (res
!= SHISHI_OK
)
322 res
= shishi_enckdcreppart_parse (tkts
->handle
, fh
, &enckdcreppart
);
323 if (res
!= SHISHI_OK
)
326 res
= shishi_ticket_parse (tkts
->handle
, fh
, &ticket
);
327 if (res
!= SHISHI_OK
)
330 res
= shishi_tkts_new (tkts
, ticket
, enckdcreppart
, kdcrep
);
331 if (res
!= SHISHI_OK
)
334 if (VERBOSE (tkts
->handle
))
336 printf ("Read ticket for principal `':\n");
337 shishi_kdcrep_print (tkts
->handle
, stdout
, kdcrep
);
338 shishi_enckdcreppart_print (tkts
->handle
, stdout
, enckdcreppart
);
339 shishi_ticket_print (tkts
->handle
, stdout
, ticket
);
347 * shishi_tkts_from_file:
348 * @tkts: ticket set handle as allocated by shishi_tkts().
349 * @filename: filename to read tickets from.
351 * Read tickets from file and add them to the ticket set.
353 * Return value: Returns SHISHI_OK iff succesful.
356 shishi_tkts_from_file (Shishi_tkts
* tkts
, const char *filename
)
361 fh
= fopen (filename
, "r");
363 return SHISHI_FOPEN_ERROR
;
365 res
= shishi_tkts_read (tkts
, fh
);
366 if (res
!= SHISHI_OK
)
374 return SHISHI_FCLOSE_ERROR
;
381 * @tkts: ticket set handle as allocated by shishi_tkts().
382 * @filename: filename to write tickets to.
384 * Write tickets in set to file descriptor.
386 * Return value: Returns SHISHI_OK iff succesful.
389 shishi_tkts_write (Shishi_tkts
* tkts
, FILE * fh
)
394 for (i
= 0; i
< tkts
->ntkts
; i
++)
396 res
= shishi_kdcrep_print
397 (tkts
->handle
, fh
, shishi_tkt_kdcrep (tkts
->tkts
[i
]));
398 if (res
!= SHISHI_OK
)
400 shishi_error_printf (tkts
->handle
,
401 "Could not print ticket: %s\n",
402 shishi_strerror_details (tkts
->handle
));
406 res
= shishi_enckdcreppart_print
407 (tkts
->handle
, fh
, shishi_tkt_enckdcreppart (tkts
->tkts
[i
]));
408 if (res
!= SHISHI_OK
)
410 shishi_error_printf (tkts
->handle
,
411 "Could not print ticket: %s\n",
412 shishi_strerror_details (tkts
->handle
));
416 res
= shishi_ticket_print (tkts
->handle
, fh
,
417 shishi_tkt_ticket (tkts
->tkts
[i
]));
418 if (res
!= SHISHI_OK
)
420 shishi_error_printf (tkts
->handle
,
421 "Could not print ticket: %s\n",
422 shishi_strerror_details (tkts
->handle
));
426 fprintf (fh
, "\n\n");
433 * shishi_tkts_expire:
434 * @tkts: ticket set handle as allocated by shishi_tkts().
436 * Remove expired tickets from ticket set.
438 * Return value: Returns SHISHI_OK iff succesful.
441 shishi_tkts_expire (Shishi_tkts
* tkts
)
446 while (i
< tkts
->ntkts
)
448 if (!shishi_tkt_valid_now_p (tkts
->tkts
[i
]))
451 shishi_tkts_remove (tkts
, i
);
457 if (VERBOSE (tkts
->handle
) && warn
)
458 shishi_warn (tkts
->handle
,
459 ngettext ("removed %d expired ticket\n",
460 "removed %d expired tickets\n", warn
), warn
);
466 * shishi_tkts_to_file:
467 * @tkts: ticket set handle as allocated by shishi_tkts().
468 * @filename: filename to write tickets to.
470 * Write tickets in set to file.
472 * Return value: Returns SHISHI_OK iff succesful.
475 shishi_tkts_to_file (Shishi_tkts
* tkts
, const char *filename
)
480 fh
= fopen (filename
, "w");
482 return SHISHI_FOPEN_ERROR
;
484 res
= shishi_tkts_write (tkts
, fh
);
485 if (res
!= SHISHI_OK
)
493 return SHISHI_FCLOSE_ERROR
;
499 * shishi_tkts_print_for_service:
500 * @tkts: ticket set handle as allocated by shishi_tkts().
501 * @fh: file descriptor to print to.
502 * @service: service to limit tickets printed to, or NULL.
504 * Print description of tickets for specified service to file
505 * descriptor. If service is NULL, all tickets are printed.
507 * Return value: Returns SHISHI_OK iff succesful.
510 shishi_tkts_print_for_service (Shishi_tkts
* tkts
, FILE * fh
,
518 for (i
= 0; i
< shishi_tkts_size (tkts
); i
++)
520 Shishi_tkt
*tkt
= shishi_tkts_nth (tkts
, i
);
527 buflen
= strlen (service
) + 1;
528 buf
= malloc (buflen
);
531 res
= SHISHI_MALLOC_ERROR
;
535 res
= shishi_tkt_server (tkt
, buf
, &buflen
);
536 if (res
!= SHISHI_OK
)
543 if (strcmp (service
, buf
) != 0)
553 res
= shishi_tkt_pretty_print (shishi_tkts_nth (tkts
, i
), fh
);
554 if (res
!= SHISHI_OK
)
562 printf (ngettext ("\n%d ticket found.\n", "\n%d tickets found.\n",
568 printf ("\nNo matching tickets found.\n");
570 printf ("\nNo tickets found.\n");
576 if (res
!= SHISHI_OK
)
577 fprintf (stderr
, "Could not list tickets: %s", shishi_strerror (res
));
583 * @tkts: ticket set handle as allocated by shishi_tkts().
584 * @fh: file descriptor to print to.
586 * Print description of all tickets to file descriptor.
588 * Return value: Returns SHISHI_OK iff succesful.
591 shishi_tkts_print (Shishi_tkts
* tkts
, FILE * fh
)
593 return shishi_tkts_print_for_service (tkts
, fh
, NULL
);
597 * shishi_tkt_match_p:
598 * @tkt: ticket to test hints on.
599 * @hint: structure with characteristics of ticket to be found.
601 * Return value: Returns 0 iff ticket fails to match given criteria.
604 shishi_tkt_match_p (Shishi_tkt
* tkt
, Shishi_tkts_hint
* hint
)
606 if (hint
->server
&& !shishi_tkt_server_p (tkt
, hint
->server
))
609 if (hint
->client
&& !shishi_tkt_client_p (tkt
, hint
->client
))
612 if (!(hint
->flags
& SHISHI_TKTSHINTFLAGS_ACCEPT_EXPIRED
) &&
613 !shishi_tkt_valid_now_p (tkt
))
616 if (hint
->etype
&& !shishi_tkt_keytype_p (tkt
, hint
->etype
))
624 * @tkts: ticket set handle as allocated by shishi_tkts().
625 * @hint: structure with characteristics of ticket to be found.
627 * Search the ticketset sequentially (from ticket number 0 through all
628 * tickets in the set) for a ticket that fits the given
629 * characteristics. If a ticket is found, the hint->startpos field is
630 * updated to point to the next ticket in the set, so this function
631 * can be called repeatedly with the same hint argument in order to
632 * find all tickets matching a certain criterium. Note that if
633 * tickets are added to, or removed from, the ticketset during a query
634 * with the same hint argument, the hint->startpos field must be
635 * updated appropriately.
637 * Here is how you would typically use this function:
639 * Shishi_tkts_hint hint;
645 * memset(&hint, 0, sizeof(hint));
647 * hint.server = "imap/mail.example.org";
649 * tkt = shishi_tkts_find (shishi_tkts_default(handle), &hint);
653 * printf("No ticket found...\n");
657 * ...do something with ticket
659 * Return value: Returns a ticket if found, or NULL if no further
660 * matching tickets could be found.
663 shishi_tkts_find (Shishi_tkts
* tkts
, Shishi_tkts_hint
* hint
)
667 if (VERBOSENOICE(tkts
->handle
))
669 fprintf (stderr
, "Searching tickets... ");
671 fprintf (stderr
, "server=`%s' ", hint
->server
);
673 fprintf (stderr
, "client=`%s' ", hint
->client
);
674 fprintf (stderr
, "\n");
677 for (i
= hint
->startpos
; i
< tkts
->ntkts
; i
++)
679 if (!shishi_tkt_match_p (tkts
->tkts
[i
], hint
))
682 hint
->startpos
= i
+ 1;
683 return tkts
->tkts
[i
];
691 * shishi_tkts_find_for_clientserver:
692 * @tkts: ticket set handle as allocated by shishi_tkts().
693 * @client: client name to find ticket for.
694 * @server: server name to find ticket for.
696 * Short-hand function for searching the ticket set for a ticket for
697 * the given client and server. See shishi_tkts_find().
699 * Return value: Returns a ticket if found, or NULL.
702 shishi_tkts_find_for_clientserver (Shishi_tkts
* tkts
,
703 const char *client
, const char *server
)
705 Shishi_tkts_hint hint
;
708 memset (&hint
, 0, sizeof (hint
));
709 hint
.server
= server
;
710 hint
.client
= client
;
712 tkt
= shishi_tkts_find (tkts
, &hint
);
718 * shishi_tkts_find_for_server:
719 * @tkts: ticket set handle as allocated by shishi_tkts().
720 * @server: server name to find ticket for.
722 * Short-hand function for searching the ticket set for a ticket for
723 * the given server using the default client principal. See
724 * shishi_tkts_find_for_clientserver() and shishi_tkts_find().
726 * Return value: Returns a ticket if found, or NULL.
729 shishi_tkts_find_for_server (Shishi_tkts
* tkts
, const char *server
)
731 return shishi_tkts_find_for_clientserver
732 (tkts
, shishi_principal_default (tkts
->handle
), server
);
737 * @tkts: ticket set handle as allocated by shishi_tkts().
738 * @hint: structure with characteristics of ticket to begot.
740 * Get a ticket matching given characteristics. This function first
741 * looks in the ticket set for the ticket, then tries to find a TGT
742 * for the realm (possibly by using an AS exchange) and then use the
743 * TGT in a TGS exchange to get the ticket. Currently this function
744 * do not implement cross realm logic.
746 * Return value: Returns a ticket if found, or NULL if this function
747 * is unable to get the ticket.
750 shishi_tkts_get (Shishi_tkts
* tkts
, Shishi_tkts_hint
* hint
)
752 Shishi_tkts_hint lochint
;
753 Shishi_tkt
*tkt
, *tgt
;
759 pos
= hint
->startpos
;
761 /* Try to get cached ticket ... */
762 tkt
= shishi_tkts_find (tkts
, hint
);
766 hint
->startpos
= pos
;
768 /* Try to get cached TGT ... */
769 memset (&lochint
, 0, sizeof (lochint
));
770 shishi_asprintf (&tgtname
, "krbtgt/%s",
771 shishi_realm_default (tkts
->handle
));
772 lochint
.server
= tgtname
;
773 tgt
= shishi_tkts_find (tkts
, &lochint
);
778 /* Get TGT ... XXX cross realm */
780 rc
= shishi_as (tkts
->handle
, &as
);
782 rc
= shishi_as_sendrecv (as
);
784 rc
= shishi_as_rep_process (as
, NULL
, hint
->passwd
);
787 printf ("AS exchange failed: %s\n%s\n", shishi_strerror (rc
),
788 shishi_strerror_details (tkts
->handle
));
789 if (rc
== SHISHI_GOT_KRBERROR
)
790 shishi_krberror_pretty_print (tkts
->handle
, stdout
,
791 shishi_as_krberror (as
));
795 tgt
= shishi_as_tkt (as
);
799 printf ("No ticket in AS-REP?!: %s\n",
800 shishi_strerror_details (tkts
->handle
));
804 if (VERBOSEASN1 (tkts
->handle
))
805 shishi_tkt_pretty_print (tgt
, stdout
);
807 rc
= shishi_tkts_add (tkts
, tgt
);
809 printf ("Could not add ticket: %s", shishi_strerror (rc
));
813 /* Maybe user asked for TGT ... */
814 if (shishi_tkt_match_p (tgt
, hint
))
817 /* Get ticket using TGT ... */
818 rc
= shishi_tgs (tkts
->handle
, &tgs
);
819 shishi_tgs_tgtkt_set (tgs
, tgt
);
821 rc
= shishi_tgs_set_server (tgs
, hint
->server
);
823 rc
= shishi_tgs_req_build (tgs
);
825 rc
= shishi_tgs_sendrecv (tgs
);
827 rc
= shishi_tgs_rep_process (tgs
);
830 printf ("TGS exchange failed: %s\n%s\n", shishi_strerror (rc
),
831 shishi_strerror_details (tkts
->handle
));
832 if (rc
== SHISHI_GOT_KRBERROR
)
833 shishi_krberror_pretty_print (tkts
->handle
, stdout
,
834 shishi_tgs_krberror (tgs
));
838 tkt
= shishi_tgs_tkt (tgs
);
842 printf ("No ticket in TGS-REP?!: %s\n",
843 shishi_strerror_details (tkts
->handle
));
847 if (VERBOSEASN1 (tkts
->handle
))
848 shishi_tkt_pretty_print (tkt
, stdout
);
850 rc
= shishi_tkts_add (tkts
, tkt
);
852 printf ("Could not add ticket: %s", shishi_strerror (rc
));
858 * shishi_tkts_get_for_clientserver:
859 * @tkts: ticket set handle as allocated by shishi_tkts().
860 * @client: client name to get ticket for.
861 * @server: server name to get ticket for.
863 * Short-hand function for getting a ticket for the given client and
864 * server. See shishi_tkts_get().
866 * Return value: Returns a ticket if found, or NULL.
869 shishi_tkts_get_for_clientserver (Shishi_tkts
* tkts
,
870 const char *client
, const char *server
)
872 Shishi_tkts_hint hint
;
875 memset (&hint
, 0, sizeof (hint
));
876 hint
.client
= client
;
877 hint
.server
= server
;
879 tkt
= shishi_tkts_get (tkts
, &hint
);
885 * shishi_tkts_get_for_server:
886 * @tkts: ticket set handle as allocated by shishi_tkts().
887 * @server: server name to get ticket for.
889 * Short-hand function for getting a ticket for the given server and
890 * the default principal client. See shishi_tkts_get().
892 * Return value: Returns a ticket if found, or NULL.
895 shishi_tkts_get_for_server (Shishi_tkts
* tkts
, const char *server
)
897 return shishi_tkts_get_for_clientserver
898 (tkts
, shishi_principal_default (tkts
->handle
), server
);
902 shishi_tkts_get_for_localservicepasswd (Shishi_tkts
* tkts
,
906 Shishi_tkts_hint hint
;
907 char buf
[HOST_NAME_MAX
];
910 strcpy (buf
, service
);
913 ret
= gethostname (&buf
[strlen (service
) + 1],
914 sizeof (buf
) - strlen (service
) - 1);
915 buf
[sizeof (buf
) - 1] = '\0';
918 strcpy (&buf
[strlen (service
) + 1], "localhost");
920 memset (&hint
, 0, sizeof (hint
));
921 hint
.client
= shishi_principal_default (tkts
->handle
);
923 hint
.passwd
= passwd
;
925 return shishi_tkts_get (tkts
, &hint
);