* sync more files from 3.0
[Samba.git] / source / lib / afs.c
blob882442a79f1ac114692351d2868fa0c0fa851e0e
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;
47 Put an AFS token into the Kernel so that it can authenticate against
48 the AFS server. This assumes correct local uid settings.
50 This is currently highly Linux and OpenAFS-specific. The correct API
51 call for this would be ktc_SetToken. But to do that we would have to
52 import a REALLY big bunch of libraries which I would currently like
53 to avoid.
56 static BOOL afs_settoken(const char *username, const char *cell,
57 const struct ClearToken *ctok,
58 char *v4tkt_data, int v4tkt_length)
60 int ret;
61 struct {
62 char *in, *out;
63 uint16 in_size, out_size;
64 } iob;
66 char buf[1024];
67 char *p = buf;
68 int tmp;
70 memcpy(p, &v4tkt_length, sizeof(uint32));
71 p += sizeof(uint32);
72 memcpy(p, v4tkt_data, v4tkt_length);
73 p += v4tkt_length;
75 tmp = sizeof(struct ClearToken);
76 memcpy(p, &tmp, sizeof(uint32));
77 p += sizeof(uint32);
78 memcpy(p, ctok, tmp);
79 p += tmp;
81 tmp = 0;
83 memcpy(p, &tmp, sizeof(uint32));
84 p += sizeof(uint32);
86 tmp = strlen(cell);
87 if (tmp >= MAXKTCREALMLEN) {
88 DEBUG(1, ("Realm too long\n"));
89 return False;
92 strncpy(p, cell, tmp);
93 p += tmp;
94 *p = 0;
95 p +=1;
97 iob.in = buf;
98 iob.in_size = PTR_DIFF(p,buf);
99 iob.out = buf;
100 iob.out_size = sizeof(buf);
102 #if 0
103 file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
104 #endif
106 ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
108 DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
109 return (ret == 0);
113 This routine takes a radical approach completely defeating the
114 Kerberos idea of security and using AFS simply as an intelligent
115 file backend. Samba has persuaded itself somehow that the user is
116 actually correctly identified and then we create a ticket that the
117 AFS server hopefully accepts using its KeyFile that the admin has
118 kindly stored to our secrets.tdb.
120 Thanks to the book "Network Security -- PRIVATE Communication in a
121 PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner
122 Kerberos 4 tickets are not really hard to construct.
124 For the comments "Alice" is the User to be auth'ed, and "Bob" is the
125 AFS server. */
127 BOOL afs_login(connection_struct *conn)
129 fstring ticket;
130 char *p = ticket;
131 uint32 len;
132 struct afs_key key;
133 pstring afs_username;
134 char *cell;
136 struct ClearToken ct;
138 uint32 now; /* I assume time() returns 32 bit */
140 des_key_schedule key_schedule;
142 pstrcpy(afs_username, lp_afs_username_map());
143 standard_sub_conn(conn, afs_username, sizeof(afs_username));
145 cell = strchr(afs_username, '@');
147 if (cell == NULL) {
148 DEBUG(1, ("AFS username doesn't contain a @, "
149 "could not find cell\n"));
150 return False;
153 *cell = '\0';
154 cell += 1;
155 strlower_m(cell);
157 DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
158 afs_username, cell));
160 if (!secrets_init())
161 return False;
163 if (!secrets_fetch_afs_key(cell, &key)) {
164 DEBUG(5, ("Could not fetch AFS service key\n"));
165 return False;
168 ct.AuthHandle = key.kvno;
170 /* Build the ticket. This is going to be encrypted, so in our
171 way we fill in ct while we still have the unencrypted
172 form. */
174 p = ticket;
176 /* The byte-order */
177 *p = 1;
178 p += 1;
180 /* "Alice", the client username */
181 strncpy(p, afs_username, sizeof(ticket)-PTR_DIFF(p,ticket)-1);
182 p += strlen(p)+1;
183 strncpy(p, "", sizeof(ticket)-PTR_DIFF(p,ticket)-1);
184 p += strlen(p)+1;
185 strncpy(p, cell, sizeof(ticket)-PTR_DIFF(p,ticket)-1);
186 p += strlen(p)+1;
188 /* As long as we still only use the effective UID we need to set the
189 * token for it here as well. This involves patching AFS in two
190 * places. Once we start using the real uid where we have the
191 * setresuid function, we can use getuid() here which would be more
192 * correct. */
194 ct.ViceId = geteuid();
195 DEBUG(10, ("Creating Token for uid %d\n", ct.ViceId));
197 /* Alice's network layer address. At least Openafs-1.2.10
198 ignores this, so we fill in a dummy value here. */
199 SIVAL(p, 0, 0);
200 p += 4;
202 /* We need to create a session key */
203 generate_random_buffer(p, 8, False);
205 /* Our client code needs the the key in the clear, it does not
206 know the server-key ... */
207 memcpy(ct.HandShakeKey, p, 8);
209 p += 8;
211 /* Ticket lifetime. We fake everything here, so go as long as
212 possible. This is in 5-minute intervals, so 255 is 21 hours
213 and 15 minutes.*/
214 *p = 255;
215 p += 1;
217 /* Ticket creation time */
218 now = time(NULL);
219 SIVAL(p, 0, now);
220 ct.BeginTimestamp = now;
222 ct.EndTimestamp = now + (255*60*5);
223 if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1) {
224 ct.BeginTimestamp += 1; /* Lifetime must be even */
226 p += 4;
228 /* And here comes Bob's name and instance, in this case the
229 AFS server. */
230 strncpy(p, "afs", sizeof(ticket)-PTR_DIFF(p,ticket)-1);
231 p += strlen(p)+1;
232 strncpy(p, "", sizeof(ticket)-PTR_DIFF(p,ticket)-1);
233 p += strlen(p)+1;
235 /* And zero-pad to a multiple of 8 bytes */
236 len = PTR_DIFF(p, ticket);
237 if (len & 7) {
238 uint32 extra_space = 8-(len & 7);
239 memset(p, 0, extra_space);
240 p+=extra_space;
242 len = PTR_DIFF(p, ticket);
244 des_key_sched((const_des_cblock *)key.key, key_schedule);
245 des_pcbc_encrypt(ticket, ticket,
246 len, key_schedule, (C_Block *)key.key, 1);
248 ZERO_STRUCT(key);
250 return afs_settoken(afs_username, cell, &ct, ticket, len);
253 #else
255 BOOL afs_login(connection_struct *conn)
257 return True;
260 #endif /* WITH_FAKE_KASERVER */