2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3 * Authors: Doug Rabson <dfr@rabson.org>
4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/ctype.h>
32 #include <sys/param.h>
33 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
38 #include <sys/socketvar.h>
39 #include <sys/sysent.h>
40 #include <sys/sysproto.h>
42 #include <kgssapi/gssapi.h>
43 #include <kgssapi/gssapi_impl.h>
45 #include <rpc/rpc_com.h>
46 #include <rpc/rpcb_prot.h>
47 #include <rpc/rpcsec_gss.h>
50 report_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
52 OM_uint32 maj_stat, min_stat;
53 OM_uint32 message_context;
56 uprintf("major_stat=%d, minor_stat=%d\n", maj, min);
59 maj_stat = gss_display_status(&min_stat, maj,
60 GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf);
61 if (GSS_ERROR(maj_stat))
63 uprintf("%.*s\n", (int)buf.length, (char *) buf.value);
64 gss_release_buffer(&min_stat, &buf);
65 } while (message_context);
69 maj_stat = gss_display_status(&min_stat, min,
70 GSS_C_MECH_CODE, mech, &message_context, &buf);
71 if (GSS_ERROR(maj_stat))
73 uprintf("%.*s\n", (int)buf.length, (char *) buf.value);
74 gss_release_buffer(&min_stat, &buf);
75 } while (message_context);
81 send_token_to_peer(const gss_buffer_t token)
86 printf("send token:\n");
87 printf("%d ", (int) token->length);
88 p = (const uint8_t *) token->value;
89 for (i = 0; i < token->length; i++)
95 receive_token_from_peer(gss_buffer_t token)
102 printf("receive token:\n");
103 fgets(line, sizeof(line), stdin);
104 if (line[strlen(line) - 1] != '\n') {
105 printf("token truncated\n");
109 if (sscanf(line, "%d ", &len) != 1) {
110 printf("bad token\n");
113 p = strchr(p, ' ') + 1;
115 token->value = malloc(len);
116 q = (uint8_t *) token->value;
118 if (sscanf(p, "%02x", &val) != 1) {
119 printf("bad token\n");
131 server(int argc, char** argv)
133 OM_uint32 maj_stat, min_stat;
134 gss_buffer_desc input_token, output_token;
135 gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
136 gss_name_t client_name;
143 receive_token_from_peer(&input_token);
144 maj_stat = gss_accept_sec_context(&min_stat,
148 GSS_C_NO_CHANNEL_BINDINGS,
155 if (GSS_ERROR(maj_stat)) {
156 report_error(mech_type, maj_stat, min_stat);
158 if (output_token.length != 0) {
159 send_token_to_peer(&output_token);
160 gss_release_buffer(&min_stat, &output_token);
162 if (GSS_ERROR(maj_stat)) {
163 if (context_hdl != GSS_C_NO_CONTEXT)
164 gss_delete_sec_context(&min_stat,
169 } while (maj_stat & GSS_S_CONTINUE_NEEDED);
172 gss_buffer_desc name_desc;
175 gss_display_name(&min_stat, client_name, &name_desc, NULL);
176 memcpy(buf, name_desc.value, name_desc.length);
177 buf[name_desc.length] = 0;
178 gss_release_buffer(&min_stat, &name_desc);
179 printf("client name is %s\n", buf);
182 receive_token_from_peer(&input_token);
183 gss_unwrap(&min_stat, context_hdl, &input_token, &output_token,
185 printf("%.*s\n", (int)output_token.length, (char *) output_token.value);
186 gss_release_buffer(&min_stat, &output_token);
190 /* 1.2.752.43.13.14 */
191 static gss_OID_desc gss_krb5_set_allowable_enctypes_x_desc =
192 {6, (void *) "\x2a\x85\x70\x2b\x0d\x0e"};
194 gss_OID GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X = &gss_krb5_set_allowable_enctypes_x_desc;
195 #define ETYPE_DES_CBC_CRC 1
198 * Create an initiator context and acceptor context in the kernel and
199 * use them to exchange signed and sealed messages.
202 gsstest_1(struct thread *td)
204 OM_uint32 maj_stat, min_stat;
205 OM_uint32 smaj_stat, smin_stat;
206 int context_established = 0;
207 gss_ctx_id_t client_context = GSS_C_NO_CONTEXT;
208 gss_ctx_id_t server_context = GSS_C_NO_CONTEXT;
209 gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL;
210 gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
211 gss_name_t name = GSS_C_NO_NAME;
212 gss_name_t received_name = GSS_C_NO_NAME;
213 gss_buffer_desc name_desc;
214 gss_buffer_desc client_token, server_token, message_buf;
215 gss_OID mech, actual_mech, mech_type;
216 static gss_OID_desc krb5_desc =
217 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
219 static gss_OID_desc spnego_desc =
220 {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
221 static gss_OID_desc ntlm_desc =
222 {10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"};
224 char enctype[sizeof(uint32_t)];
229 static char sbuf[512];
230 memcpy(sbuf, "nfs@", 4);
231 getcredhostname(td->td_ucred, sbuf + 4, sizeof(sbuf) - 4);
232 name_desc.value = sbuf;
235 name_desc.length = strlen((const char *) name_desc.value);
236 maj_stat = gss_import_name(&min_stat, &name_desc,
237 GSS_C_NT_HOSTBASED_SERVICE, &name);
238 if (GSS_ERROR(maj_stat)) {
239 printf("gss_import_name failed\n");
240 report_error(mech, maj_stat, min_stat);
244 maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME,
245 0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred,
247 if (GSS_ERROR(maj_stat)) {
248 printf("gss_acquire_cred (client) failed\n");
249 report_error(mech, maj_stat, min_stat);
253 enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff;
254 enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff;
255 enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff;
256 enctype[3] = ETYPE_DES_CBC_CRC & 0xff;
257 message_buf.length = sizeof(enctype);
258 message_buf.value = enctype;
259 maj_stat = gss_set_cred_option(&min_stat, &client_cred,
260 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf);
261 if (GSS_ERROR(maj_stat)) {
262 printf("gss_set_cred_option failed\n");
263 report_error(mech, maj_stat, min_stat);
267 server_token.length = 0;
268 server_token.value = NULL;
269 while (!context_established) {
270 client_token.length = 0;
271 client_token.value = NULL;
272 maj_stat = gss_init_sec_context(&min_stat,
277 GSS_C_MUTUAL_FLAG|GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG,
279 GSS_C_NO_CHANNEL_BINDINGS,
285 if (server_token.length)
286 gss_release_buffer(&smin_stat, &server_token);
287 if (GSS_ERROR(maj_stat)) {
288 printf("gss_init_sec_context failed\n");
289 report_error(mech, maj_stat, min_stat);
293 if (client_token.length != 0) {
295 gss_OID_set_desc oid_set;
297 oid_set.elements = &krb5_desc;
298 smaj_stat = gss_acquire_cred(&smin_stat,
299 name, 0, &oid_set, GSS_C_ACCEPT, &server_cred,
301 if (GSS_ERROR(smaj_stat)) {
302 printf("gss_acquire_cred (server) failed\n");
303 report_error(mech_type, smaj_stat, smin_stat);
307 smaj_stat = gss_accept_sec_context(&smin_stat,
311 GSS_C_NO_CHANNEL_BINDINGS,
318 if (GSS_ERROR(smaj_stat)) {
319 printf("gss_accept_sec_context failed\n");
320 report_error(mech_type, smaj_stat, smin_stat);
323 gss_release_buffer(&min_stat, &client_token);
325 if (GSS_ERROR(maj_stat)) {
326 if (client_context != GSS_C_NO_CONTEXT)
327 gss_delete_sec_context(&min_stat,
333 if (maj_stat == GSS_S_COMPLETE) {
334 context_established = 1;
338 message_buf.length = strlen("Hello world");
339 message_buf.value = (void *) "Hello world";
341 maj_stat = gss_get_mic(&min_stat, client_context,
342 GSS_C_QOP_DEFAULT, &message_buf, &client_token);
343 if (GSS_ERROR(maj_stat)) {
344 printf("gss_get_mic failed\n");
345 report_error(mech_type, maj_stat, min_stat);
348 maj_stat = gss_verify_mic(&min_stat, server_context,
349 &message_buf, &client_token, NULL);
350 if (GSS_ERROR(maj_stat)) {
351 printf("gss_verify_mic failed\n");
352 report_error(mech_type, maj_stat, min_stat);
355 gss_release_buffer(&min_stat, &client_token);
357 maj_stat = gss_wrap(&min_stat, client_context,
358 TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, &client_token);
359 if (GSS_ERROR(maj_stat)) {
360 printf("gss_wrap failed\n");
361 report_error(mech_type, maj_stat, min_stat);
364 maj_stat = gss_unwrap(&min_stat, server_context,
365 &client_token, &server_token, NULL, NULL);
366 if (GSS_ERROR(maj_stat)) {
367 printf("gss_unwrap failed\n");
368 report_error(mech_type, maj_stat, min_stat);
372 if (message_buf.length != server_token.length
373 || memcmp(message_buf.value, server_token.value,
375 printf("unwrap result corrupt\n");
377 gss_release_buffer(&min_stat, &client_token);
378 gss_release_buffer(&min_stat, &server_token);
382 gss_delete_sec_context(&min_stat, &client_context,
385 gss_delete_sec_context(&min_stat, &server_context,
388 gss_release_cred(&min_stat, &client_cred);
390 gss_release_cred(&min_stat, &server_cred);
392 gss_release_name(&min_stat, &name);
394 gss_release_name(&min_stat, &received_name);
400 * Interoperability with userland. This takes several steps:
402 * 1. Accept an initiator token from userland, return acceptor
403 * token. Repeat this step until both userland and kernel return
406 * 2. Receive a signed message from userland and verify the
407 * signature. Return a signed reply to userland for it to verify.
409 * 3. Receive a wrapped message from userland and unwrap it. Return a
410 * wrapped reply to userland.
413 gsstest_2(struct thread *td, int step, const gss_buffer_t input_token,
414 OM_uint32 *maj_stat_res, OM_uint32 *min_stat_res, gss_buffer_t output_token)
416 OM_uint32 maj_stat, min_stat;
417 static int context_established = 0;
418 static gss_ctx_id_t server_context = GSS_C_NO_CONTEXT;
419 static gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
420 static gss_name_t name = GSS_C_NO_NAME;
421 gss_buffer_desc name_desc;
422 gss_buffer_desc message_buf;
423 gss_OID mech_type = GSS_C_NO_OID;
424 char enctype[sizeof(uint32_t)];
427 maj_stat = GSS_S_FAILURE;
432 if (server_context == GSS_C_NO_CONTEXT) {
433 static char sbuf[512];
434 memcpy(sbuf, "nfs@", 4);
435 getcredhostname(td->td_ucred, sbuf + 4,
437 name_desc.value = sbuf;
438 name_desc.length = strlen((const char *)
440 maj_stat = gss_import_name(&min_stat, &name_desc,
441 GSS_C_NT_HOSTBASED_SERVICE, &name);
442 if (GSS_ERROR(maj_stat)) {
443 printf("gss_import_name failed\n");
444 report_error(mech_type, maj_stat, min_stat);
448 maj_stat = gss_acquire_cred(&min_stat,
449 name, 0, GSS_C_NO_OID_SET, GSS_C_ACCEPT,
450 &server_cred, NULL, NULL);
451 if (GSS_ERROR(maj_stat)) {
452 printf("gss_acquire_cred (server) failed\n");
453 report_error(mech_type, maj_stat, min_stat);
457 enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff;
458 enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff;
459 enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff;
460 enctype[3] = ETYPE_DES_CBC_CRC & 0xff;
461 message_buf.length = sizeof(enctype);
462 message_buf.value = enctype;
463 maj_stat = gss_set_cred_option(&min_stat, &server_cred,
464 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf);
465 if (GSS_ERROR(maj_stat)) {
466 printf("gss_set_cred_option failed\n");
467 report_error(mech_type, maj_stat, min_stat);
472 maj_stat = gss_accept_sec_context(&min_stat,
476 GSS_C_NO_CHANNEL_BINDINGS,
483 if (GSS_ERROR(maj_stat)) {
484 printf("gss_accept_sec_context failed\n");
485 report_error(mech_type, maj_stat, min_stat);
489 if (maj_stat == GSS_S_COMPLETE) {
490 context_established = 1;
492 *maj_stat_res = maj_stat;
493 *min_stat_res = min_stat;
497 message_buf.length = strlen("Hello world");
498 message_buf.value = (void *) "Hello world";
500 maj_stat = gss_verify_mic(&min_stat, server_context,
501 &message_buf, input_token, NULL);
502 if (GSS_ERROR(maj_stat)) {
503 printf("gss_verify_mic failed\n");
504 report_error(mech_type, maj_stat, min_stat);
508 maj_stat = gss_get_mic(&min_stat, server_context,
509 GSS_C_QOP_DEFAULT, &message_buf, output_token);
510 if (GSS_ERROR(maj_stat)) {
511 printf("gss_get_mic failed\n");
512 report_error(mech_type, maj_stat, min_stat);
518 maj_stat = gss_unwrap(&min_stat, server_context,
519 input_token, &message_buf, NULL, NULL);
520 if (GSS_ERROR(maj_stat)) {
521 printf("gss_unwrap failed\n");
522 report_error(mech_type, maj_stat, min_stat);
525 gss_release_buffer(&min_stat, &message_buf);
527 message_buf.length = strlen("Hello world");
528 message_buf.value = (void *) "Hello world";
529 maj_stat = gss_wrap(&min_stat, server_context,
530 TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token);
531 if (GSS_ERROR(maj_stat)) {
532 printf("gss_wrap failed\n");
533 report_error(mech_type, maj_stat, min_stat);
539 maj_stat = gss_unwrap(&min_stat, server_context,
540 input_token, &message_buf, NULL, NULL);
541 if (GSS_ERROR(maj_stat)) {
542 printf("gss_unwrap failed\n");
543 report_error(mech_type, maj_stat, min_stat);
546 gss_release_buffer(&min_stat, &message_buf);
548 message_buf.length = strlen("Hello world");
549 message_buf.value = (void *) "Hello world";
550 maj_stat = gss_wrap(&min_stat, server_context,
551 FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token);
552 if (GSS_ERROR(maj_stat)) {
553 printf("gss_wrap failed\n");
554 report_error(mech_type, maj_stat, min_stat);
563 *maj_stat_res = maj_stat;
564 *min_stat_res = min_stat;
568 *maj_stat_res = maj_stat;
569 *min_stat_res = min_stat;
571 gss_delete_sec_context(&min_stat, &server_context,
574 gss_release_cred(&min_stat, &server_cred);
576 gss_release_name(&min_stat, &name);
582 * Create an RPC client handle for the given (address,prog,vers)
586 gsstest_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers)
588 struct thread *td = curthread;
589 const char* protofmly;
590 struct sockaddr_storage ss;
596 enum clnt_stat stat = RPC_SUCCESS;
597 int rpcvers = RPCBVERS4;
598 bool_t do_tcp = FALSE;
599 struct portmap mapping;
603 * First we need to contact the remote RPCBIND service to find
606 memcpy(&ss, sa, sa->sa_len);
607 switch (ss.ss_family) {
609 ((struct sockaddr_in *)&ss)->sin_port = htons(111);
611 socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td);
616 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111);
618 socreate(AF_INET6, &so, SOCK_DGRAM, 0, td->td_ucred, td);
624 * Unsupported address family - fail.
629 rpcb = clnt_dg_create(so, (struct sockaddr *)&ss,
630 RPCBPROG, rpcvers, 0, 0);
638 parms.r_netid = "tcp";
640 parms.r_netid = "udp";
645 * Use the default timeout.
654 * Try RPCBIND 4 then 3.
657 stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR,
658 (xdrproc_t) xdr_rpcb, &parms,
659 (xdrproc_t) xdr_wrapstring, &uaddr, timo);
660 if (stat == RPC_PROGVERSMISMATCH) {
661 if (rpcvers == RPCBVERS4)
663 else if (rpcvers == RPCBVERS)
665 CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers);
667 } else if (stat == RPC_SUCCESS) {
669 * We have a reply from the remote RPCBIND - turn it
670 * into an appropriate address and make a new client
671 * that can talk to the remote service.
673 * XXX fixup IPv6 scope ID.
676 a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr);
677 xdr_free((xdrproc_t) xdr_wrapstring, &uaddr);
682 memcpy(&ss, a->buf, a->len);
691 mapping.pm_prog = parms.r_prog;
692 mapping.pm_vers = parms.r_vers;
693 mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP;
696 stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT,
697 (xdrproc_t) xdr_portmap, &mapping,
698 (xdrproc_t) xdr_u_short, &port, timo);
700 if (stat == RPC_SUCCESS) {
701 switch (ss.ss_family) {
703 ((struct sockaddr_in *)&ss)->sin_port =
709 ((struct sockaddr_in6 *)&ss)->sin6_port =
717 panic("invalid rpcvers %d", rpcvers);
720 * We may have a positive response from the portmapper, but
721 * the requested service was not found. Make sure we received
724 switch (ss.ss_family) {
726 port = ((struct sockaddr_in *)&ss)->sin_port;
730 port = ((struct sockaddr_in6 *)&ss)->sin6_port;
734 if (stat != RPC_SUCCESS || !port) {
736 * If we were able to talk to rpcbind or portmap, but the udp
737 * variant wasn't available, ask about tcp.
739 * XXX - We could also check for a TCP portmapper, but
740 * if the host is running a portmapper at all, we should be able
741 * to hail it over UDP.
743 if (stat == RPC_SUCCESS && !do_tcp) {
748 /* Otherwise, bad news. */
749 printf("gsstest_get_rpc: failed to contact remote rpcbind, "
750 "stat = %d, port = %d\n",
758 * Destroy the UDP client we used to speak to rpcbind and
759 * recreate as a TCP client.
761 struct netconfig *nconf = NULL;
765 switch (ss.ss_family) {
767 nconf = getnetconfigent("tcp");
771 nconf = getnetconfigent("tcp6");
776 rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss,
780 * Re-use the client we used to speak to rpcbind.
782 CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss);
783 CLNT_CONTROL(rpcb, CLSET_PROG, &prog);
784 CLNT_CONTROL(rpcb, CLSET_VERS, &vers);
794 gsstest_3(struct thread *td)
796 struct sockaddr_in sin;
800 rpc_gss_options_ret_t options_ret;
803 rpc_gss_service_t svc;
806 sin.sin_len = sizeof(sin);
807 sin.sin_family = AF_INET;
808 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
811 client = gsstest_get_rpc((struct sockaddr *) &sin, 123456, 1);
813 uprintf("Can't connect to service\n");
817 memcpy(service, "host@", 5);
818 getcredhostname(td->td_ucred, service + 5, sizeof(service) - 5);
820 auth = rpc_gss_seccreate(client, curthread->td_ucred,
821 service, "kerberosv5", rpc_gss_svc_privacy,
822 NULL, NULL, &options_ret);
825 uprintf("Can't authorize to service (mech=%s)\n",
826 options_ret.actual_mechanism);
828 rpc_gss_mech_to_oid(options_ret.actual_mechanism, &oid);
829 report_error(oid, options_ret.major_status,
830 options_ret.minor_status);
831 CLNT_DESTROY(client);
835 for (svc = rpc_gss_svc_none; svc <= rpc_gss_svc_privacy; svc++) {
836 const char *svc_names[] = {
837 "rpc_gss_svc_default",
839 "rpc_gss_svc_integrity",
840 "rpc_gss_svc_privacy"
844 rpc_gss_set_defaults(auth, svc, NULL);
846 client->cl_auth = auth;
849 for (i = 42; i < 142; i++) {
851 stat = CLNT_CALL(client, 1,
852 (xdrproc_t) xdr_int, (char *) &num,
853 (xdrproc_t) xdr_int, (char *) &num, tv);
854 if (stat == RPC_SUCCESS) {
856 uprintf("unexpected reply %d\n", num);
858 uprintf("call failed, stat=%d\n", (int) stat);
863 uprintf("call succeeded with %s\n", svc_names[svc]);
867 CLNT_RELEASE(client);
875 static rpc_gss_principal_t server_acl = NULL;
876 static bool_t server_new_context(struct svc_req *req, gss_cred_id_t deleg,
877 gss_ctx_id_t gss_context, rpc_gss_lock_t *lock, void **cookie);
878 static void server_program_1(struct svc_req *rqstp, register SVCXPRT *transp);
881 gsstest_4(struct thread *td)
884 char principal[128 + 5];
886 static rpc_gss_callback_t cb;
888 memcpy(principal, "host@", 5);
889 getcredhostname(td->td_ucred, principal + 5, sizeof(principal) - 5);
891 mechs = rpc_gss_get_mechanisms();
893 if (!rpc_gss_set_svc_name(principal, *mechs, GSS_C_INDEFINITE,
897 rpc_gss_get_error(&e);
898 printf("setting name for %s for %s failed: %d, %d\n",
900 e.rpc_gss_error, e.system_error);
907 cb.callback = server_new_context;
908 rpc_gss_set_callback(&cb);
910 pool = svcpool_create("gsstest", NULL);
912 svc_create(pool, server_program_1, 123456, 1, NULL);
915 rpc_gss_clear_svc_name(123456, 1);
916 rpc_gss_clear_callback(&cb);
918 svcpool_destroy(pool);
924 server_program_1(struct svc_req *rqstp, register SVCXPRT *transp)
926 rpc_gss_rawcred_t *rcred;
927 rpc_gss_ucred_t *ucred;
930 if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS) {
931 svcerr_weakauth(rqstp);
935 if (!rpc_gss_getcred(rqstp, &rcred, &ucred, NULL)) {
936 svcerr_systemerr(rqstp);
940 printf("svc=%d, mech=%s, uid=%d, gid=%d, gids={",
941 rcred->service, rcred->mechanism, ucred->uid, ucred->gid);
942 for (i = 0; i < ucred->gidlen; i++) {
943 if (i > 0) printf(",");
944 printf("%d", ucred->gidlist[i]);
948 switch (rqstp->rq_proc) {
950 if (!svc_getargs(rqstp, (xdrproc_t) xdr_void, 0)) {
951 svcerr_decode(rqstp);
954 if (!svc_sendreply(rqstp, (xdrproc_t) xdr_void, 0)) {
955 svcerr_systemerr(rqstp);
960 if (!svc_getargs(rqstp, (xdrproc_t) xdr_int,
962 svcerr_decode(rqstp);
966 if (!svc_sendreply(rqstp, (xdrproc_t) xdr_int,
968 svcerr_systemerr(rqstp);
973 svcerr_noproc(rqstp);
983 print_principal(rpc_gss_principal_t principal)
988 len = principal->len;
989 p = (uint8_t *) principal->name;
994 for (i = 0; i < n; i++)
995 printf("%02x ", p[i]);
999 for (i = 0; i < n; i++)
1000 printf("%c", isprint(p[i]) ? p[i] : '.');
1008 server_new_context(__unused struct svc_req *req,
1009 gss_cred_id_t deleg,
1010 __unused gss_ctx_id_t gss_context,
1011 rpc_gss_lock_t *lock,
1012 __unused void **cookie)
1014 rpc_gss_rawcred_t *rcred = lock->raw_cred;
1017 printf("new security context version=%d, mech=%s, qop=%s:\n",
1018 rcred->version, rcred->mechanism, rcred->qop);
1019 print_principal(rcred->client_principal);
1022 if (rcred->client_principal->len != server_acl->len
1023 || memcmp(rcred->client_principal->name, server_acl->name,
1028 gss_release_cred(&junk, &deleg);
1034 * Hook up a syscall for gssapi testing.
1037 struct gsstest_args {
1043 struct gsstest_2_args {
1044 int step; /* test step number */
1045 gss_buffer_desc input_token; /* token from userland */
1046 gss_buffer_desc output_token; /* buffer to receive reply token */
1048 struct gsstest_2_res {
1049 OM_uint32 maj_stat; /* maj_stat from kernel */
1050 OM_uint32 min_stat; /* min_stat from kernel */
1051 gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */
1055 gsstest(struct thread *td, struct gsstest_args *uap)
1059 switch (uap->a_op) {
1061 return (gsstest_1(td));
1064 struct gsstest_2_args args;
1065 struct gsstest_2_res res;
1066 gss_buffer_desc input_token, output_token;
1069 error = copyin(uap->a_args, &args, sizeof(args));
1072 input_token.length = args.input_token.length;
1073 input_token.value = malloc(input_token.length, M_GSSAPI,
1075 error = copyin(args.input_token.value, input_token.value,
1076 input_token.length);
1078 gss_release_buffer(&junk, &input_token);
1081 output_token.length = 0;
1082 output_token.value = NULL;
1083 gsstest_2(td, args.step, &input_token,
1084 &res.maj_stat, &res.min_stat, &output_token);
1085 gss_release_buffer(&junk, &input_token);
1086 if (output_token.length > args.output_token.length) {
1087 gss_release_buffer(&junk, &output_token);
1090 res.output_token.length = output_token.length;
1091 res.output_token.value = args.output_token.value;
1092 error = copyout(output_token.value, res.output_token.value,
1093 output_token.length);
1094 gss_release_buffer(&junk, &output_token);
1098 return (copyout(&res, uap->a_res, sizeof(res)));
1103 return (gsstest_3(td));
1105 return (gsstest_4(td));
1112 * The `sysent' for the new syscall
1114 static struct sysent gsstest_sysent = {
1116 (sy_call_t *) gsstest /* sy_call */
1120 * The offset in sysent where the syscall is allocated.
1122 static int gsstest_offset = NO_SYSCALL;
1125 * The function called at load/unload.
1130 gsstest_load(struct module *module, int cmd, void *arg)
1146 SYSCALL_MODULE(gsstest_syscall, &gsstest_offset, &gsstest_sysent,
1147 gsstest_load, NULL);