Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/kcm/protocol.c
34878 views
1
/*
2
* Copyright (c) 2005, PADL Software Pty Ltd.
3
* All rights reserved.
4
*
5
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
*
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
*
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* 3. Neither the name of PADL Software nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include "kcm_locl.h"
36
#include <heimntlm.h>
37
38
static void
39
kcm_drop_default_cache(krb5_context context, kcm_client *client, char *name);
40
41
42
int
43
kcm_is_same_session(kcm_client *client, uid_t uid, pid_t session)
44
{
45
#if 0 /* XXX pppd is running in diffrent session the user */
46
if (session != -1)
47
return (client->session == session);
48
else
49
#endif
50
return (client->uid == uid);
51
}
52
53
static krb5_error_code
54
kcm_op_noop(krb5_context context,
55
kcm_client *client,
56
kcm_operation opcode,
57
krb5_storage *request,
58
krb5_storage *response)
59
{
60
KCM_LOG_REQUEST(context, client, opcode);
61
62
return 0;
63
}
64
65
/*
66
* Request:
67
* NameZ
68
* Response:
69
* NameZ
70
*
71
*/
72
static krb5_error_code
73
kcm_op_get_name(krb5_context context,
74
kcm_client *client,
75
kcm_operation opcode,
76
krb5_storage *request,
77
krb5_storage *response)
78
79
{
80
krb5_error_code ret;
81
char *name = NULL;
82
kcm_ccache ccache;
83
84
ret = krb5_ret_stringz(request, &name);
85
if (ret)
86
return ret;
87
88
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
89
90
ret = kcm_ccache_resolve_client(context, client, opcode,
91
name, &ccache);
92
if (ret) {
93
free(name);
94
return ret;
95
}
96
97
ret = krb5_store_stringz(response, ccache->name);
98
if (ret) {
99
kcm_release_ccache(context, ccache);
100
free(name);
101
return ret;
102
}
103
104
free(name);
105
kcm_release_ccache(context, ccache);
106
return 0;
107
}
108
109
/*
110
* Request:
111
*
112
* Response:
113
* NameZ
114
*/
115
static krb5_error_code
116
kcm_op_gen_new(krb5_context context,
117
kcm_client *client,
118
kcm_operation opcode,
119
krb5_storage *request,
120
krb5_storage *response)
121
{
122
krb5_error_code ret;
123
char *name;
124
125
KCM_LOG_REQUEST(context, client, opcode);
126
127
name = kcm_ccache_nextid(client->pid, client->uid, client->gid);
128
if (name == NULL) {
129
return KRB5_CC_NOMEM;
130
}
131
132
ret = krb5_store_stringz(response, name);
133
free(name);
134
135
return ret;
136
}
137
138
/*
139
* Request:
140
* NameZ
141
* Principal
142
*
143
* Response:
144
*
145
*/
146
static krb5_error_code
147
kcm_op_initialize(krb5_context context,
148
kcm_client *client,
149
kcm_operation opcode,
150
krb5_storage *request,
151
krb5_storage *response)
152
{
153
kcm_ccache ccache;
154
krb5_principal principal;
155
krb5_error_code ret;
156
char *name;
157
#if 0
158
kcm_event event;
159
#endif
160
161
KCM_LOG_REQUEST(context, client, opcode);
162
163
ret = krb5_ret_stringz(request, &name);
164
if (ret)
165
return ret;
166
167
ret = krb5_ret_principal(request, &principal);
168
if (ret) {
169
free(name);
170
return ret;
171
}
172
173
ret = kcm_ccache_new_client(context, client, name, &ccache);
174
if (ret) {
175
free(name);
176
krb5_free_principal(context, principal);
177
return ret;
178
}
179
180
ccache->client = principal;
181
182
free(name);
183
184
#if 0
185
/*
186
* Create a new credentials cache. To mitigate DoS attacks we will
187
* expire it in 30 minutes unless it has some credentials added
188
* to it
189
*/
190
191
event.fire_time = 30 * 60;
192
event.expire_time = 0;
193
event.backoff_time = 0;
194
event.action = KCM_EVENT_DESTROY_EMPTY_CACHE;
195
event.ccache = ccache;
196
197
ret = kcm_enqueue_event_relative(context, &event);
198
#endif
199
200
kcm_release_ccache(context, ccache);
201
202
return ret;
203
}
204
205
/*
206
* Request:
207
* NameZ
208
*
209
* Response:
210
*
211
*/
212
static krb5_error_code
213
kcm_op_destroy(krb5_context context,
214
kcm_client *client,
215
kcm_operation opcode,
216
krb5_storage *request,
217
krb5_storage *response)
218
{
219
krb5_error_code ret;
220
char *name;
221
222
ret = krb5_ret_stringz(request, &name);
223
if (ret)
224
return ret;
225
226
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
227
228
ret = kcm_ccache_destroy_client(context, client, name);
229
if (ret == 0)
230
kcm_drop_default_cache(context, client, name);
231
232
free(name);
233
234
return ret;
235
}
236
237
/*
238
* Request:
239
* NameZ
240
* Creds
241
*
242
* Response:
243
*
244
*/
245
static krb5_error_code
246
kcm_op_store(krb5_context context,
247
kcm_client *client,
248
kcm_operation opcode,
249
krb5_storage *request,
250
krb5_storage *response)
251
{
252
krb5_creds creds;
253
krb5_error_code ret;
254
kcm_ccache ccache;
255
char *name;
256
257
ret = krb5_ret_stringz(request, &name);
258
if (ret)
259
return ret;
260
261
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
262
263
ret = krb5_ret_creds(request, &creds);
264
if (ret) {
265
free(name);
266
return ret;
267
}
268
269
ret = kcm_ccache_resolve_client(context, client, opcode,
270
name, &ccache);
271
if (ret) {
272
free(name);
273
krb5_free_cred_contents(context, &creds);
274
return ret;
275
}
276
277
ret = kcm_ccache_store_cred(context, ccache, &creds, 0);
278
if (ret) {
279
free(name);
280
krb5_free_cred_contents(context, &creds);
281
kcm_release_ccache(context, ccache);
282
return ret;
283
}
284
285
kcm_ccache_enqueue_default(context, ccache, &creds);
286
287
free(name);
288
kcm_release_ccache(context, ccache);
289
290
return 0;
291
}
292
293
/*
294
* Request:
295
* NameZ
296
* WhichFields
297
* MatchCreds
298
*
299
* Response:
300
* Creds
301
*
302
*/
303
static krb5_error_code
304
kcm_op_retrieve(krb5_context context,
305
kcm_client *client,
306
kcm_operation opcode,
307
krb5_storage *request,
308
krb5_storage *response)
309
{
310
uint32_t flags;
311
krb5_creds mcreds;
312
krb5_error_code ret;
313
kcm_ccache ccache;
314
char *name;
315
krb5_creds *credp;
316
int free_creds = 0;
317
318
ret = krb5_ret_stringz(request, &name);
319
if (ret)
320
return ret;
321
322
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
323
324
ret = krb5_ret_uint32(request, &flags);
325
if (ret) {
326
free(name);
327
return ret;
328
}
329
330
ret = krb5_ret_creds_tag(request, &mcreds);
331
if (ret) {
332
free(name);
333
return ret;
334
}
335
336
if (disallow_getting_krbtgt &&
337
mcreds.server->name.name_string.len == 2 &&
338
strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0)
339
{
340
free(name);
341
krb5_free_cred_contents(context, &mcreds);
342
return KRB5_FCC_PERM;
343
}
344
345
ret = kcm_ccache_resolve_client(context, client, opcode,
346
name, &ccache);
347
if (ret) {
348
free(name);
349
krb5_free_cred_contents(context, &mcreds);
350
return ret;
351
}
352
353
ret = kcm_ccache_retrieve_cred(context, ccache, flags,
354
&mcreds, &credp);
355
if (ret && ((flags & KRB5_GC_CACHED) == 0) &&
356
!krb5_is_config_principal(context, mcreds.server)) {
357
krb5_ccache_data ccdata;
358
359
/* try and acquire */
360
HEIMDAL_MUTEX_lock(&ccache->mutex);
361
362
/* Fake up an internal ccache */
363
kcm_internal_ccache(context, ccache, &ccdata);
364
365
/* glue cc layer will store creds */
366
ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp);
367
if (ret == 0)
368
free_creds = 1;
369
370
HEIMDAL_MUTEX_unlock(&ccache->mutex);
371
}
372
373
if (ret == 0) {
374
ret = krb5_store_creds(response, credp);
375
}
376
377
free(name);
378
krb5_free_cred_contents(context, &mcreds);
379
kcm_release_ccache(context, ccache);
380
381
if (free_creds)
382
krb5_free_cred_contents(context, credp);
383
384
return ret;
385
}
386
387
/*
388
* Request:
389
* NameZ
390
*
391
* Response:
392
* Principal
393
*/
394
static krb5_error_code
395
kcm_op_get_principal(krb5_context context,
396
kcm_client *client,
397
kcm_operation opcode,
398
krb5_storage *request,
399
krb5_storage *response)
400
{
401
krb5_error_code ret;
402
kcm_ccache ccache;
403
char *name;
404
405
ret = krb5_ret_stringz(request, &name);
406
if (ret)
407
return ret;
408
409
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
410
411
ret = kcm_ccache_resolve_client(context, client, opcode,
412
name, &ccache);
413
if (ret) {
414
free(name);
415
return ret;
416
}
417
418
if (ccache->client == NULL)
419
ret = KRB5_CC_NOTFOUND;
420
else
421
ret = krb5_store_principal(response, ccache->client);
422
423
free(name);
424
kcm_release_ccache(context, ccache);
425
426
return ret;
427
}
428
429
/*
430
* Request:
431
* NameZ
432
*
433
* Response:
434
* UUIDs
435
*
436
*/
437
static krb5_error_code
438
kcm_op_get_cred_uuid_list(krb5_context context,
439
kcm_client *client,
440
kcm_operation opcode,
441
krb5_storage *request,
442
krb5_storage *response)
443
{
444
struct kcm_creds *creds;
445
krb5_error_code ret;
446
kcm_ccache ccache;
447
char *name;
448
449
ret = krb5_ret_stringz(request, &name);
450
if (ret)
451
return ret;
452
453
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
454
455
ret = kcm_ccache_resolve_client(context, client, opcode,
456
name, &ccache);
457
free(name);
458
if (ret)
459
return ret;
460
461
for (creds = ccache->creds ; creds ; creds = creds->next) {
462
ssize_t sret;
463
sret = krb5_storage_write(response, &creds->uuid, sizeof(creds->uuid));
464
if (sret != sizeof(creds->uuid)) {
465
ret = ENOMEM;
466
break;
467
}
468
}
469
470
kcm_release_ccache(context, ccache);
471
472
return ret;
473
}
474
475
/*
476
* Request:
477
* NameZ
478
* Cursor
479
*
480
* Response:
481
* Creds
482
*/
483
static krb5_error_code
484
kcm_op_get_cred_by_uuid(krb5_context context,
485
kcm_client *client,
486
kcm_operation opcode,
487
krb5_storage *request,
488
krb5_storage *response)
489
{
490
krb5_error_code ret;
491
kcm_ccache ccache;
492
char *name;
493
struct kcm_creds *c;
494
kcmuuid_t uuid;
495
ssize_t sret;
496
497
ret = krb5_ret_stringz(request, &name);
498
if (ret)
499
return ret;
500
501
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
502
503
ret = kcm_ccache_resolve_client(context, client, opcode,
504
name, &ccache);
505
free(name);
506
if (ret)
507
return ret;
508
509
sret = krb5_storage_read(request, &uuid, sizeof(uuid));
510
if (sret != sizeof(uuid)) {
511
kcm_release_ccache(context, ccache);
512
krb5_clear_error_message(context);
513
return KRB5_CC_IO;
514
}
515
516
c = kcm_ccache_find_cred_uuid(context, ccache, uuid);
517
if (c == NULL) {
518
kcm_release_ccache(context, ccache);
519
return KRB5_CC_END;
520
}
521
522
HEIMDAL_MUTEX_lock(&ccache->mutex);
523
ret = krb5_store_creds(response, &c->cred);
524
HEIMDAL_MUTEX_unlock(&ccache->mutex);
525
526
kcm_release_ccache(context, ccache);
527
528
return ret;
529
}
530
531
/*
532
* Request:
533
* NameZ
534
* WhichFields
535
* MatchCreds
536
*
537
* Response:
538
*
539
*/
540
static krb5_error_code
541
kcm_op_remove_cred(krb5_context context,
542
kcm_client *client,
543
kcm_operation opcode,
544
krb5_storage *request,
545
krb5_storage *response)
546
{
547
uint32_t whichfields;
548
krb5_creds mcreds;
549
krb5_error_code ret;
550
kcm_ccache ccache;
551
char *name;
552
553
ret = krb5_ret_stringz(request, &name);
554
if (ret)
555
return ret;
556
557
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
558
559
ret = krb5_ret_uint32(request, &whichfields);
560
if (ret) {
561
free(name);
562
return ret;
563
}
564
565
ret = krb5_ret_creds_tag(request, &mcreds);
566
if (ret) {
567
free(name);
568
return ret;
569
}
570
571
ret = kcm_ccache_resolve_client(context, client, opcode,
572
name, &ccache);
573
if (ret) {
574
free(name);
575
krb5_free_cred_contents(context, &mcreds);
576
return ret;
577
}
578
579
ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds);
580
581
/* XXX need to remove any events that match */
582
583
free(name);
584
krb5_free_cred_contents(context, &mcreds);
585
kcm_release_ccache(context, ccache);
586
587
return ret;
588
}
589
590
/*
591
* Request:
592
* NameZ
593
* Flags
594
*
595
* Response:
596
*
597
*/
598
static krb5_error_code
599
kcm_op_set_flags(krb5_context context,
600
kcm_client *client,
601
kcm_operation opcode,
602
krb5_storage *request,
603
krb5_storage *response)
604
{
605
uint32_t flags;
606
krb5_error_code ret;
607
kcm_ccache ccache;
608
char *name;
609
610
ret = krb5_ret_stringz(request, &name);
611
if (ret)
612
return ret;
613
614
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
615
616
ret = krb5_ret_uint32(request, &flags);
617
if (ret) {
618
free(name);
619
return ret;
620
}
621
622
ret = kcm_ccache_resolve_client(context, client, opcode,
623
name, &ccache);
624
if (ret) {
625
free(name);
626
return ret;
627
}
628
629
/* we don't really support any flags yet */
630
free(name);
631
kcm_release_ccache(context, ccache);
632
633
return 0;
634
}
635
636
/*
637
* Request:
638
* NameZ
639
* UID
640
* GID
641
*
642
* Response:
643
*
644
*/
645
static krb5_error_code
646
kcm_op_chown(krb5_context context,
647
kcm_client *client,
648
kcm_operation opcode,
649
krb5_storage *request,
650
krb5_storage *response)
651
{
652
uint32_t uid;
653
uint32_t gid;
654
krb5_error_code ret;
655
kcm_ccache ccache;
656
char *name;
657
658
ret = krb5_ret_stringz(request, &name);
659
if (ret)
660
return ret;
661
662
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
663
664
ret = krb5_ret_uint32(request, &uid);
665
if (ret) {
666
free(name);
667
return ret;
668
}
669
670
ret = krb5_ret_uint32(request, &gid);
671
if (ret) {
672
free(name);
673
return ret;
674
}
675
676
ret = kcm_ccache_resolve_client(context, client, opcode,
677
name, &ccache);
678
if (ret) {
679
free(name);
680
return ret;
681
}
682
683
ret = kcm_chown(context, client, ccache, uid, gid);
684
685
free(name);
686
kcm_release_ccache(context, ccache);
687
688
return ret;
689
}
690
691
/*
692
* Request:
693
* NameZ
694
* Mode
695
*
696
* Response:
697
*
698
*/
699
static krb5_error_code
700
kcm_op_chmod(krb5_context context,
701
kcm_client *client,
702
kcm_operation opcode,
703
krb5_storage *request,
704
krb5_storage *response)
705
{
706
uint16_t mode;
707
krb5_error_code ret;
708
kcm_ccache ccache;
709
char *name;
710
711
ret = krb5_ret_stringz(request, &name);
712
if (ret)
713
return ret;
714
715
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
716
717
ret = krb5_ret_uint16(request, &mode);
718
if (ret) {
719
free(name);
720
return ret;
721
}
722
723
ret = kcm_ccache_resolve_client(context, client, opcode,
724
name, &ccache);
725
if (ret) {
726
free(name);
727
return ret;
728
}
729
730
ret = kcm_chmod(context, client, ccache, mode);
731
732
free(name);
733
kcm_release_ccache(context, ccache);
734
735
return ret;
736
}
737
738
/*
739
* Protocol extensions for moving ticket acquisition responsibility
740
* from client to KCM follow.
741
*/
742
743
/*
744
* Request:
745
* NameZ
746
* ServerPrincipalPresent
747
* ServerPrincipal OPTIONAL
748
* Key
749
*
750
* Repsonse:
751
*
752
*/
753
static krb5_error_code
754
kcm_op_get_initial_ticket(krb5_context context,
755
kcm_client *client,
756
kcm_operation opcode,
757
krb5_storage *request,
758
krb5_storage *response)
759
{
760
krb5_error_code ret;
761
kcm_ccache ccache;
762
char *name;
763
int8_t not_tgt = 0;
764
krb5_principal server = NULL;
765
krb5_keyblock key;
766
767
krb5_keyblock_zero(&key);
768
769
ret = krb5_ret_stringz(request, &name);
770
if (ret)
771
return ret;
772
773
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
774
775
ret = krb5_ret_int8(request, &not_tgt);
776
if (ret) {
777
free(name);
778
return ret;
779
}
780
781
if (not_tgt) {
782
ret = krb5_ret_principal(request, &server);
783
if (ret) {
784
free(name);
785
return ret;
786
}
787
}
788
789
ret = krb5_ret_keyblock(request, &key);
790
if (ret) {
791
free(name);
792
if (server != NULL)
793
krb5_free_principal(context, server);
794
return ret;
795
}
796
797
ret = kcm_ccache_resolve_client(context, client, opcode,
798
name, &ccache);
799
if (ret == 0) {
800
HEIMDAL_MUTEX_lock(&ccache->mutex);
801
802
if (ccache->server != NULL) {
803
krb5_free_principal(context, ccache->server);
804
ccache->server = NULL;
805
}
806
807
krb5_free_keyblock(context, &ccache->key.keyblock);
808
809
ccache->server = server;
810
ccache->key.keyblock = key;
811
ccache->flags |= KCM_FLAGS_USE_CACHED_KEY;
812
813
ret = kcm_ccache_enqueue_default(context, ccache, NULL);
814
if (ret) {
815
ccache->server = NULL;
816
krb5_keyblock_zero(&ccache->key.keyblock);
817
ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY);
818
}
819
820
HEIMDAL_MUTEX_unlock(&ccache->mutex);
821
}
822
823
free(name);
824
825
if (ret != 0) {
826
krb5_free_principal(context, server);
827
krb5_free_keyblock(context, &key);
828
}
829
830
kcm_release_ccache(context, ccache);
831
832
return ret;
833
}
834
835
/*
836
* Request:
837
* NameZ
838
* ServerPrincipal
839
* KDCFlags
840
* EncryptionType
841
*
842
* Repsonse:
843
*
844
*/
845
static krb5_error_code
846
kcm_op_get_ticket(krb5_context context,
847
kcm_client *client,
848
kcm_operation opcode,
849
krb5_storage *request,
850
krb5_storage *response)
851
{
852
krb5_error_code ret;
853
kcm_ccache ccache;
854
char *name;
855
krb5_principal server = NULL;
856
krb5_ccache_data ccdata;
857
krb5_creds in, *out;
858
krb5_kdc_flags flags;
859
860
memset(&in, 0, sizeof(in));
861
862
ret = krb5_ret_stringz(request, &name);
863
if (ret)
864
return ret;
865
866
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
867
868
ret = krb5_ret_uint32(request, &flags.i);
869
if (ret) {
870
free(name);
871
return ret;
872
}
873
874
ret = krb5_ret_int32(request, &in.session.keytype);
875
if (ret) {
876
free(name);
877
return ret;
878
}
879
880
ret = krb5_ret_principal(request, &server);
881
if (ret) {
882
free(name);
883
return ret;
884
}
885
886
ret = kcm_ccache_resolve_client(context, client, opcode,
887
name, &ccache);
888
if (ret) {
889
krb5_free_principal(context, server);
890
free(name);
891
return ret;
892
}
893
894
HEIMDAL_MUTEX_lock(&ccache->mutex);
895
896
/* Fake up an internal ccache */
897
kcm_internal_ccache(context, ccache, &ccdata);
898
899
in.client = ccache->client;
900
in.server = server;
901
in.times.endtime = 0;
902
903
/* glue cc layer will store creds */
904
ret = krb5_get_credentials_with_flags(context, 0, flags,
905
&ccdata, &in, &out);
906
907
HEIMDAL_MUTEX_unlock(&ccache->mutex);
908
909
krb5_free_principal(context, server);
910
911
if (ret == 0)
912
krb5_free_cred_contents(context, out);
913
914
kcm_release_ccache(context, ccache);
915
free(name);
916
917
return ret;
918
}
919
920
/*
921
* Request:
922
* OldNameZ
923
* NewNameZ
924
*
925
* Repsonse:
926
*
927
*/
928
static krb5_error_code
929
kcm_op_move_cache(krb5_context context,
930
kcm_client *client,
931
kcm_operation opcode,
932
krb5_storage *request,
933
krb5_storage *response)
934
{
935
krb5_error_code ret;
936
kcm_ccache oldid, newid;
937
char *oldname, *newname;
938
939
ret = krb5_ret_stringz(request, &oldname);
940
if (ret)
941
return ret;
942
943
KCM_LOG_REQUEST_NAME(context, client, opcode, oldname);
944
945
ret = krb5_ret_stringz(request, &newname);
946
if (ret) {
947
free(oldname);
948
return ret;
949
}
950
951
/* move to ourself is simple, done! */
952
if (strcmp(oldname, newname) == 0) {
953
free(oldname);
954
free(newname);
955
return 0;
956
}
957
958
ret = kcm_ccache_resolve_client(context, client, opcode, oldname, &oldid);
959
if (ret) {
960
free(oldname);
961
free(newname);
962
return ret;
963
}
964
965
/* Check if new credential cache exists, if not create one. */
966
ret = kcm_ccache_resolve_client(context, client, opcode, newname, &newid);
967
if (ret == KRB5_FCC_NOFILE)
968
ret = kcm_ccache_new_client(context, client, newname, &newid);
969
free(newname);
970
971
if (ret) {
972
free(oldname);
973
kcm_release_ccache(context, oldid);
974
return ret;
975
}
976
977
HEIMDAL_MUTEX_lock(&oldid->mutex);
978
HEIMDAL_MUTEX_lock(&newid->mutex);
979
980
/* move content */
981
{
982
kcm_ccache_data tmp;
983
984
#define MOVE(n,o,f) { tmp.f = n->f ; n->f = o->f; o->f = tmp.f; }
985
986
MOVE(newid, oldid, flags);
987
MOVE(newid, oldid, client);
988
MOVE(newid, oldid, server);
989
MOVE(newid, oldid, creds);
990
MOVE(newid, oldid, tkt_life);
991
MOVE(newid, oldid, renew_life);
992
MOVE(newid, oldid, key);
993
MOVE(newid, oldid, kdc_offset);
994
#undef MOVE
995
}
996
997
HEIMDAL_MUTEX_unlock(&oldid->mutex);
998
HEIMDAL_MUTEX_unlock(&newid->mutex);
999
1000
kcm_release_ccache(context, oldid);
1001
kcm_release_ccache(context, newid);
1002
1003
ret = kcm_ccache_destroy_client(context, client, oldname);
1004
if (ret == 0)
1005
kcm_drop_default_cache(context, client, oldname);
1006
1007
free(oldname);
1008
1009
return ret;
1010
}
1011
1012
static krb5_error_code
1013
kcm_op_get_cache_uuid_list(krb5_context context,
1014
kcm_client *client,
1015
kcm_operation opcode,
1016
krb5_storage *request,
1017
krb5_storage *response)
1018
{
1019
KCM_LOG_REQUEST(context, client, opcode);
1020
1021
return kcm_ccache_get_uuids(context, client, opcode, response);
1022
}
1023
1024
static krb5_error_code
1025
kcm_op_get_cache_by_uuid(krb5_context context,
1026
kcm_client *client,
1027
kcm_operation opcode,
1028
krb5_storage *request,
1029
krb5_storage *response)
1030
{
1031
krb5_error_code ret;
1032
kcmuuid_t uuid;
1033
ssize_t sret;
1034
kcm_ccache cache;
1035
1036
KCM_LOG_REQUEST(context, client, opcode);
1037
1038
sret = krb5_storage_read(request, &uuid, sizeof(uuid));
1039
if (sret != sizeof(uuid)) {
1040
krb5_clear_error_message(context);
1041
return KRB5_CC_IO;
1042
}
1043
1044
ret = kcm_ccache_resolve_by_uuid(context, uuid, &cache);
1045
if (ret)
1046
return ret;
1047
1048
ret = kcm_access(context, client, opcode, cache);
1049
if (ret)
1050
ret = KRB5_FCC_NOFILE;
1051
1052
if (ret == 0)
1053
ret = krb5_store_stringz(response, cache->name);
1054
1055
kcm_release_ccache(context, cache);
1056
1057
return ret;
1058
}
1059
1060
struct kcm_default_cache *default_caches;
1061
1062
static krb5_error_code
1063
kcm_op_get_default_cache(krb5_context context,
1064
kcm_client *client,
1065
kcm_operation opcode,
1066
krb5_storage *request,
1067
krb5_storage *response)
1068
{
1069
struct kcm_default_cache *c;
1070
krb5_error_code ret;
1071
const char *name = NULL;
1072
char *n = NULL;
1073
1074
KCM_LOG_REQUEST(context, client, opcode);
1075
1076
for (c = default_caches; c != NULL; c = c->next) {
1077
if (kcm_is_same_session(client, c->uid, c->session)) {
1078
name = c->name;
1079
break;
1080
}
1081
}
1082
if (name == NULL)
1083
name = n = kcm_ccache_first_name(client);
1084
1085
if (name == NULL) {
1086
asprintf(&n, "%d", (int)client->uid);
1087
name = n;
1088
}
1089
if (name == NULL)
1090
return ENOMEM;
1091
ret = krb5_store_stringz(response, name);
1092
if (n)
1093
free(n);
1094
return ret;
1095
}
1096
1097
static void
1098
kcm_drop_default_cache(krb5_context context, kcm_client *client, char *name)
1099
{
1100
struct kcm_default_cache **c;
1101
1102
for (c = &default_caches; *c != NULL; c = &(*c)->next) {
1103
if (!kcm_is_same_session(client, (*c)->uid, (*c)->session))
1104
continue;
1105
if (strcmp((*c)->name, name) == 0) {
1106
struct kcm_default_cache *h = *c;
1107
*c = (*c)->next;
1108
free(h->name);
1109
free(h);
1110
break;
1111
}
1112
}
1113
}
1114
1115
static krb5_error_code
1116
kcm_op_set_default_cache(krb5_context context,
1117
kcm_client *client,
1118
kcm_operation opcode,
1119
krb5_storage *request,
1120
krb5_storage *response)
1121
{
1122
struct kcm_default_cache *c;
1123
krb5_error_code ret;
1124
char *name;
1125
1126
ret = krb5_ret_stringz(request, &name);
1127
if (ret)
1128
return ret;
1129
1130
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
1131
1132
for (c = default_caches; c != NULL; c = c->next) {
1133
if (kcm_is_same_session(client, c->uid, c->session))
1134
break;
1135
}
1136
if (c == NULL) {
1137
c = malloc(sizeof(*c));
1138
if (c == NULL)
1139
return ENOMEM;
1140
c->session = client->session;
1141
c->uid = client->uid;
1142
c->name = strdup(name);
1143
1144
c->next = default_caches;
1145
default_caches = c;
1146
} else {
1147
free(c->name);
1148
c->name = strdup(name);
1149
}
1150
1151
return 0;
1152
}
1153
1154
static krb5_error_code
1155
kcm_op_get_kdc_offset(krb5_context context,
1156
kcm_client *client,
1157
kcm_operation opcode,
1158
krb5_storage *request,
1159
krb5_storage *response)
1160
{
1161
krb5_error_code ret;
1162
kcm_ccache ccache;
1163
char *name;
1164
1165
ret = krb5_ret_stringz(request, &name);
1166
if (ret)
1167
return ret;
1168
1169
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
1170
1171
ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache);
1172
free(name);
1173
if (ret)
1174
return ret;
1175
1176
HEIMDAL_MUTEX_lock(&ccache->mutex);
1177
ret = krb5_store_int32(response, ccache->kdc_offset);
1178
HEIMDAL_MUTEX_unlock(&ccache->mutex);
1179
1180
kcm_release_ccache(context, ccache);
1181
1182
return ret;
1183
}
1184
1185
static krb5_error_code
1186
kcm_op_set_kdc_offset(krb5_context context,
1187
kcm_client *client,
1188
kcm_operation opcode,
1189
krb5_storage *request,
1190
krb5_storage *response)
1191
{
1192
krb5_error_code ret;
1193
kcm_ccache ccache;
1194
int32_t offset;
1195
char *name;
1196
1197
ret = krb5_ret_stringz(request, &name);
1198
if (ret)
1199
return ret;
1200
1201
KCM_LOG_REQUEST_NAME(context, client, opcode, name);
1202
1203
ret = krb5_ret_int32(request, &offset);
1204
if (ret) {
1205
free(name);
1206
return ret;
1207
}
1208
1209
ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache);
1210
free(name);
1211
if (ret)
1212
return ret;
1213
1214
HEIMDAL_MUTEX_lock(&ccache->mutex);
1215
ccache->kdc_offset = offset;
1216
HEIMDAL_MUTEX_unlock(&ccache->mutex);
1217
1218
kcm_release_ccache(context, ccache);
1219
1220
return ret;
1221
}
1222
1223
struct kcm_ntlm_cred {
1224
kcmuuid_t uuid;
1225
char *user;
1226
char *domain;
1227
krb5_data nthash;
1228
uid_t uid;
1229
pid_t session;
1230
struct kcm_ntlm_cred *next;
1231
};
1232
1233
static struct kcm_ntlm_cred *ntlm_head;
1234
1235
static void
1236
free_cred(struct kcm_ntlm_cred *cred)
1237
{
1238
free(cred->user);
1239
free(cred->domain);
1240
krb5_data_free(&cred->nthash);
1241
free(cred);
1242
}
1243
1244
1245
/*
1246
* name
1247
* domain
1248
* ntlm hash
1249
*
1250
* Reply:
1251
* uuid
1252
*/
1253
1254
static struct kcm_ntlm_cred *
1255
find_ntlm_cred(const char *user, const char *domain, kcm_client *client)
1256
{
1257
struct kcm_ntlm_cred *c;
1258
1259
for (c = ntlm_head; c != NULL; c = c->next)
1260
if ((user[0] == '\0' || strcmp(user, c->user) == 0) &&
1261
(domain == NULL || strcmp(domain, c->domain) == 0) &&
1262
kcm_is_same_session(client, c->uid, c->session))
1263
return c;
1264
1265
return NULL;
1266
}
1267
1268
static krb5_error_code
1269
kcm_op_add_ntlm_cred(krb5_context context,
1270
kcm_client *client,
1271
kcm_operation opcode,
1272
krb5_storage *request,
1273
krb5_storage *response)
1274
{
1275
struct kcm_ntlm_cred *cred, *c;
1276
krb5_error_code ret;
1277
1278
cred = calloc(1, sizeof(*cred));
1279
if (cred == NULL)
1280
return ENOMEM;
1281
1282
RAND_bytes(cred->uuid, sizeof(cred->uuid));
1283
1284
ret = krb5_ret_stringz(request, &cred->user);
1285
if (ret)
1286
goto error;
1287
1288
ret = krb5_ret_stringz(request, &cred->domain);
1289
if (ret)
1290
goto error;
1291
1292
ret = krb5_ret_data(request, &cred->nthash);
1293
if (ret)
1294
goto error;
1295
1296
/* search for dups */
1297
c = find_ntlm_cred(cred->user, cred->domain, client);
1298
if (c) {
1299
krb5_data hash = c->nthash;
1300
c->nthash = cred->nthash;
1301
cred->nthash = hash;
1302
free_cred(cred);
1303
cred = c;
1304
} else {
1305
cred->next = ntlm_head;
1306
ntlm_head = cred;
1307
}
1308
1309
cred->uid = client->uid;
1310
cred->session = client->session;
1311
1312
/* write response */
1313
(void)krb5_storage_write(response, &cred->uuid, sizeof(cred->uuid));
1314
1315
return 0;
1316
1317
error:
1318
free_cred(cred);
1319
1320
return ret;
1321
}
1322
1323
/*
1324
* { "HAVE_NTLM_CRED", NULL },
1325
*
1326
* input:
1327
* name
1328
* domain
1329
*/
1330
1331
static krb5_error_code
1332
kcm_op_have_ntlm_cred(krb5_context context,
1333
kcm_client *client,
1334
kcm_operation opcode,
1335
krb5_storage *request,
1336
krb5_storage *response)
1337
{
1338
struct kcm_ntlm_cred *c;
1339
char *user = NULL, *domain = NULL;
1340
krb5_error_code ret;
1341
1342
ret = krb5_ret_stringz(request, &user);
1343
if (ret)
1344
goto error;
1345
1346
ret = krb5_ret_stringz(request, &domain);
1347
if (ret)
1348
goto error;
1349
1350
if (domain[0] == '\0') {
1351
free(domain);
1352
domain = NULL;
1353
}
1354
1355
c = find_ntlm_cred(user, domain, client);
1356
if (c == NULL)
1357
ret = ENOENT;
1358
1359
error:
1360
free(user);
1361
if (domain)
1362
free(domain);
1363
1364
return ret;
1365
}
1366
1367
/*
1368
* { "DEL_NTLM_CRED", NULL },
1369
*
1370
* input:
1371
* name
1372
* domain
1373
*/
1374
1375
static krb5_error_code
1376
kcm_op_del_ntlm_cred(krb5_context context,
1377
kcm_client *client,
1378
kcm_operation opcode,
1379
krb5_storage *request,
1380
krb5_storage *response)
1381
{
1382
struct kcm_ntlm_cred **cp, *c;
1383
char *user = NULL, *domain = NULL;
1384
krb5_error_code ret;
1385
1386
ret = krb5_ret_stringz(request, &user);
1387
if (ret)
1388
goto error;
1389
1390
ret = krb5_ret_stringz(request, &domain);
1391
if (ret)
1392
goto error;
1393
1394
for (cp = &ntlm_head; *cp != NULL; cp = &(*cp)->next) {
1395
if (strcmp(user, (*cp)->user) == 0 && strcmp(domain, (*cp)->domain) == 0 &&
1396
kcm_is_same_session(client, (*cp)->uid, (*cp)->session))
1397
{
1398
c = *cp;
1399
*cp = c->next;
1400
1401
free_cred(c);
1402
break;
1403
}
1404
}
1405
1406
error:
1407
free(user);
1408
free(domain);
1409
1410
return ret;
1411
}
1412
1413
/*
1414
* { "DO_NTLM_AUTH", NULL },
1415
*
1416
* input:
1417
* name:string
1418
* domain:string
1419
* type2:data
1420
*
1421
* reply:
1422
* type3:data
1423
* flags:int32
1424
* session-key:data
1425
*/
1426
1427
#define NTLM_FLAG_SESSIONKEY 1
1428
#define NTLM_FLAG_NTLM2_SESSION 2
1429
#define NTLM_FLAG_KEYEX 4
1430
1431
static krb5_error_code
1432
kcm_op_do_ntlm(krb5_context context,
1433
kcm_client *client,
1434
kcm_operation opcode,
1435
krb5_storage *request,
1436
krb5_storage *response)
1437
{
1438
struct kcm_ntlm_cred *c;
1439
struct ntlm_type2 type2;
1440
struct ntlm_type3 type3;
1441
char *user = NULL, *domain = NULL;
1442
struct ntlm_buf ndata, sessionkey;
1443
krb5_data data;
1444
krb5_error_code ret;
1445
uint32_t flags = 0;
1446
1447
memset(&type2, 0, sizeof(type2));
1448
memset(&type3, 0, sizeof(type3));
1449
sessionkey.data = NULL;
1450
sessionkey.length = 0;
1451
1452
ret = krb5_ret_stringz(request, &user);
1453
if (ret)
1454
goto error;
1455
1456
ret = krb5_ret_stringz(request, &domain);
1457
if (ret)
1458
goto error;
1459
1460
if (domain[0] == '\0') {
1461
free(domain);
1462
domain = NULL;
1463
}
1464
1465
c = find_ntlm_cred(user, domain, client);
1466
if (c == NULL) {
1467
ret = EINVAL;
1468
goto error;
1469
}
1470
1471
ret = krb5_ret_data(request, &data);
1472
if (ret)
1473
goto error;
1474
1475
ndata.data = data.data;
1476
ndata.length = data.length;
1477
1478
ret = heim_ntlm_decode_type2(&ndata, &type2);
1479
krb5_data_free(&data);
1480
if (ret)
1481
goto error;
1482
1483
if (domain && strcmp(domain, type2.targetname) == 0) {
1484
ret = EINVAL;
1485
goto error;
1486
}
1487
1488
type3.username = c->user;
1489
type3.flags = type2.flags;
1490
type3.targetname = type2.targetname;
1491
type3.ws = rk_UNCONST("workstation");
1492
1493
/*
1494
* NTLM Version 1 if no targetinfo buffer.
1495
*/
1496
1497
if (1 || type2.targetinfo.length == 0) {
1498
struct ntlm_buf sessionkey;
1499
1500
if (type2.flags & NTLM_NEG_NTLM2_SESSION) {
1501
unsigned char nonce[8];
1502
1503
if (RAND_bytes(nonce, sizeof(nonce)) != 1) {
1504
ret = EINVAL;
1505
goto error;
1506
}
1507
1508
ret = heim_ntlm_calculate_ntlm2_sess(nonce,
1509
type2.challenge,
1510
c->nthash.data,
1511
&type3.lm,
1512
&type3.ntlm);
1513
} else {
1514
ret = heim_ntlm_calculate_ntlm1(c->nthash.data,
1515
c->nthash.length,
1516
type2.challenge,
1517
&type3.ntlm);
1518
1519
}
1520
if (ret)
1521
goto error;
1522
1523
ret = heim_ntlm_build_ntlm1_master(c->nthash.data,
1524
c->nthash.length,
1525
&sessionkey,
1526
&type3.sessionkey);
1527
if (ret) {
1528
if (type3.lm.data)
1529
free(type3.lm.data);
1530
if (type3.ntlm.data)
1531
free(type3.ntlm.data);
1532
goto error;
1533
}
1534
1535
free(sessionkey.data);
1536
if (ret) {
1537
if (type3.lm.data)
1538
free(type3.lm.data);
1539
if (type3.ntlm.data)
1540
free(type3.ntlm.data);
1541
goto error;
1542
}
1543
flags |= NTLM_FLAG_SESSIONKEY;
1544
#if 0
1545
} else {
1546
struct ntlm_buf sessionkey;
1547
unsigned char ntlmv2[16];
1548
struct ntlm_targetinfo ti;
1549
1550
/* verify infotarget */
1551
1552
ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti);
1553
if(ret) {
1554
_gss_ntlm_delete_sec_context(minor_status,
1555
context_handle, NULL);
1556
*minor_status = ret;
1557
return GSS_S_FAILURE;
1558
}
1559
1560
if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) {
1561
_gss_ntlm_delete_sec_context(minor_status,
1562
context_handle, NULL);
1563
*minor_status = EINVAL;
1564
return GSS_S_FAILURE;
1565
}
1566
1567
ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data,
1568
ctx->client->key.length,
1569
type3.username,
1570
name->domain,
1571
type2.challenge,
1572
&type2.targetinfo,
1573
ntlmv2,
1574
&type3.ntlm);
1575
if (ret) {
1576
_gss_ntlm_delete_sec_context(minor_status,
1577
context_handle, NULL);
1578
*minor_status = ret;
1579
return GSS_S_FAILURE;
1580
}
1581
1582
ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2),
1583
&sessionkey,
1584
&type3.sessionkey);
1585
memset(ntlmv2, 0, sizeof(ntlmv2));
1586
if (ret) {
1587
_gss_ntlm_delete_sec_context(minor_status,
1588
context_handle, NULL);
1589
*minor_status = ret;
1590
return GSS_S_FAILURE;
1591
}
1592
1593
flags |= NTLM_FLAG_NTLM2_SESSION |
1594
NTLM_FLAG_SESSION;
1595
1596
if (type3.flags & NTLM_NEG_KEYEX)
1597
flags |= NTLM_FLAG_KEYEX;
1598
1599
ret = krb5_data_copy(&ctx->sessionkey,
1600
sessionkey.data, sessionkey.length);
1601
free(sessionkey.data);
1602
if (ret) {
1603
_gss_ntlm_delete_sec_context(minor_status,
1604
context_handle, NULL);
1605
*minor_status = ret;
1606
return GSS_S_FAILURE;
1607
}
1608
#endif
1609
}
1610
1611
#if 0
1612
if (flags & NTLM_FLAG_NTLM2_SESSION) {
1613
_gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX),
1614
ctx->sessionkey.data,
1615
ctx->sessionkey.length);
1616
_gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX),
1617
ctx->sessionkey.data,
1618
ctx->sessionkey.length);
1619
} else {
1620
flags |= NTLM_FLAG_SESSION;
1621
RC4_set_key(&ctx->u.v1.crypto_recv.key,
1622
ctx->sessionkey.length,
1623
ctx->sessionkey.data);
1624
RC4_set_key(&ctx->u.v1.crypto_send.key,
1625
ctx->sessionkey.length,
1626
ctx->sessionkey.data);
1627
}
1628
#endif
1629
1630
ret = heim_ntlm_encode_type3(&type3, &ndata);
1631
if (ret)
1632
goto error;
1633
1634
data.data = ndata.data;
1635
data.length = ndata.length;
1636
ret = krb5_store_data(response, data);
1637
heim_ntlm_free_buf(&ndata);
1638
if (ret) goto error;
1639
1640
ret = krb5_store_int32(response, flags);
1641
if (ret) goto error;
1642
1643
data.data = sessionkey.data;
1644
data.length = sessionkey.length;
1645
1646
ret = krb5_store_data(response, data);
1647
if (ret) goto error;
1648
1649
error:
1650
free(type3.username);
1651
heim_ntlm_free_type2(&type2);
1652
free(user);
1653
if (domain)
1654
free(domain);
1655
1656
return ret;
1657
}
1658
1659
1660
/*
1661
* { "GET_NTLM_UUID_LIST", NULL }
1662
*
1663
* reply:
1664
* 1 user domain
1665
* 0 [ end of list ]
1666
*/
1667
1668
static krb5_error_code
1669
kcm_op_get_ntlm_user_list(krb5_context context,
1670
kcm_client *client,
1671
kcm_operation opcode,
1672
krb5_storage *request,
1673
krb5_storage *response)
1674
{
1675
struct kcm_ntlm_cred *c;
1676
krb5_error_code ret;
1677
1678
for (c = ntlm_head; c != NULL; c = c->next) {
1679
if (!kcm_is_same_session(client, c->uid, c->session))
1680
continue;
1681
1682
ret = krb5_store_uint32(response, 1);
1683
if (ret)
1684
return ret;
1685
ret = krb5_store_stringz(response, c->user);
1686
if (ret)
1687
return ret;
1688
ret = krb5_store_stringz(response, c->domain);
1689
if (ret)
1690
return ret;
1691
}
1692
return krb5_store_uint32(response, 0);
1693
}
1694
1695
/*
1696
*
1697
*/
1698
1699
static struct kcm_op kcm_ops[] = {
1700
{ "NOOP", kcm_op_noop },
1701
{ "GET_NAME", kcm_op_get_name },
1702
{ "RESOLVE", kcm_op_noop },
1703
{ "GEN_NEW", kcm_op_gen_new },
1704
{ "INITIALIZE", kcm_op_initialize },
1705
{ "DESTROY", kcm_op_destroy },
1706
{ "STORE", kcm_op_store },
1707
{ "RETRIEVE", kcm_op_retrieve },
1708
{ "GET_PRINCIPAL", kcm_op_get_principal },
1709
{ "GET_CRED_UUID_LIST", kcm_op_get_cred_uuid_list },
1710
{ "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid },
1711
{ "REMOVE_CRED", kcm_op_remove_cred },
1712
{ "SET_FLAGS", kcm_op_set_flags },
1713
{ "CHOWN", kcm_op_chown },
1714
{ "CHMOD", kcm_op_chmod },
1715
{ "GET_INITIAL_TICKET", kcm_op_get_initial_ticket },
1716
{ "GET_TICKET", kcm_op_get_ticket },
1717
{ "MOVE_CACHE", kcm_op_move_cache },
1718
{ "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list },
1719
{ "GET_CACHE_BY_UUID", kcm_op_get_cache_by_uuid },
1720
{ "GET_DEFAULT_CACHE", kcm_op_get_default_cache },
1721
{ "SET_DEFAULT_CACHE", kcm_op_set_default_cache },
1722
{ "GET_KDC_OFFSET", kcm_op_get_kdc_offset },
1723
{ "SET_KDC_OFFSET", kcm_op_set_kdc_offset },
1724
{ "ADD_NTLM_CRED", kcm_op_add_ntlm_cred },
1725
{ "HAVE_USER_CRED", kcm_op_have_ntlm_cred },
1726
{ "DEL_NTLM_CRED", kcm_op_del_ntlm_cred },
1727
{ "DO_NTLM_AUTH", kcm_op_do_ntlm },
1728
{ "GET_NTLM_USER_LIST", kcm_op_get_ntlm_user_list }
1729
};
1730
1731
1732
const char *
1733
kcm_op2string(kcm_operation opcode)
1734
{
1735
if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0]))
1736
return "Unknown operation";
1737
1738
return kcm_ops[opcode].name;
1739
}
1740
1741
krb5_error_code
1742
kcm_dispatch(krb5_context context,
1743
kcm_client *client,
1744
krb5_data *req_data,
1745
krb5_data *resp_data)
1746
{
1747
krb5_error_code ret;
1748
kcm_method method;
1749
krb5_storage *req_sp = NULL;
1750
krb5_storage *resp_sp = NULL;
1751
uint16_t opcode;
1752
1753
resp_sp = krb5_storage_emem();
1754
if (resp_sp == NULL) {
1755
return ENOMEM;
1756
}
1757
1758
if (client->pid == -1) {
1759
kcm_log(0, "Client had invalid process number");
1760
ret = KRB5_FCC_INTERNAL;
1761
goto out;
1762
}
1763
1764
req_sp = krb5_storage_from_data(req_data);
1765
if (req_sp == NULL) {
1766
kcm_log(0, "Process %d: failed to initialize storage from data",
1767
client->pid);
1768
ret = KRB5_CC_IO;
1769
goto out;
1770
}
1771
1772
ret = krb5_ret_uint16(req_sp, &opcode);
1773
if (ret) {
1774
kcm_log(0, "Process %d: didn't send a message", client->pid);
1775
goto out;
1776
}
1777
1778
if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) {
1779
kcm_log(0, "Process %d: invalid operation code %d",
1780
client->pid, opcode);
1781
ret = KRB5_FCC_INTERNAL;
1782
goto out;
1783
}
1784
method = kcm_ops[opcode].method;
1785
if (method == NULL) {
1786
kcm_log(0, "Process %d: operation code %s not implemented",
1787
client->pid, kcm_op2string(opcode));
1788
ret = KRB5_FCC_INTERNAL;
1789
goto out;
1790
}
1791
1792
/* seek past place for status code */
1793
krb5_storage_seek(resp_sp, 4, SEEK_SET);
1794
1795
ret = (*method)(context, client, opcode, req_sp, resp_sp);
1796
1797
out:
1798
if (req_sp != NULL) {
1799
krb5_storage_free(req_sp);
1800
}
1801
1802
krb5_storage_seek(resp_sp, 0, SEEK_SET);
1803
krb5_store_int32(resp_sp, ret);
1804
1805
ret = krb5_storage_to_data(resp_sp, resp_data);
1806
krb5_storage_free(resp_sp);
1807
1808
return ret;
1809
}
1810
1811
1812