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