1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 9 * 10 * Openvision retains the copyright to derivative works of 11 * this source code. Do *NOT* create a derivative of this 12 * source code before consulting with your legal department. 13 * Do *NOT* integrate *ANY* of this source code into another 14 * product before consulting with your legal department. 15 * 16 * For further information, read the top-level Openvision 17 * copyright which is contained in the top-level MIT Kerberos 18 * copyright. 19 * 20 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 21 * 22 */ 23 24 25 /* 26 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 27 * 28 * $Header$ 29 */ 30 31 #if !defined(lint) && !defined(__CODECENTER__) 32 static char *rcsid = "$Header$"; 33 #endif 34 35 #include <rpc/rpc.h> /* SUNWresync121 XXX */ 36 #include <kadm5/admin.h> 37 #include <kadm5/kadm_rpc.h> 38 #ifdef HAVE_MEMORY_H 39 #include <memory.h> 40 #endif 41 #include <errno.h> 42 #include "client_internal.h" 43 44 #ifdef DEBUG /* SUNWresync14 XXX */ 45 #define eret() {clnt_perror(handle->clnt, "null ret"); return KADM5_RPC_ERROR;} 46 #else 47 #define eret() return KADM5_RPC_ERROR 48 #endif 49 50 kadm5_ret_t 51 kadm5_create_principal(void *server_handle, 52 kadm5_principal_ent_t princ, long mask, 53 char *pw) 54 { 55 generic_ret *r; 56 cprinc_arg arg; 57 kadm5_server_handle_t handle = server_handle; 58 59 CHECK_HANDLE(server_handle); 60 61 memset(&arg, 0, sizeof(arg)); 62 arg.mask = mask; 63 arg.passwd = pw; 64 arg.api_version = handle->api_version; 65 66 if(princ == NULL) 67 return EINVAL; 68 69 if (handle->api_version == KADM5_API_VERSION_1) { 70 memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1)); 71 } else { 72 memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec)); 73 } 74 if (handle->api_version == KADM5_API_VERSION_1) { 75 /* 76 * hack hack cough cough. 77 * krb5_unparse name dumps core if we pass it in garbage 78 * or null. So, since the client is not allowed to set mod_name 79 * anyway, we just fill it in with a dummy principal. The server of 80 * course ignores this. 81 */ 82 /* krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); */ 83 arg.rec.mod_name = NULL; 84 } else 85 arg.rec.mod_name = NULL; 86 87 if(!(mask & KADM5_POLICY)) 88 arg.rec.policy = NULL; 89 if (! (mask & KADM5_KEY_DATA)) { 90 arg.rec.n_key_data = 0; 91 arg.rec.key_data = NULL; 92 } 93 if (! (mask & KADM5_TL_DATA)) { 94 arg.rec.n_tl_data = 0; 95 arg.rec.tl_data = NULL; 96 } 97 98 r = create_principal_2(&arg, handle->clnt); 99 100 if (handle->api_version == KADM5_API_VERSION_1) 101 krb5_free_principal(handle->context, arg.rec.mod_name); 102 103 if(r == NULL) 104 eret(); 105 return r->code; 106 } 107 108 kadm5_ret_t 109 kadm5_create_principal_3(void *server_handle, 110 kadm5_principal_ent_t princ, long mask, 111 int n_ks_tuple, 112 krb5_key_salt_tuple *ks_tuple, 113 char *pw) 114 { 115 generic_ret *r; 116 cprinc3_arg arg; 117 kadm5_server_handle_t handle = server_handle; 118 119 CHECK_HANDLE(server_handle); 120 121 memset(&arg, 0, sizeof(arg)); 122 arg.mask = mask; 123 arg.passwd = pw; 124 arg.api_version = handle->api_version; 125 arg.n_ks_tuple = n_ks_tuple; 126 arg.ks_tuple = ks_tuple; 127 128 if(princ == NULL) 129 return EINVAL; 130 131 if (handle->api_version == KADM5_API_VERSION_1) { 132 memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1)); 133 } else { 134 memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec)); 135 } 136 if (handle->api_version == KADM5_API_VERSION_1) { 137 /* 138 * hack hack cough cough. 139 * krb5_unparse name dumps core if we pass it in garbage 140 * or null. So, since the client is not allowed to set mod_name 141 * anyway, we just fill it in with a dummy principal. The server of 142 * course ignores this. 143 */ 144 krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); 145 } else 146 arg.rec.mod_name = NULL; 147 148 if(!(mask & KADM5_POLICY)) 149 arg.rec.policy = NULL; 150 if (! (mask & KADM5_KEY_DATA)) { 151 arg.rec.n_key_data = 0; 152 arg.rec.key_data = NULL; 153 } 154 if (! (mask & KADM5_TL_DATA)) { 155 arg.rec.n_tl_data = 0; 156 arg.rec.tl_data = NULL; 157 } 158 159 r = create_principal3_2(&arg, handle->clnt); 160 161 if (handle->api_version == KADM5_API_VERSION_1) 162 krb5_free_principal(handle->context, arg.rec.mod_name); 163 164 if(r == NULL) 165 eret(); 166 return r->code; 167 } 168 169 kadm5_ret_t 170 kadm5_delete_principal(void *server_handle, krb5_principal principal) 171 { 172 dprinc_arg arg; 173 generic_ret *r; 174 kadm5_server_handle_t handle = server_handle; 175 176 CHECK_HANDLE(server_handle); 177 178 if(principal == NULL) 179 return EINVAL; 180 arg.princ = principal; 181 arg.api_version = handle->api_version; 182 r = delete_principal_2(&arg, handle->clnt); 183 if(r == NULL) 184 eret(); 185 return r->code; 186 } 187 188 kadm5_ret_t 189 kadm5_modify_principal(void *server_handle, 190 kadm5_principal_ent_t princ, long mask) 191 { 192 mprinc_arg arg; 193 generic_ret *r; 194 kadm5_server_handle_t handle = server_handle; 195 196 CHECK_HANDLE(server_handle); 197 198 memset(&arg, 0, sizeof(arg)); 199 arg.mask = mask; 200 arg.api_version = handle->api_version; 201 /* 202 * cough cough gag gag 203 * see comment in create_principal. 204 */ 205 if(princ == NULL) 206 return EINVAL; 207 if (handle->api_version == KADM5_API_VERSION_1) { 208 memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1)); 209 } else { 210 memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec)); 211 } 212 if(!(mask & KADM5_POLICY)) 213 arg.rec.policy = NULL; 214 if (! (mask & KADM5_KEY_DATA)) { 215 arg.rec.n_key_data = 0; 216 arg.rec.key_data = NULL; 217 } 218 if (! (mask & KADM5_TL_DATA)) { 219 arg.rec.n_tl_data = 0; 220 arg.rec.tl_data = NULL; 221 } 222 223 if (handle->api_version == KADM5_API_VERSION_1) { 224 /* 225 * See comment in create_principal 226 */ 227 krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); 228 } else 229 arg.rec.mod_name = NULL; 230 231 r = modify_principal_2(&arg, handle->clnt); 232 233 if (handle->api_version == KADM5_API_VERSION_1) 234 krb5_free_principal(handle->context, arg.rec.mod_name); 235 236 if(r == NULL) 237 eret(); 238 return r->code; 239 } 240 241 kadm5_ret_t 242 kadm5_get_principal(void *server_handle, 243 krb5_principal princ, kadm5_principal_ent_t ent, 244 long mask) 245 { 246 gprinc_arg arg; 247 gprinc_ret *r; 248 kadm5_server_handle_t handle = server_handle; 249 250 CHECK_HANDLE(server_handle); 251 252 if(princ == NULL) 253 return EINVAL; 254 arg.princ = princ; 255 if (handle->api_version == KADM5_API_VERSION_1) 256 arg.mask = KADM5_PRINCIPAL_NORMAL_MASK; 257 else 258 arg.mask = mask; 259 arg.api_version = handle->api_version; 260 r = get_principal_2(&arg, handle->clnt); 261 if(r == NULL) 262 eret(); 263 if (handle->api_version == KADM5_API_VERSION_1) { 264 kadm5_principal_ent_t_v1 *entp; 265 266 entp = (kadm5_principal_ent_t_v1 *) ent; 267 if (r->code == 0) { 268 if (!(*entp = (kadm5_principal_ent_t_v1) 269 malloc(sizeof(kadm5_principal_ent_rec_v1)))) 270 return ENOMEM; 271 /* this memcpy works because the v1 structure is an initial 272 subset of the v2 struct. C guarantees that this will 273 result in the same layout in memory */ 274 memcpy(*entp, &r->rec, sizeof(**entp)); 275 } else { 276 *entp = NULL; 277 } 278 } else { 279 if (r->code == 0) 280 memcpy(ent, &r->rec, sizeof(r->rec)); 281 } 282 283 return r->code; 284 } 285 286 kadm5_ret_t 287 kadm5_get_principals(void *server_handle, 288 char *exp, char ***princs, int *count) 289 { 290 gprincs_arg arg; 291 gprincs_ret *r; 292 kadm5_server_handle_t handle = server_handle; 293 294 CHECK_HANDLE(server_handle); 295 296 if(princs == NULL || count == NULL) 297 return EINVAL; 298 arg.exp = exp; 299 arg.api_version = handle->api_version; 300 r = get_princs_2(&arg, handle->clnt); 301 if(r == NULL) 302 eret(); 303 if(r->code == 0) { 304 *count = r->count; 305 *princs = r->princs; 306 } else { 307 *count = 0; 308 *princs = NULL; 309 } 310 311 return r->code; 312 } 313 314 kadm5_ret_t 315 kadm5_rename_principal(void *server_handle, 316 krb5_principal source, krb5_principal dest) 317 { 318 rprinc_arg arg; 319 generic_ret *r; 320 kadm5_server_handle_t handle = server_handle; 321 322 CHECK_HANDLE(server_handle); 323 324 arg.src = source; 325 arg.dest = dest; 326 arg.api_version = handle->api_version; 327 if (source == NULL || dest == NULL) 328 return EINVAL; 329 r = rename_principal_2(&arg, handle->clnt); 330 if(r == NULL) 331 eret(); 332 return r->code; 333 } 334 335 kadm5_ret_t 336 kadm5_chpass_principal(void *server_handle, 337 krb5_principal princ, char *password) 338 { 339 chpass_arg arg; 340 generic_ret *r; 341 kadm5_server_handle_t handle = server_handle; 342 343 CHECK_HANDLE(server_handle); 344 345 arg.princ = princ; 346 arg.pass = password; 347 arg.api_version = handle->api_version; 348 349 if(princ == NULL) 350 return EINVAL; 351 r = chpass_principal_2(&arg, handle->clnt); 352 if(r == NULL) 353 eret(); 354 return r->code; 355 } 356 357 kadm5_ret_t 358 kadm5_chpass_principal_3(void *server_handle, 359 krb5_principal princ, krb5_boolean keepold, 360 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 361 char *password) 362 { 363 chpass3_arg arg; 364 generic_ret *r; 365 kadm5_server_handle_t handle = server_handle; 366 367 CHECK_HANDLE(server_handle); 368 369 arg.princ = princ; 370 arg.pass = password; 371 arg.api_version = handle->api_version; 372 arg.keepold = keepold; 373 arg.n_ks_tuple = n_ks_tuple; 374 arg.ks_tuple = ks_tuple; 375 376 if(princ == NULL) 377 return EINVAL; 378 r = chpass_principal3_2(&arg, handle->clnt); 379 if(r == NULL) 380 eret(); 381 return r->code; 382 } 383 384 kadm5_ret_t 385 kadm5_setv4key_principal(void *server_handle, 386 krb5_principal princ, 387 krb5_keyblock *keyblock) 388 { 389 setv4key_arg arg; 390 generic_ret *r; 391 kadm5_server_handle_t handle = server_handle; 392 393 CHECK_HANDLE(server_handle); 394 395 arg.princ = princ; 396 arg.keyblock = keyblock; 397 arg.api_version = handle->api_version; 398 399 if(princ == NULL || keyblock == NULL) 400 return EINVAL; 401 r = setv4key_principal_2(&arg, handle->clnt); 402 if(r == NULL) 403 eret(); 404 return r->code; 405 } 406 407 kadm5_ret_t 408 kadm5_setkey_principal(void *server_handle, 409 krb5_principal princ, 410 krb5_keyblock *keyblocks, 411 int n_keys) 412 { 413 setkey_arg arg; 414 generic_ret *r; 415 kadm5_server_handle_t handle = server_handle; 416 417 CHECK_HANDLE(server_handle); 418 419 arg.princ = princ; 420 arg.keyblocks = keyblocks; 421 arg.n_keys = n_keys; 422 arg.api_version = handle->api_version; 423 424 if(princ == NULL || keyblocks == NULL) 425 return EINVAL; 426 r = setkey_principal_2(&arg, handle->clnt); 427 if(r == NULL) 428 eret(); 429 return r->code; 430 } 431 432 kadm5_ret_t 433 kadm5_setkey_principal_3(void *server_handle, 434 krb5_principal princ, 435 krb5_boolean keepold, int n_ks_tuple, 436 krb5_key_salt_tuple *ks_tuple, 437 krb5_keyblock *keyblocks, 438 int n_keys) 439 { 440 setkey3_arg arg; 441 generic_ret *r; 442 kadm5_server_handle_t handle = server_handle; 443 444 CHECK_HANDLE(server_handle); 445 446 arg.princ = princ; 447 arg.keyblocks = keyblocks; 448 arg.n_keys = n_keys; 449 arg.api_version = handle->api_version; 450 arg.keepold = keepold; 451 arg.n_ks_tuple = n_ks_tuple; 452 arg.ks_tuple = ks_tuple; 453 454 if(princ == NULL || keyblocks == NULL) 455 return EINVAL; 456 r = setkey_principal3_2(&arg, handle->clnt); 457 if(r == NULL) 458 eret(); 459 return r->code; 460 } 461 462 /* 463 * Solaris Kerberos: 464 * This routine implements just the "old" randkey_principal code. 465 * The code in the kadmin client sometimes needs to call this 466 * directly when the kadm5_randkey_principal_3 call fails. 467 * 468 * The kadmin client utility uses a specific set of key/salt tuples, 469 * so the standard fallback in kadm5_randkey_principal (see below) 470 * will not work because it would result in kadm5_randkey_principal_3 471 * being called twice - once with the specific key/salts specified by 472 * kadmin and once with the NULL set (used to indicate that the server 473 * should use the full set of supported enctypes). Making this 474 * routine separate makes the code simpler and avoids making the 475 * kadm5_randkey_principal_3 twice from kadmin. 476 */ 477 kadm5_ret_t 478 kadm5_randkey_principal_old(void *server_handle, 479 krb5_principal princ, 480 krb5_keyblock **key, 481 int *n_keys) 482 { 483 chrand_arg arg; 484 chrand_ret *r; 485 kadm5_server_handle_t handle = server_handle; 486 int i, ret; 487 488 /* For safety */ 489 if (n_keys) 490 *n_keys = 0; 491 if (key) 492 *key = NULL; 493 CHECK_HANDLE(server_handle); 494 495 arg.princ = princ; 496 arg.api_version = handle->api_version; 497 498 if(princ == NULL) 499 return EINVAL; 500 r = chrand_principal_2(&arg, handle->clnt); 501 if (r == NULL) 502 return KADM5_RPC_ERROR; 503 if (handle->api_version == KADM5_API_VERSION_1) { 504 if (key) 505 krb5_copy_keyblock(handle->context, &r->key, key); 506 } else if (key && (r->n_keys > 0)) { 507 *key = (krb5_keyblock *) malloc( 508 r->n_keys*sizeof(krb5_keyblock)); 509 if (*key == NULL) 510 return ENOMEM; 511 for (i = 0; i < r->n_keys; i++) { 512 ret = krb5_copy_keyblock_contents( 513 handle->context, 514 &r->keys[i], 515 &(*key)[i]); 516 if (ret) { 517 free(*key); 518 *key = NULL; 519 return ENOMEM; 520 } 521 } 522 if (n_keys) 523 *n_keys = r->n_keys; 524 } 525 return (r->code); 526 } 527 528 kadm5_ret_t 529 kadm5_randkey_principal_3(void *server_handle, 530 krb5_principal princ, 531 krb5_boolean keepold, int n_ks_tuple, 532 krb5_key_salt_tuple *ks_tuple, 533 krb5_keyblock **key, int *n_keys) 534 { 535 chrand3_arg arg; 536 chrand_ret *r; 537 kadm5_server_handle_t handle = server_handle; 538 int i, ret; 539 540 /* Solaris Kerberos - For safety */ 541 if (n_keys) 542 *n_keys = 0; 543 if (key) 544 *key = NULL; 545 546 CHECK_HANDLE(server_handle); 547 548 arg.princ = princ; 549 arg.api_version = handle->api_version; 550 arg.keepold = keepold; 551 arg.n_ks_tuple = n_ks_tuple; 552 arg.ks_tuple = ks_tuple; 553 554 if(princ == NULL) 555 return EINVAL; 556 r = chrand_principal3_2(&arg, handle->clnt); 557 if(r == NULL) 558 eret(); 559 if (handle->api_version == KADM5_API_VERSION_1) { 560 if (key) 561 krb5_copy_keyblock(handle->context, &r->key, key); 562 } else { 563 if (n_keys) 564 *n_keys = r->n_keys; 565 if (key) { 566 if(r->n_keys) { 567 *key = (krb5_keyblock *) 568 malloc(r->n_keys*sizeof(krb5_keyblock)); 569 if (*key == NULL) 570 return ENOMEM; 571 for (i = 0; i < r->n_keys; i++) { 572 ret = krb5_copy_keyblock_contents(handle->context, 573 &r->keys[i], 574 &(*key)[i]); 575 if (ret) { 576 free(*key); 577 return ENOMEM; 578 } 579 } 580 } else *key = NULL; 581 } 582 } 583 584 return r->code; 585 } 586 587 kadm5_ret_t 588 kadm5_randkey_principal(void *server_handle, 589 krb5_principal princ, 590 krb5_keyblock **key, int *n_keys) 591 { 592 /* Solaris Kerberos */ 593 kadm5_ret_t kret; 594 595 /* 596 * Default to trying the newest API to insure that the full 597 * set of enctypes is created. 598 */ 599 kret = kadm5_randkey_principal_3(server_handle, princ, FALSE, 600 0, NULL, key, n_keys); 601 602 /* 603 * We will get an RPC error if the RPC call failed which 604 * will normally indicate that the remote procedure did not 605 * exist on the server, so try the older API. 606 */ 607 if (kret == KADM5_RPC_ERROR) { 608 kret = kadm5_randkey_principal_old(server_handle, princ, 609 key, n_keys); 610 } 611 return (kret); 612 } 613 614 /* not supported on client side */ 615 kadm5_ret_t kadm5_decrypt_key(void *server_handle, 616 kadm5_principal_ent_t entry, krb5_int32 617 ktype, krb5_int32 stype, krb5_int32 618 kvno, krb5_keyblock *keyblock, 619 krb5_keysalt *keysalt, int *kvnop) 620 { 621 return EINVAL; 622 } 623