2 * Copyright (c) 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "kadmin_locl.h"
37 #include <gssapi_krb5.h>
38 #include <gssapi_spnego.h>
44 krb5_errx(dcontext, 1, "Failed (%d) on %s:%d", \
45 __r, __FILE__, __LINE__); \
49 static krb5_context dcontext
;
51 #define INSIST(x) CHECK(!(x))
53 #define VERSION2 0x12345702
55 #define LAST_FRAGMENT 0x80000000
58 #define KADM_SERVER 2112
61 #define FLAVOR_GSS_VERSION 1
74 struct opaque_auth cred
;
75 struct opaque_auth verf
;
81 RPG_CONTINUE_INIT
= 2,
91 krb5_ui_4 api_version;
108 parse_name(const unsigned char *p
, size_t len
,
109 const gss_OID oid
, char **name
)
117 if (memcmp(p
, "\x04\x01", 2) != 0)
123 l
= (p
[0] << 8) | p
[1];
126 if (l
< 2 || len
< l
)
130 if (p
[0] != 6 || p
[1] != l
- 2)
137 if (l
!= oid
->length
|| memcmp(p
, oid
->elements
, oid
->length
) != 0)
145 l
= (unsigned long)p
[0] << 24 | p
[1] << 16 | p
[2] << 8 | p
[3];
153 *name
= malloc(l
+ 1);
154 INSIST(*name
!= NULL
);
164 gss_error(krb5_context contextp
,
165 gss_OID mech
, OM_uint32 type
, OM_uint32 error
)
168 OM_uint32 msg_ctx
= 0;
169 gss_buffer_desc status_string
;
173 ret
= gss_display_status (&new_stat
,
179 krb5_warnx(contextp
, "%.*s",
180 (int)status_string
.length
,
181 (char *)status_string
.value
);
182 gss_release_buffer (&new_stat
, &status_string
);
183 } while (!GSS_ERROR(ret
) && msg_ctx
!= 0);
187 gss_print_errors (krb5_context contextp
,
188 OM_uint32 maj_stat
, OM_uint32 min_stat
)
190 gss_error(contextp
, GSS_C_NO_OID
, GSS_C_GSS_CODE
, maj_stat
);
191 gss_error(contextp
, GSS_C_NO_OID
, GSS_C_MECH_CODE
, min_stat
);
195 read_data(krb5_storage
*sp
, krb5_storage
*msg
, size_t len
)
203 if (tlen
> sizeof(buf
))
206 slen
= krb5_storage_read(sp
, buf
, tlen
);
207 INSIST((size_t)slen
== tlen
);
209 slen
= krb5_storage_write(msg
, buf
, tlen
);
210 INSIST((size_t)slen
== tlen
);
218 collect_framents(krb5_storage
*sp
, krb5_storage
*msg
)
223 size_t total_len
= 0;
226 ret
= krb5_ret_uint32(sp
, &len
);
230 last_fragment
= (len
& LAST_FRAGMENT
);
231 len
&= ~LAST_FRAGMENT
;
233 CHECK(read_data(sp
, msg
, len
));
236 } while(!last_fragment
|| total_len
== 0);
241 static krb5_error_code
242 store_data_xdr(krb5_storage
*sp
, krb5_data data
)
247 ret
= krb5_store_data(sp
, data
);
250 res
= 4 - (data
.length
% 4);
252 static const char zero
[4] = { 0, 0, 0, 0 };
254 ret
= krb5_storage_write(sp
, zero
, res
);
255 if((size_t)ret
!= res
)
256 return (ret
< 0)? errno
: krb5_storage_get_eof_code(sp
);
261 static krb5_error_code
262 ret_data_xdr(krb5_storage
*sp
, krb5_data
*data
)
265 ret
= krb5_ret_data(sp
, data
);
269 if ((data
->length
% 4) != 0) {
273 res
= 4 - (data
->length
% 4);
275 ret
= krb5_storage_read(sp
, buf
, res
);
276 if((size_t)ret
!= res
)
277 return (ret
< 0)? errno
: krb5_storage_get_eof_code(sp
);
283 static krb5_error_code
284 ret_auth_opaque(krb5_storage
*msg
, struct opaque_auth
*ao
)
287 ret
= krb5_ret_uint32(msg
, &ao
->flavor
);
289 ret
= ret_data_xdr(msg
, &ao
->data
);
294 ret_gcred(krb5_data
*data
, struct gcred
*gcred
)
298 memset(gcred
, 0, sizeof(*gcred
));
300 sp
= krb5_storage_from_data(data
);
303 CHECK(krb5_ret_uint32(sp
, &gcred
->version
));
304 CHECK(krb5_ret_uint32(sp
, &gcred
->proc
));
305 CHECK(krb5_ret_uint32(sp
, &gcred
->seq_num
));
306 CHECK(krb5_ret_uint32(sp
, &gcred
->service
));
307 CHECK(ret_data_xdr(sp
, &gcred
->handle
));
309 krb5_storage_free(sp
);
314 static krb5_error_code
315 store_gss_init_res(krb5_storage
*sp
, krb5_data handle
,
316 OM_uint32 maj_stat
, OM_uint32 min_stat
,
317 uint32_t seq_window
, gss_buffer_t gout
)
322 out
.data
= gout
->value
;
323 out
.length
= gout
->length
;
325 ret
= store_data_xdr(sp
, handle
);
327 ret
= krb5_store_uint32(sp
, maj_stat
);
329 ret
= krb5_store_uint32(sp
, min_stat
);
331 ret
= store_data_xdr(sp
, out
);
336 store_string_xdr(krb5_storage
*sp
, const char *str
)
340 c
.data
= rk_UNCONST(str
);
341 c
.length
= strlen(str
) + 1;
345 return store_data_xdr(sp
, c
);
349 ret_string_xdr(krb5_storage
*sp
, char **str
)
353 CHECK(ret_data_xdr(sp
, &c
));
355 *str
= malloc(c
.length
+ 1);
356 INSIST(*str
!= NULL
);
357 memcpy(*str
, c
.data
, c
.length
);
358 (*str
)[c
.length
] = '\0';
365 store_principal_xdr(krb5_context contextp
,
370 CHECK(krb5_unparse_name(contextp
, p
, &str
));
371 CHECK(store_string_xdr(sp
, str
));
377 ret_principal_xdr(krb5_context contextp
,
383 CHECK(ret_string_xdr(sp
, &str
));
385 CHECK(krb5_parse_name(contextp
, str
, p
));
392 store_principal_ent(krb5_context contextp
,
394 kadm5_principal_ent_rec
*ent
)
398 CHECK(store_principal_xdr(contextp
, sp
, ent
->principal
));
399 CHECK(krb5_store_uint32(sp
, ent
->princ_expire_time
));
400 CHECK(krb5_store_uint32(sp
, ent
->pw_expiration
));
401 CHECK(krb5_store_uint32(sp
, ent
->last_pwd_change
));
402 CHECK(krb5_store_uint32(sp
, ent
->max_life
));
403 CHECK(krb5_store_int32(sp
, ent
->mod_name
== NULL
));
405 CHECK(store_principal_xdr(contextp
, sp
, ent
->mod_name
));
406 CHECK(krb5_store_uint32(sp
, ent
->mod_date
));
407 CHECK(krb5_store_uint32(sp
, ent
->attributes
));
408 CHECK(krb5_store_uint32(sp
, ent
->kvno
));
409 CHECK(krb5_store_uint32(sp
, ent
->mkvno
));
410 CHECK(store_string_xdr(sp
, ent
->policy
));
411 CHECK(krb5_store_int32(sp
, ent
->aux_attributes
));
412 CHECK(krb5_store_int32(sp
, ent
->max_renewable_life
));
413 CHECK(krb5_store_int32(sp
, ent
->last_success
));
414 CHECK(krb5_store_int32(sp
, ent
->last_failed
));
415 CHECK(krb5_store_int32(sp
, ent
->fail_auth_count
));
416 CHECK(krb5_store_int32(sp
, ent
->n_key_data
));
417 CHECK(krb5_store_int32(sp
, ent
->n_tl_data
));
418 CHECK(krb5_store_int32(sp
, ent
->n_tl_data
== 0));
419 if (ent
->n_tl_data
) {
422 for (tp
= ent
->tl_data
; tp
; tp
= tp
->tl_data_next
) {
424 c
.length
= tp
->tl_data_length
;
425 c
.data
= tp
->tl_data_contents
;
427 CHECK(krb5_store_int32(sp
, 0)); /* last item */
428 CHECK(krb5_store_int32(sp
, tp
->tl_data_type
));
429 CHECK(store_data_xdr(sp
, c
));
431 CHECK(krb5_store_int32(sp
, 1)); /* last item */
434 CHECK(krb5_store_int32(sp
, ent
->n_key_data
));
435 for (i
= 0; i
< ent
->n_key_data
; i
++) {
436 CHECK(krb5_store_uint32(sp
, 2));
437 CHECK(krb5_store_uint32(sp
, ent
->kvno
));
438 CHECK(krb5_store_uint32(sp
, ent
->key_data
[i
].key_data_type
[0]));
439 CHECK(krb5_store_uint32(sp
, ent
->key_data
[i
].key_data_type
[1]));
446 ret_principal_ent(krb5_context contextp
,
448 kadm5_principal_ent_rec
*ent
)
453 memset(ent
, 0, sizeof(*ent
));
455 CHECK(ret_principal_xdr(contextp
, sp
, &ent
->principal
));
456 CHECK(krb5_ret_uint32(sp
, &flag
));
457 ent
->princ_expire_time
= flag
;
458 CHECK(krb5_ret_uint32(sp
, &flag
));
459 ent
->pw_expiration
= flag
;
460 CHECK(krb5_ret_uint32(sp
, &flag
));
461 ent
->last_pwd_change
= flag
;
462 CHECK(krb5_ret_uint32(sp
, &flag
));
463 ent
->max_life
= flag
;
464 CHECK(krb5_ret_uint32(sp
, &flag
));
466 CHECK(ret_principal_xdr(contextp
, sp
, &ent
->mod_name
));
467 CHECK(krb5_ret_uint32(sp
, &flag
));
468 ent
->mod_date
= flag
;
469 CHECK(krb5_ret_uint32(sp
, &flag
));
470 ent
->attributes
= flag
;
471 CHECK(krb5_ret_uint32(sp
, &flag
));
473 CHECK(krb5_ret_uint32(sp
, &flag
));
475 CHECK(ret_string_xdr(sp
, &ent
->policy
));
476 CHECK(krb5_ret_uint32(sp
, &flag
));
477 ent
->aux_attributes
= flag
;
478 CHECK(krb5_ret_uint32(sp
, &flag
));
479 ent
->max_renewable_life
= flag
;
480 CHECK(krb5_ret_uint32(sp
, &flag
));
481 ent
->last_success
= flag
;
482 CHECK(krb5_ret_uint32(sp
, &flag
));
483 ent
->last_failed
= flag
;
484 CHECK(krb5_ret_uint32(sp
, &flag
));
485 ent
->fail_auth_count
= flag
;
486 CHECK(krb5_ret_uint32(sp
, &flag
));
487 ent
->n_key_data
= flag
;
488 CHECK(krb5_ret_uint32(sp
, &flag
));
489 ent
->n_tl_data
= flag
;
490 CHECK(krb5_ret_uint32(sp
, &flag
));
492 krb5_tl_data
**tp
= &ent
->tl_data
;
497 CHECK(krb5_ret_uint32(sp
, &flag
)); /* last item */
500 *tp
= calloc(1, sizeof(**tp
));
502 CHECK(krb5_ret_uint32(sp
, &flag
));
503 (*tp
)->tl_data_type
= flag
;
504 CHECK(ret_data_xdr(sp
, &c
));
505 (*tp
)->tl_data_length
= c
.length
;
506 (*tp
)->tl_data_contents
= c
.data
;
507 tp
= &(*tp
)->tl_data_next
;
511 INSIST((size_t)ent
->n_tl_data
== count
);
513 INSIST(ent
->n_tl_data
== 0);
516 CHECK(krb5_ret_uint32(sp
, &num
));
517 INSIST(num
== (uint32_t)ent
->n_key_data
);
519 ent
->key_data
= calloc(num
, sizeof(ent
->key_data
[0]));
520 INSIST(ent
->key_data
!= NULL
);
522 for (i
= 0; i
< num
; i
++) {
523 CHECK(krb5_ret_uint32(sp
, &flag
)); /* data version */
525 CHECK(krb5_ret_uint32(sp
, &flag
));
527 CHECK(krb5_ret_uint32(sp
, &flag
));
528 ent
->key_data
[i
].key_data_type
[0] = flag
;
529 CHECK(krb5_ret_uint32(sp
, &flag
));
530 ent
->key_data
[i
].key_data_type
[1] = flag
;
542 proc_create_principal(kadm5_server_context
*contextp
,
546 uint32_t version
, mask
;
547 kadm5_principal_ent_rec ent
;
551 memset(&ent
, 0, sizeof(ent
));
553 CHECK(krb5_ret_uint32(in
, &version
));
554 INSIST(version
== VERSION2
);
555 CHECK(ret_principal_ent(contextp
->context
, in
, &ent
));
556 CHECK(krb5_ret_uint32(in
, &mask
));
557 CHECK(ret_string_xdr(in
, &password
));
559 INSIST(ent
.principal
);
562 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_ADD
, ent
.principal
);
566 ret
= kadm5_create_principal(contextp
, &ent
, mask
, password
);
569 krb5_warn(contextp
->context
, ret
, "create principal");
570 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
571 CHECK(krb5_store_uint32(out
, ret
)); /* code */
574 kadm5_free_principal_ent(contextp
, &ent
);
578 proc_delete_principal(kadm5_server_context
*contextp
,
583 krb5_principal princ
;
586 CHECK(krb5_ret_uint32(in
, &version
));
587 INSIST(version
== VERSION2
);
588 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
590 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_DELETE
, princ
);
594 ret
= kadm5_delete_principal(contextp
, princ
);
597 krb5_warn(contextp
->context
, ret
, "delete principal");
598 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
599 CHECK(krb5_store_uint32(out
, ret
)); /* code */
601 krb5_free_principal(contextp
->context
, princ
);
605 proc_get_principal(kadm5_server_context
*contextp
,
609 uint32_t version
, mask
;
610 krb5_principal princ
;
611 kadm5_principal_ent_rec ent
;
614 memset(&ent
, 0, sizeof(ent
));
616 CHECK(krb5_ret_uint32(in
, &version
));
617 INSIST(version
== VERSION2
);
618 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
619 CHECK(krb5_ret_uint32(in
, &mask
));
621 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_GET
, princ
);
625 ret
= kadm5_get_principal(contextp
, princ
, &ent
, mask
);
628 krb5_warn(contextp
->context
, ret
, "get principal principal");
630 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
631 CHECK(krb5_store_uint32(out
, ret
)); /* code */
633 CHECK(store_principal_ent(contextp
->context
, out
, &ent
));
635 krb5_free_principal(contextp
->context
, princ
);
636 kadm5_free_principal_ent(contextp
, &ent
);
640 proc_chrand_principal_v2(kadm5_server_context
*contextp
,
645 krb5_principal princ
;
647 krb5_keyblock
*new_keys
;
650 CHECK(krb5_ret_uint32(in
, &version
));
651 INSIST(version
== VERSION2
);
652 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
654 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_CPW
, princ
);
658 ret
= kadm5_randkey_principal(contextp
, princ
,
662 krb5_warn(contextp
->context
, ret
, "rand key principal");
664 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
665 CHECK(krb5_store_uint32(out
, ret
));
668 CHECK(krb5_store_int32(out
, n_keys
));
670 for(i
= 0; i
< n_keys
; i
++){
671 CHECK(krb5_store_uint32(out
, new_keys
[i
].keytype
));
672 CHECK(store_data_xdr(out
, new_keys
[i
].keyvalue
));
673 krb5_free_keyblock_contents(contextp
->context
, &new_keys
[i
]);
677 krb5_free_principal(contextp
->context
, princ
);
681 proc_init(kadm5_server_context
*contextp
,
685 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
686 CHECK(krb5_store_uint32(out
, 0)); /* code */
687 CHECK(krb5_store_uint32(out
, 0)); /* code */
692 void (*func
)(kadm5_server_context
*, krb5_storage
*, krb5_storage
*);
695 { "create principal", proc_create_principal
},
696 { "delete principal", proc_delete_principal
},
697 { "modify principal", NULL
},
698 { "rename principal", NULL
},
699 { "get principal", proc_get_principal
},
700 { "chpass principal", NULL
},
701 { "chrand principal", proc_chrand_principal_v2
},
702 { "create policy", NULL
},
703 { "delete policy", NULL
},
704 { "modify policy", NULL
},
705 { "get policy", NULL
},
706 { "get privs", NULL
},
707 { "init", proc_init
},
708 { "get principals", NULL
},
709 { "get polices", NULL
},
710 { "setkey principal", NULL
},
711 { "setkey principal v4", NULL
},
712 { "create principal v3", NULL
},
713 { "chpass principal v3", NULL
},
714 { "chrand principal v3", NULL
},
715 { "setkey principal v3", NULL
}
718 { "create principal", NULL
},
719 { "delete principal", NULL
},
720 { "modify principal", NULL
},
721 { "rename principal", NULL
},
722 { "get principal", proc_get_principal
},
723 { "chpass principal", NULL
},
724 { "chrand principal", NULL
},
725 { "create policy", NULL
},
726 { "delete policy", NULL
},
727 { "modify policy", NULL
},
728 { "get policy", NULL
},
729 { "get privs", NULL
},
731 { "get principals", NULL
},
732 { "get polices", NULL
},
733 { "setkey principal", NULL
},
734 { "setkey principal v4", NULL
},
735 { "create principal v3", NULL
},
736 { "chpass principal v3", NULL
},
737 { "chrand principal v3", NULL
},
738 { "setkey principal v3", NULL
}
741 static krb5_error_code
742 copyheader(krb5_storage
*sp
, krb5_data
*data
)
747 off
= krb5_storage_seek(sp
, 0, SEEK_CUR
);
749 CHECK(krb5_data_alloc(data
, off
));
750 INSIST((size_t)off
== data
->length
);
751 krb5_storage_seek(sp
, 0, SEEK_SET
);
752 sret
= krb5_storage_read(sp
, data
->data
, data
->length
);
754 INSIST(off
== krb5_storage_seek(sp
, 0, SEEK_CUR
));
768 process_stream(krb5_context contextp
,
775 krb5_storage
*msg
, *reply
, *dreply
;
776 OM_uint32 maj_stat
, min_stat
;
777 gss_buffer_desc gin
, gout
;
779 void *server_handle
= NULL
;
781 memset(&gctx
, 0, sizeof(gctx
));
783 msg
= krb5_storage_emem();
784 reply
= krb5_storage_emem();
785 dreply
= krb5_storage_emem();
787 if (msg
== NULL
|| reply
== NULL
|| dreply
== NULL
) {
789 krb5_storage_free(msg
);
791 krb5_storage_free(reply
);
793 krb5_storage_free(dreply
);
794 return krb5_enomem(contextp
);
798 * First packet comes partly from the caller
804 struct call_header chdr
;
807 krb5_data headercopy
;
809 krb5_storage_truncate(dreply
, 0);
810 krb5_storage_truncate(reply
, 0);
811 krb5_storage_truncate(msg
, 0);
813 krb5_data_zero(&headercopy
);
814 memset(&chdr
, 0, sizeof(chdr
));
815 memset(&gcred
, 0, sizeof(gcred
));
818 * This is very icky to handle the the auto-detection between
819 * the Heimdal protocol and the MIT ONC-RPC based protocol.
826 unsigned char tmp
[4];
829 memcpy(tmp
, buf
, ilen
);
830 slen
= krb5_storage_read(sp
, tmp
+ ilen
, sizeof(tmp
) - ilen
);
831 INSIST((size_t)slen
== sizeof(tmp
) - ilen
);
838 _krb5_get_int(buf
, &len
, 4);
839 last_fragment
= (len
& LAST_FRAGMENT
) != 0;
840 len
&= ~LAST_FRAGMENT
;
847 slen
= krb5_storage_write(msg
, buf
, len
);
848 INSIST((size_t)slen
== len
);
852 slen
= krb5_storage_write(msg
, buf
, ilen
);
853 INSIST((size_t)slen
== ilen
);
858 CHECK(read_data(sp
, msg
, len
));
860 if (!last_fragment
) {
861 ret
= collect_framents(sp
, msg
);
862 if (ret
== HEIM_ERR_EOF
)
863 krb5_errx(contextp
, 0, "client disconnected");
868 ret
= collect_framents(sp
, msg
);
869 if (ret
== HEIM_ERR_EOF
)
870 krb5_errx(contextp
, 0, "client disconnected");
873 krb5_storage_seek(msg
, 0, SEEK_SET
);
875 CHECK(krb5_ret_uint32(msg
, &chdr
.xid
));
876 CHECK(krb5_ret_uint32(msg
, &mtype
));
877 CHECK(krb5_ret_uint32(msg
, &chdr
.rpcvers
));
878 CHECK(krb5_ret_uint32(msg
, &chdr
.prog
));
879 CHECK(krb5_ret_uint32(msg
, &chdr
.vers
));
880 CHECK(krb5_ret_uint32(msg
, &chdr
.proc
));
881 CHECK(ret_auth_opaque(msg
, &chdr
.cred
));
882 CHECK(copyheader(msg
, &headercopy
));
883 CHECK(ret_auth_opaque(msg
, &chdr
.verf
));
885 INSIST(chdr
.rpcvers
== RPC_VERSION
);
886 INSIST(chdr
.prog
== KADM_SERVER
);
887 INSIST(chdr
.vers
== VVERSION
);
888 INSIST(chdr
.cred
.flavor
== FLAVOR_GSS
);
890 CHECK(ret_gcred(&chdr
.cred
.data
, &gcred
));
892 INSIST(gcred
.version
== FLAVOR_GSS_VERSION
);
895 INSIST(chdr
.verf
.flavor
== FLAVOR_GSS
);
897 /* from first byte to last of credential */
898 gin
.value
= headercopy
.data
;
899 gin
.length
= headercopy
.length
;
900 gout
.value
= chdr
.verf
.data
.data
;
901 gout
.length
= chdr
.verf
.data
.length
;
903 maj_stat
= gss_verify_mic(&min_stat
, gctx
.ctx
, &gin
, &gout
, NULL
);
904 INSIST(maj_stat
== GSS_S_COMPLETE
);
913 struct krb5_proc
*procs
= readonly
? roprocs
: rwprocs
;
915 INSIST(gcred
.service
== rpg_privacy
);
919 INSIST(krb5_data_cmp(&gcred
.handle
, &gctx
.handle
) == 0);
921 CHECK(ret_data_xdr(msg
, &data
));
923 gin
.value
= data
.data
;
924 gin
.length
= data
.length
;
926 maj_stat
= gss_unwrap(&min_stat
, gctx
.ctx
, &gin
, &gout
,
928 krb5_data_free(&data
);
929 INSIST(maj_stat
== GSS_S_COMPLETE
);
930 INSIST(conf_state
!= 0);
932 sp1
= krb5_storage_from_mem(gout
.value
, gout
.length
);
935 CHECK(krb5_ret_uint32(sp1
, &seq
));
936 INSIST (seq
== gcred
.seq_num
);
939 * Check sequence number
941 INSIST(seq
> gctx
.seq_num
);
945 * If contextp is setup, priv data have the seq_num stored
946 * first in the block, so add it here before users data is
949 CHECK(krb5_store_uint32(dreply
, gctx
.seq_num
));
951 if (chdr
.proc
>= sizeof(rwprocs
)/sizeof(rwprocs
[0])) {
952 krb5_warnx(contextp
, "proc number out of array");
953 } else if (procs
[chdr
.proc
].func
== NULL
) {
954 if (readonly
&& rwprocs
[chdr
.proc
].func
)
956 "proc '%s' not allowed (readonly mode)",
957 procs
[chdr
.proc
].name
);
959 krb5_warnx(contextp
, "proc '%s' never implemented",
960 procs
[chdr
.proc
].name
);
962 krb5_warnx(contextp
, "proc %s", procs
[chdr
.proc
].name
);
963 INSIST(server_handle
!= NULL
);
964 (*procs
[chdr
.proc
].func
)(server_handle
, sp
, dreply
);
966 krb5_storage_free(sp
);
967 gss_release_buffer(&min_stat
, &gout
);
972 INSIST(gctx
.inprogress
== 0);
973 INSIST(gctx
.ctx
== NULL
);
977 case RPG_CONTINUE_INIT
: {
978 gss_name_t src_name
= GSS_C_NO_NAME
;
981 INSIST(gctx
.inprogress
);
983 CHECK(ret_data_xdr(msg
, &in
));
986 gin
.length
= in
.length
;
990 maj_stat
= gss_accept_sec_context(&min_stat
,
994 GSS_C_NO_CHANNEL_BINDINGS
,
1001 if (GSS_ERROR(maj_stat
)) {
1002 gss_print_errors(contextp
, maj_stat
, min_stat
);
1003 krb5_errx(contextp
, 1, "gss error, exit");
1005 if ((maj_stat
& GSS_S_CONTINUE_NEEDED
) == 0) {
1006 kadm5_config_params realm_params
;
1007 gss_buffer_desc bufp
;
1012 memset(&realm_params
, 0, sizeof(realm_params
));
1014 maj_stat
= gss_export_name(&min_stat
, src_name
, &bufp
);
1015 INSIST(maj_stat
== GSS_S_COMPLETE
);
1017 CHECK(parse_name(bufp
.value
, bufp
.length
,
1018 GSS_KRB5_MECHANISM
, &client
));
1020 gss_release_buffer(&min_stat
, &bufp
);
1022 krb5_warnx(contextp
, "%s connected", client
);
1024 ret
= kadm5_s_init_with_password_ctx(contextp
,
1027 KADM5_ADMIN_SERVICE
,
1034 INSIST(gctx
.ctx
!= GSS_C_NO_CONTEXT
);
1036 CHECK(krb5_store_uint32(dreply
, 0));
1037 CHECK(store_gss_init_res(dreply
, gctx
.handle
,
1038 maj_stat
, min_stat
, 1, &gout
));
1040 gss_release_buffer(&min_stat
, &gout
);
1042 gss_release_name(&min_stat
, &src_name
);
1047 krb5_errx(contextp
, 1, "client destroyed gss contextp");
1049 krb5_errx(contextp
, 1, "client sent unknown gsscode %d",
1053 krb5_data_free(&gcred
.handle
);
1054 krb5_data_free(&chdr
.cred
.data
);
1055 krb5_data_free(&chdr
.verf
.data
);
1056 krb5_data_free(&headercopy
);
1058 CHECK(krb5_store_uint32(reply
, chdr
.xid
));
1059 CHECK(krb5_store_uint32(reply
, 1)); /* REPLY */
1060 CHECK(krb5_store_uint32(reply
, 0)); /* MSG_ACCEPTED */
1065 CHECK(krb5_store_uint32(reply
, 0)); /* flavor_none */
1066 CHECK(krb5_store_uint32(reply
, 0)); /* length */
1068 CHECK(krb5_store_uint32(reply
, 0)); /* SUCCESS */
1070 CHECK(krb5_storage_to_data(dreply
, &data
));
1071 INSIST((size_t)krb5_storage_write(reply
, data
.data
, data
.length
) == data
.length
);
1072 krb5_data_free(&data
);
1075 uint32_t seqnum
= htonl(gctx
.seq_num
);
1078 gin
.value
= &seqnum
;
1079 gin
.length
= sizeof(seqnum
);
1081 maj_stat
= gss_get_mic(&min_stat
, gctx
.ctx
, 0, &gin
, &gout
);
1082 INSIST(maj_stat
== GSS_S_COMPLETE
);
1084 data
.data
= gout
.value
;
1085 data
.length
= gout
.length
;
1087 CHECK(krb5_store_uint32(reply
, FLAVOR_GSS
));
1088 CHECK(store_data_xdr(reply
, data
));
1089 gss_release_buffer(&min_stat
, &gout
);
1091 CHECK(krb5_store_uint32(reply
, 0)); /* SUCCESS */
1093 CHECK(krb5_storage_to_data(dreply
, &data
));
1095 if (gctx
.inprogress
) {
1097 gctx
.inprogress
= 0;
1098 sret
= krb5_storage_write(reply
, data
.data
, data
.length
);
1099 INSIST((size_t)sret
== data
.length
);
1100 krb5_data_free(&data
);
1104 gin
.value
= data
.data
;
1105 gin
.length
= data
.length
;
1107 maj_stat
= gss_wrap(&min_stat
, gctx
.ctx
, 1, 0,
1108 &gin
, &conf_state
, &gout
);
1109 INSIST(maj_stat
== GSS_S_COMPLETE
);
1110 INSIST(conf_state
!= 0);
1111 krb5_data_free(&data
);
1113 data
.data
= gout
.value
;
1114 data
.length
= gout
.length
;
1116 store_data_xdr(reply
, data
);
1117 gss_release_buffer(&min_stat
, &gout
);
1124 CHECK(krb5_storage_to_data(reply
, &data
));
1125 CHECK(krb5_store_uint32(sp
, data
.length
| LAST_FRAGMENT
));
1126 sret
= krb5_storage_write(sp
, data
.data
, data
.length
);
1127 INSIST((size_t)sret
== data
.length
);
1128 krb5_data_free(&data
);
1136 handle_mit(krb5_context contextp
,
1144 dcontext
= contextp
;
1146 sp
= krb5_storage_from_socket(sock
);
1149 process_stream(contextp
, buf
, len
, sp
, readonly
);