LCOV - code coverage report
Current view: top level - source4/heimdal/lib/krb5 - changepw.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 199 353 56.4 %
Date: 2021-09-23 10:06:22 Functions: 7 10 70.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "krb5_locl.h"
      35             : 
      36             : #undef __attribute__
      37             : #define __attribute__(X)
      38             : 
      39             : 
      40             : static void
      41             : str2data (krb5_data *d,
      42             :           const char *fmt,
      43             :           ...) __attribute__ ((format (printf, 2, 3)));
      44             : 
      45             : static void
      46           0 : str2data (krb5_data *d,
      47             :           const char *fmt,
      48             :           ...)
      49             : {
      50             :     va_list args;
      51             :     char *str;
      52             : 
      53           0 :     va_start(args, fmt);
      54           0 :     d->length = vasprintf (&str, fmt, args);
      55           0 :     va_end(args);
      56           0 :     d->data = str;
      57           0 : }
      58             : 
      59             : /*
      60             :  * Change password protocol defined by
      61             :  * draft-ietf-cat-kerb-chg-password-02.txt
      62             :  *
      63             :  * Share the response part of the protocol with MS set password
      64             :  * (RFC3244)
      65             :  */
      66             : 
      67             : static krb5_error_code
      68          13 : chgpw_send_request (krb5_context context,
      69             :                     krb5_auth_context *auth_context,
      70             :                     krb5_creds *creds,
      71             :                     krb5_principal targprinc,
      72             :                     int is_stream,
      73             :                     rk_socket_t sock,
      74             :                     const char *passwd,
      75             :                     const char *host)
      76             : {
      77             :     krb5_error_code ret;
      78             :     krb5_data ap_req_data;
      79             :     krb5_data krb_priv_data;
      80             :     krb5_data passwd_data;
      81             :     size_t len;
      82             :     u_char header[6];
      83             :     struct iovec iov[3];
      84             :     struct msghdr msghdr;
      85             : 
      86          13 :     if (is_stream)
      87           0 :         return KRB5_KPASSWD_MALFORMED;
      88             : 
      89          26 :     if (targprinc &&
      90          13 :         krb5_principal_compare(context, creds->client, targprinc) != TRUE)
      91           0 :         return KRB5_KPASSWD_MALFORMED;
      92             : 
      93          13 :     krb5_data_zero (&ap_req_data);
      94             : 
      95          13 :     ret = krb5_mk_req_extended (context,
      96             :                                 auth_context,
      97             :                                 AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
      98             :                                 NULL, /* in_data */
      99             :                                 creds,
     100             :                                 &ap_req_data);
     101          13 :     if (ret)
     102           0 :         return ret;
     103             : 
     104          13 :     passwd_data.data   = rk_UNCONST(passwd);
     105          13 :     passwd_data.length = strlen(passwd);
     106             : 
     107          13 :     krb5_data_zero (&krb_priv_data);
     108             : 
     109          13 :     ret = krb5_mk_priv (context,
     110             :                         *auth_context,
     111             :                         &passwd_data,
     112             :                         &krb_priv_data,
     113             :                         NULL);
     114          13 :     if (ret)
     115           0 :         goto out2;
     116             : 
     117          13 :     len = 6 + ap_req_data.length + krb_priv_data.length;
     118          13 :     header[0] = (len >> 8) & 0xFF;
     119          13 :     header[1] = (len >> 0) & 0xFF;
     120          13 :     header[2] = 0;
     121          13 :     header[3] = 1;
     122          13 :     header[4] = (ap_req_data.length >> 8) & 0xFF;
     123          13 :     header[5] = (ap_req_data.length >> 0) & 0xFF;
     124             : 
     125          13 :     memset(&msghdr, 0, sizeof(msghdr));
     126          13 :     msghdr.msg_name       = NULL;
     127          13 :     msghdr.msg_namelen    = 0;
     128          13 :     msghdr.msg_iov        = iov;
     129          13 :     msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
     130             : #if 0
     131             :     msghdr.msg_control    = NULL;
     132             :     msghdr.msg_controllen = 0;
     133             : #endif
     134             : 
     135          13 :     iov[0].iov_base    = (void*)header;
     136          13 :     iov[0].iov_len     = 6;
     137          13 :     iov[1].iov_base    = ap_req_data.data;
     138          13 :     iov[1].iov_len     = ap_req_data.length;
     139          13 :     iov[2].iov_base    = krb_priv_data.data;
     140          13 :     iov[2].iov_len     = krb_priv_data.length;
     141             : 
     142          13 :     if (rk_IS_SOCKET_ERROR( sendmsg (sock, &msghdr, 0) )) {
     143           0 :         ret = rk_SOCK_ERRNO;
     144           0 :         krb5_set_error_message(context, ret, "sendmsg %s: %s",
     145             :                                host, strerror(ret));
     146             :     }
     147             : 
     148          13 :     krb5_data_free (&krb_priv_data);
     149          13 : out2:
     150          13 :     krb5_data_free (&ap_req_data);
     151          13 :     return ret;
     152             : }
     153             : 
     154             : /*
     155             :  * Set password protocol as defined by RFC3244 --
     156             :  * Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols
     157             :  */
     158             : 
     159             : static krb5_error_code
     160          21 : setpw_send_request (krb5_context context,
     161             :                     krb5_auth_context *auth_context,
     162             :                     krb5_creds *creds,
     163             :                     krb5_principal targprinc,
     164             :                     int is_stream,
     165             :                     rk_socket_t sock,
     166             :                     const char *passwd,
     167             :                     const char *host)
     168             : {
     169             :     krb5_error_code ret;
     170             :     krb5_data ap_req_data;
     171             :     krb5_data krb_priv_data;
     172             :     krb5_data pwd_data;
     173             :     ChangePasswdDataMS chpw;
     174          21 :     size_t len = 0;
     175             :     u_char header[4 + 6];
     176             :     u_char *p;
     177             :     struct iovec iov[3];
     178             :     struct msghdr msghdr;
     179             : 
     180          21 :     krb5_data_zero (&ap_req_data);
     181             : 
     182          21 :     ret = krb5_mk_req_extended (context,
     183             :                                 auth_context,
     184             :                                 AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
     185             :                                 NULL, /* in_data */
     186             :                                 creds,
     187             :                                 &ap_req_data);
     188          21 :     if (ret)
     189           0 :         return ret;
     190             : 
     191          21 :     chpw.newpasswd.length = strlen(passwd);
     192          21 :     chpw.newpasswd.data = rk_UNCONST(passwd);
     193          21 :     if (targprinc) {
     194          21 :         chpw.targname = &targprinc->name;
     195          21 :         chpw.targrealm = &targprinc->realm;
     196             :     } else {
     197           0 :         chpw.targname = NULL;
     198           0 :         chpw.targrealm = NULL;
     199             :     }
     200             : 
     201          21 :     ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
     202             :                        &chpw, &len, ret);
     203          21 :     if (ret) {
     204           0 :         krb5_data_free (&ap_req_data);
     205           0 :         return ret;
     206             :     }
     207             : 
     208          21 :     if(pwd_data.length != len)
     209           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
     210             : 
     211          21 :     ret = krb5_mk_priv (context,
     212             :                         *auth_context,
     213             :                         &pwd_data,
     214             :                         &krb_priv_data,
     215             :                         NULL);
     216          21 :     if (ret)
     217           0 :         goto out2;
     218             : 
     219          21 :     len = 6 + ap_req_data.length + krb_priv_data.length;
     220          21 :     p = header;
     221          21 :     if (is_stream) {
     222           0 :         _krb5_put_int(p, len, 4);
     223           0 :         p += 4;
     224             :     }
     225          21 :     *p++ = (len >> 8) & 0xFF;
     226          21 :     *p++ = (len >> 0) & 0xFF;
     227          21 :     *p++ = 0xff;
     228          21 :     *p++ = 0x80;
     229          21 :     *p++ = (ap_req_data.length >> 8) & 0xFF;
     230          21 :     *p   = (ap_req_data.length >> 0) & 0xFF;
     231             : 
     232          21 :     memset(&msghdr, 0, sizeof(msghdr));
     233          21 :     msghdr.msg_name       = NULL;
     234          21 :     msghdr.msg_namelen    = 0;
     235          21 :     msghdr.msg_iov        = iov;
     236          21 :     msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
     237             : #if 0
     238             :     msghdr.msg_control    = NULL;
     239             :     msghdr.msg_controllen = 0;
     240             : #endif
     241             : 
     242          21 :     iov[0].iov_base    = (void*)header;
     243          21 :     if (is_stream)
     244           0 :         iov[0].iov_len     = 10;
     245             :     else
     246          21 :         iov[0].iov_len     = 6;
     247          21 :     iov[1].iov_base    = ap_req_data.data;
     248          21 :     iov[1].iov_len     = ap_req_data.length;
     249          21 :     iov[2].iov_base    = krb_priv_data.data;
     250          21 :     iov[2].iov_len     = krb_priv_data.length;
     251             : 
     252          21 :     if (rk_IS_SOCKET_ERROR( sendmsg (sock, &msghdr, 0) )) {
     253           0 :         ret = rk_SOCK_ERRNO;
     254           0 :         krb5_set_error_message(context, ret, "sendmsg %s: %s",
     255             :                                host, strerror(ret));
     256             :     }
     257             : 
     258          21 :     krb5_data_free (&krb_priv_data);
     259          21 : out2:
     260          21 :     krb5_data_free (&ap_req_data);
     261          21 :     krb5_data_free (&pwd_data);
     262          21 :     return ret;
     263             : }
     264             : 
     265             : static krb5_error_code
     266          34 : process_reply (krb5_context context,
     267             :                krb5_auth_context auth_context,
     268             :                int is_stream,
     269             :                rk_socket_t sock,
     270             :                int *result_code,
     271             :                krb5_data *result_code_string,
     272             :                krb5_data *result_string,
     273             :                const char *host)
     274             : {
     275             :     krb5_error_code ret;
     276             :     u_char reply[1024 * 3];
     277             :     size_t len;
     278             :     uint16_t pkt_len, pkt_ver;
     279             :     krb5_data ap_rep_data;
     280             :     int save_errno;
     281             : 
     282          34 :     len = 0;
     283          34 :     if (is_stream) {
     284           0 :         while (len < sizeof(reply)) {
     285             :             unsigned long size;
     286             : 
     287           0 :             ret = recvfrom (sock, reply + len, sizeof(reply) - len,
     288             :                             0, NULL, NULL);
     289           0 :             if (rk_IS_SOCKET_ERROR(ret)) {
     290           0 :                 save_errno = rk_SOCK_ERRNO;
     291           0 :                 krb5_set_error_message(context, save_errno,
     292             :                                        "recvfrom %s: %s",
     293             :                                        host, strerror(save_errno));
     294           0 :                 return save_errno;
     295           0 :             } else if (ret == 0) {
     296           0 :                 krb5_set_error_message(context, 1,"recvfrom timeout %s", host);
     297           0 :                 return 1;
     298             :             }
     299           0 :             len += ret;
     300           0 :             if (len < 4)
     301           0 :                 continue;
     302           0 :             _krb5_get_int(reply, &size, 4);
     303           0 :             if (size + 4 < len)
     304           0 :                 continue;
     305           0 :             memmove(reply, reply + 4, size);
     306           0 :             len = size;
     307           0 :             break;
     308             :         }
     309           0 :         if (len == sizeof(reply)) {
     310           0 :             krb5_set_error_message(context, ENOMEM,
     311           0 :                                    N_("Message too large from %s", "host"),
     312             :                                    host);
     313           0 :             return ENOMEM;
     314             :         }
     315             :     } else {
     316          34 :         ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL);
     317          34 :         if (rk_IS_SOCKET_ERROR(ret)) {
     318           0 :             save_errno = rk_SOCK_ERRNO;
     319           0 :             krb5_set_error_message(context, save_errno,
     320             :                                    "recvfrom %s: %s",
     321             :                                    host, strerror(save_errno));
     322           0 :             return save_errno;
     323             :         }
     324          34 :         len = ret;
     325             :     }
     326             : 
     327          34 :     if (len < 6) {
     328           0 :         str2data (result_string, "server %s sent to too short message "
     329             :                   "(%zu bytes)", host, len);
     330           0 :         *result_code = KRB5_KPASSWD_MALFORMED;
     331           0 :         return 0;
     332             :     }
     333             : 
     334          34 :     pkt_len = (reply[0] << 8) | (reply[1]);
     335          34 :     pkt_ver = (reply[2] << 8) | (reply[3]);
     336             : 
     337          34 :     if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) {
     338             :         KRB_ERROR error;
     339             :         size_t size;
     340             :         u_char *p;
     341             : 
     342           0 :         memset(&error, 0, sizeof(error));
     343             : 
     344           0 :         ret = decode_KRB_ERROR(reply, len, &error, &size);
     345           0 :         if (ret)
     346           0 :             return ret;
     347             : 
     348           0 :         if (error.e_data->length < 2) {
     349           0 :             str2data(result_string, "server %s sent too short "
     350             :                      "e_data to print anything usable", host);
     351           0 :             free_KRB_ERROR(&error);
     352           0 :             *result_code = KRB5_KPASSWD_MALFORMED;
     353           0 :             return 0;
     354             :         }
     355             : 
     356           0 :         p = error.e_data->data;
     357           0 :         *result_code = (p[0] << 8) | p[1];
     358           0 :         if (error.e_data->length == 2)
     359           0 :             str2data(result_string, "server only sent error code");
     360             :         else
     361           0 :             krb5_data_copy (result_string,
     362           0 :                             p + 2,
     363           0 :                             error.e_data->length - 2);
     364           0 :         free_KRB_ERROR(&error);
     365           0 :         return 0;
     366             :     }
     367             : 
     368          34 :     if (pkt_len != len) {
     369           0 :         str2data (result_string, "client: wrong len in reply");
     370           0 :         *result_code = KRB5_KPASSWD_MALFORMED;
     371           0 :         return 0;
     372             :     }
     373          34 :     if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) {
     374           0 :         str2data (result_string,
     375             :                   "client: wrong version number (%d)", pkt_ver);
     376           0 :         *result_code = KRB5_KPASSWD_MALFORMED;
     377           0 :         return 0;
     378             :     }
     379             : 
     380          34 :     ap_rep_data.data = reply + 6;
     381          34 :     ap_rep_data.length  = (reply[4] << 8) | (reply[5]);
     382             : 
     383          34 :     if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) {
     384           0 :         str2data (result_string, "client: wrong AP len in reply");
     385           0 :         *result_code = KRB5_KPASSWD_MALFORMED;
     386           0 :         return 0;
     387             :     }
     388             : 
     389          34 :     if (ap_rep_data.length) {
     390             :         krb5_ap_rep_enc_part *ap_rep;
     391             :         krb5_data priv_data;
     392             :         u_char *p;
     393             : 
     394          34 :         priv_data.data   = (u_char*)ap_rep_data.data + ap_rep_data.length;
     395          34 :         priv_data.length = len - ap_rep_data.length - 6;
     396             : 
     397          34 :         ret = krb5_rd_rep (context,
     398             :                            auth_context,
     399             :                            &ap_rep_data,
     400             :                            &ap_rep);
     401          34 :         if (ret)
     402           0 :             return ret;
     403             : 
     404          34 :         krb5_free_ap_rep_enc_part (context, ap_rep);
     405             : 
     406          34 :         ret = krb5_rd_priv (context,
     407             :                             auth_context,
     408             :                             &priv_data,
     409             :                             result_code_string,
     410             :                             NULL);
     411          34 :         if (ret) {
     412           0 :             krb5_data_free (result_code_string);
     413           0 :             return ret;
     414             :         }
     415             : 
     416          34 :         if (result_code_string->length < 2) {
     417           0 :             *result_code = KRB5_KPASSWD_MALFORMED;
     418           0 :             str2data (result_string,
     419             :                       "client: bad length in result");
     420           0 :             return 0;
     421             :         }
     422             : 
     423          34 :         p = result_code_string->data;
     424             : 
     425          34 :         *result_code = (p[0] << 8) | p[1];
     426          68 :         krb5_data_copy (result_string,
     427          34 :                         (unsigned char*)result_code_string->data + 2,
     428          34 :                         result_code_string->length - 2);
     429          34 :         return 0;
     430             :     } else {
     431             :         KRB_ERROR error;
     432             :         size_t size;
     433             :         u_char *p;
     434             : 
     435           0 :         ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size);
     436           0 :         if (ret) {
     437           0 :             return ret;
     438             :         }
     439           0 :         if (error.e_data->length < 2) {
     440           0 :             krb5_warnx (context, "too short e_data to print anything usable");
     441           0 :             return 1;           /* XXX */
     442             :         }
     443             : 
     444           0 :         p = error.e_data->data;
     445           0 :         *result_code = (p[0] << 8) | p[1];
     446           0 :         krb5_data_copy (result_string,
     447           0 :                         p + 2,
     448           0 :                         error.e_data->length - 2);
     449           0 :         return 0;
     450             :     }
     451             : }
     452             : 
     453             : 
     454             : /*
     455             :  * change the password using the credentials in `creds' (for the
     456             :  * principal indicated in them) to `newpw', storing the result of
     457             :  * the operation in `result_*' and an error code or 0.
     458             :  */
     459             : 
     460             : typedef krb5_error_code (*kpwd_send_request) (krb5_context,
     461             :                                               krb5_auth_context *,
     462             :                                               krb5_creds *,
     463             :                                               krb5_principal,
     464             :                                               int,
     465             :                                               rk_socket_t,
     466             :                                               const char *,
     467             :                                               const char *);
     468             : typedef krb5_error_code (*kpwd_process_reply) (krb5_context,
     469             :                                                krb5_auth_context,
     470             :                                                int,
     471             :                                                rk_socket_t,
     472             :                                                int *,
     473             :                                                krb5_data *,
     474             :                                                krb5_data *,
     475             :                                                const char *);
     476             : 
     477             : static struct kpwd_proc {
     478             :     const char *name;
     479             :     int flags;
     480             : #define SUPPORT_TCP     1
     481             : #define SUPPORT_UDP     2
     482             :     kpwd_send_request send_req;
     483             :     kpwd_process_reply process_rep;
     484             : } procs[] = {
     485             :     {
     486             :         "MS set password",
     487             :         SUPPORT_TCP|SUPPORT_UDP,
     488             :         setpw_send_request,
     489             :         process_reply
     490             :     },
     491             :     {
     492             :         "change password",
     493             :         SUPPORT_UDP,
     494             :         chgpw_send_request,
     495             :         process_reply
     496             :     },
     497             :     { NULL, 0, NULL, NULL }
     498             : };
     499             : 
     500             : /*
     501             :  *
     502             :  */
     503             : 
     504             : static krb5_error_code
     505          34 : change_password_loop (krb5_context      context,
     506             :                       krb5_creds        *creds,
     507             :                       krb5_principal    targprinc,
     508             :                       const char        *newpw,
     509             :                       int               *result_code,
     510             :                       krb5_data         *result_code_string,
     511             :                       krb5_data         *result_string,
     512             :                       struct kpwd_proc  *proc)
     513             : {
     514             :     krb5_error_code ret;
     515          34 :     krb5_auth_context auth_context = NULL;
     516          34 :     krb5_krbhst_handle handle = NULL;
     517             :     krb5_krbhst_info *hi;
     518             :     rk_socket_t sock;
     519             :     unsigned int i;
     520          34 :     int done = 0;
     521             :     krb5_realm realm;
     522             : 
     523          34 :     if (targprinc)
     524          34 :         realm = targprinc->realm;
     525             :     else
     526           0 :         realm = creds->client->realm;
     527             : 
     528          34 :     ret = krb5_auth_con_init (context, &auth_context);
     529          34 :     if (ret)
     530           0 :         return ret;
     531             : 
     532          34 :     krb5_auth_con_setflags (context, auth_context,
     533             :                             KRB5_AUTH_CONTEXT_DO_SEQUENCE);
     534             : 
     535          34 :     ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle);
     536          34 :     if (ret)
     537           0 :         goto out;
     538             : 
     539         136 :     while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) {
     540             :         struct addrinfo *ai, *a;
     541             :         int is_stream;
     542             : 
     543          34 :         switch (hi->proto) {
     544          34 :         case KRB5_KRBHST_UDP:
     545          34 :             if ((proc->flags & SUPPORT_UDP) == 0)
     546           0 :                 continue;
     547          34 :             is_stream = 0;
     548          34 :             break;
     549           0 :         case KRB5_KRBHST_TCP:
     550           0 :             if ((proc->flags & SUPPORT_TCP) == 0)
     551           0 :                 continue;
     552           0 :             is_stream = 1;
     553           0 :             break;
     554           0 :         default:
     555           0 :             continue;
     556             :         }
     557             : 
     558          34 :         ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
     559          34 :         if (ret)
     560           0 :             continue;
     561             : 
     562          68 :         for (a = ai; !done && a != NULL; a = a->ai_next) {
     563          34 :             int replied = 0;
     564             : 
     565          34 :             sock = socket (a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol);
     566          34 :             if (rk_IS_BAD_SOCKET(sock))
     567           0 :                 continue;
     568          34 :             rk_cloexec(sock);
     569             : 
     570          34 :             ret = connect(sock, a->ai_addr, a->ai_addrlen);
     571          34 :             if (rk_IS_SOCKET_ERROR(ret)) {
     572           0 :                 rk_closesocket (sock);
     573           0 :                 goto out;
     574             :             }
     575             : 
     576          34 :             ret = krb5_auth_con_genaddrs (context, auth_context, sock,
     577             :                                           KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
     578          34 :             if (ret) {
     579           0 :                 rk_closesocket (sock);
     580           0 :                 goto out;
     581             :             }
     582             : 
     583         136 :             for (i = 0; !done && i < 5; ++i) {
     584             :                 fd_set fdset;
     585             :                 struct timeval tv;
     586             : 
     587          34 :                 if (!replied) {
     588          34 :                     replied = 0;
     589             : 
     590          68 :                     ret = (*proc->send_req) (context,
     591             :                                              &auth_context,
     592             :                                              creds,
     593             :                                              targprinc,
     594             :                                              is_stream,
     595             :                                              sock,
     596             :                                              newpw,
     597          34 :                                              hi->hostname);
     598          34 :                     if (ret) {
     599           0 :                         rk_closesocket(sock);
     600           0 :                         goto out;
     601             :                     }
     602             :                 }
     603             : 
     604             : #ifndef NO_LIMIT_FD_SETSIZE
     605          34 :                 if (sock >= FD_SETSIZE) {
     606           0 :                     ret = ERANGE;
     607           0 :                     krb5_set_error_message(context, ret,
     608             :                                            "fd %d too large", sock);
     609           0 :                     rk_closesocket (sock);
     610           0 :                     goto out;
     611             :                 }
     612             : #endif
     613             : 
     614          34 :                 FD_ZERO(&fdset);
     615          34 :                 FD_SET(sock, &fdset);
     616          34 :                 tv.tv_usec = 0;
     617          34 :                 tv.tv_sec  = 1 + (1 << i);
     618             : 
     619          34 :                 ret = select (sock + 1, &fdset, NULL, NULL, &tv);
     620          34 :                 if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR) {
     621           0 :                     rk_closesocket(sock);
     622           0 :                     goto out;
     623             :                 }
     624          34 :                 if (ret == 1) {
     625          68 :                     ret = (*proc->process_rep) (context,
     626             :                                                 auth_context,
     627             :                                                 is_stream,
     628             :                                                 sock,
     629             :                                                 result_code,
     630             :                                                 result_code_string,
     631             :                                                 result_string,
     632          34 :                                                 hi->hostname);
     633          34 :                     if (ret == 0)
     634          34 :                         done = 1;
     635           0 :                     else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL)
     636           0 :                         replied = 1;
     637             :                 } else {
     638           0 :                     ret = KRB5_KDC_UNREACH;
     639             :                 }
     640             :             }
     641          34 :             rk_closesocket (sock);
     642             :         }
     643             :     }
     644             : 
     645          34 :  out:
     646          34 :     krb5_krbhst_free (context, handle);
     647          34 :     krb5_auth_con_free (context, auth_context);
     648             : 
     649          34 :     if (ret == KRB5_KDC_UNREACH) {
     650           0 :         krb5_set_error_message(context,
     651             :                                ret,
     652           0 :                                N_("Unable to reach any changepw server "
     653             :                                  " in realm %s", "realm"), realm);
     654           0 :         *result_code = KRB5_KPASSWD_HARDERROR;
     655             :     }
     656          34 :     return ret;
     657             : }
     658             : 
     659             : #ifndef HEIMDAL_SMALLER
     660             : 
     661             : static struct kpwd_proc *
     662           0 : find_chpw_proto(const char *name)
     663             : {
     664             :     struct kpwd_proc *p;
     665           0 :     for (p = procs; p->name != NULL; p++) {
     666           0 :         if (strcmp(p->name, name) == 0)
     667           0 :             return p;
     668             :     }
     669           0 :     return NULL;
     670             : }
     671             : 
     672             : /**
     673             :  * Deprecated: krb5_change_password() is deprecated, use krb5_set_password().
     674             :  *
     675             :  * @param context a Keberos context
     676             :  * @param creds
     677             :  * @param newpw
     678             :  * @param result_code
     679             :  * @param result_code_string
     680             :  * @param result_string
     681             :  *
     682             :  * @return On sucess password is changed.
     683             : 
     684             :  * @ingroup @krb5_deprecated
     685             :  */
     686             : 
     687             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     688           0 : krb5_change_password (krb5_context      context,
     689             :                       krb5_creds        *creds,
     690             :                       const char        *newpw,
     691             :                       int               *result_code,
     692             :                       krb5_data         *result_code_string,
     693             :                       krb5_data         *result_string)
     694             :     KRB5_DEPRECATED_FUNCTION("Use X instead")
     695             : {
     696           0 :     struct kpwd_proc *p = find_chpw_proto("change password");
     697             : 
     698           0 :     *result_code = KRB5_KPASSWD_MALFORMED;
     699           0 :     result_code_string->data = result_string->data = NULL;
     700           0 :     result_code_string->length = result_string->length = 0;
     701             : 
     702           0 :     if (p == NULL)
     703           0 :         return KRB5_KPASSWD_MALFORMED;
     704             : 
     705           0 :     return change_password_loop(context, creds, NULL, newpw,
     706             :                                 result_code, result_code_string,
     707             :                                 result_string, p);
     708             : }
     709             : #endif /* HEIMDAL_SMALLER */
     710             : 
     711             : /**
     712             :  * Change password using creds.
     713             :  *
     714             :  * @param context a Keberos context
     715             :  * @param creds The initial kadmin/passwd for the principal or an admin principal
     716             :  * @param newpw The new password to set
     717             :  * @param targprinc if unset, the default principal is used.
     718             :  * @param result_code Result code, KRB5_KPASSWD_SUCCESS is when password is changed.
     719             :  * @param result_code_string binary message from the server, contains
     720             :  * at least the result_code.
     721             :  * @param result_string A message from the kpasswd service or the
     722             :  * library in human printable form. The string is NUL terminated.
     723             :  *
     724             :  * @return On sucess and *result_code is KRB5_KPASSWD_SUCCESS, the password is changed.
     725             : 
     726             :  * @ingroup @krb5
     727             :  */
     728             : 
     729             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     730          21 : krb5_set_password(krb5_context context,
     731             :                   krb5_creds *creds,
     732             :                   const char *newpw,
     733             :                   krb5_principal targprinc,
     734             :                   int *result_code,
     735             :                   krb5_data *result_code_string,
     736             :                   krb5_data *result_string)
     737             : {
     738          21 :     krb5_principal principal = NULL;
     739          21 :     krb5_error_code ret = 0;
     740             :     int i;
     741             : 
     742          21 :     *result_code = KRB5_KPASSWD_MALFORMED;
     743          21 :     krb5_data_zero(result_code_string);
     744          21 :     krb5_data_zero(result_string);
     745             : 
     746          21 :     if (targprinc == NULL) {
     747           3 :         ret = krb5_get_default_principal(context, &principal);
     748           3 :         if (ret)
     749           0 :             return ret;
     750             :     } else
     751          18 :         principal = targprinc;
     752             : 
     753          36 :     for (i = 0; procs[i].name != NULL; i++) {
     754          34 :         *result_code = 0;
     755          34 :         ret = change_password_loop(context, creds, principal, newpw,
     756             :                                    result_code, result_code_string,
     757             :                                    result_string,
     758             :                                    &procs[i]);
     759          34 :         if (ret == 0 && *result_code == 0)
     760          19 :             break;
     761             :     }
     762             : 
     763          21 :     if (targprinc == NULL)
     764           3 :         krb5_free_principal(context, principal);
     765          21 :     return ret;
     766             : }
     767             : 
     768             : /*
     769             :  *
     770             :  */
     771             : 
     772             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     773          14 : krb5_set_password_using_ccache(krb5_context context,
     774             :                                krb5_ccache ccache,
     775             :                                const char *newpw,
     776             :                                krb5_principal targprinc,
     777             :                                int *result_code,
     778             :                                krb5_data *result_code_string,
     779             :                                krb5_data *result_string)
     780             : {
     781             :     krb5_creds creds, *credsp;
     782             :     krb5_error_code ret;
     783          14 :     krb5_principal principal = NULL;
     784             : 
     785          14 :     *result_code = KRB5_KPASSWD_MALFORMED;
     786          14 :     result_code_string->data = result_string->data = NULL;
     787          14 :     result_code_string->length = result_string->length = 0;
     788             : 
     789          14 :     memset(&creds, 0, sizeof(creds));
     790             : 
     791          14 :     if (targprinc == NULL) {
     792           0 :         ret = krb5_cc_get_principal(context, ccache, &principal);
     793           0 :         if (ret)
     794           0 :             return ret;
     795             :     } else
     796          14 :         principal = targprinc;
     797             : 
     798          14 :     ret = krb5_make_principal(context, &creds.server,
     799             :                               krb5_principal_get_realm(context, principal),
     800             :                               "kadmin", "changepw", NULL);
     801          14 :     if (ret)
     802           0 :         goto out;
     803             : 
     804          14 :     ret = krb5_cc_get_principal(context, ccache, &creds.client);
     805          14 :     if (ret) {
     806           0 :         krb5_free_principal(context, creds.server);
     807           0 :         goto out;
     808             :     }
     809             : 
     810          14 :     ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
     811          14 :     krb5_free_principal(context, creds.server);
     812          14 :     krb5_free_principal(context, creds.client);
     813          14 :     if (ret)
     814           0 :         goto out;
     815             : 
     816          14 :     ret = krb5_set_password(context,
     817             :                             credsp,
     818             :                             newpw,
     819             :                             principal,
     820             :                             result_code,
     821             :                             result_code_string,
     822             :                             result_string);
     823             : 
     824          14 :     krb5_free_creds(context, credsp);
     825             : 
     826          14 :     return ret;
     827           0 :  out:
     828           0 :     if (targprinc == NULL)
     829           0 :         krb5_free_principal(context, principal);
     830           0 :     return ret;
     831             : }
     832             : 
     833             : /*
     834             :  *
     835             :  */
     836             : 
     837             : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
     838          12 : krb5_passwd_result_to_string (krb5_context context,
     839             :                               int result)
     840             : {
     841             :     static const char *strings[] = {
     842             :         "Success",
     843             :         "Malformed",
     844             :         "Hard error",
     845             :         "Auth error",
     846             :         "Soft error" ,
     847             :         "Access denied",
     848             :         "Bad version",
     849             :         "Initial flag needed"
     850             :     };
     851             : 
     852          12 :     if (result < 0 || result > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)
     853           0 :         return "unknown result code";
     854             :     else
     855          12 :         return strings[result];
     856             : }

Generated by: LCOV version 1.13