2 * Unix SMB/CIFS implementation.
4 * Copyright (C) Volker Lendecke 2003
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #ifdef WITH_FAKE_KASERVER
28 #include <afs/venus.h>
29 #include <asm/unistd.h>
30 #include <openssl/des.h>
32 _syscall5(int, afs_syscall
, int, subcall
,
42 uint32 BeginTimestamp
;
46 static char *afs_encode_token(const char *cell
, const DATA_BLOB ticket
,
47 const struct ClearToken
*ct
)
52 DATA_BLOB key
= data_blob(ct
->HandShakeKey
, 8);
55 base64_ticket
= base64_encode_data_blob(ticket
);
56 if (base64_ticket
== NULL
)
59 base64_key
= base64_encode_data_blob(key
);
60 if (base64_key
== NULL
) {
65 asprintf(&result
, "%s\n%u\n%s\n%u\n%u\n%u\n%s\n", cell
,
66 ct
->AuthHandle
, base64_key
, ct
->ViceId
, ct
->BeginTimestamp
,
67 ct
->EndTimestamp
, base64_ticket
);
69 DEBUG(10, ("Got ticket string:\n%s\n", result
));
77 static BOOL
afs_decode_token(const char *string
, char **cell
,
78 DATA_BLOB
*ticket
, struct ClearToken
*ct
)
81 struct ClearToken result_ct
;
83 char *s
= strdup(string
);
87 if ((t
= strtok(s
, "\n")) == NULL
) {
88 DEBUG(10, ("strtok failed\n"));
94 if ((t
= strtok(NULL
, "\n")) == NULL
) {
95 DEBUG(10, ("strtok failed\n"));
99 if (sscanf(t
, "%u", &result_ct
.AuthHandle
) != 1) {
100 DEBUG(10, ("sscanf AuthHandle failed\n"));
104 if ((t
= strtok(NULL
, "\n")) == NULL
) {
105 DEBUG(10, ("strtok failed\n"));
109 blob
= base64_decode_data_blob(t
);
111 if ( (blob
.data
== NULL
) ||
112 (blob
.length
!= sizeof(result_ct
.HandShakeKey
) )) {
113 DEBUG(10, ("invalid key: %x/%d\n", (uint32
)blob
.data
,
118 memcpy(result_ct
.HandShakeKey
, blob
.data
, blob
.length
);
120 data_blob_free(&blob
);
122 if ((t
= strtok(NULL
, "\n")) == NULL
) {
123 DEBUG(10, ("strtok failed\n"));
127 if (sscanf(t
, "%u", &result_ct
.ViceId
) != 1) {
128 DEBUG(10, ("sscanf ViceId failed\n"));
132 if ((t
= strtok(NULL
, "\n")) == NULL
) {
133 DEBUG(10, ("strtok failed\n"));
137 if (sscanf(t
, "%u", &result_ct
.BeginTimestamp
) != 1) {
138 DEBUG(10, ("sscanf BeginTimestamp failed\n"));
142 if ((t
= strtok(NULL
, "\n")) == NULL
) {
143 DEBUG(10, ("strtok failed\n"));
147 if (sscanf(t
, "%u", &result_ct
.EndTimestamp
) != 1) {
148 DEBUG(10, ("sscanf EndTimestamp failed\n"));
152 if ((t
= strtok(NULL
, "\n")) == NULL
) {
153 DEBUG(10, ("strtok failed\n"));
157 blob
= base64_decode_data_blob(t
);
159 if (blob
.data
== NULL
) {
160 DEBUG(10, ("Could not get ticket\n"));
171 Put an AFS token into the Kernel so that it can authenticate against
172 the AFS server. This assumes correct local uid settings.
174 This is currently highly Linux and OpenAFS-specific. The correct API
175 call for this would be ktc_SetToken. But to do that we would have to
176 import a REALLY big bunch of libraries which I would currently like
180 static BOOL
afs_settoken(const char *cell
,
181 const struct ClearToken
*ctok
,
187 uint16 in_size
, out_size
;
194 memcpy(p
, &ticket
.length
, sizeof(uint32
));
196 memcpy(p
, ticket
.data
, ticket
.length
);
199 tmp
= sizeof(struct ClearToken
);
200 memcpy(p
, &tmp
, sizeof(uint32
));
202 memcpy(p
, ctok
, tmp
);
207 memcpy(p
, &tmp
, sizeof(uint32
));
211 if (tmp
>= MAXKTCREALMLEN
) {
212 DEBUG(1, ("Realm too long\n"));
216 strncpy(p
, cell
, tmp
);
222 iob
.in_size
= PTR_DIFF(p
,buf
);
224 iob
.out_size
= sizeof(buf
);
227 file_save("/tmp/ioctlbuf", iob
.in
, iob
.in_size
);
230 ret
= afs_syscall(AFSCALL_PIOCTL
, 0, VIOCSETTOK
, (char *)&iob
, 0);
232 DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret
));
236 BOOL
afs_settoken_str(const char *token_string
)
239 struct ClearToken ct
;
243 if (!afs_decode_token(token_string
, &cell
, &ticket
, &ct
))
247 ct
.ViceId
= getuid();
249 result
= afs_settoken(cell
, &ct
, ticket
);
252 data_blob_free(&ticket
);
257 /* Create a ClearToken and an encrypted ticket. ClearToken has not yet the
258 * ViceId set, this should be set by the caller. */
260 static BOOL
afs_createtoken(const char *username
, const char *cell
,
261 DATA_BLOB
*ticket
, struct ClearToken
*ct
)
263 fstring clear_ticket
;
264 char *p
= clear_ticket
;
269 des_key_schedule key_schedule
;
274 if (!secrets_fetch_afs_key(cell
, &key
)) {
275 DEBUG(1, ("Could not fetch AFS service key\n"));
279 ct
->AuthHandle
= key
.kvno
;
281 /* Build the ticket. This is going to be encrypted, so in our
282 way we fill in ct while we still have the unencrypted
291 /* "Alice", the client username */
292 strncpy(p
, username
, sizeof(clear_ticket
)-PTR_DIFF(p
,clear_ticket
)-1);
294 strncpy(p
, "", sizeof(clear_ticket
)-PTR_DIFF(p
,clear_ticket
)-1);
296 strncpy(p
, cell
, sizeof(clear_ticket
)-PTR_DIFF(p
,clear_ticket
)-1);
299 /* Alice's network layer address. At least Openafs-1.2.10
300 ignores this, so we fill in a dummy value here. */
304 /* We need to create a session key */
305 generate_random_buffer(p
, 8, False
);
307 /* Our client code needs the the key in the clear, it does not
308 know the server-key ... */
309 memcpy(ct
->HandShakeKey
, p
, 8);
313 /* Ticket lifetime. We fake everything here, so go as long as
314 possible. This is in 5-minute intervals, so 255 is 21 hours
319 /* Ticket creation time */
322 ct
->BeginTimestamp
= now
;
324 ct
->EndTimestamp
= now
+ (255*60*5);
325 if (((ct
->EndTimestamp
- ct
->BeginTimestamp
) & 1) == 1) {
326 ct
->BeginTimestamp
+= 1; /* Lifetime must be even */
330 /* And here comes Bob's name and instance, in this case the
332 strncpy(p
, "afs", sizeof(clear_ticket
)-PTR_DIFF(p
,clear_ticket
)-1);
334 strncpy(p
, "", sizeof(clear_ticket
)-PTR_DIFF(p
,clear_ticket
)-1);
337 /* And zero-pad to a multiple of 8 bytes */
338 len
= PTR_DIFF(p
, clear_ticket
);
340 uint32 extra_space
= 8-(len
& 7);
341 memset(p
, 0, extra_space
);
344 len
= PTR_DIFF(p
, clear_ticket
);
346 des_key_sched((const_des_cblock
*)key
.key
, key_schedule
);
347 des_pcbc_encrypt(clear_ticket
, clear_ticket
,
348 len
, key_schedule
, (C_Block
*)key
.key
, 1);
352 *ticket
= data_blob(clear_ticket
, len
);
357 char *afs_createtoken_str(const char *username
, const char *cell
)
360 struct ClearToken ct
;
363 if (!afs_createtoken(username
, cell
, &ticket
, &ct
))
366 result
= afs_encode_token(cell
, ticket
, &ct
);
368 data_blob_free(&ticket
);
374 This routine takes a radical approach completely bypassing the
375 Kerberos idea of security and using AFS simply as an intelligent
376 file backend. Samba has persuaded itself somehow that the user is
377 actually correctly identified and then we create a ticket that the
378 AFS server hopefully accepts using its KeyFile that the admin has
379 kindly stored to our secrets.tdb.
381 Thanks to the book "Network Security -- PRIVATE Communication in a
382 PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner
383 Kerberos 4 tickets are not really hard to construct.
385 For the comments "Alice" is the User to be auth'ed, and "Bob" is the
388 BOOL
afs_login(connection_struct
*conn
)
391 pstring afs_username
;
395 struct ClearToken ct
;
397 pstrcpy(afs_username
, lp_afs_username_map());
398 standard_sub_conn(conn
, afs_username
, sizeof(afs_username
));
400 /* The pts command always generates completely lower-case user
402 strlower_m(afs_username
);
404 cell
= strchr(afs_username
, '@');
407 DEBUG(1, ("AFS username doesn't contain a @, "
408 "could not find cell\n"));
415 DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
416 afs_username
, cell
));
418 if (!afs_createtoken(afs_username
, cell
, &ticket
, &ct
))
421 /* For which Unix-UID do we want to set the token? */
422 ct
.ViceId
= getuid();
425 char *str
, *new_cell
;
426 DATA_BLOB test_ticket
;
427 struct ClearToken test_ct
;
429 hex_encode(ct
.HandShakeKey
, sizeof(ct
.HandShakeKey
), &str
);
430 DEBUG(10, ("Key: %s\n", str
));
433 str
= afs_encode_token(cell
, ticket
, &ct
);
435 if (!afs_decode_token(str
, &new_cell
, &test_ticket
,
437 DEBUG(0, ("Could not decode token"));
441 if (strcmp(cell
, new_cell
) != 0) {
442 DEBUG(0, ("cell changed\n"));
445 if ((ticket
.length
!= test_ticket
.length
) ||
446 (memcmp(ticket
.data
, test_ticket
.data
,
447 ticket
.length
) != 0)) {
448 DEBUG(0, ("Ticket changed\n"));
451 if (memcmp(&ct
, &test_ct
, sizeof(ct
)) != 0) {
452 DEBUG(0, ("ClearToken changed\n"));
455 data_blob_free(&test_ticket
);
462 result
= afs_settoken(cell
, &ct
, ticket
);
464 data_blob_free(&ticket
);
471 BOOL
afs_login(connection_struct
*conn
)
476 BOOL
afs_settoken_str(const char *token_string
)
481 char *afs_createtoken_str(const char *username
, const char *cell
)
486 #endif /* WITH_FAKE_KASERVER */