Commit unfinished --renew code for later.
[shishi.git] / src / shishi.c
blob05416bb75722465b22f6dca8fc49c20044647588
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 "error.h"
116 #include <argp.h>
117 #include <gettext.h>
118 #include <shishi.h>
120 #define _(String) gettext (String)
121 #define gettext_noop(String) String
122 #define N_(String) gettext_noop (String)
124 /* Long parameters only */
125 enum
127 OPTION_REQUEST = 300,
128 OPTION_SENDRECV,
129 OPTION_RESPONSE,
130 OPTION_WRITE_AP_REQUEST_FILE,
131 OPTION_WRITE_AUTHENTICATOR_FILE,
132 OPTION_WRITE_REQUEST_FILE,
133 OPTION_WRITE_RESPONSE_FILE,
134 OPTION_READ_REQUEST_FILE,
135 OPTION_READ_RESPONSE_FILE,
136 OPTION_SERVER,
137 OPTION_CLIENT,
138 OPTION_CLIENT_NAME,
139 OPTION_REALM,
140 OPTION_SERVER_NAME,
141 OPTION_TICKET_GRANTER,
142 OPTION_FORCE_AS,
143 OPTION_FORCE_TGS,
144 OPTION_CRYPTO_ENCRYPT,
145 OPTION_CRYPTO_DECRYPT,
146 OPTION_CRYPTO_ALGORITHM,
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_DEBUG,
159 OPTION_CRYPTO_GENERATE_KEY,
160 OPTION_VERBOSE_LIBRARY,
161 OPTION_LIST,
162 OPTION_DESTROY,
163 OPTION_CRYPTO,
164 OPTION_RENEW,
165 OPTION_RENEWABLE,
166 OPTION_STARTTIME,
167 OPTION_ENDTIME,
168 OPTION_RENEW_TILL,
169 OPTION_CFG_SYSTEM,
170 OPTION_CFG_USER,
171 OPTION_WRITE_TICKET_FILE
174 #define TYPE_TEXT_NAME "text"
175 #define TYPE_DER_NAME "der"
176 #define TYPE_HEX_NAME "hex"
177 #define TYPE_BASE64_NAME "base64"
178 #define TYPE_BINARY_NAME "binary"
180 struct arguments
182 int silent, verbose, verbose_library;
183 char *etypes;
184 char *lib_options;
185 int command;
186 char *ticketfile;
187 char *ticketwritefile;
188 const char *realm;
189 char *systemcfgfile;
190 char *usercfgfile;
191 const char *client;
192 const char *cname;
193 const char *sname;
194 char *tgtname;
195 int forceas_p;
196 int forcetgs_p;
197 char *servername;
198 int renewable;
199 time_t starttime;
200 char *endtime_str;
201 time_t endtime;
202 char *renew_till_str;
203 time_t renew_till;
204 /* crypto */
205 int algorithm;
206 int encrypt_p;
207 int decrypt_p;
208 char *password;
209 char *salt;
210 char *parameter;
211 int random;
212 int kvno;
213 char *keyvalue;
214 int keyusage;
215 char *readkeyfile;
216 char *writekeyfile;
217 char *inputfile;
218 int inputtype;
219 char *outputfile;
220 int outputtype;
223 const char *program_name = PACKAGE;
224 const char *argp_program_version = PACKAGE_STRING;
225 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
227 static int
228 crypto (Shishi * handle, struct arguments arg)
230 Shishi_key *key;
231 int rc;
233 if (arg.cname == NULL)
234 arg.cname = shishi_principal_default (handle);
236 if (arg.realm == NULL)
237 arg.realm = shishi_realm_default (handle);
239 if (arg.salt == NULL)
241 arg.salt = malloc (strlen (arg.realm) + strlen (arg.cname) + 1);
242 if (!arg.salt)
243 return SHISHI_MALLOC_ERROR;
244 strcpy (arg.salt, arg.realm);
245 strcat (arg.salt, arg.cname);
248 rc = shishi_key (handle, &key);
249 if (rc != SHISHI_OK)
251 shishi_error_printf (handle, _("Cannot create key: %s"),
252 shishi_strerror (rc));
253 return rc;
256 shishi_key_type_set (key, arg.algorithm);
257 shishi_key_version_set (key, arg.kvno);
258 shishi_key_principal_set (key, arg.cname);
259 shishi_key_realm_set (key, arg.realm);
261 if (arg.password)
263 rc = shishi_string_to_key (handle, arg.algorithm,
264 arg.password,
265 strlen (arg.password),
266 arg.salt,
267 strlen (arg.salt), arg.parameter, key);
268 if (rc != SHISHI_OK)
270 shishi_error_printf (handle, _("Error in string2key"));
271 return rc;
275 else if (arg.keyvalue)
277 rc = shishi_key_from_base64 (handle, arg.algorithm, arg.keyvalue, &key);
278 if (rc != SHISHI_OK)
280 fprintf (stderr, _("Could not create key: %s\n"),
281 shishi_strerror (rc));
282 return rc;
285 else if (arg.random)
287 char buf[BUFSIZ];
289 rc = shishi_randomize (handle, buf,
290 shishi_cipher_randomlen (arg.algorithm));
291 if (rc != SHISHI_OK)
292 return rc;
294 shishi_random_to_key (handle, arg.algorithm,
295 buf, shishi_cipher_randomlen (arg.algorithm),
296 key);
298 else if (arg.readkeyfile)
300 key = shishi_keys_for_server_in_file (handle, arg.readkeyfile,
301 arg.cname);
302 #if 0
303 shishi_key_from_file (handle, arg.writekeyfile, arg.algorithm, key,
304 keylen, arg.kvno, arg.cname, arg.realm);
305 #endif
307 if (key == NULL)
309 fprintf (stderr, _("Could not find key: %s\n"),
310 shishi_strerror_details (handle));
311 return 1;
314 else
316 fprintf (stderr, "Nothing to do.\n");
317 return SHISHI_OK;
320 if (shishi_key_type (key) == SHISHI_NULL && !arg.silent)
321 fprintf (stderr,
322 "warning: using %s is silly, consider using --algorithm.\n",
323 shishi_cipher_name (arg.algorithm));
325 if (arg.verbose ||
326 ((arg.password || arg.random || arg.keyvalue) &&
327 !(arg.encrypt_p || arg.decrypt_p)))
329 shishi_key_print (handle, stdout, key);
332 #if 0
333 currently broken
334 if (arg.encrypt_p || arg.decrypt_p)
336 if (arg.inputfile)
338 infh = fopen (arg.inputfile, "r");
339 if (infh == NULL)
341 shishi_error_printf (handle, _("`%s': %s\n"),
342 arg.inputfile, strerror (errno));
343 return SHISHI_FOPEN_ERROR;
346 else
347 infh = stdin;
349 if (arg.outputfile)
351 outfh = fopen (arg.outputfile, "w");
352 if (outfh == NULL)
354 shishi_error_printf (handle, _("`%s': %s\n"),
355 arg.inputfile, strerror (errno));
356 return SHISHI_FOPEN_ERROR;
359 else
360 outfh = stdout;
362 outlen = fread (out, sizeof (out[0]),
363 sizeof (out) / sizeof (out[0]), infh);
364 if (outlen == 0)
366 fprintf (stderr, _("Error reading `%s'\n"), arg.inputfile);
367 return !SHISHI_OK;
369 if (arg.verbose)
370 printf (_("Read %d bytes...\n"), outlen);
372 if (arg.encrypt_p)
373 rc = shishi_encrypt (handle, key, arg.keyusage,
374 out, outlen, &in, &inlen);
375 else
376 rc = shishi_decrypt (handle, key, arg.keyusage,
377 in, inlen, &out, &outlen);
378 if (rc != SHISHI_OK)
380 shishi_error_printf (handle, _("Error ciphering\n"));
381 return rc;
384 if (arg.outputtype == SHISHI_FILETYPE_HEX)
386 for (i = 0; i < inlen; i++)
388 if ((i % 16) == 0)
389 fprintf (outfh, "\n");
390 fprintf (outfh, "%02x ", in[i]);
392 fprintf (outfh, "\n");
394 else if (arg.outputtype == SHISHI_FILETYPE_BINARY)
396 i = fwrite (in, sizeof (in[0]), inlen, outfh);
397 if (i != inlen)
399 fprintf (stderr, _("Short write (%d < %d)...\n"), i, inlen);
400 return 1;
402 printf (_("Wrote %d bytes...\n"), inlen);
405 if (arg.outputfile)
407 rc = fclose (outfh);
408 if (rc != 0)
410 shishi_error_printf (handle, _("`%s': %s\n"),
411 arg.outputfile, strerror (errno));
412 return SHISHI_FCLOSE_ERROR;
416 if (arg.inputfile)
418 rc = fclose (infh);
419 if (rc != 0)
421 shishi_error_printf (handle, _("`%s': %s\n"),
422 arg.inputfile, strerror (errno));
423 return SHISHI_FCLOSE_ERROR;
427 #endif
429 if (arg.writekeyfile)
431 shishi_key_to_file (handle, arg.writekeyfile, key);
434 return 0;
437 static void
438 parse_filename (char *arg, int *type, char **var)
440 if (strncasecmp (arg, TYPE_TEXT_NAME ",", strlen (TYPE_TEXT_NAME ",")) == 0)
442 (*type) = SHISHI_FILETYPE_TEXT;
443 arg += strlen (TYPE_TEXT_NAME ",");
445 else if (strncasecmp (arg, TYPE_DER_NAME ",", strlen (TYPE_DER_NAME ",")) ==
448 (*type) = SHISHI_FILETYPE_DER;
449 arg += strlen (TYPE_DER_NAME ",");
451 else if (strncasecmp (arg, TYPE_HEX_NAME ",", strlen (TYPE_HEX_NAME ",")) ==
454 (*type) = SHISHI_FILETYPE_HEX;
455 arg += strlen (TYPE_HEX_NAME ",");
457 else if (strncasecmp (arg, TYPE_BASE64_NAME ",",
458 strlen (TYPE_BASE64_NAME ",")) == 0)
460 (*type) = SHISHI_FILETYPE_BASE64;
461 arg += strlen (TYPE_BASE64_NAME ",");
463 else if (strncasecmp (arg, TYPE_BINARY_NAME ",",
464 strlen (TYPE_BINARY_NAME ",")) == 0)
466 (*type) = SHISHI_FILETYPE_BINARY;
467 arg += strlen (TYPE_BINARY_NAME ",");
469 else
470 (*type) = 0;
471 *var = strdup (arg);
474 static error_t
475 parse_opt (int key, char *arg, struct argp_state *state)
477 struct arguments *arguments = state->input;
479 switch (key)
481 case 'q':
482 arguments->silent = 1;
483 break;
485 case 'v':
486 arguments->verbose = 1;
487 break;
489 case OPTION_VERBOSE_LIBRARY:
490 arguments->verbose_library = 1;
491 break;
493 case 'o':
494 arguments->lib_options = arg;
495 break;
497 case OPTION_WRITE_TICKET_FILE:
498 arguments->ticketwritefile = strdup (arg);
499 break;
501 case 'E':
502 arguments->etypes = strdup (arg);
503 break;
505 case OPTION_CFG_SYSTEM:
506 arguments->systemcfgfile = strdup (arg);
507 break;
509 case OPTION_CFG_USER:
510 arguments->usercfgfile = strdup (arg);
511 break;
513 case 'c':
514 arguments->ticketfile = strdup (arg);
515 break;
517 case OPTION_CRYPTO_ALGORITHM:
518 if (arguments->command != OPTION_CRYPTO)
519 argp_error (state, _("Option `%s' only valid with CRYPTO."),
520 state->argv[state->next - 1]);
521 arguments->algorithm = shishi_cipher_parse (arg);
522 if (arguments->algorithm == -1)
523 argp_error (state, _("Unknown encryption type in `%s'"),
524 state->argv[state->next - 1]);
525 break;
527 case OPTION_CRYPTO_ENCRYPT:
528 if (arguments->command != OPTION_CRYPTO)
529 argp_error (state, _("Option `%s' only valid with CRYPTO."),
530 state->argv[state->next - 1]);
531 if (arguments->decrypt_p)
532 argp_error (state, _("Cannot both encrypt and decrypt."));
533 arguments->encrypt_p = 1;
534 break;
536 case OPTION_CRYPTO_DECRYPT:
537 if (arguments->command != OPTION_CRYPTO)
538 argp_error (state, _("Option `%s' only valid with CRYPTO."),
539 state->argv[state->next - 1]);
540 if (arguments->encrypt_p)
541 argp_error (state, _("Cannot both encrypt and decrypt."));
542 arguments->decrypt_p = 1;
543 break;
545 case OPTION_CRYPTO_KEY_VALUE:
546 arguments->keyvalue = strdup (arg);
547 break;
549 case OPTION_CRYPTO_KEY_USAGE:
550 if (arguments->command != OPTION_CRYPTO)
551 argp_error (state, _("Option `%s' only valid with CRYPTO."),
552 state->argv[state->next - 1]);
553 arguments->keyusage = atoi (arg);
554 break;
556 case OPTION_CRYPTO_KEY_VERSION:
557 if (arguments->command != OPTION_CRYPTO)
558 argp_error (state, _("Option `%s' only valid with CRYPTO."),
559 state->argv[state->next - 1]);
560 arguments->kvno = atoi (arg);
561 break;
563 case OPTION_CRYPTO_PARAMETER:
564 if (arguments->command != OPTION_CRYPTO)
565 argp_error (state, _("Option `%s' only valid with CRYPTO."),
566 state->argv[state->next - 1]);
567 arguments->parameter = strdup (arg);
568 break;
570 case OPTION_CRYPTO_PASSWORD:
571 arguments->password = strdup (arg);
572 break;
574 case OPTION_CRYPTO_RANDOM:
575 if (arguments->command != OPTION_CRYPTO)
576 argp_error (state, _("Option `%s' only valid with CRYPTO."),
577 state->argv[state->next - 1]);
578 arguments->random = 1;
579 break;
581 case OPTION_CRYPTO_READ_DATA_FILE:
582 if (arguments->command != OPTION_CRYPTO)
583 argp_error (state, _("Option `%s' only valid with CRYPTO."),
584 state->argv[state->next - 1]);
585 parse_filename (arg, &arguments->inputtype, &arguments->inputfile);
586 if (arguments->inputtype == SHISHI_FILETYPE_TEXT ||
587 arguments->inputtype == SHISHI_FILETYPE_DER)
588 arguments->inputtype = SHISHI_FILETYPE_BINARY;
589 break;
591 case OPTION_CRYPTO_READ_KEY_FILE:
592 if (arguments->command != OPTION_CRYPTO)
593 argp_error (state, _("Option `%s' only valid with CRYPTO."),
594 state->argv[state->next - 1]);
595 arguments->readkeyfile = strdup (arg);
596 break;
598 case OPTION_CRYPTO_SALT:
599 if (arguments->command != OPTION_CRYPTO)
600 argp_error (state, _("Option `%s' only valid with CRYPTO."),
601 state->argv[state->next - 1]);
602 arguments->salt = strdup (arg);
603 break;
605 case OPTION_CRYPTO_WRITE_DATA_FILE:
606 if (arguments->command != OPTION_CRYPTO)
607 argp_error (state, _("Option `%s' only valid with CRYPTO."),
608 state->argv[state->next - 1]);
609 parse_filename (arg, &arguments->outputtype, &arguments->outputfile);
610 if (arguments->outputtype == SHISHI_FILETYPE_TEXT ||
611 arguments->outputtype == SHISHI_FILETYPE_DER)
612 arguments->outputtype = SHISHI_FILETYPE_BINARY;
613 break;
615 case OPTION_CRYPTO_WRITE_KEY_FILE:
616 if (arguments->command != OPTION_CRYPTO)
617 argp_error (state, _("Option `%s' only valid with CRYPTO."),
618 state->argv[state->next - 1]);
619 arguments->writekeyfile = strdup (arg);
620 break;
622 case OPTION_CLIENT_NAME:
623 arguments->cname = strdup (arg);
624 break;
626 case 'e':
627 case OPTION_ENDTIME:
628 arguments->endtime_str = strdup (arg);
629 break;
631 case OPTION_REALM:
632 arguments->realm = strdup (arg);
633 break;
635 case 'R':
636 case OPTION_RENEW:
637 arguments->command = OPTION_RENEW;
638 break;
640 case OPTION_RENEW_TILL:
641 arguments->renew_till_str = strdup (arg);
642 /* fall through */
644 case OPTION_RENEWABLE:
645 arguments->renewable = 1;
646 break;
648 case 's':
649 case OPTION_STARTTIME:
650 arguments->starttime = get_date (arg, NULL);
651 if (arguments->starttime == -1)
652 argp_error (state, _("invalid --starttime date `%s'"), arg);
653 break;
655 case OPTION_SERVER_NAME:
656 arguments->sname = strdup (arg);
657 break;
659 case OPTION_FORCE_AS:
660 arguments->forceas_p = 1;
661 break;
663 case OPTION_FORCE_TGS:
664 arguments->forcetgs_p = 1;
665 break;
667 case OPTION_TICKET_GRANTER:
668 arguments->tgtname = strdup (arg);
669 break;
671 case OPTION_CRYPTO:
672 arguments->command = OPTION_CRYPTO;
673 break;
675 case 'l':
676 case OPTION_LIST:
677 arguments->command = OPTION_LIST;
678 break;
680 case 'd':
681 case OPTION_DESTROY:
682 arguments->command = OPTION_DESTROY;
683 break;
685 case ARGP_KEY_ARG:
686 if (arguments->client)
687 argp_error (state, _("Too many arguments: `%s'"), arg);
688 else
689 arguments->client = arg;
690 break;
692 default:
693 return ARGP_ERR_UNKNOWN;
696 return 0;
699 static struct argp_option options[] = {
701 {0, 0, 0, 0, "If no command is given, Shishi try to make sure you have a "
702 "ticket granting ticket for the default realm, and then display it."},
704 {"client-name", OPTION_CLIENT_NAME, "NAME", 0,
705 "Client name. Default is login username. Only for AS.", 10},
707 {"destroy", 'd', 0, 0,
708 "Destroy tickets in local cache, subject to --server-name limiting."},
710 {"encryption-type", 'E', "ETYPE,[ETYPE...]", 0,
711 "Encryption types to use. ETYPE is either registered name or integer."},
713 {"force-as", OPTION_FORCE_AS, 0, 0,
714 "Force AS mode. Default is to use TGS iff a TGT is found."},
716 {"force-tgs", OPTION_FORCE_TGS, 0, 0,
717 "Force TGS mode. Default is to use TGS iff a TGT is found."},
719 {"endtime", 'e', "STRING", 0,
720 "Specify when ticket validity should expire. The time syntax may be "
721 "relative (to the start time), such as \"20 hours\", or absolute, "
722 "such as \"2001-02-03 04:05:06 CET\". The default is 8 hours after "
723 "the start time."},
725 {"list", 'l', 0, 0,
726 "List tickets in local cache, subject to --server-name limiting."},
728 {"renew", 'R', 0, 0,
729 "Renew ticket. Use --server-name to specify ticket, default is the "
730 "most recent renewable ticket granting ticket for the default realm."},
732 {"renewable", OPTION_RENEWABLE, 0, 0,
733 "Get a renewable ticket."},
735 {"renew-till", OPTION_RENEW_TILL, "STRING", 0,
736 "Specify renewable life of ticket. Implies --renewable. Accepts same "
737 "time syntax as --endtime. If --renewable is specified, the default is 1 "
738 "week after the start time."},
740 {"realm", OPTION_REALM, "REALM", 0,
741 "Realm of server. Default is DNS domain of local host. For AS, this also "
742 "indicates realm of client."},
744 {"server", OPTION_SERVER, "[FAMILY:]ADDRESS:SERVICE/TYPE", 0,
745 "Send all requests to HOST instead of using normal logic to locate "
746 "KDC addresses (discouraged)."},
748 {"server-name", OPTION_SERVER_NAME, "NAME", 0,
749 "Server name. Default is \"krbtgt/REALM\" where REALM is server "
750 "realm (see --realm)."},
752 {"starttime", 's', "STRING", 0,
753 "Specify when ticket should start to be valid. Accepts same time syntax "
754 "as --endtime. The default is to become valid immediately."},
756 {"ticket-granter", OPTION_TICKET_GRANTER, "NAME", 0,
757 "Service name in ticket to use for authenticating request. Only for TGS. "
758 "Defaults to \"krbtgt/REALM@REALM\" where REALM is server "
759 "realm (see --realm)."},
761 {"key-value", OPTION_CRYPTO_KEY_VALUE, "KEY", 0,
762 "Cipher key to decrypt response (discouraged)."},
764 {"password", OPTION_CRYPTO_PASSWORD, "PASSWORD", 0,
765 "Password to decrypt response (discouraged). Only for AS."},
767 /************** CRYPTO */
769 {0, 0, 0, 0,
770 "Options for low-level cryptography (CRYPTO-OPTIONS):", 100},
772 {"algorithm", OPTION_CRYPTO_ALGORITHM, "ALGORITHM", 0,
773 "Cipher algorithm, expressed either as the etype integer or "
774 "the registered name."},
776 {"client-name", OPTION_CLIENT_NAME, "NAME", 0,
777 "Username. Default is login name."},
779 {"decrypt", OPTION_CRYPTO_DECRYPT, 0, 0,
780 "Decrypt data."},
782 {"encrypt", OPTION_CRYPTO_ENCRYPT, 0, 0,
783 "Encrypt data."},
785 {"key-usage", OPTION_CRYPTO_KEY_USAGE, "KEYUSAGE", 0,
786 "Encrypt or decrypt using specified key usage. Default is 0, which "
787 "means no key derivation are performed."},
789 {"key-value", OPTION_CRYPTO_KEY_VALUE, "KEY", 0,
790 "Base64 encoded key value."},
792 {"key-version", OPTION_CRYPTO_KEY_VERSION, "INTEGER", 0,
793 "Version number of key."},
795 {"password", OPTION_CRYPTO_PASSWORD, "PASSWORD", 0,
796 "Password used to generate key. --client-name and --realm also modify "
797 "the computed key value."},
799 {"random", OPTION_CRYPTO_RANDOM, 0, 0,
800 "Generate key from random data."},
802 {"read-key-file", OPTION_CRYPTO_READ_KEY_FILE, "FILE", 0,
803 "Read cipher key from FILE"},
805 {"read-data-file", OPTION_CRYPTO_READ_DATA_FILE, "[TYPE,]FILE", 0,
806 "Read data from FILE in TYPE, BASE64, HEX or BINARY (default)."},
808 {"realm", OPTION_REALM, "REALM", 0,
809 "Realm of principal. Defaults to DNS domain of local host. "},
811 {"salt", OPTION_CRYPTO_SALT, "SALT", 0,
812 "Salt to use when --password is specified. Defaults to using the"
813 "username (--client-name) and realm (--realm)."},
815 {"parameter", OPTION_CRYPTO_PARAMETER, "STRING", 0,
816 "String-to-key parameter to use when --password is specified. This data "
817 "is specific for each encryption algorithm and rarely needed."},
819 {"write-key-file", OPTION_CRYPTO_WRITE_KEY_FILE, "FILE", 0,
820 "Append cipher key to FILE"},
822 {"write-data-file", OPTION_CRYPTO_WRITE_DATA_FILE, "[TYPE,]FILE", 0,
823 "Write data to FILE in TYPE, BASE64, HEX or BINARY (default)."},
825 /************** OTHER */
827 {0, 0, 0, 0, "Other options:", 200},
829 {"verbose", 'v', 0, 0,
830 "Produce verbose output.",},
832 {"verbose-library", OPTION_VERBOSE_LIBRARY, 0, 0,
833 "Produce verbose output in the library.",},
835 {"quiet", 'q', 0, 0,
836 "Don't produce any output."},
838 {"silent", 0, 0, OPTION_ALIAS},
840 {"system-configuration-file", OPTION_CFG_SYSTEM, "FILE", 0,
841 "Read system wide configuration from file. Default is " SYSTEMCFGFILE
842 "."},
844 {"configuration-file", OPTION_CFG_USER, "FILE", 0,
845 "Read user configuration from file. Default is ~/.shishi/config."},
847 {"library-options", 'o', "STRING", 0,
848 "Parse STRING as a configuration file statement."},
850 {"ticket-file", 'c', "FILE", 0,
851 "Read tickets from FILE. Default is $HOME/.shishi/tickets."},
853 {"ticket-write-file", OPTION_WRITE_TICKET_FILE, "FILE", 0,
854 "Write tickets to FILE. Default is to write them back to ticket file."},
856 {"NAME", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
857 "Set client name and realm from NAME. The --client-name and --realm can "
858 "be used to override part of NAME."},
860 /************** EXAMPLES */
862 {0, 0, 0, 0, "Examples:", 300},
864 {"shishi", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
865 "Get a ticket granting ticket from the default KDC server for the "
866 "default user and realm."},
868 {"shishi jas/admin@ACCOUNTING", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
869 "Get a ticket for jas/admin in the ACCOUNTING realm."},
871 {"shishi --list --server-name=krbtgt/JOSEFSSON.ORG@JOSEFSSON.ORG",
872 0, 0, OPTION_DOC | OPTION_NO_USAGE,
873 "List tickets for the Ticket Granting Service in the JOSEFSSON.ORG realm."},
878 static struct argp argp = {
879 options,
880 parse_opt,
881 "[NAME] [OPTION...]\n"
882 "--list [--server-name=NAME]\n"
883 "--destroy [--server-name=NAME]\n"
884 "--crypto [CRYPTO-OPTION...]\n",
885 "Shishi -- A Kerberos 5 implementation"
889 main (int argc, char *argv[])
891 struct arguments arg;
892 Shishi *handle;
893 int rc;
895 setlocale (LC_ALL, "");
896 bindtextdomain (PACKAGE, LOCALEDIR);
897 textdomain (PACKAGE);
899 memset (&arg, 0, sizeof (arg));
900 argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &arg);
902 rc = shishi_init_with_paths (&handle, arg.ticketfile,
903 arg.systemcfgfile, arg.usercfgfile);
904 if (rc == SHISHI_HANDLE_ERROR)
905 error (1, 0, "Internal error: could not initialize shishi\n");
907 rc = shishi_cfg_clientkdcetype_set (handle, arg.etypes);
908 if (rc != SHISHI_OK)
909 error (1, 0, "Could not set encryption types: %s\n", shishi_strerror (rc));
911 if (arg.client)
913 rc = shishi_parse_name (handle, arg.client,
914 (char **) (arg.cname ? NULL : &arg.cname),
915 (char **) (arg.realm ? NULL : &arg.realm));
917 if (rc != SHISHI_OK)
918 error (1, 0, "Could not parse principal \"%s\": %s\n", arg.client,
919 shishi_strerror (rc));
922 rc = shishi_cfg (handle, arg.lib_options);
923 if (rc != SHISHI_OK)
924 error (1, 0, "Could not read library options: %s\n", shishi_strerror (rc));
926 if (arg.verbose_library)
928 rc = shishi_cfg (handle, "verbose");
929 if (rc != SHISHI_OK)
930 error (1, 0, "Could not make library verbose: %s\n",
931 shishi_strerror (rc));
934 if (!arg.starttime)
935 arg.starttime = time(NULL);
937 if (arg.endtime_str)
939 arg.endtime = get_date (arg.endtime_str, &arg.starttime);
940 if (arg.endtime == -1)
941 error (1, 0, _("invalid --endtime date `%s'"), arg.endtime_str);
944 if (arg.renew_till_str)
946 arg.renew_till = get_date (arg.renew_till_str, &arg.starttime);
947 if (arg.renew_till == -1)
948 error (1, 0, _("invalid --renew-till date `%s'"), arg.renew_till_str);
951 if (arg.cname)
952 shishi_principal_default_set (handle, arg.cname);
954 if (arg.realm)
955 shishi_realm_default_set (handle, arg.realm);
957 if (!arg.tgtname)
959 asprintf (&arg.tgtname, "krbtgt/%s", shishi_realm_default (handle));
960 if (arg.tgtname == NULL)
961 error (1, 0, "Could not allocate TGT name.");
964 rc = 1;
966 switch (arg.command)
968 case OPTION_LIST:
969 if (!arg.silent)
970 printf (_("Tickets in `%s':\n"), shishi_tkts_default_file (handle));
972 rc = shishi_tkts_print_for_service (shishi_tkts_default (handle),
973 stdout, arg.sname);
974 if (rc != SHISHI_OK)
975 fprintf (stderr, "Could not list tickets: %s", shishi_strerror (rc));
976 break;
978 case OPTION_DESTROY:
980 int i, removed = 0;
981 for (i = 0; i < shishi_tkts_size (shishi_tkts_default (handle)); i++)
983 if (arg.sname &&
984 !shishi_tkt_server_p (shishi_tkts_nth
985 (shishi_tkts_default (handle),
986 i), arg.sname))
987 continue;
989 if (arg.verbose)
991 printf ("Removing ticket:\n");
992 shishi_tkt_pretty_print (shishi_tkts_nth
993 (shishi_tkts_default
994 (handle), i), stdout);
997 rc = shishi_tkts_remove (shishi_tkts_default (handle), i);
998 if (rc != SHISHI_OK)
999 fprintf (stderr, "Could not destroy ticket %d:\n%s\n", i,
1000 shishi_strerror (rc));
1001 i--;
1002 removed++;
1004 if (removed == 0)
1005 printf ("No tickets removed.\n");
1006 else if (removed == 1)
1007 printf ("1 ticket removed.\n");
1008 else
1009 printf ("%d tickets removed.\n", removed);
1010 rc = SHISHI_OK;
1012 break;
1014 case OPTION_CRYPTO:
1015 rc = crypto (handle, arg);
1016 if (rc != SHISHI_OK)
1017 fprintf (stderr, "Operation failed:\n%s\n%s\n",
1018 shishi_strerror (rc), shishi_strerror_details (handle));
1019 break;
1021 case OPTION_RENEW:
1023 Shishi_tkt *tkt;
1024 Shishi_tkts_hint hint;
1025 Shishi_tgs *tgs;
1027 /* This doesn't work */
1029 memset (&hint, 0, sizeof (hint));
1030 hint.client = (char *) arg.cname;
1031 hint.server = (char *) (arg.sname ? arg.sname : arg.tgtname);
1032 hint.starttime = arg.starttime;
1033 hint.endtime = arg.endtime;
1034 hint.renew_till = arg.renew_till;
1035 hint.renewable = arg.renewable;
1037 tkt = shishi_tkts_find (shishi_tkts_default (handle), &hint);
1038 if (!tkt)
1040 printf ("Could not get ticket for `%s'.\n", hint.server);
1041 rc = !SHISHI_OK;
1043 else
1045 rc = shishi_tkt_pretty_print (tkt, stdout);
1046 if (rc != SHISHI_OK)
1047 fprintf (stderr, "Pretty printing ticket failed:\n%s\n%s\n",
1048 shishi_strerror (rc), shishi_strerror_details (handle));
1051 /* Get ticket using TGT ... */
1052 rc = shishi_tgs (handle, &tgs);
1053 shishi_tgs_tgtkt_set (tgs, tkt);
1054 if (rc == SHISHI_OK)
1055 rc = shishi_tgs_set_server (tgs, hint.server);
1056 rc = shishi_kdcreq_options_add (handle, shishi_tgs_req(tgs),
1057 SHISHI_KDCOPTIONS_RENEWABLE|
1058 SHISHI_KDCOPTIONS_RENEW);
1059 if (rc == SHISHI_OK)
1060 rc = shishi_asn1_write (handle, shishi_tgs_req(tgs),
1061 "req-body.rtime",
1062 shishi_generalize_time
1063 (handle, hint.renew_till),
1065 if (rc == SHISHI_OK)
1066 rc = shishi_tgs_req_build (tgs);
1067 if (rc == SHISHI_OK)
1068 rc = shishi_tgs_sendrecv (tgs);
1069 if (rc == SHISHI_OK)
1070 rc = shishi_tgs_rep_process (tgs);
1071 if (rc != SHISHI_OK)
1073 printf ("TGS exchange failed: %s\n%s\n", shishi_strerror (rc),
1074 shishi_strerror_details (handle));
1075 if (rc == SHISHI_GOT_KRBERROR)
1076 shishi_krberror_pretty_print (handle, stdout,
1077 shishi_tgs_krberror (tgs));
1078 return NULL;
1081 tkt = shishi_tgs_tkt (tgs);
1082 if (!tkt)
1084 printf ("No ticket in TGS-REP?!: %s\n",
1085 shishi_strerror_details (handle));
1086 return NULL;
1089 shishi_tkt_pretty_print (tkt, stdout);
1091 rc = shishi_tkts_add (shishi_tkts_default (handle), tkt);
1092 if (rc != SHISHI_OK)
1093 printf ("Could not add ticket: %s", shishi_strerror (rc));
1095 break;
1097 default:
1099 Shishi_tkt *tkt;
1100 Shishi_tkts_hint hint;
1102 memset (&hint, 0, sizeof (hint));
1103 hint.client = (char *) arg.cname;
1104 hint.server = (char *) (arg.sname ? arg.sname : arg.tgtname);
1105 hint.starttime = arg.starttime;
1106 hint.endtime = arg.endtime;
1107 hint.renew_till = arg.renew_till;
1108 hint.renewable = arg.renewable;
1110 tkt = shishi_tkts_get (shishi_tkts_default (handle), &hint);
1111 if (!tkt)
1113 printf ("Could not get ticket for `%s'.\n",
1114 arg.tgtname ? arg.tgtname : arg.cname);
1115 rc = !SHISHI_OK;
1117 else
1119 rc = shishi_tkt_pretty_print (tkt, stdout);
1120 if (rc != SHISHI_OK)
1121 fprintf (stderr, "Pretty printing ticket failed:\n%s\n%s\n",
1122 shishi_strerror (rc), shishi_strerror_details (handle));
1125 break;
1128 shishi_tkts_expire (shishi_tkts_default (handle));
1130 if (arg.ticketwritefile)
1131 shishi_tkts_default_file_set (handle, arg.ticketwritefile);
1133 shishi_done (handle);
1135 return rc == SHISHI_OK ? 0 : 1;