1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate * 5*0Sstevel@tonic-gate * $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*0Sstevel@tonic-gate */ 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gate /* 11*0Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * All rights reserved. 14*0Sstevel@tonic-gate * 15*0Sstevel@tonic-gate * Export of this software from the United States of America may require 16*0Sstevel@tonic-gate * a specific license from the United States Government. It is the 17*0Sstevel@tonic-gate * responsibility of any person or organization contemplating export to 18*0Sstevel@tonic-gate * obtain such a license before exporting. 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 21*0Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 22*0Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 23*0Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 24*0Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 25*0Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining 26*0Sstevel@tonic-gate * to distribution of the software without specific, written prior 27*0Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of 28*0Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 29*0Sstevel@tonic-gate * or implied warranty. 30*0Sstevel@tonic-gate * 31*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 32*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 33*0Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 34*0Sstevel@tonic-gate */ 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate /* 38*0Sstevel@tonic-gate * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 39*0Sstevel@tonic-gate * 40*0Sstevel@tonic-gate * $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*0Sstevel@tonic-gate */ 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include <stdio.h> 44*0Sstevel@tonic-gate #include <netdb.h> 45*0Sstevel@tonic-gate #include <memory.h> 46*0Sstevel@tonic-gate #include <string.h> 47*0Sstevel@tonic-gate #include <com_err.h> 48*0Sstevel@tonic-gate #include <sys/types.h> 49*0Sstevel@tonic-gate #include <sys/socket.h> 50*0Sstevel@tonic-gate #include <netinet/in.h> 51*0Sstevel@tonic-gate #include <krb5.h> 52*0Sstevel@tonic-gate #include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */ 53*0Sstevel@tonic-gate #ifdef __STDC__ 54*0Sstevel@tonic-gate #include <stdlib.h> 55*0Sstevel@tonic-gate #endif 56*0Sstevel@tonic-gate #include <libintl.h> 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate #include <syslog.h> 59*0Sstevel@tonic-gate #include <gssapi/gssapi.h> 60*0Sstevel@tonic-gate #include <gssapi_krb5.h> 61*0Sstevel@tonic-gate #include <gssapiP_krb5.h> 62*0Sstevel@tonic-gate #include <kadm5/kadm_rpc.h> 63*0Sstevel@tonic-gate #include <rpc/clnt.h> 64*0Sstevel@tonic-gate #include <kadm5/admin.h> 65*0Sstevel@tonic-gate #include "client_internal.h" 66*0Sstevel@tonic-gate #include <iprop_hdr.h> 67*0Sstevel@tonic-gate #include "iprop.h" 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX" 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* connection timeout to kadmind in seconds */ 72*0Sstevel@tonic-gate #define KADMIND_CONNECT_TIMEOUT 25 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate int _kadm5_check_handle(); 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS }; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name, 79*0Sstevel@tonic-gate enum init_type init_type, 80*0Sstevel@tonic-gate char *pass, 81*0Sstevel@tonic-gate krb5_ccache ccache_in, 82*0Sstevel@tonic-gate char *service_name, 83*0Sstevel@tonic-gate kadm5_config_params *params, 84*0Sstevel@tonic-gate krb5_ui_4 struct_version, 85*0Sstevel@tonic-gate krb5_ui_4 api_version, 86*0Sstevel@tonic-gate void **server_handle); 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_creds(char *client_name, 89*0Sstevel@tonic-gate krb5_ccache ccache, 90*0Sstevel@tonic-gate char *service_name, 91*0Sstevel@tonic-gate kadm5_config_params *params, 92*0Sstevel@tonic-gate krb5_ui_4 struct_version, 93*0Sstevel@tonic-gate krb5_ui_4 api_version, 94*0Sstevel@tonic-gate void **server_handle) 95*0Sstevel@tonic-gate { 96*0Sstevel@tonic-gate return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache, 97*0Sstevel@tonic-gate service_name, params, 98*0Sstevel@tonic-gate struct_version, api_version, 99*0Sstevel@tonic-gate server_handle); 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass, 104*0Sstevel@tonic-gate char *service_name, 105*0Sstevel@tonic-gate kadm5_config_params *params, 106*0Sstevel@tonic-gate krb5_ui_4 struct_version, 107*0Sstevel@tonic-gate krb5_ui_4 api_version, 108*0Sstevel@tonic-gate void **server_handle) 109*0Sstevel@tonic-gate { 110*0Sstevel@tonic-gate return _kadm5_init_any(client_name, INIT_PASS, pass, NULL, 111*0Sstevel@tonic-gate service_name, params, struct_version, 112*0Sstevel@tonic-gate api_version, server_handle); 113*0Sstevel@tonic-gate } 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate kadm5_ret_t kadm5_init(char *client_name, char *pass, 116*0Sstevel@tonic-gate char *service_name, 117*0Sstevel@tonic-gate kadm5_config_params *params, 118*0Sstevel@tonic-gate krb5_ui_4 struct_version, 119*0Sstevel@tonic-gate krb5_ui_4 api_version, 120*0Sstevel@tonic-gate void **server_handle) 121*0Sstevel@tonic-gate { 122*0Sstevel@tonic-gate return _kadm5_init_any(client_name, INIT_PASS, pass, NULL, 123*0Sstevel@tonic-gate service_name, params, struct_version, 124*0Sstevel@tonic-gate api_version, server_handle); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, 128*0Sstevel@tonic-gate char *service_name, 129*0Sstevel@tonic-gate kadm5_config_params *params, 130*0Sstevel@tonic-gate krb5_ui_4 struct_version, 131*0Sstevel@tonic-gate krb5_ui_4 api_version, 132*0Sstevel@tonic-gate void **server_handle) 133*0Sstevel@tonic-gate { 134*0Sstevel@tonic-gate return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL, 135*0Sstevel@tonic-gate service_name, params, struct_version, 136*0Sstevel@tonic-gate api_version, server_handle); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate krb5_error_code kadm5_free_config_params(); 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate static void 142*0Sstevel@tonic-gate display_status_1(m, code, type, mech) 143*0Sstevel@tonic-gate char *m; 144*0Sstevel@tonic-gate OM_uint32 code; 145*0Sstevel@tonic-gate int type; 146*0Sstevel@tonic-gate const gss_OID mech; 147*0Sstevel@tonic-gate { 148*0Sstevel@tonic-gate OM_uint32 maj_stat, min_stat; 149*0Sstevel@tonic-gate gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; 150*0Sstevel@tonic-gate OM_uint32 msg_ctx; 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate msg_ctx = 0; 153*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, "%s\n", m); 154*0Sstevel@tonic-gate /* LINTED */ 155*0Sstevel@tonic-gate while (1) { 156*0Sstevel@tonic-gate maj_stat = gss_display_status(&min_stat, code, 157*0Sstevel@tonic-gate type, mech, 158*0Sstevel@tonic-gate &msg_ctx, &msg); 159*0Sstevel@tonic-gate if (maj_stat != GSS_S_COMPLETE) { 160*0Sstevel@tonic-gate syslog(LOG_ERR, 161*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 162*0Sstevel@tonic-gate "error in gss_display_status" 163*0Sstevel@tonic-gate " called from <%s>\n"), m); 164*0Sstevel@tonic-gate break; 165*0Sstevel@tonic-gate } else 166*0Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 167*0Sstevel@tonic-gate "GSS-API error : %s\n"), 168*0Sstevel@tonic-gate m); 169*0Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 170*0Sstevel@tonic-gate "GSS-API error : %s\n"), 171*0Sstevel@tonic-gate (char *)msg.value); 172*0Sstevel@tonic-gate if (msg.length != 0) 173*0Sstevel@tonic-gate (void) gss_release_buffer(&min_stat, &msg); 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate if (!msg_ctx) 176*0Sstevel@tonic-gate break; 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* 181*0Sstevel@tonic-gate * Function: display_status 182*0Sstevel@tonic-gate * 183*0Sstevel@tonic-gate * Purpose: displays GSS-API messages 184*0Sstevel@tonic-gate * 185*0Sstevel@tonic-gate * Arguments: 186*0Sstevel@tonic-gate * 187*0Sstevel@tonic-gate * msg a string to be displayed with the message 188*0Sstevel@tonic-gate * maj_stat the GSS-API major status code 189*0Sstevel@tonic-gate * min_stat the GSS-API minor status code 190*0Sstevel@tonic-gate * mech kerberos mech 191*0Sstevel@tonic-gate * Effects: 192*0Sstevel@tonic-gate * 193*0Sstevel@tonic-gate * The GSS-API messages associated with maj_stat and min_stat are 194*0Sstevel@tonic-gate * displayed on stderr, each preceeded by "GSS-API error <msg>: " and 195*0Sstevel@tonic-gate * followed by a newline. 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate void 198*0Sstevel@tonic-gate display_status(msg, maj_stat, min_stat, mech) 199*0Sstevel@tonic-gate char *msg; 200*0Sstevel@tonic-gate OM_uint32 maj_stat; 201*0Sstevel@tonic-gate OM_uint32 min_stat; 202*0Sstevel@tonic-gate char *mech; 203*0Sstevel@tonic-gate { 204*0Sstevel@tonic-gate gss_OID mech_oid; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) { 207*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, 208*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 209*0Sstevel@tonic-gate "Invalid mechanism oid <%s>"), mech); 210*0Sstevel@tonic-gate return; 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate display_status_1(msg, maj_stat, GSS_C_GSS_CODE, mech_oid); 214*0Sstevel@tonic-gate display_status_1(msg, min_stat, GSS_C_MECH_CODE, mech_oid); 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate /* 218*0Sstevel@tonic-gate * Open an fd for the given address and connect asynchronously. Wait 219*0Sstevel@tonic-gate * KADMIND_CONNECT_TIMEOUT seconds or till it succeeds. If it succeeds 220*0Sstevel@tonic-gate * change fd to blocking and return it, else return -1. 221*0Sstevel@tonic-gate */ 222*0Sstevel@tonic-gate static int 223*0Sstevel@tonic-gate get_connection(struct netconfig *nconf, struct netbuf netaddr) 224*0Sstevel@tonic-gate { 225*0Sstevel@tonic-gate struct t_info tinfo; 226*0Sstevel@tonic-gate struct t_call sndcall; 227*0Sstevel@tonic-gate struct t_call *rcvcall = NULL; 228*0Sstevel@tonic-gate int connect_time; 229*0Sstevel@tonic-gate int flags; 230*0Sstevel@tonic-gate int fd; 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate (void) memset(&tinfo, 0, sizeof (tinfo)); 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* we'l open with O_NONBLOCK and avoid an fcntl */ 235*0Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR | O_NONBLOCK, &tinfo); 236*0Sstevel@tonic-gate if (fd == -1) { 237*0Sstevel@tonic-gate return (-1); 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate if (t_bind(fd, (struct t_bind *)NULL, (struct t_bind *)NULL) == -1) { 241*0Sstevel@tonic-gate (void) close(fd); 242*0Sstevel@tonic-gate return (-1); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate /* we can't connect unless fd is in IDLE state */ 246*0Sstevel@tonic-gate if (t_getstate(fd) != T_IDLE) { 247*0Sstevel@tonic-gate (void) close(fd); 248*0Sstevel@tonic-gate return (-1); 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* setup connect parameters */ 252*0Sstevel@tonic-gate netaddr.len = netaddr.maxlen = __rpc_get_a_size(tinfo.addr); 253*0Sstevel@tonic-gate sndcall.addr = netaddr; 254*0Sstevel@tonic-gate sndcall.opt.len = sndcall.udata.len = 0; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate /* we wait for KADMIND_CONNECT_TIMEOUT seconds from now */ 257*0Sstevel@tonic-gate connect_time = time(NULL) + KADMIND_CONNECT_TIMEOUT; 258*0Sstevel@tonic-gate if (t_connect(fd, &sndcall, rcvcall) != 0) { 259*0Sstevel@tonic-gate if (t_errno != TNODATA) { 260*0Sstevel@tonic-gate (void) close(fd); 261*0Sstevel@tonic-gate return (-1); 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* loop till success or timeout */ 266*0Sstevel@tonic-gate for (;;) { 267*0Sstevel@tonic-gate if (t_rcvconnect(fd, rcvcall) == 0) 268*0Sstevel@tonic-gate break; 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate if (t_errno != TNODATA || time(NULL) > connect_time) { 271*0Sstevel@tonic-gate /* we have either timed out or caught an error */ 272*0Sstevel@tonic-gate (void) close(fd); 273*0Sstevel@tonic-gate if (rcvcall != NULL) 274*0Sstevel@tonic-gate t_free((char *)rcvcall, T_CALL); 275*0Sstevel@tonic-gate return (-1); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate sleep(1); 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate /* make the fd blocking (synchronous) */ 281*0Sstevel@tonic-gate flags = fcntl(fd, F_GETFL, 0); 282*0Sstevel@tonic-gate (void) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 283*0Sstevel@tonic-gate if (rcvcall != NULL) 284*0Sstevel@tonic-gate t_free((char *)rcvcall, T_CALL); 285*0Sstevel@tonic-gate return (fd); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate /* 289*0Sstevel@tonic-gate * Open an RPCSEC_GSS connection and 290*0Sstevel@tonic-gate * get a client handle to use for future RPCSEC calls. 291*0Sstevel@tonic-gate * 292*0Sstevel@tonic-gate * This function is only used when changing passwords and 293*0Sstevel@tonic-gate * the kpasswd_protocol is RPCSEC_GSS 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate static int 296*0Sstevel@tonic-gate _kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle, 297*0Sstevel@tonic-gate char *client_name, 298*0Sstevel@tonic-gate char *service_name) 299*0Sstevel@tonic-gate { 300*0Sstevel@tonic-gate struct netbuf netaddr; 301*0Sstevel@tonic-gate struct hostent *hp; 302*0Sstevel@tonic-gate int fd; 303*0Sstevel@tonic-gate struct sockaddr_in addr; 304*0Sstevel@tonic-gate struct sockaddr_in *sin; 305*0Sstevel@tonic-gate struct netconfig *nconf; 306*0Sstevel@tonic-gate int code = 0; 307*0Sstevel@tonic-gate generic_ret *r; 308*0Sstevel@tonic-gate char *ccname_orig; 309*0Sstevel@tonic-gate char *iprop_svc; 310*0Sstevel@tonic-gate boolean_t iprop_enable = B_FALSE; 311*0Sstevel@tonic-gate char mech[] = "kerberos_v5"; 312*0Sstevel@tonic-gate gss_OID mech_oid; 313*0Sstevel@tonic-gate gss_OID_set_desc oid_set; 314*0Sstevel@tonic-gate gss_name_t gss_client; 315*0Sstevel@tonic-gate gss_buffer_desc input_name; 316*0Sstevel@tonic-gate gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL; 317*0Sstevel@tonic-gate rpc_gss_options_req_t options_req; 318*0Sstevel@tonic-gate rpc_gss_options_ret_t options_ret; 319*0Sstevel@tonic-gate rpc_gss_service_t service = rpc_gss_svc_privacy; 320*0Sstevel@tonic-gate OM_uint32 gssstat, minor_stat; 321*0Sstevel@tonic-gate void *handlep; 322*0Sstevel@tonic-gate enum clnt_stat rpc_err_code; 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate hp = gethostbyname(handle->params.admin_server); 325*0Sstevel@tonic-gate if (hp == (struct hostent *)NULL) { 326*0Sstevel@tonic-gate code = KADM5_BAD_SERVER_NAME; 327*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 328*0Sstevel@tonic-gate "bad server name\n")); 329*0Sstevel@tonic-gate goto cleanup; 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate memset(&addr, 0, sizeof (addr)); 333*0Sstevel@tonic-gate addr.sin_family = hp->h_addrtype; 334*0Sstevel@tonic-gate (void) memcpy((char *)&addr.sin_addr, (char *)hp->h_addr, 335*0Sstevel@tonic-gate sizeof (addr.sin_addr)); 336*0Sstevel@tonic-gate addr.sin_port = htons((ushort_t)handle->params.kadmind_port); 337*0Sstevel@tonic-gate sin = &addr; 338*0Sstevel@tonic-gate #ifdef DEBUG 339*0Sstevel@tonic-gate printf("kadmin_port %d\n", handle->params.kadmind_port); 340*0Sstevel@tonic-gate printf("addr: sin_port: %d, sin_family: %d, sin_zero %s\n", 341*0Sstevel@tonic-gate addr.sin_port, addr.sin_family, addr.sin_zero); 342*0Sstevel@tonic-gate printf("sin_addr %d:%d\n", addr.sin_addr.S_un.S_un_w.s_w1, 343*0Sstevel@tonic-gate addr.sin_addr.S_un.S_un_w.s_w2); 344*0Sstevel@tonic-gate #endif 345*0Sstevel@tonic-gate if ((handlep = setnetconfig()) == (void *) NULL) { 346*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 347*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 348*0Sstevel@tonic-gate "cannot get any transport information")); 349*0Sstevel@tonic-gate goto error; 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate while (nconf = getnetconfig(handlep)) { 353*0Sstevel@tonic-gate if ((nconf->nc_semantics == NC_TPI_COTS_ORD) && 354*0Sstevel@tonic-gate (strcmp(nconf->nc_protofmly, NC_INET) == 0) && 355*0Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) == 0)) 356*0Sstevel@tonic-gate break; 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if (nconf == (struct netconfig *)NULL) 360*0Sstevel@tonic-gate goto error; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* Transform addr to netbuf */ 363*0Sstevel@tonic-gate (void) memset(&netaddr, 0, sizeof (netaddr)); 364*0Sstevel@tonic-gate netaddr.buf = (char *)sin; 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate /* get an fd connected to the given address */ 367*0Sstevel@tonic-gate fd = get_connection(nconf, netaddr); 368*0Sstevel@tonic-gate if (fd == -1) { 369*0Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 370*0Sstevel@tonic-gate "unable to open connection to ADMIN server " 371*0Sstevel@tonic-gate "(t_error %i)"), t_errno); 372*0Sstevel@tonic-gate code = KADM5_RPC_ERROR; 373*0Sstevel@tonic-gate goto error; 374*0Sstevel@tonic-gate } 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate #ifdef DEBUG 377*0Sstevel@tonic-gate printf("fd: %d, KADM: %d, KADMVERS %d\n", fd, KADM, KADMVERS); 378*0Sstevel@tonic-gate printf("nconf: nc_netid: %s, nc_semantics: %d, nc_flag: %d, " 379*0Sstevel@tonic-gate "nc_protofmly: %s\n", 380*0Sstevel@tonic-gate nconf->nc_netid, nconf->nc_semantics, nconf->nc_flag, 381*0Sstevel@tonic-gate nconf->nc_protofmly); 382*0Sstevel@tonic-gate printf("nc_proto: %s, nc_device: %s, nc_nlookups: %d, nc_used: %d\n", 383*0Sstevel@tonic-gate nconf->nc_proto, nconf->nc_device, nconf->nc_nlookups, 384*0Sstevel@tonic-gate nconf->nc_unused); 385*0Sstevel@tonic-gate printf("netaddr: maxlen %d, buf: %s, len: %d\n", netaddr.maxlen, 386*0Sstevel@tonic-gate netaddr.buf, netaddr.len); 387*0Sstevel@tonic-gate #endif 388*0Sstevel@tonic-gate /* 389*0Sstevel@tonic-gate * Tell clnt_tli_create that given fd is already connected 390*0Sstevel@tonic-gate * 391*0Sstevel@tonic-gate * If the service_name and client_name are iprop-centric, 392*0Sstevel@tonic-gate * we need to clnt_tli_create to the appropriate RPC prog 393*0Sstevel@tonic-gate */ 394*0Sstevel@tonic-gate iprop_svc = strdup(KIPROP_SVC_NAME); 395*0Sstevel@tonic-gate if (iprop_svc == NULL) 396*0Sstevel@tonic-gate return (ENOMEM); 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate if ((strstr(service_name, iprop_svc) != NULL) && 399*0Sstevel@tonic-gate (strstr(client_name, iprop_svc) != NULL)) { 400*0Sstevel@tonic-gate iprop_enable = B_TRUE; 401*0Sstevel@tonic-gate handle->clnt = clnt_tli_create(fd, nconf, NULL, 402*0Sstevel@tonic-gate KRB5_IPROP_PROG, KRB5_IPROP_VERS, 0, 0); 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate else 405*0Sstevel@tonic-gate handle->clnt = clnt_tli_create(fd, nconf, NULL, 406*0Sstevel@tonic-gate KADM, KADMVERS, 0, 0); 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate if (iprop_svc) 409*0Sstevel@tonic-gate free(iprop_svc); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate if (handle->clnt == NULL) { 412*0Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 413*0Sstevel@tonic-gate "clnt_tli_create failed\n")); 414*0Sstevel@tonic-gate code = KADM5_RPC_ERROR; 415*0Sstevel@tonic-gate (void) close(fd); 416*0Sstevel@tonic-gate goto error; 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate /* 419*0Sstevel@tonic-gate * The rpc-handle was created on an fd opened and connected 420*0Sstevel@tonic-gate * by us, so we have to explicitly tell rpc to close it. 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate if (clnt_control(handle->clnt, CLSET_FD_CLOSE, NULL) != TRUE) { 423*0Sstevel@tonic-gate clnt_pcreateerror("ERROR:"); 424*0Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 425*0Sstevel@tonic-gate "clnt_control failed to set CLSET_FD_CLOSE")); 426*0Sstevel@tonic-gate code = KADM5_RPC_ERROR; 427*0Sstevel@tonic-gate (void) close(fd); 428*0Sstevel@tonic-gate goto error; 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate handle->lhandle->clnt = handle->clnt; 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate /* now that handle->clnt is set, we can check the handle */ 434*0Sstevel@tonic-gate if (code = _kadm5_check_handle((void *) handle)) 435*0Sstevel@tonic-gate goto error; 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* 438*0Sstevel@tonic-gate * The RPC connection is open; establish the GSS-API 439*0Sstevel@tonic-gate * authentication context. 440*0Sstevel@tonic-gate */ 441*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 442*0Sstevel@tonic-gate "have an rpc connection open\n")); 443*0Sstevel@tonic-gate /* use the kadm5 cache */ 444*0Sstevel@tonic-gate ccname_orig = getenv("KRB5CCNAME"); 445*0Sstevel@tonic-gate if (ccname_orig) 446*0Sstevel@tonic-gate ccname_orig = strdup(ccname_orig); 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate (void) krb5_setenv("KRB5CCNAME", handle->cache_name, 1); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, 451*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 452*0Sstevel@tonic-gate "current credential cache: %s"), handle->cache_name); 453*0Sstevel@tonic-gate input_name.value = client_name; 454*0Sstevel@tonic-gate input_name.length = strlen((char *)input_name.value) + 1; 455*0Sstevel@tonic-gate gssstat = gss_import_name(&minor_stat, &input_name, 456*0Sstevel@tonic-gate (gss_OID)gss_nt_krb5_name, &gss_client); 457*0Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) { 458*0Sstevel@tonic-gate code = KADM5_GSS_ERROR; 459*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, 460*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 461*0Sstevel@tonic-gate "gss_import_name failed for client name\n")); 462*0Sstevel@tonic-gate goto error; 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) { 466*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, 467*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 468*0Sstevel@tonic-gate "Invalid mechanism oid <%s>"), mech); 469*0Sstevel@tonic-gate goto error; 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate oid_set.count = 1; 473*0Sstevel@tonic-gate oid_set.elements = mech_oid; 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate gssstat = gss_acquire_cred(&minor_stat, gss_client, 0, 476*0Sstevel@tonic-gate &oid_set, GSS_C_INITIATE, 477*0Sstevel@tonic-gate &gss_client_creds, NULL, NULL); 478*0Sstevel@tonic-gate (void) gss_release_name(&minor_stat, &gss_client); 479*0Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) { 480*0Sstevel@tonic-gate code = KADM5_GSS_ERROR; 481*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, 482*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 483*0Sstevel@tonic-gate "could not acquire credentials, " 484*0Sstevel@tonic-gate "major error code: %d\n"), gssstat); 485*0Sstevel@tonic-gate goto error; 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate handle->my_cred = gss_client_creds; 488*0Sstevel@tonic-gate options_req.my_cred = gss_client_creds; 489*0Sstevel@tonic-gate options_req.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; 490*0Sstevel@tonic-gate options_req.time_req = 0; 491*0Sstevel@tonic-gate options_req.input_channel_bindings = NULL; 492*0Sstevel@tonic-gate #ifndef INIT_TEST 493*0Sstevel@tonic-gate handle->clnt->cl_auth = rpc_gss_seccreate(handle->clnt, 494*0Sstevel@tonic-gate service_name, 495*0Sstevel@tonic-gate mech, 496*0Sstevel@tonic-gate service, 497*0Sstevel@tonic-gate NULL, 498*0Sstevel@tonic-gate &options_req, 499*0Sstevel@tonic-gate &options_ret); 500*0Sstevel@tonic-gate #endif /* ! INIT_TEST */ 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate if (ccname_orig) { 503*0Sstevel@tonic-gate (void) krb5_setenv("KRB5CCNAME", ccname_orig, 1); 504*0Sstevel@tonic-gate free(ccname_orig); 505*0Sstevel@tonic-gate } else 506*0Sstevel@tonic-gate (void) krb5_unsetenv("KRB5CCNAME"); 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate if (handle->clnt->cl_auth == NULL) { 509*0Sstevel@tonic-gate code = KADM5_GSS_ERROR; 510*0Sstevel@tonic-gate display_status(dgettext(TEXT_DOMAIN, 511*0Sstevel@tonic-gate "rpc_gss_seccreate failed\n"), 512*0Sstevel@tonic-gate options_ret.major_status, 513*0Sstevel@tonic-gate options_ret.minor_status, 514*0Sstevel@tonic-gate mech); 515*0Sstevel@tonic-gate goto error; 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate /* 519*0Sstevel@tonic-gate * Bypass the remainder of the code and return straightaway 520*0Sstevel@tonic-gate * if the gss service requested is kiprop 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate if (iprop_enable == B_TRUE) { 523*0Sstevel@tonic-gate code = 0; 524*0Sstevel@tonic-gate goto cleanup; 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate r = init_1(&handle->api_version, handle->clnt, &rpc_err_code); 528*0Sstevel@tonic-gate if (r == NULL) { 529*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 530*0Sstevel@tonic-gate "error during admin api initialization\n")); 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate if (rpc_err_code == RPC_CANTENCODEARGS) { 533*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 534*0Sstevel@tonic-gate "encryption needed to encode RPC data may not be " 535*0Sstevel@tonic-gate "installed/configured on this system")); 536*0Sstevel@tonic-gate code = KADM5_RPC_ERROR_CANTENCODEARGS; 537*0Sstevel@tonic-gate } else if (rpc_err_code == RPC_CANTDECODEARGS) { 538*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 539*0Sstevel@tonic-gate "encryption needed to decode RPC data may not be " 540*0Sstevel@tonic-gate "installed/configured on the server")); 541*0Sstevel@tonic-gate code = KADM5_RPC_ERROR_CANTDECODEARGS; 542*0Sstevel@tonic-gate } else 543*0Sstevel@tonic-gate code = KADM5_RPC_ERROR; 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate goto error; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate } 548*0Sstevel@tonic-gate if (r->code) { 549*0Sstevel@tonic-gate code = r->code; 550*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, 551*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 552*0Sstevel@tonic-gate "error during admin api initialization: %d\n"), 553*0Sstevel@tonic-gate r->code); 554*0Sstevel@tonic-gate goto error; 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate error: 557*0Sstevel@tonic-gate cleanup: 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate if (handlep != (void *) NULL) 560*0Sstevel@tonic-gate (void) endnetconfig(handlep); 561*0Sstevel@tonic-gate /* 562*0Sstevel@tonic-gate * gss_client_creds is freed only when there is an error condition, 563*0Sstevel@tonic-gate * given that rpc_gss_seccreate() will assign the cred pointer to the 564*0Sstevel@tonic-gate * my_cred member in the auth handle's private data structure. 565*0Sstevel@tonic-gate */ 566*0Sstevel@tonic-gate if (code && (gss_client_creds != GSS_C_NO_CREDENTIAL)) 567*0Sstevel@tonic-gate (void) gss_release_cred(&minor_stat, &gss_client_creds); 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate return (code); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name, 573*0Sstevel@tonic-gate enum init_type init_type, 574*0Sstevel@tonic-gate char *pass, 575*0Sstevel@tonic-gate krb5_ccache ccache_in, 576*0Sstevel@tonic-gate char *service_name, 577*0Sstevel@tonic-gate kadm5_config_params *params_in, 578*0Sstevel@tonic-gate krb5_ui_4 struct_version, 579*0Sstevel@tonic-gate krb5_ui_4 api_version, 580*0Sstevel@tonic-gate void **server_handle) 581*0Sstevel@tonic-gate { 582*0Sstevel@tonic-gate int i; 583*0Sstevel@tonic-gate krb5_creds creds; 584*0Sstevel@tonic-gate krb5_ccache ccache = NULL; 585*0Sstevel@tonic-gate krb5_timestamp now; 586*0Sstevel@tonic-gate OM_uint32 gssstat, minor_stat; 587*0Sstevel@tonic-gate kadm5_server_handle_t handle; 588*0Sstevel@tonic-gate kadm5_config_params params_local; 589*0Sstevel@tonic-gate int code = 0; 590*0Sstevel@tonic-gate krb5_get_init_creds_opt opt; 591*0Sstevel@tonic-gate gss_buffer_desc input_name; 592*0Sstevel@tonic-gate krb5_error_code kret; 593*0Sstevel@tonic-gate krb5_int32 starttime; 594*0Sstevel@tonic-gate char *server = NULL; 595*0Sstevel@tonic-gate krb5_principal serverp = NULL, clientp = NULL; 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 598*0Sstevel@tonic-gate "entering kadm5_init_any\n")); 599*0Sstevel@tonic-gate if (! server_handle) { 600*0Sstevel@tonic-gate return (EINVAL); 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate if (! (handle = malloc(sizeof(*handle)))) { 604*0Sstevel@tonic-gate return (ENOMEM); 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate if (! (handle->lhandle = malloc(sizeof(*handle)))) { 607*0Sstevel@tonic-gate free(handle); 608*0Sstevel@tonic-gate return (ENOMEM); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate handle->magic_number = KADM5_SERVER_HANDLE_MAGIC; 612*0Sstevel@tonic-gate handle->struct_version = struct_version; 613*0Sstevel@tonic-gate handle->api_version = api_version; 614*0Sstevel@tonic-gate handle->clnt = 0; 615*0Sstevel@tonic-gate handle->cache_name = 0; 616*0Sstevel@tonic-gate handle->destroy_cache = 0; 617*0Sstevel@tonic-gate *handle->lhandle = *handle; 618*0Sstevel@tonic-gate handle->lhandle->api_version = KADM5_API_VERSION_2; 619*0Sstevel@tonic-gate handle->lhandle->struct_version = KADM5_STRUCT_VERSION; 620*0Sstevel@tonic-gate handle->lhandle->lhandle = handle->lhandle; 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate kret = krb5_init_context(&handle->context); 623*0Sstevel@tonic-gate if (kret) { 624*0Sstevel@tonic-gate free(handle->lhandle); 625*0Sstevel@tonic-gate free(handle); 626*0Sstevel@tonic-gate return (kret); 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate if(service_name == NULL || client_name == NULL) { 630*0Sstevel@tonic-gate krb5_free_context(handle->context); 631*0Sstevel@tonic-gate free(handle->lhandle); 632*0Sstevel@tonic-gate free(handle); 633*0Sstevel@tonic-gate return (EINVAL); 634*0Sstevel@tonic-gate } 635*0Sstevel@tonic-gate memset((char *) &creds, 0, sizeof(creds)); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate /* 638*0Sstevel@tonic-gate * Verify the version numbers before proceeding; we can't use 639*0Sstevel@tonic-gate * CHECK_HANDLE because not all fields are set yet. 640*0Sstevel@tonic-gate */ 641*0Sstevel@tonic-gate GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION, 642*0Sstevel@tonic-gate KADM5_NEW_LIB_API_VERSION); 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate /* 645*0Sstevel@tonic-gate * Acquire relevant profile entries. In version 2, merge values 646*0Sstevel@tonic-gate * in params_in with values from profile, based on 647*0Sstevel@tonic-gate * params_in->mask. 648*0Sstevel@tonic-gate * 649*0Sstevel@tonic-gate * In version 1, we've given a realm (which may be NULL) instead 650*0Sstevel@tonic-gate * of params_in. So use that realm, make params_in contain an 651*0Sstevel@tonic-gate * empty mask, and behave like version 2. 652*0Sstevel@tonic-gate */ 653*0Sstevel@tonic-gate memset((char *) ¶ms_local, 0, sizeof(params_local)); 654*0Sstevel@tonic-gate if (api_version == KADM5_API_VERSION_1) { 655*0Sstevel@tonic-gate if (params_in) 656*0Sstevel@tonic-gate params_local.mask = KADM5_CONFIG_REALM; 657*0Sstevel@tonic-gate params_in = ¶ms_local; 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate #define ILLEGAL_PARAMS ( \ 661*0Sstevel@tonic-gate KADM5_CONFIG_ACL_FILE | KADM5_CONFIG_ADB_LOCKFILE | \ 662*0Sstevel@tonic-gate KADM5_CONFIG_DBNAME | KADM5_CONFIG_ADBNAME | \ 663*0Sstevel@tonic-gate KADM5_CONFIG_DICT_FILE | KADM5_CONFIG_ADMIN_KEYTAB | \ 664*0Sstevel@tonic-gate KADM5_CONFIG_STASH_FILE | KADM5_CONFIG_MKEY_NAME | \ 665*0Sstevel@tonic-gate KADM5_CONFIG_ENCTYPE | KADM5_CONFIG_MAX_LIFE | \ 666*0Sstevel@tonic-gate KADM5_CONFIG_MAX_RLIFE | KADM5_CONFIG_EXPIRATION | \ 667*0Sstevel@tonic-gate KADM5_CONFIG_FLAGS | KADM5_CONFIG_ENCTYPES | \ 668*0Sstevel@tonic-gate KADM5_CONFIG_MKEY_FROM_KBD) 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate if (params_in && params_in->mask & ILLEGAL_PARAMS) { 671*0Sstevel@tonic-gate krb5_free_context(handle->context); 672*0Sstevel@tonic-gate free(handle->lhandle); 673*0Sstevel@tonic-gate free(handle); 674*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, 675*0Sstevel@tonic-gate "bad client parameters, returning %d"), 676*0Sstevel@tonic-gate KADM5_BAD_CLIENT_PARAMS); 677*0Sstevel@tonic-gate return (KADM5_BAD_CLIENT_PARAMS); 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate if ((code = kadm5_get_config_params(handle->context, 681*0Sstevel@tonic-gate DEFAULT_PROFILE_PATH, 682*0Sstevel@tonic-gate "KRB5_CONFIG", 683*0Sstevel@tonic-gate params_in, 684*0Sstevel@tonic-gate &handle->params))) { 685*0Sstevel@tonic-gate krb5_free_context(handle->context); 686*0Sstevel@tonic-gate free(handle->lhandle); 687*0Sstevel@tonic-gate free(handle); 688*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, 689*0Sstevel@tonic-gate "failed to get config_params, return: %d\n"), code); 690*0Sstevel@tonic-gate return(code); 691*0Sstevel@tonic-gate } 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \ 694*0Sstevel@tonic-gate KADM5_CONFIG_ADMIN_SERVER | \ 695*0Sstevel@tonic-gate KADM5_CONFIG_KADMIND_PORT) 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) { 698*0Sstevel@tonic-gate (void) kadm5_free_config_params(handle->context, 699*0Sstevel@tonic-gate &handle->params); 700*0Sstevel@tonic-gate krb5_free_context(handle->context); 701*0Sstevel@tonic-gate free(handle->lhandle); 702*0Sstevel@tonic-gate free(handle); 703*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 704*0Sstevel@tonic-gate "missing config parameters\n")); 705*0Sstevel@tonic-gate return (KADM5_MISSING_CONF_PARAMS); 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate /* 709*0Sstevel@tonic-gate * Acquire a service ticket for service_name@realm in the name of 710*0Sstevel@tonic-gate * client_name, using password pass (which could be NULL), and 711*0Sstevel@tonic-gate * create a ccache to store them in. If INIT_CREDS, use the 712*0Sstevel@tonic-gate * ccache we were provided instead. 713*0Sstevel@tonic-gate */ 714*0Sstevel@tonic-gate if ((code = krb5_parse_name(handle->context, client_name, 715*0Sstevel@tonic-gate &creds.client))) { 716*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 717*0Sstevel@tonic-gate "could not parse client name\n")); 718*0Sstevel@tonic-gate goto error; 719*0Sstevel@tonic-gate } 720*0Sstevel@tonic-gate clientp = creds.client; 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate if (init_type == INIT_PASS && 723*0Sstevel@tonic-gate handle->params.kpasswd_protocol == KRB5_CHGPWD_CHANGEPW_V2) { 724*0Sstevel@tonic-gate /* 725*0Sstevel@tonic-gate * The 'service_name' is constructed by the caller 726*0Sstevel@tonic-gate * but its done before the parameter which determines 727*0Sstevel@tonic-gate * the kpasswd_protocol is found. The servers that 728*0Sstevel@tonic-gate * support the SET/CHANGE password protocol expect 729*0Sstevel@tonic-gate * a slightly different service principal than 730*0Sstevel@tonic-gate * the normal SEAM kadmind so construct the correct 731*0Sstevel@tonic-gate * name here and then forget it. 732*0Sstevel@tonic-gate */ 733*0Sstevel@tonic-gate char *newsvcname = NULL; 734*0Sstevel@tonic-gate newsvcname = malloc(strlen(KADM5_CHANGEPW_SERVICE) + 735*0Sstevel@tonic-gate strlen(handle->params.realm) + 2); 736*0Sstevel@tonic-gate if (newsvcname == NULL) { 737*0Sstevel@tonic-gate return (ENOMEM); 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate sprintf(newsvcname, "%s@%s", KADM5_CHANGEPW_SERVICE, 740*0Sstevel@tonic-gate handle->params.realm); 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate if ((code = krb5_parse_name(handle->context, newsvcname, 743*0Sstevel@tonic-gate &creds.server))) { 744*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 745*0Sstevel@tonic-gate "could not parse server " 746*0Sstevel@tonic-gate "name\n")); 747*0Sstevel@tonic-gate free(newsvcname); 748*0Sstevel@tonic-gate goto error; 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate free(newsvcname); 751*0Sstevel@tonic-gate } else { 752*0Sstevel@tonic-gate input_name.value = service_name; 753*0Sstevel@tonic-gate input_name.length = strlen((char *)input_name.value) + 1; 754*0Sstevel@tonic-gate gssstat = krb5_gss_import_name(handle->context, 755*0Sstevel@tonic-gate &minor_stat, 756*0Sstevel@tonic-gate &input_name, 757*0Sstevel@tonic-gate (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, 758*0Sstevel@tonic-gate (gss_name_t *)&creds.server); 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) { 761*0Sstevel@tonic-gate code = KADM5_GSS_ERROR; 762*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 763*0Sstevel@tonic-gate "gss_import_name failed for client name\n")); 764*0Sstevel@tonic-gate goto error; 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate serverp = creds.server; 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate /* XXX temporarily fix a bug in krb5_cc_get_type */ 770*0Sstevel@tonic-gate #undef krb5_cc_get_type 771*0Sstevel@tonic-gate #define krb5_cc_get_type(context, cache) ((cache)->ops->prefix) 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate if (init_type == INIT_CREDS) { 774*0Sstevel@tonic-gate ccache = ccache_in; 775*0Sstevel@tonic-gate handle->cache_name = (char *) 776*0Sstevel@tonic-gate malloc(strlen(krb5_cc_get_type(handle->context, ccache)) + 777*0Sstevel@tonic-gate strlen(krb5_cc_get_name(handle->context, ccache)) + 2); 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate if (handle->cache_name == NULL) { 780*0Sstevel@tonic-gate code = ENOMEM; 781*0Sstevel@tonic-gate goto error; 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate sprintf(handle->cache_name, "%s:%s", 784*0Sstevel@tonic-gate krb5_cc_get_type(handle->context, ccache), 785*0Sstevel@tonic-gate krb5_cc_get_name(handle->context, ccache)); 786*0Sstevel@tonic-gate } else { 787*0Sstevel@tonic-gate handle->cache_name = 788*0Sstevel@tonic-gate (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1); 789*0Sstevel@tonic-gate if (handle->cache_name == NULL) { 790*0Sstevel@tonic-gate code = ENOMEM; 791*0Sstevel@tonic-gate goto error; 792*0Sstevel@tonic-gate } 793*0Sstevel@tonic-gate sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE); 794*0Sstevel@tonic-gate mktemp(handle->cache_name + strlen("FILE:")); 795*0Sstevel@tonic-gate 796*0Sstevel@tonic-gate if ((code = krb5_cc_resolve(handle->context, 797*0Sstevel@tonic-gate handle->cache_name, &ccache))) 798*0Sstevel@tonic-gate goto error; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate if ((code = krb5_cc_initialize (handle->context, ccache, 801*0Sstevel@tonic-gate creds.client))) 802*0Sstevel@tonic-gate goto error; 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate handle->destroy_cache = 1; 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate handle->lhandle->cache_name = handle->cache_name; 807*0Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, 808*0Sstevel@tonic-gate "cache created: %s\n"), handle->cache_name); 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate if ((code = krb5_timeofday(handle->context, &now))) 811*0Sstevel@tonic-gate goto error; 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate /* 814*0Sstevel@tonic-gate * Get a ticket, use the method specified in init_type. 815*0Sstevel@tonic-gate */ 816*0Sstevel@tonic-gate creds.times.starttime = 0; /* start timer at KDC */ 817*0Sstevel@tonic-gate creds.times.endtime = 0; /* endtime will be limited by service */ 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate memset(&opt, 0, sizeof (opt)); 820*0Sstevel@tonic-gate krb5_get_init_creds_opt_init(&opt); 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate if (creds.times.endtime) { 823*0Sstevel@tonic-gate if (creds.times.starttime) 824*0Sstevel@tonic-gate starttime = creds.times.starttime; 825*0Sstevel@tonic-gate else 826*0Sstevel@tonic-gate starttime = now; 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate krb5_get_init_creds_opt_set_tkt_life(&opt, 829*0Sstevel@tonic-gate creds.times.endtime - starttime); 830*0Sstevel@tonic-gate } 831*0Sstevel@tonic-gate code = krb5_unparse_name(handle->context, creds.server, &server); 832*0Sstevel@tonic-gate if (code) 833*0Sstevel@tonic-gate goto error; 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate if (init_type == INIT_PASS) { 836*0Sstevel@tonic-gate code = krb5_get_init_creds_password(handle->context, 837*0Sstevel@tonic-gate &creds, creds.client, pass, NULL, 838*0Sstevel@tonic-gate NULL, creds.times.starttime, 839*0Sstevel@tonic-gate server, &opt); 840*0Sstevel@tonic-gate } else if (init_type == INIT_SKEY) { 841*0Sstevel@tonic-gate krb5_keytab kt = NULL; 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate if (!(pass && (code = krb5_kt_resolve(handle->context, 844*0Sstevel@tonic-gate pass, &kt)))) { 845*0Sstevel@tonic-gate code = krb5_get_init_creds_keytab( 846*0Sstevel@tonic-gate handle->context, 847*0Sstevel@tonic-gate &creds, creds.client, kt, 848*0Sstevel@tonic-gate creds.times.starttime, 849*0Sstevel@tonic-gate server, &opt); 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate if (pass) 852*0Sstevel@tonic-gate krb5_kt_close(handle->context, kt); 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate /* Improved error messages */ 857*0Sstevel@tonic-gate if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) 858*0Sstevel@tonic-gate code = KADM5_BAD_PASSWORD; 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) 861*0Sstevel@tonic-gate code = KADM5_SECURE_PRINC_MISSING; 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate if (code != 0) { 864*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, 865*0Sstevel@tonic-gate "failed to obtain credentials cache\n")); 866*0Sstevel@tonic-gate goto error; 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate /* 870*0Sstevel@tonic-gate * If we got this far, save the creds in the cache. 871*0Sstevel@tonic-gate */ 872*0Sstevel@tonic-gate if (ccache) { 873*0Sstevel@tonic-gate code = krb5_cc_store_cred(handle->context, ccache, &creds); 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "obtained credentials cache\n")); 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate #ifdef ZEROPASSWD 879*0Sstevel@tonic-gate if (pass != NULL) 880*0Sstevel@tonic-gate memset(pass, 0, strlen(pass)); 881*0Sstevel@tonic-gate #endif 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate if (init_type != INIT_PASS || 884*0Sstevel@tonic-gate handle->params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC) { 885*0Sstevel@tonic-gate code = _kadm5_initialize_rpcsec_gss_handle(handle, 886*0Sstevel@tonic-gate client_name, service_name); 887*0Sstevel@tonic-gate if (code != 0) 888*0Sstevel@tonic-gate goto error; 889*0Sstevel@tonic-gate } 890*0Sstevel@tonic-gate 891*0Sstevel@tonic-gate *server_handle = (void *) handle; 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate if (init_type != INIT_CREDS) 894*0Sstevel@tonic-gate krb5_cc_close(handle->context, ccache); 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate goto cleanup; 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate error: 899*0Sstevel@tonic-gate /* 900*0Sstevel@tonic-gate * Note that it is illegal for this code to execute if "handle" 901*0Sstevel@tonic-gate * has not been allocated and initialized. I.e., don't use "goto 902*0Sstevel@tonic-gate * error" before the block of code at the top of the function 903*0Sstevel@tonic-gate * that allocates and initializes "handle". 904*0Sstevel@tonic-gate */ 905*0Sstevel@tonic-gate if (handle->cache_name) 906*0Sstevel@tonic-gate free(handle->cache_name); 907*0Sstevel@tonic-gate if (handle->destroy_cache && ccache) 908*0Sstevel@tonic-gate krb5_cc_destroy(handle->context, ccache); 909*0Sstevel@tonic-gate if(handle->clnt && handle->clnt->cl_auth) 910*0Sstevel@tonic-gate AUTH_DESTROY(handle->clnt->cl_auth); 911*0Sstevel@tonic-gate if(handle->clnt) 912*0Sstevel@tonic-gate clnt_destroy(handle->clnt); 913*0Sstevel@tonic-gate (void) kadm5_free_config_params(handle->context, &handle->params); 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate cleanup: 916*0Sstevel@tonic-gate if (server) 917*0Sstevel@tonic-gate free(server); 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate /* 920*0Sstevel@tonic-gate * Creds server and client members may actually be different 921*0Sstevel@tonic-gate * from when initially passed into the get_init_* functions. 922*0Sstevel@tonic-gate * So we must free the members we allocated above since get_init 923*0Sstevel@tonic-gate * zeros the members out, without freeing first. 924*0Sstevel@tonic-gate */ 925*0Sstevel@tonic-gate if (clientp != NULL) { 926*0Sstevel@tonic-gate krb5_free_principal(handle->context, clientp); 927*0Sstevel@tonic-gate clientp = NULL; 928*0Sstevel@tonic-gate } 929*0Sstevel@tonic-gate if (serverp != NULL) { 930*0Sstevel@tonic-gate krb5_free_principal(handle->context, serverp); 931*0Sstevel@tonic-gate serverp = NULL; 932*0Sstevel@tonic-gate } 933*0Sstevel@tonic-gate 934*0Sstevel@tonic-gate krb5_free_cred_contents(handle->context, &creds); 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate /* 937*0Sstevel@tonic-gate * Dont clean up the handle if the code is OK (code==0) 938*0Sstevel@tonic-gate * because it is returned to the caller in the 'server_handle' 939*0Sstevel@tonic-gate * ptr. 940*0Sstevel@tonic-gate */ 941*0Sstevel@tonic-gate if (code) { 942*0Sstevel@tonic-gate krb5_free_context(handle->context); 943*0Sstevel@tonic-gate free(handle->lhandle); 944*0Sstevel@tonic-gate free(handle); 945*0Sstevel@tonic-gate } 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate return (code); 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate 950*0Sstevel@tonic-gate kadm5_ret_t 951*0Sstevel@tonic-gate kadm5_destroy(void *server_handle) 952*0Sstevel@tonic-gate { 953*0Sstevel@tonic-gate krb5_ccache ccache = NULL; 954*0Sstevel@tonic-gate int code = KADM5_OK; 955*0Sstevel@tonic-gate kadm5_server_handle_t handle = 956*0Sstevel@tonic-gate (kadm5_server_handle_t) server_handle; 957*0Sstevel@tonic-gate OM_uint32 min_stat; 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate CHECK_HANDLE(server_handle); 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate if (handle->destroy_cache && handle->cache_name) { 962*0Sstevel@tonic-gate if ((code = krb5_cc_resolve(handle->context, 963*0Sstevel@tonic-gate handle->cache_name, &ccache)) == 0) 964*0Sstevel@tonic-gate code = krb5_cc_destroy (handle->context, ccache); 965*0Sstevel@tonic-gate } 966*0Sstevel@tonic-gate if (handle->cache_name) 967*0Sstevel@tonic-gate free(handle->cache_name); 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate if (handle->clnt && handle->clnt->cl_auth) { 970*0Sstevel@tonic-gate /* 971*0Sstevel@tonic-gate * Since kadm5 doesn't use the default credentials we 972*0Sstevel@tonic-gate * must clean this up manually. 973*0Sstevel@tonic-gate */ 974*0Sstevel@tonic-gate if (handle->my_cred != GSS_C_NO_CREDENTIAL) 975*0Sstevel@tonic-gate (void) gss_release_cred(&min_stat, &handle->my_cred); 976*0Sstevel@tonic-gate AUTH_DESTROY(handle->clnt->cl_auth); 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate if (handle->clnt) 979*0Sstevel@tonic-gate clnt_destroy(handle->clnt); 980*0Sstevel@tonic-gate if (handle->lhandle) 981*0Sstevel@tonic-gate free (handle->lhandle); 982*0Sstevel@tonic-gate 983*0Sstevel@tonic-gate kadm5_free_config_params(handle->context, &handle->params); 984*0Sstevel@tonic-gate krb5_free_context(handle->context); 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate handle->magic_number = 0; 987*0Sstevel@tonic-gate free(handle); 988*0Sstevel@tonic-gate 989*0Sstevel@tonic-gate return (code); 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate /*ARGSUSED*/ 993*0Sstevel@tonic-gate kadm5_ret_t 994*0Sstevel@tonic-gate kadm5_flush(void *server_handle) 995*0Sstevel@tonic-gate { 996*0Sstevel@tonic-gate return (KADM5_OK); 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate int 1000*0Sstevel@tonic-gate _kadm5_check_handle(void *handle) 1001*0Sstevel@tonic-gate { 1002*0Sstevel@tonic-gate CHECK_HANDLE(handle); 1003*0Sstevel@tonic-gate return (0); 1004*0Sstevel@tonic-gate } 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate /* 1007*0Sstevel@tonic-gate * Stub function for kadmin. It was created to eliminate the dependency on 1008*0Sstevel@tonic-gate * libkdb's ulog functions. The srv equivalent makes the actual calls. 1009*0Sstevel@tonic-gate */ 1010*0Sstevel@tonic-gate krb5_error_code 1011*0Sstevel@tonic-gate kadm5_init_iprop(void *handle) 1012*0Sstevel@tonic-gate { 1013*0Sstevel@tonic-gate return (0); 1014*0Sstevel@tonic-gate } 1015