Windows global stuff:
[krb5.git] / src / lib / krb5 / krb / mk_safe.c
1 /*
2  * lib/krb5/krb/mk_safe.c
3  *
4  * Copyright 1990,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  * krb5_mk_safe()
25  */
26
27 #include "k5-int.h"
28 #include "auth_con.h"
29
30 /*
31  Formats a KRB_SAFE message into outbuf.
32
33  userdata is formatted as the user data in the message.
34  sumtype specifies the encryption type; key specifies the key which
35  might be used to seed the checksum; sender_addr and recv_addr specify
36  the full addresses (host and port) of the sender and receiver.
37  The host portion of sender_addr is used to form the addresses used in the
38  KRB_SAFE message.
39
40  The outbuf buffer storage is allocated, and should be freed by the
41  caller when finished.
42
43  returns system errors
44 */
45 static krb5_error_code
46 krb5_mk_safe_basic(context, userdata, keyblock, replaydata, local_addr,
47                    remote_addr, sumtype, outbuf)
48     krb5_context          context;
49     const krb5_data     * userdata;
50     const krb5_keyblock * keyblock;
51     krb5_replay_data    * replaydata;
52     const krb5_address  * local_addr;
53     const krb5_address  * remote_addr;
54     const krb5_cksumtype  sumtype;
55     krb5_data           * outbuf;
56 {
57     krb5_error_code retval;
58     krb5_safe safemsg;
59     krb5_octet zero_octet = 0;
60     krb5_checksum safe_checksum;
61     krb5_data *scratch1, *scratch2;
62
63     if (!valid_cksumtype(sumtype))
64         return KRB5_PROG_SUMTYPE_NOSUPP;
65     if (!is_coll_proof_cksum(sumtype) || !is_keyed_cksum(sumtype))
66         return KRB5KRB_AP_ERR_INAPP_CKSUM;
67
68     safemsg.user_data = *userdata;
69     safemsg.s_address = (krb5_address *) local_addr;
70     safemsg.r_address = (krb5_address *) remote_addr;
71
72     /* We should check too make sure one exists. */
73     safemsg.timestamp  = replaydata->timestamp;
74     safemsg.usec       = replaydata->usec;
75     safemsg.seq_number = replaydata->seq;
76
77     /* 
78      * To do the checksum stuff, we need to encode the message with a
79      * zero-length zero-type checksum, then checksum the encoding, then
80      * re-encode with the checksum. 
81      */
82
83     safe_checksum.length = 0;
84     safe_checksum.checksum_type = 0;
85     safe_checksum.contents = &zero_octet;
86
87     safemsg.checksum = &safe_checksum;
88
89     if (retval = encode_krb5_safe(&safemsg, &scratch1))
90         return retval;
91
92     if (!(safe_checksum.contents =
93           (krb5_octet *) malloc(krb5_checksum_size(context, sumtype)))) {
94         retval = ENOMEM;
95         goto cleanup_scratch;
96     }
97     if (retval = krb5_calculate_checksum(context, sumtype, scratch1->data,
98                                          scratch1->length,
99                                          (krb5_pointer) keyblock->contents,
100                                          keyblock->length, &safe_checksum)) {
101         goto cleanup_checksum;
102     }
103     safemsg.checksum = &safe_checksum;
104     if (retval = encode_krb5_safe(&safemsg, &scratch2)) {
105         goto cleanup_checksum;
106     }
107     *outbuf = *scratch2;
108     krb5_xfree(scratch2);
109     retval = 0;
110
111 cleanup_checksum:
112     krb5_xfree(safe_checksum.contents);
113
114 cleanup_scratch:
115     memset((char *)scratch1->data, 0, scratch1->length); 
116     krb5_free_data(context, scratch1);
117     return retval;
118 }
119
120 krb5_error_code
121 krb5_mk_safe(context, auth_context, userdata, outbuf, outdata)
122     krb5_context        context;
123     krb5_auth_context * auth_context;
124     const krb5_data   * userdata;
125     krb5_data         * outbuf;
126     krb5_replay_data  * outdata;
127 {
128     krb5_replay_data    replaydata;
129     krb5_error_code     retval;
130
131     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
132       (auth_context->rcache == NULL))
133         return KRB5_RC_REQUIRED;
134
135     if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
136       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
137       (outdata == NULL))
138         /* Need a better error */
139         return KRB5_RC_REQUIRED;
140
141     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) ||
142         (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) {
143         if (retval = krb5_us_timeofday(context, &replaydata.timestamp,
144                                        &replaydata.usec))
145             return retval;
146         if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) {
147             outdata->timestamp = replaydata.timestamp;
148             outdata->usec = replaydata.usec;
149         }
150     }
151     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
152         (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
153         replaydata.seq = auth_context->local_seq_number++;
154         if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) {
155             outdata->seq = replaydata.seq;
156         }
157     } 
158
159     if (retval = krb5_mk_safe_basic(context, userdata, auth_context->keyblock,
160       &replaydata, auth_context->local_addr, auth_context->remote_addr,
161       auth_context->cksumtype, outbuf)) 
162         goto error;
163
164     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
165         krb5_donot_replay replay;
166
167         if (retval = krb5_gen_replay_name(context, auth_context->local_addr, 
168                                           "_safe", &replay.client)) {
169             krb5_xfree(outbuf);
170             goto error;
171         }
172
173         replay.server = "";             /* XXX */
174         replay.cusec = replaydata.usec;
175         replay.ctime = replaydata.timestamp;
176         if (retval = krb5_rc_store(context, auth_context->rcache, &replay)) {
177             /* should we really error out here? XXX */
178             krb5_xfree(outbuf);
179             goto error;
180         }
181         krb5_xfree(replay.client);
182     }
183
184     return 0;
185
186 error:
187     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
188       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) 
189         auth_context->local_seq_number--;
190
191     return retval;
192 }
193