x
[heimdal.git] / kcm / protocol.c
blobed7e07d4d8c9cceb4ce4498213e9abadd430a9d6
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 krb5_error_code ret;
426 kcm_ccache ccache;
427 uint32_t cursor;
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 if (ret) {
439 free(name);
440 return ret;
443 ret = kcm_cursor_new(context, client->pid, ccache, &cursor);
444 if (ret) {
445 kcm_release_ccache(context, &ccache);
446 free(name);
447 return ret;
450 ret = krb5_store_int32(response, cursor);
452 free(name);
453 kcm_release_ccache(context, &ccache);
455 return ret;
459 * Request:
460 * NameZ
461 * Cursor
463 * Response:
464 * Creds
466 static krb5_error_code
467 kcm_op_get_next(krb5_context context,
468 kcm_client *client,
469 kcm_operation opcode,
470 krb5_storage *request,
471 krb5_storage *response)
473 krb5_error_code ret;
474 kcm_ccache ccache;
475 char *name;
476 uint32_t cursor;
477 kcm_cursor *c;
479 ret = krb5_ret_stringz(request, &name);
480 if (ret)
481 return ret;
483 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
485 ret = krb5_ret_uint32(request, &cursor);
486 if (ret) {
487 free(name);
488 return ret;
491 ret = kcm_ccache_resolve_client(context, client, opcode,
492 name, &ccache);
493 if (ret) {
494 free(name);
495 return ret;
498 ret = kcm_cursor_find(context, client->pid, ccache, cursor, &c);
499 if (ret) {
500 kcm_release_ccache(context, &ccache);
501 free(name);
502 return ret;
505 HEIMDAL_MUTEX_lock(&ccache->mutex);
506 if (c->credp == NULL) {
507 ret = KRB5_CC_END;
508 } else {
509 ret = krb5_store_creds(response, &c->credp->cred);
510 c->credp = c->credp->next;
512 HEIMDAL_MUTEX_unlock(&ccache->mutex);
514 free(name);
515 kcm_release_ccache(context, &ccache);
517 return ret;
521 * Request:
522 * NameZ
523 * Cursor
525 * Response:
528 static krb5_error_code
529 kcm_op_end_get(krb5_context context,
530 kcm_client *client,
531 kcm_operation opcode,
532 krb5_storage *request,
533 krb5_storage *response)
535 krb5_error_code ret;
536 kcm_ccache ccache;
537 uint32_t cursor;
538 char *name;
540 ret = krb5_ret_stringz(request, &name);
541 if (ret)
542 return ret;
544 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
546 ret = krb5_ret_uint32(request, &cursor);
547 if (ret) {
548 free(name);
549 return ret;
552 ret = kcm_ccache_resolve_client(context, client, opcode,
553 name, &ccache);
554 if (ret) {
555 free(name);
556 return ret;
559 ret = kcm_cursor_delete(context, client->pid, ccache, cursor);
561 free(name);
562 kcm_release_ccache(context, &ccache);
564 return ret;
568 * Request:
569 * NameZ
570 * WhichFields
571 * MatchCreds
573 * Response:
576 static krb5_error_code
577 kcm_op_remove_cred(krb5_context context,
578 kcm_client *client,
579 kcm_operation opcode,
580 krb5_storage *request,
581 krb5_storage *response)
583 uint32_t whichfields;
584 krb5_creds mcreds;
585 krb5_error_code ret;
586 kcm_ccache ccache;
587 char *name;
589 ret = krb5_ret_stringz(request, &name);
590 if (ret)
591 return ret;
593 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
595 ret = krb5_ret_uint32(request, &whichfields);
596 if (ret) {
597 free(name);
598 return ret;
601 ret = krb5_ret_creds_tag(request, &mcreds);
602 if (ret) {
603 free(name);
604 return ret;
607 ret = kcm_ccache_resolve_client(context, client, opcode,
608 name, &ccache);
609 if (ret) {
610 free(name);
611 krb5_free_cred_contents(context, &mcreds);
612 return ret;
615 ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds);
617 /* XXX need to remove any events that match */
619 free(name);
620 krb5_free_cred_contents(context, &mcreds);
621 kcm_release_ccache(context, &ccache);
623 return ret;
627 * Request:
628 * NameZ
629 * Flags
631 * Response:
634 static krb5_error_code
635 kcm_op_set_flags(krb5_context context,
636 kcm_client *client,
637 kcm_operation opcode,
638 krb5_storage *request,
639 krb5_storage *response)
641 uint32_t flags;
642 krb5_error_code ret;
643 kcm_ccache ccache;
644 char *name;
646 ret = krb5_ret_stringz(request, &name);
647 if (ret)
648 return ret;
650 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
652 ret = krb5_ret_uint32(request, &flags);
653 if (ret) {
654 free(name);
655 return ret;
658 ret = kcm_ccache_resolve_client(context, client, opcode,
659 name, &ccache);
660 if (ret) {
661 free(name);
662 return ret;
665 /* we don't really support any flags yet */
666 free(name);
667 kcm_release_ccache(context, &ccache);
669 return 0;
673 * Request:
674 * NameZ
675 * UID
676 * GID
678 * Response:
681 static krb5_error_code
682 kcm_op_chown(krb5_context context,
683 kcm_client *client,
684 kcm_operation opcode,
685 krb5_storage *request,
686 krb5_storage *response)
688 uint32_t uid;
689 uint32_t gid;
690 krb5_error_code ret;
691 kcm_ccache ccache;
692 char *name;
694 ret = krb5_ret_stringz(request, &name);
695 if (ret)
696 return ret;
698 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
700 ret = krb5_ret_uint32(request, &uid);
701 if (ret) {
702 free(name);
703 return ret;
706 ret = krb5_ret_uint32(request, &gid);
707 if (ret) {
708 free(name);
709 return ret;
712 ret = kcm_ccache_resolve_client(context, client, opcode,
713 name, &ccache);
714 if (ret) {
715 free(name);
716 return ret;
719 ret = kcm_chown(context, client, ccache, uid, gid);
721 free(name);
722 kcm_release_ccache(context, &ccache);
724 return ret;
728 * Request:
729 * NameZ
730 * Mode
732 * Response:
735 static krb5_error_code
736 kcm_op_chmod(krb5_context context,
737 kcm_client *client,
738 kcm_operation opcode,
739 krb5_storage *request,
740 krb5_storage *response)
742 uint16_t mode;
743 krb5_error_code ret;
744 kcm_ccache ccache;
745 char *name;
747 ret = krb5_ret_stringz(request, &name);
748 if (ret)
749 return ret;
751 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
753 ret = krb5_ret_uint16(request, &mode);
754 if (ret) {
755 free(name);
756 return ret;
759 ret = kcm_ccache_resolve_client(context, client, opcode,
760 name, &ccache);
761 if (ret) {
762 free(name);
763 return ret;
766 ret = kcm_chmod(context, client, ccache, mode);
768 free(name);
769 kcm_release_ccache(context, &ccache);
771 return ret;
775 * Protocol extensions for moving ticket acquisition responsibility
776 * from client to KCM follow.
780 * Request:
781 * NameZ
782 * ServerPrincipalPresent
783 * ServerPrincipal OPTIONAL
784 * Key
786 * Repsonse:
789 static krb5_error_code
790 kcm_op_get_initial_ticket(krb5_context context,
791 kcm_client *client,
792 kcm_operation opcode,
793 krb5_storage *request,
794 krb5_storage *response)
796 krb5_error_code ret;
797 kcm_ccache ccache;
798 char *name;
799 int8_t not_tgt = 0;
800 krb5_principal server = NULL;
801 krb5_keyblock key;
803 krb5_keyblock_zero(&key);
805 ret = krb5_ret_stringz(request, &name);
806 if (ret)
807 return ret;
809 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
811 ret = krb5_ret_int8(request, &not_tgt);
812 if (ret) {
813 free(name);
814 return ret;
817 if (not_tgt) {
818 ret = krb5_ret_principal(request, &server);
819 if (ret) {
820 free(name);
821 return ret;
825 ret = krb5_ret_keyblock(request, &key);
826 if (ret) {
827 free(name);
828 if (server != NULL)
829 krb5_free_principal(context, server);
830 return ret;
833 ret = kcm_ccache_resolve_client(context, client, opcode,
834 name, &ccache);
835 if (ret == 0) {
836 HEIMDAL_MUTEX_lock(&ccache->mutex);
838 if (ccache->server != NULL) {
839 krb5_free_principal(context, ccache->server);
840 ccache->server = NULL;
843 krb5_free_keyblock(context, &ccache->key.keyblock);
845 ccache->server = server;
846 ccache->key.keyblock = key;
847 ccache->flags |= KCM_FLAGS_USE_CACHED_KEY;
849 ret = kcm_ccache_enqueue_default(context, ccache, NULL);
850 if (ret) {
851 ccache->server = NULL;
852 krb5_keyblock_zero(&ccache->key.keyblock);
853 ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY);
856 HEIMDAL_MUTEX_unlock(&ccache->mutex);
859 free(name);
861 if (ret != 0) {
862 krb5_free_principal(context, server);
863 krb5_free_keyblock(context, &key);
866 kcm_release_ccache(context, &ccache);
868 return ret;
872 * Request:
873 * NameZ
874 * ServerPrincipal
875 * KDCFlags
876 * EncryptionType
878 * Repsonse:
881 static krb5_error_code
882 kcm_op_get_ticket(krb5_context context,
883 kcm_client *client,
884 kcm_operation opcode,
885 krb5_storage *request,
886 krb5_storage *response)
888 krb5_error_code ret;
889 kcm_ccache ccache;
890 char *name;
891 krb5_principal server = NULL;
892 krb5_ccache_data ccdata;
893 krb5_creds in, *out;
894 krb5_kdc_flags flags;
896 memset(&in, 0, sizeof(in));
898 ret = krb5_ret_stringz(request, &name);
899 if (ret)
900 return ret;
902 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
904 ret = krb5_ret_uint32(request, &flags.i);
905 if (ret) {
906 free(name);
907 return ret;
910 ret = krb5_ret_int32(request, &in.session.keytype);
911 if (ret) {
912 free(name);
913 return ret;
916 ret = krb5_ret_principal(request, &server);
917 if (ret) {
918 free(name);
919 return ret;
922 ret = kcm_ccache_resolve_client(context, client, opcode,
923 name, &ccache);
924 if (ret) {
925 krb5_free_principal(context, server);
926 free(name);
927 return ret;
930 HEIMDAL_MUTEX_lock(&ccache->mutex);
932 /* Fake up an internal ccache */
933 kcm_internal_ccache(context, ccache, &ccdata);
935 in.client = ccache->client;
936 in.server = server;
937 in.times.endtime = 0;
939 /* glue cc layer will store creds */
940 ret = krb5_get_credentials_with_flags(context, 0, flags,
941 &ccdata, &in, &out);
943 HEIMDAL_MUTEX_unlock(&ccache->mutex);
945 if (ret == 0)
946 krb5_free_cred_contents(context, out);
948 free(name);
950 return ret;
954 * Request:
955 * OldNameZ
956 * NewNameZ
958 * Repsonse:
961 static krb5_error_code
962 kcm_op_move_cache(krb5_context context,
963 kcm_client *client,
964 kcm_operation opcode,
965 krb5_storage *request,
966 krb5_storage *response)
968 krb5_error_code ret;
969 kcm_ccache oldid, newid;
970 char *oldname, *newname;
972 ret = krb5_ret_stringz(request, &oldname);
973 if (ret)
974 return ret;
976 KCM_LOG_REQUEST_NAME(context, client, opcode, oldname);
978 ret = krb5_ret_stringz(request, &newname);
979 if (ret) {
980 free(oldname);
981 return ret;
984 ret = kcm_ccache_resolve_client(context, client, opcode, oldname, &oldid);
985 if (ret) {
986 free(oldname);
987 free(newname);
988 return ret;
991 /* Check if new credential cache exists, if not create one. */
992 ret = kcm_ccache_resolve_client(context, client, opcode, newname, &newid);
993 if (ret == KRB5_FCC_NOFILE)
994 ret = kcm_ccache_new_client(context, client, newname, &newid);
995 free(newname);
997 if (ret) {
998 free(oldname);
999 kcm_release_ccache(context, &oldid);
1000 return ret;
1003 HEIMDAL_MUTEX_lock(&oldid->mutex);
1004 HEIMDAL_MUTEX_lock(&newid->mutex);
1006 /* move content */
1008 kcm_ccache_data tmp;
1010 #define MOVE(n,o,f) { tmp.f = n->f ; n->f = o->f; o->f = tmp.f; }
1012 MOVE(newid, oldid, flags);
1013 MOVE(newid, oldid, client);
1014 MOVE(newid, oldid, server);
1015 MOVE(newid, oldid, creds);
1016 MOVE(newid, oldid, tkt_life);
1017 MOVE(newid, oldid, renew_life);
1018 MOVE(newid, oldid, key);
1019 MOVE(newid, oldid, key);
1020 #undef MOVE
1023 HEIMDAL_MUTEX_unlock(&oldid->mutex);
1024 HEIMDAL_MUTEX_unlock(&newid->mutex);
1026 kcm_release_ccache(context, &oldid);
1027 kcm_release_ccache(context, &newid);
1029 ret = kcm_ccache_destroy_client(context, client, oldname);
1031 free(oldname);
1033 return ret;
1037 static struct kcm_op kcm_ops[] = {
1038 { "NOOP", kcm_op_noop },
1039 { "GET_NAME", kcm_op_get_name },
1040 { "RESOLVE", kcm_op_noop },
1041 { "GEN_NEW", kcm_op_gen_new },
1042 { "INITIALIZE", kcm_op_initialize },
1043 { "DESTROY", kcm_op_destroy },
1044 { "STORE", kcm_op_store },
1045 { "RETRIEVE", kcm_op_retrieve },
1046 { "GET_PRINCIPAL", kcm_op_get_principal },
1047 { "GET_FIRST", kcm_op_get_first },
1048 { "GET_NEXT", kcm_op_get_next },
1049 { "END_GET", kcm_op_end_get },
1050 { "REMOVE_CRED", kcm_op_remove_cred },
1051 { "SET_FLAGS", kcm_op_set_flags },
1052 { "CHOWN", kcm_op_chown },
1053 { "CHMOD", kcm_op_chmod },
1054 { "GET_INITIAL_TICKET", kcm_op_get_initial_ticket },
1055 { "GET_TICKET", kcm_op_get_ticket },
1056 { "MOVE_CACHE", kcm_op_move_cache }
1060 const char *kcm_op2string(kcm_operation opcode)
1062 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0]))
1063 return "Unknown operation";
1065 return kcm_ops[opcode].name;
1068 krb5_error_code
1069 kcm_dispatch(krb5_context context,
1070 kcm_client *client,
1071 krb5_data *req_data,
1072 krb5_data *resp_data)
1074 krb5_error_code ret;
1075 kcm_method method;
1076 krb5_storage *req_sp = NULL;
1077 krb5_storage *resp_sp = NULL;
1078 uint16_t opcode;
1080 resp_sp = krb5_storage_emem();
1081 if (resp_sp == NULL) {
1082 return ENOMEM;
1085 if (client->pid == -1) {
1086 kcm_log(0, "Client had invalid process number");
1087 ret = KRB5_FCC_INTERNAL;
1088 goto out;
1091 req_sp = krb5_storage_from_data(req_data);
1092 if (req_sp == NULL) {
1093 kcm_log(0, "Process %d: failed to initialize storage from data",
1094 client->pid);
1095 ret = KRB5_CC_IO;
1096 goto out;
1099 ret = krb5_ret_uint16(req_sp, &opcode);
1100 if (ret) {
1101 kcm_log(0, "Process %d: didn't send a message", client->pid);
1102 goto out;
1105 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) {
1106 kcm_log(0, "Process %d: invalid operation code %d",
1107 client->pid, opcode);
1108 ret = KRB5_FCC_INTERNAL;
1109 goto out;
1111 method = kcm_ops[opcode].method;
1113 /* seek past place for status code */
1114 krb5_storage_seek(resp_sp, 4, SEEK_SET);
1116 ret = (*method)(context, client, opcode, req_sp, resp_sp);
1118 out:
1119 if (req_sp != NULL) {
1120 krb5_storage_free(req_sp);
1123 krb5_storage_seek(resp_sp, 0, SEEK_SET);
1124 krb5_store_int32(resp_sp, ret);
1126 ret = krb5_storage_to_data(resp_sp, resp_data);
1127 krb5_storage_free(resp_sp);
1129 return ret;