LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - changepw.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 199 405 49.1 %
Date: 2024-04-13 12:30:31 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           0 :     va_list args;
      51           0 :     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           0 :     krb5_error_code ret;
      78           0 :     krb5_data ap_req_data;
      79           0 :     krb5_data krb_priv_data;
      80           0 :     krb5_data passwd_data;
      81           0 :     size_t len;
      82           0 :     u_char header[6];
      83           0 :     struct iovec iov[3];
      84           0 :     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          16 : 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           0 :     krb5_error_code ret;
     170           0 :     krb5_data ap_req_data;
     171           0 :     krb5_data krb_priv_data;
     172           0 :     krb5_data pwd_data;
     173           0 :     ChangePasswdDataMS chpw;
     174          16 :     size_t len = 0;
     175           0 :     u_char header[4 + 6];
     176           0 :     u_char *p;
     177           0 :     struct iovec iov[3];
     178           0 :     struct msghdr msghdr;
     179             : 
     180          16 :     krb5_data_zero (&ap_req_data);
     181             : 
     182          16 :     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          16 :     if (ret)
     189           0 :         return ret;
     190             : 
     191          16 :     chpw.newpasswd.length = strlen(passwd);
     192          16 :     chpw.newpasswd.data = rk_UNCONST(passwd);
     193          16 :     if (targprinc) {
     194          16 :         chpw.targname = &targprinc->name;
     195          16 :         chpw.targrealm = &targprinc->realm;
     196             :     } else {
     197           0 :         chpw.targname = NULL;
     198           0 :         chpw.targrealm = NULL;
     199             :     }
     200             : 
     201          16 :     ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
     202             :                        &chpw, &len, ret);
     203          16 :     if (ret) {
     204           0 :         krb5_data_free (&ap_req_data);
     205           0 :         return ret;
     206             :     }
     207             : 
     208          16 :     if(pwd_data.length != len)
     209           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
     210             : 
     211          16 :     ret = krb5_mk_priv (context,
     212             :                         *auth_context,
     213             :                         &pwd_data,
     214             :                         &krb_priv_data,
     215             :                         NULL);
     216          16 :     if (ret)
     217           0 :         goto out2;
     218             : 
     219          16 :     len = 6 + ap_req_data.length + krb_priv_data.length;
     220          16 :     p = header;
     221          16 :     if (is_stream) {
     222           0 :         _krb5_put_int(p, len, 4);
     223           0 :         p += 4;
     224             :     }
     225          16 :     *p++ = (len >> 8) & 0xFF;
     226          16 :     *p++ = (len >> 0) & 0xFF;
     227          16 :     *p++ = 0xff;
     228          16 :     *p++ = 0x80;
     229          16 :     *p++ = (ap_req_data.length >> 8) & 0xFF;
     230          16 :     *p   = (ap_req_data.length >> 0) & 0xFF;
     231             : 
     232          16 :     memset(&msghdr, 0, sizeof(msghdr));
     233          16 :     msghdr.msg_name       = NULL;
     234          16 :     msghdr.msg_namelen    = 0;
     235          16 :     msghdr.msg_iov        = iov;
     236          16 :     msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
     237             : #if 0
     238             :     msghdr.msg_control    = NULL;
     239             :     msghdr.msg_controllen = 0;
     240             : #endif
     241             : 
     242          16 :     iov[0].iov_base    = (void*)header;
     243          16 :     if (is_stream)
     244           0 :         iov[0].iov_len     = 10;
     245             :     else
     246          16 :         iov[0].iov_len     = 6;
     247          16 :     iov[1].iov_base    = ap_req_data.data;
     248          16 :     iov[1].iov_len     = ap_req_data.length;
     249          16 :     iov[2].iov_base    = krb_priv_data.data;
     250          16 :     iov[2].iov_len     = krb_priv_data.length;
     251             : 
     252          16 :     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          16 :     krb5_data_free (&krb_priv_data);
     259          16 : out2:
     260          16 :     krb5_data_free (&ap_req_data);
     261          16 :     krb5_data_free (&pwd_data);
     262          16 :     return ret;
     263             : }
     264             : 
     265             : static krb5_error_code
     266          29 : 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           0 :     krb5_error_code ret;
     276           0 :     u_char reply[1024 * 3];
     277           0 :     size_t len;
     278           0 :     uint16_t pkt_len, pkt_ver;
     279           0 :     krb5_data ap_rep_data;
     280           0 :     int save_errno;
     281             : 
     282          29 :     len = 0;
     283          29 :     if (is_stream) {
     284           0 :         while (len < sizeof(reply)) {
     285           0 :             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 :             if (sizeof(reply) - 4 < size) {
     306           0 :                 krb5_set_error_message(context, ERANGE, "size from server too large %s", host);
     307           0 :                 return ERANGE;
     308             :             }
     309           0 :             memmove(reply, reply + 4, size);
     310           0 :             len = size;
     311           0 :             break;
     312             :         }
     313           0 :         if (len == sizeof(reply)) {
     314           0 :             krb5_set_error_message(context, ENOMEM,
     315           0 :                                    N_("Message too large from %s", "host"),
     316             :                                    host);
     317           0 :             return ENOMEM;
     318             :         }
     319             :     } else {
     320          29 :         ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL);
     321          29 :         if (rk_IS_SOCKET_ERROR(ret)) {
     322           0 :             save_errno = rk_SOCK_ERRNO;
     323           0 :             krb5_set_error_message(context, save_errno,
     324             :                                    "recvfrom %s: %s",
     325             :                                    host, strerror(save_errno));
     326           0 :             return save_errno;
     327             :         }
     328          29 :         len = ret;
     329             :     }
     330             : 
     331          29 :     if (len < 6) {
     332           0 :         str2data (result_string, "server %s sent to too short message "
     333             :                   "(%llu bytes)", host, (unsigned long long)len);
     334           0 :         *result_code = KRB5_KPASSWD_MALFORMED;
     335           0 :         return 0;
     336             :     }
     337             : 
     338          29 :     pkt_len = (reply[0] << 8) | (reply[1]);
     339          29 :     pkt_ver = (reply[2] << 8) | (reply[3]);
     340             : 
     341          29 :     if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) {
     342           0 :         KRB_ERROR error;
     343           0 :         size_t size;
     344           0 :         u_char *p;
     345             : 
     346           0 :         memset(&error, 0, sizeof(error));
     347             : 
     348           0 :         ret = decode_KRB_ERROR(reply, len, &error, &size);
     349           0 :         if (ret)
     350           0 :             return ret;
     351             : 
     352           0 :         if (error.e_data->length < 2) {
     353           0 :             str2data(result_string, "server %s sent too short "
     354             :                      "e_data to print anything usable", host);
     355           0 :             free_KRB_ERROR(&error);
     356           0 :             *result_code = KRB5_KPASSWD_MALFORMED;
     357           0 :             return 0;
     358             :         }
     359             : 
     360           0 :         p = error.e_data->data;
     361           0 :         *result_code = (p[0] << 8) | p[1];
     362           0 :         if (error.e_data->length == 2)
     363           0 :             str2data(result_string, "server only sent error code");
     364             :         else
     365           0 :             krb5_data_copy (result_string,
     366           0 :                             p + 2,
     367           0 :                             error.e_data->length - 2);
     368           0 :         free_KRB_ERROR(&error);
     369           0 :         return 0;
     370             :     }
     371             : 
     372          29 :     if (pkt_len != len) {
     373           0 :         str2data (result_string, "client: wrong len in reply");
     374           0 :         *result_code = KRB5_KPASSWD_MALFORMED;
     375           0 :         return 0;
     376             :     }
     377          29 :     if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) {
     378           0 :         str2data (result_string,
     379             :                   "client: wrong version number (%d)", pkt_ver);
     380           0 :         *result_code = KRB5_KPASSWD_MALFORMED;
     381           0 :         return 0;
     382             :     }
     383             : 
     384          29 :     ap_rep_data.data = reply + 6;
     385          29 :     ap_rep_data.length  = (reply[4] << 8) | (reply[5]);
     386             : 
     387          29 :     if (len - 6 < ap_rep_data.length) {
     388           0 :         str2data (result_string, "client: wrong AP len in reply");
     389           0 :         *result_code = KRB5_KPASSWD_MALFORMED;
     390           0 :         return 0;
     391             :     }
     392             : 
     393          29 :     if (ap_rep_data.length) {
     394           0 :         krb5_ap_rep_enc_part *ap_rep;
     395           0 :         krb5_data priv_data;
     396           0 :         u_char *p;
     397             : 
     398          29 :         priv_data.data   = (u_char*)ap_rep_data.data + ap_rep_data.length;
     399          29 :         priv_data.length = len - ap_rep_data.length - 6;
     400             : 
     401          29 :         ret = krb5_rd_rep (context,
     402             :                            auth_context,
     403             :                            &ap_rep_data,
     404             :                            &ap_rep);
     405          29 :         if (ret)
     406           0 :             return ret;
     407             : 
     408          29 :         krb5_free_ap_rep_enc_part (context, ap_rep);
     409             : 
     410          29 :         ret = krb5_rd_priv (context,
     411             :                             auth_context,
     412             :                             &priv_data,
     413             :                             result_code_string,
     414             :                             NULL);
     415          29 :         if (ret) {
     416           0 :             krb5_data_free (result_code_string);
     417           0 :             return ret;
     418             :         }
     419             : 
     420          29 :         if (result_code_string->length < 2) {
     421           0 :             *result_code = KRB5_KPASSWD_MALFORMED;
     422           0 :             str2data (result_string,
     423             :                       "client: bad length in result");
     424           0 :             return 0;
     425             :         }
     426             : 
     427          29 :         p = result_code_string->data;
     428             : 
     429          29 :         *result_code = (p[0] << 8) | p[1];
     430          29 :         krb5_data_copy (result_string,
     431          29 :                         (unsigned char*)result_code_string->data + 2,
     432          29 :                         result_code_string->length - 2);
     433          29 :         return 0;
     434             :     } else {
     435           0 :         KRB_ERROR error;
     436           0 :         size_t size;
     437           0 :         u_char *p;
     438             : 
     439           0 :         ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size);
     440           0 :         if (ret) {
     441           0 :             return ret;
     442             :         }
     443           0 :         if (error.e_data->length < 2) {
     444           0 :             krb5_warnx (context, "too short e_data to print anything usable");
     445           0 :             return 1;           /* XXX */
     446             :         }
     447             : 
     448           0 :         p = error.e_data->data;
     449           0 :         *result_code = (p[0] << 8) | p[1];
     450           0 :         krb5_data_copy (result_string,
     451           0 :                         p + 2,
     452           0 :                         error.e_data->length - 2);
     453           0 :         return 0;
     454             :     }
     455             : }
     456             : 
     457             : 
     458             : /*
     459             :  * change the password using the credentials in `creds' (for the
     460             :  * principal indicated in them) to `newpw', storing the result of
     461             :  * the operation in `result_*' and an error code or 0.
     462             :  */
     463             : 
     464             : typedef krb5_error_code (*kpwd_send_request) (krb5_context,
     465             :                                               krb5_auth_context *,
     466             :                                               krb5_creds *,
     467             :                                               krb5_principal,
     468             :                                               int,
     469             :                                               rk_socket_t,
     470             :                                               const char *,
     471             :                                               const char *);
     472             : typedef krb5_error_code (*kpwd_process_reply) (krb5_context,
     473             :                                                krb5_auth_context,
     474             :                                                int,
     475             :                                                rk_socket_t,
     476             :                                                int *,
     477             :                                                krb5_data *,
     478             :                                                krb5_data *,
     479             :                                                const char *);
     480             : 
     481             : static const struct kpwd_proc {
     482             :     const char *name;
     483             :     int flags;
     484             : #define SUPPORT_TCP     1
     485             : #define SUPPORT_UDP     2
     486             :     kpwd_send_request send_req;
     487             :     kpwd_process_reply process_rep;
     488             : } procs[] = {
     489             :     {
     490             :         "MS set password",
     491             :         SUPPORT_TCP|SUPPORT_UDP,
     492             :         setpw_send_request,
     493             :         process_reply
     494             :     },
     495             :     {
     496             :         "change password",
     497             :         SUPPORT_UDP,
     498             :         chgpw_send_request,
     499             :         process_reply
     500             :     },
     501             :     { NULL, 0, NULL, NULL }
     502             : };
     503             : 
     504             : /*
     505             :  *
     506             :  */
     507             : 
     508             : static krb5_error_code
     509          29 : change_password_loop (krb5_context      context,
     510             :                       krb5_creds        *creds,
     511             :                       krb5_principal    targprinc,
     512             :                       const char        *newpw,
     513             :                       int               *result_code,
     514             :                       krb5_data         *result_code_string,
     515             :                       krb5_data         *result_string,
     516             :                       const struct kpwd_proc    *proc)
     517             : {
     518           0 :     krb5_error_code ret;
     519          29 :     krb5_auth_context auth_context = NULL;
     520          29 :     krb5_krbhst_handle handle = NULL;
     521           0 :     krb5_krbhst_info *hi;
     522           0 :     rk_socket_t sock;
     523           0 :     unsigned int i;
     524          29 :     int done = 0;
     525           0 :     krb5_realm realm;
     526             : 
     527          29 :     if (targprinc)
     528          29 :         realm = targprinc->realm;
     529             :     else
     530           0 :         realm = creds->client->realm;
     531             : 
     532          29 :     ret = krb5_auth_con_init (context, &auth_context);
     533          29 :     if (ret)
     534           0 :         return ret;
     535             : 
     536          29 :     krb5_auth_con_setflags (context, auth_context,
     537             :                             KRB5_AUTH_CONTEXT_DO_SEQUENCE);
     538             : 
     539          29 :     ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle);
     540          29 :     if (ret)
     541           0 :         goto out;
     542             : 
     543          58 :     while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) {
     544           0 :         struct addrinfo *ai, *a;
     545           0 :         int is_stream;
     546             : 
     547          29 :         switch (hi->proto) {
     548          29 :         case KRB5_KRBHST_UDP:
     549          29 :             if ((proc->flags & SUPPORT_UDP) == 0)
     550           0 :                 continue;
     551          29 :             is_stream = 0;
     552          29 :             break;
     553           0 :         case KRB5_KRBHST_TCP:
     554           0 :             if ((proc->flags & SUPPORT_TCP) == 0)
     555           0 :                 continue;
     556           0 :             is_stream = 1;
     557           0 :             break;
     558           0 :         default:
     559           0 :             continue;
     560             :         }
     561             : 
     562          29 :         ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
     563          29 :         if (ret)
     564           0 :             continue;
     565             : 
     566          58 :         for (a = ai; !done && a != NULL; a = a->ai_next) {
     567          29 :             int replied = 0;
     568             : 
     569          29 :             sock = socket (a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol);
     570          29 :             if (rk_IS_BAD_SOCKET(sock))
     571           0 :                 continue;
     572          29 :             rk_cloexec(sock);
     573             : 
     574          29 :             ret = connect(sock, a->ai_addr, a->ai_addrlen);
     575          29 :             if (rk_IS_SOCKET_ERROR(ret)) {
     576           0 :                 rk_closesocket (sock);
     577           0 :                 goto out;
     578             :             }
     579             : 
     580          29 :             ret = krb5_auth_con_genaddrs (context, auth_context, sock,
     581             :                                           KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
     582          29 :             if (ret) {
     583           0 :                 rk_closesocket (sock);
     584           0 :                 goto out;
     585             :             }
     586             : 
     587          58 :             for (i = 0; !done && i < 5; ++i) {
     588           0 :                 fd_set fdset;
     589           0 :                 struct timeval tv;
     590             : 
     591          29 :                 if (!replied) {
     592          29 :                     replied = 0;
     593             : 
     594          29 :                     ret = (*proc->send_req) (context,
     595             :                                              &auth_context,
     596             :                                              creds,
     597             :                                              targprinc,
     598             :                                              is_stream,
     599             :                                              sock,
     600             :                                              newpw,
     601          29 :                                              hi->hostname);
     602          29 :                     if (ret) {
     603           0 :                         rk_closesocket(sock);
     604           0 :                         goto out;
     605             :                     }
     606             :                 }
     607             : 
     608             : #ifndef NO_LIMIT_FD_SETSIZE
     609          29 :                 if (sock >= FD_SETSIZE) {
     610           0 :                     ret = ERANGE;
     611           0 :                     krb5_set_error_message(context, ret,
     612             :                                            "fd %d too large", sock);
     613           0 :                     rk_closesocket (sock);
     614           0 :                     goto out;
     615             :                 }
     616             : #endif
     617             : 
     618         493 :                 FD_ZERO(&fdset);
     619          29 :                 FD_SET(sock, &fdset);
     620          29 :                 tv.tv_usec = 0;
     621          29 :                 tv.tv_sec  = 1 + (1 << i);
     622             : 
     623          29 :                 ret = select (sock + 1, &fdset, NULL, NULL, &tv);
     624          29 :                 if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR) {
     625           0 :                     rk_closesocket(sock);
     626           0 :                     goto out;
     627             :                 }
     628          29 :                 if (ret == 1) {
     629          29 :                     ret = (*proc->process_rep) (context,
     630             :                                                 auth_context,
     631             :                                                 is_stream,
     632             :                                                 sock,
     633             :                                                 result_code,
     634             :                                                 result_code_string,
     635             :                                                 result_string,
     636          29 :                                                 hi->hostname);
     637          29 :                     if (ret == 0)
     638          29 :                         done = 1;
     639           0 :                     else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL)
     640           0 :                         replied = 1;
     641             :                 } else {
     642           0 :                     ret = KRB5_KDC_UNREACH;
     643             :                 }
     644             :             }
     645          29 :             rk_closesocket (sock);
     646             :         }
     647             :     }
     648             : 
     649          29 :  out:
     650          29 :     krb5_krbhst_free (context, handle);
     651          29 :     krb5_auth_con_free (context, auth_context);
     652             : 
     653          29 :     if (ret == KRB5_KDC_UNREACH) {
     654           0 :         krb5_set_error_message(context,
     655             :                                ret,
     656           0 :                                N_("Unable to reach any changepw server "
     657             :                                  " in realm %s", "realm"), realm);
     658           0 :         *result_code = KRB5_KPASSWD_HARDERROR;
     659             :     }
     660          29 :     return ret;
     661             : }
     662             : 
     663             : #ifndef HEIMDAL_SMALLER
     664             : 
     665             : static const struct kpwd_proc *
     666           0 : find_chpw_proto(const char *name)
     667             : {
     668           0 :     const struct kpwd_proc *p;
     669           0 :     for (p = procs; p->name != NULL; p++) {
     670           0 :         if (strcmp(p->name, name) == 0)
     671           0 :             return p;
     672             :     }
     673           0 :     return NULL;
     674             : }
     675             : 
     676             : /**
     677             :  * Deprecated: krb5_change_password() is deprecated, use krb5_set_password().
     678             :  *
     679             :  * @param context a Keberos context
     680             :  * @param creds
     681             :  * @param newpw
     682             :  * @param result_code
     683             :  * @param result_code_string
     684             :  * @param result_string
     685             :  *
     686             :  * @return On sucess password is changed.
     687             : 
     688             :  * @ingroup @krb5_deprecated
     689             :  */
     690             : 
     691             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     692           0 : krb5_change_password (krb5_context      context,
     693             :                       krb5_creds        *creds,
     694             :                       const char        *newpw,
     695             :                       int               *result_code,
     696             :                       krb5_data         *result_code_string,
     697             :                       krb5_data         *result_string)
     698             :     KRB5_DEPRECATED_FUNCTION("Use krb5_set_password instead")
     699             : {
     700           0 :     const struct kpwd_proc *p = find_chpw_proto("change password");
     701             : 
     702           0 :     *result_code = KRB5_KPASSWD_MALFORMED;
     703           0 :     result_code_string->data = result_string->data = NULL;
     704           0 :     result_code_string->length = result_string->length = 0;
     705             : 
     706           0 :     if (p == NULL)
     707           0 :         return KRB5_KPASSWD_MALFORMED;
     708             : 
     709           0 :     return change_password_loop(context, creds, NULL, newpw,
     710             :                                 result_code, result_code_string,
     711             :                                 result_string, p);
     712             : }
     713             : #endif /* HEIMDAL_SMALLER */
     714             : 
     715             : /**
     716             :  * Change password using creds.
     717             :  *
     718             :  * @param context a Keberos context
     719             :  * @param creds The initial kadmin/passwd for the principal or an admin principal
     720             :  * @param newpw The new password to set
     721             :  * @param targprinc if unset, the client principal from creds is used
     722             :  * @param result_code Result code, KRB5_KPASSWD_SUCCESS is when password is changed.
     723             :  * @param result_code_string binary message from the server, contains
     724             :  * at least the result_code.
     725             :  * @param result_string A message from the kpasswd service or the
     726             :  * library in human printable form. The string is NUL terminated.
     727             :  *
     728             :  * @return On sucess and *result_code is KRB5_KPASSWD_SUCCESS, the password is changed.
     729             : 
     730             :  * @ingroup @krb5
     731             :  */
     732             : 
     733             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     734          16 : krb5_set_password(krb5_context context,
     735             :                   krb5_creds *creds,
     736             :                   const char *newpw,
     737             :                   krb5_principal targprinc,
     738             :                   int *result_code,
     739             :                   krb5_data *result_code_string,
     740             :                   krb5_data *result_string)
     741             : {
     742          16 :     krb5_principal principal = NULL;
     743          16 :     krb5_error_code ret = 0;
     744           0 :     int i;
     745             : 
     746          16 :     *result_code = KRB5_KPASSWD_MALFORMED;
     747          16 :     krb5_data_zero(result_code_string);
     748          16 :     krb5_data_zero(result_string);
     749             : 
     750          16 :     if (targprinc == NULL) {
     751           3 :         ret = krb5_copy_principal(context, creds->client, &principal);
     752           3 :         if (ret)
     753           0 :             return ret;
     754             :     } else
     755          13 :         principal = targprinc;
     756             : 
     757          31 :     for (i = 0; procs[i].name != NULL; i++) {
     758          29 :         *result_code = 0;
     759          29 :         ret = change_password_loop(context, creds, principal, newpw,
     760             :                                    result_code, result_code_string,
     761             :                                    result_string,
     762             :                                    &procs[i]);
     763          29 :         if (ret == 0 && *result_code == 0)
     764          14 :             break;
     765             :     }
     766             : 
     767          16 :     if (targprinc == NULL)
     768           3 :         krb5_free_principal(context, principal);
     769          16 :     return ret;
     770             : }
     771             : 
     772             : /*
     773             :  *
     774             :  */
     775             : 
     776             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     777           9 : krb5_set_password_using_ccache(krb5_context context,
     778             :                                krb5_ccache ccache,
     779             :                                const char *newpw,
     780             :                                krb5_principal targprinc,
     781             :                                int *result_code,
     782             :                                krb5_data *result_code_string,
     783             :                                krb5_data *result_string)
     784             : {
     785           0 :     krb5_creds creds, *credsp;
     786           0 :     krb5_error_code ret;
     787           9 :     krb5_principal principal = NULL;
     788             : 
     789           9 :     *result_code = KRB5_KPASSWD_MALFORMED;
     790           9 :     result_code_string->data = result_string->data = NULL;
     791           9 :     result_code_string->length = result_string->length = 0;
     792             : 
     793           9 :     memset(&creds, 0, sizeof(creds));
     794             : 
     795           9 :     if (targprinc == NULL) {
     796           0 :         ret = krb5_cc_get_principal(context, ccache, &principal);
     797           0 :         if (ret)
     798           0 :             return ret;
     799             :     } else
     800           9 :         principal = targprinc;
     801             : 
     802           9 :     ret = krb5_make_principal(context, &creds.server,
     803             :                               krb5_principal_get_realm(context, principal),
     804             :                               "kadmin", "changepw", NULL);
     805           9 :     if (ret)
     806           0 :         goto out;
     807             : 
     808           9 :     ret = krb5_cc_get_principal(context, ccache, &creds.client);
     809           9 :     if (ret) {
     810           0 :         krb5_free_principal(context, creds.server);
     811           0 :         goto out;
     812             :     }
     813             : 
     814           9 :     ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
     815           9 :     krb5_free_principal(context, creds.server);
     816           9 :     krb5_free_principal(context, creds.client);
     817           9 :     if (ret)
     818           0 :         goto out;
     819             : 
     820           9 :     ret = krb5_set_password(context,
     821             :                             credsp,
     822             :                             newpw,
     823             :                             principal,
     824             :                             result_code,
     825             :                             result_code_string,
     826             :                             result_string);
     827             : 
     828           9 :     krb5_free_creds(context, credsp);
     829             : 
     830           9 :     return ret;
     831           0 :  out:
     832           0 :     if (targprinc == NULL)
     833           0 :         krb5_free_principal(context, principal);
     834           0 :     return ret;
     835             : }
     836             : 
     837             : /*
     838             :  *
     839             :  */
     840             : 
     841             : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
     842           6 : krb5_passwd_result_to_string (krb5_context context,
     843             :                               int result)
     844             : {
     845           0 :     static const char *strings[] = {
     846             :         "Success",
     847             :         "Malformed",
     848             :         "Hard error",
     849             :         "Auth error",
     850             :         "Soft error" ,
     851             :         "Access denied",
     852             :         "Bad version",
     853             :         "Initial flag needed"
     854             :     };
     855             : 
     856           6 :     if (result < 0 || result > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)
     857           0 :         return "unknown result code";
     858             :     else
     859           6 :         return strings[result];
     860             : }

Generated by: LCOV version 1.14