openafs-string-header-cleanup-20071030
[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 #include <string.h>
62 #include <sys/types.h>
63 #include <rx/xdr.h>
64 #include <errno.h>
65 #include <afs/auth.h>
66 #include "kauth.h"
67 #include "kautils.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(realm)
226      char *realm;
227 {
228     char ticket_file[AFSDIR_PATH_MAX];
229     int fd;
230     int count;
231     afs_int32 code;
232     int lifetime, kvno;
233     char *tf_name;
234     struct ktc_principal client, server;
235     struct ktc_token token;
236
237     if ((strlen(realm) >= sizeof(client.cell)))
238         return KABADNAME;
239     strcpy(server.name, KA_TGS_NAME);
240     strcpy(server.instance, realm);
241     lcstring(server.cell, realm, sizeof(server.cell));
242
243     code = ktc_GetToken(&server, &token, sizeof(struct ktc_token), &client);
244     if (code)
245         return code;
246
247     /* Use the KRBTKFILE environment variable if it exists, otherwise fall
248      * back upon /tmp/tkt(uid}. 
249      */
250     if (tf_name = (char *)getenv("KRBTKFILE"))
251         (void)sprintf(ticket_file, "%s", tf_name);
252     else
253         (void)sprintf(ticket_file, "%s/tkt%d", gettmpdir(), getuid());
254     fd = open(ticket_file, O_WRONLY + O_CREAT + O_TRUNC, 0700);
255     if (fd <= 0)
256         return errno;
257
258     /* write client name as file header */
259
260     count = strlen(client.name) + 1;
261     if (write(fd, client.name, count) != count)
262         goto bad;
263
264     count = strlen(client.instance) + 1;
265     if (write(fd, client.instance, count) != count)
266         goto bad;
267
268     /* Write the ticket and associated data */
269     /* Service */
270     count = strlen(server.name) + 1;
271     if (write(fd, server.name, count) != count)
272         goto bad;
273     /* Instance */
274     count = strlen(server.instance) + 1;
275     if (write(fd, server.instance, count) != count)
276         goto bad;
277     /* Realm */
278     ucstring(server.cell, server.cell, sizeof(server.cell));
279     count = strlen(server.cell) + 1;
280     if (write(fd, server.cell, count) != count)
281         goto bad;
282     /* Session key */
283     if (write(fd, (char *)&token.sessionKey, 8) != 8)
284         goto bad;
285     /* Lifetime */
286     lifetime = time_to_life(token.startTime, token.endTime);
287     if (write(fd, (char *)&lifetime, sizeof(int)) != sizeof(int))
288         goto bad;
289     /* Key vno */
290     kvno = token.kvno;
291     if (write(fd, (char *)&kvno, sizeof(int)) != sizeof(int))
292         goto bad;
293     /* Tkt length */
294     if (write(fd, (char *)&(token.ticketLen), sizeof(int)) != sizeof(int))
295         goto bad;
296     /* Ticket */
297     count = token.ticketLen;
298     if (write(fd, (char *)(token.ticket), count) != count)
299         goto bad;
300     /* Issue date */
301     if (write(fd, (char *)&(token.startTime), sizeof(afs_int32))
302         != sizeof(afs_int32))
303         goto bad;
304     close(fd);
305     return 0;
306
307     /* Alignment Record, from MIT Kerberos */
308 #ifndef WORDS_BIGENDIAN
309     if (write(fd, align_rec, sizeof(align_rec)) != sizeof(align_rec))
310         goto bad;
311 #else /* AFSLITTLE_ENDIAN */
312     {
313         int null_bytes = 0;
314         if (0 == (token.startTime & 0xff000000))
315             ++null_bytes;
316         if (0 == (token.startTime & 0x00ff0000))
317             ++null_bytes;
318         if (0 == (token.startTime & 0x0000ff00))
319             ++null_bytes;
320         if (0 == (token.startTime & 0x000000ff))
321             ++null_bytes;
322
323         switch(null_bytes) {
324         case 0:
325              /* Issue date */
326             if (write(fd, (char *) token.startTime, sizeof(afs_int32))
327                 != sizeof(afs_int32))
328                 goto bad;
329             if (write(fd, align_rec_0, sizeof(align_rec_0))
330                 != sizeof(align_rec_0))
331                 goto bad;
332             break;
333
334         case 1:
335             /* Issue date */
336             if (write(fd, (char *) &token.startTime, sizeof(afs_int32))
337                 != sizeof(afs_int32))
338                 goto bad;
339             if (write(fd, align_rec_1, sizeof(align_rec_1))
340                 != sizeof(align_rec_1))
341                 goto bad;
342             break;
343
344         case 3:
345             /* Three NULLS are troublesome but rare. We'll just pretend
346              * they don't exist by decrementing the token.startTime.
347              */
348             --token.startTime;
349         case 2:
350             /* Issue date */
351             if (write(fd, (char *) &token.startTime, sizeof(afs_int32))
352                 != sizeof(afs_int32))
353                 goto bad;
354             if (write(fd, align_rec_2, sizeof(align_rec_2))
355                 != sizeof(align_rec_2))
356                 goto bad;
357             break;
358
359         default:
360              goto bad;
361         }
362     }
363 #endif  /* AFSLITTLE_ENDIAN */
364     close(fd);
365     return 0;
366       
367     
368   bad:
369     close(fd);
370     return -1;
371 }