1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 | #pragma ident "@(#)kadmin.c 1.13 04/09/08 SMI" 6 | #pragma ident "@(#)kadmin.c 1.12 04/08/19 SMI" 7 8 /* 9 * Copyright 1994 by the Massachusetts Institute of Technology. 10 * All Rights Reserved. 11 * 12 * Export of this software from the United States of America may 13 * require a specific license from the United States Government. 14 * It is the responsibility of any person or organization contemplating 15 * export to obtain such a license before exporting. 16 * 17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 18 * distribute this software and its documentation for any purpose and 19 * without fee is hereby granted, provided that the above copyright 20 * notice appear in all copies and that both that copyright notice and 21 * this permission notice appear in supporting documentation, and that 22 * the name of M.I.T. not be used in advertising or publicity pertaining 23 * to distribution of the software without specific, written prior 24 * permission. Furthermore if you modify this software you must label 25 * your software as modified software and not distribute it in such a 26 * fashion that it might be confused with the original M.I.T. software. 27 * M.I.T. makes no representations about the suitability of 28 * this software for any purpose. It is provided "as is" without express 29 * or implied warranty. 30 * 31 * kadmin.c: base functions for a kadmin command line interface using 32 * the OVSecure library 33 */ 34 35 #include <krb5.h> 36 #include <k5-int.h> 37 #include <kadm5/admin.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <sys/types.h> 41 #include <math.h> 42 #include <unistd.h> 43 #include <pwd.h> 44 /* #include <sys/timeb.h> */ 45 #include <time.h> 46 #include <libintl.h> 47 48 /* 49 * Solaris: the following are needed for paging 50 */ 51 #include <signal.h> 52 #include <sys/wait.h> 53 54 /* command name when called "locally" (i.e. non-networked client ) */ 55 #define KADMIN_LOCAL_NAME "kadmin.local" 56 57 /* functions defined in remote/local specific files */ 58 extern void usage(const char *); 59 extern void debugEnable(int); 60 61 /* local principal helpers */ 62 static char *find_component(const char *, char); 63 static char *trim_principal(char *); 64 static char *build_admin_princ(const char *, const char *); 65 66 /* 67 * special struct to convert flag names for principals 68 * to actual krb5_flags for a principal 69 */ 70 struct pflag { 71 char *flagname; /* name of flag as typed to CLI */ 72 int flaglen; /* length of string (not counting -,+) */ 73 krb5_flags theflag; /* actual principal flag to set/clear */ 74 int set; /* 0 means clear, 1 means set (on '-') */ 75 }; ----Unchanged portion omitted---- 195 196 char * 197 kadmin_startup(argc, argv) 198 int argc; 199 char *argv[]; 200 { 201 extern krb5_kt_ops krb5_ktf_writable_ops; 202 extern char *optarg; 203 char *princstr = NULL, *keytab_name = NULL, *query = NULL; 204 char *password = NULL; 205 char *kadmin_princ = NULL; 206 char *luser, *canon, *cp; 207 int optchar, use_keytab = 0, debug = 0; 208 struct passwd *pw; 209 kadm5_ret_t retval; 210 krb5_ccache cc; 211 krb5_principal princ; 212 kadm5_config_params params; 213 214 memset((char *) ¶ms, 0, sizeof(params)); 215 216 if (retval = krb5_init_context(&context)) { 217 com_err(whoami, retval, 218 gettext("while initializing krb5 library")); 219 exit(1); 220 } 221 while ((optchar = getopt(argc, argv, "Dr:p:kq:w:d:s:mc:t:e:O")) != EOF) { 222 switch (optchar) { 223 case 'O': /* Undocumented option for testing only */ 224 kadmin_princ = KADM5_ADMIN_SERVICE_P; 225 break; 226 case 'D': 227 debug++; 228 break; 229 case 'r': 230 def_realm = optarg; 231 break; 232 case 'p': 233 princstr = strdup(optarg); 234 if (princstr == NULL) { 235 fprintf(stderr, gettext("Out of memory in %s\n"), 236 whoami); 237 exit(1); 238 } 239 break; 240 case 'c': 241 ccache_name = optarg; 242 break; 243 case 'k': 244 use_keytab++; 245 break; 246 case 't': 247 keytab_name = optarg; 248 break; 249 case 'w': 250 password = optarg; 251 break; 252 case 'q': 253 query = optarg; 254 break; 255 case 'd': 256 params.dbname = optarg; 257 params.mask |= KADM5_CONFIG_DBNAME; 258 break; 259 case 's': 260 params.admin_server = optarg; 261 params.mask |= KADM5_CONFIG_ADMIN_SERVER; 262 break; 263 case 'm': 264 params.mkey_from_kbd = 1; 265 params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; 266 break; 267 case 'e': 268 retval = krb5_string_to_keysalts(optarg, 269 ", \t", ":.-", 0, 270 ¶ms.keysalts, 271 ¶ms.num_keysalts); 272 if (retval) { 273 com_err(whoami, retval, 274 gettext("while parsing keysalts %s"), optarg); 275 exit(1); 276 } 277 params.mask |= KADM5_CONFIG_ENCTYPES; 278 break; 279 default: 280 usage(whoami); 281 } 282 } 283 284 debugEnable(debug); 285 286 if ((ccache_name && use_keytab) || 287 (keytab_name && !use_keytab)) 288 usage(whoami); 289 290 if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) { 291 free(princstr); 292 fprintf(stderr, 293 gettext("%s: unable to get default realm\n"), whoami); 294 exit(1); 295 } 296 params.mask |= KADM5_CONFIG_REALM; 297 params.realm = def_realm; 298 299 if (kadmin_princ == NULL) { 300 if (kadm5_get_adm_host_srv_name(context, 301 def_realm, &kadmin_princ)) { 302 fprintf(stderr, 303 gettext("%s: unable to get host based " 304 "service name for realm %s\n"), 305 whoami, def_realm); 306 free(princstr); 307 exit(1); 308 } 309 } 310 311 /* 312 * Set cc to an open credentials cache, either specified by the -c 313 * argument or the default. 314 */ 315 if (ccache_name == NULL) { 316 if (retval = krb5_cc_default(context, &cc)) { 317 com_err(whoami, retval, 318 gettext("while opening default " 319 "credentials cache")); 320 exit(1); 321 } 322 } else { 323 if (retval = krb5_cc_resolve(context, ccache_name, &cc)) { 324 com_err(whoami, retval, 325 gettext("while opening credentials cache %s"), 326 ccache_name); 327 exit(1); 328 } 329 } 330 331 /* 332 * If no principal name is specified: If a ccache was specified and 333 * its primary principal name can be read, it is used, else if a 334 * keytab was specified, the principal name is host/hostname, 335 * otherwise append "/admin" to the primary name of the default 336 * ccache, $USER, or pw_name. 337 * 338 * Gee, 100+ lines to figure out the client principal name. This 339 * should be compressed... 340 */ 341 342 if (princstr == NULL) { 343 if (ccache_name != NULL && 344 !krb5_cc_get_principal(context, cc, &princ)) { 345 if (retval = krb5_unparse_name(context, princ, 346 &princstr)) { 347 com_err(whoami, retval, 348 gettext("while canonicalizing principal name")); 349 krb5_free_principal(context, princ); 350 exit(1); 351 } 352 krb5_free_principal(context, princ); 353 } else if (use_keytab != 0) { 354 if (retval = krb5_sname_to_principal(context, NULL, 355 "host", KRB5_NT_SRV_HST, 356 &princ)) { 357 com_err(whoami, retval, 358 gettext("creating host service principal")); 359 exit(1); 360 } 361 if (retval = krb5_unparse_name(context, princ, 362 &princstr)) { 363 com_err(whoami, retval, 364 gettext("while canonicalizing " 365 "principal name")); 366 krb5_free_principal(context, princ); 367 exit(1); 368 } 369 krb5_free_principal(context, princ); 370 } else if (!krb5_cc_get_principal(context, cc, &princ)) { 371 char *realm = NULL; 372 373 if (krb5_unparse_name(context, princ, &canon)) { 374 fprintf(stderr, 375 gettext("%s: unable to canonicalize " 376 "principal\n"), whoami); 377 krb5_free_principal(context, princ); 378 exit(1); 379 } 380 krb5_free_principal(context, princ); 381 (void) trim_principal(canon); 382 princstr = build_admin_princ(canon, def_realm); 383 free(canon); 384 } else if (luser = getenv("USER")) { 385 princstr = build_admin_princ(luser, def_realm); 386 } else if (pw = getpwuid(getuid())) { 387 princstr = build_admin_princ(pw->pw_name, def_realm); 388 } else { 389 fprintf(stderr, 390 gettext("%s: unable to figure out " 391 "a principal name\n"), 392 whoami); 393 exit(1); 394 } 395 } else { /* (princstr != NULL) */ 396 /* See if we need to add the default realm */ 397 if (find_component(princstr, '@') == NULL) { 398 size_t len; 399 400 /* principal @ realm NULL */ 401 len = strlen(princstr) + 1 + strlen(def_realm) + 1; 402 princstr = realloc(princstr, len); 403 if (princstr == NULL) { 404 fprintf(stderr, 405 gettext("%s: out of memory\n"), whoami); 406 exit(1); 407 } 408 strcat(princstr, "@"); 409 strcat(princstr, def_realm); 410 } 411 } 412 413 /* 414 * Initialize the kadm5 connection. If we were given a ccache, use 415 * it. Otherwise, use/prompt for the password. 416 */ 417 if (ccache_name) { 418 printf(gettext( 419 "Authenticating as principal %s with existing credentials.\n"), 420 princstr); 421 retval = kadm5_init_with_creds(princstr, cc, 422 kadmin_princ, 423 ¶ms, 424 KADM5_STRUCT_VERSION, 425 KADM5_API_VERSION_2, 426 &handle); 427 } else if (use_keytab) { 428 if (keytab_name) 429 printf(gettext("Authenticating as principal %s with keytab %s.\n"), 430 princstr, keytab_name); 431 else 432 printf(gettext( 433 "Authenticating as principal %s with default keytab.\n"), 434 princstr); 435 retval = kadm5_init_with_skey(princstr, keytab_name, 436 kadmin_princ, 437 ¶ms, 438 KADM5_STRUCT_VERSION, 439 KADM5_API_VERSION_2, 440 &handle); 441 } else { 442 printf(gettext("Authenticating as principal %s with password.\n"), 443 princstr); 444 retval = kadm5_init_with_password(princstr, password, 445 kadmin_princ, ¶ms, 446 KADM5_STRUCT_VERSION, 447 KADM5_API_VERSION_2, 448 &handle); 449 } 450 if (retval) { 451 if (retval == KADM5_RPC_ERROR_CANTENCODEARGS || 452 retval == KADM5_RPC_ERROR_CANTDECODEARGS) { 453 com_err(whoami, KADM5_RPC_ERROR, 454 gettext("while initializing %s interface"), whoami); 455 456 /* privacy-enabled mech probably not installed/configed */ 457 com_err(whoami, retval, gettext("."), whoami); 458 } else { 459 com_err(whoami, retval, 460 gettext("while initializing %s interface"), whoami); 461 if (retval == KADM5_BAD_CLIENT_PARAMS || 462 retval == KADM5_BAD_SERVER_PARAMS) 463 usage(whoami); 464 } 465 exit(1); 466 } 467 free(princstr); 468 469 if (retval = krb5_cc_close(context, cc)) { 470 com_err(whoami, retval, gettext("while closing ccache %s"), 471 ccache_name); 472 exit(1); 473 } 474 /* register the WRFILE keytab type and set it as the default */ 475 if (retval = krb5_kt_register(context, &krb5_ktf_writable_ops)) { 476 com_err(whoami, retval, 477 gettext("while registering writable key table functions")); 478 exit(1); 479 } 480 { 481 /* 482 * XXX krb5_defkeyname is an internal library global and 483 * should go away 484 */ 485 extern char *krb5_defkeyname; 486 487 krb5_defkeyname = DEFAULT_KEYTAB; 488 } 489 + 490 + if ((retval = kadm5_init_iprop(handle)) != 0) { 491 + com_err(whoami, retval, gettext("while mapping update log")); 492 + exit(1); 493 + } 494 + 495 /* Solaris kerberos: fix memory leak */ 496 if (kadmin_princ) 497 free(kadmin_princ); 498 499 return (query); 500 } ----Unchanged portion omitted----