16656Ssemery /*
26656Ssemery * CDDL HEADER START
36656Ssemery *
46656Ssemery * The contents of this file are subject to the terms of the
56656Ssemery * Common Development and Distribution License (the "License").
66656Ssemery * You may not use this file except in compliance with the License.
76656Ssemery *
86656Ssemery * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96656Ssemery * or http://www.opensolaris.org/os/licensing.
106656Ssemery * See the License for the specific language governing permissions
116656Ssemery * and limitations under the License.
126656Ssemery *
136656Ssemery * When distributing Covered Code, include this CDDL HEADER in each
146656Ssemery * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156656Ssemery * If applicable, add the following below this CDDL HEADER, with the
166656Ssemery * fields enclosed by brackets "[]" replaced with your own identifying
176656Ssemery * information: Portions Copyright [yyyy] [name of copyright owner]
186656Ssemery *
196656Ssemery * CDDL HEADER END
206656Ssemery */
216656Ssemery
226656Ssemery /*
239833SShawn.Emery@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
246656Ssemery * Use is subject to license terms.
256656Ssemery */
266656Ssemery
276656Ssemery #include <stdio.h>
286656Ssemery #include <stdlib.h>
296656Ssemery #include <strings.h>
306656Ssemery #include <locale.h>
316656Ssemery #include <netdb.h>
326656Ssemery #include "k5-int.h"
336656Ssemery
346656Ssemery #define QUOTE(x) #x
356656Ssemery #define VAL2STR(x) QUOTE(x)
366656Ssemery
376656Ssemery static char *whoami = NULL;
386656Ssemery
396656Ssemery static void kt_add_entry(krb5_context ctx, krb5_keytab kt,
409833SShawn.Emery@Sun.COM const krb5_principal princ, const krb5_principal sprinc,
419833SShawn.Emery@Sun.COM krb5_enctype enctype, krb5_kvno kvno, const char *pw);
426656Ssemery
436656Ssemery static krb5_error_code kt_remove_entries(krb5_context ctx, krb5_keytab kt,
446656Ssemery const krb5_principal princ);
456656Ssemery
466656Ssemery static void usage();
476656Ssemery
486656Ssemery int
main(int argc,char ** argv)496656Ssemery main(int argc, char **argv)
506656Ssemery {
516656Ssemery krb5_context ctx = NULL;
526656Ssemery krb5_error_code code = 0;
536656Ssemery krb5_enctype *enctypes;
546656Ssemery int enctype_count = 0;
556656Ssemery krb5_ccache cc = NULL;
566656Ssemery krb5_keytab kt = NULL;
576656Ssemery krb5_kvno kvno = 1;
589833SShawn.Emery@Sun.COM krb5_principal victim, salt;
596656Ssemery char c, *vprincstr, *ktname, *token, *lasts, *newpw;
606656Ssemery int result_code, i, len, nflag = 0;
616656Ssemery krb5_data result_code_string, result_string;
626656Ssemery
636656Ssemery (void) setlocale(LC_ALL, "");
646656Ssemery
656656Ssemery #if !defined(TEXT_DOMAIN)
666656Ssemery #define TEXT_DOMAIN "SYS_TEST"
676656Ssemery #endif /* TEXT_DOMAIN */
686656Ssemery
696656Ssemery (void) textdomain(TEXT_DOMAIN);
706656Ssemery
716656Ssemery /* Misc init stuff */
726656Ssemery (void) memset(&result_code_string, 0, sizeof (result_code_string));
736656Ssemery (void) memset(&result_string, 0, sizeof (result_string));
746656Ssemery
756656Ssemery whoami = argv[0];
766656Ssemery
776656Ssemery code = krb5_init_context(&ctx);
786656Ssemery if (code != 0) {
796656Ssemery com_err(whoami, code, gettext("krb5_init_context() failed"));
806656Ssemery exit(1);
816656Ssemery }
826656Ssemery
839833SShawn.Emery@Sun.COM while ((c = getopt(argc, argv, "v:c:k:e:ns:")) != -1) {
846656Ssemery switch (c) {
856656Ssemery case 'n':
866656Ssemery nflag++;
876656Ssemery break;
886656Ssemery case 'k':
896656Ssemery if (kt != NULL)
906656Ssemery usage();
916656Ssemery len = snprintf(NULL, 0, "WRFILE:%s", optarg) + 1;
926656Ssemery if ((ktname = malloc(len)) == NULL) {
936656Ssemery (void) fprintf(stderr,
946656Ssemery gettext("Couldn't allocate memory\n"));
956656Ssemery exit(1);
966656Ssemery }
976656Ssemery (void) snprintf(ktname, len, "WRFILE:%s", optarg);
986656Ssemery if ((code = krb5_kt_resolve(ctx, ktname, &kt)) != 0) {
996656Ssemery com_err(whoami, code,
1006656Ssemery gettext("Couldn't open/create "
1016656Ssemery "keytab %s"), optarg);
1026656Ssemery exit(1);
1036656Ssemery }
1046656Ssemery break;
1056656Ssemery case 'c':
1066656Ssemery if (cc != NULL)
1076656Ssemery usage();
1086656Ssemery if ((code = krb5_cc_resolve(ctx, optarg, &cc)) != 0) {
1096656Ssemery com_err(whoami, code,
1106656Ssemery gettext("Couldn't open ccache %s"), optarg);
1116656Ssemery exit(1);
1126656Ssemery }
1136656Ssemery break;
1146656Ssemery case 'e':
1156656Ssemery len = strlen(optarg);
1166656Ssemery token = strtok_r(optarg, ",\t,", &lasts);
1176656Ssemery
1186656Ssemery if (token == NULL)
1196656Ssemery usage();
1206656Ssemery
1216656Ssemery do {
1226656Ssemery if (enctype_count++ == 0) {
1236656Ssemery enctypes = malloc(sizeof (*enctypes));
1246656Ssemery } else {
1256656Ssemery enctypes = realloc(enctypes,
1266656Ssemery sizeof (*enctypes) * enctype_count);
1276656Ssemery }
1286656Ssemery if (enctypes == NULL) {
1296656Ssemery (void) fprintf(stderr, gettext
1306656Ssemery ("Couldn't allocate memory"));
1316656Ssemery exit(1);
1326656Ssemery }
1336656Ssemery code = krb5_string_to_enctype(token,
1346656Ssemery &enctypes[enctype_count - 1]);
1356656Ssemery
1366656Ssemery if (code != 0) {
1376656Ssemery com_err(whoami, code, gettext("Unknown "
1386656Ssemery "or unsupported enctype %s"),
1396656Ssemery optarg);
1406656Ssemery exit(1);
1416656Ssemery }
1426656Ssemery } while ((token = strtok_r(NULL, ",\t ", &lasts)) !=
1436656Ssemery NULL);
1446656Ssemery break;
1456656Ssemery case 'v':
1466656Ssemery kvno = (krb5_kvno) atoi(optarg);
1476656Ssemery break;
1489833SShawn.Emery@Sun.COM case 's':
1499833SShawn.Emery@Sun.COM vprincstr = optarg;
1509833SShawn.Emery@Sun.COM code = krb5_parse_name(ctx, vprincstr, &salt);
1519833SShawn.Emery@Sun.COM if (code != 0) {
1529833SShawn.Emery@Sun.COM com_err(whoami, code,
1539833SShawn.Emery@Sun.COM gettext("krb5_parse_name(%s) failed"),
1549833SShawn.Emery@Sun.COM vprincstr);
1559833SShawn.Emery@Sun.COM exit(1);
1569833SShawn.Emery@Sun.COM }
1579833SShawn.Emery@Sun.COM break;
1586656Ssemery default:
1596656Ssemery usage();
1606656Ssemery break;
1616656Ssemery }
1626656Ssemery }
1636656Ssemery
1646656Ssemery if (nflag && enctype_count == 0)
1656656Ssemery usage();
1666656Ssemery
1676656Ssemery if (nflag == 0 && cc == NULL &&
1686656Ssemery (code = krb5_cc_default(ctx, &cc)) != 0) {
1696656Ssemery com_err(whoami, code, gettext("Could not find a ccache"));
1706656Ssemery exit(1);
1716656Ssemery }
1726656Ssemery
1736656Ssemery if (enctype_count > 0 && kt == NULL &&
1746656Ssemery (code = krb5_kt_default(ctx, &kt)) != 0) {
1756656Ssemery com_err(whoami, code, gettext("No keytab specified"));
1766656Ssemery exit(1);
1776656Ssemery }
1786656Ssemery
1796656Ssemery if (argc != (optind + 1))
1806656Ssemery usage();
1816656Ssemery
1826656Ssemery vprincstr = argv[optind];
1836656Ssemery code = krb5_parse_name(ctx, vprincstr, &victim);
1846656Ssemery if (code != 0) {
1856656Ssemery com_err(whoami, code, gettext("krb5_parse_name(%s) failed"),
1866656Ssemery vprincstr);
1876656Ssemery exit(1);
1886656Ssemery }
1896656Ssemery
1906656Ssemery if (!isatty(fileno(stdin))) {
1916656Ssemery char buf[PASS_MAX + 1];
1926656Ssemery
1936656Ssemery if (scanf("%" VAL2STR(PASS_MAX) "s", &buf) != 1) {
1946656Ssemery (void) fprintf(stderr,
1956656Ssemery gettext("Couldn't read new password\n"));
1966656Ssemery exit(1);
1976656Ssemery }
1986656Ssemery
1996656Ssemery newpw = strdup(buf);
2006656Ssemery if (newpw == NULL) {
2016656Ssemery (void) fprintf(stderr,
2026656Ssemery gettext("Couldn't allocate memory\n"));
2036656Ssemery exit(1);
2046656Ssemery }
2056656Ssemery } else {
2066656Ssemery newpw = getpassphrase(gettext("Enter new password: "));
2076656Ssemery if (newpw == NULL) {
2086656Ssemery (void) fprintf(stderr,
2096656Ssemery gettext("Couldn't read new password\n"));
2106656Ssemery exit(1);
2116656Ssemery }
2126656Ssemery
2136656Ssemery newpw = strdup(newpw);
2146656Ssemery if (newpw == NULL) {
2156656Ssemery (void) fprintf(stderr,
2166656Ssemery gettext("Couldn't allocate memory\n"));
2176656Ssemery exit(1);
2186656Ssemery }
2196656Ssemery }
2206656Ssemery
2216656Ssemery if (nflag == 0) {
2226656Ssemery code = krb5_set_password_using_ccache(ctx, cc, newpw, victim,
2236656Ssemery &result_code, &result_code_string, &result_string);
2246656Ssemery if (code != 0) {
2256656Ssemery com_err(whoami, code,
2266656Ssemery gettext("krb5_set_password() failed"));
2276656Ssemery exit(1);
2286656Ssemery }
2296656Ssemery krb5_cc_close(ctx, cc);
2306656Ssemery
2316656Ssemery (void) printf("Result: %.*s (%d) %.*s\n",
2326656Ssemery result_code == 0 ?
2336656Ssemery strlen("success") : result_code_string.length,
2346656Ssemery result_code == 0 ? "success" : result_code_string.data,
2356656Ssemery result_code,
2366656Ssemery result_string.length, result_string.data);
2376656Ssemery
2386656Ssemery if (result_code != 0) {
2396656Ssemery (void) fprintf(stderr, gettext("Exiting...\n"));
2406656Ssemery exit(result_code);
2416656Ssemery }
2426656Ssemery }
2436656Ssemery
2446656Ssemery if (enctype_count && (code = kt_remove_entries(ctx, kt, victim)))
2456656Ssemery goto error;
2466656Ssemery
2476656Ssemery for (i = 0; i < enctype_count; i++)
2489833SShawn.Emery@Sun.COM kt_add_entry(ctx, kt, victim, salt, enctypes[i], kvno, newpw);
2496656Ssemery
2506656Ssemery error:
2516656Ssemery if (kt != NULL)
2526656Ssemery krb5_kt_close(ctx, kt);
2536656Ssemery
2546656Ssemery return (code ? 1 : 0);
2556656Ssemery }
2566656Ssemery
2576656Ssemery static
2586656Ssemery krb5_error_code
kt_remove_entries(krb5_context ctx,krb5_keytab kt,const krb5_principal princ)2596656Ssemery kt_remove_entries(krb5_context ctx, krb5_keytab kt, const krb5_principal princ)
2606656Ssemery {
2616656Ssemery krb5_error_code code;
2626656Ssemery krb5_kt_cursor cursor;
2636656Ssemery krb5_keytab_entry entry;
2646656Ssemery
2656656Ssemery /*
2666656Ssemery * This is not a fatal error, we expect this to fail in the majority
2676656Ssemery * of cases (when clients are first initialized).
2686656Ssemery */
2696656Ssemery code = krb5_kt_get_entry(ctx, kt, princ, 0, 0, &entry);
2706656Ssemery if (code != 0) {
2716656Ssemery com_err(whoami, code,
2726656Ssemery gettext("Could not retrieve entry in keytab"));
2736656Ssemery return (0);
2746656Ssemery }
2756656Ssemery
2766656Ssemery krb5_kt_free_entry(ctx, &entry);
2776656Ssemery
2786656Ssemery code = krb5_kt_start_seq_get(ctx, kt, &cursor);
2796656Ssemery if (code != 0) {
2806656Ssemery com_err(whoami, code, gettext("While starting keytab scan"));
2816656Ssemery return (code);
2826656Ssemery }
2836656Ssemery
2846656Ssemery while ((code = krb5_kt_next_entry(ctx, kt, &entry, &cursor)) == 0) {
2856656Ssemery if (krb5_principal_compare(ctx, princ, entry.principal)) {
2866656Ssemery
2876656Ssemery code = krb5_kt_end_seq_get(ctx, kt, &cursor);
2886656Ssemery if (code != 0) {
2896656Ssemery com_err(whoami, code,
2906656Ssemery gettext("While temporarily "
2916656Ssemery "ending keytab scan"));
2926656Ssemery return (code);
2936656Ssemery }
2946656Ssemery
2956656Ssemery code = krb5_kt_remove_entry(ctx, kt, &entry);
2966656Ssemery if (code != 0) {
2976656Ssemery com_err(whoami, code,
2986656Ssemery gettext("While deleting entry "
2996656Ssemery "from keytab"));
3006656Ssemery return (code);
3016656Ssemery }
3026656Ssemery
3036656Ssemery code = krb5_kt_start_seq_get(ctx, kt, &cursor);
3046656Ssemery if (code != 0) {
3056656Ssemery com_err(whoami, code,
3066656Ssemery gettext("While restarting keytab scan"));
3076656Ssemery return (code);
3086656Ssemery }
3096656Ssemery }
3106656Ssemery
3116656Ssemery krb5_kt_free_entry(ctx, &entry);
3126656Ssemery }
3136656Ssemery
3146656Ssemery if (code && code != KRB5_KT_END) {
3156656Ssemery com_err(whoami, code, gettext("While scanning keytab"));
3166656Ssemery return (code);
3176656Ssemery }
3186656Ssemery
3196656Ssemery if ((code = krb5_kt_end_seq_get(ctx, kt, &cursor))) {
3206656Ssemery com_err(whoami, code, gettext("While ending keytab scan"));
3216656Ssemery return (code);
3226656Ssemery }
3236656Ssemery
3246656Ssemery return (0);
3256656Ssemery }
3266656Ssemery
3276656Ssemery static
3286656Ssemery void
kt_add_entry(krb5_context ctx,krb5_keytab kt,const krb5_principal princ,const krb5_principal sprinc,krb5_enctype enctype,krb5_kvno kvno,const char * pw)3296656Ssemery kt_add_entry(krb5_context ctx, krb5_keytab kt, const krb5_principal princ,
3309833SShawn.Emery@Sun.COM const krb5_principal sprinc, krb5_enctype enctype, krb5_kvno kvno,
3319833SShawn.Emery@Sun.COM const char *pw)
3326656Ssemery {
3336656Ssemery krb5_keytab_entry *entry;
3346656Ssemery krb5_data password, salt;
3356656Ssemery krb5_keyblock key;
3366656Ssemery krb5_error_code code;
3376656Ssemery char buf[100];
3386656Ssemery
3396656Ssemery if ((code = krb5_enctype_to_string(enctype, buf, sizeof (buf)))) {
3406656Ssemery com_err(whoami, code, gettext("Enctype %d has no name!"),
3416656Ssemery enctype);
3426656Ssemery return;
3436656Ssemery }
3446656Ssemery if ((entry = (krb5_keytab_entry *) malloc(sizeof (*entry))) == NULL) {
3456656Ssemery (void) fprintf(stderr, gettext("Couldn't allocate memory"));
3466656Ssemery return;
3476656Ssemery }
3486656Ssemery
3496656Ssemery (void) memset((char *)entry, 0, sizeof (*entry));
3506656Ssemery
3516656Ssemery password.length = strlen(pw);
3526656Ssemery password.data = (char *)pw;
3536656Ssemery
3549833SShawn.Emery@Sun.COM if ((code = krb5_principal2salt(ctx, sprinc, &salt)) != 0) {
3556656Ssemery com_err(whoami, code,
3566656Ssemery gettext("Could not compute salt for %s"), enctype);
3576656Ssemery return;
3586656Ssemery }
3596656Ssemery
3606656Ssemery code = krb5_c_string_to_key(ctx, enctype, &password, &salt, &key);
3616656Ssemery
3626656Ssemery if (code != 0) {
3636656Ssemery com_err(whoami, code, gettext("Could not compute salt for %s"),
3646656Ssemery enctype);
3656656Ssemery krb5_xfree(salt.data);
3666656Ssemery return;
3676656Ssemery }
3686656Ssemery
3696656Ssemery (void) memcpy(&entry->key, &key, sizeof (krb5_keyblock));
3706656Ssemery entry->vno = kvno;
3716656Ssemery entry->principal = princ;
3726656Ssemery
3736656Ssemery if ((code = krb5_kt_add_entry(ctx, kt, entry)) != 0) {
3746656Ssemery com_err(whoami, code,
3756656Ssemery gettext("Could not add entry to keytab"));
3766656Ssemery }
3776656Ssemery }
3786656Ssemery
3796656Ssemery static
3806656Ssemery void
usage()3816656Ssemery usage()
3826656Ssemery {
3836656Ssemery (void) fprintf(stderr, gettext("Usage: %s [-c ccache] [-k keytab] "
384*11061SShawn.Emery@Sun.COM "[-e enctype_list] [-s salt_name] [-n] princ\n"), whoami);
3856656Ssemery (void) fprintf(stderr,
3866656Ssemery gettext("\t-n\tDon't set the principal's password\n"));
3876656Ssemery (void) fprintf(stderr, gettext("\tenctype_list is a comma or whitespace"
3886656Ssemery " separated list\n"));
3896656Ssemery (void) fprintf(stderr, gettext("\tIf -n is used then -k and -e must be "
3906656Ssemery "used\n"));
3916656Ssemery
3926656Ssemery exit(1);
3936656Ssemery }
394