No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / kcm / protocol.c
blobe360f49d615e6e5f010673ec67230a052ff0adbf
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("$Heimdal: protocol.c 22112 2007-12-03 19:34:33Z lha $"
36 "$NetBSD$");
38 static krb5_error_code
39 kcm_op_noop(krb5_context context,
40 kcm_client *client,
41 kcm_operation opcode,
42 krb5_storage *request,
43 krb5_storage *response)
45 KCM_LOG_REQUEST(context, client, opcode);
47 return 0;
51 * Request:
52 * NameZ
53 * Response:
54 * NameZ
57 static krb5_error_code
58 kcm_op_get_name(krb5_context context,
59 kcm_client *client,
60 kcm_operation opcode,
61 krb5_storage *request,
62 krb5_storage *response)
65 krb5_error_code ret;
66 char *name = NULL;
67 kcm_ccache ccache;
69 ret = krb5_ret_stringz(request, &name);
70 if (ret)
71 return ret;
73 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
75 ret = kcm_ccache_resolve_client(context, client, opcode,
76 name, &ccache);
77 if (ret) {
78 free(name);
79 return ret;
82 ret = krb5_store_stringz(response, ccache->name);
83 if (ret) {
84 kcm_release_ccache(context, &ccache);
85 free(name);
86 return ret;
89 free(name);
90 kcm_release_ccache(context, &ccache);
91 return 0;
95 * Request:
97 * Response:
98 * NameZ
100 static krb5_error_code
101 kcm_op_gen_new(krb5_context context,
102 kcm_client *client,
103 kcm_operation opcode,
104 krb5_storage *request,
105 krb5_storage *response)
107 krb5_error_code ret;
108 char *name;
110 KCM_LOG_REQUEST(context, client, opcode);
112 name = kcm_ccache_nextid(client->pid, client->uid, client->gid);
113 if (name == NULL) {
114 return KRB5_CC_NOMEM;
117 ret = krb5_store_stringz(response, name);
118 free(name);
120 return ret;
124 * Request:
125 * NameZ
126 * Principal
128 * Response:
131 static krb5_error_code
132 kcm_op_initialize(krb5_context context,
133 kcm_client *client,
134 kcm_operation opcode,
135 krb5_storage *request,
136 krb5_storage *response)
138 kcm_ccache ccache;
139 krb5_principal principal;
140 krb5_error_code ret;
141 char *name;
142 #if 0
143 kcm_event event;
144 #endif
146 KCM_LOG_REQUEST(context, client, opcode);
148 ret = krb5_ret_stringz(request, &name);
149 if (ret)
150 return ret;
152 ret = krb5_ret_principal(request, &principal);
153 if (ret) {
154 free(name);
155 return ret;
158 ret = kcm_ccache_new_client(context, client, name, &ccache);
159 if (ret) {
160 free(name);
161 krb5_free_principal(context, principal);
162 return ret;
165 ccache->client = principal;
167 free(name);
169 #if 0
171 * Create a new credentials cache. To mitigate DoS attacks we will
172 * expire it in 30 minutes unless it has some credentials added
173 * to it
176 event.fire_time = 30 * 60;
177 event.expire_time = 0;
178 event.backoff_time = 0;
179 event.action = KCM_EVENT_DESTROY_EMPTY_CACHE;
180 event.ccache = ccache;
182 ret = kcm_enqueue_event_relative(context, &event);
183 #endif
185 kcm_release_ccache(context, &ccache);
187 return ret;
191 * Request:
192 * NameZ
194 * Response:
197 static krb5_error_code
198 kcm_op_destroy(krb5_context context,
199 kcm_client *client,
200 kcm_operation opcode,
201 krb5_storage *request,
202 krb5_storage *response)
204 krb5_error_code ret;
205 char *name;
207 ret = krb5_ret_stringz(request, &name);
208 if (ret)
209 return ret;
211 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
213 ret = kcm_ccache_destroy_client(context, client, name);
215 free(name);
217 return ret;
221 * Request:
222 * NameZ
223 * Creds
225 * Response:
228 static krb5_error_code
229 kcm_op_store(krb5_context context,
230 kcm_client *client,
231 kcm_operation opcode,
232 krb5_storage *request,
233 krb5_storage *response)
235 krb5_creds creds;
236 krb5_error_code ret;
237 kcm_ccache ccache;
238 char *name;
240 ret = krb5_ret_stringz(request, &name);
241 if (ret)
242 return ret;
244 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
246 ret = krb5_ret_creds(request, &creds);
247 if (ret) {
248 free(name);
249 return ret;
252 ret = kcm_ccache_resolve_client(context, client, opcode,
253 name, &ccache);
254 if (ret) {
255 free(name);
256 krb5_free_cred_contents(context, &creds);
257 return ret;
260 ret = kcm_ccache_store_cred(context, ccache, &creds, 0);
261 if (ret) {
262 free(name);
263 krb5_free_cred_contents(context, &creds);
264 kcm_release_ccache(context, &ccache);
265 return ret;
268 kcm_ccache_enqueue_default(context, ccache, &creds);
270 free(name);
271 kcm_release_ccache(context, &ccache);
273 return 0;
277 * Request:
278 * NameZ
279 * WhichFields
280 * MatchCreds
282 * Response:
283 * Creds
286 static krb5_error_code
287 kcm_op_retrieve(krb5_context context,
288 kcm_client *client,
289 kcm_operation opcode,
290 krb5_storage *request,
291 krb5_storage *response)
293 uint32_t flags;
294 krb5_creds mcreds;
295 krb5_error_code ret;
296 kcm_ccache ccache;
297 char *name;
298 krb5_creds *credp;
299 int free_creds = 0;
301 ret = krb5_ret_stringz(request, &name);
302 if (ret)
303 return ret;
305 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
307 ret = krb5_ret_uint32(request, &flags);
308 if (ret) {
309 free(name);
310 return ret;
313 ret = krb5_ret_creds_tag(request, &mcreds);
314 if (ret) {
315 free(name);
316 return ret;
319 if (disallow_getting_krbtgt &&
320 mcreds.server->name.name_string.len == 2 &&
321 strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0)
323 free(name);
324 krb5_free_cred_contents(context, &mcreds);
325 return KRB5_FCC_PERM;
328 ret = kcm_ccache_resolve_client(context, client, opcode,
329 name, &ccache);
330 if (ret) {
331 free(name);
332 krb5_free_cred_contents(context, &mcreds);
333 return ret;
336 ret = kcm_ccache_retrieve_cred(context, ccache, flags,
337 &mcreds, &credp);
338 if (ret && ((flags & KRB5_GC_CACHED) == 0)) {
339 krb5_ccache_data ccdata;
341 /* try and acquire */
342 HEIMDAL_MUTEX_lock(&ccache->mutex);
344 /* Fake up an internal ccache */
345 kcm_internal_ccache(context, ccache, &ccdata);
347 /* glue cc layer will store creds */
348 ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp);
349 if (ret == 0)
350 free_creds = 1;
352 HEIMDAL_MUTEX_unlock(&ccache->mutex);
355 if (ret == 0) {
356 ret = krb5_store_creds(response, credp);
359 free(name);
360 krb5_free_cred_contents(context, &mcreds);
361 kcm_release_ccache(context, &ccache);
363 if (free_creds)
364 krb5_free_cred_contents(context, credp);
366 return ret;
370 * Request:
371 * NameZ
373 * Response:
374 * Principal
376 static krb5_error_code
377 kcm_op_get_principal(krb5_context context,
378 kcm_client *client,
379 kcm_operation opcode,
380 krb5_storage *request,
381 krb5_storage *response)
383 krb5_error_code ret;
384 kcm_ccache ccache;
385 char *name;
387 ret = krb5_ret_stringz(request, &name);
388 if (ret)
389 return ret;
391 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
393 ret = kcm_ccache_resolve_client(context, client, opcode,
394 name, &ccache);
395 if (ret) {
396 free(name);
397 return ret;
400 if (ccache->client == NULL)
401 ret = KRB5_CC_NOTFOUND;
402 else
403 ret = krb5_store_principal(response, ccache->client);
405 free(name);
406 kcm_release_ccache(context, &ccache);
408 return 0;
412 * Request:
413 * NameZ
415 * Response:
416 * Cursor
419 static krb5_error_code
420 kcm_op_get_first(krb5_context context,
421 kcm_client *client,
422 kcm_operation opcode,
423 krb5_storage *request,
424 krb5_storage *response)
426 krb5_error_code ret;
427 kcm_ccache ccache;
428 uint32_t cursor;
429 char *name;
431 ret = krb5_ret_stringz(request, &name);
432 if (ret)
433 return ret;
435 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
437 ret = kcm_ccache_resolve_client(context, client, opcode,
438 name, &ccache);
439 if (ret) {
440 free(name);
441 return ret;
444 ret = kcm_cursor_new(context, client->pid, ccache, &cursor);
445 if (ret) {
446 kcm_release_ccache(context, &ccache);
447 free(name);
448 return ret;
451 ret = krb5_store_int32(response, cursor);
453 free(name);
454 kcm_release_ccache(context, &ccache);
456 return ret;
460 * Request:
461 * NameZ
462 * Cursor
464 * Response:
465 * Creds
467 static krb5_error_code
468 kcm_op_get_next(krb5_context context,
469 kcm_client *client,
470 kcm_operation opcode,
471 krb5_storage *request,
472 krb5_storage *response)
474 krb5_error_code ret;
475 kcm_ccache ccache;
476 char *name;
477 uint32_t cursor;
478 kcm_cursor *c;
480 ret = krb5_ret_stringz(request, &name);
481 if (ret)
482 return ret;
484 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
486 ret = krb5_ret_uint32(request, &cursor);
487 if (ret) {
488 free(name);
489 return ret;
492 ret = kcm_ccache_resolve_client(context, client, opcode,
493 name, &ccache);
494 if (ret) {
495 free(name);
496 return ret;
499 ret = kcm_cursor_find(context, client->pid, ccache, cursor, &c);
500 if (ret) {
501 kcm_release_ccache(context, &ccache);
502 free(name);
503 return ret;
506 HEIMDAL_MUTEX_lock(&ccache->mutex);
507 if (c->credp == NULL) {
508 ret = KRB5_CC_END;
509 } else {
510 ret = krb5_store_creds(response, &c->credp->cred);
511 c->credp = c->credp->next;
513 HEIMDAL_MUTEX_unlock(&ccache->mutex);
515 free(name);
516 kcm_release_ccache(context, &ccache);
518 return ret;
522 * Request:
523 * NameZ
524 * Cursor
526 * Response:
529 static krb5_error_code
530 kcm_op_end_get(krb5_context context,
531 kcm_client *client,
532 kcm_operation opcode,
533 krb5_storage *request,
534 krb5_storage *response)
536 krb5_error_code ret;
537 kcm_ccache ccache;
538 uint32_t cursor;
539 char *name;
541 ret = krb5_ret_stringz(request, &name);
542 if (ret)
543 return ret;
545 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
547 ret = krb5_ret_uint32(request, &cursor);
548 if (ret) {
549 free(name);
550 return ret;
553 ret = kcm_ccache_resolve_client(context, client, opcode,
554 name, &ccache);
555 if (ret) {
556 free(name);
557 return ret;
560 ret = kcm_cursor_delete(context, client->pid, ccache, cursor);
562 free(name);
563 kcm_release_ccache(context, &ccache);
565 return ret;
569 * Request:
570 * NameZ
571 * WhichFields
572 * MatchCreds
574 * Response:
577 static krb5_error_code
578 kcm_op_remove_cred(krb5_context context,
579 kcm_client *client,
580 kcm_operation opcode,
581 krb5_storage *request,
582 krb5_storage *response)
584 uint32_t whichfields;
585 krb5_creds mcreds;
586 krb5_error_code ret;
587 kcm_ccache ccache;
588 char *name;
590 ret = krb5_ret_stringz(request, &name);
591 if (ret)
592 return ret;
594 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
596 ret = krb5_ret_uint32(request, &whichfields);
597 if (ret) {
598 free(name);
599 return ret;
602 ret = krb5_ret_creds_tag(request, &mcreds);
603 if (ret) {
604 free(name);
605 return ret;
608 ret = kcm_ccache_resolve_client(context, client, opcode,
609 name, &ccache);
610 if (ret) {
611 free(name);
612 krb5_free_cred_contents(context, &mcreds);
613 return ret;
616 ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds);
618 /* XXX need to remove any events that match */
620 free(name);
621 krb5_free_cred_contents(context, &mcreds);
622 kcm_release_ccache(context, &ccache);
624 return ret;
628 * Request:
629 * NameZ
630 * Flags
632 * Response:
635 static krb5_error_code
636 kcm_op_set_flags(krb5_context context,
637 kcm_client *client,
638 kcm_operation opcode,
639 krb5_storage *request,
640 krb5_storage *response)
642 uint32_t flags;
643 krb5_error_code ret;
644 kcm_ccache ccache;
645 char *name;
647 ret = krb5_ret_stringz(request, &name);
648 if (ret)
649 return ret;
651 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
653 ret = krb5_ret_uint32(request, &flags);
654 if (ret) {
655 free(name);
656 return ret;
659 ret = kcm_ccache_resolve_client(context, client, opcode,
660 name, &ccache);
661 if (ret) {
662 free(name);
663 return ret;
666 /* we don't really support any flags yet */
667 free(name);
668 kcm_release_ccache(context, &ccache);
670 return 0;
674 * Request:
675 * NameZ
676 * UID
677 * GID
679 * Response:
682 static krb5_error_code
683 kcm_op_chown(krb5_context context,
684 kcm_client *client,
685 kcm_operation opcode,
686 krb5_storage *request,
687 krb5_storage *response)
689 uint32_t uid;
690 uint32_t gid;
691 krb5_error_code ret;
692 kcm_ccache ccache;
693 char *name;
695 ret = krb5_ret_stringz(request, &name);
696 if (ret)
697 return ret;
699 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
701 ret = krb5_ret_uint32(request, &uid);
702 if (ret) {
703 free(name);
704 return ret;
707 ret = krb5_ret_uint32(request, &gid);
708 if (ret) {
709 free(name);
710 return ret;
713 ret = kcm_ccache_resolve_client(context, client, opcode,
714 name, &ccache);
715 if (ret) {
716 free(name);
717 return ret;
720 ret = kcm_chown(context, client, ccache, uid, gid);
722 free(name);
723 kcm_release_ccache(context, &ccache);
725 return ret;
729 * Request:
730 * NameZ
731 * Mode
733 * Response:
736 static krb5_error_code
737 kcm_op_chmod(krb5_context context,
738 kcm_client *client,
739 kcm_operation opcode,
740 krb5_storage *request,
741 krb5_storage *response)
743 uint16_t mode;
744 krb5_error_code ret;
745 kcm_ccache ccache;
746 char *name;
748 ret = krb5_ret_stringz(request, &name);
749 if (ret)
750 return ret;
752 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
754 ret = krb5_ret_uint16(request, &mode);
755 if (ret) {
756 free(name);
757 return ret;
760 ret = kcm_ccache_resolve_client(context, client, opcode,
761 name, &ccache);
762 if (ret) {
763 free(name);
764 return ret;
767 ret = kcm_chmod(context, client, ccache, mode);
769 free(name);
770 kcm_release_ccache(context, &ccache);
772 return ret;
776 * Protocol extensions for moving ticket acquisition responsibility
777 * from client to KCM follow.
781 * Request:
782 * NameZ
783 * ServerPrincipalPresent
784 * ServerPrincipal OPTIONAL
785 * Key
787 * Repsonse:
790 static krb5_error_code
791 kcm_op_get_initial_ticket(krb5_context context,
792 kcm_client *client,
793 kcm_operation opcode,
794 krb5_storage *request,
795 krb5_storage *response)
797 krb5_error_code ret;
798 kcm_ccache ccache;
799 char *name;
800 int8_t not_tgt = 0;
801 krb5_principal server = NULL;
802 krb5_keyblock key;
804 krb5_keyblock_zero(&key);
806 ret = krb5_ret_stringz(request, &name);
807 if (ret)
808 return ret;
810 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
812 ret = krb5_ret_int8(request, &not_tgt);
813 if (ret) {
814 free(name);
815 return ret;
818 if (not_tgt) {
819 ret = krb5_ret_principal(request, &server);
820 if (ret) {
821 free(name);
822 return ret;
826 ret = krb5_ret_keyblock(request, &key);
827 if (ret) {
828 free(name);
829 if (server != NULL)
830 krb5_free_principal(context, server);
831 return ret;
834 ret = kcm_ccache_resolve_client(context, client, opcode,
835 name, &ccache);
836 if (ret == 0) {
837 HEIMDAL_MUTEX_lock(&ccache->mutex);
839 if (ccache->server != NULL) {
840 krb5_free_principal(context, ccache->server);
841 ccache->server = NULL;
844 krb5_free_keyblock(context, &ccache->key.keyblock);
846 ccache->server = server;
847 ccache->key.keyblock = key;
848 ccache->flags |= KCM_FLAGS_USE_CACHED_KEY;
850 ret = kcm_ccache_enqueue_default(context, ccache, NULL);
851 if (ret) {
852 ccache->server = NULL;
853 krb5_keyblock_zero(&ccache->key.keyblock);
854 ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY);
857 HEIMDAL_MUTEX_unlock(&ccache->mutex);
860 free(name);
862 if (ret != 0) {
863 krb5_free_principal(context, server);
864 krb5_free_keyblock(context, &key);
867 kcm_release_ccache(context, &ccache);
869 return ret;
873 * Request:
874 * NameZ
875 * ServerPrincipal
876 * KDCFlags
877 * EncryptionType
879 * Repsonse:
882 static krb5_error_code
883 kcm_op_get_ticket(krb5_context context,
884 kcm_client *client,
885 kcm_operation opcode,
886 krb5_storage *request,
887 krb5_storage *response)
889 krb5_error_code ret;
890 kcm_ccache ccache;
891 char *name;
892 krb5_principal server = NULL;
893 krb5_ccache_data ccdata;
894 krb5_creds in, *out;
895 krb5_kdc_flags flags;
897 memset(&in, 0, sizeof(in));
899 ret = krb5_ret_stringz(request, &name);
900 if (ret)
901 return ret;
903 KCM_LOG_REQUEST_NAME(context, client, opcode, name);
905 ret = krb5_ret_uint32(request, &flags.i);
906 if (ret) {
907 free(name);
908 return ret;
911 ret = krb5_ret_int32(request, &in.session.keytype);
912 if (ret) {
913 free(name);
914 return ret;
917 ret = krb5_ret_principal(request, &server);
918 if (ret) {
919 free(name);
920 return ret;
923 ret = kcm_ccache_resolve_client(context, client, opcode,
924 name, &ccache);
925 if (ret) {
926 krb5_free_principal(context, server);
927 free(name);
928 return ret;
931 HEIMDAL_MUTEX_lock(&ccache->mutex);
933 /* Fake up an internal ccache */
934 kcm_internal_ccache(context, ccache, &ccdata);
936 in.client = ccache->client;
937 in.server = server;
938 in.times.endtime = 0;
940 /* glue cc layer will store creds */
941 ret = krb5_get_credentials_with_flags(context, 0, flags,
942 &ccdata, &in, &out);
944 HEIMDAL_MUTEX_unlock(&ccache->mutex);
946 if (ret == 0)
947 krb5_free_cred_contents(context, out);
949 free(name);
951 return ret;
954 static struct kcm_op kcm_ops[] = {
955 { "NOOP", kcm_op_noop },
956 { "GET_NAME", kcm_op_get_name },
957 { "RESOLVE", kcm_op_noop },
958 { "GEN_NEW", kcm_op_gen_new },
959 { "INITIALIZE", kcm_op_initialize },
960 { "DESTROY", kcm_op_destroy },
961 { "STORE", kcm_op_store },
962 { "RETRIEVE", kcm_op_retrieve },
963 { "GET_PRINCIPAL", kcm_op_get_principal },
964 { "GET_FIRST", kcm_op_get_first },
965 { "GET_NEXT", kcm_op_get_next },
966 { "END_GET", kcm_op_end_get },
967 { "REMOVE_CRED", kcm_op_remove_cred },
968 { "SET_FLAGS", kcm_op_set_flags },
969 { "CHOWN", kcm_op_chown },
970 { "CHMOD", kcm_op_chmod },
971 { "GET_INITIAL_TICKET", kcm_op_get_initial_ticket },
972 { "GET_TICKET", kcm_op_get_ticket }
976 const char *kcm_op2string(kcm_operation opcode)
978 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0]))
979 return "Unknown operation";
981 return kcm_ops[opcode].name;
984 krb5_error_code
985 kcm_dispatch(krb5_context context,
986 kcm_client *client,
987 krb5_data *req_data,
988 krb5_data *resp_data)
990 krb5_error_code ret;
991 kcm_method method;
992 krb5_storage *req_sp = NULL;
993 krb5_storage *resp_sp = NULL;
994 uint16_t opcode;
996 resp_sp = krb5_storage_emem();
997 if (resp_sp == NULL) {
998 return ENOMEM;
1001 if (client->pid == -1) {
1002 kcm_log(0, "Client had invalid process number");
1003 ret = KRB5_FCC_INTERNAL;
1004 goto out;
1007 req_sp = krb5_storage_from_data(req_data);
1008 if (req_sp == NULL) {
1009 kcm_log(0, "Process %d: failed to initialize storage from data",
1010 client->pid);
1011 ret = KRB5_CC_IO;
1012 goto out;
1015 ret = krb5_ret_uint16(req_sp, &opcode);
1016 if (ret) {
1017 kcm_log(0, "Process %d: didn't send a message", client->pid);
1018 goto out;
1021 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) {
1022 kcm_log(0, "Process %d: invalid operation code %d",
1023 client->pid, opcode);
1024 ret = KRB5_FCC_INTERNAL;
1025 goto out;
1027 method = kcm_ops[opcode].method;
1029 /* seek past place for status code */
1030 krb5_storage_seek(resp_sp, 4, SEEK_SET);
1032 ret = (*method)(context, client, opcode, req_sp, resp_sp);
1034 out:
1035 if (req_sp != NULL) {
1036 krb5_storage_free(req_sp);
1039 krb5_storage_seek(resp_sp, 0, SEEK_SET);
1040 krb5_store_int32(resp_sp, ret);
1042 ret = krb5_storage_to_data(resp_sp, resp_data);
1043 krb5_storage_free(resp_sp);
1045 return ret;