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