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