1 /* $NetBSD: sendauth.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "krb5_locl.h"
37
38 /*
39 * The format seems to be:
40 * client -> server
41 *
42 * 4 bytes - length
43 * KRB5_SENDAUTH_V1.0 (including zero)
44 * 4 bytes - length
45 * protocol string (with terminating zero)
46 *
47 * server -> client
48 * 1 byte - (0 = OK, else some kind of error)
49 *
50 * client -> server
51 * 4 bytes - length
52 * AP-REQ
53 *
54 * server -> client
55 * 4 bytes - length (0 = OK, else length of error)
56 * (error)
57 *
58 * if(mutual) {
59 * server -> client
60 * 4 bytes - length
61 * AP-REP
62 * }
63 */
64
65 /**
66 * Perform the client side of the sendauth protocol.
67 *
68 * @param context Kerberos 5 context.
69 * @param auth_context Authentication context of the peer.
70 * @param p_fd Socket associated to the connection.
71 * @param appl_version Server-specific string.
72 * @param client Client principal. If NULL, use the credentials in \a ccache.
73 * @param server Server principal.
74 * @param ap_req_options Options for the AP_REQ message. See the AP_OPTS_* defines in krb5.h.
75 * @param in_data FIXME
76 * @param in_creds FIXME
77 * @param ccache Credentials cache. If NULL, use the default credentials cache.
78 * @param ret_error If not NULL, will be set to the error reported by server, if any.
79 * Must be deallocated with krb5_free_error_contents().
80 * @param rep_result If not NULL, will be set to the EncApRepPart of the AP_REP message.
81 * Must be deallocated with krb5_free_ap_rep_enc_part().
82 * @param out_creds FIXME If not NULL, will be set to FIXME. Must be deallocated with
83 * krb5_free_creds().
84 *
85 * @return 0 to indicate success. Otherwise a Kerberos error code is
86 * returned, see krb5_get_error_message().
87 */
88 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_sendauth(krb5_context context,krb5_auth_context * auth_context,krb5_pointer p_fd,const char * appl_version,krb5_principal client,krb5_principal server,krb5_flags ap_req_options,krb5_data * in_data,krb5_creds * in_creds,krb5_ccache ccache,krb5_error ** ret_error,krb5_ap_rep_enc_part ** rep_result,krb5_creds ** out_creds)89 krb5_sendauth(krb5_context context,
90 krb5_auth_context *auth_context,
91 krb5_pointer p_fd,
92 const char *appl_version,
93 krb5_principal client,
94 krb5_principal server,
95 krb5_flags ap_req_options,
96 krb5_data *in_data,
97 krb5_creds *in_creds,
98 krb5_ccache ccache,
99 krb5_error **ret_error,
100 krb5_ap_rep_enc_part **rep_result,
101 krb5_creds **out_creds)
102 {
103 krb5_error_code ret;
104 uint32_t len, net_len;
105 const char *version = KRB5_SENDAUTH_VERSION;
106 u_char repl;
107 krb5_data ap_req, error_data;
108 krb5_creds this_cred;
109 krb5_principal this_client = NULL;
110 krb5_creds *creds;
111 ssize_t sret;
112 krb5_boolean my_ccache = FALSE;
113
114 len = strlen(version) + 1;
115 net_len = htonl(len);
116 if (krb5_net_write (context, p_fd, &net_len, 4) != 4
117 || krb5_net_write (context, p_fd, version, len) != len) {
118 ret = errno;
119 krb5_set_error_message (context, ret, "write: %s", strerror(ret));
120 return ret;
121 }
122
123 len = strlen(appl_version) + 1;
124 net_len = htonl(len);
125 if (krb5_net_write (context, p_fd, &net_len, 4) != 4
126 || krb5_net_write (context, p_fd, appl_version, len) != len) {
127 ret = errno;
128 krb5_set_error_message (context, ret, "write: %s", strerror(ret));
129 return ret;
130 }
131
132 sret = krb5_net_read (context, p_fd, &repl, sizeof(repl));
133 if (sret < 0) {
134 ret = errno;
135 krb5_set_error_message (context, ret, "read: %s", strerror(ret));
136 return ret;
137 } else if (sret != sizeof(repl)) {
138 krb5_clear_error_message (context);
139 return KRB5_SENDAUTH_BADRESPONSE;
140 }
141
142 if (repl != 0) {
143 krb5_clear_error_message (context);
144 return KRB5_SENDAUTH_REJECTED;
145 }
146
147 if (in_creds == NULL) {
148 if (ccache == NULL) {
149 ret = krb5_cc_default (context, &ccache);
150 if (ret)
151 return ret;
152 my_ccache = TRUE;
153 }
154
155 if (client == NULL) {
156 ret = krb5_cc_get_principal (context, ccache, &this_client);
157 if (ret) {
158 if(my_ccache)
159 krb5_cc_close(context, ccache);
160 return ret;
161 }
162 client = this_client;
163 }
164 memset(&this_cred, 0, sizeof(this_cred));
165 this_cred.client = client;
166 this_cred.server = server;
167 this_cred.times.endtime = 0;
168 this_cred.ticket.length = 0;
169 in_creds = &this_cred;
170 }
171 if (in_creds->ticket.length == 0) {
172 ret = krb5_get_credentials (context, 0, ccache, in_creds, &creds);
173 if (ret) {
174 if(my_ccache)
175 krb5_cc_close(context, ccache);
176 return ret;
177 }
178 } else {
179 creds = in_creds;
180 }
181 if(my_ccache)
182 krb5_cc_close(context, ccache);
183 ret = krb5_mk_req_extended (context,
184 auth_context,
185 ap_req_options,
186 in_data,
187 creds,
188 &ap_req);
189
190 if (out_creds)
191 *out_creds = creds;
192 else
193 krb5_free_creds(context, creds);
194 if(this_client)
195 krb5_free_principal(context, this_client);
196
197 if (ret)
198 return ret;
199
200 ret = krb5_write_message (context,
201 p_fd,
202 &ap_req);
203 if (ret)
204 return ret;
205
206 krb5_data_free (&ap_req);
207
208 ret = krb5_read_message (context, p_fd, &error_data);
209 if (ret)
210 return ret;
211
212 if (error_data.length != 0) {
213 KRB_ERROR error;
214
215 ret = krb5_rd_error (context, &error_data, &error);
216 krb5_data_free (&error_data);
217 if (ret == 0) {
218 ret = krb5_error_from_rd_error(context, &error, NULL);
219 if (ret_error != NULL) {
220 *ret_error = malloc (sizeof(krb5_error));
221 if (*ret_error == NULL) {
222 krb5_free_error_contents (context, &error);
223 } else {
224 **ret_error = error;
225 }
226 } else {
227 krb5_free_error_contents (context, &error);
228 }
229 return ret;
230 } else {
231 krb5_clear_error_message(context);
232 return ret;
233 }
234 } else
235 krb5_data_free (&error_data);
236
237 if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) {
238 krb5_data ap_rep;
239 krb5_ap_rep_enc_part *ignore = NULL;
240
241 krb5_data_zero (&ap_rep);
242 ret = krb5_read_message (context,
243 p_fd,
244 &ap_rep);
245 if (ret)
246 return ret;
247
248 ret = krb5_rd_rep (context, *auth_context, &ap_rep,
249 rep_result ? rep_result : &ignore);
250 krb5_data_free (&ap_rep);
251 if (ret)
252 return ret;
253 if (rep_result == NULL)
254 krb5_free_ap_rep_enc_part (context, ignore);
255 }
256 return 0;
257 }
258