1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 * 5 * $Header: /cvs/krbdev/krb5/src/lib/kadm5/clnt/client_init.c,v 1.13.2.2 2000/05/09 13:17:14 raeburn Exp $ 6 */ 7 8 | #pragma ident "@(#)client_init.c 1.16 04/09/08 SMI" 8 | #pragma ident "@(#)client_init.c 1.15 04/05/04 SMI" 9 10 /* 11 * Copyright (C) 1998 by the FundsXpress, INC. 12 * 13 * All rights reserved. 14 * 15 * Export of this software from the United States of America may require 16 * a specific license from the United States Government. It is the 17 * responsibility of any person or organization contemplating export to 18 * obtain such a license before exporting. 19 * 20 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 21 * distribute this software and its documentation for any purpose and 22 * without fee is hereby granted, provided that the above copyright 23 * notice appear in all copies and that both that copyright notice and 24 * this permission notice appear in supporting documentation, and that 25 * the name of FundsXpress. not be used in advertising or publicity pertaining 26 * to distribution of the software without specific, written prior 27 * permission. FundsXpress 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 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 32 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 33 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 34 */ 35 36 37 /* 38 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 39 * 40 * $Header: /afs/athena.mit.edu/astaff/project/krbdev/.cvsroot/src/lib/kadm5/clnt/client_init.c,v 1.6 1996/11/07 17:13:44 tytso Exp $ 41 */ 42 43 #include <stdio.h> 44 #include <netdb.h> 45 #include <memory.h> 46 #include <string.h> 47 #include <com_err.h> 48 #include <sys/types.h> 49 #include <sys/socket.h> 50 #include <netinet/in.h> 51 #include <krb5.h> 52 #include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */ 53 #ifdef __STDC__ 54 #include <stdlib.h> 55 #endif 56 #include <libintl.h> 57 58 #include <syslog.h> 59 #include <gssapi/gssapi.h> 60 #include <gssapi_krb5.h> 61 #include <gssapiP_krb5.h> 62 #include <kadm5/kadm_rpc.h> 63 #include <rpc/clnt.h> 64 #include <kadm5/admin.h> 65 #include "client_internal.h" 66 + #include <iprop_hdr.h> 67 + #include "iprop.h" 68 69 #define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX" 70 71 /* connection timeout to kadmind in seconds */ 72 #define KADMIND_CONNECT_TIMEOUT 25 73 74 int _kadm5_check_handle(); 75 76 enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS }; 77 78 static kadm5_ret_t _kadm5_init_any(char *client_name, 79 enum init_type init_type, 80 char *pass, 81 krb5_ccache ccache_in, 82 char *service_name, 83 kadm5_config_params *params, 84 krb5_ui_4 struct_version, 85 krb5_ui_4 api_version, 86 void **server_handle); 87 88 kadm5_ret_t kadm5_init_with_creds(char *client_name, 89 krb5_ccache ccache, 90 char *service_name, 91 kadm5_config_params *params, 92 krb5_ui_4 struct_version, 93 krb5_ui_4 api_version, 94 void **server_handle) 95 { 96 return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache, 97 service_name, params, 98 struct_version, api_version, 99 server_handle); 100 } ----Unchanged portion omitted---- 287 288 /* 289 * Open an RPCSEC_GSS connection and 290 * get a client handle to use for future RPCSEC calls. 291 * 292 * This function is only used when changing passwords and 293 * the kpasswd_protocol is RPCSEC_GSS 294 */ 295 static int 296 _kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle, 297 char *client_name, 298 char *service_name) 299 { 300 struct netbuf netaddr; 301 struct hostent *hp; 302 int fd; 303 struct sockaddr_in addr; 304 struct sockaddr_in *sin; 305 struct netconfig *nconf; 306 int code = 0; 307 generic_ret *r; 308 char *ccname_orig; 309 + char *iprop_svc; 310 + boolean_t iprop_enable = B_FALSE; 311 char mech[] = "kerberos_v5"; 312 gss_OID mech_oid; 313 gss_OID_set_desc oid_set; 314 gss_name_t gss_client; 315 gss_buffer_desc input_name; 316 gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL; 317 rpc_gss_options_req_t options_req; 318 rpc_gss_options_ret_t options_ret; 319 rpc_gss_service_t service = rpc_gss_svc_privacy; 320 OM_uint32 gssstat, minor_stat; 321 void *handlep; 322 enum clnt_stat rpc_err_code; 323 324 hp = gethostbyname(handle->params.admin_server); 325 if (hp == (struct hostent *)NULL) { 326 code = KADM5_BAD_SERVER_NAME; 327 ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 328 "bad server name\n")); 329 goto cleanup; 330 } 331 332 memset(&addr, 0, sizeof (addr)); 333 addr.sin_family = hp->h_addrtype; 334 (void) memcpy((char *)&addr.sin_addr, (char *)hp->h_addr, 335 sizeof (addr.sin_addr)); 336 addr.sin_port = htons((ushort_t)handle->params.kadmind_port); 337 sin = &addr; 338 #ifdef DEBUG 339 printf("kadmin_port %d\n", handle->params.kadmind_port); 340 printf("addr: sin_port: %d, sin_family: %d, sin_zero %s\n", 341 addr.sin_port, addr.sin_family, addr.sin_zero); 342 printf("sin_addr %d:%d\n", addr.sin_addr.S_un.S_un_w.s_w1, 343 addr.sin_addr.S_un.S_un_w.s_w2); 344 #endif 345 if ((handlep = setnetconfig()) == (void *) NULL) { 346 (void) syslog(LOG_ERR, 347 dgettext(TEXT_DOMAIN, 348 "cannot get any transport information")); 349 goto error; 350 } 351 352 while (nconf = getnetconfig(handlep)) { 353 if ((nconf->nc_semantics == NC_TPI_COTS_ORD) && 354 (strcmp(nconf->nc_protofmly, NC_INET) == 0) && 355 (strcmp(nconf->nc_proto, NC_TCP) == 0)) 356 break; 357 } 358 359 if (nconf == (struct netconfig *)NULL) { 360 (void) endnetconfig(handlep); 361 goto error; 362 } 363 364 /* Transform addr to netbuf */ 365 (void) memset(&netaddr, 0, sizeof (netaddr)); 366 netaddr.buf = (char *)sin; 367 368 /* get an fd connected to the given address */ 369 fd = get_connection(nconf, netaddr); 370 if (fd == -1) { 371 syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 372 "unable to open connection to ADMIN server " 373 "(t_error %i)"), t_errno); 374 code = KADM5_RPC_ERROR; 375 goto error; 376 } 377 378 #ifdef DEBUG 379 printf("fd: %d, KADM: %d, KADMVERS %d\n", fd, KADM, KADMVERS); 380 printf("nconf: nc_netid: %s, nc_semantics: %d, nc_flag: %d, " 381 "nc_protofmly: %s\n", 382 nconf->nc_netid, nconf->nc_semantics, nconf->nc_flag, 383 nconf->nc_protofmly); 384 printf("nc_proto: %s, nc_device: %s, nc_nlookups: %d, nc_used: %d\n", 385 nconf->nc_proto, nconf->nc_device, nconf->nc_nlookups, 386 nconf->nc_unused); 387 printf("netaddr: maxlen %d, buf: %s, len: %d\n", netaddr.maxlen, 388 netaddr.buf, netaddr.len); 389 #endif 386 | /* tell clnt_tli_create that given fd is already connected */ 387 | handle->clnt = clnt_tli_create(fd, nconf, NULL, KADM, KADMVERS, 0, 0); 390 | /* 391 | * Tell clnt_tli_create that given fd is already connected 392 + * 393 + * If the service_name and client_name are iprop-centric, 394 + * we need to clnt_tli_create to the appropriate RPC prog 395 + */ 396 + iprop_svc = strdup(KIPROP_SVC_NAME); 397 + if (iprop_svc == NULL) 398 + return (ENOMEM); 399 + 400 + if ((strstr(service_name, iprop_svc) != NULL) && 401 + (strstr(client_name, iprop_svc) != NULL)) { 402 + iprop_enable = B_TRUE; 403 + handle->clnt = clnt_tli_create(fd, nconf, NULL, 404 + KRB5_IPROP_PROG, KRB5_IPROP_VERS, 0, 0); 405 + } 406 + else 407 + handle->clnt = clnt_tli_create(fd, nconf, NULL, 408 + KADM, KADMVERS, 0, 0); 409 + 410 + if (iprop_svc) 411 + free(iprop_svc); 412 + 413 if (handle->clnt == NULL) { 414 syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 415 "clnt_tli_create failed\n")); 416 code = KADM5_RPC_ERROR; 417 (void) close(fd); 418 goto error; 419 } 420 /* 421 * The rpc-handle was created on an fd opened and connected 422 * by us, so we have to explicitly tell rpc to close it. 423 */ 424 if (clnt_control(handle->clnt, CLSET_FD_CLOSE, NULL) != TRUE) { 425 clnt_pcreateerror("ERROR:"); 426 syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 427 "clnt_control failed to set CLSET_FD_CLOSE")); 428 code = KADM5_RPC_ERROR; 429 (void) close(fd); 430 goto error; 431 } 432 433 handle->lhandle->clnt = handle->clnt; 434 435 /* now that handle->clnt is set, we can check the handle */ 436 if (code = _kadm5_check_handle((void *) handle)) 437 goto error; 438 439 /* 440 * The RPC connection is open; establish the GSS-API 441 * authentication context. 442 */ 443 ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 444 "have an rpc connection open\n")); 445 /* use the kadm5 cache */ 446 ccname_orig = getenv("KRB5CCNAME"); 447 if (ccname_orig) 448 ccname_orig = strdup(ccname_orig); 449 450 (void) krb5_setenv("KRB5CCNAME", handle->cache_name, 1); 451 452 ADMIN_LOG(LOG_ERR, 453 dgettext(TEXT_DOMAIN, 454 "current credential cache: %s"), handle->cache_name); 455 input_name.value = client_name; 456 input_name.length = strlen((char *)input_name.value) + 1; 457 gssstat = gss_import_name(&minor_stat, &input_name, 458 (gss_OID)gss_nt_krb5_name, &gss_client); 459 if (gssstat != GSS_S_COMPLETE) { 460 code = KADM5_GSS_ERROR; 461 ADMIN_LOGO(LOG_ERR, 462 dgettext(TEXT_DOMAIN, 463 "gss_import_name failed for client name\n")); 464 goto error; 465 } 466 467 if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) { 468 ADMIN_LOG(LOG_ERR, 469 dgettext(TEXT_DOMAIN, 470 "Invalid mechanism oid <%s>"), mech); 471 goto error; 472 } 473 474 oid_set.count = 1; 475 oid_set.elements = mech_oid; 476 477 gssstat = gss_acquire_cred(&minor_stat, gss_client, 0, 478 &oid_set, GSS_C_INITIATE, 479 &gss_client_creds, NULL, NULL); 480 (void) gss_release_name(&minor_stat, &gss_client); 481 if (gssstat != GSS_S_COMPLETE) { 482 code = KADM5_GSS_ERROR; 483 ADMIN_LOG(LOG_ERR, 484 dgettext(TEXT_DOMAIN, 485 "could not acquire credentials, " 486 "major error code: %d\n"), gssstat); 487 goto error; 488 } 489 options_req.my_cred = gss_client_creds; 490 options_req.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; 491 options_req.time_req = 0; 492 options_req.input_channel_bindings = NULL; 493 #ifndef INIT_TEST 494 handle->clnt->cl_auth = rpc_gss_seccreate(handle->clnt, 495 service_name, 496 mech, 497 service, 498 NULL, 499 &options_req, 500 &options_ret); 501 #endif /* ! INIT_TEST */ 502 503 if (ccname_orig) { 504 (void) krb5_setenv("KRB5CCNAME", ccname_orig, 1); 505 free(ccname_orig); 506 } else 507 (void) krb5_unsetenv("KRB5CCNAME"); 508 509 510 if (handle->clnt->cl_auth == NULL) { 511 code = KADM5_GSS_ERROR; 512 display_status(dgettext(TEXT_DOMAIN, 513 "rpc_gss_seccreate failed\n"), 514 options_ret.major_status, 515 options_ret.minor_status, 516 mech); 517 goto error; 518 } 519 520 + /* 521 + * Bypass the remainder of the code and return straightaway 522 + * if the gss service requested is kiprop 523 + */ 524 + if (iprop_enable == B_TRUE) { 525 + code = 0; 526 + goto cleanup; 527 + } 528 + 529 r = init_1(&handle->api_version, handle->clnt, &rpc_err_code); 530 if (r == NULL) { 531 ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 532 "error during admin api initialization\n")); 533 534 if (rpc_err_code == RPC_CANTENCODEARGS) { 535 ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 536 "encryption needed to encode RPC data may not be " 537 "installed/configured on this system")); 538 code = KADM5_RPC_ERROR_CANTENCODEARGS; 539 } else if (rpc_err_code == RPC_CANTDECODEARGS) { 540 ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 541 "encryption needed to decode RPC data may not be " 542 "installed/configured on the server")); 543 code = KADM5_RPC_ERROR_CANTDECODEARGS; 544 } else 545 code = KADM5_RPC_ERROR; 546 547 goto error; 548 549 } 550 if (r->code) { 551 code = r->code; 552 ADMIN_LOG(LOG_ERR, 553 dgettext(TEXT_DOMAIN, 554 "error during admin api initialization: %d\n"), 555 r->code); 556 goto error; 557 } 558 error: 559 cleanup: 560 if (gss_client_creds != GSS_C_NO_CREDENTIAL) 561 (void) gss_release_cred(&minor_stat, &gss_client_creds); 562 563 return (code); 564 } ----Unchanged portion omitted---- 970 971 + /* 972 + * Stub function for kadmin. It was created to eliminate the dependency on 973 + * libkdb's ulog functions. The srv equivalent makes the actual calls. 974 + */ 975 + krb5_error_code 976 + kadm5_init_iprop(void *handle) 977 + { 978 + return (0); 979 + }