10Sstevel@tonic-gate /*
26656Ssemery * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
6*7934SMark.Phalan@Sun.COM
7*7934SMark.Phalan@Sun.COM
8*7934SMark.Phalan@Sun.COM /*
9*7934SMark.Phalan@Sun.COM * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
10*7934SMark.Phalan@Sun.COM */
110Sstevel@tonic-gate
120Sstevel@tonic-gate /*
130Sstevel@tonic-gate * Copyright (C) 1998 by the FundsXpress, INC.
140Sstevel@tonic-gate *
150Sstevel@tonic-gate * All rights reserved.
160Sstevel@tonic-gate *
170Sstevel@tonic-gate * Export of this software from the United States of America may require
180Sstevel@tonic-gate * a specific license from the United States Government. It is the
190Sstevel@tonic-gate * responsibility of any person or organization contemplating export to
200Sstevel@tonic-gate * obtain such a license before exporting.
210Sstevel@tonic-gate *
220Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
230Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
240Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
250Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
260Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
270Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining
280Sstevel@tonic-gate * to distribution of the software without specific, written prior
290Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of
300Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
310Sstevel@tonic-gate * or implied warranty.
320Sstevel@tonic-gate *
330Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
340Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
350Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
360Sstevel@tonic-gate */
370Sstevel@tonic-gate
380Sstevel@tonic-gate #include <stdio.h>
390Sstevel@tonic-gate #include <netdb.h>
404960Swillf #include "autoconf.h"
412881Smp153739 #ifdef HAVE_MEMORY_H
420Sstevel@tonic-gate #include <memory.h>
432881Smp153739 #endif
440Sstevel@tonic-gate #include <string.h>
450Sstevel@tonic-gate #include <com_err.h>
460Sstevel@tonic-gate #include <sys/types.h>
470Sstevel@tonic-gate #include <sys/socket.h>
480Sstevel@tonic-gate #include <netinet/in.h>
494960Swillf #include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */
500Sstevel@tonic-gate #include <krb5.h>
510Sstevel@tonic-gate #ifdef __STDC__
520Sstevel@tonic-gate #include <stdlib.h>
530Sstevel@tonic-gate #endif
540Sstevel@tonic-gate #include <libintl.h>
550Sstevel@tonic-gate
562881Smp153739 #include <kadm5/admin.h>
572881Smp153739 #include <kadm5/kadm_rpc.h>
582881Smp153739 #include "client_internal.h"
592881Smp153739
600Sstevel@tonic-gate #include <syslog.h>
610Sstevel@tonic-gate #include <gssapi/gssapi.h>
620Sstevel@tonic-gate #include <gssapi_krb5.h>
630Sstevel@tonic-gate #include <gssapiP_krb5.h>
640Sstevel@tonic-gate #include <rpc/clnt.h>
652881Smp153739
660Sstevel@tonic-gate #include <iprop_hdr.h>
670Sstevel@tonic-gate #include "iprop.h"
680Sstevel@tonic-gate
690Sstevel@tonic-gate #define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX"
700Sstevel@tonic-gate
712881Smp153739 static int old_auth_gssapi = 0;
720Sstevel@tonic-gate /* connection timeout to kadmind in seconds */
730Sstevel@tonic-gate #define KADMIND_CONNECT_TIMEOUT 25
740Sstevel@tonic-gate
750Sstevel@tonic-gate int _kadm5_check_handle();
760Sstevel@tonic-gate
770Sstevel@tonic-gate enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS };
780Sstevel@tonic-gate
790Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name,
800Sstevel@tonic-gate enum init_type init_type,
810Sstevel@tonic-gate char *pass,
820Sstevel@tonic-gate krb5_ccache ccache_in,
830Sstevel@tonic-gate char *service_name,
840Sstevel@tonic-gate kadm5_config_params *params,
850Sstevel@tonic-gate krb5_ui_4 struct_version,
860Sstevel@tonic-gate krb5_ui_4 api_version,
874960Swillf char **db_args,
880Sstevel@tonic-gate void **server_handle);
890Sstevel@tonic-gate
kadm5_init_with_creds(char * client_name,krb5_ccache ccache,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)900Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_creds(char *client_name,
910Sstevel@tonic-gate krb5_ccache ccache,
920Sstevel@tonic-gate char *service_name,
930Sstevel@tonic-gate kadm5_config_params *params,
940Sstevel@tonic-gate krb5_ui_4 struct_version,
950Sstevel@tonic-gate krb5_ui_4 api_version,
964960Swillf char **db_args,
970Sstevel@tonic-gate void **server_handle)
980Sstevel@tonic-gate {
992881Smp153739 return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache,
1000Sstevel@tonic-gate service_name, params,
1014960Swillf struct_version, api_version, db_args,
1020Sstevel@tonic-gate server_handle);
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate
kadm5_init_with_password(char * client_name,char * pass,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)1060Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
1070Sstevel@tonic-gate char *service_name,
1080Sstevel@tonic-gate kadm5_config_params *params,
1090Sstevel@tonic-gate krb5_ui_4 struct_version,
1100Sstevel@tonic-gate krb5_ui_4 api_version,
1114960Swillf char **db_args,
1120Sstevel@tonic-gate void **server_handle)
1130Sstevel@tonic-gate {
1142881Smp153739 return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
1150Sstevel@tonic-gate service_name, params, struct_version,
1164960Swillf api_version, db_args, server_handle);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate
kadm5_init(char * client_name,char * pass,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)1190Sstevel@tonic-gate kadm5_ret_t kadm5_init(char *client_name, char *pass,
1202881Smp153739 char *service_name,
1212881Smp153739 kadm5_config_params *params,
1222881Smp153739 krb5_ui_4 struct_version,
1232881Smp153739 krb5_ui_4 api_version,
1244960Swillf char **db_args,
1252881Smp153739 void **server_handle)
1260Sstevel@tonic-gate {
1272881Smp153739 return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
1280Sstevel@tonic-gate service_name, params, struct_version,
1294960Swillf api_version, db_args, server_handle);
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate
kadm5_init_with_skey(char * client_name,char * keytab,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)1320Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
1330Sstevel@tonic-gate char *service_name,
1340Sstevel@tonic-gate kadm5_config_params *params,
1350Sstevel@tonic-gate krb5_ui_4 struct_version,
1360Sstevel@tonic-gate krb5_ui_4 api_version,
1374960Swillf char **db_args,
1380Sstevel@tonic-gate void **server_handle)
1390Sstevel@tonic-gate {
1402881Smp153739 return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL,
1410Sstevel@tonic-gate service_name, params, struct_version,
1424960Swillf api_version, db_args, server_handle);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate krb5_error_code kadm5_free_config_params();
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate static void
display_status_1(m,code,type,mech)1480Sstevel@tonic-gate display_status_1(m, code, type, mech)
1490Sstevel@tonic-gate char *m;
1500Sstevel@tonic-gate OM_uint32 code;
1510Sstevel@tonic-gate int type;
1520Sstevel@tonic-gate const gss_OID mech;
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate OM_uint32 maj_stat, min_stat;
1550Sstevel@tonic-gate gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
1560Sstevel@tonic-gate OM_uint32 msg_ctx;
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate msg_ctx = 0;
1590Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, "%s\n", m);
1600Sstevel@tonic-gate /* LINTED */
1610Sstevel@tonic-gate while (1) {
1620Sstevel@tonic-gate maj_stat = gss_display_status(&min_stat, code,
1630Sstevel@tonic-gate type, mech,
1640Sstevel@tonic-gate &msg_ctx, &msg);
1650Sstevel@tonic-gate if (maj_stat != GSS_S_COMPLETE) {
1660Sstevel@tonic-gate syslog(LOG_ERR,
1670Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
1680Sstevel@tonic-gate "error in gss_display_status"
1690Sstevel@tonic-gate " called from <%s>\n"), m);
1700Sstevel@tonic-gate break;
1710Sstevel@tonic-gate } else
1720Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
1730Sstevel@tonic-gate "GSS-API error : %s\n"),
1740Sstevel@tonic-gate m);
1750Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
1760Sstevel@tonic-gate "GSS-API error : %s\n"),
1770Sstevel@tonic-gate (char *)msg.value);
1780Sstevel@tonic-gate if (msg.length != 0)
1790Sstevel@tonic-gate (void) gss_release_buffer(&min_stat, &msg);
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate if (!msg_ctx)
1820Sstevel@tonic-gate break;
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate * Function: display_status
1880Sstevel@tonic-gate *
1890Sstevel@tonic-gate * Purpose: displays GSS-API messages
1900Sstevel@tonic-gate *
1910Sstevel@tonic-gate * Arguments:
1920Sstevel@tonic-gate *
1930Sstevel@tonic-gate * msg a string to be displayed with the message
1940Sstevel@tonic-gate * maj_stat the GSS-API major status code
1950Sstevel@tonic-gate * min_stat the GSS-API minor status code
1960Sstevel@tonic-gate * mech kerberos mech
1970Sstevel@tonic-gate * Effects:
1980Sstevel@tonic-gate *
1990Sstevel@tonic-gate * The GSS-API messages associated with maj_stat and min_stat are
2000Sstevel@tonic-gate * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
2010Sstevel@tonic-gate * followed by a newline.
2020Sstevel@tonic-gate */
2030Sstevel@tonic-gate void
display_status(msg,maj_stat,min_stat,mech)2040Sstevel@tonic-gate display_status(msg, maj_stat, min_stat, mech)
2050Sstevel@tonic-gate char *msg;
2060Sstevel@tonic-gate OM_uint32 maj_stat;
2070Sstevel@tonic-gate OM_uint32 min_stat;
2080Sstevel@tonic-gate char *mech;
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate gss_OID mech_oid;
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) {
2130Sstevel@tonic-gate ADMIN_LOG(LOG_ERR,
2140Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
2150Sstevel@tonic-gate "Invalid mechanism oid <%s>"), mech);
2160Sstevel@tonic-gate return;
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate display_status_1(msg, maj_stat, GSS_C_GSS_CODE, mech_oid);
2200Sstevel@tonic-gate display_status_1(msg, min_stat, GSS_C_MECH_CODE, mech_oid);
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate * Open an fd for the given address and connect asynchronously. Wait
2250Sstevel@tonic-gate * KADMIND_CONNECT_TIMEOUT seconds or till it succeeds. If it succeeds
2260Sstevel@tonic-gate * change fd to blocking and return it, else return -1.
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate static int
get_connection(struct netconfig * nconf,struct netbuf netaddr)2290Sstevel@tonic-gate get_connection(struct netconfig *nconf, struct netbuf netaddr)
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate struct t_info tinfo;
2320Sstevel@tonic-gate struct t_call sndcall;
2330Sstevel@tonic-gate struct t_call *rcvcall = NULL;
2340Sstevel@tonic-gate int connect_time;
2350Sstevel@tonic-gate int flags;
2360Sstevel@tonic-gate int fd;
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate (void) memset(&tinfo, 0, sizeof (tinfo));
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate /* we'l open with O_NONBLOCK and avoid an fcntl */
2410Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR | O_NONBLOCK, &tinfo);
2420Sstevel@tonic-gate if (fd == -1) {
2430Sstevel@tonic-gate return (-1);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate if (t_bind(fd, (struct t_bind *)NULL, (struct t_bind *)NULL) == -1) {
2470Sstevel@tonic-gate (void) close(fd);
2480Sstevel@tonic-gate return (-1);
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate /* we can't connect unless fd is in IDLE state */
2520Sstevel@tonic-gate if (t_getstate(fd) != T_IDLE) {
2530Sstevel@tonic-gate (void) close(fd);
2540Sstevel@tonic-gate return (-1);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /* setup connect parameters */
2580Sstevel@tonic-gate netaddr.len = netaddr.maxlen = __rpc_get_a_size(tinfo.addr);
2590Sstevel@tonic-gate sndcall.addr = netaddr;
2600Sstevel@tonic-gate sndcall.opt.len = sndcall.udata.len = 0;
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate /* we wait for KADMIND_CONNECT_TIMEOUT seconds from now */
2630Sstevel@tonic-gate connect_time = time(NULL) + KADMIND_CONNECT_TIMEOUT;
2640Sstevel@tonic-gate if (t_connect(fd, &sndcall, rcvcall) != 0) {
2650Sstevel@tonic-gate if (t_errno != TNODATA) {
2660Sstevel@tonic-gate (void) close(fd);
2670Sstevel@tonic-gate return (-1);
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate /* loop till success or timeout */
2720Sstevel@tonic-gate for (;;) {
2730Sstevel@tonic-gate if (t_rcvconnect(fd, rcvcall) == 0)
2740Sstevel@tonic-gate break;
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate if (t_errno != TNODATA || time(NULL) > connect_time) {
2770Sstevel@tonic-gate /* we have either timed out or caught an error */
2780Sstevel@tonic-gate (void) close(fd);
2790Sstevel@tonic-gate if (rcvcall != NULL)
2800Sstevel@tonic-gate t_free((char *)rcvcall, T_CALL);
2810Sstevel@tonic-gate return (-1);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate sleep(1);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate /* make the fd blocking (synchronous) */
2870Sstevel@tonic-gate flags = fcntl(fd, F_GETFL, 0);
2880Sstevel@tonic-gate (void) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
2890Sstevel@tonic-gate if (rcvcall != NULL)
2900Sstevel@tonic-gate t_free((char *)rcvcall, T_CALL);
2910Sstevel@tonic-gate return (fd);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate /*
2950Sstevel@tonic-gate * Open an RPCSEC_GSS connection and
2960Sstevel@tonic-gate * get a client handle to use for future RPCSEC calls.
2970Sstevel@tonic-gate *
2980Sstevel@tonic-gate * This function is only used when changing passwords and
2990Sstevel@tonic-gate * the kpasswd_protocol is RPCSEC_GSS
3000Sstevel@tonic-gate */
3010Sstevel@tonic-gate static int
_kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle,char * client_name,char * service_name)3020Sstevel@tonic-gate _kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle,
3030Sstevel@tonic-gate char *client_name,
3040Sstevel@tonic-gate char *service_name)
3050Sstevel@tonic-gate {
3060Sstevel@tonic-gate struct netbuf netaddr;
3070Sstevel@tonic-gate struct hostent *hp;
3080Sstevel@tonic-gate int fd;
3090Sstevel@tonic-gate struct sockaddr_in addr;
3100Sstevel@tonic-gate struct sockaddr_in *sin;
3110Sstevel@tonic-gate struct netconfig *nconf;
3120Sstevel@tonic-gate int code = 0;
3130Sstevel@tonic-gate generic_ret *r;
3140Sstevel@tonic-gate char *ccname_orig;
3150Sstevel@tonic-gate char *iprop_svc;
3160Sstevel@tonic-gate boolean_t iprop_enable = B_FALSE;
3170Sstevel@tonic-gate char mech[] = "kerberos_v5";
3180Sstevel@tonic-gate gss_OID mech_oid;
3190Sstevel@tonic-gate gss_OID_set_desc oid_set;
3200Sstevel@tonic-gate gss_name_t gss_client;
3210Sstevel@tonic-gate gss_buffer_desc input_name;
3220Sstevel@tonic-gate gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL;
3230Sstevel@tonic-gate rpc_gss_options_req_t options_req;
3240Sstevel@tonic-gate rpc_gss_options_ret_t options_ret;
3250Sstevel@tonic-gate rpc_gss_service_t service = rpc_gss_svc_privacy;
3260Sstevel@tonic-gate OM_uint32 gssstat, minor_stat;
3270Sstevel@tonic-gate void *handlep;
3280Sstevel@tonic-gate enum clnt_stat rpc_err_code;
3296656Ssemery char *server = handle->params.admin_server;
3300Sstevel@tonic-gate
3316656Ssemery /*
3326656Ssemery * Try to find the kpasswd_server first if this is for the changepw
3336656Ssemery * service. If defined then it should be resolvable else return error.
3346656Ssemery */
3356656Ssemery if (strncmp(service_name, KADM5_CHANGEPW_HOST_SERVICE,
3366656Ssemery strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0) {
3376656Ssemery if (handle->params.kpasswd_server != NULL)
3386656Ssemery server = handle->params.kpasswd_server;
3396656Ssemery }
3406656Ssemery hp = gethostbyname(server);
3410Sstevel@tonic-gate if (hp == (struct hostent *)NULL) {
3420Sstevel@tonic-gate code = KADM5_BAD_SERVER_NAME;
3430Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
3440Sstevel@tonic-gate "bad server name\n"));
3450Sstevel@tonic-gate goto cleanup;
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate memset(&addr, 0, sizeof (addr));
3490Sstevel@tonic-gate addr.sin_family = hp->h_addrtype;
3500Sstevel@tonic-gate (void) memcpy((char *)&addr.sin_addr, (char *)hp->h_addr,
3510Sstevel@tonic-gate sizeof (addr.sin_addr));
3520Sstevel@tonic-gate addr.sin_port = htons((ushort_t)handle->params.kadmind_port);
3530Sstevel@tonic-gate sin = &addr;
3540Sstevel@tonic-gate #ifdef DEBUG
3550Sstevel@tonic-gate printf("kadmin_port %d\n", handle->params.kadmind_port);
3560Sstevel@tonic-gate printf("addr: sin_port: %d, sin_family: %d, sin_zero %s\n",
3570Sstevel@tonic-gate addr.sin_port, addr.sin_family, addr.sin_zero);
3580Sstevel@tonic-gate printf("sin_addr %d:%d\n", addr.sin_addr.S_un.S_un_w.s_w1,
3590Sstevel@tonic-gate addr.sin_addr.S_un.S_un_w.s_w2);
3600Sstevel@tonic-gate #endif
3610Sstevel@tonic-gate if ((handlep = setnetconfig()) == (void *) NULL) {
3620Sstevel@tonic-gate (void) syslog(LOG_ERR,
3630Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
3640Sstevel@tonic-gate "cannot get any transport information"));
3650Sstevel@tonic-gate goto error;
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate while (nconf = getnetconfig(handlep)) {
3690Sstevel@tonic-gate if ((nconf->nc_semantics == NC_TPI_COTS_ORD) &&
3700Sstevel@tonic-gate (strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
3710Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) == 0))
3720Sstevel@tonic-gate break;
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate if (nconf == (struct netconfig *)NULL)
3760Sstevel@tonic-gate goto error;
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate /* Transform addr to netbuf */
3790Sstevel@tonic-gate (void) memset(&netaddr, 0, sizeof (netaddr));
3800Sstevel@tonic-gate netaddr.buf = (char *)sin;
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate /* get an fd connected to the given address */
3830Sstevel@tonic-gate fd = get_connection(nconf, netaddr);
3840Sstevel@tonic-gate if (fd == -1) {
3850Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
3860Sstevel@tonic-gate "unable to open connection to ADMIN server "
3870Sstevel@tonic-gate "(t_error %i)"), t_errno);
3880Sstevel@tonic-gate code = KADM5_RPC_ERROR;
3890Sstevel@tonic-gate goto error;
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate #ifdef DEBUG
3930Sstevel@tonic-gate printf("fd: %d, KADM: %d, KADMVERS %d\n", fd, KADM, KADMVERS);
3940Sstevel@tonic-gate printf("nconf: nc_netid: %s, nc_semantics: %d, nc_flag: %d, "
3950Sstevel@tonic-gate "nc_protofmly: %s\n",
3960Sstevel@tonic-gate nconf->nc_netid, nconf->nc_semantics, nconf->nc_flag,
3970Sstevel@tonic-gate nconf->nc_protofmly);
3980Sstevel@tonic-gate printf("nc_proto: %s, nc_device: %s, nc_nlookups: %d, nc_used: %d\n",
3990Sstevel@tonic-gate nconf->nc_proto, nconf->nc_device, nconf->nc_nlookups,
4000Sstevel@tonic-gate nconf->nc_unused);
4010Sstevel@tonic-gate printf("netaddr: maxlen %d, buf: %s, len: %d\n", netaddr.maxlen,
4020Sstevel@tonic-gate netaddr.buf, netaddr.len);
4030Sstevel@tonic-gate #endif
4040Sstevel@tonic-gate /*
4050Sstevel@tonic-gate * Tell clnt_tli_create that given fd is already connected
4060Sstevel@tonic-gate *
4070Sstevel@tonic-gate * If the service_name and client_name are iprop-centric,
4080Sstevel@tonic-gate * we need to clnt_tli_create to the appropriate RPC prog
4090Sstevel@tonic-gate */
4100Sstevel@tonic-gate iprop_svc = strdup(KIPROP_SVC_NAME);
4110Sstevel@tonic-gate if (iprop_svc == NULL)
4120Sstevel@tonic-gate return (ENOMEM);
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate if ((strstr(service_name, iprop_svc) != NULL) &&
4150Sstevel@tonic-gate (strstr(client_name, iprop_svc) != NULL)) {
4160Sstevel@tonic-gate iprop_enable = B_TRUE;
4170Sstevel@tonic-gate handle->clnt = clnt_tli_create(fd, nconf, NULL,
4180Sstevel@tonic-gate KRB5_IPROP_PROG, KRB5_IPROP_VERS, 0, 0);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate else
4210Sstevel@tonic-gate handle->clnt = clnt_tli_create(fd, nconf, NULL,
4220Sstevel@tonic-gate KADM, KADMVERS, 0, 0);
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate if (iprop_svc)
4250Sstevel@tonic-gate free(iprop_svc);
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate if (handle->clnt == NULL) {
4280Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
4290Sstevel@tonic-gate "clnt_tli_create failed\n"));
4300Sstevel@tonic-gate code = KADM5_RPC_ERROR;
4310Sstevel@tonic-gate (void) close(fd);
4320Sstevel@tonic-gate goto error;
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate /*
4350Sstevel@tonic-gate * The rpc-handle was created on an fd opened and connected
4360Sstevel@tonic-gate * by us, so we have to explicitly tell rpc to close it.
4370Sstevel@tonic-gate */
4380Sstevel@tonic-gate if (clnt_control(handle->clnt, CLSET_FD_CLOSE, NULL) != TRUE) {
4390Sstevel@tonic-gate clnt_pcreateerror("ERROR:");
4400Sstevel@tonic-gate syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
4410Sstevel@tonic-gate "clnt_control failed to set CLSET_FD_CLOSE"));
4420Sstevel@tonic-gate code = KADM5_RPC_ERROR;
4430Sstevel@tonic-gate (void) close(fd);
4440Sstevel@tonic-gate goto error;
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate handle->lhandle->clnt = handle->clnt;
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /* now that handle->clnt is set, we can check the handle */
4500Sstevel@tonic-gate if (code = _kadm5_check_handle((void *) handle))
4510Sstevel@tonic-gate goto error;
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate * The RPC connection is open; establish the GSS-API
4550Sstevel@tonic-gate * authentication context.
4560Sstevel@tonic-gate */
4570Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
4580Sstevel@tonic-gate "have an rpc connection open\n"));
4590Sstevel@tonic-gate /* use the kadm5 cache */
4600Sstevel@tonic-gate ccname_orig = getenv("KRB5CCNAME");
4610Sstevel@tonic-gate if (ccname_orig)
4620Sstevel@tonic-gate ccname_orig = strdup(ccname_orig);
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate (void) krb5_setenv("KRB5CCNAME", handle->cache_name, 1);
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate ADMIN_LOG(LOG_ERR,
4670Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
4680Sstevel@tonic-gate "current credential cache: %s"), handle->cache_name);
4690Sstevel@tonic-gate input_name.value = client_name;
4700Sstevel@tonic-gate input_name.length = strlen((char *)input_name.value) + 1;
4710Sstevel@tonic-gate gssstat = gss_import_name(&minor_stat, &input_name,
4720Sstevel@tonic-gate (gss_OID)gss_nt_krb5_name, &gss_client);
4730Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) {
4740Sstevel@tonic-gate code = KADM5_GSS_ERROR;
4750Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR,
4760Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
4770Sstevel@tonic-gate "gss_import_name failed for client name\n"));
4780Sstevel@tonic-gate goto error;
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) {
4820Sstevel@tonic-gate ADMIN_LOG(LOG_ERR,
4830Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
4840Sstevel@tonic-gate "Invalid mechanism oid <%s>"), mech);
4850Sstevel@tonic-gate goto error;
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate oid_set.count = 1;
4890Sstevel@tonic-gate oid_set.elements = mech_oid;
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
4920Sstevel@tonic-gate &oid_set, GSS_C_INITIATE,
4930Sstevel@tonic-gate &gss_client_creds, NULL, NULL);
4940Sstevel@tonic-gate (void) gss_release_name(&minor_stat, &gss_client);
4950Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) {
4960Sstevel@tonic-gate code = KADM5_GSS_ERROR;
4970Sstevel@tonic-gate ADMIN_LOG(LOG_ERR,
4980Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
4990Sstevel@tonic-gate "could not acquire credentials, "
5000Sstevel@tonic-gate "major error code: %d\n"), gssstat);
5010Sstevel@tonic-gate goto error;
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate handle->my_cred = gss_client_creds;
5040Sstevel@tonic-gate options_req.my_cred = gss_client_creds;
5050Sstevel@tonic-gate options_req.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
5060Sstevel@tonic-gate options_req.time_req = 0;
5070Sstevel@tonic-gate options_req.input_channel_bindings = NULL;
5080Sstevel@tonic-gate #ifndef INIT_TEST
5090Sstevel@tonic-gate handle->clnt->cl_auth = rpc_gss_seccreate(handle->clnt,
5100Sstevel@tonic-gate service_name,
5110Sstevel@tonic-gate mech,
5120Sstevel@tonic-gate service,
5130Sstevel@tonic-gate NULL,
5140Sstevel@tonic-gate &options_req,
5150Sstevel@tonic-gate &options_ret);
5160Sstevel@tonic-gate #endif /* ! INIT_TEST */
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate if (ccname_orig) {
5190Sstevel@tonic-gate (void) krb5_setenv("KRB5CCNAME", ccname_orig, 1);
5200Sstevel@tonic-gate free(ccname_orig);
5210Sstevel@tonic-gate } else
5220Sstevel@tonic-gate (void) krb5_unsetenv("KRB5CCNAME");
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate if (handle->clnt->cl_auth == NULL) {
5250Sstevel@tonic-gate code = KADM5_GSS_ERROR;
5260Sstevel@tonic-gate display_status(dgettext(TEXT_DOMAIN,
5270Sstevel@tonic-gate "rpc_gss_seccreate failed\n"),
5280Sstevel@tonic-gate options_ret.major_status,
5290Sstevel@tonic-gate options_ret.minor_status,
5300Sstevel@tonic-gate mech);
5310Sstevel@tonic-gate goto error;
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate /*
5350Sstevel@tonic-gate * Bypass the remainder of the code and return straightaway
5360Sstevel@tonic-gate * if the gss service requested is kiprop
5370Sstevel@tonic-gate */
5380Sstevel@tonic-gate if (iprop_enable == B_TRUE) {
5390Sstevel@tonic-gate code = 0;
5400Sstevel@tonic-gate goto cleanup;
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate
543*7934SMark.Phalan@Sun.COM r = init_2(&handle->api_version, handle->clnt);
544*7934SMark.Phalan@Sun.COM /* Solaris Kerberos: 163 resync */
5450Sstevel@tonic-gate if (r == NULL) {
5460Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
5470Sstevel@tonic-gate "error during admin api initialization\n"));
548*7934SMark.Phalan@Sun.COM code = KADM5_RPC_ERROR;
549*7934SMark.Phalan@Sun.COM goto error;
550*7934SMark.Phalan@Sun.COM }
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate if (r->code) {
5530Sstevel@tonic-gate code = r->code;
5540Sstevel@tonic-gate ADMIN_LOG(LOG_ERR,
5550Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
5560Sstevel@tonic-gate "error during admin api initialization: %d\n"),
5570Sstevel@tonic-gate r->code);
5580Sstevel@tonic-gate goto error;
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate error:
5610Sstevel@tonic-gate cleanup:
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate if (handlep != (void *) NULL)
5640Sstevel@tonic-gate (void) endnetconfig(handlep);
5650Sstevel@tonic-gate /*
5660Sstevel@tonic-gate * gss_client_creds is freed only when there is an error condition,
5670Sstevel@tonic-gate * given that rpc_gss_seccreate() will assign the cred pointer to the
5680Sstevel@tonic-gate * my_cred member in the auth handle's private data structure.
5690Sstevel@tonic-gate */
5700Sstevel@tonic-gate if (code && (gss_client_creds != GSS_C_NO_CREDENTIAL))
5710Sstevel@tonic-gate (void) gss_release_cred(&minor_stat, &gss_client_creds);
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate return (code);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate
_kadm5_init_any(char * client_name,enum init_type init_type,char * pass,krb5_ccache ccache_in,char * service_name,kadm5_config_params * params_in,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)5760Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name,
5770Sstevel@tonic-gate enum init_type init_type,
5780Sstevel@tonic-gate char *pass,
5790Sstevel@tonic-gate krb5_ccache ccache_in,
5800Sstevel@tonic-gate char *service_name,
5810Sstevel@tonic-gate kadm5_config_params *params_in,
5820Sstevel@tonic-gate krb5_ui_4 struct_version,
5830Sstevel@tonic-gate krb5_ui_4 api_version,
5844960Swillf char **db_args,
5850Sstevel@tonic-gate void **server_handle)
5860Sstevel@tonic-gate {
5872881Smp153739 int i;
5882881Smp153739 krb5_creds creds;
5892881Smp153739 krb5_ccache ccache = NULL;
5902881Smp153739 krb5_timestamp now;
5912881Smp153739 OM_uint32 gssstat, minor_stat;
5922881Smp153739 kadm5_server_handle_t handle;
5932881Smp153739 kadm5_config_params params_local;
5942881Smp153739 int code = 0;
5952881Smp153739 krb5_get_init_creds_opt opt;
5962881Smp153739 gss_buffer_desc input_name;
5972881Smp153739 krb5_error_code kret;
5982881Smp153739 krb5_int32 starttime;
5992881Smp153739 char *server = NULL;
6002881Smp153739 krb5_principal serverp = NULL, clientp = NULL;
6014807Smp153739 krb5_principal saved_server = NULL;
6022881Smp153739 bool_t cpw = FALSE;
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
6050Sstevel@tonic-gate "entering kadm5_init_any\n"));
6062881Smp153739 if (! server_handle) {
6072881Smp153739 return EINVAL;
6082881Smp153739 }
6090Sstevel@tonic-gate
6102881Smp153739 if (! (handle = malloc(sizeof(*handle)))) {
6112881Smp153739 return ENOMEM;
6122881Smp153739 }
6132881Smp153739 if (! (handle->lhandle = malloc(sizeof(*handle)))) {
6142881Smp153739 free(handle);
6152881Smp153739 return ENOMEM;
6162881Smp153739 }
6170Sstevel@tonic-gate
6182881Smp153739 handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
6192881Smp153739 handle->struct_version = struct_version;
6202881Smp153739 handle->api_version = api_version;
6212881Smp153739 handle->clnt = 0;
6222881Smp153739 handle->cache_name = 0;
6232881Smp153739 handle->destroy_cache = 0;
6242881Smp153739 *handle->lhandle = *handle;
6252881Smp153739 handle->lhandle->api_version = KADM5_API_VERSION_2;
6262881Smp153739 handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
6272881Smp153739 handle->lhandle->lhandle = handle->lhandle;
6280Sstevel@tonic-gate
6292881Smp153739 kret = krb5_init_context(&handle->context);
6300Sstevel@tonic-gate if (kret) {
6310Sstevel@tonic-gate free(handle->lhandle);
6320Sstevel@tonic-gate free(handle);
6330Sstevel@tonic-gate return (kret);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate
6362881Smp153739 if(service_name == NULL || client_name == NULL) {
6372881Smp153739 krb5_free_context(handle->context);
6382881Smp153739 free(handle->lhandle);
6392881Smp153739 free(handle);
6402881Smp153739 return EINVAL;
6412881Smp153739 }
6422881Smp153739 memset((char *) &creds, 0, sizeof(creds));
6430Sstevel@tonic-gate
6442881Smp153739 /*
6452881Smp153739 * Verify the version numbers before proceeding; we can't use
6462881Smp153739 * CHECK_HANDLE because not all fields are set yet.
6472881Smp153739 */
6482881Smp153739 GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
6490Sstevel@tonic-gate KADM5_NEW_LIB_API_VERSION);
6502881Smp153739
6512881Smp153739 /*
6522881Smp153739 * Acquire relevant profile entries. In version 2, merge values
6532881Smp153739 * in params_in with values from profile, based on
6542881Smp153739 * params_in->mask.
6552881Smp153739 *
6562881Smp153739 * In version 1, we've given a realm (which may be NULL) instead
6572881Smp153739 * of params_in. So use that realm, make params_in contain an
6582881Smp153739 * empty mask, and behave like version 2.
6592881Smp153739 */
6602881Smp153739 memset((char *) ¶ms_local, 0, sizeof(params_local));
6612881Smp153739 if (api_version == KADM5_API_VERSION_1) {
6622881Smp153739 if (params_in)
6632881Smp153739 params_local.mask = KADM5_CONFIG_REALM;
6642881Smp153739 params_in = ¶ms_local;
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate #define ILLEGAL_PARAMS ( \
6682881Smp153739 KADM5_CONFIG_ACL_FILE | KADM5_CONFIG_ADB_LOCKFILE | \
6692881Smp153739 KADM5_CONFIG_DBNAME | KADM5_CONFIG_ADBNAME | \
6702881Smp153739 KADM5_CONFIG_DICT_FILE | KADM5_CONFIG_ADMIN_KEYTAB | \
6712881Smp153739 KADM5_CONFIG_STASH_FILE | KADM5_CONFIG_MKEY_NAME | \
6722881Smp153739 KADM5_CONFIG_ENCTYPE | KADM5_CONFIG_MAX_LIFE | \
6732881Smp153739 KADM5_CONFIG_MAX_RLIFE | KADM5_CONFIG_EXPIRATION | \
6742881Smp153739 KADM5_CONFIG_FLAGS | KADM5_CONFIG_ENCTYPES | \
6752881Smp153739 KADM5_CONFIG_MKEY_FROM_KBD)
6760Sstevel@tonic-gate
6772881Smp153739 if (params_in && params_in->mask & ILLEGAL_PARAMS) {
6780Sstevel@tonic-gate krb5_free_context(handle->context);
6790Sstevel@tonic-gate free(handle->lhandle);
6802881Smp153739 free(handle);
6810Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
6820Sstevel@tonic-gate "bad client parameters, returning %d"),
6830Sstevel@tonic-gate KADM5_BAD_CLIENT_PARAMS);
6842881Smp153739 return KADM5_BAD_CLIENT_PARAMS;
6852881Smp153739 }
6860Sstevel@tonic-gate
687*7934SMark.Phalan@Sun.COM if ((code = kadm5_get_config_params(handle->context, 0,
688*7934SMark.Phalan@Sun.COM params_in, &handle->params))) {
6892881Smp153739 krb5_free_context(handle->context);
6902881Smp153739 free(handle->lhandle);
6912881Smp153739 free(handle);
6920Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
6930Sstevel@tonic-gate "failed to get config_params, return: %d\n"), code);
6942881Smp153739 return(code);
6952881Smp153739 }
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
6980Sstevel@tonic-gate KADM5_CONFIG_ADMIN_SERVER | \
6990Sstevel@tonic-gate KADM5_CONFIG_KADMIND_PORT)
7006656Ssemery #define KPW_REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
7016656Ssemery KADM5_CONFIG_KPASSWD_SERVER | \
7026656Ssemery KADM5_CONFIG_KPASSWD_PORT)
7030Sstevel@tonic-gate
7046656Ssemery if (((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) &&
7056656Ssemery ((handle->params.mask & KPW_REQUIRED_PARAMS) != KPW_REQUIRED_PARAMS)) {
7060Sstevel@tonic-gate (void) kadm5_free_config_params(handle->context,
7070Sstevel@tonic-gate &handle->params);
7082881Smp153739 krb5_free_context(handle->context);
7090Sstevel@tonic-gate free(handle->lhandle);
7102881Smp153739 free(handle);
7110Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7120Sstevel@tonic-gate "missing config parameters\n"));
7132881Smp153739 return KADM5_MISSING_KRB5_CONF_PARAMS;
7142881Smp153739 }
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate /*
7170Sstevel@tonic-gate * Acquire a service ticket for service_name@realm in the name of
7180Sstevel@tonic-gate * client_name, using password pass (which could be NULL), and
7190Sstevel@tonic-gate * create a ccache to store them in. If INIT_CREDS, use the
7200Sstevel@tonic-gate * ccache we were provided instead.
7210Sstevel@tonic-gate */
7220Sstevel@tonic-gate if ((code = krb5_parse_name(handle->context, client_name,
7230Sstevel@tonic-gate &creds.client))) {
7240Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7250Sstevel@tonic-gate "could not parse client name\n"));
7260Sstevel@tonic-gate goto error;
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate clientp = creds.client;
7290Sstevel@tonic-gate
73096Ssemery if (strncmp(service_name, KADM5_CHANGEPW_HOST_SERVICE,
73196Ssemery strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0)
73296Ssemery cpw = TRUE;
73396Ssemery
7340Sstevel@tonic-gate if (init_type == INIT_PASS &&
73596Ssemery handle->params.kpasswd_protocol == KRB5_CHGPWD_CHANGEPW_V2 &&
73696Ssemery cpw == TRUE) {
7370Sstevel@tonic-gate /*
7380Sstevel@tonic-gate * The 'service_name' is constructed by the caller
7390Sstevel@tonic-gate * but its done before the parameter which determines
7400Sstevel@tonic-gate * the kpasswd_protocol is found. The servers that
7410Sstevel@tonic-gate * support the SET/CHANGE password protocol expect
7420Sstevel@tonic-gate * a slightly different service principal than
7430Sstevel@tonic-gate * the normal SEAM kadmind so construct the correct
7440Sstevel@tonic-gate * name here and then forget it.
7450Sstevel@tonic-gate */
7460Sstevel@tonic-gate char *newsvcname = NULL;
7470Sstevel@tonic-gate newsvcname = malloc(strlen(KADM5_CHANGEPW_SERVICE) +
7480Sstevel@tonic-gate strlen(handle->params.realm) + 2);
7490Sstevel@tonic-gate if (newsvcname == NULL) {
7504152Sps57422 ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7514152Sps57422 "could not malloc\n"));
7524152Sps57422 code = ENOMEM;
7534152Sps57422 goto error;
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate sprintf(newsvcname, "%s@%s", KADM5_CHANGEPW_SERVICE,
7560Sstevel@tonic-gate handle->params.realm);
7570Sstevel@tonic-gate
7580Sstevel@tonic-gate if ((code = krb5_parse_name(handle->context, newsvcname,
7590Sstevel@tonic-gate &creds.server))) {
7600Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7610Sstevel@tonic-gate "could not parse server "
7620Sstevel@tonic-gate "name\n"));
7630Sstevel@tonic-gate free(newsvcname);
7640Sstevel@tonic-gate goto error;
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate free(newsvcname);
7670Sstevel@tonic-gate } else {
7680Sstevel@tonic-gate input_name.value = service_name;
7690Sstevel@tonic-gate input_name.length = strlen((char *)input_name.value) + 1;
7705053Sgtb gssstat = krb5_gss_import_name(&minor_stat,
7710Sstevel@tonic-gate &input_name,
7720Sstevel@tonic-gate (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
7730Sstevel@tonic-gate (gss_name_t *)&creds.server);
7740Sstevel@tonic-gate
7750Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) {
7760Sstevel@tonic-gate code = KADM5_GSS_ERROR;
7770Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7780Sstevel@tonic-gate "gss_import_name failed for client name\n"));
7790Sstevel@tonic-gate goto error;
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate serverp = creds.server;
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate /* XXX temporarily fix a bug in krb5_cc_get_type */
7850Sstevel@tonic-gate #undef krb5_cc_get_type
7860Sstevel@tonic-gate #define krb5_cc_get_type(context, cache) ((cache)->ops->prefix)
7872881Smp153739
7880Sstevel@tonic-gate
7892881Smp153739 if (init_type == INIT_CREDS) {
7902881Smp153739 ccache = ccache_in;
7912881Smp153739 handle->cache_name = (char *)
7922881Smp153739 malloc(strlen(krb5_cc_get_type(handle->context, ccache)) +
7932881Smp153739 strlen(krb5_cc_get_name(handle->context, ccache)) + 2);
7942881Smp153739 if (handle->cache_name == NULL) {
7952881Smp153739 code = ENOMEM;
7962881Smp153739 goto error;
7972881Smp153739 }
7982881Smp153739 sprintf(handle->cache_name, "%s:%s",
7992881Smp153739 krb5_cc_get_type(handle->context, ccache),
8002881Smp153739 krb5_cc_get_name(handle->context, ccache));
8012881Smp153739 } else {
8022881Smp153739 #if 0
8032881Smp153739 handle->cache_name =
8042881Smp153739 (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1);
8052881Smp153739 if (handle->cache_name == NULL) {
8062881Smp153739 code = ENOMEM;
8072881Smp153739 goto error;
8082881Smp153739 }
8092881Smp153739 sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE);
8102881Smp153739 mktemp(handle->cache_name + strlen("FILE:"));
8112881Smp153739 #endif
8122881Smp153739 {
8132881Smp153739 static int counter = 0;
8142881Smp153739 handle->cache_name = malloc(sizeof("MEMORY:kadm5_")
8152881Smp153739 + 3*sizeof(counter));
8162881Smp153739 sprintf(handle->cache_name, "MEMORY:kadm5_%u", counter++);
8172881Smp153739 }
8182881Smp153739
8192881Smp153739 if ((code = krb5_cc_resolve(handle->context, handle->cache_name,
8202881Smp153739 &ccache)))
8212881Smp153739 goto error;
8222881Smp153739
8232881Smp153739 if ((code = krb5_cc_initialize (handle->context, ccache,
8242881Smp153739 creds.client)))
8252881Smp153739 goto error;
8260Sstevel@tonic-gate
8272881Smp153739 handle->destroy_cache = 1;
8282881Smp153739 }
8292881Smp153739 handle->lhandle->cache_name = handle->cache_name;
8300Sstevel@tonic-gate ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
8310Sstevel@tonic-gate "cache created: %s\n"), handle->cache_name);
8322881Smp153739
8332881Smp153739 if ((code = krb5_timeofday(handle->context, &now)))
8342881Smp153739 goto error;
8350Sstevel@tonic-gate
8362881Smp153739 /*
8372881Smp153739 * Get a ticket, use the method specified in init_type.
8382881Smp153739 */
8392881Smp153739
8402881Smp153739 creds.times.starttime = 0; /* start timer at KDC */
8412881Smp153739 creds.times.endtime = 0; /* endtime will be limited by service */
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate memset(&opt, 0, sizeof (opt));
8440Sstevel@tonic-gate krb5_get_init_creds_opt_init(&opt);
8450Sstevel@tonic-gate
8460Sstevel@tonic-gate if (creds.times.endtime) {
8470Sstevel@tonic-gate if (creds.times.starttime)
8480Sstevel@tonic-gate starttime = creds.times.starttime;
8490Sstevel@tonic-gate else
8500Sstevel@tonic-gate starttime = now;
8510Sstevel@tonic-gate
8520Sstevel@tonic-gate krb5_get_init_creds_opt_set_tkt_life(&opt,
8530Sstevel@tonic-gate creds.times.endtime - starttime);
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate code = krb5_unparse_name(handle->context, creds.server, &server);
8560Sstevel@tonic-gate if (code)
8570Sstevel@tonic-gate goto error;
8580Sstevel@tonic-gate
8594807Smp153739 /*
8604807Smp153739 * Solaris Kerberos:
8614807Smp153739 * Save the original creds.server as krb5_get_init_creds*() always
8624807Smp153739 * sets the realm of the server to the client realm.
8634807Smp153739 */
8644807Smp153739 code = krb5_copy_principal(handle->context, creds.server, &saved_server);
8654807Smp153739 if (code)
8664807Smp153739 goto error;
8674807Smp153739
8680Sstevel@tonic-gate if (init_type == INIT_PASS) {
8690Sstevel@tonic-gate code = krb5_get_init_creds_password(handle->context,
8700Sstevel@tonic-gate &creds, creds.client, pass, NULL,
8710Sstevel@tonic-gate NULL, creds.times.starttime,
8720Sstevel@tonic-gate server, &opt);
8730Sstevel@tonic-gate } else if (init_type == INIT_SKEY) {
8740Sstevel@tonic-gate krb5_keytab kt = NULL;
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate if (!(pass && (code = krb5_kt_resolve(handle->context,
8770Sstevel@tonic-gate pass, &kt)))) {
8780Sstevel@tonic-gate code = krb5_get_init_creds_keytab(
8790Sstevel@tonic-gate handle->context,
8800Sstevel@tonic-gate &creds, creds.client, kt,
8810Sstevel@tonic-gate creds.times.starttime,
8820Sstevel@tonic-gate server, &opt);
8830Sstevel@tonic-gate
8842881Smp153739 if (pass) krb5_kt_close(handle->context, kt);
8852881Smp153739 }
8862881Smp153739 }
8870Sstevel@tonic-gate
8882881Smp153739 /* Improved error messages */
8892881Smp153739 if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
8902881Smp153739 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
8912881Smp153739 code = KADM5_SECURE_PRINC_MISSING;
8920Sstevel@tonic-gate
8932881Smp153739 if (code != 0) {
8940Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
8950Sstevel@tonic-gate "failed to obtain credentials cache\n"));
8964807Smp153739 krb5_free_principal(handle->context, saved_server);
8970Sstevel@tonic-gate goto error;
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate
9005062Smp153739 /*
9014807Smp153739 * Solaris Kerberos:
9024807Smp153739 * If the server principal had an empty realm then store that in
9034807Smp153739 * the cred cache and not the server realm as returned by
9045062Smp153739 * krb5_get_init_creds_{keytab|password}(). This ensures that rpcsec_gss
9055062Smp153739 * will find the credential in the cred cache even if a "fallback"
9065062Smp153739 * method is being used to determine the realm.
9074807Smp153739 */
9085062Smp153739 if (init_type != INIT_CREDS) {
9095062Smp153739 krb5_free_principal(handle->context, creds.server);
9105062Smp153739 }
9114807Smp153739 creds.server = saved_server;
9124807Smp153739
9130Sstevel@tonic-gate /*
9140Sstevel@tonic-gate * If we got this far, save the creds in the cache.
9150Sstevel@tonic-gate */
9160Sstevel@tonic-gate if (ccache) {
9170Sstevel@tonic-gate code = krb5_cc_store_cred(handle->context, ccache, &creds);
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate
9200Sstevel@tonic-gate ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "obtained credentials cache\n"));
9210Sstevel@tonic-gate
9220Sstevel@tonic-gate #ifdef ZEROPASSWD
9232881Smp153739 if (pass != NULL)
9242881Smp153739 memset(pass, 0, strlen(pass));
9250Sstevel@tonic-gate #endif
9260Sstevel@tonic-gate
9270Sstevel@tonic-gate if (init_type != INIT_PASS ||
92896Ssemery handle->params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC ||
92996Ssemery cpw == FALSE) {
9300Sstevel@tonic-gate code = _kadm5_initialize_rpcsec_gss_handle(handle,
9310Sstevel@tonic-gate client_name, service_name);
9325062Smp153739
9335062Smp153739 /*
9345062Smp153739 * Solaris Kerberos:
9355062Smp153739 * If _kadm5_initialize_rpcsec_gss_handle() fails it will have
9365062Smp153739 * called krb5_gss_release_cred(). If the credential cache is a
9375062Smp153739 * MEMORY cred cache krb5_gss_release_cred() destroys the
9385062Smp153739 * cred cache data. Make sure that the cred-cache is closed
9395062Smp153739 * to prevent a double free in the "error" code.
9405062Smp153739 */
9415062Smp153739 if (code != 0) {
942*7934SMark.Phalan@Sun.COM if (init_type != INIT_CREDS) {
9435062Smp153739 krb5_cc_close(handle->context, ccache);
944*7934SMark.Phalan@Sun.COM ccache = NULL;
945*7934SMark.Phalan@Sun.COM }
9460Sstevel@tonic-gate goto error;
9475062Smp153739 }
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate
9500Sstevel@tonic-gate *server_handle = (void *) handle;
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate if (init_type != INIT_CREDS)
9530Sstevel@tonic-gate krb5_cc_close(handle->context, ccache);
9540Sstevel@tonic-gate
9550Sstevel@tonic-gate goto cleanup;
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate error:
9582881Smp153739 /*
9592881Smp153739 * Note that it is illegal for this code to execute if "handle"
9602881Smp153739 * has not been allocated and initialized. I.e., don't use "goto
9612881Smp153739 * error" before the block of code at the top of the function
9622881Smp153739 * that allocates and initializes "handle".
9632881Smp153739 */
9642881Smp153739 if (handle->cache_name)
9650Sstevel@tonic-gate free(handle->cache_name);
9662881Smp153739 if (handle->destroy_cache && ccache)
9670Sstevel@tonic-gate krb5_cc_destroy(handle->context, ccache);
9682881Smp153739 if(handle->clnt && handle->clnt->cl_auth)
9690Sstevel@tonic-gate AUTH_DESTROY(handle->clnt->cl_auth);
9702881Smp153739 if(handle->clnt)
9710Sstevel@tonic-gate clnt_destroy(handle->clnt);
9720Sstevel@tonic-gate (void) kadm5_free_config_params(handle->context, &handle->params);
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate cleanup:
9750Sstevel@tonic-gate if (server)
9760Sstevel@tonic-gate free(server);
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /*
9791692Ssemery * cred's server and client pointers could have been overwritten
9801692Ssemery * by the krb5_get_init_* functions. If the addresses are different
9811692Ssemery * before and after the calls then we must free the memory that
9821692Ssemery * was allocated before the call.
9830Sstevel@tonic-gate */
9841692Ssemery if (clientp && clientp != creds.client)
9850Sstevel@tonic-gate krb5_free_principal(handle->context, clientp);
9861692Ssemery
9871692Ssemery if (serverp && serverp != creds.server)
9880Sstevel@tonic-gate krb5_free_principal(handle->context, serverp);
9890Sstevel@tonic-gate
9902881Smp153739 krb5_free_cred_contents(handle->context, &creds);
9910Sstevel@tonic-gate
9920Sstevel@tonic-gate /*
9930Sstevel@tonic-gate * Dont clean up the handle if the code is OK (code==0)
9940Sstevel@tonic-gate * because it is returned to the caller in the 'server_handle'
9950Sstevel@tonic-gate * ptr.
9960Sstevel@tonic-gate */
9972881Smp153739 if (code) {
9980Sstevel@tonic-gate krb5_free_context(handle->context);
9990Sstevel@tonic-gate free(handle->lhandle);
10000Sstevel@tonic-gate free(handle);
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate
10032881Smp153739 return code;
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate
10060Sstevel@tonic-gate kadm5_ret_t
kadm5_destroy(void * server_handle)10070Sstevel@tonic-gate kadm5_destroy(void *server_handle)
10080Sstevel@tonic-gate {
10092881Smp153739 krb5_ccache ccache = NULL;
10102881Smp153739 int code = KADM5_OK;
10112881Smp153739 kadm5_server_handle_t handle =
10120Sstevel@tonic-gate (kadm5_server_handle_t) server_handle;
10130Sstevel@tonic-gate OM_uint32 min_stat;
10140Sstevel@tonic-gate
10152881Smp153739 CHECK_HANDLE(server_handle);
10162881Smp153739 /* SUNW14resync:
10172881Smp153739 * krb5_cc_resolve() will resolve a ccache with the same data that
10182881Smp153739 * handle->my_cred points to. If the ccache is a MEMORY ccache then
10192881Smp153739 * gss_release_cred() will free that data (it doesn't do this when ccache
10202881Smp153739 * is a FILE ccache).
10212881Smp153739 * if'ed out to avoid the double free.
10222881Smp153739 */
10232881Smp153739 #if 0
10242881Smp153739 if (handle->destroy_cache && handle->cache_name) {
10250Sstevel@tonic-gate if ((code = krb5_cc_resolve(handle->context,
10260Sstevel@tonic-gate handle->cache_name, &ccache)) == 0)
10270Sstevel@tonic-gate code = krb5_cc_destroy (handle->context, ccache);
10282881Smp153739 }
10292881Smp153739 #endif
10302881Smp153739 if (handle->cache_name)
10310Sstevel@tonic-gate free(handle->cache_name);
10322881Smp153739 if (handle->clnt && handle->clnt->cl_auth) {
10330Sstevel@tonic-gate /*
10340Sstevel@tonic-gate * Since kadm5 doesn't use the default credentials we
10350Sstevel@tonic-gate * must clean this up manually.
10360Sstevel@tonic-gate */
10370Sstevel@tonic-gate if (handle->my_cred != GSS_C_NO_CREDENTIAL)
10380Sstevel@tonic-gate (void) gss_release_cred(&min_stat, &handle->my_cred);
10392881Smp153739 AUTH_DESTROY(handle->clnt->cl_auth);
10400Sstevel@tonic-gate }
10412881Smp153739 if (handle->clnt)
10420Sstevel@tonic-gate clnt_destroy(handle->clnt);
10432881Smp153739 if (handle->lhandle)
10442881Smp153739 free (handle->lhandle);
10452881Smp153739
10462881Smp153739 kadm5_free_config_params(handle->context, &handle->params);
10472881Smp153739 krb5_free_context(handle->context);
10480Sstevel@tonic-gate
10492881Smp153739 handle->magic_number = 0;
10502881Smp153739 free(handle);
10510Sstevel@tonic-gate
10522881Smp153739 return code;
10532881Smp153739 }
10542881Smp153739 /* not supported on client */
kadm5_lock(void * server_handle)10552881Smp153739 kadm5_ret_t kadm5_lock(void *server_handle)
10562881Smp153739 {
10572881Smp153739 return EINVAL;
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate
10602881Smp153739 /* not supported on client */
kadm5_unlock(void * server_handle)10612881Smp153739 kadm5_ret_t kadm5_unlock(void *server_handle)
10620Sstevel@tonic-gate {
10632881Smp153739 return EINVAL;
10640Sstevel@tonic-gate }
10650Sstevel@tonic-gate
kadm5_flush(void * server_handle)10662881Smp153739 kadm5_ret_t kadm5_flush(void *server_handle)
10670Sstevel@tonic-gate {
10682881Smp153739 return KADM5_OK;
10692881Smp153739 }
10702881Smp153739
_kadm5_check_handle(void * handle)10712881Smp153739 int _kadm5_check_handle(void *handle)
10722881Smp153739 {
10732881Smp153739 CHECK_HANDLE(handle);
10742881Smp153739 return 0;
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate
kadm5_init_krb5_context(krb5_context * ctx)10774960Swillf krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
10784960Swillf {
10794960Swillf return krb5_init_context(ctx);
10804960Swillf }
10814960Swillf
10820Sstevel@tonic-gate /*
10830Sstevel@tonic-gate * Stub function for kadmin. It was created to eliminate the dependency on
10840Sstevel@tonic-gate * libkdb's ulog functions. The srv equivalent makes the actual calls.
10850Sstevel@tonic-gate */
10860Sstevel@tonic-gate krb5_error_code
kadm5_init_iprop(void * handle)10870Sstevel@tonic-gate kadm5_init_iprop(void *handle)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate return (0);
10900Sstevel@tonic-gate }
1091