* sync more files from 3.0
[tprouty/samba.git] / source3 / lib / afs.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Generate AFS tickets
4  *  Copyright (C) Volker Lendecke 2003
5  *
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.
10  *  
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.
15  *  
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.
19  */
20
21 #include "includes.h"
22
23 #ifdef WITH_FAKE_KASERVER
24
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>
31
32 _syscall5(int, afs_syscall, int, subcall,
33           char *, path,
34           int, cmd,
35           char *, cmarg,
36           int, follow);
37
38 struct ClearToken {
39         uint32 AuthHandle;
40         char HandShakeKey[8];
41         uint32 ViceId;
42         uint32 BeginTimestamp;
43         uint32 EndTimestamp;
44 };
45
46 /*
47   Put an AFS token into the Kernel so that it can authenticate against
48   the AFS server. This assumes correct local uid settings.
49
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. 
54 */
55
56 static BOOL afs_settoken(const char *username, const char *cell,
57                          const struct ClearToken *ctok,
58                          char *v4tkt_data, int v4tkt_length)
59 {
60         int ret;
61         struct {
62                 char *in, *out;
63                 uint16 in_size, out_size;
64         } iob;
65
66         char buf[1024];
67         char *p = buf;
68         int tmp;
69
70         memcpy(p, &v4tkt_length, sizeof(uint32));
71         p += sizeof(uint32);
72         memcpy(p, v4tkt_data, v4tkt_length);
73         p += v4tkt_length;
74
75         tmp = sizeof(struct ClearToken);
76         memcpy(p, &tmp, sizeof(uint32));
77         p += sizeof(uint32);
78         memcpy(p, ctok, tmp);
79         p += tmp;
80
81         tmp = 0;
82
83         memcpy(p, &tmp, sizeof(uint32));
84         p += sizeof(uint32);
85
86         tmp = strlen(cell);
87         if (tmp >= MAXKTCREALMLEN) {
88                 DEBUG(1, ("Realm too long\n"));
89                 return False;
90         }
91
92         strncpy(p, cell, tmp);
93         p += tmp;
94         *p = 0;
95         p +=1;
96
97         iob.in = buf;
98         iob.in_size = PTR_DIFF(p,buf);
99         iob.out = buf;
100         iob.out_size = sizeof(buf);
101
102 #if 0
103         file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
104 #endif
105
106         ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
107
108         DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
109         return (ret == 0);
110 }
111
112 /*
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.
119
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.
123
124   For the comments "Alice" is the User to be auth'ed, and "Bob" is the
125   AFS server.  */
126
127 BOOL afs_login(connection_struct *conn)
128 {
129         fstring ticket;
130         char *p = ticket;
131         uint32 len;
132         struct afs_key key;
133         pstring afs_username;
134         char *cell;
135
136         struct ClearToken ct;
137
138         uint32 now;             /* I assume time() returns 32 bit */
139
140         des_key_schedule key_schedule;
141
142         pstrcpy(afs_username, lp_afs_username_map());
143         standard_sub_conn(conn, afs_username, sizeof(afs_username));
144
145         cell = strchr(afs_username, '@');
146
147         if (cell == NULL) {
148                 DEBUG(1, ("AFS username doesn't contain a @, "
149                           "could not find cell\n"));
150                 return False;
151         }
152
153         *cell = '\0';
154         cell += 1;
155         strlower_m(cell);
156
157         DEBUG(10, ("Trying to log into AFS for user %s@%s\n", 
158                    afs_username, cell));
159
160         if (!secrets_init()) 
161                 return False;
162
163         if (!secrets_fetch_afs_key(cell, &key)) {
164                 DEBUG(5, ("Could not fetch AFS service key\n"));
165                 return False;
166         }
167
168         ct.AuthHandle = key.kvno;
169
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. */
173
174         p = ticket;
175
176         /* The byte-order */
177         *p = 1;
178         p += 1;
179
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;
187
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. */
193
194         ct.ViceId = geteuid();
195         DEBUG(10, ("Creating Token for uid %d\n", ct.ViceId));
196
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;
201
202         /* We need to create a session key */
203         generate_random_buffer(p, 8, False);
204
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);
208
209         p += 8;
210
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;
216
217         /* Ticket creation time */
218         now = time(NULL);
219         SIVAL(p, 0, now);
220         ct.BeginTimestamp = now;
221
222         ct.EndTimestamp = now + (255*60*5);
223         if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1) {
224                 ct.BeginTimestamp += 1; /* Lifetime must be even */
225         }
226         p += 4;
227
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;
234
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;
241         }
242         len = PTR_DIFF(p, ticket);
243
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);
247
248         ZERO_STRUCT(key);
249
250         return afs_settoken(afs_username, cell, &ct, ticket, len);
251 }
252
253 #else
254
255 BOOL afs_login(connection_struct *conn)
256 {
257         return True;
258 }
259
260 #endif /* WITH_FAKE_KASERVER */