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