1 /* shisa.c --- Command line interface to Shishi database.
2 * Copyright (C) 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
36 # define setlocale(Category, Locale) /* empty */
39 #define _(String) gettext (String)
40 #define gettext_noop(String) String
41 #define N_(String) gettext_noop (String)
44 #include "xvasprintf.h"
46 /* Get xgethostname. */
47 #include "xgethostname.h"
49 /* Get set_program_name and program_name. */
55 /* Shishi and Shisa library. */
59 /* Command line parameter parser via gengetopt. */
60 #include "shisa_cmd.h"
62 /* Global variables. */
65 struct gengetopt_args_info args
;
68 printfield (const char *fieldname
, const char *value
)
70 printf ("\t\t%s %s.\n", fieldname
, value
);
74 printtimefield (const char *fieldname
, time_t t
)
77 p
[strlen (p
) - 1] = '\0';
78 printfield (fieldname
, t
== (time_t) - 1 ? "N/A" : p
);
82 printintfield (const char *fieldname
, int num
)
84 char *p
= xasprintf ("%d (0x%x)", num
, num
);
85 printfield (fieldname
, p
);
90 printuint32field (const char *fieldname
, uint32_t num
)
92 char *p
= xasprintf ("%d (0x%x)", num
, num
);
93 printfield (fieldname
, p
);
98 print3field (const char *fieldname
, const char *text
, uint32_t num
)
100 char *p
= xasprintf ("%s (0x%x, %d)", text
, num
, num
);
101 printfield (fieldname
, p
);
106 printdbkey (const char *realm
, const char *principal
, Shisa_key
* dbkey
)
111 rc
= shishi_key_from_value (sh
, dbkey
->etype
, dbkey
->key
, &key
);
114 shishi_key_realm_set (key
, realm
);
115 shishi_key_principal_set (key
, principal
);
116 shishi_key_print (sh
, stdout
, key
);
119 error (0, 0, "shishi_key_from_value (%d):\n%s",
120 rc
, shishi_strerror (rc
));
124 dumplist_realm_principal (const char *realm
, const char *principal
)
129 if (args
.dump_given
|| args
.enabled_flag
|| args
.disabled_flag
)
131 rc
= shisa_principal_find (dbh
, realm
, principal
, &ph
);
134 error (0, 0, "shishi_principal_find (%d):\n%s",
135 rc
, shisa_strerror (rc
));
139 if (args
.enabled_flag
&& ph
.isdisabled
)
142 if (args
.disabled_flag
&& !ph
.isdisabled
)
146 printf ("\t%s\n", principal
);
154 printfield (_("Account is"),
155 ph
.isdisabled
? _("DISABLED") : _("enabled"));
156 printuint32field (_("Current key version"), ph
.kvno
);
157 if (ph
.notusedbefore
!= (time_t) - 1)
158 printtimefield (_("Account not valid before"), ph
.notusedbefore
);
159 if (ph
.lastinitialtgt
!= (time_t) - 1)
160 printtimefield (_("Last initial TGT request at"), ph
.lastinitialtgt
);
161 if (ph
.lastinitialrequest
!= (time_t) - 1)
162 printtimefield (_("Last initial request at"), ph
.lastinitialrequest
);
163 if (ph
.lasttgt
!= (time_t) - 1)
164 printtimefield (_("Last TGT request at"), ph
.lasttgt
);
165 if (ph
.lastrenewal
!= (time_t) - 1)
166 printtimefield (_("Last ticket renewal at"), ph
.lastrenewal
);
167 if (ph
.passwordexpire
!= (time_t) - 1)
168 printtimefield (_("Password expire on"), ph
.passwordexpire
);
169 if (ph
.accountexpire
!= (time_t) - 1)
170 printtimefield (_("Account expire on"), ph
.accountexpire
);
172 rc
= shisa_keys_find (dbh
, realm
, principal
, NULL
, &keys
, &nkeys
);
175 error (0, 0, "shishi_keys_find(%s, %s) (%d):\n%s",
176 realm
, principal
, rc
, shisa_strerror (rc
));
180 for (i
= 0; i
< nkeys
; i
++)
183 printintfield (_("Key"), i
);
185 print3field (_("\tEtype"), shishi_cipher_name (keys
[i
]->etype
),
187 if (keys
[i
]->priority
> 0)
188 printintfield (_("\tPriority"), keys
[i
]->priority
);
190 printdbkey (realm
, principal
, keys
[i
]);
191 if (keys
[i
]->saltlen
> 0)
192 printfield (_("\tSalt"), keys
[i
]->salt
);
193 if (keys
[i
]->str2keyparamlen
> 0)
194 printfield (_("\tS2K params"), keys
[i
]->str2keyparam
);
196 if (keys
[i
]->password
)
197 printfield (_("\tPassword"), keys
[i
]->password
);
200 printfield (_("\tKey is"), _("MISSING"));
202 shisa_keys_free (dbh
, keys
, nkeys
);
209 dumplist_realm (const char *realm
)
216 printf ("%s\n", realm
);
218 rc
= shisa_enumerate_principals (dbh
, realm
, &principals
, &nprincipals
);
222 for (i
= 0; i
< nprincipals
; i
++)
225 rc
= dumplist_realm_principal (realm
, principals
[i
]);
226 free (principals
[i
]);
239 if (args
.inputs_num
== 1)
240 rc
= dumplist_realm (args
.inputs
[0]);
241 else if (args
.inputs_num
== 2)
243 char *realm
= args
.inputs
[0];
244 char *principal
= args
.inputs
[1];
245 printf ("%s\n", realm
);
246 rc
= dumplist_realm_principal (realm
, principal
);
254 rc
= shisa_enumerate_realms (dbh
, &realms
, &nrealms
);
258 for (i
= 0; i
< nrealms
; i
++)
261 rc
= dumplist_realm (realms
[i
]);
272 add (const char *realm
, const char *principal
,
273 Shisa_principal
* ph
, Shisa_key
* key
)
277 if (principal
== NULL
)
278 printf (_("Adding realm `%s'...\n"), realm
);
280 printf (_("Adding principal `%s@%s'...\n"), principal
, realm
);
282 rc
= shisa_principal_add (dbh
, realm
, principal
, ph
, key
);
284 error (EXIT_FAILURE
, 0, "shisa_principal_add (%d):\n%s",
285 rc
, shisa_strerror (rc
));
288 printdbkey (realm
, principal
, key
);
290 if (principal
== NULL
)
291 printf (_("Adding realm `%s'...done\n"), realm
);
293 printf (_("Adding principal `%s@%s'...done\n"), principal
, realm
);
297 delete (const char *realm
, const char *principal
)
301 if (principal
== NULL
&& args
.force_flag
)
307 rc
= shisa_enumerate_principals (dbh
, realm
, &principals
, &nprincipals
);
309 error (EXIT_FAILURE
, 0, "shisa_enumerate_principals (%d):\n%s",
310 rc
, shisa_strerror (rc
));
312 for (i
= 0; i
< nprincipals
; i
++)
315 delete (realm
, principals
[i
]);
316 free (principals
[i
]);
323 if (principal
== NULL
)
324 printf (_("Removing realm `%s'...\n"), realm
);
326 printf (_("Removing principal `%s@%s'...\n"), principal
, realm
);
328 rc
= shisa_principal_remove (dbh
, realm
, principal
);
330 error (EXIT_FAILURE
, 0, "shisa_principal_remove (%d):\n%s",
331 rc
, shisa_strerror (rc
));
333 if (principal
== NULL
)
334 printf (_("Removing realm `%s'...done\n"), realm
);
336 printf (_("Removing principal `%s@%s'...done\n"), principal
, realm
);
340 apply_options (const char *realm
,
341 const char *principal
, Shisa_principal
* ph
, Shisa_key
* dbkey
)
343 char *passwd
= args
.password_arg
;
344 char *salt
= args
.salt_arg
;
345 char *str2keyparam
= NULL
;
346 size_t str2keyparamlen
= 0;
353 if (args
.key_version_given
)
354 ph
->kvno
= args
.key_version_arg
;
359 etype
= shishi_cfg_clientkdcetype_fast (sh
);
361 if (!salt
&& realm
&& principal
)
363 char *name
= xasprintf ("%s@%s", principal
, realm
);
365 rc
= shishi_derive_default_salt (sh
, name
, &salt
);
368 error (EXIT_FAILURE
, 0, "shisa_derive_default_salt (%d):\n%s",
369 rc
, shisa_strerror (rc
));
372 if (args
.string_to_key_parameter_given
)
377 if (args
.password_given
)
381 if (realm
&& principal
)
382 rc
= shishi_prompt_password (sh
, &passwd
,
383 _("Password for `%s@%s': "),
386 rc
= shishi_prompt_password (sh
, &passwd
, _("Password: "));
388 error (EXIT_FAILURE
, 0, _("Could not read password"));
391 rc
= shishi_key_from_string (sh
, etype
,
392 passwd
, strlen (passwd
),
393 salt
, salt
? strlen (salt
) : 0,
397 rc
= shishi_key_random (sh
, etype
, &key
);
400 error (EXIT_FAILURE
, 0, _("Could not create key (%d):\n%s"),
401 rc
, shishi_strerror (rc
));
403 if (realm
&& principal
)
405 shishi_key_realm_set (key
, realm
);
406 shishi_key_principal_set (key
, principal
);
409 dbkey
->kvno
= args
.key_version_arg
;
410 dbkey
->etype
= etype
;
411 dbkey
->priority
= args
.priority_arg
;
412 dbkey
->key
= shishi_key_value (key
);
413 dbkey
->keylen
= shishi_key_length (key
);
415 dbkey
->saltlen
= salt
? strlen (salt
) : 0;
416 dbkey
->str2keyparam
= str2keyparam
;
417 dbkey
->str2keyparamlen
= str2keyparamlen
;
418 dbkey
->password
= passwd
;
423 main (int argc
, char *argv
[])
425 const char *realm
= NULL
;
426 const char *principal
= NULL
;
431 setlocale (LC_ALL
, "");
432 bindtextdomain (PACKAGE
, LOCALEDIR
);
433 textdomain (PACKAGE
);
434 set_program_name (argv
[0]);
436 if (cmdline_parser (argc
, argv
, &args
) != 0)
437 error (EXIT_FAILURE
, 0, _("Try `%s --help' for more information."),
440 rc
= args
.add_given
+ args
.dump_given
+ args
.list_given
+
441 args
.modify_given
+ args
.remove_given
+
442 args
.key_add_given
+ args
.key_remove_given
;
444 if (rc
> 1 || args
.inputs_num
> 2)
446 error (0, 0, _("too many arguments"));
447 error (EXIT_FAILURE
, 0, _("Try `%s --help' for more information."),
451 if (rc
== 0 || args
.help_given
)
453 cmdline_parser_print_help ();
454 printf (_("\nMandatory arguments to long options are "
455 "mandatory for short options too.\n\n"));
456 printf (_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
460 rc
= shisa_init_with_paths (&dbh
, args
.configuration_file_arg
);
462 error (EXIT_FAILURE
, 0, _("Initialization failed:\n%s"),
463 shisa_strerror (rc
));
465 rc
= shisa_cfg (dbh
, args
.library_options_arg
);
467 error (EXIT_FAILURE
, 0, _("Could not read library options `%s':\n%s"),
468 args
.library_options_arg
, shisa_strerror (rc
));
470 rc
= shishi_init (&sh
);
472 error (EXIT_FAILURE
, 0, _("Shishi initialization failed:\n%s"),
473 shishi_strerror (rc
));
475 rc
= shishi_cfg_clientkdcetype_set (sh
, args
.encryption_type_arg
);
477 error (EXIT_FAILURE
, 0, _("Could not set encryption type `%s':\n%s"),
478 args
.encryption_type_arg
, shishi_strerror (rc
));
480 if ((args
.inputs_num
< 2 && (args
.modify_given
||
481 args
.key_add_given
||
482 args
.key_remove_given
)) ||
483 (args
.inputs_num
< 1 && (args
.remove_given
)))
485 error (0, 0, _("too few arguments"));
486 error (0, 0, _("Try `%s --help' for more information."), program_name
);
490 if (args
.inputs_num
> 0)
491 realm
= args
.inputs
[0];
492 if (args
.inputs_num
> 1)
493 principal
= args
.inputs
[1];
495 memset (&ph
, 0, sizeof (ph
));
496 memset (&key
, 0, sizeof (key
));
497 apply_options (realm
, principal
, &ph
, &key
);
499 if (args
.list_given
|| args
.dump_given
)
501 else if (args
.remove_given
)
502 delete (realm
, principal
);
503 else if (args
.add_given
&& (args
.inputs_num
== 1 || args
.inputs_num
== 2))
504 add (realm
, principal
, &ph
, &key
);
505 else if (args
.add_given
)
511 /* This is mostly meant for 'make install', as it set up the
512 default realm, and write a host key to stdout, which can be
513 redirected into $prefix/etc/shishi/shishi.keys. */
515 realm
= shishi_realm_default (sh
);
517 printf (_("Adding default realm `%s'...\n"), realm
);
518 add (realm
, NULL
, NULL
, NULL
);
520 tmp
= xasprintf ("krbtgt/%s", realm
);
521 add (realm
, tmp
, &ph
, &key
);
524 host
= xgethostname ();
525 tmp
= xasprintf ("host/%s", host
);
528 memset (&key2
, 0, sizeof (key2
));
529 apply_options (realm
, tmp
, NULL
, &key2
);
532 add (realm
, tmp
, &ph
, &key2
);
535 else if (args
.modify_given
)
537 printf (_("Modifying principal `%s@%s'...\n"), principal
, realm
);
539 rc
= shisa_principal_update (dbh
, realm
, principal
, &ph
);
541 error (EXIT_FAILURE
, 0, "shisa_principal_update (%d):\n%s",
542 rc
, shisa_strerror (rc
));
544 printf (_("Modifying principal `%s@%s'...done\n"), principal
, realm
);
546 else if (args
.key_add_given
)
548 printf (_("Adding key to `%s@%s'...\n"), principal
, realm
);
550 rc
= shisa_key_add (dbh
, realm
, principal
, &key
);
552 error (EXIT_FAILURE
, 0, "shisa_key_add (%d):\n%s",
553 rc
, shisa_strerror (rc
));
556 printdbkey (realm
, principal
, &key
);
558 printf (_("Adding key to `%s@%s'...done\n"), principal
, realm
);
560 else if (args
.key_remove_given
)
562 printf (_("Removing key from `%s@%s'...\n"), principal
, realm
);
564 if (!args
.password_given
)
570 rc
= shisa_key_remove (dbh
, realm
, principal
, &key
);
572 error (EXIT_FAILURE
, 0, "shisa_key_remove (%d):\n%s",
573 rc
, shisa_strerror (rc
));
575 printf (_("Removing key from `%s@%s'...done\n"), principal
, realm
);