Home | History | Annotate | Line # | Download | only in krb5
      1  1.1     elric /*	$NetBSD: recvauth.c,v 1.2 2017/01/28 21:31:49 christos Exp $	*/
      2  1.1     elric 
      3  1.1     elric /*
      4  1.1     elric  * Copyright (c) 1997-2007 Kungliga Tekniska Hgskolan
      5  1.1     elric  * (Royal Institute of Technology, Stockholm, Sweden).
      6  1.1     elric  * All rights reserved.
      7  1.1     elric  *
      8  1.1     elric  * Redistribution and use in source and binary forms, with or without
      9  1.1     elric  * modification, are permitted provided that the following conditions
     10  1.1     elric  * are met:
     11  1.1     elric  *
     12  1.1     elric  * 1. Redistributions of source code must retain the above copyright
     13  1.1     elric  *    notice, this list of conditions and the following disclaimer.
     14  1.1     elric  *
     15  1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17  1.1     elric  *    documentation and/or other materials provided with the distribution.
     18  1.1     elric  *
     19  1.1     elric  * 3. Neither the name of the Institute nor the names of its contributors
     20  1.1     elric  *    may be used to endorse or promote products derived from this software
     21  1.1     elric  *    without specific prior written permission.
     22  1.1     elric  *
     23  1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  1.1     elric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  1.1     elric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  1.1     elric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  1.1     elric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  1.1     elric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  1.1     elric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  1.1     elric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  1.1     elric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  1.1     elric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  1.1     elric  * SUCH DAMAGE.
     34  1.1     elric  */
     35  1.1     elric 
     36  1.1     elric #include "krb5_locl.h"
     37  1.1     elric 
     38  1.1     elric /*
     39  1.1     elric  * See `sendauth.c' for the format.
     40  1.1     elric  */
     41  1.1     elric 
     42  1.1     elric static krb5_boolean
     43  1.1     elric match_exact(const void *data, const char *appl_version)
     44  1.1     elric {
     45  1.1     elric     return strcmp(data, appl_version) == 0;
     46  1.1     elric }
     47  1.1     elric 
     48  1.2  christos /**
     49  1.2  christos  * Perform the server side of the sendauth protocol.
     50  1.2  christos  *
     51  1.2  christos  * @param context       Kerberos 5 context.
     52  1.2  christos  * @param auth_context  authentication context of the peer.
     53  1.2  christos  * @param p_fd          socket associated to the connection.
     54  1.2  christos  * @param appl_version  server-specific string.
     55  1.2  christos  * @param server        server principal.
     56  1.2  christos  * @param flags         if KRB5_RECVAUTH_IGNORE_VERSION is set, skip the sendauth version
     57  1.2  christos  *                      part of the protocol.
     58  1.2  christos  * @param keytab        server keytab.
     59  1.2  christos  * @param ticket        on success, set to the authenticated client credentials.
     60  1.2  christos  *                      Must be deallocated with krb5_free_ticket(). If not
     61  1.2  christos  *                      interested, pass a NULL value.
     62  1.2  christos  *
     63  1.2  christos  * @return 0 to indicate success. Otherwise a Kerberos error code is
     64  1.2  christos  *         returned, see krb5_get_error_message().
     65  1.2  christos  */
     66  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     67  1.1     elric krb5_recvauth(krb5_context context,
     68  1.1     elric 	      krb5_auth_context *auth_context,
     69  1.1     elric 	      krb5_pointer p_fd,
     70  1.1     elric 	      const char *appl_version,
     71  1.1     elric 	      krb5_principal server,
     72  1.1     elric 	      int32_t flags,
     73  1.1     elric 	      krb5_keytab keytab,
     74  1.1     elric 	      krb5_ticket **ticket)
     75  1.1     elric {
     76  1.1     elric     return krb5_recvauth_match_version(context, auth_context, p_fd,
     77  1.1     elric 				       match_exact, appl_version,
     78  1.1     elric 				       server, flags,
     79  1.1     elric 				       keytab, ticket);
     80  1.1     elric }
     81  1.1     elric 
     82  1.2  christos /**
     83  1.2  christos  * Perform the server side of the sendauth protocol like krb5_recvauth(), but support
     84  1.2  christos  * a user-specified callback, \a match_appl_version, to perform the match of the application
     85  1.2  christos  * version \a match_data.
     86  1.2  christos  */
     87  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     88  1.1     elric krb5_recvauth_match_version(krb5_context context,
     89  1.1     elric 			    krb5_auth_context *auth_context,
     90  1.1     elric 			    krb5_pointer p_fd,
     91  1.1     elric 			    krb5_boolean (*match_appl_version)(const void *,
     92  1.1     elric 							       const char*),
     93  1.1     elric 			    const void *match_data,
     94  1.1     elric 			    krb5_principal server,
     95  1.1     elric 			    int32_t flags,
     96  1.1     elric 			    krb5_keytab keytab,
     97  1.1     elric 			    krb5_ticket **ticket)
     98  1.1     elric {
     99  1.1     elric     krb5_error_code ret;
    100  1.1     elric     const char *version = KRB5_SENDAUTH_VERSION;
    101  1.1     elric     char her_version[sizeof(KRB5_SENDAUTH_VERSION)];
    102  1.1     elric     char *her_appl_version;
    103  1.1     elric     uint32_t len;
    104  1.1     elric     u_char repl;
    105  1.1     elric     krb5_data data;
    106  1.1     elric     krb5_flags ap_options;
    107  1.1     elric     ssize_t n;
    108  1.1     elric 
    109  1.1     elric     /*
    110  1.1     elric      * If there are no addresses in auth_context, get them from `fd'.
    111  1.1     elric      */
    112  1.1     elric 
    113  1.1     elric     if (*auth_context == NULL) {
    114  1.1     elric 	ret = krb5_auth_con_init (context, auth_context);
    115  1.1     elric 	if (ret)
    116  1.1     elric 	    return ret;
    117  1.1     elric     }
    118  1.1     elric 
    119  1.1     elric     ret = krb5_auth_con_setaddrs_from_fd (context,
    120  1.1     elric 					  *auth_context,
    121  1.1     elric 					  p_fd);
    122  1.1     elric     if (ret)
    123  1.1     elric 	return ret;
    124  1.1     elric 
    125  1.2  christos     /*
    126  1.2  christos      * Expect SENDAUTH protocol version.
    127  1.2  christos      */
    128  1.1     elric     if(!(flags & KRB5_RECVAUTH_IGNORE_VERSION)) {
    129  1.1     elric 	n = krb5_net_read (context, p_fd, &len, 4);
    130  1.1     elric 	if (n < 0) {
    131  1.2  christos 	    ret = errno ? errno : EINVAL;
    132  1.1     elric 	    krb5_set_error_message(context, ret, "read: %s", strerror(ret));
    133  1.1     elric 	    return ret;
    134  1.1     elric 	}
    135  1.1     elric 	if (n == 0) {
    136  1.1     elric 	    krb5_set_error_message(context, KRB5_SENDAUTH_BADAUTHVERS,
    137  1.1     elric 				   N_("Failed to receive sendauth data", ""));
    138  1.1     elric 	    return KRB5_SENDAUTH_BADAUTHVERS;
    139  1.1     elric 	}
    140  1.1     elric 	len = ntohl(len);
    141  1.1     elric 	if (len != sizeof(her_version)
    142  1.1     elric 	    || krb5_net_read (context, p_fd, her_version, len) != len
    143  1.1     elric 	    || strncmp (version, her_version, len)) {
    144  1.1     elric 	    repl = 1;
    145  1.1     elric 	    krb5_net_write (context, p_fd, &repl, 1);
    146  1.1     elric 	    krb5_clear_error_message (context);
    147  1.1     elric 	    return KRB5_SENDAUTH_BADAUTHVERS;
    148  1.1     elric 	}
    149  1.1     elric     }
    150  1.1     elric 
    151  1.2  christos     /*
    152  1.2  christos      * Expect application protocol version.
    153  1.2  christos      */
    154  1.1     elric     n = krb5_net_read (context, p_fd, &len, 4);
    155  1.1     elric     if (n < 0) {
    156  1.2  christos 	ret = errno ? errno : EINVAL;
    157  1.1     elric 	krb5_set_error_message(context, ret, "read: %s", strerror(ret));
    158  1.1     elric 	return ret;
    159  1.1     elric     }
    160  1.1     elric     if (n == 0) {
    161  1.1     elric 	krb5_clear_error_message (context);
    162  1.1     elric 	return KRB5_SENDAUTH_BADAPPLVERS;
    163  1.1     elric     }
    164  1.1     elric     len = ntohl(len);
    165  1.1     elric     her_appl_version = malloc (len);
    166  1.1     elric     if (her_appl_version == NULL) {
    167  1.1     elric 	repl = 2;
    168  1.1     elric 	krb5_net_write (context, p_fd, &repl, 1);
    169  1.2  christos 	return krb5_enomem(context);
    170  1.1     elric     }
    171  1.1     elric     if (krb5_net_read (context, p_fd, her_appl_version, len) != len
    172  1.1     elric 	|| !(*match_appl_version)(match_data, her_appl_version)) {
    173  1.1     elric 	repl = 2;
    174  1.1     elric 	krb5_net_write (context, p_fd, &repl, 1);
    175  1.1     elric 	krb5_set_error_message(context, KRB5_SENDAUTH_BADAPPLVERS,
    176  1.2  christos 			       N_("wrong sendauth application version (%s)", ""),
    177  1.1     elric 			       her_appl_version);
    178  1.1     elric 	free (her_appl_version);
    179  1.1     elric 	return KRB5_SENDAUTH_BADAPPLVERS;
    180  1.1     elric     }
    181  1.1     elric     free (her_appl_version);
    182  1.1     elric 
    183  1.2  christos     /*
    184  1.2  christos      * Send OK.
    185  1.2  christos      */
    186  1.1     elric     repl = 0;
    187  1.1     elric     if (krb5_net_write (context, p_fd, &repl, 1) != 1) {
    188  1.2  christos 	ret = errno ? errno : EINVAL;
    189  1.1     elric 	krb5_set_error_message(context, ret, "write: %s", strerror(ret));
    190  1.1     elric 	return ret;
    191  1.1     elric     }
    192  1.1     elric 
    193  1.2  christos     /*
    194  1.2  christos      * Until here, the fields in the message were in cleartext and unauthenticated.
    195  1.2  christos      * From now on, Kerberos kicks in.
    196  1.2  christos      */
    197  1.2  christos 
    198  1.2  christos     /*
    199  1.2  christos      * Expect AP_REQ.
    200  1.2  christos      */
    201  1.1     elric     krb5_data_zero (&data);
    202  1.1     elric     ret = krb5_read_message (context, p_fd, &data);
    203  1.1     elric     if (ret)
    204  1.1     elric 	return ret;
    205  1.1     elric 
    206  1.1     elric     ret = krb5_rd_req (context,
    207  1.1     elric 		       auth_context,
    208  1.1     elric 		       &data,
    209  1.1     elric 		       server,
    210  1.1     elric 		       keytab,
    211  1.1     elric 		       &ap_options,
    212  1.1     elric 		       ticket);
    213  1.1     elric     krb5_data_free (&data);
    214  1.1     elric     if (ret) {
    215  1.1     elric 	krb5_data error_data;
    216  1.1     elric 	krb5_error_code ret2;
    217  1.1     elric 
    218  1.1     elric 	ret2 = krb5_mk_error (context,
    219  1.1     elric 			      ret,
    220  1.1     elric 			      NULL,
    221  1.1     elric 			      NULL,
    222  1.1     elric 			      NULL,
    223  1.1     elric 			      server,
    224  1.1     elric 			      NULL,
    225  1.1     elric 			      NULL,
    226  1.1     elric 			      &error_data);
    227  1.1     elric 	if (ret2 == 0) {
    228  1.1     elric 	    krb5_write_message (context, p_fd, &error_data);
    229  1.1     elric 	    krb5_data_free (&error_data);
    230  1.1     elric 	}
    231  1.1     elric 	return ret;
    232  1.1     elric     }
    233  1.1     elric 
    234  1.2  christos     /*
    235  1.2  christos      * Send OK.
    236  1.2  christos      */
    237  1.1     elric     len = 0;
    238  1.1     elric     if (krb5_net_write (context, p_fd, &len, 4) != 4) {
    239  1.2  christos 	ret = errno ? errno : EINVAL;
    240  1.1     elric 	krb5_set_error_message(context, ret, "write: %s", strerror(ret));
    241  1.1     elric 	krb5_free_ticket(context, *ticket);
    242  1.1     elric 	*ticket = NULL;
    243  1.1     elric 	return ret;
    244  1.1     elric     }
    245  1.1     elric 
    246  1.2  christos     /*
    247  1.2  christos      * If client requires mutual authentication, send AP_REP.
    248  1.2  christos      */
    249  1.1     elric     if (ap_options & AP_OPTS_MUTUAL_REQUIRED) {
    250  1.1     elric 	ret = krb5_mk_rep (context, *auth_context, &data);
    251  1.1     elric 	if (ret) {
    252  1.1     elric 	    krb5_free_ticket(context, *ticket);
    253  1.1     elric 	    *ticket = NULL;
    254  1.1     elric 	    return ret;
    255  1.1     elric 	}
    256  1.1     elric 
    257  1.1     elric 	ret = krb5_write_message (context, p_fd, &data);
    258  1.1     elric 	if (ret) {
    259  1.1     elric 	    krb5_free_ticket(context, *ticket);
    260  1.1     elric 	    *ticket = NULL;
    261  1.1     elric 	    return ret;
    262  1.1     elric 	}
    263  1.1     elric 	krb5_data_free (&data);
    264  1.1     elric     }
    265  1.1     elric     return 0;
    266  1.1     elric }
    267