e71a749704c9f2f3ca72906acfbee485f2b744b5
[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 #define WORKING_RCACHE
37
38 extern krb5_flags       krb5_kdc_default_options;
39
40 static char *sendauth_version = "KRB5_SENDAUTH_V1.0";
41
42 krb5_error_code INTERFACE
43 krb5_sendauth(context, auth_context,
44               /* IN */
45               fd, appl_version, client, server, ap_req_options, in_data,
46               in_creds,
47               /* IN/OUT */
48               ccache,
49               /* OUT */
50               error, rep_result, out_creds)
51         krb5_context              context;
52         krb5_auth_context      ** auth_context;
53         krb5_pointer              fd;
54         char                    * appl_version;
55         krb5_principal            client;
56         krb5_principal            server;
57         krb5_flags                ap_req_options;
58         krb5_data               * in_data;
59         krb5_creds              * in_creds;
60         krb5_ccache               ccache;
61         krb5_error             ** error;
62         krb5_ap_rep_enc_part   ** rep_result;
63         krb5_creds             ** out_creds;
64 {
65         krb5_flags              kdc_options = krb5_kdc_default_options;
66         krb5_octet              result;
67         krb5_creds              creds;
68         krb5_creds *            credsp = NULL;
69         krb5_creds *            credspout = NULL;
70         krb5_error_code         retval = 0;
71         krb5_data               inbuf, outbuf;
72         int                     len;
73         krb5_ccache             use_ccache = 0;
74
75         /*
76          * First, send over the length of the sendauth version string;
77          * then, we send over the sendauth version.  Next, we send
78          * over the length of the application version strings followed
79          * by the string itself.  
80          */
81         outbuf.length = strlen(sendauth_version) + 1;
82         outbuf.data = sendauth_version;
83         if (retval = krb5_write_message(context, fd, &outbuf))
84                 return(retval);
85         outbuf.length = strlen(appl_version) + 1;
86         outbuf.data = appl_version;
87         if (retval = krb5_write_message(context, fd, &outbuf))
88                 return(retval);
89         /*
90          * Now, read back a byte: 0 means no error, 1 means bad sendauth
91          * version, 2 means bad application version
92          */
93     if ((len = krb5_net_read(context, *((int *) fd), (char *)&result, 1)) != 1)
94         return((len < 0) ? errno : ECONNABORTED);
95     if (result == 1)
96         return(KRB5_SENDAUTH_BADAUTHVERS);
97     else if (result == 2)
98         return(KRB5_SENDAUTH_BADAPPLVERS);
99     else if (result != 0)
100         return(KRB5_SENDAUTH_BADRESPONSE);
101         /*
102          * We're finished with the initial negotiations; let's get and
103          * send over the authentication header.  (The AP_REQ message)
104          */
105
106         /*
107          * If no credentials were provided, try getting it from the
108          * credentials cache.
109          */
110         memset((char *)&creds, 0, sizeof(creds));
111
112         /*
113          * See if we need to access the credentials cache
114          */
115         if (!in_creds || !in_creds->ticket.length) {
116                 if (ccache)
117                         use_ccache = ccache;
118                 else if (retval = krb5_cc_default(context, &use_ccache))
119                         goto error_return;
120         }
121         if (!in_creds) {
122                 if (retval = krb5_copy_principal(context, server, &creds.server))
123                         goto error_return;
124                 if (client)
125                         retval = krb5_copy_principal(context, client, 
126                                                      &creds.client);
127                 else
128                         retval = krb5_cc_get_principal(context, use_ccache,
129                                                        &creds.client);
130                 if (retval) {
131                         krb5_free_principal(context, creds.server);
132                         goto error_return;
133                 }
134                 /* creds.times.endtime = 0; -- memset 0 takes care of this
135                                         zero means "as long as possible" */
136                 /* creds.keyblock.keytype = 0; -- as well as this.
137                                         zero means no session keytype
138                                         preference */
139                 in_creds = &creds;
140         }
141         if (!in_creds->ticket.length) {
142             if (retval = krb5_get_credentials(context, kdc_options, use_ccache,
143                                               in_creds, &credsp))
144                     goto error_return;
145             credspout = credsp;
146         } else {
147             credsp = in_creds;
148         }
149
150     if (retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
151                                       in_data, credsp, &outbuf))
152         goto error_return;
153
154         /*
155          * First write the length of the AP_REQ message, then write
156          * the message itself.
157          */
158         retval = krb5_write_message(context, fd, &outbuf);
159         free(outbuf.data);
160         if (retval)
161             goto error_return;
162
163         /*
164          * Now, read back a message.  If it was a null message (the
165          * length was zero) then there was no error.  If not, we the
166          * authentication was rejected, and we need to return the
167          * error structure.
168          */
169         if (retval = krb5_read_message(context, fd, &inbuf))
170             goto error_return;
171
172         if (inbuf.length) {
173                 if (error) {
174                     if (retval = krb5_rd_error(context, &inbuf, error)) {
175                         krb5_xfree(inbuf.data);
176                         goto error_return;
177                     }
178                 }
179                 retval = KRB5_SENDAUTH_REJECTED;
180                 krb5_xfree(inbuf.data);
181                 goto error_return;
182         }
183         
184         /*
185          * If we asked for mutual authentication, we should now get a
186          * length field, followed by a AP_REP message
187          */
188         if ((ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) {
189             krb5_ap_rep_enc_part        *repl = 0;
190                 
191             if (retval = krb5_read_message(context, fd, &inbuf))
192                 goto error_return;
193
194             if (retval = krb5_rd_rep(context, *auth_context, &inbuf, &repl)) {
195                 if (repl)
196                     krb5_free_ap_rep_enc_part(context, repl);
197                 krb5_xfree(inbuf.data);
198                 goto error_return;
199             }
200
201             krb5_xfree(inbuf.data);
202             /*
203              * If the user wants to look at the AP_REP message,
204              * copy it for him
205              */
206             if (rep_result) 
207                 *rep_result = repl;
208             else
209                 krb5_free_ap_rep_enc_part(context, repl);
210         }
211         retval = 0;             /* Normal return */
212         if (out_creds) {
213                 *out_creds = credsp;
214         }
215
216 error_return:
217     if (credspout)
218         krb5_free_creds(context, credspout); 
219     if (!ccache && use_ccache)
220         krb5_cc_close(context, use_ccache);
221     return(retval);
222 }
223
224