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"
13 #include <afs/param.h>
15 #include <afsconfig.h>
20 #include "../afs/sysincludes.h"
21 #include "../afs/afsincludes.h"
22 #include "../afs/stds.h"
23 #include "../rx/xdr.h"
25 #include "../des/des.h"
26 #include "../afs/lifetimes.h"
27 #include "../afs/rxkad.h"
28 #else /* defined(UKERNEL) */
30 #include <sys/types.h>
34 #include <netinet/in.h>
39 #include "lifetimes.h"
41 #endif /* defined(UKERNEL) */
44 extern afs_int32 ktohl();
45 extern afs_uint32 life_to_time();
46 extern unsigned char time_to_life();
48 static int decode_athena_ticket();
49 static int assemble_athena_ticket();
51 #define ANDREWFLAGSVALUE (0x80)
52 #define TICKET_LABEL "TicketEnd"
54 /* This is called to interpret a ticket. It is assumed that the necessary keys
55 have been added so that the key version number in the ticket will indicate a
56 valid key for decrypting the ticket. The various fields inside the ticket
57 are copied into the return arguments. An error code indicate some problem
58 interpreting the ticket and the values of the output parameters are
61 int tkt_DecodeTicket (asecret, ticketLen, key,
62 name, inst, cell, sessionKey, host, start, end)
65 struct ktc_encryptionKey *key;
73 { char clear_ticket[MAXKTCTICKETLEN];
75 Key_schedule schedule;
76 /* unsigned char flags; */
79 if (ticketLen == 0) return RXKADBADTICKET; /* no ticket */
80 if ((ticketLen < MINKTCTICKETLEN) || /* minimum legal ticket size */
81 ((ticketLen) % 8 != 0)) /* enc. part must be (0 mod 8) bytes */
82 return RXKADBADTICKET;
84 if (key_sched (key, schedule)) return RXKADBADKEY;
86 ticket = clear_ticket;
87 pcbc_encrypt (asecret, ticket, ticketLen, schedule, key, DECRYPT);
89 /* flags = *ticket; */ /* get the first byte: the flags */
91 if (flags == ANDREWFLAGSVALUE) {
92 code = decode_andrew_ticket (ticket, ticketLen, name, inst, cell,
93 host, sessionKey, start, end);
95 code = decode_athena_ticket (ticket, ticketLen, name, inst, cell,
96 host, sessionKey, start, end);
101 code = decode_athena_ticket (ticket, ticketLen, name, inst, cell,
102 host, sessionKey, start, end);
104 code = decode_andrew_ticket (ticket, ticketLen, name, inst, cell,
105 host, sessionKey, start, end);
106 flags = ANDREWFLAGSVALUE;
110 code = decode_athena_ticket
111 (ticket, ticketLen, name, inst, cell, host, sessionKey, start, end);
115 if (code) return RXKADBADTICKET;
116 if (tkt_CheckTimes (*start, *end, time(0)) < -1) return RXKADBADTICKET;
121 /* This makes a Kerberos ticket */
123 int tkt_MakeTicket (ticket, ticketLen, key, name, inst, cell,
124 start, end, sessionKey, host, sname, sinst)
125 char *ticket; /* ticket is constructed here */
126 int *ticketLen; /* output length of finished ticket */
127 struct ktc_encryptionKey *key; /* key ticket should be sealed with */
128 char *name; /* user of this ticket */
130 char *cell; /* cell of authentication */
131 afs_uint32 start,end; /* life of ticket */
132 struct ktc_encryptionKey *sessionKey; /* session key invented for ticket */
133 afs_uint32 host; /* caller's host address */
134 char *sname; /* server */
137 Key_schedule schedule;
139 *ticketLen = 0; /* in case we return early */
140 code = assemble_athena_ticket (ticket, ticketLen, name, inst, cell,
141 host, sessionKey, start, end, sname, sinst);
142 *ticketLen = round_up_to_ebs(*ticketLen); /* round up */
146 if (code = key_sched (key, schedule)) {
147 printf ("In tkt_MakeTicket: key_sched returned %d\n", code);
150 pcbc_encrypt (ticket, ticket, *ticketLen, schedule, key, ENCRYPT);
154 #define getstr(name,min) \
155 slen = strlen(ticket); \
156 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
157 strcpy (name, ticket); \
160 static int decode_athena_ticket (ticket, ticketLen, name, inst, realm,
161 host, sessionKey, start, end)
168 struct ktc_encryptionKey *sessionKey;
171 { char *ticketBeg = ticket;
175 unsigned char lifetime;
176 char sname[MAXKTCNAMELEN]; /* these aren't used, */
177 char sinst[MAXKTCNAMELEN]; /* but are in the ticket */
184 bcopy (ticket, host, sizeof (*host));
185 ticket += sizeof(*host);
186 *host = ktohl (flags, *host);
188 bcopy (ticket, sessionKey, sizeof (struct ktc_encryptionKey));
189 ticket += sizeof (struct ktc_encryptionKey);
191 lifetime = *ticket++;
192 bcopy (ticket, start, sizeof (*start));
193 ticket += sizeof(*start);
194 *start = ktohl (flags, *start);
195 *end = life_to_time (*start, lifetime);
200 tlen = ticket - ticketBeg;
201 if ((round_up_to_ebs(tlen) != ticketLen) && (ticketLen != 56)) return -1;
205 #define putstr(name,min) \
206 slen = strlen(name); \
207 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
208 strcpy (ticket, name); \
210 #define putint(num) num = htonl(num);\
211 bcopy (&num, ticket, sizeof(num));\
212 ticket += sizeof(num)
214 static int assemble_athena_ticket (ticket, ticketLen, name, inst, realm,
215 host, sessionKey, start, end, sname, sinst)
222 struct ktc_encryptionKey *sessionKey;
227 { char *ticketBeg = ticket;
231 *ticket++ = 0; /* flags, always send net-byte-order */
237 bcopy (sessionKey, ticket, sizeof(struct ktc_encryptionKey));
238 ticket += sizeof(struct ktc_encryptionKey);
240 life = time_to_life (start, end);
241 if (life == 0) return -1;
248 *ticketLen = ticket - ticketBeg;
252 /* This is just a routine that checks the consistency of ticket lifetimes. It
253 returns three values: */
254 /* -2 means the times are inconsistent or ticket has expired
255 -1 means the ticket has recently expired.
256 0 means the times are consistent but start time is in the (near) future.
257 1 means the start time is in the past and the end time is infinity.
258 2 means the start time is past and the end time is in the future
259 and the lifetime is within the legal limit.
262 int tkt_CheckTimes (start, end, now)
268 if (start >= end) return -2; /* zero or negative lifetime */
269 if (start > now+KTC_TIME_UNCERTAINTY+MAXKTCTICKETLIFETIME)
270 return -2; /* starts too far in the future? */
271 if ((start != 0) && (end != NEVERDATE) &&
272 (end-start > MAXKTCTICKETLIFETIME)) return -2; /* too long a life */
273 if ((end != NEVERDATE) && (end+KTC_TIME_UNCERTAINTY < now)) { /* expired */
274 if ((start != 0) && (now - start > MAXKTCTICKETLIFETIME + 24*60*60))
276 else return -1; /* expired only recently */
278 if ((start == 0) || (start-KTC_TIME_UNCERTAINTY <= now)) active = 1;
279 else active = 0; /* start time not yet arrived */
281 if ((start == 0) || (end == NEVERDATE))
282 return active; /* no expiration time */
283 return active*2; /* ticket valid */
286 afs_int32 ktohl (flags, l)
291 unsigned char *lp = (unsigned char *)&l;
293 hl = *lp + (*(lp+1) << 8) + (*(lp+2) << 16) + (*(lp+3) << 24);
299 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
300 * returns the corresponding end time. There are four simple cases to be
301 * handled. The first is a life of 0xff, meaning no expiration, and results in
302 * an end time of 0xffffffff. The second is when life is less than the values
303 * covered by the table. In this case, the end time is the start time plus the
304 * number of 5 minute intervals specified by life. The third case returns
305 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
306 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
307 * table to extract the lifetime in seconds, which is added to start to produce
310 afs_uint32 life_to_time (start, life)
315 if (life == TKTLIFENOEXPIRE) return NEVERDATE;
316 if (life < TKTLIFEMINFIXED) return start + life*5*60;
317 if (life > TKTLIFEMAXFIXED) return start + MAXTKTLIFETIME;
318 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
319 return start + realLife;
322 /* time_to_life - takes start and end times for the ticket and returns a
323 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
324 * lifetimes above 127*5minutes. First, the special case of (end ==
325 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
326 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
327 * less than the first table entry are handled by rounding the requested
328 * lifetime *up* to the next 5 minute interval. The final step is to search
329 * the table for the smallest entry *greater than or equal* to the requested
330 * entry. The actual code is prepared to handle the case where the table is
331 * unordered but that it an unnecessary frill. */
333 unsigned char time_to_life (start, end)
336 { int lifetime = end-start;
340 if (end == NEVERDATE) return TKTLIFENOEXPIRE;
341 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0)) return 0;
342 if (lifetime < tkt_lifetimes[0]) return (lifetime + 5*60-1) / (5*60);
344 best = MAXKTCTICKETLIFETIME;
345 for (i=0; i<TKTLIFENUMFIXED; i++)
346 if (tkt_lifetimes[i] >= lifetime) {
347 int diff = tkt_lifetimes[i]-lifetime;
352 if (best_i < 0) return 0;
353 return best_i+TKTLIFEMINFIXED;