1 /* $NetBSD: rpc.c,v 1.2 2014/05/12 15:34:23 christos Exp $ */
4 * Copyright (c) 2008 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include "kadmin_locl.h"
38 #include <gssapi/gssapi.h>
39 #include <gssapi/gssapi_krb5.h>
40 #include <gssapi/gssapi_spnego.h>
46 krb5_errx(dcontext, 1, "Failed (%d) on %s:%d", \
47 __r, __FILE__, __LINE__); \
51 static krb5_context dcontext
;
53 #define INSIST(x) CHECK(!(x))
55 #define VERSION2 0x12345702
57 #define LAST_FRAGMENT 0x80000000
60 #define KADM_SERVER 2112
63 #define FLAVOR_GSS_VERSION 1
76 struct opaque_auth cred
;
77 struct opaque_auth verf
;
83 RPG_CONTINUE_INIT
= 2,
93 krb5_ui_4 api_version;
110 parse_name(const unsigned char *p
, size_t len
,
111 const gss_OID oid
, char **name
)
119 if (memcmp(p
, "\x04\x01", 2) != 0)
125 l
= (p
[0] << 8) | p
[1];
128 if (l
< 2 || len
< l
)
132 if (p
[0] != 6 || p
[1] != l
- 2)
139 if (l
!= oid
->length
|| memcmp(p
, oid
->elements
, oid
->length
) != 0)
147 l
= p
[0] << 24 | p
[1] << 16 | p
[2] << 8 | p
[3];
155 *name
= malloc(l
+ 1);
156 INSIST(*name
!= NULL
);
166 gss_error(krb5_context contextp
,
167 gss_OID mech
, OM_uint32 type
, OM_uint32 error
)
170 OM_uint32 msg_ctx
= 0;
171 gss_buffer_desc status_string
;
175 ret
= gss_display_status (&new_stat
,
181 krb5_warnx(contextp
, "%.*s",
182 (int)status_string
.length
,
183 (char *)status_string
.value
);
184 gss_release_buffer (&new_stat
, &status_string
);
185 } while (!GSS_ERROR(ret
) && msg_ctx
!= 0);
189 gss_print_errors (krb5_context contextp
,
190 OM_uint32 maj_stat
, OM_uint32 min_stat
)
192 gss_error(contextp
, GSS_C_NO_OID
, GSS_C_GSS_CODE
, maj_stat
);
193 gss_error(contextp
, GSS_C_NO_OID
, GSS_C_MECH_CODE
, min_stat
);
197 read_data(krb5_storage
*sp
, krb5_storage
*msg
, size_t len
)
205 if (tlen
> sizeof(buf
))
208 slen
= krb5_storage_read(sp
, buf
, tlen
);
209 INSIST((size_t)slen
== tlen
);
211 slen
= krb5_storage_write(msg
, buf
, tlen
);
212 INSIST((size_t)slen
== tlen
);
220 collect_framents(krb5_storage
*sp
, krb5_storage
*msg
)
225 size_t total_len
= 0;
228 ret
= krb5_ret_uint32(sp
, &len
);
232 last_fragment
= (len
& LAST_FRAGMENT
);
233 len
&= ~LAST_FRAGMENT
;
235 CHECK(read_data(sp
, msg
, len
));
238 } while(!last_fragment
|| total_len
== 0);
243 static krb5_error_code
244 store_data_xdr(krb5_storage
*sp
, krb5_data data
)
249 ret
= krb5_store_data(sp
, data
);
252 res
= 4 - (data
.length
% 4);
254 static const char zero
[4] = { 0, 0, 0, 0 };
256 ret
= krb5_storage_write(sp
, zero
, res
);
257 if((size_t)ret
!= res
)
258 return (ret
< 0)? errno
: krb5_storage_get_eof_code(sp
);
263 static krb5_error_code
264 ret_data_xdr(krb5_storage
*sp
, krb5_data
*data
)
267 ret
= krb5_ret_data(sp
, data
);
271 if ((data
->length
% 4) != 0) {
275 res
= 4 - (data
->length
% 4);
277 ret
= krb5_storage_read(sp
, buf
, res
);
278 if((size_t)ret
!= res
)
279 return (ret
< 0)? errno
: krb5_storage_get_eof_code(sp
);
285 static krb5_error_code
286 ret_auth_opaque(krb5_storage
*msg
, struct opaque_auth
*ao
)
289 ret
= krb5_ret_uint32(msg
, &ao
->flavor
);
291 ret
= ret_data_xdr(msg
, &ao
->data
);
296 ret_gcred(krb5_data
*data
, struct gcred
*gcred
)
300 memset(gcred
, 0, sizeof(*gcred
));
302 sp
= krb5_storage_from_data(data
);
305 CHECK(krb5_ret_uint32(sp
, &gcred
->version
));
306 CHECK(krb5_ret_uint32(sp
, &gcred
->proc
));
307 CHECK(krb5_ret_uint32(sp
, &gcred
->seq_num
));
308 CHECK(krb5_ret_uint32(sp
, &gcred
->service
));
309 CHECK(ret_data_xdr(sp
, &gcred
->handle
));
311 krb5_storage_free(sp
);
316 static krb5_error_code
317 store_gss_init_res(krb5_storage
*sp
, krb5_data handle
,
318 OM_uint32 maj_stat
, OM_uint32 min_stat
,
319 uint32_t seq_window
, gss_buffer_t gout
)
324 out
.data
= gout
->value
;
325 out
.length
= gout
->length
;
327 ret
= store_data_xdr(sp
, handle
);
329 ret
= krb5_store_uint32(sp
, maj_stat
);
331 ret
= krb5_store_uint32(sp
, min_stat
);
333 ret
= store_data_xdr(sp
, out
);
338 store_string_xdr(krb5_storage
*sp
, const char *str
)
342 c
.data
= rk_UNCONST(str
);
343 c
.length
= strlen(str
) + 1;
347 return store_data_xdr(sp
, c
);
351 ret_string_xdr(krb5_storage
*sp
, char **str
)
355 CHECK(ret_data_xdr(sp
, &c
));
357 *str
= malloc(c
.length
+ 1);
358 INSIST(*str
!= NULL
);
359 memcpy(*str
, c
.data
, c
.length
);
360 (*str
)[c
.length
] = '\0';
367 store_principal_xdr(krb5_context contextp
,
372 CHECK(krb5_unparse_name(contextp
, p
, &str
));
373 CHECK(store_string_xdr(sp
, str
));
379 ret_principal_xdr(krb5_context contextp
,
385 CHECK(ret_string_xdr(sp
, &str
));
387 CHECK(krb5_parse_name(contextp
, str
, p
));
394 store_principal_ent(krb5_context contextp
,
396 kadm5_principal_ent_rec
*ent
)
400 CHECK(store_principal_xdr(contextp
, sp
, ent
->principal
));
401 CHECK(krb5_store_uint32(sp
, ent
->princ_expire_time
));
402 CHECK(krb5_store_uint32(sp
, ent
->pw_expiration
));
403 CHECK(krb5_store_uint32(sp
, ent
->last_pwd_change
));
404 CHECK(krb5_store_uint32(sp
, ent
->max_life
));
405 CHECK(krb5_store_int32(sp
, ent
->mod_name
== NULL
));
407 CHECK(store_principal_xdr(contextp
, sp
, ent
->mod_name
));
408 CHECK(krb5_store_uint32(sp
, ent
->mod_date
));
409 CHECK(krb5_store_uint32(sp
, ent
->attributes
));
410 CHECK(krb5_store_uint32(sp
, ent
->kvno
));
411 CHECK(krb5_store_uint32(sp
, ent
->mkvno
));
412 CHECK(store_string_xdr(sp
, ent
->policy
));
413 CHECK(krb5_store_int32(sp
, ent
->aux_attributes
));
414 CHECK(krb5_store_int32(sp
, ent
->max_renewable_life
));
415 CHECK(krb5_store_int32(sp
, ent
->last_success
));
416 CHECK(krb5_store_int32(sp
, ent
->last_failed
));
417 CHECK(krb5_store_int32(sp
, ent
->fail_auth_count
));
418 CHECK(krb5_store_int32(sp
, ent
->n_key_data
));
419 CHECK(krb5_store_int32(sp
, ent
->n_tl_data
));
420 CHECK(krb5_store_int32(sp
, ent
->n_tl_data
== 0));
421 if (ent
->n_tl_data
) {
424 for (tp
= ent
->tl_data
; tp
; tp
= tp
->tl_data_next
) {
426 c
.length
= tp
->tl_data_length
;
427 c
.data
= tp
->tl_data_contents
;
429 CHECK(krb5_store_int32(sp
, 0)); /* last item */
430 CHECK(krb5_store_int32(sp
, tp
->tl_data_type
));
431 CHECK(store_data_xdr(sp
, c
));
433 CHECK(krb5_store_int32(sp
, 1)); /* last item */
436 CHECK(krb5_store_int32(sp
, ent
->n_key_data
));
437 for (i
= 0; i
< ent
->n_key_data
; i
++) {
438 CHECK(krb5_store_uint32(sp
, 2));
439 CHECK(krb5_store_uint32(sp
, ent
->kvno
));
440 CHECK(krb5_store_uint32(sp
, ent
->key_data
[i
].key_data_type
[0]));
441 CHECK(krb5_store_uint32(sp
, ent
->key_data
[i
].key_data_type
[1]));
448 ret_principal_ent(krb5_context contextp
,
450 kadm5_principal_ent_rec
*ent
)
455 memset(ent
, 0, sizeof(*ent
));
457 CHECK(ret_principal_xdr(contextp
, sp
, &ent
->principal
));
458 CHECK(krb5_ret_uint32(sp
, &flag
));
459 ent
->princ_expire_time
= flag
;
460 CHECK(krb5_ret_uint32(sp
, &flag
));
461 ent
->pw_expiration
= flag
;
462 CHECK(krb5_ret_uint32(sp
, &flag
));
463 ent
->last_pwd_change
= flag
;
464 CHECK(krb5_ret_uint32(sp
, &flag
));
465 ent
->max_life
= flag
;
466 CHECK(krb5_ret_uint32(sp
, &flag
));
468 CHECK(ret_principal_xdr(contextp
, sp
, &ent
->mod_name
));
469 CHECK(krb5_ret_uint32(sp
, &flag
));
470 ent
->mod_date
= flag
;
471 CHECK(krb5_ret_uint32(sp
, &flag
));
472 ent
->attributes
= flag
;
473 CHECK(krb5_ret_uint32(sp
, &flag
));
475 CHECK(krb5_ret_uint32(sp
, &flag
));
477 CHECK(ret_string_xdr(sp
, &ent
->policy
));
478 CHECK(krb5_ret_uint32(sp
, &flag
));
479 ent
->aux_attributes
= flag
;
480 CHECK(krb5_ret_uint32(sp
, &flag
));
481 ent
->max_renewable_life
= flag
;
482 CHECK(krb5_ret_uint32(sp
, &flag
));
483 ent
->last_success
= flag
;
484 CHECK(krb5_ret_uint32(sp
, &flag
));
485 ent
->last_failed
= flag
;
486 CHECK(krb5_ret_uint32(sp
, &flag
));
487 ent
->fail_auth_count
= flag
;
488 CHECK(krb5_ret_uint32(sp
, &flag
));
489 ent
->n_key_data
= flag
;
490 CHECK(krb5_ret_uint32(sp
, &flag
));
491 ent
->n_tl_data
= flag
;
492 CHECK(krb5_ret_uint32(sp
, &flag
));
494 krb5_tl_data
**tp
= &ent
->tl_data
;
499 CHECK(krb5_ret_uint32(sp
, &flag
)); /* last item */
502 *tp
= calloc(1, sizeof(**tp
));
504 CHECK(krb5_ret_uint32(sp
, &flag
));
505 (*tp
)->tl_data_type
= flag
;
506 CHECK(ret_data_xdr(sp
, &c
));
507 (*tp
)->tl_data_length
= c
.length
;
508 (*tp
)->tl_data_contents
= c
.data
;
509 tp
= &(*tp
)->tl_data_next
;
513 INSIST((size_t)ent
->n_tl_data
== count
);
515 INSIST(ent
->n_tl_data
== 0);
518 CHECK(krb5_ret_uint32(sp
, &num
));
519 INSIST(num
== (uint32_t)ent
->n_key_data
);
521 ent
->key_data
= calloc(num
, sizeof(ent
->key_data
[0]));
522 INSIST(ent
->key_data
!= NULL
);
524 for (i
= 0; i
< num
; i
++) {
525 CHECK(krb5_ret_uint32(sp
, &flag
)); /* data version */
527 CHECK(krb5_ret_uint32(sp
, &flag
));
529 CHECK(krb5_ret_uint32(sp
, &flag
));
530 ent
->key_data
[i
].key_data_type
[0] = flag
;
531 CHECK(krb5_ret_uint32(sp
, &flag
));
532 ent
->key_data
[i
].key_data_type
[1] = flag
;
543 proc_create_principal(kadm5_server_context
*contextp
,
547 uint32_t version
, mask
;
548 kadm5_principal_ent_rec ent
;
552 memset(&ent
, 0, sizeof(ent
));
554 CHECK(krb5_ret_uint32(in
, &version
));
555 INSIST(version
== VERSION2
);
556 CHECK(ret_principal_ent(contextp
->context
, in
, &ent
));
557 CHECK(krb5_ret_uint32(in
, &mask
));
558 CHECK(ret_string_xdr(in
, &password
));
560 INSIST(ent
.principal
);
563 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_ADD
, ent
.principal
);
567 ret
= kadm5_create_principal(contextp
, &ent
, mask
, password
);
570 krb5_warn(contextp
->context
, ret
, "create principal");
571 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
572 CHECK(krb5_store_uint32(out
, ret
)); /* code */
575 kadm5_free_principal_ent(contextp
, &ent
);
579 proc_delete_principal(kadm5_server_context
*contextp
,
584 krb5_principal princ
;
587 CHECK(krb5_ret_uint32(in
, &version
));
588 INSIST(version
== VERSION2
);
589 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
591 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_DELETE
, princ
);
595 ret
= kadm5_delete_principal(contextp
, princ
);
598 krb5_warn(contextp
->context
, ret
, "delete principal");
599 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
600 CHECK(krb5_store_uint32(out
, ret
)); /* code */
602 krb5_free_principal(contextp
->context
, princ
);
606 proc_get_principal(kadm5_server_context
*contextp
,
610 uint32_t version
, mask
;
611 krb5_principal princ
;
612 kadm5_principal_ent_rec ent
;
615 memset(&ent
, 0, sizeof(ent
));
617 CHECK(krb5_ret_uint32(in
, &version
));
618 INSIST(version
== VERSION2
);
619 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
620 CHECK(krb5_ret_uint32(in
, &mask
));
622 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_GET
, princ
);
626 ret
= kadm5_get_principal(contextp
, princ
, &ent
, mask
);
629 krb5_warn(contextp
->context
, ret
, "get principal principal");
631 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
632 CHECK(krb5_store_uint32(out
, ret
)); /* code */
634 CHECK(store_principal_ent(contextp
->context
, out
, &ent
));
636 krb5_free_principal(contextp
->context
, princ
);
637 kadm5_free_principal_ent(contextp
, &ent
);
641 proc_chrand_principal_v2(kadm5_server_context
*contextp
,
646 krb5_principal princ
;
648 krb5_keyblock
*new_keys
;
651 CHECK(krb5_ret_uint32(in
, &version
));
652 INSIST(version
== VERSION2
);
653 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
655 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_CPW
, princ
);
659 ret
= kadm5_randkey_principal(contextp
, princ
,
663 krb5_warn(contextp
->context
, ret
, "rand key principal");
665 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
666 CHECK(krb5_store_uint32(out
, ret
));
669 CHECK(krb5_store_int32(out
, n_keys
));
671 for(i
= 0; i
< n_keys
; i
++){
672 CHECK(krb5_store_uint32(out
, new_keys
[i
].keytype
));
673 CHECK(store_data_xdr(out
, new_keys
[i
].keyvalue
));
674 krb5_free_keyblock_contents(contextp
->context
, &new_keys
[i
]);
678 krb5_free_principal(contextp
->context
, princ
);
682 proc_init(kadm5_server_context
*contextp
,
686 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
687 CHECK(krb5_store_uint32(out
, 0)); /* code */
688 CHECK(krb5_store_uint32(out
, 0)); /* code */
693 void (*func
)(kadm5_server_context
*, krb5_storage
*, krb5_storage
*);
696 { "create principal", proc_create_principal
},
697 { "delete principal", proc_delete_principal
},
698 { "modify principal", NULL
},
699 { "rename principal", NULL
},
700 { "get principal", proc_get_principal
},
701 { "chpass principal", NULL
},
702 { "chrand principal", proc_chrand_principal_v2
},
703 { "create policy", NULL
},
704 { "delete policy", NULL
},
705 { "modify policy", NULL
},
706 { "get policy", NULL
},
707 { "get privs", NULL
},
708 { "init", proc_init
},
709 { "get principals", NULL
},
710 { "get polices", NULL
},
711 { "setkey principal", NULL
},
712 { "setkey principal v4", NULL
},
713 { "create principal v3", NULL
},
714 { "chpass principal v3", NULL
},
715 { "chrand principal v3", NULL
},
716 { "setkey principal v3", NULL
}
719 static krb5_error_code
720 copyheader(krb5_storage
*sp
, krb5_data
*data
)
725 off
= krb5_storage_seek(sp
, 0, SEEK_CUR
);
727 CHECK(krb5_data_alloc(data
, off
));
728 INSIST((size_t)off
== data
->length
);
729 krb5_storage_seek(sp
, 0, SEEK_SET
);
730 sret
= krb5_storage_read(sp
, data
->data
, data
->length
);
732 INSIST(off
== krb5_storage_seek(sp
, 0, SEEK_CUR
));
746 process_stream(krb5_context contextp
,
747 unsigned char *buf
, size_t ilen
,
751 krb5_storage
*msg
, *reply
, *dreply
;
752 OM_uint32 maj_stat
, min_stat
;
753 gss_buffer_desc gin
, gout
;
755 void *server_handle
= NULL
;
757 memset(&gctx
, 0, sizeof(gctx
));
759 msg
= krb5_storage_emem();
760 reply
= krb5_storage_emem();
761 dreply
= krb5_storage_emem();
764 * First packet comes partly from the caller
770 struct call_header chdr
;
773 krb5_data headercopy
;
775 krb5_storage_truncate(dreply
, 0);
776 krb5_storage_truncate(reply
, 0);
777 krb5_storage_truncate(msg
, 0);
779 krb5_data_zero(&headercopy
);
780 memset(&chdr
, 0, sizeof(chdr
));
781 memset(&gcred
, 0, sizeof(gcred
));
784 * This is very icky to handle the the auto-detection between
785 * the Heimdal protocol and the MIT ONC-RPC based protocol.
792 unsigned char tmp
[4];
795 memcpy(tmp
, buf
, ilen
);
796 slen
= krb5_storage_read(sp
, tmp
+ ilen
, sizeof(tmp
) - ilen
);
797 INSIST((size_t)slen
== sizeof(tmp
) - ilen
);
804 _krb5_get_int(buf
, &len
, 4);
805 last_fragment
= (len
& LAST_FRAGMENT
) != 0;
806 len
&= ~LAST_FRAGMENT
;
813 slen
= krb5_storage_write(msg
, buf
, len
);
814 INSIST((size_t)slen
== len
);
818 slen
= krb5_storage_write(msg
, buf
, ilen
);
819 INSIST((size_t)slen
== ilen
);
824 CHECK(read_data(sp
, msg
, len
));
826 if (!last_fragment
) {
827 ret
= collect_framents(sp
, msg
);
828 if (ret
== HEIM_ERR_EOF
)
829 krb5_errx(contextp
, 0, "client disconnected");
834 ret
= collect_framents(sp
, msg
);
835 if (ret
== HEIM_ERR_EOF
)
836 krb5_errx(contextp
, 0, "client disconnected");
839 krb5_storage_seek(msg
, 0, SEEK_SET
);
841 CHECK(krb5_ret_uint32(msg
, &chdr
.xid
));
842 CHECK(krb5_ret_uint32(msg
, &mtype
));
843 CHECK(krb5_ret_uint32(msg
, &chdr
.rpcvers
));
844 CHECK(krb5_ret_uint32(msg
, &chdr
.prog
));
845 CHECK(krb5_ret_uint32(msg
, &chdr
.vers
));
846 CHECK(krb5_ret_uint32(msg
, &chdr
.proc
));
847 CHECK(ret_auth_opaque(msg
, &chdr
.cred
));
848 CHECK(copyheader(msg
, &headercopy
));
849 CHECK(ret_auth_opaque(msg
, &chdr
.verf
));
851 INSIST(chdr
.rpcvers
== RPC_VERSION
);
852 INSIST(chdr
.prog
== KADM_SERVER
);
853 INSIST(chdr
.vers
== VVERSION
);
854 INSIST(chdr
.cred
.flavor
== FLAVOR_GSS
);
856 CHECK(ret_gcred(&chdr
.cred
.data
, &gcred
));
858 INSIST(gcred
.version
== FLAVOR_GSS_VERSION
);
861 INSIST(chdr
.verf
.flavor
== FLAVOR_GSS
);
863 /* from first byte to last of credential */
864 gin
.value
= headercopy
.data
;
865 gin
.length
= headercopy
.length
;
866 gout
.value
= chdr
.verf
.data
.data
;
867 gout
.length
= chdr
.verf
.data
.length
;
869 maj_stat
= gss_verify_mic(&min_stat
, gctx
.ctx
, &gin
, &gout
, NULL
);
870 INSIST(maj_stat
== GSS_S_COMPLETE
);
880 INSIST(gcred
.service
== rpg_privacy
);
884 INSIST(krb5_data_cmp(&gcred
.handle
, &gctx
.handle
) == 0);
886 CHECK(ret_data_xdr(msg
, &data
));
888 gin
.value
= data
.data
;
889 gin
.length
= data
.length
;
891 maj_stat
= gss_unwrap(&min_stat
, gctx
.ctx
, &gin
, &gout
,
893 krb5_data_free(&data
);
894 INSIST(maj_stat
== GSS_S_COMPLETE
);
895 INSIST(conf_state
!= 0);
897 sp1
= krb5_storage_from_mem(gout
.value
, gout
.length
);
900 CHECK(krb5_ret_uint32(sp1
, &seq
));
901 INSIST (seq
== gcred
.seq_num
);
904 * Check sequence number
906 INSIST(seq
> gctx
.seq_num
);
910 * If contextp is setup, priv data have the seq_num stored
911 * first in the block, so add it here before users data is
914 CHECK(krb5_store_uint32(dreply
, gctx
.seq_num
));
916 if (chdr
.proc
>= sizeof(procs
)/sizeof(procs
[0])) {
917 krb5_warnx(contextp
, "proc number out of array");
918 } else if (procs
[chdr
.proc
].func
== NULL
) {
919 krb5_warnx(contextp
, "proc '%s' never implemented",
920 procs
[chdr
.proc
].name
);
922 krb5_warnx(contextp
, "proc %s", procs
[chdr
.proc
].name
);
923 INSIST(server_handle
!= NULL
);
924 (*procs
[chdr
.proc
].func
)(server_handle
, sp
, dreply
);
926 krb5_storage_free(sp
);
927 gss_release_buffer(&min_stat
, &gout
);
932 INSIST(gctx
.inprogress
== 0);
933 INSIST(gctx
.ctx
== NULL
);
937 case RPG_CONTINUE_INIT
: {
938 gss_name_t src_name
= GSS_C_NO_NAME
;
941 INSIST(gctx
.inprogress
);
943 CHECK(ret_data_xdr(msg
, &in
));
946 gin
.length
= in
.length
;
950 maj_stat
= gss_accept_sec_context(&min_stat
,
954 GSS_C_NO_CHANNEL_BINDINGS
,
961 if (GSS_ERROR(maj_stat
)) {
962 gss_print_errors(contextp
, maj_stat
, min_stat
);
963 krb5_errx(contextp
, 1, "gss error, exit");
965 if ((maj_stat
& GSS_S_CONTINUE_NEEDED
) == 0) {
966 kadm5_config_params realm_params
;
967 gss_buffer_desc bufp
;
972 memset(&realm_params
, 0, sizeof(realm_params
));
974 maj_stat
= gss_export_name(&min_stat
, src_name
, &bufp
);
975 INSIST(maj_stat
== GSS_S_COMPLETE
);
977 CHECK(parse_name(bufp
.value
, bufp
.length
,
978 GSS_KRB5_MECHANISM
, &client
));
980 gss_release_buffer(&min_stat
, &bufp
);
982 krb5_warnx(contextp
, "%s connected", client
);
984 ret
= kadm5_s_init_with_password_ctx(contextp
,
994 INSIST(gctx
.ctx
!= GSS_C_NO_CONTEXT
);
996 CHECK(krb5_store_uint32(dreply
, 0));
997 CHECK(store_gss_init_res(dreply
, gctx
.handle
,
998 maj_stat
, min_stat
, 1, &gout
));
1000 gss_release_buffer(&min_stat
, &gout
);
1002 gss_release_name(&min_stat
, &src_name
);
1007 krb5_errx(contextp
, 1, "client destroyed gss contextp");
1009 krb5_errx(contextp
, 1, "client sent unknown gsscode %d",
1013 krb5_data_free(&gcred
.handle
);
1014 krb5_data_free(&chdr
.cred
.data
);
1015 krb5_data_free(&chdr
.verf
.data
);
1016 krb5_data_free(&headercopy
);
1018 CHECK(krb5_store_uint32(reply
, chdr
.xid
));
1019 CHECK(krb5_store_uint32(reply
, 1)); /* REPLY */
1020 CHECK(krb5_store_uint32(reply
, 0)); /* MSG_ACCEPTED */
1025 CHECK(krb5_store_uint32(reply
, 0)); /* flavor_none */
1026 CHECK(krb5_store_uint32(reply
, 0)); /* length */
1028 CHECK(krb5_store_uint32(reply
, 0)); /* SUCCESS */
1030 CHECK(krb5_storage_to_data(dreply
, &data
));
1031 INSIST((size_t)krb5_storage_write(reply
, data
.data
, data
.length
) == data
.length
);
1032 krb5_data_free(&data
);
1035 uint32_t seqnum
= htonl(gctx
.seq_num
);
1038 gin
.value
= &seqnum
;
1039 gin
.length
= sizeof(seqnum
);
1041 maj_stat
= gss_get_mic(&min_stat
, gctx
.ctx
, 0, &gin
, &gout
);
1042 INSIST(maj_stat
== GSS_S_COMPLETE
);
1044 data
.data
= gout
.value
;
1045 data
.length
= gout
.length
;
1047 CHECK(krb5_store_uint32(reply
, FLAVOR_GSS
));
1048 CHECK(store_data_xdr(reply
, data
));
1049 gss_release_buffer(&min_stat
, &gout
);
1051 CHECK(krb5_store_uint32(reply
, 0)); /* SUCCESS */
1053 CHECK(krb5_storage_to_data(dreply
, &data
));
1055 if (gctx
.inprogress
) {
1057 gctx
.inprogress
= 0;
1058 sret
= krb5_storage_write(reply
, data
.data
, data
.length
);
1059 INSIST((size_t)sret
== data
.length
);
1060 krb5_data_free(&data
);
1064 gin
.value
= data
.data
;
1065 gin
.length
= data
.length
;
1067 maj_stat
= gss_wrap(&min_stat
, gctx
.ctx
, 1, 0,
1068 &gin
, &conf_state
, &gout
);
1069 INSIST(maj_stat
== GSS_S_COMPLETE
);
1070 INSIST(conf_state
!= 0);
1071 krb5_data_free(&data
);
1073 data
.data
= gout
.value
;
1074 data
.length
= gout
.length
;
1076 store_data_xdr(reply
, data
);
1077 gss_release_buffer(&min_stat
, &gout
);
1084 CHECK(krb5_storage_to_data(reply
, &data
));
1085 CHECK(krb5_store_uint32(sp
, data
.length
| LAST_FRAGMENT
));
1086 sret
= krb5_storage_write(sp
, data
.data
, data
.length
);
1087 INSIST((size_t)sret
== data
.length
);
1088 krb5_data_free(&data
);
1096 handle_mit(krb5_context contextp
, void *buf
, size_t len
, krb5_socket_t sock
)
1100 dcontext
= contextp
;
1102 sp
= krb5_storage_from_fd(sock
);
1105 process_stream(contextp
, buf
, len
, sp
);