r191: Only send the ntlm_auth 'ntlm-server-1' helper client a '.' after the
[Samba/gebeck_regimport.git] / source / lib / afs.c
blobce972ec27b77eea3cbe04ad5d27df26514d70788
1 /*
2 * Unix SMB/CIFS implementation.
3 * Generate AFS tickets
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.
21 #include "includes.h"
23 #ifdef WITH_FAKE_KASERVER
25 #include <afs/stds.h>
26 #include <afs/afs.h>
27 #include <afs/auth.h>
28 #include <afs/venus.h>
29 #include <asm/unistd.h>
30 #include <openssl/des.h>
32 _syscall5(int, afs_syscall, int, subcall,
33 char *, path,
34 int, cmd,
35 char *, cmarg,
36 int, follow);
38 struct ClearToken {
39 uint32 AuthHandle;
40 char HandShakeKey[8];
41 uint32 ViceId;
42 uint32 BeginTimestamp;
43 uint32 EndTimestamp;
46 static char *afs_encode_token(const char *cell, const DATA_BLOB ticket,
47 const struct ClearToken *ct)
49 char *base64_ticket;
50 char *result;
52 DATA_BLOB key = data_blob(ct->HandShakeKey, 8);
53 char *base64_key;
55 base64_ticket = base64_encode_data_blob(ticket);
56 if (base64_ticket == NULL)
57 return NULL;
59 base64_key = base64_encode_data_blob(key);
60 if (base64_key == NULL) {
61 free(base64_ticket);
62 return 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));
71 free(base64_ticket);
72 free(base64_key);
74 return result;
77 static BOOL afs_decode_token(const char *string, char **cell,
78 DATA_BLOB *ticket, struct ClearToken *ct)
80 DATA_BLOB blob;
81 struct ClearToken result_ct;
83 char *s = strdup(string);
85 char *t;
87 if ((t = strtok(s, "\n")) == NULL) {
88 DEBUG(10, ("strtok failed\n"));
89 return False;
92 *cell = strdup(t);
94 if ((t = strtok(NULL, "\n")) == NULL) {
95 DEBUG(10, ("strtok failed\n"));
96 return False;
99 if (sscanf(t, "%u", &result_ct.AuthHandle) != 1) {
100 DEBUG(10, ("sscanf AuthHandle failed\n"));
101 return False;
104 if ((t = strtok(NULL, "\n")) == NULL) {
105 DEBUG(10, ("strtok failed\n"));
106 return False;
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,
114 blob.length));
115 return False;
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"));
124 return False;
127 if (sscanf(t, "%u", &result_ct.ViceId) != 1) {
128 DEBUG(10, ("sscanf ViceId failed\n"));
129 return False;
132 if ((t = strtok(NULL, "\n")) == NULL) {
133 DEBUG(10, ("strtok failed\n"));
134 return False;
137 if (sscanf(t, "%u", &result_ct.BeginTimestamp) != 1) {
138 DEBUG(10, ("sscanf BeginTimestamp failed\n"));
139 return False;
142 if ((t = strtok(NULL, "\n")) == NULL) {
143 DEBUG(10, ("strtok failed\n"));
144 return False;
147 if (sscanf(t, "%u", &result_ct.EndTimestamp) != 1) {
148 DEBUG(10, ("sscanf EndTimestamp failed\n"));
149 return False;
152 if ((t = strtok(NULL, "\n")) == NULL) {
153 DEBUG(10, ("strtok failed\n"));
154 return False;
157 blob = base64_decode_data_blob(t);
159 if (blob.data == NULL) {
160 DEBUG(10, ("Could not get ticket\n"));
161 return False;
164 *ticket = blob;
165 *ct = result_ct;
167 return True;
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
177 to avoid.
180 static BOOL afs_settoken(const char *cell,
181 const struct ClearToken *ctok,
182 DATA_BLOB ticket)
184 int ret;
185 struct {
186 char *in, *out;
187 uint16 in_size, out_size;
188 } iob;
190 char buf[1024];
191 char *p = buf;
192 int tmp;
194 memcpy(p, &ticket.length, sizeof(uint32));
195 p += sizeof(uint32);
196 memcpy(p, ticket.data, ticket.length);
197 p += ticket.length;
199 tmp = sizeof(struct ClearToken);
200 memcpy(p, &tmp, sizeof(uint32));
201 p += sizeof(uint32);
202 memcpy(p, ctok, tmp);
203 p += tmp;
205 tmp = 0;
207 memcpy(p, &tmp, sizeof(uint32));
208 p += sizeof(uint32);
210 tmp = strlen(cell);
211 if (tmp >= MAXKTCREALMLEN) {
212 DEBUG(1, ("Realm too long\n"));
213 return False;
216 strncpy(p, cell, tmp);
217 p += tmp;
218 *p = 0;
219 p +=1;
221 iob.in = buf;
222 iob.in_size = PTR_DIFF(p,buf);
223 iob.out = buf;
224 iob.out_size = sizeof(buf);
226 #if 0
227 file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
228 #endif
230 ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
232 DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
233 return (ret == 0);
236 BOOL afs_settoken_str(const char *token_string)
238 DATA_BLOB ticket;
239 struct ClearToken ct;
240 BOOL result;
241 char *cell;
243 if (!afs_decode_token(token_string, &cell, &ticket, &ct))
244 return False;
246 if (geteuid() != 0)
247 ct.ViceId = getuid();
249 result = afs_settoken(cell, &ct, ticket);
251 SAFE_FREE(cell);
252 data_blob_free(&ticket);
254 return result;
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;
265 uint32 len;
266 uint32 now;
268 struct afs_key key;
269 des_key_schedule key_schedule;
271 if (!secrets_init())
272 return False;
274 if (!secrets_fetch_afs_key(cell, &key)) {
275 DEBUG(1, ("Could not fetch AFS service key\n"));
276 return False;
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
283 form. */
285 p = clear_ticket;
287 /* The byte-order */
288 *p = 1;
289 p += 1;
291 /* "Alice", the client username */
292 strncpy(p, username, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
293 p += strlen(p)+1;
294 strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
295 p += strlen(p)+1;
296 strncpy(p, cell, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
297 p += strlen(p)+1;
299 /* Alice's network layer address. At least Openafs-1.2.10
300 ignores this, so we fill in a dummy value here. */
301 SIVAL(p, 0, 0);
302 p += 4;
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);
311 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
315 and 15 minutes.*/
316 *p = 255;
317 p += 1;
319 /* Ticket creation time */
320 now = time(NULL);
321 SIVAL(p, 0, now);
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 */
328 p += 4;
330 /* And here comes Bob's name and instance, in this case the
331 AFS server. */
332 strncpy(p, "afs", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
333 p += strlen(p)+1;
334 strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
335 p += strlen(p)+1;
337 /* And zero-pad to a multiple of 8 bytes */
338 len = PTR_DIFF(p, clear_ticket);
339 if (len & 7) {
340 uint32 extra_space = 8-(len & 7);
341 memset(p, 0, extra_space);
342 p+=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);
350 ZERO_STRUCT(key);
352 *ticket = data_blob(clear_ticket, len);
354 return True;
357 char *afs_createtoken_str(const char *username, const char *cell)
359 DATA_BLOB ticket;
360 struct ClearToken ct;
361 char *result;
363 if (!afs_createtoken(username, cell, &ticket, &ct))
364 return NULL;
366 result = afs_encode_token(cell, ticket, &ct);
368 data_blob_free(&ticket);
370 return result;
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
386 AFS server. */
388 BOOL afs_login(connection_struct *conn)
390 DATA_BLOB ticket;
391 pstring afs_username;
392 char *cell;
393 BOOL result;
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
401 * names. */
402 strlower_m(afs_username);
404 cell = strchr(afs_username, '@');
406 if (cell == NULL) {
407 DEBUG(1, ("AFS username doesn't contain a @, "
408 "could not find cell\n"));
409 return False;
412 *cell = '\0';
413 cell += 1;
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))
419 return False;
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));
431 free(str);
433 str = afs_encode_token(cell, ticket, &ct);
435 if (!afs_decode_token(str, &new_cell, &test_ticket,
436 &test_ct)) {
437 DEBUG(0, ("Could not decode token"));
438 goto decode_failed;
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);
457 decode_failed:
458 SAFE_FREE(str);
459 SAFE_FREE(new_cell);
462 result = afs_settoken(cell, &ct, ticket);
464 data_blob_free(&ticket);
466 return result;
469 #else
471 BOOL afs_login(connection_struct *conn)
473 return True;
476 BOOL afs_settoken_str(const char *token_string)
478 return False;
481 char *afs_createtoken_str(const char *username, const char *cell)
483 return False;
486 #endif /* WITH_FAKE_KASERVER */