Argp fixes.
[shishi.git] / src / shishi.c
blob3ace3e7befed1f7305b654b2115e441756fc57c3
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"
115 #include <argp.h>
116 #include <gettext.h>
117 #include <shishi.h>
119 #define _(String) gettext (String)
120 #define gettext_noop(String) String
121 #define N_(String) gettext_noop (String)
123 /* Long parameters only */
124 enum
126 OPTION_REQUEST = 300,
127 OPTION_SENDRECV,
128 OPTION_RESPONSE,
129 OPTION_WRITE_AP_REQUEST_FILE,
130 OPTION_WRITE_AUTHENTICATOR_FILE,
131 OPTION_WRITE_REQUEST_FILE,
132 OPTION_WRITE_RESPONSE_FILE,
133 OPTION_READ_REQUEST_FILE,
134 OPTION_READ_RESPONSE_FILE,
135 OPTION_SERVER,
136 OPTION_CLIENT,
137 OPTION_CLIENT_NAME,
138 OPTION_REALM,
139 OPTION_SERVER_NAME,
140 OPTION_TICKET_GRANTER,
141 OPTION_FORCE_AS,
142 OPTION_FORCE_TGS,
143 OPTION_CRYPTO_ENCRYPT,
144 OPTION_CRYPTO_DECRYPT,
145 OPTION_CRYPTO_ALGORITHM,
146 OPTION_CRYPTO_KEY_VERSION,
147 OPTION_CRYPTO_KEY_USAGE,
148 OPTION_CRYPTO_KEY_VALUE,
149 OPTION_CRYPTO_READ_KEY_FILE,
150 OPTION_CRYPTO_WRITE_KEY_FILE,
151 OPTION_CRYPTO_READ_DATA_FILE,
152 OPTION_CRYPTO_WRITE_DATA_FILE,
153 OPTION_CRYPTO_RANDOM,
154 OPTION_CRYPTO_PARAMETER,
155 OPTION_CRYPTO_PASSWORD,
156 OPTION_CRYPTO_SALT,
157 OPTION_CRYPTO_DEBUG,
158 OPTION_CRYPTO_GENERATE_KEY,
159 OPTION_VERBOSE_LIBRARY,
160 OPTION_LIST,
161 OPTION_DESTROY,
162 OPTION_CRYPTO,
163 OPTION_RENEW,
164 OPTION_RENEWABLE,
165 OPTION_STARTTIME,
166 OPTION_ENDTIME,
167 OPTION_RENEW_TILL,
168 OPTION_CFG_SYSTEM,
169 OPTION_CFG_USER,
170 OPTION_WRITE_TICKET_FILE
173 #define TYPE_TEXT_NAME "text"
174 #define TYPE_DER_NAME "der"
175 #define TYPE_HEX_NAME "hex"
176 #define TYPE_BASE64_NAME "base64"
177 #define TYPE_BINARY_NAME "binary"
179 struct arguments
181 int silent, verbose, verbose_library;
182 char *etypes;
183 char *lib_options;
184 int command;
185 char *ticketfile;
186 char *ticketwritefile;
187 const char *realm;
188 char *systemcfgfile;
189 char *usercfgfile;
190 const char *client;
191 const char *cname;
192 const char *sname;
193 char *tgtname;
194 int forceas_p;
195 int forcetgs_p;
196 char *servername;
197 int renew;
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;
228 crypto (Shishi * handle, struct arguments arg)
230 FILE *infh, *outfh;
231 Shishi_key *key;
232 char *in, *out;
233 size_t inlen, outlen;
234 int rc;
235 int i;
237 if (arg.cname == NULL)
238 arg.cname = shishi_principal_default (handle);
240 if (arg.realm == NULL)
241 arg.realm = shishi_realm_default (handle);
243 if (arg.salt == NULL)
245 arg.salt = malloc (strlen (arg.realm) + strlen (arg.cname) + 1);
246 if (!arg.salt)
247 return SHISHI_MALLOC_ERROR;
248 strcpy (arg.salt, arg.realm);
249 strcat (arg.salt, arg.cname);
252 rc = shishi_key (handle, &key);
253 if (rc != SHISHI_OK)
255 shishi_error_printf (handle, _("Cannot create key: %s"),
256 shishi_strerror (rc));
257 return rc;
260 shishi_key_type_set (key, arg.algorithm);
261 shishi_key_version_set (key, arg.kvno);
262 shishi_key_principal_set (key, arg.cname);
263 shishi_key_realm_set (key, arg.realm);
265 if (arg.password)
267 rc = shishi_string_to_key (handle, arg.algorithm,
268 arg.password,
269 strlen (arg.password),
270 arg.salt,
271 strlen (arg.salt), arg.parameter, key);
272 if (rc != SHISHI_OK)
274 shishi_error_printf (handle, _("Error in string2key"));
275 return rc;
279 else if (arg.keyvalue)
281 rc = shishi_key_from_base64 (handle, arg.algorithm, arg.keyvalue, &key);
282 if (rc != SHISHI_OK)
284 fprintf (stderr, _("Could not create key: %s\n"),
285 shishi_strerror (rc));
286 return rc;
289 else if (arg.random)
291 char buf[BUFSIZ];
293 rc = shishi_randomize (handle, buf,
294 shishi_cipher_randomlen (arg.algorithm));
295 if (rc != SHISHI_OK)
296 return rc;
298 shishi_random_to_key (handle, arg.algorithm,
299 buf, shishi_cipher_randomlen (arg.algorithm),
300 key);
302 else if (arg.readkeyfile)
304 key = shishi_keys_for_server_in_file (handle, arg.readkeyfile,
305 arg.cname);
306 #if 0
307 shishi_key_from_file (handle, arg.writekeyfile, arg.algorithm, key,
308 keylen, arg.kvno, arg.cname, arg.realm);
309 #endif
311 if (key == NULL)
313 fprintf (stderr, _("Could not find key: %s\n"),
314 shishi_strerror_details (handle));
315 return 1;
318 else
320 fprintf (stderr, "Nothing to do.\n");
321 return SHISHI_OK;
324 if (shishi_key_type (key) == SHISHI_NULL && !arg.silent)
325 fprintf (stderr,
326 "warning: using %s is silly, consider using --algorithm.\n",
327 shishi_cipher_name (arg.algorithm));
329 if (arg.verbose ||
330 ((arg.password || arg.random || arg.keyvalue) &&
331 !(arg.encrypt_p || arg.decrypt_p)))
333 shishi_key_print (handle, stdout, key);
336 #if 0
337 currently broken
338 if (arg.encrypt_p || arg.decrypt_p)
340 if (arg.inputfile)
342 infh = fopen (arg.inputfile, "r");
343 if (infh == NULL)
345 shishi_error_printf (handle, _("`%s': %s\n"),
346 arg.inputfile, strerror (errno));
347 return SHISHI_FOPEN_ERROR;
350 else
351 infh = stdin;
353 if (arg.outputfile)
355 outfh = fopen (arg.outputfile, "w");
356 if (outfh == NULL)
358 shishi_error_printf (handle, _("`%s': %s\n"),
359 arg.inputfile, strerror (errno));
360 return SHISHI_FOPEN_ERROR;
363 else
364 outfh = stdout;
366 outlen = fread (out, sizeof (out[0]),
367 sizeof (out) / sizeof (out[0]), infh);
368 if (outlen == 0)
370 fprintf (stderr, _("Error reading `%s'\n"), arg.inputfile);
371 return !SHISHI_OK;
373 if (arg.verbose)
374 printf (_("Read %d bytes...\n"), outlen);
376 if (arg.encrypt_p)
377 rc = shishi_encrypt (handle, key, arg.keyusage,
378 out, outlen, &in, &inlen);
379 else
380 rc = shishi_decrypt (handle, key, arg.keyusage,
381 in, inlen, &out, &outlen);
382 if (rc != SHISHI_OK)
384 shishi_error_printf (handle, _("Error ciphering\n"));
385 return rc;
388 if (arg.outputtype == SHISHI_FILETYPE_HEX)
390 for (i = 0; i < inlen; i++)
392 if ((i % 16) == 0)
393 fprintf (outfh, "\n");
394 fprintf (outfh, "%02x ", in[i]);
396 fprintf (outfh, "\n");
398 else if (arg.outputtype == SHISHI_FILETYPE_BINARY)
400 i = fwrite (in, sizeof (in[0]), inlen, outfh);
401 if (i != inlen)
403 fprintf (stderr, _("Short write (%d < %d)...\n"), i, inlen);
404 return 1;
406 printf (_("Wrote %d bytes...\n"), inlen);
409 if (arg.outputfile)
411 rc = fclose (outfh);
412 if (rc != 0)
414 shishi_error_printf (handle, _("`%s': %s\n"),
415 arg.outputfile, strerror (errno));
416 return SHISHI_FCLOSE_ERROR;
420 if (arg.inputfile)
422 rc = fclose (infh);
423 if (rc != 0)
425 shishi_error_printf (handle, _("`%s': %s\n"),
426 arg.inputfile, strerror (errno));
427 return SHISHI_FCLOSE_ERROR;
431 #endif
433 if (arg.writekeyfile)
435 shishi_key_to_file (handle, arg.writekeyfile, key);
438 return 0;
441 static void
442 parse_filename (char *arg, int *type, char **var)
444 if (strncasecmp (arg, TYPE_TEXT_NAME ",", strlen (TYPE_TEXT_NAME ",")) == 0)
446 (*type) = SHISHI_FILETYPE_TEXT;
447 arg += strlen (TYPE_TEXT_NAME ",");
449 else if (strncasecmp (arg, TYPE_DER_NAME ",", strlen (TYPE_DER_NAME ",")) ==
452 (*type) = SHISHI_FILETYPE_DER;
453 arg += strlen (TYPE_DER_NAME ",");
455 else if (strncasecmp (arg, TYPE_HEX_NAME ",", strlen (TYPE_HEX_NAME ",")) ==
458 (*type) = SHISHI_FILETYPE_HEX;
459 arg += strlen (TYPE_HEX_NAME ",");
461 else if (strncasecmp (arg, TYPE_BASE64_NAME ",",
462 strlen (TYPE_BASE64_NAME ",")) == 0)
464 (*type) = SHISHI_FILETYPE_BASE64;
465 arg += strlen (TYPE_BASE64_NAME ",");
467 else if (strncasecmp (arg, TYPE_BINARY_NAME ",",
468 strlen (TYPE_BINARY_NAME ",")) == 0)
470 (*type) = SHISHI_FILETYPE_BINARY;
471 arg += strlen (TYPE_BINARY_NAME ",");
473 else
474 (*type) = 0;
475 *var = strdup (arg);
478 static error_t
479 parse_opt (int key, char *arg, struct argp_state *state)
481 struct arguments *arguments = state->input;
483 switch (key)
485 case 'q':
486 arguments->silent = 1;
487 break;
489 case 'v':
490 arguments->verbose = 1;
491 break;
493 case OPTION_VERBOSE_LIBRARY:
494 arguments->verbose_library = 1;
495 break;
497 case 'o':
498 arguments->lib_options = arg;
499 break;
501 case OPTION_WRITE_TICKET_FILE:
502 arguments->ticketwritefile = strdup (arg);
503 break;
505 case 'E':
506 arguments->etypes = strdup (arg);
507 break;
509 case OPTION_CFG_SYSTEM:
510 arguments->systemcfgfile = strdup (arg);
511 break;
513 case OPTION_CFG_USER:
514 arguments->usercfgfile = strdup (arg);
515 break;
517 case 'c':
518 arguments->ticketfile = strdup (arg);
519 break;
521 case OPTION_CRYPTO_ALGORITHM:
522 if (arguments->command != OPTION_CRYPTO)
523 argp_error (state, _("Option `%s' only valid with CRYPTO."),
524 state->argv[state->next - 1]);
525 arguments->algorithm = shishi_cipher_parse (arg);
526 if (arguments->algorithm == -1)
527 argp_error (state, _("Unknown encryption type in `%s'"),
528 state->argv[state->next - 1]);
529 break;
531 case OPTION_CRYPTO_ENCRYPT:
532 if (arguments->command != OPTION_CRYPTO)
533 argp_error (state, _("Option `%s' only valid with CRYPTO."),
534 state->argv[state->next - 1]);
535 if (arguments->decrypt_p)
536 argp_error (state, _("Cannot both encrypt and decrypt."));
537 arguments->encrypt_p = 1;
538 break;
540 case OPTION_CRYPTO_DECRYPT:
541 if (arguments->command != OPTION_CRYPTO)
542 argp_error (state, _("Option `%s' only valid with CRYPTO."),
543 state->argv[state->next - 1]);
544 if (arguments->encrypt_p)
545 argp_error (state, _("Cannot both encrypt and decrypt."));
546 arguments->decrypt_p = 1;
547 break;
549 case OPTION_CRYPTO_KEY_VALUE:
550 arguments->keyvalue = strdup (arg);
551 break;
553 case OPTION_CRYPTO_KEY_USAGE:
554 if (arguments->command != OPTION_CRYPTO)
555 argp_error (state, _("Option `%s' only valid with CRYPTO."),
556 state->argv[state->next - 1]);
557 arguments->keyusage = atoi (arg);
558 break;
560 case OPTION_CRYPTO_KEY_VERSION:
561 if (arguments->command != OPTION_CRYPTO)
562 argp_error (state, _("Option `%s' only valid with CRYPTO."),
563 state->argv[state->next - 1]);
564 arguments->kvno = atoi (arg);
565 break;
567 case OPTION_CRYPTO_PARAMETER:
568 if (arguments->command != OPTION_CRYPTO)
569 argp_error (state, _("Option `%s' only valid with CRYPTO."),
570 state->argv[state->next - 1]);
571 arguments->parameter = strdup (arg);
572 break;
574 case OPTION_CRYPTO_PASSWORD:
575 arguments->password = strdup (arg);
576 break;
578 case OPTION_CRYPTO_RANDOM:
579 if (arguments->command != OPTION_CRYPTO)
580 argp_error (state, _("Option `%s' only valid with CRYPTO."),
581 state->argv[state->next - 1]);
582 arguments->random = 1;
583 break;
585 case OPTION_CRYPTO_READ_DATA_FILE:
586 if (arguments->command != OPTION_CRYPTO)
587 argp_error (state, _("Option `%s' only valid with CRYPTO."),
588 state->argv[state->next - 1]);
589 parse_filename (arg, &arguments->inputtype, &arguments->inputfile);
590 if (arguments->inputtype == SHISHI_FILETYPE_TEXT ||
591 arguments->inputtype == SHISHI_FILETYPE_DER)
592 arguments->inputtype = SHISHI_FILETYPE_BINARY;
593 break;
595 case OPTION_CRYPTO_READ_KEY_FILE:
596 if (arguments->command != OPTION_CRYPTO)
597 argp_error (state, _("Option `%s' only valid with CRYPTO."),
598 state->argv[state->next - 1]);
599 arguments->readkeyfile = strdup (arg);
600 break;
602 case OPTION_CRYPTO_SALT:
603 if (arguments->command != OPTION_CRYPTO)
604 argp_error (state, _("Option `%s' only valid with CRYPTO."),
605 state->argv[state->next - 1]);
606 arguments->salt = 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_REALM:
636 arguments->realm = strdup (arg);
637 break;
639 case 'R':
640 case OPTION_RENEW:
641 arguments->renew = 1;
642 break;
644 case OPTION_RENEW_TILL:
645 arguments->renew_till_str = strdup (arg);
646 /* fall through */
648 case OPTION_RENEWABLE:
649 arguments->renewable = 1;
650 break;
652 case 's':
653 case OPTION_STARTTIME:
654 arguments->starttime = get_date (arg, NULL);
655 if (arguments->starttime == -1)
656 argp_error (state, _("invalid --starttime date `%s'"), arg);
657 break;
659 case OPTION_SERVER_NAME:
660 arguments->sname = strdup (arg);
661 break;
663 case OPTION_FORCE_AS:
664 arguments->forceas_p = 1;
665 break;
667 case OPTION_FORCE_TGS:
668 arguments->forcetgs_p = 1;
669 break;
671 case OPTION_TICKET_GRANTER:
672 arguments->tgtname = strdup (arg);
673 break;
675 case OPTION_CRYPTO:
676 arguments->command = OPTION_CRYPTO;
677 break;
679 case 'l':
680 case OPTION_LIST:
681 arguments->command = OPTION_LIST;
682 break;
684 case 'd':
685 case OPTION_DESTROY:
686 arguments->command = OPTION_DESTROY;
687 break;
689 case ARGP_KEY_ARG:
690 if (arguments->client)
691 argp_error (state, _("Too many arguments: `%s'"), arg);
692 else
693 arguments->client = arg;
694 break;
696 default:
697 return ARGP_ERR_UNKNOWN;
700 return 0;
703 static struct argp_option options[] = {
705 {0, 0, 0, 0, "If no command is given, Shishi try to make sure you have a "
706 "ticket granting ticket for the default realm, and then display it."},
708 {"client-name", OPTION_CLIENT_NAME, "NAME", 0,
709 "Client name. Default is login username. Only for AS.", 10},
711 {"destroy", 'd', 0, 0,
712 "Destroy tickets in local cache, subject to --server-name limiting."},
714 {"encryption-type", 'E', "ETYPE,[ETYPE...]", 0,
715 "Encryption types to use. ETYPE is either registered name or integer."},
717 {"force-as", OPTION_FORCE_AS, 0, 0,
718 "Force AS mode. Default is to use TGS iff a TGT is found."},
720 {"force-tgs", OPTION_FORCE_TGS, 0, 0,
721 "Force TGS mode. Default is to use TGS iff a TGT is found."},
723 {"endtime", 'e', "STRING", 0,
724 "Specify when ticket validity should expire. The time syntax may be "
725 "relative (to the start time), such as \"20 hours\", or absolute, "
726 "such as \"2001-02-03 04:05:06 CET\". The default is 8 hours after "
727 "the start time."},
729 {"list", 'l', 0, 0,
730 "List tickets in local cache, subject to --server-name limiting."},
732 {"renew", 'R', 0, 0,
733 "Renew ticket. Use --server-name to specify ticket, default is the "
734 "most recent renewable ticket granting ticket for the default realm."},
736 {"renewable", OPTION_RENEWABLE, 0, 0,
737 "Get a renewable ticket."},
739 {"renew-till", OPTION_RENEW_TILL, "STRING", 0,
740 "Specify renewable life of ticket. Implies --renewable. Accepts same "
741 "time syntax as --endtime. If --renewable is specified, the default is 1 "
742 "week after the start time."},
744 {"realm", OPTION_REALM, "REALM", 0,
745 "Realm of server. Default is DNS domain of local host. For AS, this also "
746 "indicates realm of client."},
748 {"server", OPTION_SERVER, "[FAMILY:]ADDRESS:SERVICE/TYPE", 0,
749 "Send all requests to HOST instead of using normal logic to locate "
750 "KDC addresses (discouraged)."},
752 {"server-name", OPTION_SERVER_NAME, "NAME", 0,
753 "Server name. Default is \"krbtgt/REALM\" where REALM is server "
754 "realm (see --realm)."},
756 {"starttime", 's', "STRING", 0,
757 "Specify when ticket should start to be valid. Accepts same time syntax "
758 "as --endtime. The default is to become valid immediately."},
760 {"ticket-granter", OPTION_TICKET_GRANTER, "NAME", 0,
761 "Service name in ticket to use for authenticating request. Only for TGS. "
762 "Defaults to \"krbtgt/REALM@REALM\" where REALM is server "
763 "realm (see --realm)."},
765 {"key-value", OPTION_CRYPTO_KEY_VALUE, "KEY", 0,
766 "Cipher key to decrypt response (discouraged)."},
768 {"password", OPTION_CRYPTO_PASSWORD, "PASSWORD", 0,
769 "Password to decrypt response (discouraged). Only for AS."},
771 /************** CRYPTO */
773 {0, 0, 0, 0,
774 "Options for low-level cryptography (CRYPTO-OPTIONS):", 100},
776 {"algorithm", OPTION_CRYPTO_ALGORITHM, "ALGORITHM", 0,
777 "Cipher algorithm, expressed either as the etype integer or "
778 "the registered name."},
780 {"client-name", OPTION_CLIENT_NAME, "NAME", 0,
781 "Username. Default is login name."},
783 {"decrypt", OPTION_CRYPTO_DECRYPT, 0, 0,
784 "Decrypt data."},
786 {"encrypt", OPTION_CRYPTO_ENCRYPT, 0, 0,
787 "Encrypt data."},
789 {"key-usage", OPTION_CRYPTO_KEY_USAGE, "KEYUSAGE", 0,
790 "Encrypt or decrypt using specified key usage. Default is 0, which "
791 "means no key derivation are performed."},
793 {"key-value", OPTION_CRYPTO_KEY_VALUE, "KEY", 0,
794 "Base64 encoded key value."},
796 {"key-version", OPTION_CRYPTO_KEY_VERSION, "INTEGER", 0,
797 "Version number of key."},
799 {"password", OPTION_CRYPTO_PASSWORD, "PASSWORD", 0,
800 "Password used to generate key. --client-name and --realm also modify "
801 "the computed key value."},
803 {"random", OPTION_CRYPTO_RANDOM, 0, 0,
804 "Generate key from random data."},
806 {"read-key-file", OPTION_CRYPTO_READ_KEY_FILE, "FILE", 0,
807 "Read cipher key from FILE"},
809 {"read-data-file", OPTION_CRYPTO_READ_DATA_FILE, "[TYPE,]FILE", 0,
810 "Read data from FILE in TYPE, BASE64, HEX or BINARY (default)."},
812 {"realm", OPTION_REALM, "REALM", 0,
813 "Realm of principal. Defaults to DNS domain of local host. "},
815 {"salt", OPTION_CRYPTO_SALT, "SALT", 0,
816 "Salt to use when --password is specified. Defaults to using the"
817 "username (--client-name) and realm (--realm)."},
819 {"parameter", OPTION_CRYPTO_PARAMETER, "STRING", 0,
820 "String-to-key parameter to use when --password is specified. This data "
821 "is specific for each encryption algorithm and rarely needed."},
823 {"write-key-file", OPTION_CRYPTO_WRITE_KEY_FILE, "FILE", 0,
824 "Append cipher key to FILE"},
826 {"write-data-file", OPTION_CRYPTO_WRITE_DATA_FILE, "[TYPE,]FILE", 0,
827 "Write data to FILE in TYPE, BASE64, HEX or BINARY (default)."},
829 /************** OTHER */
831 {0, 0, 0, 0, "Other options:", 200},
833 {"verbose", 'v', 0, 0,
834 "Produce verbose output.",},
836 {"verbose-library", OPTION_VERBOSE_LIBRARY, 0, 0,
837 "Produce verbose output in the library.",},
839 {"quiet", 'q', 0, 0,
840 "Don't produce any output."},
842 {"silent", 0, 0, OPTION_ALIAS},
844 {"system-configuration-file", OPTION_CFG_SYSTEM, "FILE", 0,
845 "Read system wide configuration from file. Default is " SYSTEMCFGFILE
846 "."},
848 {"configuration-file", OPTION_CFG_USER, "FILE", 0,
849 "Read user configuration from file. Default is ~/.shishi/config."},
851 {"library-options", 'o', "STRING", 0,
852 "Parse STRING as a configuration file statement."},
854 {"ticket-file", 'c', "FILE", 0,
855 "Read tickets from FILE. Default is $HOME/.shishi/tickets."},
857 {"ticket-write-file", OPTION_WRITE_TICKET_FILE, "FILE", 0,
858 "Write tickets to FILE. Default is to write them back to ticket file."},
860 {"NAME", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
861 "Set client name and realm from NAME. The --client-name and --realm can "
862 "be used to override part of NAME."},
864 /************** EXAMPLES */
866 {0, 0, 0, 0, "Examples:", 300},
868 {"shishi", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
869 "Get a ticket granting ticket from the default KDC server for the "
870 "default user and realm."},
872 {"shishi jas/admin@ACCOUNTING", 0, 0, OPTION_DOC | OPTION_NO_USAGE,
873 "Get a ticket for jas/admin in the ACCOUNTING realm."},
875 {"shishi --list --server-name=krbtgt/JOSEFSSON.ORG@JOSEFSSON.ORG",
876 0, 0, OPTION_DOC | OPTION_NO_USAGE,
877 "List tickets for the Ticket Granting Service in the JOSEFSSON.ORG realm."},
882 static struct argp argp = {
883 options,
884 parse_opt,
885 "[NAME] [OPTION...]\n"
886 "--list [--server-name=NAME]\n"
887 "--destroy [--server-name=NAME]\n"
888 "--crypto [CRYPTO-OPTION...]\n",
889 "Shishi -- A Kerberos 5 implementation"
893 main (int argc, char *argv[])
895 struct arguments arg;
896 Shishi *handle;
897 int rc;
899 setlocale (LC_ALL, "");
900 bindtextdomain (PACKAGE, LOCALEDIR);
901 textdomain (PACKAGE);
903 memset (&arg, 0, sizeof (arg));
904 argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &arg);
906 rc = shishi_init_with_paths (&handle, arg.ticketfile,
907 arg.systemcfgfile, arg.usercfgfile);
908 if (rc == SHISHI_HANDLE_ERROR)
909 error (1, 0, "Internal error: could not initialize shishi\n");
911 rc = shishi_cfg_clientkdcetype_set (handle, arg.etypes);
912 if (rc != SHISHI_OK)
913 error (1, 0, "Could not set encryption types: %s\n", shishi_strerror (rc));
915 if (arg.client)
917 rc = shishi_parse_name (handle, arg.client,
918 (char **) (arg.cname ? NULL : &arg.cname),
919 (char **) (arg.realm ? NULL : &arg.realm));
921 if (rc != SHISHI_OK)
922 error (1, 0, "Could not parse principal \"%s\": %s\n", arg.client,
923 shishi_strerror (rc));
926 rc = shishi_cfg (handle, arg.lib_options);
927 if (rc != SHISHI_OK)
928 error (1, 0, "Could not read library options: %s\n", shishi_strerror (rc));
930 if (arg.verbose_library)
932 rc = shishi_cfg (handle, "verbose");
933 if (rc != SHISHI_OK)
934 error (1, 0, "Could not make library verbose: %s\n",
935 shishi_strerror (rc));
938 if (!arg.starttime)
939 arg.starttime = time(NULL);
941 if (arg.endtime_str)
943 arg.endtime = get_date (arg.endtime_str, &arg.starttime);
944 if (arg.endtime == -1)
945 error (1, 0, _("invalid --endtime date `%s'"), arg.endtime_str);
948 if (arg.renew_till_str)
950 arg.renew_till = get_date (arg.renew_till_str, &arg.starttime);
951 if (arg.renew_till == -1)
952 error (1, 0, _("invalid --renew-till date `%s'"), arg.renew_till_str);
955 if (arg.cname)
956 shishi_principal_default_set (handle, arg.cname);
958 if (arg.realm)
959 shishi_realm_default_set (handle, arg.realm);
961 if (!arg.tgtname)
963 asprintf (&arg.tgtname, "krbtgt/%s", shishi_realm_default (handle));
964 if (arg.tgtname == NULL)
965 error (1, 0, "Could not allocate TGT name.");
968 rc = 1;
970 switch (arg.command)
972 case OPTION_LIST:
973 if (!arg.silent)
974 printf (_("Tickets in `%s':\n"), shishi_tkts_default_file (handle));
976 rc = shishi_tkts_print_for_service (shishi_tkts_default (handle),
977 stdout, arg.sname);
978 if (rc != SHISHI_OK)
979 fprintf (stderr, "Could not list tickets: %s", shishi_strerror (rc));
980 break;
982 case OPTION_DESTROY:
984 int i, removed = 0;
985 for (i = 0; i < shishi_tkts_size (shishi_tkts_default (handle)); i++)
987 if (arg.sname &&
988 !shishi_tkt_server_p (shishi_tkts_nth
989 (shishi_tkts_default (handle),
990 i), arg.sname))
991 continue;
993 if (arg.verbose)
995 printf ("Removing ticket:\n");
996 shishi_tkt_pretty_print (shishi_tkts_nth
997 (shishi_tkts_default
998 (handle), i), stdout);
1001 rc = shishi_tkts_remove (shishi_tkts_default (handle), i);
1002 if (rc != SHISHI_OK)
1003 fprintf (stderr, "Could not destroy ticket %d:\n%s\n", i,
1004 shishi_strerror (rc));
1005 i--;
1006 removed++;
1008 if (removed == 0)
1009 printf ("No tickets removed.\n");
1010 else if (removed == 1)
1011 printf ("1 ticket removed.\n");
1012 else
1013 printf ("%d tickets removed.\n", removed);
1014 rc = SHISHI_OK;
1016 break;
1018 case OPTION_CRYPTO:
1019 rc = crypto (handle, arg);
1020 if (rc != SHISHI_OK)
1021 fprintf (stderr, "Operation failed:\n%s\n%s\n",
1022 shishi_strerror (rc), shishi_strerror_details (handle));
1023 break;
1025 default:
1027 Shishi_tkt *tkt;
1028 Shishi_tkts_hint hint;
1030 memset (&hint, 0, sizeof (hint));
1031 hint.client = (char *) arg.cname;
1032 hint.server = (char *) (arg.sname ? arg.sname : arg.tgtname);
1033 hint.starttime = arg.starttime;
1034 hint.starttime = arg.endtime;
1035 hint.renew_till = arg.renew_till;
1036 hint.renewable = arg.renewable;
1038 tkt = shishi_tkts_get (shishi_tkts_default (handle), &hint);
1039 if (!tkt)
1041 printf ("Could not get ticket for `%s'.\n",
1042 arg.tgtname ? arg.tgtname : arg.cname);
1043 rc = !SHISHI_OK;
1045 else
1047 rc = shishi_tkt_pretty_print (tkt, stdout);
1048 if (rc != SHISHI_OK)
1049 fprintf (stderr, "Pretty printing ticket failed:\n%s\n%s\n",
1050 shishi_strerror (rc), shishi_strerror_details (handle));
1053 break;
1056 shishi_tkts_expire (shishi_tkts_default (handle));
1058 if (arg.ticketwritefile)
1059 shishi_tkts_default_file_set (handle, arg.ticketwritefile);
1061 shishi_done (handle);
1063 return rc == SHISHI_OK ? 0 : 1;