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 + }