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