1/*
2 *  Unix SMB/CIFS implementation.
3 *  Generate AFS tickets
4 *  Copyright (C) Volker Lendecke 2004
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#include <sys/syscall.h>
32
33int afs_syscall( int subcall,
34	  char * path,
35	  int cmd,
36	  char * cmarg,
37	  int follow)
38{
39	return( syscall( SYS_afs_syscall, subcall, path, cmd, cmarg, follow));
40}
41
42struct ClearToken {
43	uint32 AuthHandle;
44	char HandShakeKey[8];
45	uint32 ViceId;
46	uint32 BeginTimestamp;
47	uint32 EndTimestamp;
48};
49
50static BOOL afs_decode_token(const char *string, char **cell,
51			     DATA_BLOB *ticket, struct ClearToken *ct)
52{
53	DATA_BLOB blob;
54	struct ClearToken result_ct;
55
56	char *s = SMB_STRDUP(string);
57
58	char *t;
59
60	if ((t = strtok(s, "\n")) == NULL) {
61		DEBUG(10, ("strtok failed\n"));
62		return False;
63	}
64
65	*cell = SMB_STRDUP(t);
66
67	if ((t = strtok(NULL, "\n")) == NULL) {
68		DEBUG(10, ("strtok failed\n"));
69		return False;
70	}
71
72	if (sscanf(t, "%u", &result_ct.AuthHandle) != 1) {
73		DEBUG(10, ("sscanf AuthHandle failed\n"));
74		return False;
75	}
76
77	if ((t = strtok(NULL, "\n")) == NULL) {
78		DEBUG(10, ("strtok failed\n"));
79		return False;
80	}
81
82	blob = base64_decode_data_blob(t);
83
84	if ( (blob.data == NULL) ||
85	     (blob.length != sizeof(result_ct.HandShakeKey) )) {
86		DEBUG(10, ("invalid key: %x/%d\n", (uint32)blob.data,
87			   blob.length));
88		return False;
89	}
90
91	memcpy(result_ct.HandShakeKey, blob.data, blob.length);
92
93	data_blob_free(&blob);
94
95	if ((t = strtok(NULL, "\n")) == NULL) {
96		DEBUG(10, ("strtok failed\n"));
97		return False;
98	}
99
100	if (sscanf(t, "%u", &result_ct.ViceId) != 1) {
101		DEBUG(10, ("sscanf ViceId failed\n"));
102		return False;
103	}
104
105	if ((t = strtok(NULL, "\n")) == NULL) {
106		DEBUG(10, ("strtok failed\n"));
107		return False;
108	}
109
110	if (sscanf(t, "%u", &result_ct.BeginTimestamp) != 1) {
111		DEBUG(10, ("sscanf BeginTimestamp failed\n"));
112		return False;
113	}
114
115	if ((t = strtok(NULL, "\n")) == NULL) {
116		DEBUG(10, ("strtok failed\n"));
117		return False;
118	}
119
120	if (sscanf(t, "%u", &result_ct.EndTimestamp) != 1) {
121		DEBUG(10, ("sscanf EndTimestamp failed\n"));
122		return False;
123	}
124
125	if ((t = strtok(NULL, "\n")) == NULL) {
126		DEBUG(10, ("strtok failed\n"));
127		return False;
128	}
129
130	blob = base64_decode_data_blob(t);
131
132	if (blob.data == NULL) {
133		DEBUG(10, ("Could not get ticket\n"));
134		return False;
135	}
136
137	*ticket = blob;
138	*ct = result_ct;
139
140	return True;
141}
142
143/*
144  Put an AFS token into the Kernel so that it can authenticate against
145  the AFS server. This assumes correct local uid settings.
146
147  This is currently highly Linux and OpenAFS-specific. The correct API
148  call for this would be ktc_SetToken. But to do that we would have to
149  import a REALLY big bunch of libraries which I would currently like
150  to avoid.
151*/
152
153static BOOL afs_settoken(const char *cell,
154			 const struct ClearToken *ctok,
155			 DATA_BLOB ticket)
156{
157	int ret;
158	struct {
159		char *in, *out;
160		uint16 in_size, out_size;
161	} iob;
162
163	char buf[1024];
164	char *p = buf;
165	int tmp;
166
167	memcpy(p, &ticket.length, sizeof(uint32));
168	p += sizeof(uint32);
169	memcpy(p, ticket.data, ticket.length);
170	p += ticket.length;
171
172	tmp = sizeof(struct ClearToken);
173	memcpy(p, &tmp, sizeof(uint32));
174	p += sizeof(uint32);
175	memcpy(p, ctok, tmp);
176	p += tmp;
177
178	tmp = 0;
179
180	memcpy(p, &tmp, sizeof(uint32));
181	p += sizeof(uint32);
182
183	tmp = strlen(cell);
184	if (tmp >= MAXKTCREALMLEN) {
185		DEBUG(1, ("Realm too long\n"));
186		return False;
187	}
188
189	strncpy(p, cell, tmp);
190	p += tmp;
191	*p = 0;
192	p +=1;
193
194	iob.in = buf;
195	iob.in_size = PTR_DIFF(p,buf);
196	iob.out = buf;
197	iob.out_size = sizeof(buf);
198
199#if 0
200	file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
201#endif
202
203	ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
204
205	DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
206	return (ret == 0);
207}
208
209BOOL afs_settoken_str(const char *token_string)
210{
211	DATA_BLOB ticket;
212	struct ClearToken ct;
213	BOOL result;
214	char *cell;
215
216	if (!afs_decode_token(token_string, &cell, &ticket, &ct))
217		return False;
218
219	if (geteuid() != 0)
220		ct.ViceId = getuid();
221
222	result = afs_settoken(cell, &ct, ticket);
223
224	SAFE_FREE(cell);
225	data_blob_free(&ticket);
226
227	return result;
228}
229
230#else
231
232BOOL afs_settoken_str(const char *token_string)
233{
234	return False;
235}
236
237#endif
238