~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/lib/afs.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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