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