1*6656Ssemery /* 2*6656Ssemery * CDDL HEADER START 3*6656Ssemery * 4*6656Ssemery * The contents of this file are subject to the terms of the 5*6656Ssemery * Common Development and Distribution License (the "License"). 6*6656Ssemery * You may not use this file except in compliance with the License. 7*6656Ssemery * 8*6656Ssemery * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6656Ssemery * or http://www.opensolaris.org/os/licensing. 10*6656Ssemery * See the License for the specific language governing permissions 11*6656Ssemery * and limitations under the License. 12*6656Ssemery * 13*6656Ssemery * When distributing Covered Code, include this CDDL HEADER in each 14*6656Ssemery * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6656Ssemery * If applicable, add the following below this CDDL HEADER, with the 16*6656Ssemery * fields enclosed by brackets "[]" replaced with your own identifying 17*6656Ssemery * information: Portions Copyright [yyyy] [name of copyright owner] 18*6656Ssemery * 19*6656Ssemery * CDDL HEADER END 20*6656Ssemery */ 21*6656Ssemery 22*6656Ssemery /* 23*6656Ssemery * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*6656Ssemery * Use is subject to license terms. 25*6656Ssemery */ 26*6656Ssemery 27*6656Ssemery #pragma ident "%Z%%M% %I% %E% SMI" 28*6656Ssemery 29*6656Ssemery #include <stdio.h> 30*6656Ssemery #include <stdlib.h> 31*6656Ssemery #include <strings.h> 32*6656Ssemery #include <locale.h> 33*6656Ssemery #include <netdb.h> 34*6656Ssemery #include "k5-int.h" 35*6656Ssemery 36*6656Ssemery #define QUOTE(x) #x 37*6656Ssemery #define VAL2STR(x) QUOTE(x) 38*6656Ssemery 39*6656Ssemery static char *whoami = NULL; 40*6656Ssemery 41*6656Ssemery static void kt_add_entry(krb5_context ctx, krb5_keytab kt, 42*6656Ssemery const krb5_principal princ, krb5_enctype enctype, krb5_kvno kvno, 43*6656Ssemery const char *pw); 44*6656Ssemery 45*6656Ssemery static krb5_error_code kt_remove_entries(krb5_context ctx, krb5_keytab kt, 46*6656Ssemery const krb5_principal princ); 47*6656Ssemery 48*6656Ssemery static void usage(); 49*6656Ssemery 50*6656Ssemery int 51*6656Ssemery main(int argc, char **argv) 52*6656Ssemery { 53*6656Ssemery krb5_context ctx = NULL; 54*6656Ssemery krb5_error_code code = 0; 55*6656Ssemery krb5_enctype *enctypes; 56*6656Ssemery int enctype_count = 0; 57*6656Ssemery krb5_ccache cc = NULL; 58*6656Ssemery krb5_keytab kt = NULL; 59*6656Ssemery krb5_kvno kvno = 1; 60*6656Ssemery krb5_principal victim; 61*6656Ssemery char c, *vprincstr, *ktname, *token, *lasts, *newpw; 62*6656Ssemery int result_code, i, len, nflag = 0; 63*6656Ssemery krb5_data result_code_string, result_string; 64*6656Ssemery 65*6656Ssemery (void) setlocale(LC_ALL, ""); 66*6656Ssemery 67*6656Ssemery #if !defined(TEXT_DOMAIN) 68*6656Ssemery #define TEXT_DOMAIN "SYS_TEST" 69*6656Ssemery #endif /* TEXT_DOMAIN */ 70*6656Ssemery 71*6656Ssemery (void) textdomain(TEXT_DOMAIN); 72*6656Ssemery 73*6656Ssemery /* Misc init stuff */ 74*6656Ssemery (void) memset(&result_code_string, 0, sizeof (result_code_string)); 75*6656Ssemery (void) memset(&result_string, 0, sizeof (result_string)); 76*6656Ssemery 77*6656Ssemery whoami = argv[0]; 78*6656Ssemery 79*6656Ssemery code = krb5_init_context(&ctx); 80*6656Ssemery if (code != 0) { 81*6656Ssemery com_err(whoami, code, gettext("krb5_init_context() failed")); 82*6656Ssemery exit(1); 83*6656Ssemery } 84*6656Ssemery 85*6656Ssemery while ((c = getopt(argc, argv, "v:c:k:e:n")) != -1) { 86*6656Ssemery switch (c) { 87*6656Ssemery case 'n': 88*6656Ssemery nflag++; 89*6656Ssemery break; 90*6656Ssemery case 'k': 91*6656Ssemery if (kt != NULL) 92*6656Ssemery usage(); 93*6656Ssemery len = snprintf(NULL, 0, "WRFILE:%s", optarg) + 1; 94*6656Ssemery if ((ktname = malloc(len)) == NULL) { 95*6656Ssemery (void) fprintf(stderr, 96*6656Ssemery gettext("Couldn't allocate memory\n")); 97*6656Ssemery exit(1); 98*6656Ssemery } 99*6656Ssemery (void) snprintf(ktname, len, "WRFILE:%s", optarg); 100*6656Ssemery if ((code = krb5_kt_resolve(ctx, ktname, &kt)) != 0) { 101*6656Ssemery com_err(whoami, code, 102*6656Ssemery gettext("Couldn't open/create " 103*6656Ssemery "keytab %s"), optarg); 104*6656Ssemery exit(1); 105*6656Ssemery } 106*6656Ssemery break; 107*6656Ssemery case 'c': 108*6656Ssemery if (cc != NULL) 109*6656Ssemery usage(); 110*6656Ssemery if ((code = krb5_cc_resolve(ctx, optarg, &cc)) != 0) { 111*6656Ssemery com_err(whoami, code, 112*6656Ssemery gettext("Couldn't open ccache %s"), optarg); 113*6656Ssemery exit(1); 114*6656Ssemery } 115*6656Ssemery break; 116*6656Ssemery case 'e': 117*6656Ssemery len = strlen(optarg); 118*6656Ssemery token = strtok_r(optarg, ",\t,", &lasts); 119*6656Ssemery 120*6656Ssemery if (token == NULL) 121*6656Ssemery usage(); 122*6656Ssemery 123*6656Ssemery do { 124*6656Ssemery if (enctype_count++ == 0) { 125*6656Ssemery enctypes = malloc(sizeof (*enctypes)); 126*6656Ssemery } else { 127*6656Ssemery enctypes = realloc(enctypes, 128*6656Ssemery sizeof (*enctypes) * enctype_count); 129*6656Ssemery } 130*6656Ssemery if (enctypes == NULL) { 131*6656Ssemery (void) fprintf(stderr, gettext 132*6656Ssemery ("Couldn't allocate memory")); 133*6656Ssemery exit(1); 134*6656Ssemery } 135*6656Ssemery code = krb5_string_to_enctype(token, 136*6656Ssemery &enctypes[enctype_count - 1]); 137*6656Ssemery 138*6656Ssemery if (code != 0) { 139*6656Ssemery com_err(whoami, code, gettext("Unknown " 140*6656Ssemery "or unsupported enctype %s"), 141*6656Ssemery optarg); 142*6656Ssemery exit(1); 143*6656Ssemery } 144*6656Ssemery } while ((token = strtok_r(NULL, ",\t ", &lasts)) != 145*6656Ssemery NULL); 146*6656Ssemery break; 147*6656Ssemery case 'v': 148*6656Ssemery kvno = (krb5_kvno) atoi(optarg); 149*6656Ssemery break; 150*6656Ssemery default: 151*6656Ssemery usage(); 152*6656Ssemery break; 153*6656Ssemery } 154*6656Ssemery } 155*6656Ssemery 156*6656Ssemery if (nflag && enctype_count == 0) 157*6656Ssemery usage(); 158*6656Ssemery 159*6656Ssemery if (nflag == 0 && cc == NULL && 160*6656Ssemery (code = krb5_cc_default(ctx, &cc)) != 0) { 161*6656Ssemery com_err(whoami, code, gettext("Could not find a ccache")); 162*6656Ssemery exit(1); 163*6656Ssemery } 164*6656Ssemery 165*6656Ssemery if (enctype_count > 0 && kt == NULL && 166*6656Ssemery (code = krb5_kt_default(ctx, &kt)) != 0) { 167*6656Ssemery com_err(whoami, code, gettext("No keytab specified")); 168*6656Ssemery exit(1); 169*6656Ssemery } 170*6656Ssemery 171*6656Ssemery if (argc != (optind + 1)) 172*6656Ssemery usage(); 173*6656Ssemery 174*6656Ssemery vprincstr = argv[optind]; 175*6656Ssemery code = krb5_parse_name(ctx, vprincstr, &victim); 176*6656Ssemery if (code != 0) { 177*6656Ssemery com_err(whoami, code, gettext("krb5_parse_name(%s) failed"), 178*6656Ssemery vprincstr); 179*6656Ssemery exit(1); 180*6656Ssemery } 181*6656Ssemery 182*6656Ssemery if (!isatty(fileno(stdin))) { 183*6656Ssemery char buf[PASS_MAX + 1]; 184*6656Ssemery 185*6656Ssemery if (scanf("%" VAL2STR(PASS_MAX) "s", &buf) != 1) { 186*6656Ssemery (void) fprintf(stderr, 187*6656Ssemery gettext("Couldn't read new password\n")); 188*6656Ssemery exit(1); 189*6656Ssemery } 190*6656Ssemery 191*6656Ssemery newpw = strdup(buf); 192*6656Ssemery if (newpw == NULL) { 193*6656Ssemery (void) fprintf(stderr, 194*6656Ssemery gettext("Couldn't allocate memory\n")); 195*6656Ssemery exit(1); 196*6656Ssemery } 197*6656Ssemery } else { 198*6656Ssemery newpw = getpassphrase(gettext("Enter new password: ")); 199*6656Ssemery if (newpw == NULL) { 200*6656Ssemery (void) fprintf(stderr, 201*6656Ssemery gettext("Couldn't read new password\n")); 202*6656Ssemery exit(1); 203*6656Ssemery } 204*6656Ssemery 205*6656Ssemery newpw = strdup(newpw); 206*6656Ssemery if (newpw == NULL) { 207*6656Ssemery (void) fprintf(stderr, 208*6656Ssemery gettext("Couldn't allocate memory\n")); 209*6656Ssemery exit(1); 210*6656Ssemery } 211*6656Ssemery } 212*6656Ssemery 213*6656Ssemery if (nflag == 0) { 214*6656Ssemery code = krb5_set_password_using_ccache(ctx, cc, newpw, victim, 215*6656Ssemery &result_code, &result_code_string, &result_string); 216*6656Ssemery if (code != 0) { 217*6656Ssemery com_err(whoami, code, 218*6656Ssemery gettext("krb5_set_password() failed")); 219*6656Ssemery exit(1); 220*6656Ssemery } 221*6656Ssemery krb5_cc_close(ctx, cc); 222*6656Ssemery 223*6656Ssemery (void) printf("Result: %.*s (%d) %.*s\n", 224*6656Ssemery result_code == 0 ? 225*6656Ssemery strlen("success") : result_code_string.length, 226*6656Ssemery result_code == 0 ? "success" : result_code_string.data, 227*6656Ssemery result_code, 228*6656Ssemery result_string.length, result_string.data); 229*6656Ssemery 230*6656Ssemery if (result_code != 0) { 231*6656Ssemery (void) fprintf(stderr, gettext("Exiting...\n")); 232*6656Ssemery exit(result_code); 233*6656Ssemery } 234*6656Ssemery } 235*6656Ssemery 236*6656Ssemery if (enctype_count && (code = kt_remove_entries(ctx, kt, victim))) 237*6656Ssemery goto error; 238*6656Ssemery 239*6656Ssemery for (i = 0; i < enctype_count; i++) 240*6656Ssemery kt_add_entry(ctx, kt, victim, enctypes[i], kvno, newpw); 241*6656Ssemery 242*6656Ssemery error: 243*6656Ssemery if (kt != NULL) 244*6656Ssemery krb5_kt_close(ctx, kt); 245*6656Ssemery 246*6656Ssemery return (code ? 1 : 0); 247*6656Ssemery } 248*6656Ssemery 249*6656Ssemery static 250*6656Ssemery krb5_error_code 251*6656Ssemery kt_remove_entries(krb5_context ctx, krb5_keytab kt, const krb5_principal princ) 252*6656Ssemery { 253*6656Ssemery krb5_error_code code; 254*6656Ssemery krb5_kt_cursor cursor; 255*6656Ssemery krb5_keytab_entry entry; 256*6656Ssemery 257*6656Ssemery /* 258*6656Ssemery * This is not a fatal error, we expect this to fail in the majority 259*6656Ssemery * of cases (when clients are first initialized). 260*6656Ssemery */ 261*6656Ssemery code = krb5_kt_get_entry(ctx, kt, princ, 0, 0, &entry); 262*6656Ssemery if (code != 0) { 263*6656Ssemery com_err(whoami, code, 264*6656Ssemery gettext("Could not retrieve entry in keytab")); 265*6656Ssemery return (0); 266*6656Ssemery } 267*6656Ssemery 268*6656Ssemery krb5_kt_free_entry(ctx, &entry); 269*6656Ssemery 270*6656Ssemery code = krb5_kt_start_seq_get(ctx, kt, &cursor); 271*6656Ssemery if (code != 0) { 272*6656Ssemery com_err(whoami, code, gettext("While starting keytab scan")); 273*6656Ssemery return (code); 274*6656Ssemery } 275*6656Ssemery 276*6656Ssemery while ((code = krb5_kt_next_entry(ctx, kt, &entry, &cursor)) == 0) { 277*6656Ssemery if (krb5_principal_compare(ctx, princ, entry.principal)) { 278*6656Ssemery 279*6656Ssemery code = krb5_kt_end_seq_get(ctx, kt, &cursor); 280*6656Ssemery if (code != 0) { 281*6656Ssemery com_err(whoami, code, 282*6656Ssemery gettext("While temporarily " 283*6656Ssemery "ending keytab scan")); 284*6656Ssemery return (code); 285*6656Ssemery } 286*6656Ssemery 287*6656Ssemery code = krb5_kt_remove_entry(ctx, kt, &entry); 288*6656Ssemery if (code != 0) { 289*6656Ssemery com_err(whoami, code, 290*6656Ssemery gettext("While deleting entry " 291*6656Ssemery "from keytab")); 292*6656Ssemery return (code); 293*6656Ssemery } 294*6656Ssemery 295*6656Ssemery code = krb5_kt_start_seq_get(ctx, kt, &cursor); 296*6656Ssemery if (code != 0) { 297*6656Ssemery com_err(whoami, code, 298*6656Ssemery gettext("While restarting keytab scan")); 299*6656Ssemery return (code); 300*6656Ssemery } 301*6656Ssemery } 302*6656Ssemery 303*6656Ssemery krb5_kt_free_entry(ctx, &entry); 304*6656Ssemery } 305*6656Ssemery 306*6656Ssemery if (code && code != KRB5_KT_END) { 307*6656Ssemery com_err(whoami, code, gettext("While scanning keytab")); 308*6656Ssemery return (code); 309*6656Ssemery } 310*6656Ssemery 311*6656Ssemery if ((code = krb5_kt_end_seq_get(ctx, kt, &cursor))) { 312*6656Ssemery com_err(whoami, code, gettext("While ending keytab scan")); 313*6656Ssemery return (code); 314*6656Ssemery } 315*6656Ssemery 316*6656Ssemery return (0); 317*6656Ssemery } 318*6656Ssemery 319*6656Ssemery static 320*6656Ssemery void 321*6656Ssemery kt_add_entry(krb5_context ctx, krb5_keytab kt, const krb5_principal princ, 322*6656Ssemery krb5_enctype enctype, krb5_kvno kvno, const char *pw) 323*6656Ssemery { 324*6656Ssemery krb5_keytab_entry *entry; 325*6656Ssemery krb5_data password, salt; 326*6656Ssemery krb5_keyblock key; 327*6656Ssemery krb5_error_code code; 328*6656Ssemery char buf[100]; 329*6656Ssemery 330*6656Ssemery if ((code = krb5_enctype_to_string(enctype, buf, sizeof (buf)))) { 331*6656Ssemery com_err(whoami, code, gettext("Enctype %d has no name!"), 332*6656Ssemery enctype); 333*6656Ssemery return; 334*6656Ssemery } 335*6656Ssemery if ((entry = (krb5_keytab_entry *) malloc(sizeof (*entry))) == NULL) { 336*6656Ssemery (void) fprintf(stderr, gettext("Couldn't allocate memory")); 337*6656Ssemery return; 338*6656Ssemery } 339*6656Ssemery 340*6656Ssemery (void) memset((char *)entry, 0, sizeof (*entry)); 341*6656Ssemery 342*6656Ssemery password.length = strlen(pw); 343*6656Ssemery password.data = (char *)pw; 344*6656Ssemery 345*6656Ssemery if ((code = krb5_principal2salt(ctx, princ, &salt)) != 0) { 346*6656Ssemery com_err(whoami, code, 347*6656Ssemery gettext("Could not compute salt for %s"), enctype); 348*6656Ssemery return; 349*6656Ssemery } 350*6656Ssemery 351*6656Ssemery code = krb5_c_string_to_key(ctx, enctype, &password, &salt, &key); 352*6656Ssemery 353*6656Ssemery if (code != 0) { 354*6656Ssemery com_err(whoami, code, gettext("Could not compute salt for %s"), 355*6656Ssemery enctype); 356*6656Ssemery krb5_xfree(salt.data); 357*6656Ssemery return; 358*6656Ssemery } 359*6656Ssemery 360*6656Ssemery (void) memcpy(&entry->key, &key, sizeof (krb5_keyblock)); 361*6656Ssemery entry->vno = kvno; 362*6656Ssemery entry->principal = princ; 363*6656Ssemery 364*6656Ssemery if ((code = krb5_kt_add_entry(ctx, kt, entry)) != 0) { 365*6656Ssemery com_err(whoami, code, 366*6656Ssemery gettext("Could not add entry to keytab")); 367*6656Ssemery } 368*6656Ssemery } 369*6656Ssemery 370*6656Ssemery static 371*6656Ssemery void 372*6656Ssemery usage() 373*6656Ssemery { 374*6656Ssemery (void) fprintf(stderr, gettext("Usage: %s [-c ccache] [-k keytab] " 375*6656Ssemery "[-e enctype_list] [-n] princ\n"), whoami); 376*6656Ssemery (void) fprintf(stderr, 377*6656Ssemery gettext("\t-n\tDon't set the principal's password\n")); 378*6656Ssemery (void) fprintf(stderr, gettext("\tenctype_list is a comma or whitespace" 379*6656Ssemery " separated list\n")); 380*6656Ssemery (void) fprintf(stderr, gettext("\tIf -n is used then -k and -e must be " 381*6656Ssemery "used\n")); 382*6656Ssemery 383*6656Ssemery exit(1); 384*6656Ssemery } 385