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