Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/appl/ftp/ftpd/gssapi.c
34889 views
1
/*
2
* Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* 3. Neither the name of the Institute nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#ifdef FTP_SERVER
35
#include "ftpd_locl.h"
36
#else
37
#include "ftp_locl.h"
38
#endif
39
#include <gssapi/gssapi.h>
40
#include <gssapi/gssapi_krb5.h>
41
#include <krb5_err.h>
42
43
RCSID("$Id$");
44
45
int ftp_do_gss_bindings = 0;
46
int ftp_do_gss_delegate = 1;
47
48
struct gssapi_data {
49
gss_ctx_id_t context_hdl;
50
gss_name_t client_name;
51
gss_cred_id_t delegated_cred_handle;
52
void *mech_data;
53
};
54
55
static int
56
gss_init(void *app_data)
57
{
58
struct gssapi_data *d = app_data;
59
d->context_hdl = GSS_C_NO_CONTEXT;
60
d->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
61
#if defined(FTP_SERVER)
62
return 0;
63
#else
64
/* XXX Check the gss mechanism; with gss_indicate_mechs() ? */
65
#ifdef KRB5
66
return !use_kerberos;
67
#else
68
return 0;
69
#endif /* KRB5 */
70
#endif /* FTP_SERVER */
71
}
72
73
static int
74
gss_check_prot(void *app_data, int level)
75
{
76
if(level == prot_confidential)
77
return -1;
78
return 0;
79
}
80
81
static int
82
gss_decode(void *app_data, void *buf, int len, int level)
83
{
84
OM_uint32 maj_stat, min_stat;
85
gss_buffer_desc input, output;
86
gss_qop_t qop_state;
87
int conf_state;
88
struct gssapi_data *d = app_data;
89
size_t ret_len;
90
91
input.length = len;
92
input.value = buf;
93
maj_stat = gss_unwrap (&min_stat,
94
d->context_hdl,
95
&input,
96
&output,
97
&conf_state,
98
&qop_state);
99
if(GSS_ERROR(maj_stat))
100
return -1;
101
memmove(buf, output.value, output.length);
102
ret_len = output.length;
103
gss_release_buffer(&min_stat, &output);
104
return ret_len;
105
}
106
107
static int
108
gss_overhead(void *app_data, int level, int len)
109
{
110
return 100; /* dunno? */
111
}
112
113
114
static int
115
gss_encode(void *app_data, void *from, int length, int level, void **to)
116
{
117
OM_uint32 maj_stat, min_stat;
118
gss_buffer_desc input, output;
119
int conf_state;
120
struct gssapi_data *d = app_data;
121
122
input.length = length;
123
input.value = from;
124
maj_stat = gss_wrap (&min_stat,
125
d->context_hdl,
126
level == prot_private,
127
GSS_C_QOP_DEFAULT,
128
&input,
129
&conf_state,
130
&output);
131
*to = output.value;
132
return output.length;
133
}
134
135
static void
136
sockaddr_to_gss_address (struct sockaddr *sa,
137
OM_uint32 *addr_type,
138
gss_buffer_desc *gss_addr)
139
{
140
switch (sa->sa_family) {
141
#ifdef HAVE_IPV6
142
case AF_INET6 : {
143
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
144
145
gss_addr->length = 16;
146
gss_addr->value = &sin6->sin6_addr;
147
*addr_type = GSS_C_AF_INET6;
148
break;
149
}
150
#endif
151
case AF_INET : {
152
struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
153
154
gss_addr->length = 4;
155
gss_addr->value = &sin4->sin_addr;
156
*addr_type = GSS_C_AF_INET;
157
break;
158
}
159
default :
160
errx (1, "unknown address family %d", sa->sa_family);
161
162
}
163
}
164
165
/* end common stuff */
166
167
#ifdef FTP_SERVER
168
169
static int
170
gss_adat(void *app_data, void *buf, size_t len)
171
{
172
char *p = NULL;
173
gss_buffer_desc input_token, output_token;
174
OM_uint32 maj_stat, min_stat;
175
gss_name_t client_name;
176
struct gssapi_data *d = app_data;
177
gss_channel_bindings_t bindings;
178
179
if (ftp_do_gss_bindings) {
180
bindings = malloc(sizeof(*bindings));
181
if (bindings == NULL)
182
errx(1, "out of memory");
183
184
sockaddr_to_gss_address (his_addr,
185
&bindings->initiator_addrtype,
186
&bindings->initiator_address);
187
sockaddr_to_gss_address (ctrl_addr,
188
&bindings->acceptor_addrtype,
189
&bindings->acceptor_address);
190
191
bindings->application_data.length = 0;
192
bindings->application_data.value = NULL;
193
} else
194
bindings = GSS_C_NO_CHANNEL_BINDINGS;
195
196
input_token.value = buf;
197
input_token.length = len;
198
199
maj_stat = gss_accept_sec_context (&min_stat,
200
&d->context_hdl,
201
GSS_C_NO_CREDENTIAL,
202
&input_token,
203
bindings,
204
&client_name,
205
NULL,
206
&output_token,
207
NULL,
208
NULL,
209
&d->delegated_cred_handle);
210
211
if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
212
free(bindings);
213
214
if(output_token.length) {
215
if(base64_encode(output_token.value, output_token.length, &p) < 0) {
216
reply(535, "Out of memory base64-encoding.");
217
return -1;
218
}
219
gss_release_buffer(&min_stat, &output_token);
220
}
221
if(maj_stat == GSS_S_COMPLETE){
222
d->client_name = client_name;
223
client_name = GSS_C_NO_NAME;
224
if(p)
225
reply(235, "ADAT=%s", p);
226
else
227
reply(235, "ADAT Complete");
228
sec_complete = 1;
229
230
} else if(maj_stat == GSS_S_CONTINUE_NEEDED) {
231
if(p)
232
reply(335, "ADAT=%s", p);
233
else
234
reply(335, "OK, need more data");
235
} else {
236
OM_uint32 new_stat;
237
OM_uint32 msg_ctx = 0;
238
gss_buffer_desc status_string;
239
gss_display_status(&new_stat,
240
min_stat,
241
GSS_C_MECH_CODE,
242
GSS_C_NO_OID,
243
&msg_ctx,
244
&status_string);
245
syslog(LOG_ERR, "gss_accept_sec_context: %.*s",
246
(int)status_string.length,
247
(char*)status_string.value);
248
gss_release_buffer(&new_stat, &status_string);
249
reply(431, "Security resource unavailable");
250
}
251
252
if (client_name)
253
gss_release_name(&min_stat, &client_name);
254
free(p);
255
return 0;
256
}
257
258
int gssapi_userok(void*, char*);
259
int gssapi_session(void*, char*);
260
261
struct sec_server_mech gss_server_mech = {
262
"GSSAPI",
263
sizeof(struct gssapi_data),
264
gss_init, /* init */
265
NULL, /* end */
266
gss_check_prot,
267
gss_overhead,
268
gss_encode,
269
gss_decode,
270
/* */
271
NULL,
272
gss_adat,
273
NULL, /* pbsz */
274
NULL, /* ccc */
275
gssapi_userok,
276
gssapi_session
277
};
278
279
#else /* FTP_SERVER */
280
281
extern struct sockaddr *hisctladdr, *myctladdr;
282
283
static int
284
import_name(const char *kname, const char *host, gss_name_t *target_name)
285
{
286
OM_uint32 maj_stat, min_stat;
287
gss_buffer_desc name;
288
char *str;
289
290
name.length = asprintf(&str, "%s@%s", kname, host);
291
if (str == NULL) {
292
printf("Out of memory\n");
293
return AUTH_ERROR;
294
}
295
name.value = str;
296
297
maj_stat = gss_import_name(&min_stat,
298
&name,
299
GSS_C_NT_HOSTBASED_SERVICE,
300
target_name);
301
if (GSS_ERROR(maj_stat)) {
302
OM_uint32 new_stat;
303
OM_uint32 msg_ctx = 0;
304
gss_buffer_desc status_string;
305
306
gss_display_status(&new_stat,
307
min_stat,
308
GSS_C_MECH_CODE,
309
GSS_C_NO_OID,
310
&msg_ctx,
311
&status_string);
312
printf("Error importing name %.*s: %.*s\n",
313
(int)name.length,
314
(char *)name.value,
315
(int)status_string.length,
316
(char *)status_string.value);
317
free(name.value);
318
gss_release_buffer(&new_stat, &status_string);
319
return AUTH_ERROR;
320
}
321
free(name.value);
322
return 0;
323
}
324
325
static int
326
gss_auth(void *app_data, char *host)
327
{
328
329
OM_uint32 maj_stat, min_stat;
330
gss_name_t target_name;
331
gss_buffer_desc input, output_token;
332
int context_established = 0;
333
char *p;
334
int n;
335
gss_channel_bindings_t bindings;
336
struct gssapi_data *d = app_data;
337
OM_uint32 mech_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
338
339
const char *knames[] = { "ftp", "host", NULL }, **kname = knames;
340
341
342
if(import_name(*kname++, host, &target_name))
343
return AUTH_ERROR;
344
345
input.length = 0;
346
input.value = NULL;
347
348
if (ftp_do_gss_bindings) {
349
bindings = malloc(sizeof(*bindings));
350
if (bindings == NULL)
351
errx(1, "out of memory");
352
353
sockaddr_to_gss_address (myctladdr,
354
&bindings->initiator_addrtype,
355
&bindings->initiator_address);
356
sockaddr_to_gss_address (hisctladdr,
357
&bindings->acceptor_addrtype,
358
&bindings->acceptor_address);
359
360
bindings->application_data.length = 0;
361
bindings->application_data.value = NULL;
362
} else
363
bindings = GSS_C_NO_CHANNEL_BINDINGS;
364
365
if (ftp_do_gss_delegate)
366
mech_flags |= GSS_C_DELEG_FLAG;
367
368
while(!context_established) {
369
maj_stat = gss_init_sec_context(&min_stat,
370
GSS_C_NO_CREDENTIAL,
371
&d->context_hdl,
372
target_name,
373
GSS_C_NO_OID,
374
mech_flags,
375
0,
376
bindings,
377
&input,
378
NULL,
379
&output_token,
380
NULL,
381
NULL);
382
if (GSS_ERROR(maj_stat)) {
383
OM_uint32 new_stat;
384
OM_uint32 msg_ctx = 0;
385
gss_buffer_desc status_string;
386
387
d->context_hdl = GSS_C_NO_CONTEXT;
388
389
gss_release_name(&min_stat, &target_name);
390
391
if(*kname != NULL) {
392
393
if(import_name(*kname++, host, &target_name)) {
394
if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
395
free(bindings);
396
return AUTH_ERROR;
397
}
398
continue;
399
}
400
401
if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
402
free(bindings);
403
404
gss_display_status(&new_stat,
405
min_stat,
406
GSS_C_MECH_CODE,
407
GSS_C_NO_OID,
408
&msg_ctx,
409
&status_string);
410
printf("Error initializing security context: %.*s\n",
411
(int)status_string.length,
412
(char*)status_string.value);
413
gss_release_buffer(&new_stat, &status_string);
414
return AUTH_CONTINUE;
415
}
416
417
if (input.value) {
418
free(input.value);
419
input.value = NULL;
420
input.length = 0;
421
}
422
if (output_token.length != 0) {
423
base64_encode(output_token.value, output_token.length, &p);
424
gss_release_buffer(&min_stat, &output_token);
425
n = command("ADAT %s", p);
426
free(p);
427
}
428
if (GSS_ERROR(maj_stat)) {
429
if (d->context_hdl != GSS_C_NO_CONTEXT)
430
gss_delete_sec_context (&min_stat,
431
&d->context_hdl,
432
GSS_C_NO_BUFFER);
433
break;
434
}
435
if (maj_stat & GSS_S_CONTINUE_NEEDED) {
436
p = strstr(reply_string, "ADAT=");
437
if(p == NULL){
438
printf("Error: expected ADAT in reply. got: %s\n",
439
reply_string);
440
if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
441
free(bindings);
442
return AUTH_ERROR;
443
} else {
444
p+=5;
445
input.value = malloc(strlen(p));
446
input.length = base64_decode(p, input.value);
447
}
448
} else {
449
if(code != 235) {
450
printf("Unrecognized response code: %d\n", code);
451
if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
452
free(bindings);
453
return AUTH_ERROR;
454
}
455
context_established = 1;
456
}
457
}
458
459
gss_release_name(&min_stat, &target_name);
460
461
if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
462
free(bindings);
463
if (input.value)
464
free(input.value);
465
466
{
467
gss_name_t targ_name;
468
469
maj_stat = gss_inquire_context(&min_stat,
470
d->context_hdl,
471
NULL,
472
&targ_name,
473
NULL,
474
NULL,
475
NULL,
476
NULL,
477
NULL);
478
if (GSS_ERROR(maj_stat) == 0) {
479
gss_buffer_desc name;
480
maj_stat = gss_display_name (&min_stat,
481
targ_name,
482
&name,
483
NULL);
484
if (GSS_ERROR(maj_stat) == 0) {
485
printf("Authenticated to <%.*s>\n",
486
(int)name.length,
487
(char *)name.value);
488
gss_release_buffer(&min_stat, &name);
489
}
490
gss_release_name(&min_stat, &targ_name);
491
} else
492
printf("Failed to get gss name of peer.\n");
493
}
494
495
496
return AUTH_OK;
497
}
498
499
struct sec_client_mech gss_client_mech = {
500
"GSSAPI",
501
sizeof(struct gssapi_data),
502
gss_init,
503
gss_auth,
504
NULL, /* end */
505
gss_check_prot,
506
gss_overhead,
507
gss_encode,
508
gss_decode,
509
};
510
511
#endif /* FTP_SERVER */
512
513