If client tried IPv6, but service only listened on IPv4
[heimdal.git] / kcm / protocol.c
blob3627007679646814e4d41173204d54d23394fe15
1 /*
2 * Copyright (c) 2005, PADL Software Pty Ltd.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of PADL Software nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include "kcm_locl.h"
35 RCSID("$Id$");
37 static krb5_error_code
38 kcm_op_noop(krb5_context context,
39 kcm_client *client,
40 kcm_operation opcode,
41 krb5_storage *request,
42 krb5_storage *response)
44 KCM_LOG_REQUEST(context, client, opcode);
46 return 0;
50 * Request:
51 * NameZ
52 * Response:
53 * NameZ
56 static krb5_error_code
57 kcm_op_get_name(krb5_context context,
58 kcm_client *client,
59 kcm_operation opcode,
60 krb5_storage *request,
61 krb5_storage *response)
64 krb5_error_code ret;
65 char *name = NULL;
66 kcm_ccache ccache;
68 ret = krb5_ret_stringz(request, &name);
69 if (ret)
70 return ret;
72 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
74 ret = kcm_ccache_resolve_client(context, client, opcode,
75 name, &ccache);
76 if (ret) {
77 free(name);
78 return ret;
81 ret = krb5_store_stringz(response, ccache->name);
82 if (ret) {
83 kcm_release_ccache(context, &ccache);
84 free(name);
85 return ret;
88 free(name);
89 kcm_release_ccache(context, &ccache);
90 return 0;
94 * Request:
96 * Response:
97 * NameZ
99 static krb5_error_code
100 kcm_op_gen_new(krb5_context context,
101 kcm_client *client,
102 kcm_operation opcode,
103 krb5_storage *request,
104 krb5_storage *response)
106 krb5_error_code ret;
107 char *name;
109 KCM_LOG_REQUEST(context, client, opcode);
111 name = kcm_ccache_nextid(client->pid, client->uid, client->gid);
112 if (name == NULL) {
113 return KRB5_CC_NOMEM;
116 ret = krb5_store_stringz(response, name);
117 free(name);
119 return ret;
123 * Request:
124 * NameZ
125 * Principal
127 * Response:
130 static krb5_error_code
131 kcm_op_initialize(krb5_context context,
132 kcm_client *client,
133 kcm_operation opcode,
134 krb5_storage *request,
135 krb5_storage *response)
137 kcm_ccache ccache;
138 krb5_principal principal;
139 krb5_error_code ret;
140 char *name;
141 #if 0
142 kcm_event event;
143 #endif
145 KCM_LOG_REQUEST(context, client, opcode);
147 ret = krb5_ret_stringz(request, &name);
148 if (ret)
149 return ret;
151 ret = krb5_ret_principal(request, &principal);
152 if (ret) {
153 free(name);
154 return ret;
157 ret = kcm_ccache_new_client(context, client, name, &ccache);
158 if (ret) {
159 free(name);
160 krb5_free_principal(context, principal);
161 return ret;
164 ccache->client = principal;
166 free(name);
168 #if 0
170 * Create a new credentials cache. To mitigate DoS attacks we will
171 * expire it in 30 minutes unless it has some credentials added
172 * to it
175 event.fire_time = 30 * 60;
176 event.expire_time = 0;
177 event.backoff_time = 0;
178 event.action = KCM_EVENT_DESTROY_EMPTY_CACHE;
179 event.ccache = ccache;
181 ret = kcm_enqueue_event_relative(context, &event);
182 #endif
184 kcm_release_ccache(context, &ccache);
186 return ret;
190 * Request:
191 * NameZ
193 * Response:
196 static krb5_error_code
197 kcm_op_destroy(krb5_context context,
198 kcm_client *client,
199 kcm_operation opcode,
200 krb5_storage *request,
201 krb5_storage *response)
203 krb5_error_code ret;
204 char *name;
206 ret = krb5_ret_stringz(request, &name);
207 if (ret)
208 return ret;
210 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
212 ret = kcm_ccache_destroy_client(context, client, name);
214 free(name);
216 return ret;
220 * Request:
221 * NameZ
222 * Creds
224 * Response:
227 static krb5_error_code
228 kcm_op_store(krb5_context context,
229 kcm_client *client,
230 kcm_operation opcode,
231 krb5_storage *request,
232 krb5_storage *response)
234 krb5_creds creds;
235 krb5_error_code ret;
236 kcm_ccache ccache;
237 char *name;
239 ret = krb5_ret_stringz(request, &name);
240 if (ret)
241 return ret;
243 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
245 ret = krb5_ret_creds(request, &creds);
246 if (ret) {
247 free(name);
248 return ret;
251 ret = kcm_ccache_resolve_client(context, client, opcode,
252 name, &ccache);
253 if (ret) {
254 free(name);
255 krb5_free_cred_contents(context, &creds);
256 return ret;
259 ret = kcm_ccache_store_cred(context, ccache, &creds, 0);
260 if (ret) {
261 free(name);
262 krb5_free_cred_contents(context, &creds);
263 kcm_release_ccache(context, &ccache);
264 return ret;
267 kcm_ccache_enqueue_default(context, ccache, &creds);
269 free(name);
270 kcm_release_ccache(context, &ccache);
272 return 0;
276 * Request:
277 * NameZ
278 * WhichFields
279 * MatchCreds
281 * Response:
282 * Creds
285 static krb5_error_code
286 kcm_op_retrieve(krb5_context context,
287 kcm_client *client,
288 kcm_operation opcode,
289 krb5_storage *request,
290 krb5_storage *response)
292 uint32_t flags;
293 krb5_creds mcreds;
294 krb5_error_code ret;
295 kcm_ccache ccache;
296 char *name;
297 krb5_creds *credp;
298 int free_creds = 0;
300 ret = krb5_ret_stringz(request, &name);
301 if (ret)
302 return ret;
304 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
306 ret = krb5_ret_uint32(request, &flags);
307 if (ret) {
308 free(name);
309 return ret;
312 ret = krb5_ret_creds_tag(request, &mcreds);
313 if (ret) {
314 free(name);
315 return ret;
318 if (disallow_getting_krbtgt &&
319 mcreds.server->name.name_string.len == 2 &&
320 strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0)
322 free(name);
323 krb5_free_cred_contents(context, &mcreds);
324 return KRB5_FCC_PERM;
327 ret = kcm_ccache_resolve_client(context, client, opcode,
328 name, &ccache);
329 if (ret) {
330 free(name);
331 krb5_free_cred_contents(context, &mcreds);
332 return ret;
335 ret = kcm_ccache_retrieve_cred(context, ccache, flags,
336 &mcreds, &credp);
337 if (ret && ((flags & KRB5_GC_CACHED) == 0)) {
338 krb5_ccache_data ccdata;
340 /* try and acquire */
341 HEIMDAL_MUTEX_lock(&ccache->mutex);
343 /* Fake up an internal ccache */
344 kcm_internal_ccache(context, ccache, &ccdata);
346 /* glue cc layer will store creds */
347 ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp);
348 if (ret == 0)
349 free_creds = 1;
351 HEIMDAL_MUTEX_unlock(&ccache->mutex);
354 if (ret == 0) {
355 ret = krb5_store_creds(response, credp);
358 free(name);
359 krb5_free_cred_contents(context, &mcreds);
360 kcm_release_ccache(context, &ccache);
362 if (free_creds)
363 krb5_free_cred_contents(context, credp);
365 return ret;
369 * Request:
370 * NameZ
372 * Response:
373 * Principal
375 static krb5_error_code
376 kcm_op_get_principal(krb5_context context,
377 kcm_client *client,
378 kcm_operation opcode,
379 krb5_storage *request,
380 krb5_storage *response)
382 krb5_error_code ret;
383 kcm_ccache ccache;
384 char *name;
386 ret = krb5_ret_stringz(request, &name);
387 if (ret)
388 return ret;
390 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
392 ret = kcm_ccache_resolve_client(context, client, opcode,
393 name, &ccache);
394 if (ret) {
395 free(name);
396 return ret;
399 if (ccache->client == NULL)
400 ret = KRB5_CC_NOTFOUND;
401 else
402 ret = krb5_store_principal(response, ccache->client);
404 free(name);
405 kcm_release_ccache(context, &ccache);
407 return 0;
411 * Request:
412 * NameZ
414 * Response:
415 * Cursor
418 static krb5_error_code
419 kcm_op_get_first(krb5_context context,
420 kcm_client *client,
421 kcm_operation opcode,
422 krb5_storage *request,
423 krb5_storage *response)
425 struct kcm_creds *creds;
426 krb5_error_code ret;
427 kcm_ccache ccache;
428 char *name;
430 ret = krb5_ret_stringz(request, &name);
431 if (ret)
432 return ret;
434 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
436 ret = kcm_ccache_resolve_client(context, client, opcode,
437 name, &ccache);
438 free(name);
439 if (ret)
440 return ret;
442 for (creds = ccache->creds ; creds ; creds = creds->next) {
443 ssize_t sret;
444 sret = krb5_storage_write(response, &creds->uuid, sizeof(creds->uuid));
445 if (sret != sizeof(creds->uuid)) {
446 ret = ENOMEM;
447 break;
451 kcm_release_ccache(context, &ccache);
453 return ret;
457 * Request:
458 * NameZ
459 * Cursor
461 * Response:
462 * Creds
464 static krb5_error_code
465 kcm_op_get_next(krb5_context context,
466 kcm_client *client,
467 kcm_operation opcode,
468 krb5_storage *request,
469 krb5_storage *response)
471 krb5_error_code ret;
472 kcm_ccache ccache;
473 char *name;
474 struct kcm_creds *c;
475 kcmuuid_t uuid;
476 ssize_t sret;
478 ret = krb5_ret_stringz(request, &name);
479 if (ret)
480 return ret;
482 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
484 ret = kcm_ccache_resolve_client(context, client, opcode,
485 name, &ccache);
486 free(name);
487 if (ret)
488 return ret;
490 sret = krb5_storage_read(request, &uuid, sizeof(uuid));
491 if (sret != sizeof(uuid)) {
492 kcm_release_ccache(context, &ccache);
493 krb5_clear_error_message(context);
494 return KRB5_CC_IO;
497 c = kcm_ccache_find_cred_uuid(context, ccache, uuid);
498 if (c == NULL) {
499 kcm_release_ccache(context, &ccache);
500 return KRB5_CC_END;
503 HEIMDAL_MUTEX_lock(&ccache->mutex);
504 ret = krb5_store_creds(response, &c->cred);
505 HEIMDAL_MUTEX_unlock(&ccache->mutex);
507 kcm_release_ccache(context, &ccache);
509 return ret;
513 * Request:
514 * NameZ
515 * Cursor
517 * Response:
520 static krb5_error_code
521 kcm_op_end_get(krb5_context context,
522 kcm_client *client,
523 kcm_operation opcode,
524 krb5_storage *request,
525 krb5_storage *response)
527 krb5_error_code ret;
528 char *name;
530 ret = krb5_ret_stringz(request, &name);
531 if (ret)
532 return ret;
534 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
535 free(name);
537 return ret;
541 * Request:
542 * NameZ
543 * WhichFields
544 * MatchCreds
546 * Response:
549 static krb5_error_code
550 kcm_op_remove_cred(krb5_context context,
551 kcm_client *client,
552 kcm_operation opcode,
553 krb5_storage *request,
554 krb5_storage *response)
556 uint32_t whichfields;
557 krb5_creds mcreds;
558 krb5_error_code ret;
559 kcm_ccache ccache;
560 char *name;
562 ret = krb5_ret_stringz(request, &name);
563 if (ret)
564 return ret;
566 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
568 ret = krb5_ret_uint32(request, &whichfields);
569 if (ret) {
570 free(name);
571 return ret;
574 ret = krb5_ret_creds_tag(request, &mcreds);
575 if (ret) {
576 free(name);
577 return ret;
580 ret = kcm_ccache_resolve_client(context, client, opcode,
581 name, &ccache);
582 if (ret) {
583 free(name);
584 krb5_free_cred_contents(context, &mcreds);
585 return ret;
588 ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds);
590 /* XXX need to remove any events that match */
592 free(name);
593 krb5_free_cred_contents(context, &mcreds);
594 kcm_release_ccache(context, &ccache);
596 return ret;
600 * Request:
601 * NameZ
602 * Flags
604 * Response:
607 static krb5_error_code
608 kcm_op_set_flags(krb5_context context,
609 kcm_client *client,
610 kcm_operation opcode,
611 krb5_storage *request,
612 krb5_storage *response)
614 uint32_t flags;
615 krb5_error_code ret;
616 kcm_ccache ccache;
617 char *name;
619 ret = krb5_ret_stringz(request, &name);
620 if (ret)
621 return ret;
623 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
625 ret = krb5_ret_uint32(request, &flags);
626 if (ret) {
627 free(name);
628 return ret;
631 ret = kcm_ccache_resolve_client(context, client, opcode,
632 name, &ccache);
633 if (ret) {
634 free(name);
635 return ret;
638 /* we don't really support any flags yet */
639 free(name);
640 kcm_release_ccache(context, &ccache);
642 return 0;
646 * Request:
647 * NameZ
648 * UID
649 * GID
651 * Response:
654 static krb5_error_code
655 kcm_op_chown(krb5_context context,
656 kcm_client *client,
657 kcm_operation opcode,
658 krb5_storage *request,
659 krb5_storage *response)
661 uint32_t uid;
662 uint32_t gid;
663 krb5_error_code ret;
664 kcm_ccache ccache;
665 char *name;
667 ret = krb5_ret_stringz(request, &name);
668 if (ret)
669 return ret;
671 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
673 ret = krb5_ret_uint32(request, &uid);
674 if (ret) {
675 free(name);
676 return ret;
679 ret = krb5_ret_uint32(request, &gid);
680 if (ret) {
681 free(name);
682 return ret;
685 ret = kcm_ccache_resolve_client(context, client, opcode,
686 name, &ccache);
687 if (ret) {
688 free(name);
689 return ret;
692 ret = kcm_chown(context, client, ccache, uid, gid);
694 free(name);
695 kcm_release_ccache(context, &ccache);
697 return ret;
701 * Request:
702 * NameZ
703 * Mode
705 * Response:
708 static krb5_error_code
709 kcm_op_chmod(krb5_context context,
710 kcm_client *client,
711 kcm_operation opcode,
712 krb5_storage *request,
713 krb5_storage *response)
715 uint16_t mode;
716 krb5_error_code ret;
717 kcm_ccache ccache;
718 char *name;
720 ret = krb5_ret_stringz(request, &name);
721 if (ret)
722 return ret;
724 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
726 ret = krb5_ret_uint16(request, &mode);
727 if (ret) {
728 free(name);
729 return ret;
732 ret = kcm_ccache_resolve_client(context, client, opcode,
733 name, &ccache);
734 if (ret) {
735 free(name);
736 return ret;
739 ret = kcm_chmod(context, client, ccache, mode);
741 free(name);
742 kcm_release_ccache(context, &ccache);
744 return ret;
748 * Protocol extensions for moving ticket acquisition responsibility
749 * from client to KCM follow.
753 * Request:
754 * NameZ
755 * ServerPrincipalPresent
756 * ServerPrincipal OPTIONAL
757 * Key
759 * Repsonse:
762 static krb5_error_code
763 kcm_op_get_initial_ticket(krb5_context context,
764 kcm_client *client,
765 kcm_operation opcode,
766 krb5_storage *request,
767 krb5_storage *response)
769 krb5_error_code ret;
770 kcm_ccache ccache;
771 char *name;
772 int8_t not_tgt = 0;
773 krb5_principal server = NULL;
774 krb5_keyblock key;
776 krb5_keyblock_zero(&key);
778 ret = krb5_ret_stringz(request, &name);
779 if (ret)
780 return ret;
782 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
784 ret = krb5_ret_int8(request, &not_tgt);
785 if (ret) {
786 free(name);
787 return ret;
790 if (not_tgt) {
791 ret = krb5_ret_principal(request, &server);
792 if (ret) {
793 free(name);
794 return ret;
798 ret = krb5_ret_keyblock(request, &key);
799 if (ret) {
800 free(name);
801 if (server != NULL)
802 krb5_free_principal(context, server);
803 return ret;
806 ret = kcm_ccache_resolve_client(context, client, opcode,
807 name, &ccache);
808 if (ret == 0) {
809 HEIMDAL_MUTEX_lock(&ccache->mutex);
811 if (ccache->server != NULL) {
812 krb5_free_principal(context, ccache->server);
813 ccache->server = NULL;
816 krb5_free_keyblock(context, &ccache->key.keyblock);
818 ccache->server = server;
819 ccache->key.keyblock = key;
820 ccache->flags |= KCM_FLAGS_USE_CACHED_KEY;
822 ret = kcm_ccache_enqueue_default(context, ccache, NULL);
823 if (ret) {
824 ccache->server = NULL;
825 krb5_keyblock_zero(&ccache->key.keyblock);
826 ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY);
829 HEIMDAL_MUTEX_unlock(&ccache->mutex);
832 free(name);
834 if (ret != 0) {
835 krb5_free_principal(context, server);
836 krb5_free_keyblock(context, &key);
839 kcm_release_ccache(context, &ccache);
841 return ret;
845 * Request:
846 * NameZ
847 * ServerPrincipal
848 * KDCFlags
849 * EncryptionType
851 * Repsonse:
854 static krb5_error_code
855 kcm_op_get_ticket(krb5_context context,
856 kcm_client *client,
857 kcm_operation opcode,
858 krb5_storage *request,
859 krb5_storage *response)
861 krb5_error_code ret;
862 kcm_ccache ccache;
863 char *name;
864 krb5_principal server = NULL;
865 krb5_ccache_data ccdata;
866 krb5_creds in, *out;
867 krb5_kdc_flags flags;
869 memset(&in, 0, sizeof(in));
871 ret = krb5_ret_stringz(request, &name);
872 if (ret)
873 return ret;
875 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
877 ret = krb5_ret_uint32(request, &flags.i);
878 if (ret) {
879 free(name);
880 return ret;
883 ret = krb5_ret_int32(request, &in.session.keytype);
884 if (ret) {
885 free(name);
886 return ret;
889 ret = krb5_ret_principal(request, &server);
890 if (ret) {
891 free(name);
892 return ret;
895 ret = kcm_ccache_resolve_client(context, client, opcode,
896 name, &ccache);
897 if (ret) {
898 krb5_free_principal(context, server);
899 free(name);
900 return ret;
903 HEIMDAL_MUTEX_lock(&ccache->mutex);
905 /* Fake up an internal ccache */
906 kcm_internal_ccache(context, ccache, &ccdata);
908 in.client = ccache->client;
909 in.server = server;
910 in.times.endtime = 0;
912 /* glue cc layer will store creds */
913 ret = krb5_get_credentials_with_flags(context, 0, flags,
914 &ccdata, &in, &out);
916 HEIMDAL_MUTEX_unlock(&ccache->mutex);
918 if (ret == 0)
919 krb5_free_cred_contents(context, out);
921 free(name);
923 return ret;
927 * Request:
928 * OldNameZ
929 * NewNameZ
931 * Repsonse:
934 static krb5_error_code
935 kcm_op_move_cache(krb5_context context,
936 kcm_client *client,
937 kcm_operation opcode,
938 krb5_storage *request,
939 krb5_storage *response)
941 krb5_error_code ret;
942 kcm_ccache oldid, newid;
943 char *oldname, *newname;
945 ret = krb5_ret_stringz(request, &oldname);
946 if (ret)
947 return ret;
949 KCM_LOG_REQUEST_NAME(context, client, opcode, oldname);
951 ret = krb5_ret_stringz(request, &newname);
952 if (ret) {
953 free(oldname);
954 return ret;
957 ret = kcm_ccache_resolve_client(context, client, opcode, oldname, &oldid);
958 if (ret) {
959 free(oldname);
960 free(newname);
961 return ret;
964 /* Check if new credential cache exists, if not create one. */
965 ret = kcm_ccache_resolve_client(context, client, opcode, newname, &newid);
966 if (ret == KRB5_FCC_NOFILE)
967 ret = kcm_ccache_new_client(context, client, newname, &newid);
968 free(newname);
970 if (ret) {
971 free(oldname);
972 kcm_release_ccache(context, &oldid);
973 return ret;
976 HEIMDAL_MUTEX_lock(&oldid->mutex);
977 HEIMDAL_MUTEX_lock(&newid->mutex);
979 /* move content */
981 kcm_ccache_data tmp;
983 #define MOVE(n,o,f) { tmp.f = n->f ; n->f = o->f; o->f = tmp.f; }
985 MOVE(newid, oldid, flags);
986 MOVE(newid, oldid, client);
987 MOVE(newid, oldid, server);
988 MOVE(newid, oldid, creds);
989 MOVE(newid, oldid, tkt_life);
990 MOVE(newid, oldid, renew_life);
991 MOVE(newid, oldid, key);
992 MOVE(newid, oldid, key);
993 #undef MOVE
996 HEIMDAL_MUTEX_unlock(&oldid->mutex);
997 HEIMDAL_MUTEX_unlock(&newid->mutex);
999 kcm_release_ccache(context, &oldid);
1000 kcm_release_ccache(context, &newid);
1002 ret = kcm_ccache_destroy_client(context, client, oldname);
1004 free(oldname);
1006 return ret;
1010 static struct kcm_op kcm_ops[] = {
1011 { "NOOP", kcm_op_noop },
1012 { "GET_NAME", kcm_op_get_name },
1013 { "RESOLVE", kcm_op_noop },
1014 { "GEN_NEW", kcm_op_gen_new },
1015 { "INITIALIZE", kcm_op_initialize },
1016 { "DESTROY", kcm_op_destroy },
1017 { "STORE", kcm_op_store },
1018 { "RETRIEVE", kcm_op_retrieve },
1019 { "GET_PRINCIPAL", kcm_op_get_principal },
1020 { "GET_FIRST", kcm_op_get_first },
1021 { "GET_NEXT", kcm_op_get_next },
1022 { "END_GET", kcm_op_end_get },
1023 { "REMOVE_CRED", kcm_op_remove_cred },
1024 { "SET_FLAGS", kcm_op_set_flags },
1025 { "CHOWN", kcm_op_chown },
1026 { "CHMOD", kcm_op_chmod },
1027 { "GET_INITIAL_TICKET", kcm_op_get_initial_ticket },
1028 { "GET_TICKET", kcm_op_get_ticket },
1029 { "MOVE_CACHE", kcm_op_move_cache }
1033 const char *kcm_op2string(kcm_operation opcode)
1035 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0]))
1036 return "Unknown operation";
1038 return kcm_ops[opcode].name;
1041 krb5_error_code
1042 kcm_dispatch(krb5_context context,
1043 kcm_client *client,
1044 krb5_data *req_data,
1045 krb5_data *resp_data)
1047 krb5_error_code ret;
1048 kcm_method method;
1049 krb5_storage *req_sp = NULL;
1050 krb5_storage *resp_sp = NULL;
1051 uint16_t opcode;
1053 resp_sp = krb5_storage_emem();
1054 if (resp_sp == NULL) {
1055 return ENOMEM;
1058 if (client->pid == -1) {
1059 kcm_log(0, "Client had invalid process number");
1060 ret = KRB5_FCC_INTERNAL;
1061 goto out;
1064 req_sp = krb5_storage_from_data(req_data);
1065 if (req_sp == NULL) {
1066 kcm_log(0, "Process %d: failed to initialize storage from data",
1067 client->pid);
1068 ret = KRB5_CC_IO;
1069 goto out;
1072 ret = krb5_ret_uint16(req_sp, &opcode);
1073 if (ret) {
1074 kcm_log(0, "Process %d: didn't send a message", client->pid);
1075 goto out;
1078 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) {
1079 kcm_log(0, "Process %d: invalid operation code %d",
1080 client->pid, opcode);
1081 ret = KRB5_FCC_INTERNAL;
1082 goto out;
1084 method = kcm_ops[opcode].method;
1086 /* seek past place for status code */
1087 krb5_storage_seek(resp_sp, 4, SEEK_SET);
1089 ret = (*method)(context, client, opcode, req_sp, resp_sp);
1091 out:
1092 if (req_sp != NULL) {
1093 krb5_storage_free(req_sp);
1096 krb5_storage_seek(resp_sp, 0, SEEK_SET);
1097 krb5_store_int32(resp_sp, ret);
1099 ret = krb5_storage_to_data(resp_sp, resp_data);
1100 krb5_storage_free(resp_sp);
1102 return ret;