1 /* tkts.c --- Ticket set handling.
2 * Copyright (C) 2002, 2003, 2004, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
31 #define TICKET_FILE "tickets"
34 * shishi_tkts_default_file_guess:
35 * @handle: Shishi library handle create by shishi_init().
37 * Guesses the default ticket filename; it is $SHISHI_TICKETS,
38 * $SHISHI_HOME/tickets, or $HOME/.shishi/tickets.
40 * Return value: Returns default tkts filename as a string that
41 * has to be deallocated with free() by the caller.
44 shishi_tkts_default_file_guess (Shishi
* handle
)
48 envfile
= getenv ("SHISHI_TICKETS");
50 return xstrdup (envfile
);
52 return shishi_cfg_userdirectory_file (handle
, TICKET_FILE
);
56 * shishi_tkts_default_file:
57 * @handle: Shishi library handle create by shishi_init().
59 * Get filename of default ticket set.
61 * Return value: Returns the default ticket set filename used in the
62 * library. The string is not a copy, so don't modify or deallocate
66 shishi_tkts_default_file (Shishi
* handle
)
68 if (!handle
->tktsdefaultfile
)
72 p
= shishi_tkts_default_file_guess (handle
);
73 shishi_tkts_default_file_set (handle
, p
);
77 return handle
->tktsdefaultfile
;
81 * shishi_tkts_default_file_set:
82 * @handle: Shishi library handle create by shishi_init().
83 * @tktsfile: string with new default tkts file name, or
84 * NULL to reset to default.
86 * Set the default ticket set filename used in the library. The
87 * string is copied into the library, so you can dispose of the
88 * variable immediately after calling this function.
91 shishi_tkts_default_file_set (Shishi
* handle
, const char *tktsfile
)
93 if (handle
->tktsdefaultfile
)
94 free (handle
->tktsdefaultfile
);
96 handle
->tktsdefaultfile
= xstrdup (tktsfile
);
98 handle
->tktsdefaultfile
= NULL
;
102 * shishi_tkts_default:
103 * @handle: Shishi library handle create by shishi_init().
105 * Get the default ticket set for library handle.
107 * Return value: Return the handle global ticket set.
110 shishi_tkts_default (Shishi
* handle
)
112 if (handle
->tkts
== NULL
&&
113 (shishi_tkts (handle
, &handle
->tkts
) != SHISHI_OK
))
120 shishi_tkts_default_to_file (Shishi_tkts
* tkts
)
122 return shishi_tkts_to_file (tkts
, shishi_tkts_default_file (tkts
->handle
));
127 * @handle: shishi handle as allocated by shishi_init().
128 * @tkts: output pointer to newly allocated tkts handle.
130 * Get a new ticket set handle.
132 * Return value: Returns %SHISHI_OK iff successful.
135 shishi_tkts (Shishi
* handle
, Shishi_tkts
** tkts
)
137 *tkts
= xcalloc (1, sizeof (**tkts
));
139 (*tkts
)->handle
= handle
;
146 * @tkts: ticket set handle as allocated by shishi_tkts().
148 * Deallocates all resources associated with ticket set. The ticket
149 * set handle must not be used in calls to other shishi_tkts_*()
150 * functions after this.
153 shishi_tkts_done (Shishi_tkts
** tkts
)
159 free ((*tkts
)->tkts
);
169 * @tkts: ticket set handle as allocated by shishi_tkts().
171 * Get size of ticket set.
173 * Return value: Returns number of tickets stored in ticket set.
176 shishi_tkts_size (Shishi_tkts
* tkts
)
183 * @tkts: ticket set handle as allocated by shishi_tkts().
184 * @ticketno: integer indicating requested ticket in ticket set.
186 * Get the n:th ticket in ticket set.
188 * Return value: Returns a ticket handle to the ticketno:th ticket in
189 * the ticket set, or NULL if ticket set is invalid or ticketno is
190 * out of bounds. The first ticket is ticketno 0, the second
191 * ticketno 1, and so on.
194 shishi_tkts_nth (Shishi_tkts
* tkts
, int ticketno
)
196 if (tkts
== NULL
|| ticketno
>= tkts
->ntkts
)
199 return tkts
->tkts
[ticketno
];
203 * shishi_tkts_remove:
204 * @tkts: ticket set handle as allocated by shishi_tkts().
205 * @ticketno: ticket number of ticket in the set to remove. The first
206 * ticket is ticket number 0.
208 * Remove a ticket, indexed by @ticketno, in ticket set.
210 * Return value: Returns SHISHI_OK if succesful or if ticketno larger
211 * than size of ticket set.
214 shishi_tkts_remove (Shishi_tkts
* tkts
, int ticketno
)
217 return SHISHI_INVALID_TKTS
;
219 if (ticketno
>= tkts
->ntkts
)
222 if (ticketno
< tkts
->ntkts
)
223 memmove (&tkts
->tkts
[ticketno
], &tkts
->tkts
[ticketno
+ 1],
224 sizeof (*tkts
->tkts
) * (tkts
->ntkts
- ticketno
- 1));
230 tkts
->tkts
= xrealloc (tkts
->tkts
, sizeof (*tkts
->tkts
) * tkts
->ntkts
);
244 * @tkts: ticket set handle as allocated by shishi_tkts().
245 * @tkt: ticket to be added to ticket set.
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
251 * Return value: Returns SHISHI_OK iff succesful.
254 shishi_tkts_add (Shishi_tkts
* tkts
, Shishi_tkt
* tkt
)
257 return SHISHI_INVALID_TICKET
;
259 if (tkts
->ntkts
++ == 0)
260 tkts
->tkts
= xmalloc (sizeof (*tkts
->tkts
));
262 tkts
->tkts
= xrealloc (tkts
->tkts
, sizeof (*tkts
->tkts
) * tkts
->ntkts
);
264 tkts
->tkts
[tkts
->ntkts
- 1] = tkt
;
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.
276 * Allocate a new ticket and add it to the ticket set.
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.
282 * Return value: Returns SHISHI_OK iff succesful.
285 shishi_tkts_new (Shishi_tkts
* tkts
,
286 Shishi_asn1 ticket
, Shishi_asn1 enckdcreppart
,
292 /* XXX Who will de-allocate these? */
293 tkt
= shishi_tkt2 (tkts
->handle
, ticket
, enckdcreppart
, kdcrep
);
295 res
= shishi_tkts_add (tkts
, tkt
);
296 if (res
!= SHISHI_OK
)
307 * @tkts: ticket set handle as allocated by shishi_tkts().
308 * @fh: file descriptor to read from.
310 * Read tickets from file descriptor and add them to the ticket set.
312 * Return value: Returns SHISHI_OK iff succesful.
315 shishi_tkts_read (Shishi_tkts
* tkts
, FILE * fh
)
323 Shishi_asn1 enckdcreppart
;
326 res
= shishi_kdcrep_parse (tkts
->handle
, fh
, &kdcrep
);
327 if (res
!= SHISHI_OK
)
333 res
= shishi_enckdcreppart_parse (tkts
->handle
, fh
, &enckdcreppart
);
334 if (res
!= SHISHI_OK
)
337 res
= shishi_ticket_parse (tkts
->handle
, fh
, &ticket
);
338 if (res
!= SHISHI_OK
)
341 /* XXX Who will de-allocate these? */
342 res
= shishi_tkts_new (tkts
, ticket
, enckdcreppart
, kdcrep
);
343 if (res
!= SHISHI_OK
)
346 if (VERBOSEASN1 (tkts
->handle
))
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
);
359 * shishi_tkts_from_file:
360 * @tkts: ticket set handle as allocated by shishi_tkts().
361 * @filename: filename to read tickets from.
363 * Read tickets from file and add them to the ticket set.
365 * Return value: Returns SHISHI_OK iff succesful.
368 shishi_tkts_from_file (Shishi_tkts
* tkts
, const char *filename
)
373 fh
= fopen (filename
, "r");
375 return SHISHI_FOPEN_ERROR
;
377 res
= shishi_tkts_read (tkts
, fh
);
378 if (res
!= SHISHI_OK
)
386 return SHISHI_IO_ERROR
;
393 * @tkts: ticket set handle as allocated by shishi_tkts().
394 * @fh: file descriptor to write tickets to.
396 * Write tickets in set to file descriptor.
398 * Return value: Returns SHISHI_OK iff succesful.
401 shishi_tkts_write (Shishi_tkts
* tkts
, FILE * fh
)
406 for (i
= 0; i
< tkts
->ntkts
; i
++)
408 res
= shishi_kdcrep_print
409 (tkts
->handle
, fh
, shishi_tkt_kdcrep (tkts
->tkts
[i
]));
410 if (res
!= SHISHI_OK
)
412 shishi_error_printf (tkts
->handle
,
413 "Could not print ticket: %s",
414 shishi_error (tkts
->handle
));
418 res
= shishi_enckdcreppart_print
419 (tkts
->handle
, fh
, shishi_tkt_enckdcreppart (tkts
->tkts
[i
]));
420 if (res
!= SHISHI_OK
)
422 shishi_error_printf (tkts
->handle
,
423 "Could not print ticket: %s",
424 shishi_error (tkts
->handle
));
428 res
= shishi_ticket_print (tkts
->handle
, fh
,
429 shishi_tkt_ticket (tkts
->tkts
[i
]));
430 if (res
!= SHISHI_OK
)
432 shishi_error_printf (tkts
->handle
,
433 "Could not print ticket: %s",
434 shishi_error (tkts
->handle
));
438 fprintf (fh
, "\n\n");
445 * shishi_tkts_expire:
446 * @tkts: ticket set handle as allocated by shishi_tkts().
448 * Remove expired tickets from ticket set.
450 * Return value: Returns SHISHI_OK iff succesful.
453 shishi_tkts_expire (Shishi_tkts
* tkts
)
458 while (i
< tkts
->ntkts
)
460 if (shishi_tkt_expired_p (tkts
->tkts
[i
]))
463 shishi_tkts_remove (tkts
, i
);
469 if (VERBOSE (tkts
->handle
) && warn
)
470 shishi_warn (tkts
->handle
,
471 ngettext ("removed %d expired ticket\n",
472 "removed %d expired tickets\n", warn
), warn
);
478 * shishi_tkts_to_file:
479 * @tkts: ticket set handle as allocated by shishi_tkts().
480 * @filename: filename to write tickets to.
482 * Write tickets in set to file.
484 * Return value: Returns SHISHI_OK iff succesful.
487 shishi_tkts_to_file (Shishi_tkts
* tkts
, const char *filename
)
492 fh
= fopen (filename
, "w");
494 return SHISHI_FOPEN_ERROR
;
496 res
= shishi_tkts_write (tkts
, fh
);
497 if (res
!= SHISHI_OK
)
505 return SHISHI_IO_ERROR
;
511 * shishi_tkts_print_for_service:
512 * @tkts: ticket set handle as allocated by shishi_tkts().
513 * @fh: file descriptor to print to.
514 * @service: service to limit tickets printed to, or NULL.
516 * Print description of tickets for specified service to file
517 * descriptor. If service is NULL, all tickets are printed.
519 * Return value: Returns SHISHI_OK iff succesful.
522 shishi_tkts_print_for_service (Shishi_tkts
* tkts
, FILE * fh
,
530 for (i
= 0; i
< shishi_tkts_size (tkts
); i
++)
532 Shishi_tkt
*tkt
= shishi_tkts_nth (tkts
, i
);
538 res
= shishi_tkt_server (tkt
, &buf
, NULL
);
539 if (res
!= SHISHI_OK
)
542 if (strcmp (service
, buf
) != 0)
552 shishi_tkt_pretty_print (shishi_tkts_nth (tkts
, i
), fh
);
558 printf (ngettext ("\n%d ticket found.\n", "\n%d tickets found.\n",
564 printf ("\nNo matching tickets found.\n");
566 printf ("\nNo tickets found.\n");
574 * @tkts: ticket set handle as allocated by shishi_tkts().
575 * @fh: file descriptor to print to.
577 * Print description of all tickets to file descriptor.
579 * Return value: Returns SHISHI_OK iff succesful.
582 shishi_tkts_print (Shishi_tkts
* tkts
, FILE * fh
)
584 return shishi_tkts_print_for_service (tkts
, fh
, NULL
);
588 * shishi_tkt_match_p:
589 * @tkt: ticket to test hints on.
590 * @hint: structure with characteristics of ticket to be found.
592 * Test if a ticket matches specified hints.
594 * Return value: Returns 0 iff ticket fails to match given criteria.
597 shishi_tkt_match_p (Shishi_tkt
* tkt
, Shishi_tkts_hint
* hint
)
599 if (hint
->server
&& !shishi_tkt_server_p (tkt
, hint
->server
))
602 if (hint
->client
&& !shishi_tkt_client_p (tkt
, hint
->client
))
605 if (!(hint
->flags
& SHISHI_TKTSHINTFLAGS_ACCEPT_EXPIRED
) &&
606 !shishi_tkt_valid_now_p (tkt
))
609 if ((hint
->tktflags
& SHISHI_TICKETFLAGS_FORWARDABLE
) &&
610 !shishi_tkt_forwardable_p (tkt
))
613 if ((hint
->tktflags
& SHISHI_TICKETFLAGS_FORWARDED
) &&
614 !shishi_tkt_forwarded_p (tkt
))
617 if ((hint
->tktflags
& SHISHI_TICKETFLAGS_RENEWABLE
) &&
618 !shishi_tkt_renewable_p (tkt
))
621 if ((hint
->tktflags
& SHISHI_TICKETFLAGS_PROXIABLE
) &&
622 !shishi_tkt_proxiable_p (tkt
))
625 if ((hint
->tktflags
& SHISHI_TICKETFLAGS_PROXY
) &&
626 !shishi_tkt_proxy_p (tkt
))
629 if (hint
->etype
&& !shishi_tkt_keytype_p (tkt
, hint
->etype
))
637 * @tkts: ticket set handle as allocated by shishi_tkts().
638 * @hint: structure with characteristics of ticket to be found.
640 * Search the ticketset sequentially (from ticket number 0 through all
641 * tickets in the set) for a ticket that fits the given
642 * characteristics. If a ticket is found, the hint->startpos field is
643 * updated to point to the next ticket in the set, so this function
644 * can be called repeatedly with the same hint argument in order to
645 * find all tickets matching a certain criterium. Note that if
646 * tickets are added to, or removed from, the ticketset during a query
647 * with the same hint argument, the hint->startpos field must be
648 * updated appropriately.
650 * Here is how you would typically use this function:
652 * Shishi_tkts_hint hint;
658 * memset(&hint, 0, sizeof(hint));
660 * hint.server = "imap/mail.example.org";
662 * tkt = shishi_tkts_find (shishi_tkts_default(handle), &hint);
666 * printf("No ticket found...\n");
670 * ...do something with ticket
672 * Return value: Returns a ticket if found, or NULL if no further
673 * matching tickets could be found.
676 shishi_tkts_find (Shishi_tkts
* tkts
, Shishi_tkts_hint
* hint
)
680 if (VERBOSENOISE (tkts
->handle
))
682 fprintf (stderr
, "Searching tickets... ");
684 fprintf (stderr
, "server=`%s' ", hint
->server
);
686 fprintf (stderr
, "client=`%s' ", hint
->client
);
687 fprintf (stderr
, "\n");
690 for (i
= hint
->startpos
; i
< tkts
->ntkts
; i
++)
692 if (!shishi_tkt_match_p (tkts
->tkts
[i
], hint
))
695 hint
->startpos
= i
+ 1;
696 return tkts
->tkts
[i
];
704 * shishi_tkts_find_for_clientserver:
705 * @tkts: ticket set handle as allocated by shishi_tkts().
706 * @client: client name to find ticket for.
707 * @server: server name to find ticket for.
709 * Short-hand function for searching the ticket set for a ticket for
710 * the given client and server. See shishi_tkts_find().
712 * Return value: Returns a ticket if found, or NULL.
715 shishi_tkts_find_for_clientserver (Shishi_tkts
* tkts
,
716 const char *client
, const char *server
)
718 Shishi_tkts_hint hint
;
721 memset (&hint
, 0, sizeof (hint
));
722 hint
.server
= (char *) server
;
723 hint
.client
= (char *) client
;
725 tkt
= shishi_tkts_find (tkts
, &hint
);
731 * shishi_tkts_find_for_server:
732 * @tkts: ticket set handle as allocated by shishi_tkts().
733 * @server: server name to find ticket for.
735 * Short-hand function for searching the ticket set for a ticket for
736 * the given server using the default client principal. See
737 * shishi_tkts_find_for_clientserver() and shishi_tkts_find().
739 * Return value: Returns a ticket if found, or NULL.
742 shishi_tkts_find_for_server (Shishi_tkts
* tkts
, const char *server
)
744 return shishi_tkts_find_for_clientserver
745 (tkts
, shishi_principal_default (tkts
->handle
), server
);
748 /* Set flags and times in KDC-REQ based on hint. */
750 act_hint_on_kdcreq (Shishi
* handle
,
751 Shishi_tkts_hint
* hint
, Shishi_asn1 kdcreq
)
753 time_t starttime
= hint
->starttime
? hint
->starttime
: time (NULL
);
754 time_t endtime
= hint
->endtime
? hint
->endtime
:
755 starttime
+ handle
->ticketlife
;
756 time_t renew_till
= hint
->renew_till
? hint
->renew_till
:
757 starttime
+ handle
->renewlife
;
762 rc
= shishi_asn1_write (handle
, kdcreq
, "req-body.from",
763 shishi_generalize_time (handle
, starttime
), 0);
766 shishi_error_printf (handle
, "Cannot set starttime: %s",
767 shishi_strerror (rc
));
774 rc
= shishi_asn1_write (handle
, kdcreq
, "req-body.till",
775 shishi_generalize_time (handle
, endtime
), 0);
778 shishi_error_printf (handle
, "Cannot set endtime: %s",
779 shishi_strerror (rc
));
784 if (hint
->tktflags
& SHISHI_TICKETFLAGS_FORWARDABLE
)
786 rc
= shishi_kdcreq_options_add (handle
, kdcreq
,
787 SHISHI_KDCOPTIONS_FORWARDABLE
);
792 if (hint
->tktflags
& SHISHI_TICKETFLAGS_FORWARDED
)
794 rc
= shishi_kdcreq_options_add (handle
, kdcreq
,
795 SHISHI_KDCOPTIONS_FORWARDED
);
800 if (hint
->tktflags
& SHISHI_TICKETFLAGS_RENEWABLE
)
802 rc
= shishi_kdcreq_options_add (handle
, kdcreq
,
803 SHISHI_KDCOPTIONS_RENEWABLE
);
807 rc
= shishi_asn1_write (handle
, kdcreq
, "req-body.rtime",
808 shishi_generalize_time (handle
, renew_till
), 0);
811 shishi_error_printf (handle
, "Cannot set renewtill: %s",
812 shishi_strerror (rc
));
817 if (hint
->tktflags
& SHISHI_TICKETFLAGS_PROXIABLE
)
819 rc
= shishi_kdcreq_options_add (handle
, kdcreq
,
820 SHISHI_KDCOPTIONS_PROXIABLE
);
825 if (hint
->tktflags
& SHISHI_TICKETFLAGS_PROXY
)
827 rc
= shishi_kdcreq_options_add (handle
, kdcreq
,
828 SHISHI_KDCOPTIONS_PROXY
);
836 rc
= shishi_kdcreq_set_etype (handle
, kdcreq
, &hint
->etype
, 1);
844 shishi_error_printf (handle
, "Cannot set KDC Options: %s",
845 shishi_strerror (rc
));
849 /* Make sure the ticket granting ticket is suitable for the wanted
850 ticket. E.g., if the wanted ticket should be a PROXY ticket, the
851 ticket granting ticket must be a PROXIABLE ticket for things to
854 set_tgtflags_based_on_hint (Shishi_tkts_hint
* tkthint
,
855 Shishi_tkts_hint
* tgthint
)
857 if (tkthint
->tktflags
& SHISHI_TICKETFLAGS_FORWARDABLE
)
858 tgthint
->tktflags
|= SHISHI_TICKETFLAGS_FORWARDABLE
;
860 if (tkthint
->tktflags
& SHISHI_TICKETFLAGS_FORWARDED
)
861 tgthint
->tktflags
|= SHISHI_TICKETFLAGS_FORWARDABLE
;
863 if (tkthint
->tktflags
& SHISHI_TICKETFLAGS_PROXIABLE
)
864 tgthint
->tktflags
|= SHISHI_TICKETFLAGS_PROXIABLE
;
866 if (tkthint
->tktflags
& SHISHI_TICKETFLAGS_PROXY
)
867 tgthint
->tktflags
|= SHISHI_TICKETFLAGS_PROXIABLE
;
869 if (tkthint
->tktflags
& SHISHI_TICKETFLAGS_RENEWABLE
)
870 tgthint
->tktflags
|= SHISHI_TICKETFLAGS_RENEWABLE
;
872 if (tkthint
->kdcoptions
& SHISHI_KDCOPTIONS_RENEW
)
873 tgthint
->tktflags
|= SHISHI_TICKETFLAGS_RENEWABLE
;
875 if (tkthint
->endtime
)
876 tgthint
->endtime
= tkthint
->endtime
;
879 tgthint
->passwd
= tkthint
->passwd
;
881 if (tkthint
->preauthetype
)
882 tgthint
->preauthetype
= tkthint
->preauthetype
;
884 if (tkthint
->preauthsalt
)
886 tgthint
->preauthsalt
= tkthint
->preauthsalt
;
887 tgthint
->preauthsaltlen
= tkthint
->preauthsaltlen
;
890 if (tkthint
->preauths2kparams
)
892 tgthint
->preauths2kparams
= tkthint
->preauths2kparams
;
893 tgthint
->preauths2kparamslen
= tkthint
->preauths2kparamslen
;
897 /* Pre-authenticate request, based on LOCHINT. Currently only
898 PA-ENC-TIMESTAMP is supported. */
900 do_preauth (Shishi_tkts
*tkts
, Shishi_tkts_hint
*lochint
, Shishi_as
*as
)
904 if (lochint
->preauthetype
)
909 /* XXX Don't prompt for password here? */
911 rc
= shishi_asreq_clientrealm (tkts
->handle
, shishi_as_req (as
),
916 rc
= shishi_prompt_password (tkts
->handle
, &lochint
->passwd
,
917 "Enter password for `%s': ", user
);
921 if (!lochint
->preauthsalt
)
923 rc
= shishi_derive_default_salt (tkts
->handle
, user
,
924 &lochint
->preauthsalt
);
928 lochint
->preauthsaltlen
= strlen (lochint
->preauthsalt
);
931 rc
= shishi_key_from_string (tkts
->handle
, lochint
->preauthetype
,
932 lochint
->passwd
, strlen (lochint
->passwd
),
933 lochint
->preauthsalt
,
934 lochint
->preauthsaltlen
,
935 lochint
->preauths2kparams
, &key
);
939 rc
= shishi_kdcreq_add_padata_preauth (tkts
->handle
,
940 shishi_as_req (as
), key
);
946 /* Handle ETYPE-INFO and ETYPE-INFO2 pre-auth data. */
948 recover_preauth_info (Shishi_tkts
*tkts
,
950 Shishi_tkts_hint
*lochint
,
955 size_t foundpos
= SIZE_MAX
;
959 shishi_verbose (tkts
->handle
, "Found INFO-ETYPE(2) pre-auth hints");
961 if (VERBOSEASN1(tkts
->handle
))
964 shishi_etype_info2_print (tkts
->handle
, stdout
, einfos
);
966 shishi_etype_info_print (tkts
->handle
, stdout
, einfos
);
969 if (lochint
->preauthetype
)
971 shishi_verbose (tkts
->handle
, "Pre-auth data already specified");
975 rc
= shishi_asn1_number_of_elements (tkts
->handle
, einfos
, "", &n
);
979 for (i
= 1; i
<= n
; i
++)
984 format
= xasprintf ("?%d.etype", i
);
985 rc
= shishi_asn1_read_int32 (tkts
->handle
, einfos
, format
, &etype
);
991 shishi_verbose (tkts
->handle
, "Server has etype %d", etype
);
993 for (j
= 0; j
< tkts
->handle
->nclientkdcetypes
; j
++)
995 if (etype
== tkts
->handle
->clientkdcetypes
[j
])
997 if (j
< foundpos
&& VERBOSENOISE(tkts
->handle
))
1002 shishi_verbose (tkts
->handle
, "New best etype %d", etype
);
1006 format
= xasprintf ("?%d.salt", i
);
1007 rc
= shishi_asn1_read (tkts
->handle
, einfos
, format
,
1008 &lochint
->preauthsalt
,
1009 &lochint
->preauthsaltlen
);
1011 if (rc
!= SHISHI_OK
&& rc
!= SHISHI_ASN1_NO_ELEMENT
)
1016 format
= xasprintf ("?%d.s2kparams", i
);
1017 rc
= shishi_asn1_read (tkts
->handle
, einfos
, format
,
1018 &lochint
->preauths2kparams
,
1019 &lochint
->preauths2kparamslen
);
1021 if (rc
!= SHISHI_OK
&& rc
!= SHISHI_ASN1_NO_ELEMENT
)
1026 foundpos
= MIN(foundpos
, j
);
1032 if (foundpos
!= SIZE_MAX
)
1034 lochint
->preauthetype
= tkts
->handle
->clientkdcetypes
[foundpos
];
1036 shishi_verbose (tkts
->handle
, "Best pre-auth etype was %d",
1037 lochint
->preauthetype
);
1045 /* Called when KDC refused with a NEED_PREAUTH error. This function
1046 should look at the METHOD-DATA, figure out what kind of pre-auth is
1047 requested, and if it is able to figure out how to recover from the
1048 error, set *RETRY to true and set any hints in LOCHINT that help
1049 do_preauth() compute the proper pre-auth data. */
1051 recover_preauth (Shishi_tkts
*tkts
,
1053 Shishi_tkts_hint
*lochint
,
1056 Shishi_asn1 krberror
= shishi_as_krberror (as
);
1063 shishi_verbose (tkts
->handle
, "Server requests pre-auth data");
1065 rc
= shishi_krberror_methoddata (tkts
->handle
, krberror
, &pas
);
1066 if (rc
!= SHISHI_OK
)
1069 rc
= shishi_asn1_number_of_elements (tkts
->handle
, pas
, "", &n
);
1070 if (rc
== SHISHI_OK
)
1072 for (i
= 1; i
<= n
; i
++)
1074 char *format
= xasprintf ("?%d.padata-type", i
);
1077 rc
= shishi_asn1_read_int32 (tkts
->handle
, pas
, format
,
1080 if (rc
== SHISHI_OK
)
1082 shishi_verbose (tkts
->handle
, "Looking at pa-type %d",
1087 /* XXX Don't parse INFO structures if there is a
1090 case SHISHI_PA_ETYPE_INFO
:
1091 case SHISHI_PA_ETYPE_INFO2
:
1097 format
= xasprintf ("?%d.padata-value", i
);
1098 rc
= shishi_asn1_read (tkts
->handle
, pas
, format
,
1101 if (rc
!= SHISHI_OK
)
1103 shishi_error_printf (tkts
->handle
,
1104 "Can't extract PA-DATA value");
1108 if (padatatype
== SHISHI_PA_ETYPE_INFO
)
1109 einfos
= shishi_der2asn1_etype_info (tkts
->handle
,
1112 einfos
= shishi_der2asn1_etype_info2 (tkts
->handle
,
1117 shishi_error_printf (tkts
->handle
,
1118 "Can't DER decode PA-DATA");
1122 rc
= recover_preauth_info
1123 (tkts
, as
, lochint
, einfos
,
1124 padatatype
== SHISHI_PA_ETYPE_INFO2
, retry
);
1125 if (rc
!= SHISHI_OK
)
1127 shishi_error_printf (tkts
->handle
,
1128 "Could not use pre-auth data: %s",
1129 shishi_strerror (rc
));
1133 shishi_asn1_done (tkts
->handle
, einfos
);
1144 shishi_asn1_done (tkts
->handle
, pas
);
1150 * shishi_tkts_get_tgt:
1151 * @tkts: ticket set handle as allocated by shishi_tkts().
1152 * @hint: structure with characteristics of ticket to begot.
1154 * Get a ticket granting ticket (TGT) suitable for acquiring ticket
1155 * matching the hint. I.e., get a TGT for the server realm in the
1156 * hint structure (hint->serverrealm), or the default realm if the
1157 * serverrealm field is NULL. Can result in AS exchange.
1159 * Currently this function do not implement cross realm logic.
1161 * This function is used by shishi_tkts_get(), which is probably what
1162 * you really want to use unless you have special needs.
1164 * Return value: Returns a ticket granting ticket if successful, or
1165 * NULL if this function is unable to acquire on.
1168 shishi_tkts_get_tgt (Shishi_tkts
* tkts
, Shishi_tkts_hint
* hint
)
1170 Shishi_tkts_hint lochint
;
1175 /* XXX cross-realm operation */
1177 memset (&lochint
, 0, sizeof (lochint
));
1178 asprintf (&lochint
.server
, "krbtgt/%s", hint
->serverrealm
?
1179 hint
->serverrealm
: shishi_realm_default (tkts
->handle
));
1180 set_tgtflags_based_on_hint (hint
, &lochint
);
1182 tgt
= shishi_tkts_find (tkts
, &lochint
);
1184 free (lochint
.server
);
1185 lochint
.server
= NULL
;
1191 rc
= shishi_as (tkts
->handle
, &as
);
1192 if (rc
== SHISHI_OK
)
1193 rc
= act_hint_on_kdcreq (tkts
->handle
, &lochint
, shishi_as_req (as
));
1194 if (rc
== SHISHI_OK
)
1195 rc
= do_preauth (tkts
, &lochint
, as
);
1196 if (rc
== SHISHI_OK
)
1197 rc
= shishi_as_req_build (as
);
1198 if (rc
== SHISHI_OK
)
1199 rc
= shishi_as_sendrecv_hint (as
, &lochint
);
1200 if (rc
== SHISHI_OK
)
1201 rc
= shishi_as_rep_process (as
, NULL
, lochint
.passwd
);
1202 if (rc
== SHISHI_GOT_KRBERROR
1203 && shishi_krberror_errorcode_fast (tkts
->handle
,
1204 shishi_as_krberror (as
))
1205 == SHISHI_KDC_ERR_PREAUTH_REQUIRED
)
1209 rc
= recover_preauth (tkts
, as
, &lochint
, &retry
);
1210 if (rc
!= SHISHI_OK
)
1215 shishi_as_done (as
);
1219 shishi_error_printf (tkts
->handle
, "Unsupported pre-auth required");
1222 if (rc
!= SHISHI_OK
)
1224 shishi_error_printf (tkts
->handle
,
1225 "AS exchange failed: %s\n%s\n",
1226 shishi_strerror (rc
), shishi_error (tkts
->handle
));
1230 /* XXX free lochint members */
1232 tgt
= shishi_as_tkt (as
);
1235 shishi_error_printf (tkts
->handle
, "No ticket in AS-REP");
1239 if (VERBOSENOISE (tkts
->handle
))
1241 printf ("Received ticket granting ticket:\n");
1242 shishi_tkt_pretty_print (tgt
, stdout
);
1245 rc
= shishi_tkts_add (tkts
, tgt
);
1246 if (rc
!= SHISHI_OK
)
1247 printf ("Could not add ticket: %s", shishi_strerror (rc
));
1253 * shishi_tkts_get_tgs:
1254 * @tkts: ticket set handle as allocated by shishi_tkts().
1255 * @hint: structure with characteristics of ticket to begot.
1256 * @tgt: ticket granting ticket to use.
1258 * Get a ticket via TGS exchange using specified ticket granting
1261 * This function is used by shishi_tkts_get(), which is probably what
1262 * you really want to use unless you have special needs.
1264 * Return value: Returns a ticket if successful, or NULL if this
1265 * function is unable to acquire on.
1268 shishi_tkts_get_tgs (Shishi_tkts
* tkts
,
1269 Shishi_tkts_hint
* hint
, Shishi_tkt
* tgt
)
1275 rc
= shishi_tgs (tkts
->handle
, &tgs
);
1276 shishi_tgs_tgtkt_set (tgs
, tgt
);
1277 if (rc
== SHISHI_OK
)
1278 rc
= act_hint_on_kdcreq (tkts
->handle
, hint
, shishi_tgs_req (tgs
));
1279 if (rc
== SHISHI_OK
)
1280 rc
= shishi_tgs_set_server (tgs
, hint
->server
);
1281 if (rc
== SHISHI_OK
)
1282 rc
= shishi_tgs_req_build (tgs
);
1283 if (rc
== SHISHI_OK
)
1284 rc
= shishi_tgs_sendrecv_hint (tgs
, hint
);
1285 if (rc
== SHISHI_OK
)
1286 rc
= shishi_tgs_rep_process (tgs
);
1287 if (rc
!= SHISHI_OK
)
1289 shishi_error_printf (tkts
->handle
,
1290 "TGS exchange failed: %s\n%s\n",
1291 shishi_strerror (rc
), shishi_error (tkts
->handle
));
1292 if (rc
== SHISHI_GOT_KRBERROR
)
1293 shishi_krberror_pretty_print (tkts
->handle
, stdout
,
1294 shishi_tgs_krberror (tgs
));
1298 tkt
= shishi_tgs_tkt (tgs
);
1301 shishi_error_printf (tkts
->handle
, "No ticket in TGS-REP?!: %s",
1302 shishi_error (tkts
->handle
));
1306 if (VERBOSENOISE (tkts
->handle
))
1308 printf ("Received ticket:\n");
1309 shishi_tkt_pretty_print (tkt
, stdout
);
1312 rc
= shishi_tkts_add (tkts
, tkt
);
1313 if (rc
!= SHISHI_OK
)
1314 printf ("Could not add ticket: %s", shishi_strerror (rc
));
1321 * @tkts: ticket set handle as allocated by shishi_tkts().
1322 * @hint: structure with characteristics of ticket to begot.
1324 * Get a ticket matching given characteristics. This function first
1325 * looks in the ticket set for the ticket, then tries to find a
1326 * suitable TGT, possibly via an AS exchange, using
1327 * shishi_tkts_get_tgt(), and then use that TGT in a TGS exchange to
1330 * Currently this function do not implement cross realm logic.
1332 * Return value: Returns a ticket if found, or NULL if this function
1333 * is unable to get the ticket.
1336 shishi_tkts_get (Shishi_tkts
* tkts
, Shishi_tkts_hint
* hint
)
1338 Shishi_tkt
*tkt
, *tgt
;
1340 /* If we already have a matching ticket, avoid getting a new one. */
1342 tkt
= shishi_tkts_find (tkts
, hint
);
1346 tgt
= shishi_tkts_get_tgt (tkts
, hint
);
1349 shishi_error_printf (tkts
->handle
, "Could not get TGT for ticket.");
1353 if (shishi_tkt_match_p (tgt
, hint
))
1356 tkt
= shishi_tkts_get_tgs (tkts
, hint
, tgt
);
1359 shishi_error_printf (tkts
->handle
, "Could not get ticket using TGT.");
1367 * shishi_tkts_get_for_clientserver:
1368 * @tkts: ticket set handle as allocated by shishi_tkts().
1369 * @client: client name to get ticket for.
1370 * @server: server name to get ticket for.
1372 * Short-hand function for getting a ticket for the given client and
1373 * server. See shishi_tkts_get().
1375 * Return value: Returns a ticket if found, or NULL.
1378 shishi_tkts_get_for_clientserver (Shishi_tkts
* tkts
,
1379 const char *client
, const char *server
)
1381 Shishi_tkts_hint hint
;
1384 memset (&hint
, 0, sizeof (hint
));
1385 hint
.client
= (char *) client
;
1386 hint
.server
= (char *) server
;
1388 tkt
= shishi_tkts_get (tkts
, &hint
);
1394 * shishi_tkts_get_for_server:
1395 * @tkts: ticket set handle as allocated by shishi_tkts().
1396 * @server: server name to get ticket for.
1398 * Short-hand function for getting a ticket for the given server and
1399 * the default principal client. See shishi_tkts_get().
1401 * Return value: Returns a ticket if found, or NULL.
1404 shishi_tkts_get_for_server (Shishi_tkts
* tkts
, const char *server
)
1406 return shishi_tkts_get_for_clientserver
1407 (tkts
, shishi_principal_default (tkts
->handle
), server
);
1411 shishi_tkts_get_for_localservicepasswd (Shishi_tkts
* tkts
,
1412 const char *service
,
1416 Shishi_tkts_hint hint
;
1418 memset (&hint
, 0, sizeof (hint
));
1419 hint
.client
= (char *) shishi_principal_default (tkts
->handle
);
1420 hint
.server
= shishi_server_for_local_service (tkts
->handle
, service
);
1421 hint
.passwd
= (char *) passwd
;
1423 tkt
= shishi_tkts_get (tkts
, &hint
);