Add system headers
[openafs.git] / src / rxkad / ticket.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #if defined(UKERNEL)
12 #include "afs/param.h"
13 #else
14 #include <afs/param.h>
15 #endif
16
17
18 #if defined(UKERNEL)
19 #include "afs/sysincludes.h"
20 #include "afsincludes.h"
21 #include "afs/stds.h"
22 #include "rx/xdr.h"
23 #include "rx/rx.h"
24 #include "des/des.h"
25 #include "rxkad/lifetimes.h"
26 #include "rx/rxkad.h"
27 #else /* defined(UKERNEL) */
28 #include <afs/stds.h>
29 #include <sys/types.h>
30 #ifdef AFS_NT40_ENV
31 #include <winsock2.h>
32 #else
33 #include <netinet/in.h>
34 #endif
35 #include <string.h>
36 #include <rx/xdr.h>
37 #include <rx/rx.h>
38 #include <des.h>
39 #include "lifetimes.h"
40 #include "rxkad.h"
41 #endif /* defined(UKERNEL) */
42
43 /* This union is used to insure we allocate enough space for a key
44  * schedule even if we are linked against a library that uses OpenSSL's
45  * larger representation.  This is necessary so we don't lose if an
46  * application uses both rxkad and openssl.
47  */
48 union Key_schedule_safe {
49     Key_schedule schedule;
50     struct {
51         union {
52             char cblock[8];
53             long deslong[2];
54         } ks;
55         int weak_key;
56     } openssl_schedule[16];
57 };
58
59 #define getstr(name,min) \
60     slen = strlen(ticket); \
61     if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
62     strcpy (name, ticket); \
63     ticket += slen+1
64
65 static int
66 decode_athena_ticket(char *ticket, int ticketLen, char *name, char *inst,
67                      char *realm, afs_int32 * host,
68                      struct ktc_encryptionKey *sessionKey, afs_uint32 * start,
69                      afs_uint32 * end)
70 {
71     char *ticketBeg = ticket;
72     char flags;
73     int slen;
74     int tlen;
75     unsigned char lifetime;
76     char sname[MAXKTCNAMELEN];  /* these aren't used, */
77     char sinst[MAXKTCNAMELEN];  /* but are in the ticket */
78
79     flags = *ticket++;
80     getstr(name, 1);
81     getstr(inst, 0);
82     getstr(realm, 0);
83
84     memcpy(host, ticket, sizeof(*host));
85     ticket += sizeof(*host);
86     *host = ktohl(flags, *host);
87
88     memcpy(sessionKey, ticket, sizeof(struct ktc_encryptionKey));
89     ticket += sizeof(struct ktc_encryptionKey);
90
91     lifetime = *ticket++;
92     memcpy(start, ticket, sizeof(*start));
93     ticket += sizeof(*start);
94     *start = ktohl(flags, *start);
95     *end = life_to_time(*start, lifetime);
96
97     getstr(sname, 1);
98     getstr(sinst, 0);
99
100     tlen = ticket - ticketBeg;
101     if ((round_up_to_ebs(tlen) != ticketLen) && (ticketLen != 56))
102         return -1;
103     return 0;
104 }
105
106 /* This is called to interpret a ticket.  It is assumed that the necessary keys
107    have been added so that the key version number in the ticket will indicate a
108    valid key for decrypting the ticket.  The various fields inside the ticket
109    are copied into the return arguments.  An error code indicate some problem
110    interpreting the ticket and the values of the output parameters are
111    undefined. */
112
113 int
114 tkt_DecodeTicket(char *asecret, afs_int32 ticketLen,
115                  struct ktc_encryptionKey *key, char *name, char *inst,
116                  char *cell, char *sessionKey, afs_int32 * host,
117                  afs_int32 * start, afs_int32 * end)
118 {
119     char clear_ticket[MAXKTCTICKETLEN];
120     char *ticket;
121     union Key_schedule_safe schedule;
122     int code;
123
124     if (ticketLen == 0)
125         return RXKADBADTICKET;  /* no ticket */
126     if ((ticketLen < MINKTCTICKETLEN) ||        /* minimum legal ticket size */
127         (ticketLen > MAXKTCTICKETLEN) ||        /* maximum legal ticket size */
128         ((ticketLen) % 8 != 0)) /* enc. part must be (0 mod 8) bytes */
129         return RXKADBADTICKET;
130
131     if (key_sched(key, schedule.schedule))
132         return RXKADBADKEY;
133
134     ticket = clear_ticket;
135     pcbc_encrypt(asecret, ticket, ticketLen, schedule.schedule, key, DECRYPT);
136
137     code =
138         decode_athena_ticket(ticket, ticketLen, name, inst, cell, host,
139                              sessionKey, start, end);
140
141     if (code)
142         return RXKADBADTICKET;
143
144     code = tkt_CheckTimes(*start, *end, time(0));
145     if (code == 0)
146         return RXKADNOAUTH;
147     else if (code == -1)
148         return RXKADEXPIRED;
149     else if (code < -1)
150         return RXKADBADTICKET;
151
152     return 0;
153 }
154
155 /* This makes a Kerberos ticket */
156 /*
157   char          *ticket;                * ticket is constructed here *
158   int           *ticketLen;             * output length of finished ticket *
159   struct ktc_encryptionKey *key;        * key ticket should be sealed with *
160   char          *name;                  * user of this ticket *
161   char          *inst;
162   char          *cell;                  * cell of authentication *
163   afs_uint32     start,end;             * life of ticket *
164   struct ktc_encryptionKey *sessionKey; * session key invented for ticket *
165   afs_uint32     host;                  * caller's host address *
166   char          *sname;                 * server *
167   char          *sinst;
168 */
169
170 #define putstr(name,min) \
171     slen = strlen(name); \
172     if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
173     strcpy (ticket, name); \
174     ticket += slen+1
175 #define putint(num) num = htonl(num);\
176                     memcpy(ticket, &num, sizeof(num));\
177                     ticket += sizeof(num)
178
179 static int
180 assemble_athena_ticket(char *ticket, int *ticketLen, char *name, char *inst,
181                        char *realm, afs_int32 host,
182                        struct ktc_encryptionKey *sessionKey, afs_uint32 start,
183                        afs_uint32 end, char *sname, char *sinst)
184 {
185     char *ticketBeg = ticket;
186     int slen;
187     unsigned char life;
188
189     *ticket++ = 0;              /* flags, always send net-byte-order */
190     putstr(name, 1);
191     putstr(inst, 0);
192     putstr(realm, 0);
193     putint(host);
194
195     memcpy(ticket, sessionKey, sizeof(struct ktc_encryptionKey));
196     ticket += sizeof(struct ktc_encryptionKey);
197
198     life = time_to_life(start, end);
199     if (life == 0)
200         return -1;
201     *ticket++ = life;
202
203     putint(start);
204     putstr(sname, 1);
205     putstr(sinst, 0);
206
207     *ticketLen = ticket - ticketBeg;
208     return 0;
209 }
210
211 int
212 tkt_MakeTicket(char *ticket, int *ticketLen, struct ktc_encryptionKey *key,
213                char *name, char *inst, char *cell, afs_uint32 start,
214                afs_uint32 end, struct ktc_encryptionKey *sessionKey,
215                afs_uint32 host, char *sname, char *sinst)
216 {
217     int code;
218     union Key_schedule_safe schedule;
219
220     *ticketLen = 0;             /* in case we return early */
221     code =
222         assemble_athena_ticket(ticket, ticketLen, name, inst, cell, host,
223                                sessionKey, start, end, sname, sinst);
224     *ticketLen = round_up_to_ebs(*ticketLen);   /* round up */
225     if (code)
226         return -1;
227
228     /* encrypt ticket */
229     if ((code = key_sched(key, schedule.schedule))) {
230         printf("In tkt_MakeTicket: key_sched returned %d\n", code);
231         return RXKADBADKEY;
232     }
233     pcbc_encrypt(ticket, ticket, *ticketLen, schedule.schedule, key, ENCRYPT);
234     return 0;
235 }
236
237 /* This is just a routine that checks the consistency of ticket lifetimes.  It
238    returns three values: */
239 /* -2 means the times are inconsistent or ticket has expired
240    -1 means the ticket has recently expired.
241     0 means the times are consistent but start time is in the (near) future.
242     1 means the start time is in the past and the end time is infinity.
243     2 means the start time is past and the end time is in the future
244             and the lifetime is within the legal limit.
245  */
246
247 int
248 tkt_CheckTimes(afs_uint32 start, afs_uint32 end, afs_uint32 now)
249 {
250     int active;
251
252     if (start >= end)
253         return -2;              /* zero or negative lifetime */
254     if (start > now + KTC_TIME_UNCERTAINTY + MAXKTCTICKETLIFETIME)
255         return -2;              /* starts too far in the future? */
256     if ((start != 0) && (end != NEVERDATE)
257         && (end - start > MAXKTCTICKETLIFETIME))
258         return -2;              /* too long a life */
259     if ((end != NEVERDATE) && (end + KTC_TIME_UNCERTAINTY < now)) {     /* expired */
260         if ((start != 0)
261             && (now - start > MAXKTCTICKETLIFETIME + 24 * 60 * 60))
262             return -2;
263         else
264             return -1;          /* expired only recently */
265     }
266     if ((start == 0) || (start - KTC_TIME_UNCERTAINTY <= now))
267         active = 1;
268     else
269         active = 0;             /* start time not yet arrived */
270
271     if ((start == 0) || (end == NEVERDATE))
272         return active;          /* no expiration time */
273     return active * 2;          /* ticket valid */
274 }
275
276 afs_int32
277 ktohl(char flags, afs_int32 l)
278 {
279     if (flags & 1) {
280         unsigned char *lp = (unsigned char *)&l;
281         afs_int32 hl;
282         hl = *lp + (*(lp + 1) << 8) + (*(lp + 2) << 16) + (*(lp + 3) << 24);
283         return hl;
284     }
285     return ntohl(l);
286 }
287
288 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
289  * returns the corresponding end time.  There are four simple cases to be
290  * handled.  The first is a life of 0xff, meaning no expiration, and results in
291  * an end time of 0xffffffff.  The second is when life is less than the values
292  * covered by the table.  In this case, the end time is the start time plus the
293  * number of 5 minute intervals specified by life.  The third case returns
294  * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED.  The
295  * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
296  * table to extract the lifetime in seconds, which is added to start to produce
297  * the end time. */
298
299 afs_uint32
300 life_to_time(afs_uint32 start, unsigned char life)
301 {
302     int realLife;
303
304     if (life == TKTLIFENOEXPIRE)
305         return NEVERDATE;
306     if (life < TKTLIFEMINFIXED)
307         return start + life * 5 * 60;
308     if (life > TKTLIFEMAXFIXED)
309         return start + MAXTKTLIFETIME;
310     realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
311     return start + realLife;
312 }
313
314 /* time_to_life - takes start and end times for the ticket and returns a
315  * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
316  * lifetimes above 127*5minutes.  First, the special case of (end ==
317  * 0xffffffff) is handled to mean no expiration.  Then negative lifetimes and
318  * those greater than the maximum ticket lifetime are rejected.  Then lifetimes
319  * less than the first table entry are handled by rounding the requested
320  * lifetime *up* to the next 5 minute interval.  The final step is to search
321  * the table for the smallest entry *greater than or equal* to the requested
322  * entry.  The actual code is prepared to handle the case where the table is
323  * unordered but that it an unnecessary frill. */
324
325 unsigned char
326 time_to_life(afs_uint32 start, afs_uint32 end)
327 {
328     int lifetime = end - start;
329     int best, best_i;
330     int i;
331
332     if (end == NEVERDATE)
333         return TKTLIFENOEXPIRE;
334     if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
335         return 0;
336     if (lifetime < tkt_lifetimes[0])
337         return (lifetime + 5 * 60 - 1) / (5 * 60);
338     best_i = -1;
339     best = MAXKTCTICKETLIFETIME;
340     for (i = 0; i < TKTLIFENUMFIXED; i++)
341         if (tkt_lifetimes[i] >= lifetime) {
342             int diff = tkt_lifetimes[i] - lifetime;
343             if (diff < best) {
344                 best = diff;
345                 best_i = i;
346             }
347         }
348     if (best_i < 0)
349         return 0;
350     return best_i + TKTLIFEMINFIXED;
351 }