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
38struct 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
56static 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
127BOOL 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	/* The pts command always generates completely lower-case user
146	 * names. */
147	strlower_m(afs_username);
148
149	cell = strchr(afs_username, '@');
150
151	if (cell == NULL) {
152		DEBUG(1, ("AFS username doesn't contain a @, "
153			  "could not find cell\n"));
154		return False;
155	}
156
157	*cell = '\0';
158	cell += 1;
159
160	DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
161		   afs_username, cell));
162
163	if (!secrets_init())
164		return False;
165
166	if (!secrets_fetch_afs_key(cell, &key)) {
167		DEBUG(5, ("Could not fetch AFS service key\n"));
168		return False;
169	}
170
171	ct.AuthHandle = key.kvno;
172
173	/* Build the ticket. This is going to be encrypted, so in our
174           way we fill in ct while we still have the unencrypted
175           form. */
176
177	p = ticket;
178
179	/* The byte-order */
180	*p = 1;
181	p += 1;
182
183	/* "Alice", the client username */
184	strncpy(p, afs_username, sizeof(ticket)-PTR_DIFF(p,ticket)-1);
185	p += strlen(p)+1;
186	strncpy(p, "", sizeof(ticket)-PTR_DIFF(p,ticket)-1);
187	p += strlen(p)+1;
188	strncpy(p, cell, sizeof(ticket)-PTR_DIFF(p,ticket)-1);
189	p += strlen(p)+1;
190
191	/* This assumes that we have setresuid and set the real uid as well as
192	   the effective uid in set_effective_uid(). */
193	ct.ViceId = getuid();
194	DEBUG(10, ("Creating Token for uid %d\n", ct.ViceId));
195
196	/* Alice's network layer address. At least Openafs-1.2.10
197           ignores this, so we fill in a dummy value here. */
198	SIVAL(p, 0, 0);
199	p += 4;
200
201	/* We need to create a session key */
202	generate_random_buffer(p, 8, False);
203
204	/* Our client code needs the the key in the clear, it does not
205           know the server-key ... */
206	memcpy(ct.HandShakeKey, p, 8);
207
208	p += 8;
209
210	/* Ticket lifetime. We fake everything here, so go as long as
211	   possible. This is in 5-minute intervals, so 255 is 21 hours
212	   and 15 minutes.*/
213	*p = 255;
214	p += 1;
215
216	/* Ticket creation time */
217	now = time(NULL);
218	SIVAL(p, 0, now);
219	ct.BeginTimestamp = now;
220
221	ct.EndTimestamp = now + (255*60*5);
222	if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1) {
223		ct.BeginTimestamp += 1; /* Lifetime must be even */
224	}
225	p += 4;
226
227	/* And here comes Bob's name and instance, in this case the
228           AFS server. */
229	strncpy(p, "afs", sizeof(ticket)-PTR_DIFF(p,ticket)-1);
230	p += strlen(p)+1;
231	strncpy(p, "", sizeof(ticket)-PTR_DIFF(p,ticket)-1);
232	p += strlen(p)+1;
233
234	/* And zero-pad to a multiple of 8 bytes */
235	len = PTR_DIFF(p, ticket);
236	if (len & 7) {
237		uint32 extra_space = 8-(len & 7);
238		memset(p, 0, extra_space);
239		p+=extra_space;
240	}
241	len = PTR_DIFF(p, ticket);
242
243	des_key_sched((const_des_cblock *)key.key, key_schedule);
244	des_pcbc_encrypt(ticket, ticket,
245			 len, key_schedule, (C_Block *)key.key, 1);
246
247	ZERO_STRUCT(key);
248
249	return afs_settoken(afs_username, cell, &ct, ticket, len);
250}
251
252#else
253
254BOOL afs_login(connection_struct *conn)
255{
256	return True;
257}
258
259#endif /* WITH_FAKE_KASERVER */
260