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