convert-from-bsd-to-posix-string-and-memory-functions-20010807
[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 #include <rx/xdr.h>
37 #include <rx/rx.h>
38 #include <des.h>
39 #include "lifetimes.h"
40 #include "rxkad.h"
41 #endif /* defined(UKERNEL) */
42
43
44 extern afs_int32 ktohl();
45 extern afs_uint32 life_to_time();
46 extern unsigned char time_to_life();
47
48 static int decode_athena_ticket();
49 static int assemble_athena_ticket();
50
51 #define ANDREWFLAGSVALUE (0x80)
52 #define TICKET_LABEL "TicketEnd"
53
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
59    undefined. */
60
61 int tkt_DecodeTicket (asecret, ticketLen, key,
62                       name, inst, cell, sessionKey, host, start, end)
63   char          *asecret;
64   afs_int32              ticketLen;
65   struct ktc_encryptionKey *key;
66   char          *name;
67   char          *inst;
68   char          *cell;
69   char          *sessionKey;
70   afs_int32             *host;
71   afs_int32             *start;
72   afs_int32             *end;
73 {   char           clear_ticket[MAXKTCTICKETLEN];
74     char          *ticket;
75     Key_schedule   schedule;
76     /* unsigned char  flags; */
77     int            code;
78
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;
83
84     if (key_sched (key, schedule)) return RXKADBADKEY;
85
86     ticket = clear_ticket;
87     pcbc_encrypt (asecret, ticket, ticketLen, schedule, key, DECRYPT);
88
89     /* flags = *ticket; */              /* get the first byte: the flags */
90 #if 0
91     if (flags == ANDREWFLAGSVALUE) {
92         code = decode_andrew_ticket (ticket, ticketLen, name, inst, cell,
93                                      host, sessionKey, start, end);
94         if (code) {
95             code = decode_athena_ticket (ticket, ticketLen, name, inst, cell,
96                                          host, sessionKey, start, end);
97             flags = 0;
98         }
99     }
100     else {
101         code = decode_athena_ticket (ticket, ticketLen, name, inst, cell,
102                                      host, sessionKey, start, end);
103         if (code) {
104             code = decode_andrew_ticket (ticket, ticketLen, name, inst, cell,
105                                          host, sessionKey, start, end);
106             flags = ANDREWFLAGSVALUE;
107         }
108     }
109 #else
110     code = decode_athena_ticket
111         (ticket, ticketLen, name, inst, cell, host, sessionKey, start, end);
112     /* flags = 0; */
113
114 #endif
115     if (code) return RXKADBADTICKET;
116     if (tkt_CheckTimes (*start, *end, time(0)) < -1) return RXKADBADTICKET;
117
118     return 0;
119 }
120
121 /* This makes a Kerberos ticket */
122
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 */
129   char          *inst;
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 */
135   char          *sinst;
136 {   int          code;
137     Key_schedule schedule;
138
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 */
143     if (code) return -1;
144
145     /* encrypt ticket */
146     if (code = key_sched (key, schedule)) {
147         printf ("In tkt_MakeTicket: key_sched returned %d\n", code);
148         return RXKADBADKEY;
149     }
150     pcbc_encrypt (ticket, ticket, *ticketLen, schedule, key, ENCRYPT);
151     return 0;
152 }
153
154 #define getstr(name,min) \
155     slen = strlen(ticket); \
156     if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
157     strcpy (name, ticket); \
158     ticket += slen+1
159
160 static int decode_athena_ticket (ticket, ticketLen, name, inst, realm,
161                                   host, sessionKey, start, end)
162   char *ticket;
163   int   ticketLen;
164   char *name;
165   char *inst;
166   char *realm;
167   afs_int32 *host;
168   struct ktc_encryptionKey *sessionKey;
169   afs_uint32 *start;
170   afs_uint32 *end;
171 {   char *ticketBeg = ticket;
172     char  flags;
173     int   slen;
174     int   tlen;
175     unsigned char  lifetime;
176     char  sname[MAXKTCNAMELEN];         /* these aren't used, */
177     char  sinst[MAXKTCNAMELEN];         /* but are in the ticket */
178
179     flags = *ticket++;
180     getstr (name, 1);
181     getstr (inst, 0);
182     getstr (realm, 0);
183
184     memcpy(host, ticket, sizeof (*host));
185     ticket += sizeof(*host);
186     *host = ktohl (flags, *host);
187
188     memcpy(sessionKey, ticket, sizeof (struct ktc_encryptionKey));
189     ticket += sizeof (struct ktc_encryptionKey);
190
191     lifetime = *ticket++;
192     memcpy(start, ticket, sizeof (*start));
193     ticket += sizeof(*start);
194     *start = ktohl (flags, *start);
195     *end = life_to_time (*start, lifetime);
196
197     getstr (sname, 1);
198     getstr (sinst, 0);
199
200     tlen = ticket - ticketBeg;
201     if ((round_up_to_ebs(tlen) != ticketLen) && (ticketLen != 56)) return -1;
202     return 0;
203 }
204
205 #define putstr(name,min) \
206     slen = strlen(name); \
207     if ((slen < min) || (slen >= MAXKTCNAMELEN)) return -1; \
208     strcpy (ticket, name); \
209     ticket += slen+1
210 #define putint(num) num = htonl(num);\
211                     memcpy(ticket, &num, sizeof(num));\
212                     ticket += sizeof(num)
213
214 static int assemble_athena_ticket (ticket, ticketLen, name, inst, realm,
215                                     host, sessionKey, start, end, sname, sinst)
216   char *ticket;
217   int  *ticketLen;
218   char *name;
219   char *inst;
220   char *realm;
221   afs_int32  host;
222   struct ktc_encryptionKey *sessionKey;
223   afs_uint32 start;
224   afs_uint32 end;
225   char *sname;
226   char *sinst;
227 {   char *ticketBeg = ticket;
228     int   slen;
229     unsigned char  life;
230
231     *ticket++ = 0;                      /* flags, always send net-byte-order */
232     putstr (name, 1);
233     putstr (inst, 0);
234     putstr (realm, 0);
235     putint (host);
236
237     memcpy(ticket, sessionKey, sizeof(struct ktc_encryptionKey));
238     ticket += sizeof(struct ktc_encryptionKey);
239
240     life = time_to_life (start, end);
241     if (life == 0) return -1;
242     *ticket++ = life;
243
244     putint (start);
245     putstr (sname, 1);
246     putstr (sinst, 0);
247
248     *ticketLen = ticket - ticketBeg;
249     return 0;
250 }
251
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.
260  */
261
262 int tkt_CheckTimes (start, end, now)
263   afs_uint32 start;
264   afs_uint32 end;
265   afs_uint32 now;
266 {   int active;
267
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))
275             return -2;
276         else return -1;                 /* expired only recently */
277     }
278     if ((start == 0) || (start-KTC_TIME_UNCERTAINTY <= now)) active = 1;
279     else active = 0;                    /* start time not yet arrived */
280
281     if ((start == 0) || (end == NEVERDATE))
282         return active; /* no expiration time */
283     return active*2;                    /* ticket valid */
284 }
285
286 afs_int32 ktohl (flags, l)
287   char flags;
288   afs_int32 l;
289 {
290     if (flags & 1) {
291         unsigned char *lp = (unsigned char *)&l;
292         afs_int32              hl;
293         hl = *lp + (*(lp+1) << 8) + (*(lp+2) << 16) + (*(lp+3) << 24);
294         return hl;
295     }
296     return ntohl(l);
297 }
298
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
308  * the end time. */
309
310 afs_uint32 life_to_time (start, life)
311   afs_uint32 start;
312   unsigned char life;
313 {   int realLife;
314
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;
320 }
321
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. */
332
333 unsigned char time_to_life (start, end)
334   afs_uint32 start;
335   afs_uint32 end;
336 {   int lifetime = end-start;
337     int best, best_i;
338     int i;
339
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);
343     best_i = -1;
344     best = MAXKTCTICKETLIFETIME;
345     for (i=0; i<TKTLIFENUMFIXED; i++)
346         if (tkt_lifetimes[i] >= lifetime) {
347             int diff = tkt_lifetimes[i]-lifetime;
348             if (diff < best) {
349                 best = diff;
350                 best_i = i;
351             }}
352     if (best_i < 0) return 0;
353     return best_i+TKTLIFEMINFIXED;
354 }