]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/kerberosIV/lib/krb/rd_req.c
This commit was generated by cvs2svn to compensate for changes in r53024,
[FreeBSD/FreeBSD.git] / crypto / kerberosIV / lib / krb / rd_req.c
1 /*
2  * Copyright (c) 1995, 1996, 1997, 1998 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. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the Kungliga Tekniska
20  *      Högskolan and its contributors.
21  * 
22  * 4. Neither the name of the Institute nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  * 
26  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #include "krb_locl.h"
40
41 RCSID("$Id: rd_req.c,v 1.25 1998/06/09 19:25:25 joda Exp $");
42
43 static struct timeval t_local = { 0, 0 };
44
45 /*
46  * Keep the following information around for subsequent calls
47  * to this routine by the same server using the same key.
48  */
49
50 static des_key_schedule serv_key;       /* Key sched to decrypt ticket */
51 static des_cblock ky;              /* Initialization vector */
52 static int st_kvno;             /* version number for this key */
53 static char st_rlm[REALM_SZ];   /* server's realm */
54 static char st_nam[ANAME_SZ];   /* service name */
55 static char st_inst[INST_SZ];   /* server's instance */
56
57 /*
58  * This file contains two functions.  krb_set_key() takes a DES
59  * key or password string and returns a DES key (either the original
60  * key, or the password converted into a DES key) and a key schedule
61  * for it.
62  *
63  * krb_rd_req() reads an authentication request and returns information
64  * about the identity of the requestor, or an indication that the
65  * identity information was not authentic.
66  */
67
68 /*
69  * krb_set_key() takes as its first argument either a DES key or a
70  * password string.  The "cvt" argument indicates how the first
71  * argument "key" is to be interpreted: if "cvt" is null, "key" is
72  * taken to be a DES key; if "cvt" is non-null, "key" is taken to
73  * be a password string, and is converted into a DES key using
74  * string_to_key().  In either case, the resulting key is returned
75  * in the external static variable "ky".  A key schedule is
76  * generated for "ky" and returned in the external static variable
77  * "serv_key".
78  *
79  * This routine returns the return value of des_key_sched.
80  *
81  * krb_set_key() needs to be in the same .o file as krb_rd_req() so that
82  * the key set by krb_set_key() is available in private storage for
83  * krb_rd_req().
84  */
85
86 int
87 krb_set_key(void *key, int cvt)
88 {
89 #ifdef NOENCRYPTION
90     memset(ky, 0, sizeof(ky));
91     return KSUCCESS;
92 #else /* Encrypt */
93     if (cvt)
94         des_string_to_key((char*)key, &ky);
95     else
96         memcpy((char*)ky, key, 8);
97     return(des_key_sched(&ky, serv_key));
98 #endif /* NOENCRYPTION */
99 }
100
101
102 /*
103  * krb_rd_req() takes an AUTH_MSG_APPL_REQUEST or
104  * AUTH_MSG_APPL_REQUEST_MUTUAL message created by krb_mk_req(),
105  * checks its integrity and returns a judgement as to the requestor's
106  * identity.
107  *
108  * The "authent" argument is a pointer to the received message.
109  * The "service" and "instance" arguments name the receiving server,
110  * and are used to get the service's ticket to decrypt the ticket
111  * in the message, and to compare against the server name inside the
112  * ticket.  "from_addr" is the network address of the host from which
113  * the message was received; this is checked against the network
114  * address in the ticket.  If "from_addr" is zero, the check is not
115  * performed.  "ad" is an AUTH_DAT structure which is
116  * filled in with information about the sender's identity according
117  * to the authenticator and ticket sent in the message.  Finally,
118  * "fn" contains the name of the file containing the server's key.
119  * (If "fn" is NULL, the server's key is assumed to have been set
120  * by krb_set_key().  If "fn" is the null string ("") the default
121  * file KEYFILE, defined in "krb.h", is used.)
122  *
123  * krb_rd_req() returns RD_AP_OK if the authentication information
124  * was genuine, or one of the following error codes (defined in
125  * "krb.h"):
126  *
127  *      RD_AP_VERSION           - wrong protocol version number
128  *      RD_AP_MSG_TYPE          - wrong message type
129  *      RD_AP_UNDEC             - couldn't decipher the message
130  *      RD_AP_INCON             - inconsistencies found
131  *      RD_AP_BADD              - wrong network address
132  *      RD_AP_TIME              - client time (in authenticator)
133  *                                too far off server time
134  *      RD_AP_NYV               - Kerberos time (in ticket) too
135  *                                far off server time
136  *      RD_AP_EXP               - ticket expired
137  *
138  * For the message format, see krb_mk_req().
139  *
140  * Mutual authentication is not implemented.
141  */
142
143 int
144 krb_rd_req(KTEXT authent,       /* The received message */
145            char *service,       /* Service name */
146            char *instance,      /* Service instance */
147            int32_t from_addr,   /* Net address of originating host */
148            AUTH_DAT *ad,        /* Structure to be filled in */
149            char *fn)            /* Filename to get keys from */
150 {
151     static KTEXT_ST ticket;     /* Temp storage for ticket */
152     static KTEXT tkt = &ticket;
153     static KTEXT_ST req_id_st;  /* Temp storage for authenticator */
154     KTEXT req_id = &req_id_st;
155
156     char realm[REALM_SZ];       /* Realm of issuing kerberos */
157
158     unsigned char skey[KKEY_SZ]; /* Session key from ticket */
159     char sname[SNAME_SZ];       /* Service name from ticket */
160     char iname[INST_SZ];        /* Instance name from ticket */
161     char r_aname[ANAME_SZ];     /* Client name from authenticator */
162     char r_inst[INST_SZ];       /* Client instance from authenticator */
163     char r_realm[REALM_SZ];     /* Client realm from authenticator */
164     u_int32_t r_time_sec;       /* Coarse time from authenticator */
165     unsigned long delta_t;      /* Time in authenticator - local time */
166     long tkt_age;               /* Age of ticket */
167     static unsigned char s_kvno;/* Version number of the server's key
168                                  * Kerberos used to encrypt ticket */
169
170     struct timeval tv;
171     int status;
172
173     int pvno;
174     int type;
175     int little_endian;
176
177     unsigned char *p;
178
179     if (authent->length <= 0)
180         return(RD_AP_MODIFIED);
181
182     p = authent->dat;
183
184     /* get msg version, type and byte order, and server key version */
185
186     pvno = *p++;
187
188     if(pvno != KRB_PROT_VERSION)
189         return RD_AP_VERSION;
190     
191     type = *p++;
192     
193     little_endian = type & 1;
194     type &= ~1;
195     
196     if(type != AUTH_MSG_APPL_REQUEST && type != AUTH_MSG_APPL_REQUEST_MUTUAL)
197         return RD_AP_MSG_TYPE;
198
199     s_kvno = *p++;
200
201     p += krb_get_string(p, realm, sizeof(realm));
202
203     /*
204      * If "fn" is NULL, key info should already be set; don't
205      * bother with ticket file.  Otherwise, check to see if we
206      * already have key info for the given server and key version
207      * (saved in the static st_* variables).  If not, go get it
208      * from the ticket file.  If "fn" is the null string, use the
209      * default ticket file.
210      */
211     if (fn && (strcmp(st_nam,service) || strcmp(st_inst,instance) ||
212                strcmp(st_rlm,realm) || (st_kvno != s_kvno))) {
213         if (*fn == 0) fn = KEYFILE;
214         st_kvno = s_kvno;
215         if (read_service_key(service, instance, realm, s_kvno,
216                              fn, (char *)skey))
217             return(RD_AP_UNDEC);
218         if ((status = krb_set_key((char*)skey, 0)))
219             return(status);
220         strcpy_truncate (st_rlm, realm, REALM_SZ);
221         strcpy_truncate (st_nam, service, SNAME_SZ);
222         strcpy_truncate (st_inst, instance, INST_SZ);
223     }
224
225     tkt->length = *p++;
226
227     req_id->length = *p++;
228
229     if(tkt->length + (p - authent->dat) > authent->length)
230         return RD_AP_MODIFIED;
231
232     memcpy(tkt->dat, p, tkt->length);
233     p += tkt->length;
234
235     if (krb_ap_req_debug)
236         krb_log("ticket->length: %d",tkt->length);
237
238     /* Decrypt and take apart ticket */
239     if (decomp_ticket(tkt, &ad->k_flags, ad->pname, ad->pinst, ad->prealm,
240                       &ad->address, ad->session, &ad->life,
241                       &ad->time_sec, sname, iname, &ky, serv_key))
242         return RD_AP_UNDEC;
243     
244     if (krb_ap_req_debug) {
245         krb_log("Ticket Contents.");
246         krb_log(" Aname:   %s.%s",ad->pname, ad->prealm);
247         krb_log(" Service: %s", krb_unparse_name_long(sname, iname, NULL));
248     }
249
250     /* Extract the authenticator */
251     
252     if(req_id->length + (p - authent->dat) > authent->length)
253         return RD_AP_MODIFIED;
254
255     memcpy(req_id->dat, p, req_id->length);
256     p = req_id->dat;
257     
258 #ifndef NOENCRYPTION
259     /* And decrypt it with the session key from the ticket */
260     if (krb_ap_req_debug) krb_log("About to decrypt authenticator");
261
262     encrypt_ktext(req_id, &ad->session, DES_DECRYPT);
263
264     if (krb_ap_req_debug) krb_log("Done.");
265 #endif /* NOENCRYPTION */
266
267     /* cast req_id->length to int? */
268 #define check_ptr() if ((ptr - (char *) req_id->dat) > req_id->length) return(RD_AP_MODIFIED);
269
270     p += krb_get_nir(p, r_aname, r_inst, r_realm); /* XXX no rangecheck */
271
272     p += krb_get_int(p, &ad->checksum, 4, little_endian);
273
274     p++; /* time_5ms is not used */
275
276     p += krb_get_int(p, &r_time_sec, 4, little_endian);
277
278     /* Check for authenticity of the request */
279     if (krb_ap_req_debug)
280         krb_log("Principal: %s.%s@%s / %s.%s@%s",ad->pname,ad->pinst, ad->prealm, 
281               r_aname, r_inst, r_realm);
282     if (strcmp(ad->pname, r_aname) != 0 ||
283         strcmp(ad->pinst, r_inst) != 0 ||
284         strcmp(ad->prealm, r_realm) != 0)
285         return RD_AP_INCON;
286     
287     if (krb_ap_req_debug)
288         krb_log("Address: %x %x", ad->address, from_addr);
289
290     if (from_addr && (!krb_equiv(ad->address, from_addr)))
291         return RD_AP_BADD;
292
293     gettimeofday(&tv, NULL);
294     delta_t = abs((int)(tv.tv_sec - r_time_sec));
295     if (delta_t > CLOCK_SKEW) {
296         if (krb_ap_req_debug)
297             krb_log("Time out of range: %lu - %lu = %lu",
298                     (unsigned long)t_local.tv_sec,
299                     (unsigned long)r_time_sec,
300                     (unsigned long)delta_t);
301         return RD_AP_TIME;
302     }
303
304     /* Now check for expiration of ticket */
305
306     tkt_age = tv.tv_sec - ad->time_sec;
307     if (krb_ap_req_debug)
308         krb_log("Time: %ld Issue Date: %lu Diff: %ld Life %x",
309                 (long)tv.tv_sec,
310                 (unsigned long)ad->time_sec,
311                 tkt_age,
312                 ad->life);
313     
314     if ((tkt_age < 0) && (-tkt_age > CLOCK_SKEW))
315         return RD_AP_NYV;
316
317     if (tv.tv_sec > krb_life_to_time(ad->time_sec, ad->life))
318         return RD_AP_EXP;
319
320     /* All seems OK */
321     ad->reply.length = 0;
322
323     return(RD_AP_OK);
324 }