2 * Copyright 2000, International Business Machines Corporation and others.
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
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"
17 #include "../des/des.h"
18 #include "../afs/lifetimes.h"
19 #include "../afs/rxkad.h"
20 #else /* defined(UKERNEL) */
21 #include <afs/param.h>
23 #include <sys/types.h>
27 #include <netinet/in.h>
32 #include "lifetimes.h"
34 #endif /* defined(UKERNEL) */
37 extern afs_int32 ktohl();
38 extern afs_uint32 life_to_time();
39 extern unsigned char time_to_life();
41 static int decode_athena_ticket();
42 static int assemble_athena_ticket();
44 #define ANDREWFLAGSVALUE (0x80)
45 #define TICKET_LABEL "TicketEnd"
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
54 int tkt_DecodeTicket (asecret, ticketLen, key,
55 name, inst, cell, sessionKey, host, start, end)
58 struct ktc_encryptionKey *key;
66 { char clear_ticket[MAXKTCTICKETLEN];
68 Key_schedule schedule;
69 /* unsigned char flags; */
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;
77 if (key_sched (key, schedule)) return RXKADBADKEY;
79 ticket = clear_ticket;
80 pcbc_encrypt (asecret, ticket, ticketLen, schedule, key, DECRYPT);
82 /* flags = *ticket; */ /* get the first byte: the flags */
84 if (flags == ANDREWFLAGSVALUE) {
85 code = decode_andrew_ticket (ticket, ticketLen, name, inst, cell,
86 host, sessionKey, start, end);
88 code = decode_athena_ticket (ticket, ticketLen, name, inst, cell,
89 host, sessionKey, start, end);
94 code = decode_athena_ticket (ticket, ticketLen, name, inst, cell,
95 host, sessionKey, start, end);
97 code = decode_andrew_ticket (ticket, ticketLen, name, inst, cell,
98 host, sessionKey, start, end);
99 flags = ANDREWFLAGSVALUE;
103 code = decode_athena_ticket
104 (ticket, ticketLen, name, inst, cell, host, sessionKey, start, end);
108 if (code) return RXKADBADTICKET;
109 if (tkt_CheckTimes (*start, *end, time(0)) < -1) return RXKADBADTICKET;
114 /* This makes a Kerberos ticket */
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 */
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 */
130 Key_schedule schedule;
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 */
139 if (code = key_sched (key, schedule)) {
140 printf ("In tkt_MakeTicket: key_sched returned %d\n", code);
143 pcbc_encrypt (ticket, ticket, *ticketLen, schedule, key, ENCRYPT);
147 #define getstr(name,min) \
148 slen = strlen(ticket); \
149 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
150 strcpy (name, ticket); \
153 static int decode_athena_ticket (ticket, ticketLen, name, inst, realm,
154 host, sessionKey, start, end)
161 struct ktc_encryptionKey *sessionKey;
164 { char *ticketBeg = ticket;
168 unsigned char lifetime;
169 char sname[MAXKTCNAMELEN]; /* these aren't used, */
170 char sinst[MAXKTCNAMELEN]; /* but are in the ticket */
177 bcopy (ticket, host, sizeof (*host));
178 ticket += sizeof(*host);
179 *host = ktohl (flags, *host);
181 bcopy (ticket, sessionKey, sizeof (struct ktc_encryptionKey));
182 ticket += sizeof (struct ktc_encryptionKey);
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);
193 tlen = ticket - ticketBeg;
194 if ((round_up_to_ebs(tlen) != ticketLen) && (ticketLen != 56)) return -1;
198 #define putstr(name,min) \
199 slen = strlen(name); \
200 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
201 strcpy (ticket, name); \
203 #define putint(num) num = htonl(num);\
204 bcopy (&num, ticket, sizeof(num));\
205 ticket += sizeof(num)
207 static int assemble_athena_ticket (ticket, ticketLen, name, inst, realm,
208 host, sessionKey, start, end, sname, sinst)
215 struct ktc_encryptionKey *sessionKey;
220 { char *ticketBeg = ticket;
224 *ticket++ = 0; /* flags, always send net-byte-order */
230 bcopy (sessionKey, ticket, sizeof(struct ktc_encryptionKey));
231 ticket += sizeof(struct ktc_encryptionKey);
233 life = time_to_life (start, end);
234 if (life == 0) return -1;
241 *ticketLen = ticket - ticketBeg;
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.
255 int tkt_CheckTimes (start, end, now)
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))
269 else return -1; /* expired only recently */
271 if ((start == 0) || (start-KTC_TIME_UNCERTAINTY <= now)) active = 1;
272 else active = 0; /* start time not yet arrived */
274 if ((start == 0) || (end == NEVERDATE))
275 return active; /* no expiration time */
276 return active*2; /* ticket valid */
279 afs_int32 ktohl (flags, l)
284 unsigned char *lp = (unsigned char *)&l;
286 hl = *lp + (*(lp+1) << 8) + (*(lp+2) << 16) + (*(lp+3) << 24);
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
303 afs_uint32 life_to_time (start, life)
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;
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. */
326 unsigned char time_to_life (start, end)
329 { int lifetime = end-start;
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);
337 best = MAXKTCTICKETLIFETIME;
338 for (i=0; i<TKTLIFENUMFIXED; i++)
339 if (tkt_lifetimes[i] >= lifetime) {
340 int diff = tkt_lifetimes[i]-lifetime;
345 if (best_i < 0) return 0;
346 return best_i+TKTLIFEMINFIXED;