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