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