Cleanup debug messages.
[shishi.git] / src / shishi.c
blob3621847dcf32edd3d40c487345ce1c6c6b6d6a9d
1 /* shishi.c command line interface to shishi
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
22 #if HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #ifdef STDC_HEADERS
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <ctype.h>
31 #endif
33 #if HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
37 #ifdef HAVE_NETDB_H
38 #include <netdb.h>
39 #endif
41 #if defined HAVE_DECL_H_ERRNO && !HAVE_DECL_H_ERRNO
42 /* extern int h_errno; */
43 #endif
45 #ifdef HAVE_PWD_H
46 #include <pwd.h>
47 #endif
49 #ifdef HAVE_SYS_TYPES_H
50 #include <sys/types.h>
51 #endif
53 #ifdef HAVE_SYS_SELECT_H
54 #include <sys/select.h>
55 #endif
57 #ifdef HAVE_SYS_SOCKET_H
58 #include <sys/socket.h>
59 #endif
61 #ifdef HAVE_SYS_IOCTL_H
62 #include <sys/ioctl.h>
63 #endif
65 #ifdef HAVE_ERRNO_H
66 #include <errno.h>
67 #endif
69 #if HAVE_INTTYPES_H
70 # include <inttypes.h>
71 #else
72 # if HAVE_STDINT_H
73 # include <stdint.h>
74 # endif
75 #endif
77 #if TIME_WITH_SYS_TIME
78 # include <sys/time.h>
79 # include <time.h>
80 #else
81 # if HAVE_SYS_TIME_H
82 # include <sys/time.h>
83 # else
84 # include <time.h>
85 # endif
86 #endif
88 #if HAVE_STRING_H
89 # if !STDC_HEADERS && HAVE_MEMORY_H
90 # include <memory.h>
91 # endif
92 # include <string.h>
93 #endif
94 #if HAVE_STRINGS_H
95 # include <strings.h>
96 #endif
98 #ifdef HAVE_SIGNAL_H
99 #include <signal.h>
100 #endif
102 #ifdef HAVE_NETINET_IN_H
103 #include <netinet/in.h>
104 #endif
105 #ifdef HAVE_NETINET_IN6_H
106 #include <netinet/in6.h>
107 #endif
109 #ifdef HAVE_LOCALE_H
110 #include <locale.h>
111 #endif
113 #include "getdate.h"
114 #include "xalloc.h"
115 #include "error.h"
117 #include <argp.h>
118 #include <gettext.h>
119 #include <shishi.h>
121 #define _(String) gettext (String)
122 #define gettext_noop(String) String
123 #define N_(String) gettext_noop (String)
125 /* Long parameters only */
126 enum
128 OPTION_REQUEST = 300,
129 OPTION_SENDRECV,
130 OPTION_RESPONSE,
131 OPTION_WRITE_AP_REQUEST_FILE,
132 OPTION_WRITE_AUTHENTICATOR_FILE,
133 OPTION_WRITE_REQUEST_FILE,
134 OPTION_WRITE_RESPONSE_FILE,
135 OPTION_READ_REQUEST_FILE,
136 OPTION_READ_RESPONSE_FILE,
137 OPTION_SERVER,
138 OPTION_CLIENT,
139 OPTION_CLIENT_NAME,
140 OPTION_REALM,
141 OPTION_SERVER_NAME,
142 OPTION_TICKET_GRANTER,
143 OPTION_FORCE_AS,
144 OPTION_FORCE_TGS,
145 OPTION_CRYPTO_ENCRYPT,
146 OPTION_CRYPTO_DECRYPT,
147 OPTION_CRYPTO_KEY_VERSION,
148 OPTION_CRYPTO_KEY_USAGE,
149 OPTION_CRYPTO_KEY_VALUE,
150 OPTION_CRYPTO_READ_KEY_FILE,
151 OPTION_CRYPTO_WRITE_KEY_FILE,
152 OPTION_CRYPTO_READ_DATA_FILE,
153 OPTION_CRYPTO_WRITE_DATA_FILE,
154 OPTION_CRYPTO_RANDOM,
155 OPTION_CRYPTO_PARAMETER,
156 OPTION_CRYPTO_PASSWORD,
157 OPTION_CRYPTO_SALT,
158 OPTION_CRYPTO_STR2KEY,
159 OPTION_CRYPTO_DEBUG,
160 OPTION_CRYPTO_GENERATE_KEY,
161 OPTION_CRYPTO,
162 OPTION_LIST,
163 OPTION_DESTROY,
164 OPTION_RENEW,
165 OPTION_RENEWABLE,
166 OPTION_PROXIABLE,
167 OPTION_PROXY,
168 OPTION_FORWARDABLE,
169 OPTION_FORWARDED,
170 OPTION_STARTTIME,
171 OPTION_ENDTIME,
172 OPTION_RENEW_TILL,
173 OPTION_CFG_SYSTEM,
174 OPTION_CFG_USER,
175 OPTION_WRITE_TICKET_FILE
178 #define TYPE_TEXT_NAME "text"
179 #define TYPE_DER_NAME "der"
180 #define TYPE_HEX_NAME "hex"
181 #define TYPE_BASE64_NAME "base64"
182 #define TYPE_BINARY_NAME "binary"
184 struct arguments
186 int silent, verbose;
187 char *etypes;
188 char *lib_options;
189 int command;
190 char *ticketfile;
191 char *ticketwritefile;
192 char *systemcfgfile;
193 char *usercfgfile;
194 const char *client;
195 const char *crealm;
196 const char *cname;
197 const char *sname;
198 const char *srealm;
199 const char *server;
200 char *tgtname;
201 int forceas_p;
202 int forcetgs_p;
203 char *servername;
204 int renewable;
205 int proxiable;
206 int proxy;
207 int forwardable;
208 int forwarded;
209 time_t starttime;
210 char *endtime_str;
211 time_t endtime;
212 char *renew_till_str;
213 time_t renew_till;
214 /* crypto */
215 int algorithm;
216 int encrypt_p;
217 int decrypt_p;
218 char *password;
219 char *salt;
220 char *parameter;
221 int random;
222 int kvno;
223 char *keyvalue;
224 int keyusage;
225 char *readkeyfile;
226 char *writekeyfile;
227 char *inputfile;
228 int inputtype;
229 char *outputfile;
230 int outputtype;
233 const char *program_name = PACKAGE;
234 const char *argp_program_version = PACKAGE_STRING;
235 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
237 static int
238 crypto (Shishi * handle, struct arguments arg)
240 Shishi_key *key;
241 int rc;
243 if (arg.cname == NULL)
244 arg.cname = shishi_principal_default (handle);
246 if (arg.crealm == NULL)
247 arg.crealm = shishi_realm_default (handle);
249 if (arg.salt == NULL)
251 char *cname, *tok, *tokptr;
253 cname = xstrdup (arg.cname);
254 arg.salt = xstrdup (arg.crealm);
255 tok = strtok_r (cname, "/", &tokptr);
256 while (tok)
258 arg.salt =
259 xrealloc (arg.salt, strlen (arg.salt) + strlen (tok) + 1);
260 strcat (arg.salt, tok);
261 tok = strtok_r (NULL, "/", &tokptr);
263 free (cname);
266 rc = shishi_key (handle, &key);
267 if (rc != SHISHI_OK)
269 shishi_error_printf (handle, _("Cannot create key: %s"),
270 shishi_strerror (rc));
271 return rc;
274 shishi_key_type_set (key, arg.algorithm);
275 shishi_key_version_set (key, arg.kvno);
276 shishi_key_principal_set (key, arg.cname);
277 shishi_key_realm_set (key, arg.crealm);
279 if (arg.password)
281 rc = shishi_string_to_key (handle, arg.algorithm,
282 arg.password,
283 strlen (arg.password),
284 arg.salt,
285 strlen (arg.salt), arg.parameter, key);
286 if (rc != SHISHI_OK)
288 shishi_error_printf (handle, _("Error in string2key"));
289 return rc;
293 else if (arg.keyvalue)
295 rc = shishi_key_from_base64 (handle, arg.algorithm, arg.keyvalue, &key);
296 if (rc != SHISHI_OK)
298 fprintf (stderr, _("Could not create key: %s\n"),
299 shishi_strerror (rc));
300 return rc;
303 else if (arg.random)
305 char buf[BUFSIZ];
307 rc = shishi_randomize (handle, buf,
308 shishi_cipher_randomlen (arg.algorithm));
309 if (rc != SHISHI_OK)
310 return rc;
312 shishi_random_to_key (handle, arg.algorithm,
313 buf, shishi_cipher_randomlen (arg.algorithm),
314 key);
316 else if (arg.readkeyfile)
318 key = shishi_keys_for_server_in_file (handle, arg.readkeyfile,
319 arg.cname);
320 #if 0
321 shishi_key_from_file (handle, arg.writekeyfile, arg.algorithm, key,
322 keylen, arg.kvno, arg.cname, arg.realm);
323 #endif
325 if (key == NULL)
327 fprintf (stderr, _("Could not find key: %s\n"),
328 shishi_error (handle));
329 return 1;
332 else
334 fprintf (stderr, "Nothing to do.\n");
335 return SHISHI_OK;
338 if (arg.verbose ||
339 ((arg.password || arg.random || arg.keyvalue) &&
340 !(arg.encrypt_p || arg.decrypt_p)))
342 shishi_key_print (handle, stdout, key);
345 #if 0
346 currently broken if (arg.encrypt_p || arg.decrypt_p)
348 if (arg.inputfile)
350 infh = fopen (arg.inputfile, "r");
351 if (infh == NULL)
353 shishi_error_printf (handle, _("`%s': %s\n"),
354 arg.inputfile, strerror (errno));
355 return SHISHI_FOPEN_ERROR;
358 else
359 infh = stdin;
361 if (arg.outputfile)
363 outfh = fopen (arg.outputfile, "w");
364 if (outfh == NULL)
366 shishi_error_printf (handle, _("`%s': %s\n"),
367 arg.inputfile, strerror (errno));
368 return SHISHI_FOPEN_ERROR;
371 else
372 outfh = stdout;
374 outlen = fread (out, sizeof (out[0]),
375 sizeof (out) / sizeof (out[0]), infh);
376 if (outlen == 0)
378 fprintf (stderr, _("Error reading `%s'\n"), arg.inputfile);
379 return !SHISHI_OK;
381 if (arg.verbose)
382 printf (_("Read %d bytes...\n"), outlen);
384 if (arg.encrypt_p)
385 rc = shishi_encrypt (handle, key, arg.keyusage,
386 out, outlen, &in, &inlen);
387 else
388 rc = shishi_decrypt (handle, key, arg.keyusage,
389 in, inlen, &out, &outlen);
390 if (rc != SHISHI_OK)
392 shishi_error_printf (handle, _("Error ciphering\n"));
393 return rc;
396 if (arg.outputtype == SHISHI_FILETYPE_HEX)
398 for (i = 0; i < inlen; i++)
400 if ((i % 16) == 0)
401 fprintf (outfh, "\n");
402 fprintf (outfh, "%02x ", in[i]);
404 fprintf (outfh, "\n");
406 else if (arg.outputtype == SHISHI_FILETYPE_BINARY)
408 i = fwrite (in, sizeof (in[0]), inlen, outfh);
409 if (i != inlen)
411 fprintf (stderr, _("Short write (%d < %d)...\n"), i, inlen);
412 return 1;
414 printf (_("Wrote %d bytes...\n"), inlen);
417 if (arg.outputfile)
419 rc = fclose (outfh);
420 if (rc != 0)
422 shishi_error_printf (handle, _("`%s': %s\n"),
423 arg.outputfile, strerror (errno));
424 return SHISHI_FCLOSE_ERROR;
428 if (arg.inputfile)
430 rc = fclose (infh);
431 if (rc != 0)
433 shishi_error_printf (handle, _("`%s': %s\n"),
434 arg.inputfile, strerror (errno));
435 return SHISHI_FCLOSE_ERROR;
439 #endif
441 if (arg.writekeyfile)
443 shishi_key_to_file (handle, arg.writekeyfile, key);
446 return 0;
449 static void
450 parse_filename (char *arg, int *type, char **var)
452 if (strncasecmp (arg, TYPE_TEXT_NAME ",", strlen (TYPE_TEXT_NAME ",")) == 0)
454 (*type) = SHISHI_FILETYPE_TEXT;
455 arg += strlen (TYPE_TEXT_NAME ",");
457 else if (strncasecmp (arg, TYPE_DER_NAME ",", strlen (TYPE_DER_NAME ",")) ==
460 (*type) = SHISHI_FILETYPE_DER;
461 arg += strlen (TYPE_DER_NAME ",");
463 else if (strncasecmp (arg, TYPE_HEX_NAME ",", strlen (TYPE_HEX_NAME ",")) ==
466 (*type) = SHISHI_FILETYPE_HEX;
467 arg += strlen (TYPE_HEX_NAME ",");
469 else if (strncasecmp (arg, TYPE_BASE64_NAME ",",
470 strlen (TYPE_BASE64_NAME ",")) == 0)
472 (*type) = SHISHI_FILETYPE_BASE64;
473 arg += strlen (TYPE_BASE64_NAME ",");
475 else if (strncasecmp (arg, TYPE_BINARY_NAME ",",
476 strlen (TYPE_BINARY_NAME ",")) == 0)
478 (*type) = SHISHI_FILETYPE_BINARY;
479 arg += strlen (TYPE_BINARY_NAME ",");
481 else
482 (*type) = 0;
483 *var = strdup (arg);
486 static error_t
487 parse_opt (int key, char *arg, struct argp_state *state)
489 struct arguments *arguments = state->input;
491 switch (key)
493 case 'q':
494 arguments->silent = 1;
495 break;
497 case 'v':
498 arguments->verbose++;
499 break;
501 case 'o':
502 arguments->lib_options = arg;
503 break;
505 case OPTION_WRITE_TICKET_FILE:
506 arguments->ticketwritefile = strdup (arg);
507 break;
509 case 'E':
510 arguments->etypes = strdup (arg);
511 break;
513 case OPTION_CFG_SYSTEM:
514 arguments->systemcfgfile = strdup (arg);
515 break;
517 case OPTION_CFG_USER:
518 arguments->usercfgfile = strdup (arg);
519 break;
521 case 'c':
522 arguments->ticketfile = strdup (arg);
523 break;
525 case OPTION_CRYPTO_ENCRYPT:
526 arguments->command = OPTION_CRYPTO;
527 if (arguments->decrypt_p)
528 argp_error (state, _("Cannot both encrypt and decrypt."));
529 arguments->encrypt_p = 1;
530 break;
532 case OPTION_CRYPTO_DECRYPT:
533 arguments->command = OPTION_CRYPTO;
534 if (arguments->encrypt_p)
535 argp_error (state, _("Cannot both encrypt and decrypt."));
536 arguments->decrypt_p = 1;
537 break;
539 case OPTION_CRYPTO_KEY_VALUE:
540 arguments->keyvalue = strdup (arg);
541 break;
543 case OPTION_CRYPTO_KEY_USAGE:
544 if (arguments->command != OPTION_CRYPTO)
545 argp_error (state, _("Option `%s' only valid with CRYPTO."),
546 state->argv[state->next - 1]);
547 arguments->keyusage = atoi (arg);
548 break;
550 case OPTION_CRYPTO_KEY_VERSION:
551 if (arguments->command != OPTION_CRYPTO)
552 argp_error (state, _("Option `%s' only valid with CRYPTO."),
553 state->argv[state->next - 1]);
554 arguments->kvno = atoi (arg);
555 break;
557 case OPTION_CRYPTO_PARAMETER:
558 if (arguments->command != OPTION_CRYPTO)
559 argp_error (state, _("Option `%s' only valid with CRYPTO."),
560 state->argv[state->next - 1]);
561 arguments->parameter = strdup (arg);
562 break;
564 case OPTION_CRYPTO_PASSWORD:
565 arguments->password = strdup (arg);
566 break;
568 case OPTION_CRYPTO_RANDOM:
569 if (arguments->command != OPTION_CRYPTO)
570 argp_error (state, _("Option `%s' only valid with CRYPTO."),
571 state->argv[state->next - 1]);
572 arguments->random = 1;
573 break;
575 case OPTION_CRYPTO_READ_DATA_FILE:
576 if (arguments->command != OPTION_CRYPTO)
577 argp_error (state, _("Option `%s' only valid with CRYPTO."),
578 state->argv[state->next - 1]);
579 parse_filename (arg, &arguments->inputtype, &arguments->inputfile);
580 if (arguments->inputtype == SHISHI_FILETYPE_TEXT ||
581 arguments->inputtype == SHISHI_FILETYPE_DER)
582 arguments->inputtype = SHISHI_FILETYPE_BINARY;
583 break;
585 case OPTION_CRYPTO_READ_KEY_FILE:
586 if (arguments->command != OPTION_CRYPTO)
587 argp_error (state, _("Option `%s' only valid with CRYPTO."),
588 state->argv[state->next - 1]);
589 arguments->readkeyfile = strdup (arg);
590 break;
592 case OPTION_CRYPTO_SALT:
593 if (arguments->command != OPTION_CRYPTO)
594 argp_error (state, _("Option `%s' only valid with CRYPTO."),
595 state->argv[state->next - 1]);
596 arguments->salt = strdup (arg);
597 break;
599 case OPTION_CRYPTO_STR2KEY:
600 arguments->command = OPTION_CRYPTO;
601 if (arg)
603 if (arguments->password)
604 argp_error (state, _("Password specified twice."));
605 arguments->password = strdup (arg);
607 break;
609 case OPTION_CRYPTO_WRITE_DATA_FILE:
610 if (arguments->command != OPTION_CRYPTO)
611 argp_error (state, _("Option `%s' only valid with CRYPTO."),
612 state->argv[state->next - 1]);
613 parse_filename (arg, &arguments->outputtype, &arguments->outputfile);
614 if (arguments->outputtype == SHISHI_FILETYPE_TEXT ||
615 arguments->outputtype == SHISHI_FILETYPE_DER)
616 arguments->outputtype = SHISHI_FILETYPE_BINARY;
617 break;
619 case OPTION_CRYPTO_WRITE_KEY_FILE:
620 if (arguments->command != OPTION_CRYPTO)
621 argp_error (state, _("Option `%s' only valid with CRYPTO."),
622 state->argv[state->next - 1]);
623 arguments->writekeyfile = strdup (arg);
624 break;
626 case OPTION_CLIENT_NAME:
627 arguments->cname = strdup (arg);
628 break;
630 case 'e':
631 case OPTION_ENDTIME:
632 arguments->endtime_str = strdup (arg);
633 break;
635 case OPTION_FORWARDABLE:
636 arguments->forwardable = 1;
637 break;
639 case OPTION_FORWARDED:
640 arguments->forwarded = 1;
641 break;
643 case OPTION_PROXIABLE:
644 arguments->proxiable = 1;
645 break;
647 case OPTION_PROXY:
648 arguments->proxy = 1;
649 break;
651 case OPTION_REALM:
652 arguments->crealm = strdup (arg);
653 break;
655 case 'R':
656 case OPTION_RENEW:
657 arguments->command = OPTION_RENEW;
658 break;
660 case OPTION_RENEW_TILL:
661 arguments->renew_till_str = strdup (arg);
662 /* fall through */
664 case OPTION_RENEWABLE:
665 arguments->renewable = 1;
666 break;
668 case 's':
669 case OPTION_STARTTIME:
670 arguments->starttime = get_date (arg, NULL);
671 if (arguments->starttime == -1)
672 argp_error (state, _("invalid --starttime date `%s'"), arg);
673 break;
675 case OPTION_SERVER_NAME:
676 arguments->sname = strdup (arg);
677 break;
679 case OPTION_FORCE_AS:
680 arguments->forceas_p = 1;
681 break;
683 case OPTION_FORCE_TGS:
684 arguments->forcetgs_p = 1;
685 break;
687 case OPTION_TICKET_GRANTER:
688 arguments->tgtname = strdup (arg);
689 break;
691 case 'l':
692 case OPTION_LIST:
693 arguments->command = OPTION_LIST;
694 break;
696 case 'd':
697 case OPTION_DESTROY:
698 arguments->command = OPTION_DESTROY;
699 break;
701 case ARGP_KEY_ARG:
702 if (arguments->server && arguments->client)
703 argp_error (state, _("Too many arguments: `%s'"), arg);
704 if (arguments->client)
705 arguments->server = strdup (arg);
706 else
707 arguments->client = strdup (arg);
708 break;
710 default:
711 return ARGP_ERR_UNKNOWN;
714 return 0;
717 static struct argp_option options[] = {
719 {0, 0, 0, 0, "If no command is given, Shishi try to make sure you have a "
720 "ticket granting ticket for the default realm, and then display it.", 0},
722 {"client-name", OPTION_CLIENT_NAME, "NAME", 0,
723 "Client name. Default is login username.", 10},
725 {"destroy", 'd', 0, 0,
726 "Destroy tickets in local cache, subject to --client-name and "
727 "--server-name limiting.", 0},
729 {"encryption-type", 'E', "ETYPE,[ETYPE...]", 0,
730 "Encryption types to use. ETYPE is either registered name or integer.",
733 {"force-as", OPTION_FORCE_AS, 0, 0,
734 "Force AS mode. Default is to use TGS iff a TGT is found.", 0},
736 {"force-tgs", OPTION_FORCE_TGS, 0, 0,
737 "Force TGS mode. Default is to use TGS iff a TGT is found.", 0},
739 {"endtime", 'e', "STRING", 0,
740 "Specify when ticket validity should expire. The time syntax may be "
741 "relative (to the start time), such as \"20 hours\", or absolute, "
742 "such as \"2001-02-03 04:05:06 CET\". The default is 8 hours after "
743 "the start time.", 0},
745 {"forwardable", OPTION_FORWARDABLE, 0, 0,
746 "Get a forwardable ticket, i.e., one that can be used to get forwarded "
747 "tickets.", 0},
749 {"forwarded", OPTION_FORWARDED, 0, 0,
750 "Get a forwarded ticket.", 0},
752 {"list", 'l', 0, 0,
753 "List tickets in local cache, subject to --server-name limiting.", 0},
755 {"proxiable", OPTION_PROXIABLE, 0, 0,
756 "Get a proxiable ticket, i.e., one that can be used to get proxy "
757 "tickets.", 0},
759 {"proxy", OPTION_PROXY, 0, 0,
760 "Get a proxy ticket.", 0},
762 {"renew", 'R', 0, 0,
763 "Renew ticket. Use --server-name to specify ticket, default is the "
764 "most recent renewable ticket granting ticket for the default realm.", 0},
766 {"renewable", OPTION_RENEWABLE, 0, 0,
767 "Get a renewable ticket.", 0},
769 {"renew-till", OPTION_RENEW_TILL, "STRING", 0,
770 "Specify renewable life of ticket. Implies --renewable. Accepts same "
771 "time syntax as --endtime. If --renewable is specified, the default is 1 "
772 "week after the start time.", 0},
774 {"realm", OPTION_REALM, "REALM", 0,
775 "Realm of server. Default is DNS domain of local host. For AS, this also "
776 "indicates realm of client.", 0},
778 {"server", OPTION_SERVER, "[FAMILY:]ADDRESS:SERVICE/TYPE", 0,
779 "Send all requests to HOST instead of using normal logic to locate "
780 "KDC addresses (discouraged).", 0},
782 {"server-name", OPTION_SERVER_NAME, "NAME", 0,
783 "Server name. Default is \"krbtgt/REALM\" where REALM is server "
784 "realm (see --realm).", 0},
786 {"starttime", 's', "STRING", 0,
787 "Specify when ticket should start to be valid. Accepts same time syntax "
788 "as --endtime. The default is to become valid immediately.", 0},
790 {"ticket-granter", OPTION_TICKET_GRANTER, "NAME", 0,
791 "Service name in ticket to use for authenticating request. Only for TGS. "
792 "Defaults to \"krbtgt/REALM@REALM\" where REALM is server "
793 "realm (see --realm).", 0},
794 #if 0
795 {"key-value", OPTION_CRYPTO_KEY_VALUE, "KEY", 0,
796 "Cipher key to decrypt response (discouraged).", 0},
797 #endif
799 /************** CRYPTO */
801 {0, 0, 0, 0,
802 "Options for low-level cryptography (CRYPTO-OPTIONS):", 100},
804 {"client-name", OPTION_CLIENT_NAME, "NAME", 0,
805 "Username. Default is login name.", 0},
806 #if 0
807 {"decrypt", OPTION_CRYPTO_DECRYPT, 0, 0,
808 "Decrypt data.", 0},
810 {"encrypt", OPTION_CRYPTO_ENCRYPT, 0, 0,
811 "Encrypt data.", 0},
813 {"key-usage", OPTION_CRYPTO_KEY_USAGE, "KEYUSAGE", 0,
814 "Encrypt or decrypt using specified key usage. Default is 0, which "
815 "means no key derivation are performed.", 0},
817 {"key-value", OPTION_CRYPTO_KEY_VALUE, "KEY", 0,
818 "Base64 encoded key value.", 0},
819 #endif
820 {"key-version", OPTION_CRYPTO_KEY_VERSION, "INTEGER", 0,
821 "Version number of key. Default is 0.", 0},
823 {"random", OPTION_CRYPTO_RANDOM, 0, 0,
824 "Generate key from random data.", 0},
825 #if 0
826 {"read-key-file", OPTION_CRYPTO_READ_KEY_FILE, "FILE", 0,
827 "Read cipher key from FILE", 0},
829 {"read-data-file", OPTION_CRYPTO_READ_DATA_FILE, "[TYPE,]FILE", 0,
830 "Read data from FILE in TYPE, BASE64, HEX or BINARY (default).", 0},
831 #endif
832 {"realm", OPTION_REALM, "REALM", 0,
833 "Realm of principal. Defaults to DNS domain of local host. ", 0},
835 {"salt", OPTION_CRYPTO_SALT, "SALT", 0,
836 "Salt to use for --string-to-key. Defaults to concatenation of "
837 "realm and (unwrapped) client name.", 0},
839 {"string-to-key", OPTION_CRYPTO_STR2KEY, "[PASSWORD]", OPTION_ARG_OPTIONAL,
840 "Convert password into Kerberos key. Note that --client-name, --realm, "
841 "and --salt influence the generated key.", 0},
843 {"parameter", OPTION_CRYPTO_PARAMETER, "STRING", 0,
844 "String-to-key parameter. This data is specific for each encryption "
845 "algorithm and rarely needed.", 0},
846 #if 0
847 {"write-key-file", OPTION_CRYPTO_WRITE_KEY_FILE, "FILE", 0,
848 "Append cipher key to FILE", 0},
850 {"write-data-file", OPTION_CRYPTO_WRITE_DATA_FILE, "[TYPE,]FILE", 0,
851 "Write data to FILE in TYPE, BASE64, HEX or BINARY (default).", 0},
852 #endif
853 /************** OTHER */
855 {0, 0, 0, 0, "Other options:", 200},
857 {"verbose", 'v', 0, 0,
858 "Produce verbose output. Use multiple times to increase amount of "
859 "verbose output.", 0},
861 {"quiet", 'q', 0, 0,
862 "Don't produce any output.", 0},
864 {"silent", 0, 0, OPTION_ALIAS,
865 NULL, 0},
867 {"system-configuration-file", OPTION_CFG_SYSTEM, "FILE", 0,
868 "Read system wide configuration from file. Default is " SYSTEMCFGFILE
869 ".", 0},
871 {"configuration-file", OPTION_CFG_USER, "FILE", 0,
872 "Read user configuration from file. Default is ~/.shishi/config.", 0},
874 {"library-options", 'o', "STRING", 0,
875 "Parse STRING as a configuration file statement.", 0},
877 {"ticket-file", 'c', "FILE", 0,
878 "Read tickets from FILE. Default is $HOME/.shishi/tickets.", 0},
880 {"ticket-write-file", OPTION_WRITE_TICKET_FILE, "FILE", 0,
881 "Write tickets to FILE. Default is to write them back to ticket file.",
884 {"CLIENT", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
885 "Set client name and realm from NAME. The --client-name and --realm "
886 "parameters can be used to override part of NAME.", 0},
888 {"SERVER", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
889 "Set server name and realm from NAME. The --server-name and "
890 "--server-realm parameters can be used to override part of SERVER.", 0},
892 /************** EXAMPLES */
894 {0, 0, 0, 0, "Examples:", 300},
896 {"shishi", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
897 "Get a ticket granting ticket from the default KDC server for the "
898 "default user and realm.", 0},
900 {"shishi jas/admin@ACCOUNTING", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
901 "Get a ticket for jas/admin in the ACCOUNTING realm.", 0},
903 {"shishi --list --server-name=krbtgt/JOSEFSSON.ORG@JOSEFSSON.ORG",
904 0, 0, OPTION_DOC | OPTION_NO_USAGE,
905 "List tickets for the Ticket Granting Service in the JOSEFSSON.ORG realm.",
908 {NULL, 0, 0, 0, NULL, 0}
911 static struct argp argp = {
912 options,
913 parse_opt,
914 "[CLIENT [SERVER]] [OPTION...]\n"
915 "--list [CLIENT [SERVER]]\n"
916 "--destroy [CLIENT [SERVER]]\n" "--string-to-key [CLIENT] [OPTION...]\n",
917 "Shishi -- A Kerberos 5 implementation",
918 NULL,
919 NULL,
920 NULL
924 main (int argc, char *argv[])
926 struct arguments arg;
927 Shishi *handle;
928 int rc;
929 int32_t *etype;
931 setlocale (LC_ALL, "");
932 bindtextdomain (PACKAGE, LOCALEDIR);
933 textdomain (PACKAGE);
935 memset (&arg, 0, sizeof (arg));
936 arg.algorithm = -1;
937 argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &arg);
939 rc = shishi_init_with_paths (&handle, arg.ticketfile,
940 arg.systemcfgfile, arg.usercfgfile);
941 if (rc == SHISHI_HANDLE_ERROR)
942 error (1, 0, "Internal error: could not initialize shishi\n");
944 rc = shishi_cfg_clientkdcetype_set (handle, arg.etypes);
945 if (rc != SHISHI_OK)
946 error (1, 0, "Could not set encryption types: %s\n",
947 shishi_strerror (rc));
949 if (arg.algorithm == -1 && shishi_cfg_clientkdcetype (handle, &etype) > 0)
950 arg.algorithm = *etype;
952 if (arg.client)
954 rc = shishi_parse_name (handle, arg.client,
955 (char **) (arg.cname ? NULL : &arg.cname),
956 (char **) (arg.crealm ? NULL : &arg.crealm));
958 if (rc != SHISHI_OK)
959 error (1, 0, "Could not parse principal \"%s\": %s\n", arg.client,
960 shishi_strerror (rc));
963 if (arg.server)
965 rc = shishi_parse_name (handle, arg.server,
966 (char **) (arg.sname ? NULL : &arg.sname),
967 (char **) (arg.srealm ? NULL : &arg.srealm));
969 if (rc != SHISHI_OK)
970 error (1, 0, "Could not parse principal \"%s\": %s\n", arg.server,
971 shishi_strerror (rc));
974 rc = shishi_cfg (handle, arg.lib_options);
975 if (rc != SHISHI_OK)
976 error (1, 0, "Could not read library options: %s\n",
977 shishi_strerror (rc));
979 if (arg.verbose > 1)
981 rc = shishi_cfg (handle, "verbose");
982 if (rc != SHISHI_OK)
983 error (1, 0, "Could not make library verbose: %s\n",
984 shishi_strerror (rc));
987 if (arg.verbose > 2)
989 rc = shishi_cfg (handle, "verbose-noice");
990 if (rc != SHISHI_OK)
991 error (1, 0, "Could not make library verbose: %s\n",
992 shishi_strerror (rc));
995 if (arg.verbose > 3)
997 rc = shishi_cfg (handle, "verbose-asn1");
998 if (rc != SHISHI_OK)
999 error (1, 0, "Could not make library verbose: %s\n",
1000 shishi_strerror (rc));
1003 if (arg.verbose > 4)
1005 rc = shishi_cfg (handle, "verbose-crypto");
1006 if (rc != SHISHI_OK)
1007 error (1, 0, "Could not make library verbose: %s\n",
1008 shishi_strerror (rc));
1011 if (!arg.starttime)
1012 arg.starttime = time (NULL);
1014 if (arg.endtime_str)
1016 arg.endtime = get_date (arg.endtime_str, &arg.starttime);
1017 if (arg.endtime == -1)
1018 error (1, 0, _("invalid --endtime date `%s'"), arg.endtime_str);
1021 if (arg.renew_till_str)
1023 arg.renew_till = get_date (arg.renew_till_str, &arg.starttime);
1024 if (arg.renew_till == -1)
1025 error (1, 0, _("invalid --renew-till date `%s'"), arg.renew_till_str);
1028 if (arg.cname)
1029 shishi_principal_default_set (handle, arg.cname);
1031 if (arg.crealm)
1032 shishi_realm_default_set (handle, arg.crealm);
1034 if (!arg.tgtname)
1036 asprintf (&arg.tgtname, "krbtgt/%s", shishi_realm_default (handle));
1037 if (arg.tgtname == NULL)
1038 error (1, 0, "Could not allocate TGT name.");
1041 rc = 1;
1043 switch (arg.command)
1045 case OPTION_LIST:
1046 if (!arg.silent)
1047 printf (_("Tickets in `%s':\n"), shishi_tkts_default_file (handle));
1049 rc = shishi_tkts_print_for_service (shishi_tkts_default (handle),
1050 stdout, arg.sname);
1051 if (rc != SHISHI_OK)
1052 fprintf (stderr, "Could not list tickets: %s", shishi_strerror (rc));
1053 break;
1055 case OPTION_DESTROY:
1057 int i, removed = 0;
1058 for (i = 0; i < shishi_tkts_size (shishi_tkts_default (handle)); i++)
1060 if (arg.sname &&
1061 !shishi_tkt_server_p (shishi_tkts_nth
1062 (shishi_tkts_default (handle),
1063 i), arg.sname))
1064 continue;
1066 if (arg.verbose)
1068 printf ("Removing ticket:\n");
1069 shishi_tkt_pretty_print (shishi_tkts_nth
1070 (shishi_tkts_default
1071 (handle), i), stdout);
1074 rc = shishi_tkts_remove (shishi_tkts_default (handle), i);
1075 if (rc != SHISHI_OK)
1076 fprintf (stderr, "Could not destroy ticket %d:\n%s\n", i,
1077 shishi_strerror (rc));
1078 i--;
1079 removed++;
1081 if (!arg.silent)
1083 if (removed == 0)
1084 printf ("No tickets removed.\n");
1085 else if (removed == 1)
1086 printf ("1 ticket removed.\n");
1087 else
1088 printf ("%d tickets removed.\n", removed);
1090 rc = SHISHI_OK;
1092 break;
1094 case OPTION_CRYPTO:
1095 rc = crypto (handle, arg);
1096 if (rc != SHISHI_OK)
1097 fprintf (stderr, "Operation failed:\n%s\n%s\n",
1098 shishi_strerror (rc), shishi_error (handle));
1099 break;
1101 case OPTION_RENEW:
1103 Shishi_tkt *tkt;
1104 Shishi_tkts_hint hint;
1105 Shishi_tgs *tgs;
1107 /* This doesn't work */
1109 memset (&hint, 0, sizeof (hint));
1110 hint.client = (char *) arg.cname;
1111 hint.server = (char *) (arg.sname ? arg.sname : arg.tgtname);
1112 hint.starttime = arg.starttime;
1113 hint.endtime = arg.endtime;
1114 hint.renew_till = arg.renew_till;
1116 tkt = shishi_tkts_find (shishi_tkts_default (handle), &hint);
1117 if (!tkt)
1119 fprintf (stderr, "Could not get ticket for `%s'.\n", hint.server);
1120 rc = !SHISHI_OK;
1122 else
1123 shishi_tkt_pretty_print (tkt, stdout);
1125 /* Get ticket using TGT ... */
1126 rc = shishi_tgs (handle, &tgs);
1127 shishi_tgs_tgtkt_set (tgs, tkt);
1128 if (rc == SHISHI_OK)
1129 rc = shishi_tgs_set_server (tgs, hint.server);
1130 rc = shishi_kdcreq_options_add (handle, shishi_tgs_req (tgs),
1131 SHISHI_KDCOPTIONS_RENEWABLE |
1132 SHISHI_KDCOPTIONS_RENEW);
1133 if (rc == SHISHI_OK)
1134 rc = shishi_asn1_write (handle, shishi_tgs_req (tgs),
1135 "req-body.rtime",
1136 shishi_generalize_time
1137 (handle, hint.renew_till), 0);
1138 if (rc == SHISHI_OK)
1139 rc = shishi_tgs_req_build (tgs);
1140 if (rc == SHISHI_OK)
1141 rc = shishi_tgs_sendrecv (tgs);
1142 if (rc == SHISHI_OK)
1143 rc = shishi_tgs_rep_process (tgs);
1144 if (rc != SHISHI_OK)
1146 fprintf (stderr, "TGS exchange failed: %s\n%s\n",
1147 shishi_strerror (rc),
1148 shishi_error (handle));
1149 if (rc == SHISHI_GOT_KRBERROR)
1150 shishi_krberror_pretty_print (handle, stdout,
1151 shishi_tgs_krberror (tgs));
1152 break;
1155 tkt = shishi_tgs_tkt (tgs);
1156 if (!tkt)
1158 fprintf (stderr, "No ticket in TGS-REP?!: %s\n",
1159 shishi_error (handle));
1160 break;
1163 shishi_tkt_pretty_print (tkt, stdout);
1165 rc = shishi_tkts_add (shishi_tkts_default (handle), tkt);
1166 if (rc != SHISHI_OK)
1167 fprintf (stderr, "Could not add ticket: %s", shishi_strerror (rc));
1169 break;
1171 default:
1173 Shishi_tkt *tkt;
1174 Shishi_tkts_hint hint;
1176 memset (&hint, 0, sizeof (hint));
1177 hint.client = (char *) arg.cname;
1178 hint.server = (char *) (arg.sname ? arg.sname : arg.tgtname);
1179 hint.starttime = arg.starttime;
1180 hint.endtime = arg.endtime;
1181 hint.renew_till = arg.renew_till;
1182 if (arg.renewable)
1183 hint.tktflags |= SHISHI_TICKETFLAGS_RENEWABLE;
1184 if (arg.proxiable)
1185 hint.tktflags |= SHISHI_TICKETFLAGS_PROXIABLE;
1186 if (arg.proxy)
1187 hint.tktflags |= SHISHI_TICKETFLAGS_PROXY;
1188 if (arg.forwardable)
1189 hint.tktflags |= SHISHI_TICKETFLAGS_FORWARDABLE;
1190 if (arg.forwarded)
1191 hint.tktflags |= SHISHI_TICKETFLAGS_FORWARDED;
1193 tkt = shishi_tkts_get (shishi_tkts_default (handle), &hint);
1194 if (!tkt)
1196 fprintf (stderr, "Could not get ticket for `%s'.\n", hint.server);
1197 rc = !SHISHI_OK;
1199 else
1200 shishi_tkt_pretty_print (tkt, stdout);
1202 break;
1205 shishi_tkts_expire (shishi_tkts_default (handle));
1207 if (arg.ticketwritefile)
1208 shishi_tkts_default_file_set (handle, arg.ticketwritefile);
1210 shishi_done (handle);
1212 return rc == SHISHI_OK ? 0 : 1;