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
= 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 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
;
541 proc_create_principal(kadm5_server_context
*contextp
,
545 uint32_t version
, mask
;
546 kadm5_principal_ent_rec ent
;
550 memset(&ent
, 0, sizeof(ent
));
552 CHECK(krb5_ret_uint32(in
, &version
));
553 INSIST(version
== VERSION2
);
554 CHECK(ret_principal_ent(contextp
->context
, in
, &ent
));
555 CHECK(krb5_ret_uint32(in
, &mask
));
556 CHECK(ret_string_xdr(in
, &password
));
558 INSIST(ent
.principal
);
561 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_ADD
, ent
.principal
);
565 ret
= kadm5_create_principal(contextp
, &ent
, mask
, password
);
568 krb5_warn(contextp
->context
, ret
, "create principal");
569 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
570 CHECK(krb5_store_uint32(out
, ret
)); /* code */
573 kadm5_free_principal_ent(contextp
, &ent
);
577 proc_delete_principal(kadm5_server_context
*contextp
,
582 krb5_principal princ
;
585 CHECK(krb5_ret_uint32(in
, &version
));
586 INSIST(version
== VERSION2
);
587 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
589 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_DELETE
, princ
);
593 ret
= kadm5_delete_principal(contextp
, princ
);
596 krb5_warn(contextp
->context
, ret
, "delete principal");
597 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
598 CHECK(krb5_store_uint32(out
, ret
)); /* code */
600 krb5_free_principal(contextp
->context
, princ
);
604 proc_get_principal(kadm5_server_context
*contextp
,
608 uint32_t version
, mask
;
609 krb5_principal princ
;
610 kadm5_principal_ent_rec ent
;
613 memset(&ent
, 0, sizeof(ent
));
615 CHECK(krb5_ret_uint32(in
, &version
));
616 INSIST(version
== VERSION2
);
617 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
618 CHECK(krb5_ret_uint32(in
, &mask
));
620 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_GET
, princ
);
624 ret
= kadm5_get_principal(contextp
, princ
, &ent
, mask
);
627 krb5_warn(contextp
->context
, ret
, "get principal principal");
629 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
630 CHECK(krb5_store_uint32(out
, ret
)); /* code */
632 CHECK(store_principal_ent(contextp
->context
, out
, &ent
));
634 krb5_free_principal(contextp
->context
, princ
);
635 kadm5_free_principal_ent(contextp
, &ent
);
639 proc_chrand_principal_v2(kadm5_server_context
*contextp
,
644 krb5_principal princ
;
646 krb5_keyblock
*new_keys
;
649 CHECK(krb5_ret_uint32(in
, &version
));
650 INSIST(version
== VERSION2
);
651 CHECK(ret_principal_xdr(contextp
->context
, in
, &princ
));
653 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_CPW
, princ
);
657 ret
= kadm5_randkey_principal(contextp
, princ
,
661 krb5_warn(contextp
->context
, ret
, "rand key principal");
663 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
664 CHECK(krb5_store_uint32(out
, ret
));
667 CHECK(krb5_store_int32(out
, n_keys
));
669 for(i
= 0; i
< n_keys
; i
++){
670 CHECK(krb5_store_uint32(out
, new_keys
[i
].keytype
));
671 CHECK(store_data_xdr(out
, new_keys
[i
].keyvalue
));
672 krb5_free_keyblock_contents(contextp
->context
, &new_keys
[i
]);
676 krb5_free_principal(contextp
->context
, princ
);
680 proc_init(kadm5_server_context
*contextp
,
684 CHECK(krb5_store_uint32(out
, VERSION2
)); /* api version */
685 CHECK(krb5_store_uint32(out
, 0)); /* code */
686 CHECK(krb5_store_uint32(out
, 0)); /* code */
691 void (*func
)(kadm5_server_context
*, krb5_storage
*, krb5_storage
*);
694 { "create principal", proc_create_principal
},
695 { "delete principal", proc_delete_principal
},
696 { "modify principal", NULL
},
697 { "rename principal", NULL
},
698 { "get principal", proc_get_principal
},
699 { "chpass principal", NULL
},
700 { "chrand principal", proc_chrand_principal_v2
},
701 { "create policy", NULL
},
702 { "delete policy", NULL
},
703 { "modify policy", NULL
},
704 { "get policy", NULL
},
705 { "get privs", NULL
},
706 { "init", proc_init
},
707 { "get principals", NULL
},
708 { "get polices", NULL
},
709 { "setkey principal", NULL
},
710 { "setkey principal v4", NULL
},
711 { "create principal v3", NULL
},
712 { "chpass principal v3", NULL
},
713 { "chrand principal v3", NULL
},
714 { "setkey principal v3", NULL
}
717 static krb5_error_code
718 copyheader(krb5_storage
*sp
, krb5_data
*data
)
723 off
= krb5_storage_seek(sp
, 0, SEEK_CUR
);
725 CHECK(krb5_data_alloc(data
, off
));
726 INSIST((size_t)off
== data
->length
);
727 krb5_storage_seek(sp
, 0, SEEK_SET
);
728 sret
= krb5_storage_read(sp
, data
->data
, data
->length
);
730 INSIST(off
== krb5_storage_seek(sp
, 0, SEEK_CUR
));
744 process_stream(krb5_context contextp
,
745 unsigned char *buf
, size_t ilen
,
749 krb5_storage
*msg
, *reply
, *dreply
;
750 OM_uint32 maj_stat
, min_stat
;
751 gss_buffer_desc gin
, gout
;
753 void *server_handle
= NULL
;
755 memset(&gctx
, 0, sizeof(gctx
));
757 msg
= krb5_storage_emem();
758 reply
= krb5_storage_emem();
759 dreply
= krb5_storage_emem();
762 * First packet comes partly from the caller
768 struct call_header chdr
;
771 krb5_data headercopy
;
773 krb5_storage_truncate(dreply
, 0);
774 krb5_storage_truncate(reply
, 0);
775 krb5_storage_truncate(msg
, 0);
777 krb5_data_zero(&headercopy
);
778 memset(&chdr
, 0, sizeof(chdr
));
779 memset(&gcred
, 0, sizeof(gcred
));
782 * This is very icky to handle the the auto-detection between
783 * the Heimdal protocol and the MIT ONC-RPC based protocol.
790 unsigned char tmp
[4];
793 memcpy(tmp
, buf
, ilen
);
794 slen
= krb5_storage_read(sp
, tmp
+ ilen
, sizeof(tmp
) - ilen
);
795 INSIST((size_t)slen
== sizeof(tmp
) - ilen
);
802 _krb5_get_int(buf
, &len
, 4);
803 last_fragment
= (len
& LAST_FRAGMENT
) != 0;
804 len
&= ~LAST_FRAGMENT
;
811 slen
= krb5_storage_write(msg
, buf
, len
);
812 INSIST((size_t)slen
== len
);
816 slen
= krb5_storage_write(msg
, buf
, ilen
);
817 INSIST((size_t)slen
== ilen
);
822 CHECK(read_data(sp
, msg
, len
));
824 if (!last_fragment
) {
825 ret
= collect_framents(sp
, msg
);
826 if (ret
== HEIM_ERR_EOF
)
827 krb5_errx(contextp
, 0, "client disconnected");
832 ret
= collect_framents(sp
, msg
);
833 if (ret
== HEIM_ERR_EOF
)
834 krb5_errx(contextp
, 0, "client disconnected");
837 krb5_storage_seek(msg
, 0, SEEK_SET
);
839 CHECK(krb5_ret_uint32(msg
, &chdr
.xid
));
840 CHECK(krb5_ret_uint32(msg
, &mtype
));
841 CHECK(krb5_ret_uint32(msg
, &chdr
.rpcvers
));
842 CHECK(krb5_ret_uint32(msg
, &chdr
.prog
));
843 CHECK(krb5_ret_uint32(msg
, &chdr
.vers
));
844 CHECK(krb5_ret_uint32(msg
, &chdr
.proc
));
845 CHECK(ret_auth_opaque(msg
, &chdr
.cred
));
846 CHECK(copyheader(msg
, &headercopy
));
847 CHECK(ret_auth_opaque(msg
, &chdr
.verf
));
849 INSIST(chdr
.rpcvers
== RPC_VERSION
);
850 INSIST(chdr
.prog
== KADM_SERVER
);
851 INSIST(chdr
.vers
== VVERSION
);
852 INSIST(chdr
.cred
.flavor
== FLAVOR_GSS
);
854 CHECK(ret_gcred(&chdr
.cred
.data
, &gcred
));
856 INSIST(gcred
.version
== FLAVOR_GSS_VERSION
);
859 INSIST(chdr
.verf
.flavor
== FLAVOR_GSS
);
861 /* from first byte to last of credential */
862 gin
.value
= headercopy
.data
;
863 gin
.length
= headercopy
.length
;
864 gout
.value
= chdr
.verf
.data
.data
;
865 gout
.length
= chdr
.verf
.data
.length
;
867 maj_stat
= gss_verify_mic(&min_stat
, gctx
.ctx
, &gin
, &gout
, NULL
);
868 INSIST(maj_stat
== GSS_S_COMPLETE
);
878 INSIST(gcred
.service
== rpg_privacy
);
882 INSIST(krb5_data_cmp(&gcred
.handle
, &gctx
.handle
) == 0);
884 CHECK(ret_data_xdr(msg
, &data
));
886 gin
.value
= data
.data
;
887 gin
.length
= data
.length
;
889 maj_stat
= gss_unwrap(&min_stat
, gctx
.ctx
, &gin
, &gout
,
891 krb5_data_free(&data
);
892 INSIST(maj_stat
== GSS_S_COMPLETE
);
893 INSIST(conf_state
!= 0);
895 sp1
= krb5_storage_from_mem(gout
.value
, gout
.length
);
898 CHECK(krb5_ret_uint32(sp1
, &seq
));
899 INSIST (seq
== gcred
.seq_num
);
902 * Check sequence number
904 INSIST(seq
> gctx
.seq_num
);
908 * If contextp is setup, priv data have the seq_num stored
909 * first in the block, so add it here before users data is
912 CHECK(krb5_store_uint32(dreply
, gctx
.seq_num
));
914 if (chdr
.proc
>= sizeof(procs
)/sizeof(procs
[0])) {
915 krb5_warnx(contextp
, "proc number out of array");
916 } else if (procs
[chdr
.proc
].func
== NULL
) {
917 krb5_warnx(contextp
, "proc '%s' never implemented",
918 procs
[chdr
.proc
].name
);
920 krb5_warnx(contextp
, "proc %s", procs
[chdr
.proc
].name
);
921 INSIST(server_handle
!= NULL
);
922 (*procs
[chdr
.proc
].func
)(server_handle
, sp
, dreply
);
924 krb5_storage_free(sp
);
925 gss_release_buffer(&min_stat
, &gout
);
930 INSIST(gctx
.inprogress
== 0);
931 INSIST(gctx
.ctx
== NULL
);
935 case RPG_CONTINUE_INIT
: {
936 gss_name_t src_name
= GSS_C_NO_NAME
;
939 INSIST(gctx
.inprogress
);
941 CHECK(ret_data_xdr(msg
, &in
));
944 gin
.length
= in
.length
;
948 maj_stat
= gss_accept_sec_context(&min_stat
,
952 GSS_C_NO_CHANNEL_BINDINGS
,
959 if (GSS_ERROR(maj_stat
)) {
960 gss_print_errors(contextp
, maj_stat
, min_stat
);
961 krb5_errx(contextp
, 1, "gss error, exit");
963 if ((maj_stat
& GSS_S_CONTINUE_NEEDED
) == 0) {
964 kadm5_config_params realm_params
;
965 gss_buffer_desc bufp
;
970 memset(&realm_params
, 0, sizeof(realm_params
));
972 maj_stat
= gss_export_name(&min_stat
, src_name
, &bufp
);
973 INSIST(maj_stat
== GSS_S_COMPLETE
);
975 CHECK(parse_name(bufp
.value
, bufp
.length
,
976 GSS_KRB5_MECHANISM
, &client
));
978 gss_release_buffer(&min_stat
, &bufp
);
980 krb5_warnx(contextp
, "%s connected", client
);
982 ret
= kadm5_s_init_with_password_ctx(contextp
,
992 INSIST(gctx
.ctx
!= GSS_C_NO_CONTEXT
);
994 CHECK(krb5_store_uint32(dreply
, 0));
995 CHECK(store_gss_init_res(dreply
, gctx
.handle
,
996 maj_stat
, min_stat
, 1, &gout
));
998 gss_release_buffer(&min_stat
, &gout
);
1000 gss_release_name(&min_stat
, &src_name
);
1005 krb5_errx(contextp
, 1, "client destroyed gss contextp");
1007 krb5_errx(contextp
, 1, "client sent unknown gsscode %d",
1011 krb5_data_free(&gcred
.handle
);
1012 krb5_data_free(&chdr
.cred
.data
);
1013 krb5_data_free(&chdr
.verf
.data
);
1014 krb5_data_free(&headercopy
);
1016 CHECK(krb5_store_uint32(reply
, chdr
.xid
));
1017 CHECK(krb5_store_uint32(reply
, 1)); /* REPLY */
1018 CHECK(krb5_store_uint32(reply
, 0)); /* MSG_ACCEPTED */
1023 CHECK(krb5_store_uint32(reply
, 0)); /* flavor_none */
1024 CHECK(krb5_store_uint32(reply
, 0)); /* length */
1026 CHECK(krb5_store_uint32(reply
, 0)); /* SUCCESS */
1028 CHECK(krb5_storage_to_data(dreply
, &data
));
1029 INSIST((size_t)krb5_storage_write(reply
, data
.data
, data
.length
) == data
.length
);
1030 krb5_data_free(&data
);
1033 uint32_t seqnum
= htonl(gctx
.seq_num
);
1036 gin
.value
= &seqnum
;
1037 gin
.length
= sizeof(seqnum
);
1039 maj_stat
= gss_get_mic(&min_stat
, gctx
.ctx
, 0, &gin
, &gout
);
1040 INSIST(maj_stat
== GSS_S_COMPLETE
);
1042 data
.data
= gout
.value
;
1043 data
.length
= gout
.length
;
1045 CHECK(krb5_store_uint32(reply
, FLAVOR_GSS
));
1046 CHECK(store_data_xdr(reply
, data
));
1047 gss_release_buffer(&min_stat
, &gout
);
1049 CHECK(krb5_store_uint32(reply
, 0)); /* SUCCESS */
1051 CHECK(krb5_storage_to_data(dreply
, &data
));
1053 if (gctx
.inprogress
) {
1055 gctx
.inprogress
= 0;
1056 sret
= krb5_storage_write(reply
, data
.data
, data
.length
);
1057 INSIST((size_t)sret
== data
.length
);
1058 krb5_data_free(&data
);
1062 gin
.value
= data
.data
;
1063 gin
.length
= data
.length
;
1065 maj_stat
= gss_wrap(&min_stat
, gctx
.ctx
, 1, 0,
1066 &gin
, &conf_state
, &gout
);
1067 INSIST(maj_stat
== GSS_S_COMPLETE
);
1068 INSIST(conf_state
!= 0);
1069 krb5_data_free(&data
);
1071 data
.data
= gout
.value
;
1072 data
.length
= gout
.length
;
1074 store_data_xdr(reply
, data
);
1075 gss_release_buffer(&min_stat
, &gout
);
1082 CHECK(krb5_storage_to_data(reply
, &data
));
1083 CHECK(krb5_store_uint32(sp
, data
.length
| LAST_FRAGMENT
));
1084 sret
= krb5_storage_write(sp
, data
.data
, data
.length
);
1085 INSIST((size_t)sret
== data
.length
);
1086 krb5_data_free(&data
);
1094 handle_mit(krb5_context contextp
, void *buf
, size_t len
, krb5_socket_t sock
)
1098 dcontext
= contextp
;
1100 sp
= krb5_storage_from_fd(sock
);
1103 process_stream(contextp
, buf
, len
, sp
);