krb4-64bit-tf-kth-or-mit-20070820
[openafs.git] / src / kauth / krb_tf.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 /*
11  * ALL RIGHTS RESERVED
12  */
13
14 /* This modified from the code in kerberos/src/lib/krb/tf_util.c. */
15
16 /*
17  * This file contains routines for manipulating the ticket cache file.
18  *
19  * The ticket file is in the following format:
20  *
21  *      principal's name        (null-terminated string)
22  *      principal's instance    (null-terminated string)
23  *      CREDENTIAL_1
24  *      CREDENTIAL_2
25  *      ...
26  *      CREDENTIAL_n
27  *      EOF
28  *
29  *      Where "CREDENTIAL_x" consists of the following fixed-length
30  *      fields from the CREDENTIALS structure (see "krb.h"):
31  *
32  *              char            service[ANAME_SZ]
33  *              char            instance[INST_SZ]
34  *              char            realm[REALM_SZ]
35  *              C_Block         session
36  *              int             lifetime
37  *              int             kvno
38  *              KTEXT_ST        ticket_st
39  *              afs_int32            issue_date
40  *
41  * . . .
42  */
43
44 /* Inspite of what the above comment suggests the fields are not fixed length
45    but null terminated as you might figure, except for the ticket which is
46    preceded by a 4 byte length.  All fields in host order. 890306 */
47 #include <afsconfig.h>
48 #include <afs/param.h>
49
50 RCSID
51     ("$Header$");
52
53 #ifdef HAVE_FCNTL_H
54 #include <fcntl.h>
55 #endif
56 #ifdef AFS_NT40_ENV
57 #include <io.h>
58 #else
59 #include <sys/file.h>
60 #endif
61 #ifdef HAVE_STRING_H
62 #include <string.h>
63 #else
64 #ifdef HAVE_STRINGS_H
65 #include <strings.h>
66 #endif
67 #endif
68 #include <sys/types.h>
69 #include <rx/xdr.h>
70 #include <errno.h>
71 #include <afs/auth.h>
72 #include "kauth.h"
73 #include "kautils.h"
74
75 #ifndef WORDS_BIGENDIAN
76 /* This was taken from jhutz's patch for heimdal krb4. It only
77  * applies to little endian systems. Big endian systems have a
78  * less elegant solution documented below.
79  *
80  * This record is written after every real ticket, to ensure that
81  * both 32- and 64-bit readers will perceive the next real ticket
82  * as starting in the same place.  This record looks like a ticket
83  * with the following properties:
84  *   Field         32-bit             64-bit
85  *   ============  =================  =================
86  *   sname         "."                "."
87  *   sinst         ""                 ""
88  *   srealm        ".."               ".."
89  *   session key   002E2E00 xxxxxxxx  xxxxxxxx 00000000
90  *   lifetime      0                  0
91  *   kvno          0                  12
92  *   ticket        12 nulls           4 nulls
93  *   issue         0                  0
94  */
95 static unsigned char align_rec[] = {
96     0x2e, 0x00, 0x00, 0x2e, 0x2e, 0x00, 0x00, 0x2e,
97     0x2e, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
98     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
99     0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
100     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101     0x00, 0x00
102 };
103
104 #else /* AFSLITTLE_ENDIAN */
105
106 /* This was taken from asedeno's patch for MIT Kerberos. These
107  * alignment records are for big endian systems. We need more of them
108  * because the portion of the 64-bit issue_date that overlaps with the
109  * start of a ticket on 32-bit systems contains an unpredictable
110  * number of NULL bytes. Preceeding these records is a second copy of
111  * the 32-bit issue_date. The srealm for the alignment records is
112  * always one of ".." or "?.."
113  */
114
115 /* No NULL bytes
116  * This is actually two alignment records since both 32- and 64-bit
117  * readers will agree on everything in the first record up through the
118  * issue_date size, except where sname starts.
119  *   Field (1)     32-bit             64-bit
120  *   ============  =================  =================
121  *   sname         "????."            "."
122  *   sinst         ""                 ""
123  *   srealm        ".."               ".."
124  *   session key   00000000 xxxxxxxx  00000000 xxxxxxxx
125  *   lifetime      0                  0
126  *   kvno          0                  0
127  *   ticket        4 nulls           4 nulls
128  *   issue         0                  0
129  *
130  *   Field (2)     32-bit             64-bit
131  *   ============  =================  =================
132  *   sname         "."                "."
133  *   sinst         ""                 ""
134  *   srealm        ".."               ".."
135  *   session key   002E2E00 xxxxxxxx  xxxxxxxx 00000000
136  *   lifetime      0                  0
137  *   kvno          0                  12
138  *   ticket        12 nulls           4 nulls
139  *   issue         0                  0
140  *
141  */
142 static unsigned char align_rec_0[] = {
143     0x2e, 0x00, 0x00, 0x2e, 0x2e, 0x00, 0x00, 0x00,
144     0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
145     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146     0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147     0x00, 0x00, 0x2e, 0x00, 0x00, 0x2e, 0x2e, 0x00,
148     0x00, 0x2e, 0x2e, 0x00, 0xff, 0xff, 0xff, 0xff,
149     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150     0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04,
151     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152     0x00, 0x00, 0x00, 0x00
153 };
154
155 /* One NULL byte
156  *   Field         32-bit             64-bit
157  *   ============  =================  =================
158  *   sname         "x"  |"xx"|"xxx"   "."
159  *   sinst         "xx."|"x."|"."     ".."
160  *   srealm        ".."               "..."
161  *   session key   2E2E2E00 xxxxxxxx  xxxxxxxx 00000000
162  *   lifetime      0                  0
163  *   kvno          0                  12
164  *   ticket        12 nulls           4 nulls
165  *   issue         0                  0
166  */
167 static unsigned char align_rec_1[] = {
168     0x2e, 0x00, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e,
169     0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
170     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171     0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
172     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173     0x00
174 };
175
176 /* Two NULL bytes
177  *   Field         32-bit             64-bit
178  *   ============  =================  =================
179  *   sname         "x"  |"x" |"xx"    ".."
180  *   sinst         ""   |"x" |""      ""
181  *   srealm        "x.."|".."|".."    ".."
182  *   session key   002E2E00 xxxxxxxx  xxxxxxxx 00000000
183  *   lifetime      0                  0
184  *   kvno          0                  12
185  *   ticket        12 nulls           4 nulls
186  *   issue         0                  0
187  */
188  static unsigned char align_rec_2[] = {
189     0x2e, 0x2e, 0x00, 0x00, 0x2e, 0x2e, 0x00, 0xff,
190     0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
191     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
192     0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
193     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
194 };
195
196 /* Three NULL bytes
197  * Things break here for 32-bit krb4 libraries that don't
198  * understand this alignment record. We can't really do
199  * anything about the fact that the three strings ended
200  * in the duplicate timestamp. The good news is that this
201  * only happens once every 0x1000000 seconds, once roughly
202  * every six and a half months. We'll live.
203  *
204  * Discussion on the krbdev list has suggested the
205  * issue_date be incremented by one in this case to avoid
206  * the problem. I'm leaving this here just in case.
207  *
208  *   Field         32-bit             64-bit
209  *   ============  =================  =================
210  *   sname         ""                 "."
211  *   sinst         ""                 ""
212  *   srealm        ""                 ".."
213  *   session key   2E00002E 2E00FFFF  xxxx0000 0000xxxx
214  *   lifetime      0                  0
215  *   kvno          4294901760         917504
216  *   ticket        14 nulls           4 nulls
217  *   issue         0                  0
218  */
219 /*
220 static unsigned char align_rec_3[] = {
221     0x2e, 0x00, 0x00, 0x2e, 0x2e, 0x00, 0xff, 0xff,
222     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
223     0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
224     0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225     0x00, 0x00, 0x00, 0x00, 0x00, 0x00
226 };
227 */
228 #endif /* AFSLITTLE_ENDIAN */
229
230 afs_int32
231 krb_write_ticket_file(realm)
232      char *realm;
233 {
234     char ticket_file[AFSDIR_PATH_MAX];
235     int fd;
236     int count;
237     afs_int32 code;
238     int lifetime, kvno;
239     char *tf_name;
240     struct ktc_principal client, server;
241     struct ktc_token token;
242
243     if ((strlen(realm) >= sizeof(client.cell)))
244         return KABADNAME;
245     strcpy(server.name, KA_TGS_NAME);
246     strcpy(server.instance, realm);
247     lcstring(server.cell, realm, sizeof(server.cell));
248
249     code = ktc_GetToken(&server, &token, sizeof(struct ktc_token), &client);
250     if (code)
251         return code;
252
253     /* Use the KRBTKFILE environment variable if it exists, otherwise fall
254      * back upon /tmp/tkt(uid}. 
255      */
256     if (tf_name = (char *)getenv("KRBTKFILE"))
257         (void)sprintf(ticket_file, "%s", tf_name);
258     else
259         (void)sprintf(ticket_file, "%s/tkt%d", gettmpdir(), getuid());
260     fd = open(ticket_file, O_WRONLY + O_CREAT + O_TRUNC, 0700);
261     if (fd <= 0)
262         return errno;
263
264     /* write client name as file header */
265
266     count = strlen(client.name) + 1;
267     if (write(fd, client.name, count) != count)
268         goto bad;
269
270     count = strlen(client.instance) + 1;
271     if (write(fd, client.instance, count) != count)
272         goto bad;
273
274     /* Write the ticket and associated data */
275     /* Service */
276     count = strlen(server.name) + 1;
277     if (write(fd, server.name, count) != count)
278         goto bad;
279     /* Instance */
280     count = strlen(server.instance) + 1;
281     if (write(fd, server.instance, count) != count)
282         goto bad;
283     /* Realm */
284     ucstring(server.cell, server.cell, sizeof(server.cell));
285     count = strlen(server.cell) + 1;
286     if (write(fd, server.cell, count) != count)
287         goto bad;
288     /* Session key */
289     if (write(fd, (char *)&token.sessionKey, 8) != 8)
290         goto bad;
291     /* Lifetime */
292     lifetime = time_to_life(token.startTime, token.endTime);
293     if (write(fd, (char *)&lifetime, sizeof(int)) != sizeof(int))
294         goto bad;
295     /* Key vno */
296     kvno = token.kvno;
297     if (write(fd, (char *)&kvno, sizeof(int)) != sizeof(int))
298         goto bad;
299     /* Tkt length */
300     if (write(fd, (char *)&(token.ticketLen), sizeof(int)) != sizeof(int))
301         goto bad;
302     /* Ticket */
303     count = token.ticketLen;
304     if (write(fd, (char *)(token.ticket), count) != count)
305         goto bad;
306     /* Issue date */
307     if (write(fd, (char *)&(token.startTime), sizeof(afs_int32))
308         != sizeof(afs_int32))
309         goto bad;
310     close(fd);
311     return 0;
312
313     /* Alignment Record, from MIT Kerberos */
314 #ifndef WORDS_BIGENDIAN
315     if (write(fd, align_rec, sizeof(align_rec)) != sizeof(align_rec))
316         goto bad;
317 #else /* AFSLITTLE_ENDIAN */
318     {
319         int null_bytes = 0;
320         if (0 == (token.startTime & 0xff000000))
321             ++null_bytes;
322         if (0 == (token.startTime & 0x00ff0000))
323             ++null_bytes;
324         if (0 == (token.startTime & 0x0000ff00))
325             ++null_bytes;
326         if (0 == (token.startTime & 0x000000ff))
327             ++null_bytes;
328
329         switch(null_bytes) {
330         case 0:
331              /* Issue date */
332             if (write(fd, (char *) token.startTime, sizeof(afs_int32))
333                 != sizeof(afs_int32))
334                 goto bad;
335             if (write(fd, align_rec_0, sizeof(align_rec_0))
336                 != sizeof(align_rec_0))
337                 goto bad;
338             break;
339
340         case 1:
341             /* Issue date */
342             if (write(fd, (char *) &token.startTime, sizeof(afs_int32))
343                 != sizeof(afs_int32))
344                 goto bad;
345             if (write(fd, align_rec_1, sizeof(align_rec_1))
346                 != sizeof(align_rec_1))
347                 goto bad;
348             break;
349
350         case 3:
351             /* Three NULLS are troublesome but rare. We'll just pretend
352              * they don't exist by decrementing the token.startTime.
353              */
354             --token.startTime;
355         case 2:
356             /* Issue date */
357             if (write(fd, (char *) &token.startTime, sizeof(afs_int32))
358                 != sizeof(afs_int32))
359                 goto bad;
360             if (write(fd, align_rec_2, sizeof(align_rec_2))
361                 != sizeof(align_rec_2))
362                 goto bad;
363             break;
364
365         default:
366              goto bad;
367         }
368     }
369 #endif  /* AFSLITTLE_ENDIAN */
370     close(fd);
371     return 0;
372       
373     
374   bad:
375     close(fd);
376     return -1;
377 }