Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/appl/gssmask/gssmask.c
34889 views
1
/*
2
* Copyright (c) 2006 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 KTH nor the names of its contributors may be
18
* used to endorse or promote products derived from this software without
19
* specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
*/
33
34
#include "common.h"
35
RCSID("$Id$");
36
37
/*
38
*
39
*/
40
41
enum handle_type { handle_context, handle_cred };
42
43
struct handle {
44
int32_t idx;
45
enum handle_type type;
46
void *ptr;
47
struct handle *next;
48
};
49
50
struct client {
51
krb5_storage *sock;
52
krb5_storage *logging;
53
char *moniker;
54
int32_t nHandle;
55
struct handle *handles;
56
struct sockaddr_storage sa;
57
socklen_t salen;
58
char servername[MAXHOSTNAMELEN];
59
};
60
61
FILE *logfile;
62
static char *targetname;
63
krb5_context context;
64
65
/*
66
*
67
*/
68
69
static void
70
logmessage(struct client *c, const char *file, unsigned int lineno,
71
int level, const char *fmt, ...)
72
{
73
char *message;
74
va_list ap;
75
int32_t ackid;
76
77
va_start(ap, fmt);
78
vasprintf(&message, fmt, ap);
79
va_end(ap);
80
81
if (logfile)
82
fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);
83
84
if (c->logging) {
85
if (krb5_store_int32(c->logging, eLogInfo) != 0)
86
errx(1, "krb5_store_int32: log level");
87
if (krb5_store_string(c->logging, file) != 0)
88
errx(1, "krb5_store_string: filename");
89
if (krb5_store_int32(c->logging, lineno) != 0)
90
errx(1, "krb5_store_string: filename");
91
if (krb5_store_string(c->logging, message) != 0)
92
errx(1, "krb5_store_string: message");
93
if (krb5_ret_int32(c->logging, &ackid) != 0)
94
errx(1, "krb5_ret_int32: ackid");
95
}
96
free(message);
97
}
98
99
/*
100
*
101
*/
102
103
static int32_t
104
add_handle(struct client *c, enum handle_type type, void *data)
105
{
106
struct handle *h;
107
108
h = ecalloc(1, sizeof(*h));
109
110
h->idx = ++c->nHandle;
111
h->type = type;
112
h->ptr = data;
113
h->next = c->handles;
114
c->handles = h;
115
116
return h->idx;
117
}
118
119
static void
120
del_handle(struct handle **h, int32_t idx)
121
{
122
OM_uint32 min_stat;
123
124
if (idx == 0)
125
return;
126
127
while (*h) {
128
if ((*h)->idx == idx) {
129
struct handle *p = *h;
130
*h = (*h)->next;
131
switch(p->type) {
132
case handle_context: {
133
gss_ctx_id_t c = p->ptr;
134
gss_delete_sec_context(&min_stat, &c, NULL);
135
break; }
136
case handle_cred: {
137
gss_cred_id_t c = p->ptr;
138
gss_release_cred(&min_stat, &c);
139
break; }
140
}
141
free(p);
142
return;
143
}
144
h = &((*h)->next);
145
}
146
errx(1, "tried to delete an unexisting handle");
147
}
148
149
static void *
150
find_handle(struct handle *h, int32_t idx, enum handle_type type)
151
{
152
if (idx == 0)
153
return NULL;
154
155
while (h) {
156
if (h->idx == idx) {
157
if (type == h->type)
158
return h->ptr;
159
errx(1, "monger switched type on handle!");
160
}
161
h = h->next;
162
}
163
return NULL;
164
}
165
166
167
static int32_t
168
convert_gss_to_gsm(OM_uint32 maj_stat)
169
{
170
switch(maj_stat) {
171
case 0:
172
return GSMERR_OK;
173
case GSS_S_CONTINUE_NEEDED:
174
return GSMERR_CONTINUE_NEEDED;
175
case GSS_S_DEFECTIVE_TOKEN:
176
return GSMERR_INVALID_TOKEN;
177
case GSS_S_BAD_MIC:
178
return GSMERR_AP_MODIFIED;
179
default:
180
return GSMERR_ERROR;
181
}
182
}
183
184
static int32_t
185
convert_krb5_to_gsm(krb5_error_code ret)
186
{
187
switch(ret) {
188
case 0:
189
return GSMERR_OK;
190
default:
191
return GSMERR_ERROR;
192
}
193
}
194
195
/*
196
*
197
*/
198
199
static int32_t
200
acquire_cred(struct client *c,
201
krb5_principal principal,
202
krb5_get_init_creds_opt *opt,
203
int32_t *handle)
204
{
205
krb5_error_code ret;
206
krb5_creds cred;
207
krb5_ccache id;
208
gss_cred_id_t gcred;
209
OM_uint32 maj_stat, min_stat;
210
211
*handle = 0;
212
213
krb5_get_init_creds_opt_set_forwardable (opt, 1);
214
krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30);
215
216
memset(&cred, 0, sizeof(cred));
217
218
ret = krb5_get_init_creds_password (context,
219
&cred,
220
principal,
221
NULL,
222
NULL,
223
NULL,
224
0,
225
NULL,
226
opt);
227
if (ret) {
228
logmessage(c, __FILE__, __LINE__, 0,
229
"krb5_get_init_creds failed: %d", ret);
230
return convert_krb5_to_gsm(ret);
231
}
232
233
ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
234
if (ret)
235
krb5_err (context, 1, ret, "krb5_cc_initialize");
236
237
ret = krb5_cc_initialize (context, id, cred.client);
238
if (ret)
239
krb5_err (context, 1, ret, "krb5_cc_initialize");
240
241
ret = krb5_cc_store_cred (context, id, &cred);
242
if (ret)
243
krb5_err (context, 1, ret, "krb5_cc_store_cred");
244
245
krb5_free_cred_contents (context, &cred);
246
247
maj_stat = gss_krb5_import_cred(&min_stat,
248
id,
249
NULL,
250
NULL,
251
&gcred);
252
krb5_cc_close(context, id);
253
if (maj_stat) {
254
logmessage(c, __FILE__, __LINE__, 0,
255
"krb5 import creds failed with: %d", maj_stat);
256
return convert_gss_to_gsm(maj_stat);
257
}
258
259
*handle = add_handle(c, handle_cred, gcred);
260
261
return 0;
262
}
263
264
265
/*
266
*
267
*/
268
269
#define HandleOP(h) \
270
handle##h(enum gssMaggotOp op, struct client *c)
271
272
/*
273
*
274
*/
275
276
static int
277
HandleOP(GetVersionInfo)
278
{
279
put32(c, GSSMAGGOTPROTOCOL);
280
errx(1, "GetVersionInfo");
281
}
282
283
static int
284
HandleOP(GoodBye)
285
{
286
struct handle *h = c->handles;
287
unsigned int i = 0;
288
289
while (h) {
290
h = h->next;
291
i++;
292
}
293
294
if (i)
295
logmessage(c, __FILE__, __LINE__, 0,
296
"Did not toast all resources: %d", i);
297
return 1;
298
}
299
300
static int
301
HandleOP(InitContext)
302
{
303
OM_uint32 maj_stat, min_stat, ret_flags;
304
int32_t hContext, hCred, flags;
305
krb5_data target_name, in_token;
306
int32_t new_context_id = 0, gsm_error = 0;
307
krb5_data out_token = { 0 , NULL };
308
309
gss_ctx_id_t ctx;
310
gss_cred_id_t creds;
311
gss_name_t gss_target_name;
312
gss_buffer_desc input_token, output_token;
313
gss_OID oid = GSS_C_NO_OID;
314
gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
315
316
ret32(c, hContext);
317
ret32(c, hCred);
318
ret32(c, flags);
319
retdata(c, target_name);
320
retdata(c, in_token);
321
322
logmessage(c, __FILE__, __LINE__, 0,
323
"targetname: <%.*s>", (int)target_name.length,
324
(char *)target_name.data);
325
326
ctx = find_handle(c->handles, hContext, handle_context);
327
if (ctx == NULL)
328
hContext = 0;
329
creds = find_handle(c->handles, hCred, handle_cred);
330
if (creds == NULL)
331
abort();
332
333
input_token.length = target_name.length;
334
input_token.value = target_name.data;
335
336
maj_stat = gss_import_name(&min_stat,
337
&input_token,
338
GSS_KRB5_NT_PRINCIPAL_NAME,
339
&gss_target_name);
340
if (GSS_ERROR(maj_stat)) {
341
logmessage(c, __FILE__, __LINE__, 0,
342
"import name creds failed with: %d", maj_stat);
343
gsm_error = convert_gss_to_gsm(maj_stat);
344
goto out;
345
}
346
347
/* oid from flags */
348
349
if (in_token.length) {
350
input_token.length = in_token.length;
351
input_token.value = in_token.data;
352
input_token_ptr = &input_token;
353
if (ctx == NULL)
354
krb5_errx(context, 1, "initcreds, context NULL, but not first req");
355
} else {
356
input_token.length = 0;
357
input_token.value = NULL;
358
if (ctx)
359
krb5_errx(context, 1, "initcreds, context not NULL, but first req");
360
}
361
362
if ((flags & GSS_C_DELEG_FLAG) != 0)
363
logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating");
364
if ((flags & GSS_C_DCE_STYLE) != 0)
365
logmessage(c, __FILE__, __LINE__, 0, "init_sec_context dce-style");
366
367
maj_stat = gss_init_sec_context(&min_stat,
368
creds,
369
&ctx,
370
gss_target_name,
371
oid,
372
flags & 0x7f,
373
0,
374
NULL,
375
input_token_ptr,
376
NULL,
377
&output_token,
378
&ret_flags,
379
NULL);
380
if (GSS_ERROR(maj_stat)) {
381
if (hContext != 0)
382
del_handle(&c->handles, hContext);
383
new_context_id = 0;
384
logmessage(c, __FILE__, __LINE__, 0,
385
"gss_init_sec_context returns code: %d/%d",
386
maj_stat, min_stat);
387
} else {
388
if (input_token.length == 0)
389
new_context_id = add_handle(c, handle_context, ctx);
390
else
391
new_context_id = hContext;
392
}
393
394
gsm_error = convert_gss_to_gsm(maj_stat);
395
396
if (output_token.length) {
397
out_token.data = output_token.value;
398
out_token.length = output_token.length;
399
}
400
401
out:
402
logmessage(c, __FILE__, __LINE__, 0,
403
"InitContext return code: %d", gsm_error);
404
405
put32(c, new_context_id);
406
put32(c, gsm_error);
407
putdata(c, out_token);
408
409
gss_release_name(&min_stat, &gss_target_name);
410
if (output_token.length)
411
gss_release_buffer(&min_stat, &output_token);
412
krb5_data_free(&in_token);
413
krb5_data_free(&target_name);
414
415
return 0;
416
}
417
418
static int
419
HandleOP(AcceptContext)
420
{
421
OM_uint32 maj_stat, min_stat, ret_flags;
422
int32_t hContext, deleg_hcred, flags;
423
krb5_data in_token;
424
int32_t new_context_id = 0, gsm_error = 0;
425
krb5_data out_token = { 0 , NULL };
426
427
gss_ctx_id_t ctx;
428
gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
429
gss_buffer_desc input_token, output_token;
430
gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
431
432
ret32(c, hContext);
433
ret32(c, flags);
434
retdata(c, in_token);
435
436
ctx = find_handle(c->handles, hContext, handle_context);
437
if (ctx == NULL)
438
hContext = 0;
439
440
if (in_token.length) {
441
input_token.length = in_token.length;
442
input_token.value = in_token.data;
443
input_token_ptr = &input_token;
444
} else {
445
input_token.length = 0;
446
input_token.value = NULL;
447
}
448
449
maj_stat = gss_accept_sec_context(&min_stat,
450
&ctx,
451
GSS_C_NO_CREDENTIAL,
452
&input_token,
453
GSS_C_NO_CHANNEL_BINDINGS,
454
NULL,
455
NULL,
456
&output_token,
457
&ret_flags,
458
NULL,
459
&deleg_cred);
460
if (GSS_ERROR(maj_stat)) {
461
if (hContext != 0)
462
del_handle(&c->handles, hContext);
463
logmessage(c, __FILE__, __LINE__, 0,
464
"gss_accept_sec_context returns code: %d/%d",
465
maj_stat, min_stat);
466
new_context_id = 0;
467
} else {
468
if (hContext == 0)
469
new_context_id = add_handle(c, handle_context, ctx);
470
else
471
new_context_id = hContext;
472
}
473
if (output_token.length) {
474
out_token.data = output_token.value;
475
out_token.length = output_token.length;
476
}
477
if ((ret_flags & GSS_C_DCE_STYLE) != 0)
478
logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style");
479
if ((ret_flags & GSS_C_DELEG_FLAG) != 0) {
480
deleg_hcred = add_handle(c, handle_cred, deleg_cred);
481
logmessage(c, __FILE__, __LINE__, 0,
482
"accept_context delegated handle: %d", deleg_hcred);
483
} else {
484
gss_release_cred(&min_stat, &deleg_cred);
485
deleg_hcred = 0;
486
}
487
488
489
gsm_error = convert_gss_to_gsm(maj_stat);
490
491
put32(c, new_context_id);
492
put32(c, gsm_error);
493
putdata(c, out_token);
494
put32(c, deleg_hcred);
495
496
if (output_token.length)
497
gss_release_buffer(&min_stat, &output_token);
498
krb5_data_free(&in_token);
499
500
return 0;
501
}
502
503
static int
504
HandleOP(ToastResource)
505
{
506
int32_t handle;
507
508
ret32(c, handle);
509
logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);
510
del_handle(&c->handles, handle);
511
put32(c, GSMERR_OK);
512
513
return 0;
514
}
515
516
static int
517
HandleOP(AcquireCreds)
518
{
519
char *name, *password;
520
int32_t gsm_error, flags, handle = 0;
521
krb5_principal principal = NULL;
522
krb5_get_init_creds_opt *opt = NULL;
523
krb5_error_code ret;
524
525
retstring(c, name);
526
retstring(c, password);
527
ret32(c, flags);
528
529
logmessage(c, __FILE__, __LINE__, 0,
530
"username: %s password: %s", name, password);
531
532
ret = krb5_parse_name(context, name, &principal);
533
if (ret) {
534
gsm_error = convert_krb5_to_gsm(ret);
535
goto out;
536
}
537
538
ret = krb5_get_init_creds_opt_alloc (context, &opt);
539
if (ret)
540
krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
541
542
krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL);
543
544
gsm_error = acquire_cred(c, principal, opt, &handle);
545
546
out:
547
logmessage(c, __FILE__, __LINE__, 0,
548
"AcquireCreds handle: %d return code: %d", handle, gsm_error);
549
550
if (opt)
551
krb5_get_init_creds_opt_free (context, opt);
552
if (principal)
553
krb5_free_principal(context, principal);
554
free(name);
555
free(password);
556
557
put32(c, gsm_error);
558
put32(c, handle);
559
560
return 0;
561
}
562
563
static int
564
HandleOP(Sign)
565
{
566
OM_uint32 maj_stat, min_stat;
567
int32_t hContext, flags, seqno;
568
krb5_data token;
569
gss_ctx_id_t ctx;
570
gss_buffer_desc input_token, output_token;
571
572
ret32(c, hContext);
573
ret32(c, flags);
574
ret32(c, seqno);
575
retdata(c, token);
576
577
ctx = find_handle(c->handles, hContext, handle_context);
578
if (ctx == NULL)
579
errx(1, "sign: reference to unknown context");
580
581
input_token.length = token.length;
582
input_token.value = token.data;
583
584
maj_stat = gss_get_mic(&min_stat, ctx, 0, &input_token,
585
&output_token);
586
if (maj_stat != GSS_S_COMPLETE)
587
errx(1, "gss_get_mic failed");
588
589
krb5_data_free(&token);
590
591
token.data = output_token.value;
592
token.length = output_token.length;
593
594
put32(c, 0); /* XXX fix gsm_error */
595
putdata(c, token);
596
597
gss_release_buffer(&min_stat, &output_token);
598
599
return 0;
600
}
601
602
static int
603
HandleOP(Verify)
604
{
605
OM_uint32 maj_stat, min_stat;
606
int32_t hContext, flags, seqno;
607
krb5_data msg, mic;
608
gss_ctx_id_t ctx;
609
gss_buffer_desc msg_token, mic_token;
610
gss_qop_t qop;
611
612
ret32(c, hContext);
613
614
ctx = find_handle(c->handles, hContext, handle_context);
615
if (ctx == NULL)
616
errx(1, "verify: reference to unknown context");
617
618
ret32(c, flags);
619
ret32(c, seqno);
620
retdata(c, msg);
621
622
msg_token.length = msg.length;
623
msg_token.value = msg.data;
624
625
retdata(c, mic);
626
627
mic_token.length = mic.length;
628
mic_token.value = mic.data;
629
630
maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,
631
&mic_token, &qop);
632
if (maj_stat != GSS_S_COMPLETE)
633
errx(1, "gss_verify_mic failed");
634
635
krb5_data_free(&mic);
636
krb5_data_free(&msg);
637
638
put32(c, 0); /* XXX fix gsm_error */
639
640
return 0;
641
}
642
643
static int
644
HandleOP(GetVersionAndCapabilities)
645
{
646
int32_t cap = HAS_MONIKER;
647
char name[256] = "unknown", *str;
648
649
if (targetname)
650
cap |= ISSERVER; /* is server */
651
652
#ifdef HAVE_UNAME
653
{
654
struct utsname ut;
655
if (uname(&ut) == 0) {
656
snprintf(name, sizeof(name), "%s-%s-%s",
657
ut.sysname, ut.version, ut.machine);
658
}
659
}
660
#endif
661
662
asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);
663
664
put32(c, GSSMAGGOTPROTOCOL);
665
put32(c, cap);
666
putstring(c, str);
667
free(str);
668
669
return 0;
670
}
671
672
static int
673
HandleOP(GetTargetName)
674
{
675
if (targetname)
676
putstring(c, targetname);
677
else
678
putstring(c, "");
679
return 0;
680
}
681
682
static int
683
HandleOP(SetLoggingSocket)
684
{
685
int32_t portnum;
686
int fd, ret;
687
688
ret32(c, portnum);
689
690
logmessage(c, __FILE__, __LINE__, 0,
691
"logging port on peer is: %d", (int)portnum);
692
693
socket_set_port((struct sockaddr *)(&c->sa), htons(portnum));
694
695
fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0);
696
if (fd < 0)
697
return 0;
698
699
ret = connect(fd, (struct sockaddr *)&c->sa, c->salen);
700
if (ret < 0) {
701
logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s",
702
strerror(errno));
703
close(fd);
704
return 0;
705
}
706
707
if (c->logging)
708
krb5_storage_free(c->logging);
709
c->logging = krb5_storage_from_fd(fd);
710
close(fd);
711
712
krb5_store_int32(c->logging, eLogSetMoniker);
713
store_string(c->logging, c->moniker);
714
715
logmessage(c, __FILE__, __LINE__, 0, "logging turned on");
716
717
return 0;
718
}
719
720
721
static int
722
HandleOP(ChangePassword)
723
{
724
errx(1, "ChangePassword");
725
}
726
727
static int
728
HandleOP(SetPasswordSelf)
729
{
730
errx(1, "SetPasswordSelf");
731
}
732
733
static int
734
HandleOP(Wrap)
735
{
736
OM_uint32 maj_stat, min_stat;
737
int32_t hContext, flags, seqno;
738
krb5_data token;
739
gss_ctx_id_t ctx;
740
gss_buffer_desc input_token, output_token;
741
int conf_state;
742
743
ret32(c, hContext);
744
ret32(c, flags);
745
ret32(c, seqno);
746
retdata(c, token);
747
748
ctx = find_handle(c->handles, hContext, handle_context);
749
if (ctx == NULL)
750
errx(1, "wrap: reference to unknown context");
751
752
input_token.length = token.length;
753
input_token.value = token.data;
754
755
maj_stat = gss_wrap(&min_stat, ctx, flags, 0, &input_token,
756
&conf_state, &output_token);
757
if (maj_stat != GSS_S_COMPLETE)
758
errx(1, "gss_wrap failed");
759
760
krb5_data_free(&token);
761
762
token.data = output_token.value;
763
token.length = output_token.length;
764
765
put32(c, 0); /* XXX fix gsm_error */
766
putdata(c, token);
767
768
gss_release_buffer(&min_stat, &output_token);
769
770
return 0;
771
}
772
773
774
static int
775
HandleOP(Unwrap)
776
{
777
OM_uint32 maj_stat, min_stat;
778
int32_t hContext, flags, seqno;
779
krb5_data token;
780
gss_ctx_id_t ctx;
781
gss_buffer_desc input_token, output_token;
782
int conf_state;
783
gss_qop_t qop_state;
784
785
ret32(c, hContext);
786
ret32(c, flags);
787
ret32(c, seqno);
788
retdata(c, token);
789
790
ctx = find_handle(c->handles, hContext, handle_context);
791
if (ctx == NULL)
792
errx(1, "unwrap: reference to unknown context");
793
794
input_token.length = token.length;
795
input_token.value = token.data;
796
797
maj_stat = gss_unwrap(&min_stat, ctx, &input_token,
798
&output_token, &conf_state, &qop_state);
799
800
if (maj_stat != GSS_S_COMPLETE)
801
errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
802
803
krb5_data_free(&token);
804
if (maj_stat == GSS_S_COMPLETE) {
805
token.data = output_token.value;
806
token.length = output_token.length;
807
} else {
808
token.data = NULL;
809
token.length = 0;
810
}
811
put32(c, 0); /* XXX fix gsm_error */
812
putdata(c, token);
813
814
if (maj_stat == GSS_S_COMPLETE)
815
gss_release_buffer(&min_stat, &output_token);
816
817
return 0;
818
}
819
820
static int
821
HandleOP(Encrypt)
822
{
823
return handleWrap(op, c);
824
}
825
826
static int
827
HandleOP(Decrypt)
828
{
829
return handleUnwrap(op, c);
830
}
831
832
static int
833
HandleOP(ConnectLoggingService2)
834
{
835
errx(1, "ConnectLoggingService2");
836
}
837
838
static int
839
HandleOP(GetMoniker)
840
{
841
putstring(c, c->moniker);
842
return 0;
843
}
844
845
static int
846
HandleOP(CallExtension)
847
{
848
errx(1, "CallExtension");
849
}
850
851
static int
852
HandleOP(AcquirePKInitCreds)
853
{
854
int32_t flags;
855
krb5_data pfxdata;
856
char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX";
857
krb5_principal principal = NULL;
858
int fd;
859
860
ret32(c, flags);
861
retdata(c, pfxdata);
862
863
fd = mkstemp(fn + 5);
864
if (fd < 0)
865
errx(1, "mkstemp");
866
867
net_write(fd, pfxdata.data, pfxdata.length);
868
krb5_data_free(&pfxdata);
869
close(fd);
870
871
if (principal)
872
krb5_free_principal(context, principal);
873
874
put32(c, -1); /* hResource */
875
put32(c, GSMERR_NOT_SUPPORTED);
876
return 0;
877
}
878
879
static int
880
HandleOP(WrapExt)
881
{
882
OM_uint32 maj_stat, min_stat;
883
int32_t hContext, flags, bflags;
884
krb5_data token, header, trailer;
885
gss_ctx_id_t ctx;
886
unsigned char *p;
887
int conf_state, iov_len;
888
gss_iov_buffer_desc iov[6];
889
890
ret32(c, hContext);
891
ret32(c, flags);
892
ret32(c, bflags);
893
retdata(c, header);
894
retdata(c, token);
895
retdata(c, trailer);
896
897
ctx = find_handle(c->handles, hContext, handle_context);
898
if (ctx == NULL)
899
errx(1, "wrap: reference to unknown context");
900
901
memset(&iov, 0, sizeof(iov));
902
903
iov_len = sizeof(iov)/sizeof(iov[0]);
904
905
if (bflags & WRAP_EXP_ONLY_HEADER)
906
iov_len -= 2; /* skip trailer and padding, aka dce-style */
907
908
iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
909
if (header.length != 0) {
910
iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
911
iov[1].buffer.length = header.length;
912
iov[1].buffer.value = header.data;
913
} else {
914
iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
915
}
916
iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
917
iov[2].buffer.length = token.length;
918
iov[2].buffer.value = token.data;
919
if (trailer.length != 0) {
920
iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
921
iov[3].buffer.length = trailer.length;
922
iov[3].buffer.value = trailer.data;
923
} else {
924
iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
925
}
926
iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
927
iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
928
929
maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state,
930
iov, iov_len);
931
if (maj_stat != GSS_S_COMPLETE)
932
errx(1, "gss_wrap_iov_length failed");
933
934
maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state,
935
iov, iov_len);
936
if (maj_stat != GSS_S_COMPLETE)
937
errx(1, "gss_wrap_iov failed");
938
939
krb5_data_free(&token);
940
941
token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length;
942
token.data = malloc(token.length);
943
944
p = token.data;
945
memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
946
p += iov[0].buffer.length;
947
memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
948
p += iov[2].buffer.length;
949
memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
950
p += iov[4].buffer.length;
951
memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
952
#ifndef __clang_analyzer__
953
p += iov[5].buffer.length;
954
#endif
955
956
gss_release_iov_buffer(NULL, iov, iov_len);
957
958
put32(c, 0); /* XXX fix gsm_error */
959
putdata(c, token);
960
961
free(token.data);
962
963
return 0;
964
}
965
966
967
static int
968
HandleOP(UnwrapExt)
969
{
970
OM_uint32 maj_stat, min_stat;
971
int32_t hContext, flags, bflags;
972
krb5_data token, header, trailer;
973
gss_ctx_id_t ctx;
974
gss_iov_buffer_desc iov[3];
975
int conf_state, iov_len;
976
gss_qop_t qop_state;
977
978
ret32(c, hContext);
979
ret32(c, flags);
980
ret32(c, bflags);
981
retdata(c, header);
982
retdata(c, token);
983
retdata(c, trailer);
984
985
iov_len = sizeof(iov)/sizeof(iov[0]);
986
987
if (bflags & WRAP_EXP_ONLY_HEADER)
988
iov_len -= 1; /* skip trailer and padding, aka dce-style */
989
990
ctx = find_handle(c->handles, hContext, handle_context);
991
if (ctx == NULL)
992
errx(1, "unwrap: reference to unknown context");
993
994
if (header.length != 0) {
995
iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
996
iov[0].buffer.length = header.length;
997
iov[0].buffer.value = header.data;
998
} else {
999
iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY;
1000
}
1001
iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
1002
iov[1].buffer.length = token.length;
1003
iov[1].buffer.value = token.data;
1004
1005
if (trailer.length != 0) {
1006
iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
1007
iov[2].buffer.length = trailer.length;
1008
iov[2].buffer.value = trailer.data;
1009
} else {
1010
iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY;
1011
}
1012
1013
maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state,
1014
iov, iov_len);
1015
1016
if (maj_stat != GSS_S_COMPLETE)
1017
errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
1018
1019
if (maj_stat == GSS_S_COMPLETE) {
1020
token.data = iov[1].buffer.value;
1021
token.length = iov[1].buffer.length;
1022
} else {
1023
token.data = NULL;
1024
token.length = 0;
1025
}
1026
put32(c, 0); /* XXX fix gsm_error */
1027
putdata(c, token);
1028
1029
return 0;
1030
}
1031
1032
/*
1033
*
1034
*/
1035
1036
struct handler {
1037
enum gssMaggotOp op;
1038
const char *name;
1039
int (*func)(enum gssMaggotOp, struct client *);
1040
};
1041
1042
#define S(a) { e##a, #a, handle##a }
1043
1044
struct handler handlers[] = {
1045
S(GetVersionInfo),
1046
S(GoodBye),
1047
S(InitContext),
1048
S(AcceptContext),
1049
S(ToastResource),
1050
S(AcquireCreds),
1051
S(Encrypt),
1052
S(Decrypt),
1053
S(Sign),
1054
S(Verify),
1055
S(GetVersionAndCapabilities),
1056
S(GetTargetName),
1057
S(SetLoggingSocket),
1058
S(ChangePassword),
1059
S(SetPasswordSelf),
1060
S(Wrap),
1061
S(Unwrap),
1062
S(ConnectLoggingService2),
1063
S(GetMoniker),
1064
S(CallExtension),
1065
S(AcquirePKInitCreds),
1066
S(WrapExt),
1067
S(UnwrapExt),
1068
};
1069
1070
#undef S
1071
1072
/*
1073
*
1074
*/
1075
1076
static struct handler *
1077
find_op(int32_t op)
1078
{
1079
int i;
1080
1081
for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
1082
if (handlers[i].op == op)
1083
return &handlers[i];
1084
return NULL;
1085
}
1086
1087
static struct client *
1088
create_client(int fd, int port, const char *moniker)
1089
{
1090
struct client *c;
1091
1092
c = ecalloc(1, sizeof(*c));
1093
1094
if (moniker) {
1095
c->moniker = estrdup(moniker);
1096
} else {
1097
char hostname[MAXHOSTNAMELEN];
1098
gethostname(hostname, sizeof(hostname));
1099
asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);
1100
}
1101
1102
{
1103
c->salen = sizeof(c->sa);
1104
getpeername(fd, (struct sockaddr *)&c->sa, &c->salen);
1105
1106
getnameinfo((struct sockaddr *)&c->sa, c->salen,
1107
c->servername, sizeof(c->servername),
1108
NULL, 0, NI_NUMERICHOST);
1109
}
1110
1111
c->sock = krb5_storage_from_fd(fd);
1112
if (c->sock == NULL)
1113
errx(1, "krb5_storage_from_fd");
1114
1115
close(fd);
1116
1117
return c;
1118
}
1119
1120
static void
1121
free_client(struct client *c)
1122
{
1123
while(c->handles)
1124
del_handle(&c->handles, c->handles->idx);
1125
1126
free(c->moniker);
1127
krb5_storage_free(c->sock);
1128
if (c->logging)
1129
krb5_storage_free(c->logging);
1130
free(c);
1131
}
1132
1133
1134
static void *
1135
handleServer(void *ptr)
1136
{
1137
struct handler *handler;
1138
struct client *c;
1139
int32_t op;
1140
1141
c = (struct client *)ptr;
1142
1143
1144
while(1) {
1145
ret32(c, op);
1146
1147
handler = find_op(op);
1148
if (handler == NULL) {
1149
logmessage(c, __FILE__, __LINE__, 0,
1150
"op %d not supported", (int)op);
1151
exit(1);
1152
}
1153
1154
logmessage(c, __FILE__, __LINE__, 0,
1155
"---> Got op %s from server %s",
1156
handler->name, c->servername);
1157
1158
if ((handler->func)(handler->op, c))
1159
break;
1160
}
1161
1162
return NULL;
1163
}
1164
1165
1166
static char *port_str;
1167
static int version_flag;
1168
static int help_flag;
1169
static char *logfile_str;
1170
static char *moniker_str;
1171
1172
static int port = 4711;
1173
1174
struct getargs args[] = {
1175
{ "spn", 0, arg_string, &targetname, "This host's SPN",
1176
"service/host@REALM" },
1177
{ "port", 'p', arg_string, &port_str, "Use this port",
1178
"number-of-service" },
1179
{ "logfile", 0, arg_string, &logfile_str, "logfile",
1180
"number-of-service" },
1181
{ "moniker", 0, arg_string, &moniker_str, "nickname",
1182
"name" },
1183
{ "version", 0, arg_flag, &version_flag, "Print version",
1184
NULL },
1185
{ "help", 0, arg_flag, &help_flag, NULL,
1186
NULL }
1187
};
1188
1189
static void
1190
usage(int ret)
1191
{
1192
arg_printusage (args,
1193
sizeof(args) / sizeof(args[0]),
1194
NULL,
1195
"");
1196
exit (ret);
1197
}
1198
1199
int
1200
main(int argc, char **argv)
1201
{
1202
int optidx = 0;
1203
1204
setprogname (argv[0]);
1205
1206
if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
1207
usage (1);
1208
1209
if (help_flag)
1210
usage (0);
1211
1212
if (version_flag) {
1213
print_version (NULL);
1214
return 0;
1215
}
1216
1217
if (optidx != argc)
1218
usage (1);
1219
1220
if (port_str) {
1221
char *ptr;
1222
1223
port = strtol (port_str, &ptr, 10);
1224
if (port == 0 && ptr == port_str)
1225
errx (1, "Bad port `%s'", port_str);
1226
}
1227
1228
krb5_init_context(&context);
1229
1230
{
1231
const char *lf = logfile_str;
1232
if (lf == NULL)
1233
lf = "/dev/tty";
1234
1235
logfile = fopen(lf, "w");
1236
if (logfile == NULL)
1237
err(1, "error opening %s", lf);
1238
}
1239
1240
mini_inetd(htons(port), NULL);
1241
fprintf(logfile, "connected\n");
1242
1243
{
1244
struct client *c;
1245
1246
c = create_client(0, port, moniker_str);
1247
/* close(0); */
1248
1249
handleServer(c);
1250
1251
free_client(c);
1252
}
1253
1254
krb5_free_context(context);
1255
1256
return 0;
1257
}
1258
1259