copy_addrs.c fwd_tgt.c mk_cred.c sendauth.c: Added FAR declarations
[krb5.git] / src / lib / krb5 / krb / sendauth.c
1 /*
2  * lib/krb5/krb/sendauth.c
3  *
4  * Copyright 1991 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  *
24  * convenience sendauth/recvauth functions
25  */
26
27 #define NEED_SOCKETS
28
29 #include "k5-int.h"
30 #include "com_err.h"
31 #include "auth_con.h"
32 #include <errno.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 static char *sendauth_version = "KRB5_SENDAUTH_V1.0";
37
38 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
39 krb5_sendauth(context, auth_context,
40               /* IN */
41               fd, appl_version, client, server, ap_req_options, in_data,
42               in_creds,
43               /* IN/OUT */
44               ccache,
45               /* OUT */
46               error, rep_result, out_creds)
47         krb5_context              context;
48         krb5_auth_context       FAR * auth_context;
49         krb5_pointer              fd;
50         char                    FAR * appl_version;
51         krb5_principal            client;
52         krb5_principal            server;
53         krb5_flags                ap_req_options;
54         krb5_data               FAR * in_data;
55         krb5_creds              FAR * in_creds;
56         krb5_ccache               ccache;
57         krb5_error             FAR * FAR * error;
58         krb5_ap_rep_enc_part   FAR * FAR * rep_result;
59         krb5_creds             FAR * FAR * out_creds;
60 {
61         krb5_octet              result;
62         krb5_creds              creds;
63         krb5_creds              FAR * credsp = NULL;
64         krb5_creds              FAR * credspout = NULL;
65         krb5_error_code         retval = 0;
66         krb5_data               inbuf, outbuf;
67         int                     len;
68         krb5_ccache             use_ccache = 0;
69
70         if (error)
71             *error = 0;
72
73         /*
74          * First, send over the length of the sendauth version string;
75          * then, we send over the sendauth version.  Next, we send
76          * over the length of the application version strings followed
77          * by the string itself.  
78          */
79         outbuf.length = strlen(sendauth_version) + 1;
80         outbuf.data = sendauth_version;
81         if ((retval = krb5_write_message(context, fd, &outbuf)))
82                 return(retval);
83         outbuf.length = strlen(appl_version) + 1;
84         outbuf.data = appl_version;
85         if ((retval = krb5_write_message(context, fd, &outbuf)))
86                 return(retval);
87         /*
88          * Now, read back a byte: 0 means no error, 1 means bad sendauth
89          * version, 2 means bad application version
90          */
91 #ifndef ECONNABORTED
92 #define ECONNABORTED WSAECONNABORTED
93 #endif
94     if ((len = krb5_net_read(context, *((int *) fd), (char *)&result, 1)) != 1)
95         return((len < 0) ? errno : ECONNABORTED);
96     if (result == 1)
97         return(KRB5_SENDAUTH_BADAUTHVERS);
98     else if (result == 2)
99         return(KRB5_SENDAUTH_BADAPPLVERS);
100     else if (result != 0)
101         return(KRB5_SENDAUTH_BADRESPONSE);
102         /*
103          * We're finished with the initial negotiations; let's get and
104          * send over the authentication header.  (The AP_REQ message)
105          */
106
107         /*
108          * If no credentials were provided, try getting it from the
109          * credentials cache.
110          */
111         memset((char *)&creds, 0, sizeof(creds));
112
113         /*
114          * See if we need to access the credentials cache
115          */
116         if (!in_creds || !in_creds->ticket.length) {
117                 if (ccache)
118                         use_ccache = ccache;
119                 else if ((retval = krb5_cc_default(context, &use_ccache)))
120                         goto error_return;
121         }
122         if (!in_creds) {
123                 if ((retval = krb5_copy_principal(context, server,
124                                                   &creds.server)))
125                         goto error_return;
126                 if (client)
127                         retval = krb5_copy_principal(context, client, 
128                                                      &creds.client);
129                 else
130                         retval = krb5_cc_get_principal(context, use_ccache,
131                                                        &creds.client);
132                 if (retval) {
133                         krb5_free_principal(context, creds.server);
134                         goto error_return;
135                 }
136                 /* creds.times.endtime = 0; -- memset 0 takes care of this
137                                         zero means "as long as possible" */
138                 /* creds.keyblock.enctype = 0; -- as well as this.
139                                         zero means no session enctype
140                                         preference */
141                 in_creds = &creds;
142         }
143         if (!in_creds->ticket.length) {
144             if ((retval = krb5_get_credentials(context, 0,
145                                                use_ccache, in_creds, &credsp)))
146                     goto error_return;
147             credspout = credsp;
148         } else {
149             credsp = in_creds;
150         }
151
152     if ((retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
153                                        in_data, credsp, &outbuf)))
154         goto error_return;
155
156         /*
157          * First write the length of the AP_REQ message, then write
158          * the message itself.
159          */
160         retval = krb5_write_message(context, fd, &outbuf);
161         free(outbuf.data);
162         if (retval)
163             goto error_return;
164
165         /*
166          * Now, read back a message.  If it was a null message (the
167          * length was zero) then there was no error.  If not, we the
168          * authentication was rejected, and we need to return the
169          * error structure.
170          */
171         if ((retval = krb5_read_message(context, fd, &inbuf)))
172             goto error_return;
173
174         if (inbuf.length) {
175                 if (error) {
176                     if ((retval = krb5_rd_error(context, &inbuf, error))) {
177                         krb5_xfree(inbuf.data);
178                         goto error_return;
179                     }
180                 }
181                 retval = KRB5_SENDAUTH_REJECTED;
182                 krb5_xfree(inbuf.data);
183                 goto error_return;
184         }
185         
186         /*
187          * If we asked for mutual authentication, we should now get a
188          * length field, followed by a AP_REP message
189          */
190         if ((ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) {
191             krb5_ap_rep_enc_part        *repl = 0;
192                 
193             if ((retval = krb5_read_message(context, fd, &inbuf)))
194                 goto error_return;
195
196             if ((retval = krb5_rd_rep(context, *auth_context, &inbuf,
197                                       &repl))) {
198                 if (repl)
199                     krb5_free_ap_rep_enc_part(context, repl);
200                 krb5_xfree(inbuf.data);
201                 goto error_return;
202             }
203
204             krb5_xfree(inbuf.data);
205             /*
206              * If the user wants to look at the AP_REP message,
207              * copy it for him
208              */
209             if (rep_result) 
210                 *rep_result = repl;
211             else
212                 krb5_free_ap_rep_enc_part(context, repl);
213         }
214         retval = 0;             /* Normal return */
215         if (out_creds) {
216                 *out_creds = credsp;
217         }
218
219 error_return:
220     krb5_free_cred_contents(context, &creds);
221     if (!out_creds && credspout)
222         krb5_free_creds(context, credspout); 
223     if (!ccache && use_ccache)
224         krb5_cc_close(context, use_ccache);
225     return(retval);
226 }
227
228