Windows global stuff:
[krb5.git] / src / lib / krb5 / krb / mk_priv.c
1 /*
2  * lib/krb5/krb/mk_priv.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_priv()
25  */
26
27 #include "k5-int.h"
28 #include "auth_con.h"
29
30 static krb5_error_code
31 krb5_mk_priv_basic(context, userdata, keyblock, replaydata, local_addr, 
32                    remote_addr, i_vector, outbuf)
33     krb5_context          context;
34     const krb5_data     * userdata;
35     const krb5_keyblock * keyblock;
36     krb5_replay_data    * replaydata;
37     krb5_address        * local_addr;
38     krb5_address        * remote_addr;
39     krb5_pointer          i_vector;
40     krb5_data           * outbuf; 
41 {
42     krb5_error_code     retval;
43     krb5_encrypt_block  eblock;
44     krb5_priv           privmsg;
45     krb5_priv_enc_part  privmsg_enc_part;
46     krb5_data           *scratch1, *scratch2;
47
48     if (!valid_etype(keyblock->etype))
49         return KRB5_PROG_ETYPE_NOSUPP;
50
51     privmsg.enc_part.kvno = 0;  /* XXX allow user-set? */
52     privmsg.enc_part.etype = keyblock->etype; 
53
54     privmsg_enc_part.user_data = *userdata;
55     privmsg_enc_part.s_address = local_addr;
56     privmsg_enc_part.r_address = remote_addr;
57
58     /* We should check too make sure one exists. */
59     privmsg_enc_part.timestamp  = replaydata->timestamp;
60     privmsg_enc_part.usec       = replaydata->usec;
61     privmsg_enc_part.seq_number = replaydata->seq;
62
63     /* start by encoding to-be-encrypted part of the message */
64     if (retval = encode_krb5_enc_priv_part(&privmsg_enc_part, &scratch1))
65         return retval;
66
67     /* put together an eblock for this encryption */
68     krb5_use_cstype(context, &eblock, keyblock->etype);
69     privmsg.enc_part.ciphertext.length = krb5_encrypt_size(scratch1->length,
70                                                 eblock.crypto_entry);
71     /* add padding area, and zero it */
72     if (!(scratch1->data = realloc(scratch1->data,
73                                   privmsg.enc_part.ciphertext.length))) {
74         /* may destroy scratch1->data */
75         krb5_xfree(scratch1);
76         return ENOMEM;
77     }
78
79     memset(scratch1->data + scratch1->length, 0,
80           privmsg.enc_part.ciphertext.length - scratch1->length);
81     if (!(privmsg.enc_part.ciphertext.data =
82           malloc(privmsg.enc_part.ciphertext.length))) {
83         retval = ENOMEM;
84         goto clean_scratch;
85     }
86
87     /* do any necessary key pre-processing */
88     if (retval = krb5_process_key(context, &eblock, keyblock)) 
89         goto clean_encpart;
90
91     /* call the encryption routine */
92     if (retval = krb5_encrypt(context, (krb5_pointer) scratch1->data,
93                               (krb5_pointer) privmsg.enc_part.ciphertext.data,
94                               scratch1->length, &eblock,
95                               i_vector)) {
96         krb5_finish_key(context, &eblock);
97         goto clean_encpart;
98     }
99
100     /* put last block into the i_vector */
101     if (i_vector)
102         memcpy(i_vector,
103                privmsg.enc_part.ciphertext.data +
104                (privmsg.enc_part.ciphertext.length -
105                 eblock.crypto_entry->block_length),
106                eblock.crypto_entry->block_length);
107            
108     if (retval = encode_krb5_priv(&privmsg, &scratch2))  {
109         krb5_finish_key(context, &eblock);
110         goto clean_encpart;
111     }
112
113     /* encode private message */
114     if (retval = krb5_finish_key(context, &eblock))
115         goto clean_encpart;
116
117     *outbuf = *scratch2;
118     krb5_xfree(scratch2);
119     retval = 0;
120
121 clean_encpart:
122     memset(privmsg.enc_part.ciphertext.data, 0, 
123            privmsg.enc_part.ciphertext.length); 
124     free(privmsg.enc_part.ciphertext.data); 
125     privmsg.enc_part.ciphertext.length = 0;
126     privmsg.enc_part.ciphertext.data = 0;
127
128 clean_scratch:
129     memset(scratch1->data, 0, scratch1->length);
130     krb5_free_data(context, scratch1); 
131
132     return retval;
133 }
134
135
136 krb5_error_code
137 krb5_mk_priv(context, auth_context, userdata, outbuf, outdata)
138     krb5_context        context;
139     krb5_auth_context * auth_context;
140     const krb5_data   * userdata;
141     krb5_data         * outbuf;
142     krb5_replay_data  * outdata;
143 {
144     krb5_replay_data    replaydata;
145     krb5_error_code     retval;
146
147     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
148       (auth_context->rcache == NULL))
149         return KRB5_RC_REQUIRED;
150
151     if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
152       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
153       (outdata == NULL))
154         /* Need a better error */
155         return KRB5_RC_REQUIRED;
156
157     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) ||
158         (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) {
159         if (retval = krb5_us_timeofday(context, &replaydata.timestamp,
160                                        &replaydata.usec))
161             return retval;
162         if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) {
163             outdata->timestamp = replaydata.timestamp;
164             outdata->usec = replaydata.usec;
165         }
166     }
167     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
168         (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
169         replaydata.seq = auth_context->local_seq_number;
170         if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
171             auth_context->local_seq_number++;
172         } else {
173             outdata->seq = replaydata.seq;
174         }
175     } 
176
177     if (retval = krb5_mk_priv_basic(context, userdata, auth_context->keyblock,
178       &replaydata, auth_context->local_addr, auth_context->remote_addr,
179       auth_context->i_vector, outbuf)) 
180         goto error;
181
182     if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
183         krb5_donot_replay replay;
184
185         if (retval = krb5_gen_replay_name(context, auth_context->local_addr, 
186                                           "_priv", &replay.client)) {
187             krb5_xfree(outbuf);
188             goto error;
189         }
190
191         replay.server = "";             /* XXX */
192         replay.cusec = replaydata.usec;
193         replay.ctime = replaydata.timestamp;
194         if (retval = krb5_rc_store(context, auth_context->rcache, &replay)) {
195             /* should we really error out here? XXX */
196             krb5_xfree(outbuf);
197             goto error;
198         }
199         krb5_xfree(replay.client);
200     }
201
202     return 0;
203
204 error:
205     if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
206       (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
207         auth_context->local_seq_number--;
208
209     return retval;
210 }
211