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