]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/krb5/rd_priv.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / lib / krb5 / rd_priv.c
1 /*
2  * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include <krb5_locl.h>
35
36 RCSID("$Id: rd_priv.c 21751 2007-07-31 20:42:20Z lha $");
37
38 krb5_error_code KRB5_LIB_FUNCTION
39 krb5_rd_priv(krb5_context context,
40              krb5_auth_context auth_context,
41              const krb5_data *inbuf,
42              krb5_data *outbuf,
43              krb5_replay_data *outdata)
44 {
45     krb5_error_code ret;
46     KRB_PRIV priv;
47     EncKrbPrivPart part;
48     size_t len;
49     krb5_data plain;
50     krb5_keyblock *key;
51     krb5_crypto crypto;
52
53     if (outbuf)
54         krb5_data_zero(outbuf);
55
56     if ((auth_context->flags & 
57          (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
58         outdata == NULL) {
59         krb5_clear_error_string (context);
60         return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */
61     }
62
63     memset(&priv, 0, sizeof(priv));
64     ret = decode_KRB_PRIV (inbuf->data, inbuf->length, &priv, &len);
65     if (ret) {
66         krb5_clear_error_string (context);
67         goto failure;
68     }
69     if (priv.pvno != 5) {
70         krb5_clear_error_string (context);
71         ret = KRB5KRB_AP_ERR_BADVERSION;
72         goto failure;
73     }
74     if (priv.msg_type != krb_priv) {
75         krb5_clear_error_string (context);
76         ret = KRB5KRB_AP_ERR_MSG_TYPE;
77         goto failure;
78     }
79
80     if (auth_context->remote_subkey)
81         key = auth_context->remote_subkey;
82     else if (auth_context->local_subkey)
83         key = auth_context->local_subkey;
84     else
85         key = auth_context->keyblock;
86
87     ret = krb5_crypto_init(context, key, 0, &crypto);
88     if (ret)
89         goto failure;
90     ret = krb5_decrypt_EncryptedData(context,
91                                      crypto,
92                                      KRB5_KU_KRB_PRIV,
93                                      &priv.enc_part,
94                                      &plain);
95     krb5_crypto_destroy(context, crypto);
96     if (ret) 
97         goto failure;
98
99     ret = decode_EncKrbPrivPart (plain.data, plain.length, &part, &len);
100     krb5_data_free (&plain);
101     if (ret) {
102         krb5_clear_error_string (context);
103         goto failure;
104     }
105   
106     /* check sender address */
107
108     if (part.s_address
109         && auth_context->remote_address
110         && !krb5_address_compare (context,
111                                   auth_context->remote_address,
112                                   part.s_address)) {
113         krb5_clear_error_string (context);
114         ret = KRB5KRB_AP_ERR_BADADDR;
115         goto failure_part;
116     }
117
118     /* check receiver address */
119
120     if (part.r_address
121         && auth_context->local_address
122         && !krb5_address_compare (context,
123                                   auth_context->local_address,
124                                   part.r_address)) {
125         krb5_clear_error_string (context);
126         ret = KRB5KRB_AP_ERR_BADADDR;
127         goto failure_part;
128     }
129
130     /* check timestamp */
131     if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
132         krb5_timestamp sec;
133
134         krb5_timeofday (context, &sec);
135         if (part.timestamp == NULL ||
136             part.usec      == NULL ||
137             abs(*part.timestamp - sec) > context->max_skew) {
138             krb5_clear_error_string (context);
139             ret = KRB5KRB_AP_ERR_SKEW;
140             goto failure_part;
141         }
142     }
143
144     /* XXX - check replay cache */
145
146     /* check sequence number. since MIT krb5 cannot generate a sequence
147        number of zero but instead generates no sequence number, we accept that
148     */
149
150     if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
151         if ((part.seq_number == NULL
152              && auth_context->remote_seqnumber != 0)
153             || (part.seq_number != NULL
154                 && *part.seq_number != auth_context->remote_seqnumber)) {
155             krb5_clear_error_string (context);
156             ret = KRB5KRB_AP_ERR_BADORDER;
157             goto failure_part;
158         }
159         auth_context->remote_seqnumber++;
160     }
161
162     ret = krb5_data_copy (outbuf, part.user_data.data, part.user_data.length);
163     if (ret)
164         goto failure_part;
165
166     if ((auth_context->flags & 
167          (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) {
168         /* if these fields are not present in the priv-part, silently
169            return zero */
170         memset(outdata, 0, sizeof(*outdata));
171         if(part.timestamp)
172             outdata->timestamp = *part.timestamp;
173         if(part.usec)
174             outdata->usec = *part.usec;
175         if(part.seq_number)
176             outdata->seq = *part.seq_number;
177     }
178
179   failure_part:
180     free_EncKrbPrivPart (&part);
181
182   failure:
183     free_KRB_PRIV (&priv);
184     return ret;
185 }