Line data Source code
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 3 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, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "lib/afs/afs_funcs.h"
22 :
23 : #ifdef WITH_FAKE_KASERVER
24 :
25 : #define NO_ASN1_TYPEDEFS 1
26 :
27 : #include "secrets.h"
28 : #include "passdb.h"
29 : #include "auth.h"
30 : #include "../librpc/gen_ndr/ndr_netlogon.h"
31 : #include "lib/afs/afs_settoken.h"
32 :
33 : #include <afs/param.h>
34 : #include <afs/stds.h>
35 : #include <afs/auth.h>
36 : #include <afs/venus.h>
37 : #include <asm/unistd.h>
38 : #include <openssl/des.h>
39 :
40 : struct ClearToken {
41 : uint32 AuthHandle;
42 : char HandShakeKey[8];
43 : uint32 ViceId;
44 : uint32 BeginTimestamp;
45 : uint32 EndTimestamp;
46 : };
47 :
48 : static char *afs_encode_token(const char *cell, const DATA_BLOB ticket,
49 : const struct ClearToken *ct)
50 : {
51 : char *base64_ticket;
52 : char *result = NULL;
53 :
54 : DATA_BLOB key = data_blob(ct->HandShakeKey, 8);
55 : char *base64_key;
56 : TALLOC_CTX *mem_ctx;
57 :
58 : mem_ctx = talloc_stackframe();
59 : if (mem_ctx == NULL)
60 : goto done;
61 :
62 : base64_ticket = base64_encode_data_blob(mem_ctx, ticket);
63 : if (base64_ticket == NULL)
64 : goto done;
65 :
66 : base64_key = base64_encode_data_blob(mem_ctx, key);
67 : if (base64_key == NULL)
68 : goto done;
69 :
70 : asprintf(&result, "%s\n%u\n%s\n%u\n%u\n%u\n%s\n", cell,
71 : ct->AuthHandle, base64_key, ct->ViceId, ct->BeginTimestamp,
72 : ct->EndTimestamp, base64_ticket);
73 :
74 : DEBUG(10, ("Got ticket string:\n%s\n", result));
75 :
76 : done:
77 : TALLOC_FREE(mem_ctx);
78 :
79 : return result;
80 : }
81 :
82 : /* Create a ClearToken and an encrypted ticket. ClearToken has not yet the
83 : * ViceId set, this should be set by the caller. */
84 :
85 : static bool afs_createtoken(const char *username, const char *cell,
86 : DATA_BLOB *ticket, struct ClearToken *ct)
87 : {
88 : fstring clear_ticket;
89 : char *p = clear_ticket;
90 : uint32 len;
91 : uint32 now;
92 :
93 : struct afs_key key;
94 : des_key_schedule key_schedule;
95 :
96 : if (!secrets_init())
97 : return false;
98 :
99 : if (!secrets_fetch_afs_key(cell, &key)) {
100 : DEBUG(1, ("Could not fetch AFS service key\n"));
101 : return false;
102 : }
103 :
104 : ct->AuthHandle = key.kvno;
105 :
106 : /* Build the ticket. This is going to be encrypted, so in our
107 : way we fill in ct while we still have the unencrypted
108 : form. */
109 :
110 : p = clear_ticket;
111 :
112 : /* The byte-order */
113 : *p = 1;
114 : p += 1;
115 :
116 : /* "Alice", the client username */
117 : strncpy(p, username, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
118 : p += strlen(p)+1;
119 : strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
120 : p += strlen(p)+1;
121 : strncpy(p, cell, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
122 : p += strlen(p)+1;
123 :
124 : /* Alice's network layer address. At least Openafs-1.2.10
125 : ignores this, so we fill in a dummy value here. */
126 : SIVAL(p, 0, 0);
127 : p += 4;
128 :
129 : /* We need to create a session key */
130 : generate_random_buffer((uint8_t *)p, 8);
131 :
132 : /* Our client code needs the the key in the clear, it does not
133 : know the server-key ... */
134 : memcpy(ct->HandShakeKey, p, 8);
135 :
136 : p += 8;
137 :
138 : /* This is a kerberos 4 life time. The life time is expressed
139 : * in units of 5 minute intervals up to 38400 seconds, after
140 : * that a table is used up to lifetime 0xBF. Values between
141 : * 0xC0 and 0xFF is undefined. 0xFF is defined to be the
142 : * infinite time that never expire.
143 : *
144 : * So here we cheat and use the infinite time */
145 : *p = 255;
146 : p += 1;
147 :
148 : /* Ticket creation time */
149 : now = time(NULL);
150 : SIVAL(p, 0, now);
151 : ct->BeginTimestamp = now;
152 :
153 : if(lp_afs_token_lifetime() == 0)
154 : ct->EndTimestamp = NEVERDATE;
155 : else
156 : ct->EndTimestamp = now + lp_afs_token_lifetime();
157 :
158 : if (((ct->EndTimestamp - ct->BeginTimestamp) & 1) == 1) {
159 : ct->BeginTimestamp += 1; /* Lifetime must be even */
160 : }
161 : p += 4;
162 :
163 : /* And here comes Bob's name and instance, in this case the
164 : AFS server. */
165 : strncpy(p, "afs", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
166 : p += strlen(p)+1;
167 : strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
168 : p += strlen(p)+1;
169 :
170 : /* And zero-pad to a multiple of 8 bytes */
171 : len = PTR_DIFF(p, clear_ticket);
172 : if (len & 7) {
173 : uint32 extra_space = 8-(len & 7);
174 : memset(p, 0, extra_space);
175 : p+=extra_space;
176 : }
177 : len = PTR_DIFF(p, clear_ticket);
178 :
179 : des_key_sched((const_des_cblock *)key.key, key_schedule);
180 : des_pcbc_encrypt((const unsigned char*) clear_ticket,
181 : (unsigned char*) clear_ticket,
182 : len, key_schedule, (C_Block *)key.key, 1);
183 :
184 : ZERO_STRUCT(key);
185 :
186 : *ticket = data_blob(clear_ticket, len);
187 :
188 : return true;
189 : }
190 :
191 : char *afs_createtoken_str(const char *username, const char *cell)
192 : {
193 : DATA_BLOB ticket;
194 : struct ClearToken ct;
195 : char *result;
196 :
197 : if (!afs_createtoken(username, cell, &ticket, &ct))
198 : return NULL;
199 :
200 : result = afs_encode_token(cell, ticket, &ct);
201 :
202 : data_blob_free(&ticket);
203 :
204 : return result;
205 : }
206 :
207 : /*
208 : This routine takes a radical approach completely bypassing the
209 : Kerberos idea of security and using AFS simply as an intelligent
210 : file backend. Samba has persuaded itself somehow that the user is
211 : actually correctly identified and then we create a ticket that the
212 : AFS server hopefully accepts using its KeyFile that the admin has
213 : kindly stored to our secrets.tdb.
214 :
215 : Thanks to the book "Network Security -- PRIVATE Communication in a
216 : PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner
217 : Kerberos 4 tickets are not really hard to construct.
218 :
219 : For the comments "Alice" is the User to be auth'ed, and "Bob" is the
220 : AFS server. */
221 :
222 : bool afs_login(connection_struct *conn)
223 : {
224 : const struct loadparm_substitution *lp_sub =
225 : loadparm_s3_global_substitution();
226 : DATA_BLOB ticket;
227 : char *afs_username = NULL;
228 : char *cell = NULL;
229 : bool result;
230 : char *ticket_str = NULL;
231 : const struct dom_sid *user_sid;
232 : TALLOC_CTX *ctx = talloc_tos();
233 : struct dom_sid_buf buf;
234 :
235 : struct ClearToken ct;
236 :
237 : afs_username = talloc_strdup(ctx,
238 : lp_afs_username_map());
239 : if (!afs_username) {
240 : return false;
241 : }
242 :
243 : afs_username = talloc_sub_advanced(ctx,
244 : lp_servicename(ctx, lp_sub, SNUM(conn)),
245 : conn->session_info->unix_info->unix_name,
246 : conn->connectpath,
247 : conn->session_info->unix_token->gid,
248 : conn->session_info->unix_info->sanitized_username,
249 : conn->session_info->info->domain_name,
250 : afs_username);
251 : if (!afs_username) {
252 : return false;
253 : }
254 :
255 : user_sid = &conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
256 : afs_username = talloc_string_sub(talloc_tos(),
257 : afs_username,
258 : "%s",
259 : dom_sid_str_buf(user_sid, &buf));
260 : if (!afs_username) {
261 : return false;
262 : }
263 :
264 : /* The pts command always generates completely lower-case user
265 : * names. */
266 : if (!strlower_m(afs_username)) {
267 : return false;
268 : }
269 :
270 : cell = strchr(afs_username, '@');
271 :
272 : if (cell == NULL) {
273 : DEBUG(1, ("AFS username doesn't contain a @, "
274 : "could not find cell\n"));
275 : return false;
276 : }
277 :
278 : *cell = '\0';
279 : cell += 1;
280 :
281 : DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
282 : afs_username, cell));
283 :
284 : if (!afs_createtoken(afs_username, cell, &ticket, &ct))
285 : return false;
286 :
287 : /* For which Unix-UID do we want to set the token? */
288 : ct.ViceId = getuid();
289 :
290 : ticket_str = afs_encode_token(cell, ticket, &ct);
291 :
292 : result = afs_settoken_str(ticket_str);
293 :
294 : SAFE_FREE(ticket_str);
295 :
296 : data_blob_free(&ticket);
297 :
298 : return result;
299 : }
300 :
301 : #else
302 :
303 0 : bool afs_login(connection_struct *conn)
304 : {
305 0 : return true;
306 : }
307 :
308 0 : char *afs_createtoken_str(const char *username, const char *cell)
309 : {
310 0 : return NULL;
311 : }
312 :
313 : #endif /* WITH_FAKE_KASERVER */
|