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