17c478bd9Sstevel@tonic-gate /* 2*159d09a2SMark Phalan * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3505d05c7Sgtb * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate 77c478bd9Sstevel@tonic-gate /* 87c478bd9Sstevel@tonic-gate * lib/krb5/os/changepw.c 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * Copyright 1990,1999 by the Massachusetts Institute of Technology. 117c478bd9Sstevel@tonic-gate * All Rights Reserved. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 147c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 157c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 167c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 177c478bd9Sstevel@tonic-gate * 187c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 197c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 207c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 217c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 227c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 237c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 247c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 257c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 267c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 277c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 287c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 297c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 307c478bd9Sstevel@tonic-gate * or implied warranty. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #define NEED_SOCKETS 357c478bd9Sstevel@tonic-gate #include <k5-int.h> 367c478bd9Sstevel@tonic-gate #include <kadm5/admin.h> 377c478bd9Sstevel@tonic-gate #include <client_internal.h> 387c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h> 397c478bd9Sstevel@tonic-gate #include <gssapi_krb5.h> 407c478bd9Sstevel@tonic-gate #include <gssapiP_krb5.h> 41*159d09a2SMark Phalan #include <krb5.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /* #include "adm_err.h" */ 447c478bd9Sstevel@tonic-gate #include <stdio.h> 457c478bd9Sstevel@tonic-gate #include <errno.h> 467c478bd9Sstevel@tonic-gate 47*159d09a2SMark Phalan extern krb5_error_code krb5int_mk_chpw_req(krb5_context context, 487c478bd9Sstevel@tonic-gate krb5_auth_context auth_context, 497c478bd9Sstevel@tonic-gate krb5_data *ap_req, char *passwd, 507c478bd9Sstevel@tonic-gate krb5_data *packet); 517c478bd9Sstevel@tonic-gate 52*159d09a2SMark Phalan extern krb5_error_code krb5int_rd_chpw_rep(krb5_context context, 537c478bd9Sstevel@tonic-gate krb5_auth_context auth_context, 547c478bd9Sstevel@tonic-gate krb5_data *packet, int *result_code, 557c478bd9Sstevel@tonic-gate krb5_data *result_data); 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* 587c478bd9Sstevel@tonic-gate * _kadm5_get_kpasswd_protocol 597c478bd9Sstevel@tonic-gate * 607c478bd9Sstevel@tonic-gate * returns the password change protocol value to the caller. 617c478bd9Sstevel@tonic-gate * Since the 'handle' is an opaque value to higher up callers, 627c478bd9Sstevel@tonic-gate * this method is needed to provide a way for them to get a peek 637c478bd9Sstevel@tonic-gate * at the protocol being used without having to expose the entire 647c478bd9Sstevel@tonic-gate * handle structure. 657c478bd9Sstevel@tonic-gate */ 667c478bd9Sstevel@tonic-gate krb5_chgpwd_prot 677c478bd9Sstevel@tonic-gate _kadm5_get_kpasswd_protocol(void *handle) 687c478bd9Sstevel@tonic-gate { 697c478bd9Sstevel@tonic-gate kadm5_server_handle_t srvrhdl = (kadm5_server_handle_t)handle; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate return (srvrhdl->params.kpasswd_protocol); 727c478bd9Sstevel@tonic-gate } 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * krb5_change_password 767c478bd9Sstevel@tonic-gate * 777c478bd9Sstevel@tonic-gate * Prepare and send a CHANGEPW request to a password server 787c478bd9Sstevel@tonic-gate * using UDP datagrams. This is only used for sending to 797c478bd9Sstevel@tonic-gate * non-SEAM servers which support the Marc Horowitz defined 807c478bd9Sstevel@tonic-gate * protocol (1998) for password changing. 817c478bd9Sstevel@tonic-gate * 82505d05c7Sgtb * SUNW14resync - added _local as it conflicts with one in krb5.h 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate static krb5_error_code 85505d05c7Sgtb krb5_change_password_local(context, params, creds, newpw, srvr_rsp_code, 867c478bd9Sstevel@tonic-gate srvr_msg) 877c478bd9Sstevel@tonic-gate krb5_context context; 887c478bd9Sstevel@tonic-gate kadm5_config_params *params; 897c478bd9Sstevel@tonic-gate krb5_creds *creds; 907c478bd9Sstevel@tonic-gate char *newpw; 917c478bd9Sstevel@tonic-gate kadm5_ret_t *srvr_rsp_code; 927c478bd9Sstevel@tonic-gate krb5_data *srvr_msg; 937c478bd9Sstevel@tonic-gate { 947c478bd9Sstevel@tonic-gate krb5_auth_context auth_context; 957c478bd9Sstevel@tonic-gate krb5_data ap_req, chpw_req, chpw_rep; 967c478bd9Sstevel@tonic-gate krb5_address local_kaddr, remote_kaddr; 977c478bd9Sstevel@tonic-gate krb5_error_code code = 0; 987c478bd9Sstevel@tonic-gate int i, addrlen; 997c478bd9Sstevel@tonic-gate struct sockaddr *addr_p, local_addr, remote_addr, tmp_addr; 1007c478bd9Sstevel@tonic-gate struct sockaddr_in *sin_p; 1017c478bd9Sstevel@tonic-gate struct hostent *hp; 1027c478bd9Sstevel@tonic-gate int naddr_p; 1037c478bd9Sstevel@tonic-gate int cc, local_result_code, tmp_len; 1047c478bd9Sstevel@tonic-gate SOCKET s1 = INVALID_SOCKET; 1057c478bd9Sstevel@tonic-gate SOCKET s2 = INVALID_SOCKET; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* Initialize values so that cleanup call can safely check for NULL */ 1097c478bd9Sstevel@tonic-gate auth_context = NULL; 1107c478bd9Sstevel@tonic-gate addr_p = NULL; 1117c478bd9Sstevel@tonic-gate memset(&chpw_req, 0, sizeof (krb5_data)); 1127c478bd9Sstevel@tonic-gate memset(&chpw_rep, 0, sizeof (krb5_data)); 1137c478bd9Sstevel@tonic-gate memset(&ap_req, 0, sizeof (krb5_data)); 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* initialize auth_context so that we know we have to free it */ 1167c478bd9Sstevel@tonic-gate if ((code = krb5_auth_con_init(context, &auth_context))) 1177c478bd9Sstevel@tonic-gate goto cleanup; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate if (code = krb5_mk_req_extended(context, &auth_context, 1207c478bd9Sstevel@tonic-gate AP_OPTS_USE_SUBKEY, 1217c478bd9Sstevel@tonic-gate NULL, creds, &ap_req)) 1227c478bd9Sstevel@tonic-gate goto cleanup; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* 1257c478bd9Sstevel@tonic-gate * find the address of the kpasswd_server. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate addr_p = (struct sockaddr *)malloc(sizeof (struct sockaddr)); 1287c478bd9Sstevel@tonic-gate if (!addr_p) 1297c478bd9Sstevel@tonic-gate goto cleanup; 1307c478bd9Sstevel@tonic-gate memset(addr_p, 0, sizeof (struct sockaddr)); 1317c478bd9Sstevel@tonic-gate if ((hp = gethostbyname(params->kpasswd_server)) == NULL) { 1327c478bd9Sstevel@tonic-gate code = KRB5_REALM_CANT_RESOLVE; 1337c478bd9Sstevel@tonic-gate goto cleanup; 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate sin_p = (struct sockaddr_in *)addr_p; 1367c478bd9Sstevel@tonic-gate memset((char *)sin_p, 0, sizeof (struct sockaddr)); 1377c478bd9Sstevel@tonic-gate sin_p->sin_family = hp->h_addrtype; 1387c478bd9Sstevel@tonic-gate sin_p->sin_port = htons(params->kpasswd_port); 1397c478bd9Sstevel@tonic-gate memcpy((char *)&sin_p->sin_addr, (char *)hp->h_addr, hp->h_length); 1407c478bd9Sstevel@tonic-gate naddr_p = 1; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /* 1447c478bd9Sstevel@tonic-gate * this is really obscure. s1 is used for all communications. it 1457c478bd9Sstevel@tonic-gate * is left unconnected in case the server is multihomed and routes 1467c478bd9Sstevel@tonic-gate * are asymmetric. s2 is connected to resolve routes and get 1477c478bd9Sstevel@tonic-gate * addresses. this is the *only* way to get proper addresses for 1487c478bd9Sstevel@tonic-gate * multihomed hosts if routing is asymmetric. 1497c478bd9Sstevel@tonic-gate * 1507c478bd9Sstevel@tonic-gate * A related problem in the server, but not the client, is that 1517c478bd9Sstevel@tonic-gate * many os's have no way to disconnect a connected udp socket, so 1527c478bd9Sstevel@tonic-gate * the s2 socket needs to be closed and recreated for each 1537c478bd9Sstevel@tonic-gate * request. The s1 socket must not be closed, or else queued 1547c478bd9Sstevel@tonic-gate * requests will be lost. 1557c478bd9Sstevel@tonic-gate * 1567c478bd9Sstevel@tonic-gate * A "naive" client implementation (one socket, no connect, 1577c478bd9Sstevel@tonic-gate * hostname resolution to get the local ip addr) will work and 1587c478bd9Sstevel@tonic-gate * interoperate if the client is single-homed. 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) 1627c478bd9Sstevel@tonic-gate { 1637c478bd9Sstevel@tonic-gate code = errno; 1647c478bd9Sstevel@tonic-gate goto cleanup; 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) 1687c478bd9Sstevel@tonic-gate { 1697c478bd9Sstevel@tonic-gate code = errno; 1707c478bd9Sstevel@tonic-gate goto cleanup; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate for (i = 0; i < naddr_p; i++) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate fd_set fdset; 1767c478bd9Sstevel@tonic-gate struct timeval timeout; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate if (connect(s2, &addr_p[i], sizeof (addr_p[i])) == 1797c478bd9Sstevel@tonic-gate SOCKET_ERROR) 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate if ((errno == ECONNREFUSED) || 1827c478bd9Sstevel@tonic-gate (errno == EHOSTUNREACH)) 1837c478bd9Sstevel@tonic-gate continue; /* try the next addr */ 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate code = errno; 1867c478bd9Sstevel@tonic-gate goto cleanup; 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate addrlen = sizeof (local_addr); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (getsockname(s2, &local_addr, &addrlen) < 0) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate if ((errno == ECONNREFUSED) || 1947c478bd9Sstevel@tonic-gate (errno == EHOSTUNREACH)) 1957c478bd9Sstevel@tonic-gate continue; /* try the next addr */ 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate code = errno; 1987c478bd9Sstevel@tonic-gate goto cleanup; 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * some brain-dead OS's don't return useful information from 2037c478bd9Sstevel@tonic-gate * the getsockname call. Namely, windows and solaris. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) 2067c478bd9Sstevel@tonic-gate { 2077c478bd9Sstevel@tonic-gate local_kaddr.addrtype = ADDRTYPE_INET; 2087c478bd9Sstevel@tonic-gate local_kaddr.length = sizeof (((struct sockaddr_in *) 2097c478bd9Sstevel@tonic-gate &local_addr)->sin_addr); 2107c478bd9Sstevel@tonic-gate local_kaddr.contents = (krb5_octet *) 2117c478bd9Sstevel@tonic-gate &(((struct sockaddr_in *) 2127c478bd9Sstevel@tonic-gate &local_addr)->sin_addr); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate else 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate krb5_address **addrs; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate krb5_os_localaddr(context, &addrs); 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate local_kaddr.magic = addrs[0]->magic; 2217c478bd9Sstevel@tonic-gate local_kaddr.addrtype = addrs[0]->addrtype; 2227c478bd9Sstevel@tonic-gate local_kaddr.length = addrs[0]->length; 2237c478bd9Sstevel@tonic-gate local_kaddr.contents = malloc(addrs[0]->length); 2247c478bd9Sstevel@tonic-gate memcpy(local_kaddr.contents, addrs[0]->contents, 2257c478bd9Sstevel@tonic-gate addrs[0]->length); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate krb5_free_addresses(context, addrs); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate addrlen = sizeof (remote_addr); 2317c478bd9Sstevel@tonic-gate if (getpeername(s2, &remote_addr, &addrlen) < 0) 2327c478bd9Sstevel@tonic-gate { 2337c478bd9Sstevel@tonic-gate if ((errno == ECONNREFUSED) || 2347c478bd9Sstevel@tonic-gate (errno == EHOSTUNREACH)) 2357c478bd9Sstevel@tonic-gate continue; /* try the next addr */ 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate code = errno; 2387c478bd9Sstevel@tonic-gate goto cleanup; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate remote_kaddr.addrtype = ADDRTYPE_INET; 2427c478bd9Sstevel@tonic-gate remote_kaddr.length = sizeof (((struct sockaddr_in *) 2437c478bd9Sstevel@tonic-gate &remote_addr)->sin_addr); 2447c478bd9Sstevel@tonic-gate remote_kaddr.contents = (krb5_octet *) 2457c478bd9Sstevel@tonic-gate &(((struct sockaddr_in *)&remote_addr)->sin_addr); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate /* 2487c478bd9Sstevel@tonic-gate * mk_priv requires that the local address be set. 2497c478bd9Sstevel@tonic-gate * getsockname is used for this. rd_priv requires that the 2507c478bd9Sstevel@tonic-gate * remote address be set. recvfrom is used for this. If 2517c478bd9Sstevel@tonic-gate * rd_priv is given a local address, and the message has the 2527c478bd9Sstevel@tonic-gate * recipient addr in it, this will be checked. However, there 2537c478bd9Sstevel@tonic-gate * is simply no way to know ahead of time what address the 2547c478bd9Sstevel@tonic-gate * message will be delivered *to*. Therefore, it is important 2557c478bd9Sstevel@tonic-gate * that either no recipient address is in the messages when 2567c478bd9Sstevel@tonic-gate * mk_priv is called, or that no local address is passed to 2577c478bd9Sstevel@tonic-gate * rd_priv. Both is a better idea, and I have done that. In 2587c478bd9Sstevel@tonic-gate * summary, when mk_priv is called, *only* a local address is 2597c478bd9Sstevel@tonic-gate * specified. when rd_priv is called, *only* a remote address 2607c478bd9Sstevel@tonic-gate * is specified. Are we having fun yet? 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate if (code = krb5_auth_con_setaddrs(context, auth_context, 2647c478bd9Sstevel@tonic-gate &local_kaddr, NULL)) 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate code = errno; 2677c478bd9Sstevel@tonic-gate goto cleanup; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 270*159d09a2SMark Phalan if (code = krb5int_mk_chpw_req(context, auth_context, 2717c478bd9Sstevel@tonic-gate &ap_req, newpw, &chpw_req)) 2727c478bd9Sstevel@tonic-gate { 2737c478bd9Sstevel@tonic-gate code = errno; 2747c478bd9Sstevel@tonic-gate goto cleanup; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if ((cc = sendto(s1, chpw_req.data, chpw_req.length, 0, 2787c478bd9Sstevel@tonic-gate (struct sockaddr *)&addr_p[i], 2797c478bd9Sstevel@tonic-gate sizeof (addr_p[i]))) != chpw_req.length) 2807c478bd9Sstevel@tonic-gate { 2817c478bd9Sstevel@tonic-gate if ((cc < 0) && ((errno == ECONNREFUSED) || 2827c478bd9Sstevel@tonic-gate (errno == EHOSTUNREACH))) 2837c478bd9Sstevel@tonic-gate continue; /* try the next addr */ 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate code = (cc < 0) ? errno : ECONNABORTED; 2867c478bd9Sstevel@tonic-gate goto cleanup; 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate chpw_rep.length = 1500; 2907c478bd9Sstevel@tonic-gate chpw_rep.data = (char *)malloc(chpw_rep.length); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* XXX need a timeout/retry loop here */ 2937c478bd9Sstevel@tonic-gate FD_ZERO(&fdset); 2947c478bd9Sstevel@tonic-gate FD_SET(s1, &fdset); 2957c478bd9Sstevel@tonic-gate timeout.tv_sec = 120; 2967c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 2977c478bd9Sstevel@tonic-gate switch (select(s1 + 1, &fdset, 0, 0, &timeout)) { 2987c478bd9Sstevel@tonic-gate case -1: 2997c478bd9Sstevel@tonic-gate code = errno; 3007c478bd9Sstevel@tonic-gate goto cleanup; 3017c478bd9Sstevel@tonic-gate case 0: 3027c478bd9Sstevel@tonic-gate code = ETIMEDOUT; 3037c478bd9Sstevel@tonic-gate goto cleanup; 3047c478bd9Sstevel@tonic-gate default: 3057c478bd9Sstevel@tonic-gate /* fall through */ 3067c478bd9Sstevel@tonic-gate ; 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate tmp_len = sizeof (tmp_addr); 3107c478bd9Sstevel@tonic-gate if ((cc = recvfrom(s1, chpw_rep.data, chpw_rep.length, 3117c478bd9Sstevel@tonic-gate 0, &tmp_addr, &tmp_len)) < 0) 3127c478bd9Sstevel@tonic-gate { 3137c478bd9Sstevel@tonic-gate code = errno; 3147c478bd9Sstevel@tonic-gate goto cleanup; 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate closesocket(s1); 3187c478bd9Sstevel@tonic-gate s1 = INVALID_SOCKET; 3197c478bd9Sstevel@tonic-gate closesocket(s2); 3207c478bd9Sstevel@tonic-gate s2 = INVALID_SOCKET; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate chpw_rep.length = cc; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if (code = krb5_auth_con_setaddrs(context, auth_context, 3257c478bd9Sstevel@tonic-gate NULL, &remote_kaddr)) 3267c478bd9Sstevel@tonic-gate goto cleanup; 3277c478bd9Sstevel@tonic-gate 328*159d09a2SMark Phalan if (code = krb5int_rd_chpw_rep(context, auth_context, &chpw_rep, 3297c478bd9Sstevel@tonic-gate &local_result_code, srvr_msg)) 3307c478bd9Sstevel@tonic-gate goto cleanup; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate if (srvr_rsp_code) 3337c478bd9Sstevel@tonic-gate *srvr_rsp_code = local_result_code; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate code = 0; 3367c478bd9Sstevel@tonic-gate goto cleanup; 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate code = errno; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate cleanup: 3427c478bd9Sstevel@tonic-gate if (auth_context != NULL) 3437c478bd9Sstevel@tonic-gate krb5_auth_con_free(context, auth_context); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate if (addr_p != NULL) 3467c478bd9Sstevel@tonic-gate krb5_xfree(addr_p); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate if (s1 != INVALID_SOCKET) 3497c478bd9Sstevel@tonic-gate closesocket(s1); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if (s2 != INVALID_SOCKET) 3527c478bd9Sstevel@tonic-gate closesocket(s2); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate krb5_xfree(chpw_req.data); 3557c478bd9Sstevel@tonic-gate krb5_xfree(chpw_rep.data); 3567c478bd9Sstevel@tonic-gate krb5_xfree(ap_req.data); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate return (code); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * kadm5_chpass_principal_v2 3647c478bd9Sstevel@tonic-gate * 3657c478bd9Sstevel@tonic-gate * New function used to prepare to make the change password request to a 3667c478bd9Sstevel@tonic-gate * non-SEAM admin server. The protocol used in this case is not based on 3677c478bd9Sstevel@tonic-gate * RPCSEC_GSS, it simply makes the request to port 464 (udp and tcp). 3687c478bd9Sstevel@tonic-gate * This is the same way that MIT KRB5 1.2.1 changes passwords. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate kadm5_ret_t 3717c478bd9Sstevel@tonic-gate kadm5_chpass_principal_v2(void *server_handle, 3727c478bd9Sstevel@tonic-gate krb5_principal princ, 3737c478bd9Sstevel@tonic-gate char *newpw, 3747c478bd9Sstevel@tonic-gate kadm5_ret_t *srvr_rsp_code, 3757c478bd9Sstevel@tonic-gate krb5_data *srvr_msg) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate kadm5_ret_t code; 3787c478bd9Sstevel@tonic-gate kadm5_server_handle_t handle = (kadm5_server_handle_t)server_handle; 3797c478bd9Sstevel@tonic-gate krb5_error_code result; 3807c478bd9Sstevel@tonic-gate krb5_creds mcreds; 3817c478bd9Sstevel@tonic-gate krb5_creds ncreds; 3827c478bd9Sstevel@tonic-gate krb5_ccache ccache; 3837c478bd9Sstevel@tonic-gate int cpwlen; 3847c478bd9Sstevel@tonic-gate char *cpw_service = NULL; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * The credentials have already been stored in the cache in the 3887c478bd9Sstevel@tonic-gate * initialization step earlier, but we dont have direct access to it 3897c478bd9Sstevel@tonic-gate * at this level. Derive the cache and fetch the credentials to use for 3907c478bd9Sstevel@tonic-gate * sending the request. 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate memset(&mcreds, 0, sizeof (krb5_creds)); 3937c478bd9Sstevel@tonic-gate if ((code = krb5_cc_resolve(handle->context, handle->cache_name, 3947c478bd9Sstevel@tonic-gate &ccache))) 3957c478bd9Sstevel@tonic-gate return (code); 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* set the client principal in the credential match structure */ 3987c478bd9Sstevel@tonic-gate mcreds.client = princ; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * set the server principal (kadmin/changepw@REALM) in the credential 4027c478bd9Sstevel@tonic-gate * match struct 4037c478bd9Sstevel@tonic-gate */ 4047c478bd9Sstevel@tonic-gate cpwlen = strlen(KADM5_CHANGEPW_SERVICE) + 4057c478bd9Sstevel@tonic-gate strlen(handle->params.realm) + 2; 4067c478bd9Sstevel@tonic-gate cpw_service = malloc(cpwlen); 4077c478bd9Sstevel@tonic-gate if (cpw_service == NULL) { 4087c478bd9Sstevel@tonic-gate return (ENOMEM); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate snprintf(cpw_service, cpwlen, "%s@%s", 4127c478bd9Sstevel@tonic-gate KADM5_CHANGEPW_SERVICE, handle->params.realm); 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate /* generate the server principal from the name string we generated */ 4157c478bd9Sstevel@tonic-gate if ((code = krb5_parse_name(handle->context, cpw_service, 4167c478bd9Sstevel@tonic-gate &mcreds.server))) { 4177c478bd9Sstevel@tonic-gate free(cpw_service); 4187c478bd9Sstevel@tonic-gate return (code); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate /* Find the credentials in the cache */ 4227c478bd9Sstevel@tonic-gate if ((code = krb5_cc_retrieve_cred(handle->context, ccache, 0, &mcreds, 4237c478bd9Sstevel@tonic-gate &ncreds))) { 4247c478bd9Sstevel@tonic-gate free(cpw_service); 4257c478bd9Sstevel@tonic-gate return (code); 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* Now we have all we need to make the change request. */ 429505d05c7Sgtb result = krb5_change_password_local(handle->context, &handle->params, 4307c478bd9Sstevel@tonic-gate &ncreds, newpw, 4317c478bd9Sstevel@tonic-gate srvr_rsp_code, 4327c478bd9Sstevel@tonic-gate srvr_msg); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate free(cpw_service); 4357c478bd9Sstevel@tonic-gate return (result); 4367c478bd9Sstevel@tonic-gate } 437