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
10 #include <afsconfig.h>
12 #include "afs/param.h"
14 #include <afs/param.h>
20 #include "afs/sysincludes.h"
21 #include "afsincludes.h"
26 #include "rxkad/lifetimes.h"
28 #else /* defined(UKERNEL) */
30 #include <sys/types.h>
34 #include <netinet/in.h>
46 #include "lifetimes.h"
48 #endif /* defined(UKERNEL) */
50 /* This union is used to insure we allocate enough space for a key
51 * schedule even if we are linked against a library that uses OpenSSL's
52 * larger representation. This is necessary so we don't lose if an
53 * application uses both rxkad and openssl.
55 union Key_schedule_safe {
56 Key_schedule schedule;
63 } openssl_schedule[16];
66 #define getstr(name,min) \
67 slen = strlen(ticket); \
68 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
69 strcpy (name, ticket); \
72 static int decode_athena_ticket (char *ticket, int ticketLen, char *name,
73 char *inst, char *realm, afs_int32 *host, struct ktc_encryptionKey *sessionKey,
74 afs_uint32 *start, afs_uint32 *end)
75 { char *ticketBeg = ticket;
79 unsigned char lifetime;
80 char sname[MAXKTCNAMELEN]; /* these aren't used, */
81 char sinst[MAXKTCNAMELEN]; /* but are in the ticket */
88 memcpy(host, ticket, sizeof (*host));
89 ticket += sizeof(*host);
90 *host = ktohl (flags, *host);
92 memcpy(sessionKey, ticket, sizeof (struct ktc_encryptionKey));
93 ticket += sizeof (struct ktc_encryptionKey);
96 memcpy(start, ticket, sizeof (*start));
97 ticket += sizeof(*start);
98 *start = ktohl (flags, *start);
99 *end = life_to_time (*start, lifetime);
104 tlen = ticket - ticketBeg;
105 if ((round_up_to_ebs(tlen) != ticketLen) && (ticketLen != 56)) return -1;
109 /* This is called to interpret a ticket. It is assumed that the necessary keys
110 have been added so that the key version number in the ticket will indicate a
111 valid key for decrypting the ticket. The various fields inside the ticket
112 are copied into the return arguments. An error code indicate some problem
113 interpreting the ticket and the values of the output parameters are
116 int tkt_DecodeTicket (char *asecret, afs_int32 ticketLen,
117 struct ktc_encryptionKey *key, char *name, char *inst, char *cell,
118 char *sessionKey, afs_int32 *host, afs_int32 *start, afs_int32 *end)
119 { char clear_ticket[MAXKTCTICKETLEN];
121 union Key_schedule_safe schedule;
124 if (ticketLen == 0) return RXKADBADTICKET; /* no ticket */
125 if ((ticketLen < MINKTCTICKETLEN) || /* minimum legal ticket size */
126 (ticketLen > MAXKTCTICKETLEN) || /* maximum legal ticket size */
127 ((ticketLen) % 8 != 0)) /* enc. part must be (0 mod 8) bytes */
128 return RXKADBADTICKET;
130 if (key_sched (key, schedule.schedule)) return RXKADBADKEY;
132 ticket = clear_ticket;
133 pcbc_encrypt (asecret, ticket, ticketLen, schedule.schedule, key, DECRYPT);
135 code = decode_athena_ticket
136 (ticket, ticketLen, name, inst, cell, host, sessionKey, start, end);
138 if (code) return RXKADBADTICKET;
139 if (tkt_CheckTimes (*start, *end, time(0)) < -1) return RXKADBADTICKET;
144 /* This makes a Kerberos ticket */
146 char *ticket; * ticket is constructed here *
147 int *ticketLen; * output length of finished ticket *
148 struct ktc_encryptionKey *key; * key ticket should be sealed with *
149 char *name; * user of this ticket *
151 char *cell; * cell of authentication *
152 afs_uint32 start,end; * life of ticket *
153 struct ktc_encryptionKey *sessionKey; * session key invented for ticket *
154 afs_uint32 host; * caller's host address *
155 char *sname; * server *
159 #define putstr(name,min) \
160 slen = strlen(name); \
161 if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
162 strcpy (ticket, name); \
164 #define putint(num) num = htonl(num);\
165 memcpy(ticket, &num, sizeof(num));\
166 ticket += sizeof(num)
168 static int assemble_athena_ticket (char *ticket, int *ticketLen, char *name,
169 char *inst, char *realm, afs_int32 host, struct ktc_encryptionKey *sessionKey,
170 afs_uint32 start, afs_uint32 end, char *sname, char *sinst)
171 { char *ticketBeg = ticket;
175 *ticket++ = 0; /* flags, always send net-byte-order */
181 memcpy(ticket, sessionKey, sizeof(struct ktc_encryptionKey));
182 ticket += sizeof(struct ktc_encryptionKey);
184 life = time_to_life (start, end);
185 if (life == 0) return -1;
192 *ticketLen = ticket - ticketBeg;
196 int tkt_MakeTicket (char *ticket, int *ticketLen,
197 struct ktc_encryptionKey *key, char *name, char *inst, char *cell,
198 afs_uint32 start, afs_uint32 end, struct ktc_encryptionKey *sessionKey,
199 afs_uint32 host, char *sname, char *sinst)
201 union Key_schedule_safe schedule;
203 *ticketLen = 0; /* in case we return early */
204 code = assemble_athena_ticket (ticket, ticketLen, name, inst, cell,
205 host, sessionKey, start, end, sname, sinst);
206 *ticketLen = round_up_to_ebs(*ticketLen); /* round up */
210 if (code = key_sched (key, schedule.schedule)) {
211 printf ("In tkt_MakeTicket: key_sched returned %d\n", code);
214 pcbc_encrypt (ticket, ticket, *ticketLen, schedule.schedule, key, ENCRYPT);
218 /* This is just a routine that checks the consistency of ticket lifetimes. It
219 returns three values: */
220 /* -2 means the times are inconsistent or ticket has expired
221 -1 means the ticket has recently expired.
222 0 means the times are consistent but start time is in the (near) future.
223 1 means the start time is in the past and the end time is infinity.
224 2 means the start time is past and the end time is in the future
225 and the lifetime is within the legal limit.
228 int tkt_CheckTimes (afs_uint32 start, afs_uint32 end, afs_uint32 now)
231 if (start >= end) return -2; /* zero or negative lifetime */
232 if (start > now+KTC_TIME_UNCERTAINTY+MAXKTCTICKETLIFETIME)
233 return -2; /* starts too far in the future? */
234 if ((start != 0) && (end != NEVERDATE) &&
235 (end-start > MAXKTCTICKETLIFETIME)) return -2; /* too long a life */
236 if ((end != NEVERDATE) && (end+KTC_TIME_UNCERTAINTY < now)) { /* expired */
237 if ((start != 0) && (now - start > MAXKTCTICKETLIFETIME + 24*60*60))
239 else return -1; /* expired only recently */
241 if ((start == 0) || (start-KTC_TIME_UNCERTAINTY <= now)) active = 1;
242 else active = 0; /* start time not yet arrived */
244 if ((start == 0) || (end == NEVERDATE))
245 return active; /* no expiration time */
246 return active*2; /* ticket valid */
249 afs_int32 ktohl (char flags, afs_int32 l)
252 unsigned char *lp = (unsigned char *)&l;
254 hl = *lp + (*(lp+1) << 8) + (*(lp+2) << 16) + (*(lp+3) << 24);
260 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
261 * returns the corresponding end time. There are four simple cases to be
262 * handled. The first is a life of 0xff, meaning no expiration, and results in
263 * an end time of 0xffffffff. The second is when life is less than the values
264 * covered by the table. In this case, the end time is the start time plus the
265 * number of 5 minute intervals specified by life. The third case returns
266 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
267 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
268 * table to extract the lifetime in seconds, which is added to start to produce
271 afs_uint32 life_to_time (afs_uint32 start, unsigned char life)
274 if (life == TKTLIFENOEXPIRE) return NEVERDATE;
275 if (life < TKTLIFEMINFIXED) return start + life*5*60;
276 if (life > TKTLIFEMAXFIXED) return start + MAXTKTLIFETIME;
277 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
278 return start + realLife;
281 /* time_to_life - takes start and end times for the ticket and returns a
282 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
283 * lifetimes above 127*5minutes. First, the special case of (end ==
284 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
285 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
286 * less than the first table entry are handled by rounding the requested
287 * lifetime *up* to the next 5 minute interval. The final step is to search
288 * the table for the smallest entry *greater than or equal* to the requested
289 * entry. The actual code is prepared to handle the case where the table is
290 * unordered but that it an unnecessary frill. */
292 unsigned char time_to_life (afs_uint32 start, afs_uint32 end)
293 { int lifetime = end-start;
297 if (end == NEVERDATE) return TKTLIFENOEXPIRE;
298 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0)) return 0;
299 if (lifetime < tkt_lifetimes[0]) return (lifetime + 5*60-1) / (5*60);
301 best = MAXKTCTICKETLIFETIME;
302 for (i=0; i<TKTLIFENUMFIXED; i++)
303 if (tkt_lifetimes[i] >= lifetime) {
304 int diff = tkt_lifetimes[i]-lifetime;
309 if (best_i < 0) return 0;
310 return best_i+TKTLIFEMINFIXED;