10Sstevel@tonic-gate /*
2*7934SMark.Phalan@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3781Sgtb * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate
70Sstevel@tonic-gate /*
80Sstevel@tonic-gate * lib/krb5/os/changepw.c
90Sstevel@tonic-gate *
100Sstevel@tonic-gate * Copyright 1990,1999 by the Massachusetts Institute of Technology.
110Sstevel@tonic-gate * All Rights Reserved.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * Export of this software from the United States of America may
140Sstevel@tonic-gate * require a specific license from the United States Government.
150Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
160Sstevel@tonic-gate * export to obtain such a license before exporting.
170Sstevel@tonic-gate *
180Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
190Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
200Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
210Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
220Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
230Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
240Sstevel@tonic-gate * to distribution of the software without specific, written prior
250Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label
260Sstevel@tonic-gate * your software as modified software and not distribute it in such a
270Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
280Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
290Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
300Sstevel@tonic-gate * or implied warranty.
310Sstevel@tonic-gate *
320Sstevel@tonic-gate */
330Sstevel@tonic-gate
340Sstevel@tonic-gate #define NEED_SOCKETS
350Sstevel@tonic-gate #include <k5-int.h>
360Sstevel@tonic-gate #include <kadm5/admin.h>
370Sstevel@tonic-gate #include <client_internal.h>
380Sstevel@tonic-gate #include <gssapi/gssapi.h>
390Sstevel@tonic-gate #include <gssapi_krb5.h>
400Sstevel@tonic-gate #include <gssapiP_krb5.h>
41*7934SMark.Phalan@Sun.COM #include <krb5.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate /* #include "adm_err.h" */
440Sstevel@tonic-gate #include <stdio.h>
450Sstevel@tonic-gate #include <errno.h>
460Sstevel@tonic-gate
47*7934SMark.Phalan@Sun.COM extern krb5_error_code krb5int_mk_chpw_req(krb5_context context,
480Sstevel@tonic-gate krb5_auth_context auth_context,
490Sstevel@tonic-gate krb5_data *ap_req, char *passwd,
500Sstevel@tonic-gate krb5_data *packet);
510Sstevel@tonic-gate
52*7934SMark.Phalan@Sun.COM extern krb5_error_code krb5int_rd_chpw_rep(krb5_context context,
530Sstevel@tonic-gate krb5_auth_context auth_context,
540Sstevel@tonic-gate krb5_data *packet, int *result_code,
550Sstevel@tonic-gate krb5_data *result_data);
560Sstevel@tonic-gate
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate * _kadm5_get_kpasswd_protocol
590Sstevel@tonic-gate *
600Sstevel@tonic-gate * returns the password change protocol value to the caller.
610Sstevel@tonic-gate * Since the 'handle' is an opaque value to higher up callers,
620Sstevel@tonic-gate * this method is needed to provide a way for them to get a peek
630Sstevel@tonic-gate * at the protocol being used without having to expose the entire
640Sstevel@tonic-gate * handle structure.
650Sstevel@tonic-gate */
660Sstevel@tonic-gate krb5_chgpwd_prot
_kadm5_get_kpasswd_protocol(void * handle)670Sstevel@tonic-gate _kadm5_get_kpasswd_protocol(void *handle)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate kadm5_server_handle_t srvrhdl = (kadm5_server_handle_t)handle;
700Sstevel@tonic-gate
710Sstevel@tonic-gate return (srvrhdl->params.kpasswd_protocol);
720Sstevel@tonic-gate }
730Sstevel@tonic-gate
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate * krb5_change_password
760Sstevel@tonic-gate *
770Sstevel@tonic-gate * Prepare and send a CHANGEPW request to a password server
780Sstevel@tonic-gate * using UDP datagrams. This is only used for sending to
790Sstevel@tonic-gate * non-SEAM servers which support the Marc Horowitz defined
800Sstevel@tonic-gate * protocol (1998) for password changing.
810Sstevel@tonic-gate *
82781Sgtb * SUNW14resync - added _local as it conflicts with one in krb5.h
830Sstevel@tonic-gate */
840Sstevel@tonic-gate static krb5_error_code
krb5_change_password_local(context,params,creds,newpw,srvr_rsp_code,srvr_msg)85781Sgtb krb5_change_password_local(context, params, creds, newpw, srvr_rsp_code,
860Sstevel@tonic-gate srvr_msg)
870Sstevel@tonic-gate krb5_context context;
880Sstevel@tonic-gate kadm5_config_params *params;
890Sstevel@tonic-gate krb5_creds *creds;
900Sstevel@tonic-gate char *newpw;
910Sstevel@tonic-gate kadm5_ret_t *srvr_rsp_code;
920Sstevel@tonic-gate krb5_data *srvr_msg;
930Sstevel@tonic-gate {
940Sstevel@tonic-gate krb5_auth_context auth_context;
950Sstevel@tonic-gate krb5_data ap_req, chpw_req, chpw_rep;
960Sstevel@tonic-gate krb5_address local_kaddr, remote_kaddr;
970Sstevel@tonic-gate krb5_error_code code = 0;
980Sstevel@tonic-gate int i, addrlen;
990Sstevel@tonic-gate struct sockaddr *addr_p, local_addr, remote_addr, tmp_addr;
1000Sstevel@tonic-gate struct sockaddr_in *sin_p;
1010Sstevel@tonic-gate struct hostent *hp;
1020Sstevel@tonic-gate int naddr_p;
1030Sstevel@tonic-gate int cc, local_result_code, tmp_len;
1040Sstevel@tonic-gate SOCKET s1 = INVALID_SOCKET;
1050Sstevel@tonic-gate SOCKET s2 = INVALID_SOCKET;
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate /* Initialize values so that cleanup call can safely check for NULL */
1090Sstevel@tonic-gate auth_context = NULL;
1100Sstevel@tonic-gate addr_p = NULL;
1110Sstevel@tonic-gate memset(&chpw_req, 0, sizeof (krb5_data));
1120Sstevel@tonic-gate memset(&chpw_rep, 0, sizeof (krb5_data));
1130Sstevel@tonic-gate memset(&ap_req, 0, sizeof (krb5_data));
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate /* initialize auth_context so that we know we have to free it */
1160Sstevel@tonic-gate if ((code = krb5_auth_con_init(context, &auth_context)))
1170Sstevel@tonic-gate goto cleanup;
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate if (code = krb5_mk_req_extended(context, &auth_context,
1200Sstevel@tonic-gate AP_OPTS_USE_SUBKEY,
1210Sstevel@tonic-gate NULL, creds, &ap_req))
1220Sstevel@tonic-gate goto cleanup;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate * find the address of the kpasswd_server.
1260Sstevel@tonic-gate */
1270Sstevel@tonic-gate addr_p = (struct sockaddr *)malloc(sizeof (struct sockaddr));
1280Sstevel@tonic-gate if (!addr_p)
1290Sstevel@tonic-gate goto cleanup;
1300Sstevel@tonic-gate memset(addr_p, 0, sizeof (struct sockaddr));
1310Sstevel@tonic-gate if ((hp = gethostbyname(params->kpasswd_server)) == NULL) {
1320Sstevel@tonic-gate code = KRB5_REALM_CANT_RESOLVE;
1330Sstevel@tonic-gate goto cleanup;
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate sin_p = (struct sockaddr_in *)addr_p;
1360Sstevel@tonic-gate memset((char *)sin_p, 0, sizeof (struct sockaddr));
1370Sstevel@tonic-gate sin_p->sin_family = hp->h_addrtype;
1380Sstevel@tonic-gate sin_p->sin_port = htons(params->kpasswd_port);
1390Sstevel@tonic-gate memcpy((char *)&sin_p->sin_addr, (char *)hp->h_addr, hp->h_length);
1400Sstevel@tonic-gate naddr_p = 1;
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate * this is really obscure. s1 is used for all communications. it
1450Sstevel@tonic-gate * is left unconnected in case the server is multihomed and routes
1460Sstevel@tonic-gate * are asymmetric. s2 is connected to resolve routes and get
1470Sstevel@tonic-gate * addresses. this is the *only* way to get proper addresses for
1480Sstevel@tonic-gate * multihomed hosts if routing is asymmetric.
1490Sstevel@tonic-gate *
1500Sstevel@tonic-gate * A related problem in the server, but not the client, is that
1510Sstevel@tonic-gate * many os's have no way to disconnect a connected udp socket, so
1520Sstevel@tonic-gate * the s2 socket needs to be closed and recreated for each
1530Sstevel@tonic-gate * request. The s1 socket must not be closed, or else queued
1540Sstevel@tonic-gate * requests will be lost.
1550Sstevel@tonic-gate *
1560Sstevel@tonic-gate * A "naive" client implementation (one socket, no connect,
1570Sstevel@tonic-gate * hostname resolution to get the local ip addr) will work and
1580Sstevel@tonic-gate * interoperate if the client is single-homed.
1590Sstevel@tonic-gate */
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate code = errno;
1640Sstevel@tonic-gate goto cleanup;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate code = errno;
1700Sstevel@tonic-gate goto cleanup;
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate for (i = 0; i < naddr_p; i++)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate fd_set fdset;
1760Sstevel@tonic-gate struct timeval timeout;
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate if (connect(s2, &addr_p[i], sizeof (addr_p[i])) ==
1790Sstevel@tonic-gate SOCKET_ERROR)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate if ((errno == ECONNREFUSED) ||
1820Sstevel@tonic-gate (errno == EHOSTUNREACH))
1830Sstevel@tonic-gate continue; /* try the next addr */
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate code = errno;
1860Sstevel@tonic-gate goto cleanup;
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate addrlen = sizeof (local_addr);
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate if (getsockname(s2, &local_addr, &addrlen) < 0)
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate if ((errno == ECONNREFUSED) ||
1940Sstevel@tonic-gate (errno == EHOSTUNREACH))
1950Sstevel@tonic-gate continue; /* try the next addr */
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate code = errno;
1980Sstevel@tonic-gate goto cleanup;
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate * some brain-dead OS's don't return useful information from
2030Sstevel@tonic-gate * the getsockname call. Namely, windows and solaris.
2040Sstevel@tonic-gate */
2050Sstevel@tonic-gate if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0)
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate local_kaddr.addrtype = ADDRTYPE_INET;
2080Sstevel@tonic-gate local_kaddr.length = sizeof (((struct sockaddr_in *)
2090Sstevel@tonic-gate &local_addr)->sin_addr);
2100Sstevel@tonic-gate local_kaddr.contents = (krb5_octet *)
2110Sstevel@tonic-gate &(((struct sockaddr_in *)
2120Sstevel@tonic-gate &local_addr)->sin_addr);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate else
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate krb5_address **addrs;
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate krb5_os_localaddr(context, &addrs);
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate local_kaddr.magic = addrs[0]->magic;
2210Sstevel@tonic-gate local_kaddr.addrtype = addrs[0]->addrtype;
2220Sstevel@tonic-gate local_kaddr.length = addrs[0]->length;
2230Sstevel@tonic-gate local_kaddr.contents = malloc(addrs[0]->length);
2240Sstevel@tonic-gate memcpy(local_kaddr.contents, addrs[0]->contents,
2250Sstevel@tonic-gate addrs[0]->length);
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate krb5_free_addresses(context, addrs);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate addrlen = sizeof (remote_addr);
2310Sstevel@tonic-gate if (getpeername(s2, &remote_addr, &addrlen) < 0)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate if ((errno == ECONNREFUSED) ||
2340Sstevel@tonic-gate (errno == EHOSTUNREACH))
2350Sstevel@tonic-gate continue; /* try the next addr */
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate code = errno;
2380Sstevel@tonic-gate goto cleanup;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate remote_kaddr.addrtype = ADDRTYPE_INET;
2420Sstevel@tonic-gate remote_kaddr.length = sizeof (((struct sockaddr_in *)
2430Sstevel@tonic-gate &remote_addr)->sin_addr);
2440Sstevel@tonic-gate remote_kaddr.contents = (krb5_octet *)
2450Sstevel@tonic-gate &(((struct sockaddr_in *)&remote_addr)->sin_addr);
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate * mk_priv requires that the local address be set.
2490Sstevel@tonic-gate * getsockname is used for this. rd_priv requires that the
2500Sstevel@tonic-gate * remote address be set. recvfrom is used for this. If
2510Sstevel@tonic-gate * rd_priv is given a local address, and the message has the
2520Sstevel@tonic-gate * recipient addr in it, this will be checked. However, there
2530Sstevel@tonic-gate * is simply no way to know ahead of time what address the
2540Sstevel@tonic-gate * message will be delivered *to*. Therefore, it is important
2550Sstevel@tonic-gate * that either no recipient address is in the messages when
2560Sstevel@tonic-gate * mk_priv is called, or that no local address is passed to
2570Sstevel@tonic-gate * rd_priv. Both is a better idea, and I have done that. In
2580Sstevel@tonic-gate * summary, when mk_priv is called, *only* a local address is
2590Sstevel@tonic-gate * specified. when rd_priv is called, *only* a remote address
2600Sstevel@tonic-gate * is specified. Are we having fun yet?
2610Sstevel@tonic-gate */
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate if (code = krb5_auth_con_setaddrs(context, auth_context,
2640Sstevel@tonic-gate &local_kaddr, NULL))
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate code = errno;
2670Sstevel@tonic-gate goto cleanup;
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate
270*7934SMark.Phalan@Sun.COM if (code = krb5int_mk_chpw_req(context, auth_context,
2710Sstevel@tonic-gate &ap_req, newpw, &chpw_req))
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate code = errno;
2740Sstevel@tonic-gate goto cleanup;
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate if ((cc = sendto(s1, chpw_req.data, chpw_req.length, 0,
2780Sstevel@tonic-gate (struct sockaddr *)&addr_p[i],
2790Sstevel@tonic-gate sizeof (addr_p[i]))) != chpw_req.length)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate if ((cc < 0) && ((errno == ECONNREFUSED) ||
2820Sstevel@tonic-gate (errno == EHOSTUNREACH)))
2830Sstevel@tonic-gate continue; /* try the next addr */
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate code = (cc < 0) ? errno : ECONNABORTED;
2860Sstevel@tonic-gate goto cleanup;
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate chpw_rep.length = 1500;
2900Sstevel@tonic-gate chpw_rep.data = (char *)malloc(chpw_rep.length);
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate /* XXX need a timeout/retry loop here */
2930Sstevel@tonic-gate FD_ZERO(&fdset);
2940Sstevel@tonic-gate FD_SET(s1, &fdset);
2950Sstevel@tonic-gate timeout.tv_sec = 120;
2960Sstevel@tonic-gate timeout.tv_usec = 0;
2970Sstevel@tonic-gate switch (select(s1 + 1, &fdset, 0, 0, &timeout)) {
2980Sstevel@tonic-gate case -1:
2990Sstevel@tonic-gate code = errno;
3000Sstevel@tonic-gate goto cleanup;
3010Sstevel@tonic-gate case 0:
3020Sstevel@tonic-gate code = ETIMEDOUT;
3030Sstevel@tonic-gate goto cleanup;
3040Sstevel@tonic-gate default:
3050Sstevel@tonic-gate /* fall through */
3060Sstevel@tonic-gate ;
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate tmp_len = sizeof (tmp_addr);
3100Sstevel@tonic-gate if ((cc = recvfrom(s1, chpw_rep.data, chpw_rep.length,
3110Sstevel@tonic-gate 0, &tmp_addr, &tmp_len)) < 0)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate code = errno;
3140Sstevel@tonic-gate goto cleanup;
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate closesocket(s1);
3180Sstevel@tonic-gate s1 = INVALID_SOCKET;
3190Sstevel@tonic-gate closesocket(s2);
3200Sstevel@tonic-gate s2 = INVALID_SOCKET;
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate chpw_rep.length = cc;
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate if (code = krb5_auth_con_setaddrs(context, auth_context,
3250Sstevel@tonic-gate NULL, &remote_kaddr))
3260Sstevel@tonic-gate goto cleanup;
3270Sstevel@tonic-gate
328*7934SMark.Phalan@Sun.COM if (code = krb5int_rd_chpw_rep(context, auth_context, &chpw_rep,
3290Sstevel@tonic-gate &local_result_code, srvr_msg))
3300Sstevel@tonic-gate goto cleanup;
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate if (srvr_rsp_code)
3330Sstevel@tonic-gate *srvr_rsp_code = local_result_code;
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate code = 0;
3360Sstevel@tonic-gate goto cleanup;
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate code = errno;
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate cleanup:
3420Sstevel@tonic-gate if (auth_context != NULL)
3430Sstevel@tonic-gate krb5_auth_con_free(context, auth_context);
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate if (addr_p != NULL)
3460Sstevel@tonic-gate krb5_xfree(addr_p);
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate if (s1 != INVALID_SOCKET)
3490Sstevel@tonic-gate closesocket(s1);
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate if (s2 != INVALID_SOCKET)
3520Sstevel@tonic-gate closesocket(s2);
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate krb5_xfree(chpw_req.data);
3550Sstevel@tonic-gate krb5_xfree(chpw_rep.data);
3560Sstevel@tonic-gate krb5_xfree(ap_req.data);
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate return (code);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /*
3630Sstevel@tonic-gate * kadm5_chpass_principal_v2
3640Sstevel@tonic-gate *
3650Sstevel@tonic-gate * New function used to prepare to make the change password request to a
3660Sstevel@tonic-gate * non-SEAM admin server. The protocol used in this case is not based on
3670Sstevel@tonic-gate * RPCSEC_GSS, it simply makes the request to port 464 (udp and tcp).
3680Sstevel@tonic-gate * This is the same way that MIT KRB5 1.2.1 changes passwords.
3690Sstevel@tonic-gate */
3700Sstevel@tonic-gate kadm5_ret_t
kadm5_chpass_principal_v2(void * server_handle,krb5_principal princ,char * newpw,kadm5_ret_t * srvr_rsp_code,krb5_data * srvr_msg)3710Sstevel@tonic-gate kadm5_chpass_principal_v2(void *server_handle,
3720Sstevel@tonic-gate krb5_principal princ,
3730Sstevel@tonic-gate char *newpw,
3740Sstevel@tonic-gate kadm5_ret_t *srvr_rsp_code,
3750Sstevel@tonic-gate krb5_data *srvr_msg)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate kadm5_ret_t code;
3780Sstevel@tonic-gate kadm5_server_handle_t handle = (kadm5_server_handle_t)server_handle;
3790Sstevel@tonic-gate krb5_error_code result;
3800Sstevel@tonic-gate krb5_creds mcreds;
3810Sstevel@tonic-gate krb5_creds ncreds;
3820Sstevel@tonic-gate krb5_ccache ccache;
3830Sstevel@tonic-gate int cpwlen;
3840Sstevel@tonic-gate char *cpw_service = NULL;
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate /*
3870Sstevel@tonic-gate * The credentials have already been stored in the cache in the
3880Sstevel@tonic-gate * initialization step earlier, but we dont have direct access to it
3890Sstevel@tonic-gate * at this level. Derive the cache and fetch the credentials to use for
3900Sstevel@tonic-gate * sending the request.
3910Sstevel@tonic-gate */
3920Sstevel@tonic-gate memset(&mcreds, 0, sizeof (krb5_creds));
3930Sstevel@tonic-gate if ((code = krb5_cc_resolve(handle->context, handle->cache_name,
3940Sstevel@tonic-gate &ccache)))
3950Sstevel@tonic-gate return (code);
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate /* set the client principal in the credential match structure */
3980Sstevel@tonic-gate mcreds.client = princ;
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate * set the server principal (kadmin/changepw@REALM) in the credential
4020Sstevel@tonic-gate * match struct
4030Sstevel@tonic-gate */
4040Sstevel@tonic-gate cpwlen = strlen(KADM5_CHANGEPW_SERVICE) +
4050Sstevel@tonic-gate strlen(handle->params.realm) + 2;
4060Sstevel@tonic-gate cpw_service = malloc(cpwlen);
4070Sstevel@tonic-gate if (cpw_service == NULL) {
4080Sstevel@tonic-gate return (ENOMEM);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate snprintf(cpw_service, cpwlen, "%s@%s",
4120Sstevel@tonic-gate KADM5_CHANGEPW_SERVICE, handle->params.realm);
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate /* generate the server principal from the name string we generated */
4150Sstevel@tonic-gate if ((code = krb5_parse_name(handle->context, cpw_service,
4160Sstevel@tonic-gate &mcreds.server))) {
4170Sstevel@tonic-gate free(cpw_service);
4180Sstevel@tonic-gate return (code);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate /* Find the credentials in the cache */
4220Sstevel@tonic-gate if ((code = krb5_cc_retrieve_cred(handle->context, ccache, 0, &mcreds,
4230Sstevel@tonic-gate &ncreds))) {
4240Sstevel@tonic-gate free(cpw_service);
4250Sstevel@tonic-gate return (code);
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate /* Now we have all we need to make the change request. */
429781Sgtb result = krb5_change_password_local(handle->context, &handle->params,
4300Sstevel@tonic-gate &ncreds, newpw,
4310Sstevel@tonic-gate srvr_rsp_code,
4320Sstevel@tonic-gate srvr_msg);
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate free(cpw_service);
4350Sstevel@tonic-gate return (result);
4360Sstevel@tonic-gate }
437