The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kgssapi/gsstest.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
    5  * Authors: Doug Rabson <dfr@rabson.org>
    6  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    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.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/12.0/sys/kgssapi/gsstest.c 326279 2017-11-27 15:49:00Z pfg $");
   32 
   33 #include <sys/ctype.h>
   34 #include <sys/param.h>
   35 #include <sys/kernel.h>
   36 #include <sys/kobj.h>
   37 #include <sys/malloc.h>
   38 #include <sys/module.h>
   39 #include <sys/proc.h>
   40 #include <sys/socketvar.h>
   41 #include <sys/sysent.h>
   42 #include <sys/sysproto.h>
   43 
   44 #include <kgssapi/gssapi.h>
   45 #include <kgssapi/gssapi_impl.h>
   46 #include <rpc/rpc.h>
   47 #include <rpc/rpc_com.h>
   48 #include <rpc/rpcb_prot.h>
   49 #include <rpc/rpcsec_gss.h>
   50 
   51 static void
   52 report_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
   53 {
   54         OM_uint32 maj_stat, min_stat;
   55         OM_uint32 message_context;
   56         gss_buffer_desc buf;
   57 
   58         uprintf("major_stat=%d, minor_stat=%d\n", maj, min);
   59         message_context = 0;
   60         do {
   61                 maj_stat = gss_display_status(&min_stat, maj,
   62                     GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf);
   63                 if (GSS_ERROR(maj_stat))
   64                         break;
   65                 uprintf("%.*s\n", (int)buf.length, (char *) buf.value);
   66                 gss_release_buffer(&min_stat, &buf);
   67         } while (message_context);
   68         if (mech && min) {
   69                 message_context = 0;
   70                 do {
   71                         maj_stat = gss_display_status(&min_stat, min,
   72                             GSS_C_MECH_CODE, mech, &message_context, &buf);
   73                         if (GSS_ERROR(maj_stat))
   74                                 break;
   75                         uprintf("%.*s\n", (int)buf.length, (char *) buf.value);
   76                         gss_release_buffer(&min_stat, &buf);
   77                 } while (message_context);
   78         }
   79 }
   80 
   81 #if 0
   82 static void
   83 send_token_to_peer(const gss_buffer_t token)
   84 {
   85         const uint8_t *p;
   86         size_t i;
   87 
   88         printf("send token:\n");
   89         printf("%d ", (int) token->length);
   90         p = (const uint8_t *) token->value;
   91         for (i = 0; i < token->length; i++)
   92                 printf("%02x", *p++);
   93         printf("\n");
   94 }
   95 
   96 static void
   97 receive_token_from_peer(gss_buffer_t token)
   98 {
   99         char line[8192];
  100         char *p;
  101         uint8_t *q;
  102         int len, val;
  103 
  104         printf("receive token:\n");
  105         fgets(line, sizeof(line), stdin);
  106         if (line[strlen(line) - 1] != '\n') {
  107                 printf("token truncated\n");
  108                 exit(1);
  109         }
  110         p = line;
  111         if (sscanf(line, "%d ", &len) != 1) {
  112                 printf("bad token\n");
  113                 exit(1);
  114         }
  115         p = strchr(p, ' ') + 1;
  116         token->length = len;
  117         token->value = malloc(len);
  118         q = (uint8_t *) token->value;
  119         while (len) {
  120                 if (sscanf(p, "%02x", &val) != 1) {
  121                         printf("bad token\n");
  122                         exit(1);
  123                 }
  124                 *q++ = val;
  125                 p += 2;
  126                 len--;
  127         }
  128 }
  129 #endif
  130 
  131 #if 0
  132 void
  133 server(int argc, char** argv)
  134 {
  135         OM_uint32 maj_stat, min_stat;
  136         gss_buffer_desc input_token, output_token;
  137         gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
  138         gss_name_t client_name;
  139         gss_OID mech_type;
  140 
  141         if (argc != 1)
  142                 usage();
  143 
  144         do {
  145                 receive_token_from_peer(&input_token);
  146                 maj_stat = gss_accept_sec_context(&min_stat,
  147                     &context_hdl,
  148                     GSS_C_NO_CREDENTIAL,
  149                     &input_token,
  150                     GSS_C_NO_CHANNEL_BINDINGS,
  151                     &client_name,
  152                     &mech_type,
  153                     &output_token,
  154                     NULL,
  155                     NULL,
  156                     NULL);
  157                 if (GSS_ERROR(maj_stat)) {
  158                         report_error(mech_type, maj_stat, min_stat);
  159                 }
  160                 if (output_token.length != 0) {
  161                         send_token_to_peer(&output_token);
  162                         gss_release_buffer(&min_stat, &output_token);
  163                 }
  164                 if (GSS_ERROR(maj_stat)) {
  165                         if (context_hdl != GSS_C_NO_CONTEXT)
  166                                 gss_delete_sec_context(&min_stat,
  167                                     &context_hdl,
  168                                     GSS_C_NO_BUFFER);
  169                         break;
  170                 }
  171         } while (maj_stat & GSS_S_CONTINUE_NEEDED);
  172 
  173         if (client_name) {
  174                 gss_buffer_desc name_desc;
  175                 char buf[512];
  176 
  177                 gss_display_name(&min_stat, client_name, &name_desc, NULL);
  178                 memcpy(buf, name_desc.value, name_desc.length);
  179                 buf[name_desc.length] = 0;
  180                 gss_release_buffer(&min_stat, &name_desc);
  181                 printf("client name is %s\n", buf);
  182         }
  183 
  184         receive_token_from_peer(&input_token);
  185         gss_unwrap(&min_stat, context_hdl, &input_token, &output_token,
  186             NULL, NULL);
  187         printf("%.*s\n", (int)output_token.length, (char *) output_token.value);
  188         gss_release_buffer(&min_stat, &output_token);
  189 }
  190 #endif
  191 
  192 /* 1.2.752.43.13.14 */
  193 static gss_OID_desc gss_krb5_set_allowable_enctypes_x_desc =
  194 {6, (void *) "\x2a\x85\x70\x2b\x0d\x0e"};
  195 
  196 gss_OID GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X = &gss_krb5_set_allowable_enctypes_x_desc;
  197 #define ETYPE_DES_CBC_CRC       1
  198 
  199 /*
  200  * Create an initiator context and acceptor context in the kernel and
  201  * use them to exchange signed and sealed messages.
  202  */
  203 static int
  204 gsstest_1(struct thread *td)
  205 {
  206         OM_uint32 maj_stat, min_stat;
  207         OM_uint32 smaj_stat, smin_stat;
  208         int context_established = 0;
  209         gss_ctx_id_t client_context = GSS_C_NO_CONTEXT;
  210         gss_ctx_id_t server_context = GSS_C_NO_CONTEXT;
  211         gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL;
  212         gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
  213         gss_name_t name = GSS_C_NO_NAME;
  214         gss_name_t received_name = GSS_C_NO_NAME;
  215         gss_buffer_desc name_desc;
  216         gss_buffer_desc client_token, server_token, message_buf;
  217         gss_OID mech, actual_mech, mech_type;
  218         static gss_OID_desc krb5_desc =
  219                 {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
  220 #if 0
  221         static gss_OID_desc spnego_desc =
  222                 {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
  223         static gss_OID_desc ntlm_desc =
  224                 {10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"};
  225 #endif
  226         char enctype[sizeof(uint32_t)];
  227 
  228         mech = GSS_C_NO_OID;
  229 
  230         {
  231                 static char sbuf[512];
  232                 memcpy(sbuf, "nfs@", 4);
  233                 getcredhostname(td->td_ucred, sbuf + 4, sizeof(sbuf) - 4);
  234                 name_desc.value = sbuf;
  235         }
  236 
  237         name_desc.length = strlen((const char *) name_desc.value);
  238         maj_stat = gss_import_name(&min_stat, &name_desc,
  239             GSS_C_NT_HOSTBASED_SERVICE, &name);
  240         if (GSS_ERROR(maj_stat)) {
  241                 printf("gss_import_name failed\n");
  242                 report_error(mech, maj_stat, min_stat);
  243                 goto out;
  244         }
  245 
  246         maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME,
  247             0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred,
  248             NULL, NULL);
  249         if (GSS_ERROR(maj_stat)) {
  250                 printf("gss_acquire_cred (client) failed\n");
  251                 report_error(mech, maj_stat, min_stat);
  252                 goto out;
  253         }
  254 
  255         enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff;
  256         enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff;
  257         enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff;
  258         enctype[3] = ETYPE_DES_CBC_CRC & 0xff;
  259         message_buf.length = sizeof(enctype);
  260         message_buf.value = enctype;
  261         maj_stat = gss_set_cred_option(&min_stat, &client_cred,
  262             GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf);
  263         if (GSS_ERROR(maj_stat)) {
  264                 printf("gss_set_cred_option failed\n");
  265                 report_error(mech, maj_stat, min_stat);
  266                 goto out;
  267         }
  268 
  269         server_token.length = 0;
  270         server_token.value = NULL;
  271         while (!context_established) {
  272                 client_token.length = 0;
  273                 client_token.value = NULL;
  274                 maj_stat = gss_init_sec_context(&min_stat,
  275                     client_cred,
  276                     &client_context,
  277                     name,
  278                     mech,
  279                     GSS_C_MUTUAL_FLAG|GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG,
  280                     0,
  281                     GSS_C_NO_CHANNEL_BINDINGS,
  282                     &server_token,
  283                     &actual_mech,
  284                     &client_token,
  285                     NULL,
  286                     NULL);
  287                 if (server_token.length)
  288                         gss_release_buffer(&smin_stat, &server_token);
  289                 if (GSS_ERROR(maj_stat)) {
  290                         printf("gss_init_sec_context failed\n");
  291                         report_error(mech, maj_stat, min_stat);
  292                         goto out;
  293                 }
  294 
  295                 if (client_token.length != 0) {
  296                         if (!server_cred) {
  297                                 gss_OID_set_desc oid_set;
  298                                 oid_set.count = 1;
  299                                 oid_set.elements = &krb5_desc;
  300                                 smaj_stat = gss_acquire_cred(&smin_stat,
  301                                     name, 0, &oid_set, GSS_C_ACCEPT, &server_cred,
  302                                     NULL, NULL);
  303                                 if (GSS_ERROR(smaj_stat)) {
  304                                         printf("gss_acquire_cred (server) failed\n");
  305                                         report_error(mech_type, smaj_stat, smin_stat);
  306                                         goto out;
  307                                 }
  308                         }
  309                         smaj_stat = gss_accept_sec_context(&smin_stat,
  310                             &server_context,
  311                             server_cred,
  312                             &client_token,
  313                             GSS_C_NO_CHANNEL_BINDINGS,
  314                             &received_name,
  315                             &mech_type,
  316                             &server_token,
  317                             NULL,
  318                             NULL,
  319                             NULL);
  320                         if (GSS_ERROR(smaj_stat)) {
  321                                 printf("gss_accept_sec_context failed\n");
  322                                 report_error(mech_type, smaj_stat, smin_stat);
  323                                 goto out;
  324                         }
  325                         gss_release_buffer(&min_stat, &client_token);
  326                 }
  327                 if (GSS_ERROR(maj_stat)) {
  328                         if (client_context != GSS_C_NO_CONTEXT)
  329                                 gss_delete_sec_context(&min_stat,
  330                                     &client_context,
  331                                     GSS_C_NO_BUFFER);
  332                         break;
  333                 }
  334 
  335                 if (maj_stat == GSS_S_COMPLETE) {
  336                         context_established = 1;
  337                 }
  338         }
  339 
  340         message_buf.length = strlen("Hello world");
  341         message_buf.value = (void *) "Hello world";
  342 
  343         maj_stat = gss_get_mic(&min_stat, client_context,
  344             GSS_C_QOP_DEFAULT, &message_buf, &client_token);
  345         if (GSS_ERROR(maj_stat)) {
  346                 printf("gss_get_mic failed\n");
  347                 report_error(mech_type, maj_stat, min_stat);
  348                 goto out;
  349         }
  350         maj_stat = gss_verify_mic(&min_stat, server_context,
  351             &message_buf, &client_token, NULL);
  352         if (GSS_ERROR(maj_stat)) {
  353                 printf("gss_verify_mic failed\n");
  354                 report_error(mech_type, maj_stat, min_stat);
  355                 goto out;
  356         }
  357         gss_release_buffer(&min_stat, &client_token);
  358 
  359         maj_stat = gss_wrap(&min_stat, client_context,
  360             TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, &client_token);
  361         if (GSS_ERROR(maj_stat)) {
  362                 printf("gss_wrap failed\n");
  363                 report_error(mech_type, maj_stat, min_stat);
  364                 goto out;
  365         }
  366         maj_stat = gss_unwrap(&min_stat, server_context,
  367             &client_token, &server_token, NULL, NULL);
  368         if (GSS_ERROR(maj_stat)) {
  369                 printf("gss_unwrap failed\n");
  370                 report_error(mech_type, maj_stat, min_stat);
  371                 goto out;
  372         }
  373 
  374         if (message_buf.length != server_token.length
  375             || memcmp(message_buf.value, server_token.value,
  376                 message_buf.length))
  377                 printf("unwrap result corrupt\n");
  378         
  379         gss_release_buffer(&min_stat, &client_token);
  380         gss_release_buffer(&min_stat, &server_token);
  381 
  382 out:
  383         if (client_context)
  384                 gss_delete_sec_context(&min_stat, &client_context,
  385                     GSS_C_NO_BUFFER);
  386         if (server_context)
  387                 gss_delete_sec_context(&min_stat, &server_context,
  388                     GSS_C_NO_BUFFER);
  389         if (client_cred)
  390                 gss_release_cred(&min_stat, &client_cred);
  391         if (server_cred)
  392                 gss_release_cred(&min_stat, &server_cred);
  393         if (name)
  394                 gss_release_name(&min_stat, &name);
  395         if (received_name)
  396                 gss_release_name(&min_stat, &received_name);
  397 
  398         return (0);
  399 }
  400 
  401 /*
  402  * Interoperability with userland. This takes several steps:
  403  *
  404  * 1. Accept an initiator token from userland, return acceptor
  405  * token. Repeat this step until both userland and kernel return
  406  * GSS_S_COMPLETE.
  407  *
  408  * 2. Receive a signed message from userland and verify the
  409  * signature. Return a signed reply to userland for it to verify.
  410  *
  411  * 3. Receive a wrapped message from userland and unwrap it. Return a
  412  * wrapped reply to userland.
  413  */
  414 static int
  415 gsstest_2(struct thread *td, int step, const gss_buffer_t input_token,
  416     OM_uint32 *maj_stat_res, OM_uint32 *min_stat_res, gss_buffer_t output_token)
  417 {
  418         OM_uint32 maj_stat, min_stat;
  419         static int context_established = 0;
  420         static gss_ctx_id_t server_context = GSS_C_NO_CONTEXT;
  421         static gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
  422         static gss_name_t name = GSS_C_NO_NAME;
  423         gss_buffer_desc name_desc;
  424         gss_buffer_desc message_buf;
  425         gss_OID mech_type = GSS_C_NO_OID;
  426         char enctype[sizeof(uint32_t)];
  427         int error = EINVAL;
  428 
  429         maj_stat = GSS_S_FAILURE;
  430         min_stat = 0;
  431         switch (step) {
  432 
  433         case 1:
  434                 if (server_context == GSS_C_NO_CONTEXT) {
  435                         static char sbuf[512];
  436                         memcpy(sbuf, "nfs@", 4);
  437                         getcredhostname(td->td_ucred, sbuf + 4,
  438                             sizeof(sbuf) - 4);
  439                         name_desc.value = sbuf;
  440                         name_desc.length = strlen((const char *)
  441                             name_desc.value);
  442                         maj_stat = gss_import_name(&min_stat, &name_desc,
  443                             GSS_C_NT_HOSTBASED_SERVICE, &name);
  444                         if (GSS_ERROR(maj_stat)) {
  445                                 printf("gss_import_name failed\n");
  446                                 report_error(mech_type, maj_stat, min_stat);
  447                                 goto out;
  448                         }
  449 
  450                         maj_stat = gss_acquire_cred(&min_stat,
  451                             name, 0, GSS_C_NO_OID_SET, GSS_C_ACCEPT,
  452                             &server_cred, NULL, NULL);
  453                         if (GSS_ERROR(maj_stat)) {
  454                                 printf("gss_acquire_cred (server) failed\n");
  455                                 report_error(mech_type, maj_stat, min_stat);
  456                                 goto out;
  457                         }
  458 
  459                         enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff;
  460                         enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff;
  461                         enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff;
  462                         enctype[3] = ETYPE_DES_CBC_CRC & 0xff;
  463                         message_buf.length = sizeof(enctype);
  464                         message_buf.value = enctype;
  465                         maj_stat = gss_set_cred_option(&min_stat, &server_cred,
  466                             GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf);
  467                         if (GSS_ERROR(maj_stat)) {
  468                                 printf("gss_set_cred_option failed\n");
  469                                 report_error(mech_type, maj_stat, min_stat);
  470                                 goto out;
  471                         }
  472                 }
  473 
  474                 maj_stat = gss_accept_sec_context(&min_stat,
  475                     &server_context,
  476                     server_cred,
  477                     input_token,
  478                     GSS_C_NO_CHANNEL_BINDINGS,
  479                     NULL,
  480                     &mech_type,
  481                     output_token,
  482                     NULL,
  483                     NULL,
  484                     NULL);
  485                 if (GSS_ERROR(maj_stat)) {
  486                         printf("gss_accept_sec_context failed\n");
  487                         report_error(mech_type, maj_stat, min_stat);
  488                         goto out;
  489                 }
  490 
  491                 if (maj_stat == GSS_S_COMPLETE) {
  492                         context_established = 1;
  493                 }
  494                 *maj_stat_res = maj_stat;
  495                 *min_stat_res = min_stat;
  496                 break;
  497 
  498         case 2:
  499                 message_buf.length = strlen("Hello world");
  500                 message_buf.value = (void *) "Hello world";
  501 
  502                 maj_stat = gss_verify_mic(&min_stat, server_context,
  503                     &message_buf, input_token, NULL);
  504                 if (GSS_ERROR(maj_stat)) {
  505                         printf("gss_verify_mic failed\n");
  506                         report_error(mech_type, maj_stat, min_stat);
  507                         goto out;
  508                 }
  509 
  510                 maj_stat = gss_get_mic(&min_stat, server_context,
  511                     GSS_C_QOP_DEFAULT, &message_buf, output_token);
  512                 if (GSS_ERROR(maj_stat)) {
  513                         printf("gss_get_mic failed\n");
  514                         report_error(mech_type, maj_stat, min_stat);
  515                         goto out;
  516                 }
  517                 break;
  518 
  519         case 3:
  520                 maj_stat = gss_unwrap(&min_stat, server_context,
  521                     input_token, &message_buf, NULL, NULL);
  522                 if (GSS_ERROR(maj_stat)) {
  523                         printf("gss_unwrap failed\n");
  524                         report_error(mech_type, maj_stat, min_stat);
  525                         goto out;
  526                 }
  527                 gss_release_buffer(&min_stat, &message_buf);
  528 
  529                 message_buf.length = strlen("Hello world");
  530                 message_buf.value = (void *) "Hello world";
  531                 maj_stat = gss_wrap(&min_stat, server_context,
  532                     TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token);
  533                 if (GSS_ERROR(maj_stat)) {
  534                         printf("gss_wrap failed\n");
  535                         report_error(mech_type, maj_stat, min_stat);
  536                         goto out;
  537                 }
  538                 break;
  539 
  540         case 4:
  541                 maj_stat = gss_unwrap(&min_stat, server_context,
  542                     input_token, &message_buf, NULL, NULL);
  543                 if (GSS_ERROR(maj_stat)) {
  544                         printf("gss_unwrap failed\n");
  545                         report_error(mech_type, maj_stat, min_stat);
  546                         goto out;
  547                 }
  548                 gss_release_buffer(&min_stat, &message_buf);
  549 
  550                 message_buf.length = strlen("Hello world");
  551                 message_buf.value = (void *) "Hello world";
  552                 maj_stat = gss_wrap(&min_stat, server_context,
  553                     FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token);
  554                 if (GSS_ERROR(maj_stat)) {
  555                         printf("gss_wrap failed\n");
  556                         report_error(mech_type, maj_stat, min_stat);
  557                         goto out;
  558                 }
  559                 break;
  560 
  561         case 5:
  562                 error = 0;
  563                 goto out;
  564         }
  565         *maj_stat_res = maj_stat;
  566         *min_stat_res = min_stat;
  567         return (0);
  568         
  569 out:
  570         *maj_stat_res = maj_stat;
  571         *min_stat_res = min_stat;
  572         if (server_context)
  573                 gss_delete_sec_context(&min_stat, &server_context,
  574                     GSS_C_NO_BUFFER);
  575         if (server_cred)
  576                 gss_release_cred(&min_stat, &server_cred);
  577         if (name)
  578                 gss_release_name(&min_stat, &name);
  579 
  580         return (error);
  581 }
  582 
  583 /*
  584  * Create an RPC client handle for the given (address,prog,vers)
  585  * triple using UDP.
  586  */
  587 static CLIENT *
  588 gsstest_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers)
  589 {
  590         struct thread *td = curthread;
  591         const char* protofmly;
  592         struct sockaddr_storage ss;
  593         struct socket *so;
  594         CLIENT *rpcb;
  595         struct timeval timo;
  596         RPCB parms;
  597         char *uaddr;
  598         enum clnt_stat stat = RPC_SUCCESS;
  599         int rpcvers = RPCBVERS4;
  600         bool_t do_tcp = FALSE;
  601         struct portmap mapping;
  602         u_short port = 0;
  603 
  604         /*
  605          * First we need to contact the remote RPCBIND service to find
  606          * the right port.
  607          */
  608         memcpy(&ss, sa, sa->sa_len);
  609         switch (ss.ss_family) {
  610         case AF_INET:
  611                 ((struct sockaddr_in *)&ss)->sin_port = htons(111);
  612                 protofmly = "inet";
  613                 socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td);
  614                 break;
  615                 
  616 #ifdef INET6
  617         case AF_INET6:
  618                 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111);
  619                 protofmly = "inet6";
  620                 socreate(AF_INET6, &so, SOCK_DGRAM, 0, td->td_ucred, td);
  621                 break;
  622 #endif
  623 
  624         default:
  625                 /*
  626                  * Unsupported address family - fail.
  627                  */
  628                 return (NULL);
  629         }
  630 
  631         rpcb = clnt_dg_create(so, (struct sockaddr *)&ss,
  632             RPCBPROG, rpcvers, 0, 0);
  633         if (!rpcb)
  634                 return (NULL);
  635 
  636 try_tcp:
  637         parms.r_prog = prog;
  638         parms.r_vers = vers;
  639         if (do_tcp)
  640                 parms.r_netid = "tcp";
  641         else
  642                 parms.r_netid = "udp";
  643         parms.r_addr = "";
  644         parms.r_owner = "";
  645 
  646         /*
  647          * Use the default timeout.
  648          */
  649         timo.tv_sec = 25;
  650         timo.tv_usec = 0;
  651 again:
  652         switch (rpcvers) {
  653         case RPCBVERS4:
  654         case RPCBVERS:
  655                 /*
  656                  * Try RPCBIND 4 then 3.
  657                  */
  658                 uaddr = NULL;
  659                 stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR,
  660                     (xdrproc_t) xdr_rpcb, &parms,
  661                     (xdrproc_t) xdr_wrapstring, &uaddr, timo);
  662                 if (stat == RPC_PROGVERSMISMATCH) {
  663                         if (rpcvers == RPCBVERS4)
  664                                 rpcvers = RPCBVERS;
  665                         else if (rpcvers == RPCBVERS)
  666                                 rpcvers = PMAPVERS;
  667                         CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers);
  668                         goto again;
  669                 } else if (stat == RPC_SUCCESS) {
  670                         /*
  671                          * We have a reply from the remote RPCBIND - turn it
  672                          * into an appropriate address and make a new client
  673                          * that can talk to the remote service.
  674                          *
  675                          * XXX fixup IPv6 scope ID.
  676                          */
  677                         struct netbuf *a;
  678                         a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr);
  679                         xdr_free((xdrproc_t) xdr_wrapstring, &uaddr);
  680                         if (!a) {
  681                                 CLNT_DESTROY(rpcb);
  682                                 return (NULL);
  683                         }
  684                         memcpy(&ss, a->buf, a->len);
  685                         free(a->buf, M_RPC);
  686                         free(a, M_RPC);
  687                 }
  688                 break;
  689         case PMAPVERS:
  690                 /*
  691                  * Try portmap.
  692                  */
  693                 mapping.pm_prog = parms.r_prog;
  694                 mapping.pm_vers = parms.r_vers;
  695                 mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP;
  696                 mapping.pm_port = 0;
  697 
  698                 stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT,
  699                     (xdrproc_t) xdr_portmap, &mapping,
  700                     (xdrproc_t) xdr_u_short, &port, timo);
  701 
  702                 if (stat == RPC_SUCCESS) {
  703                         switch (ss.ss_family) {
  704                         case AF_INET:
  705                                 ((struct sockaddr_in *)&ss)->sin_port =
  706                                         htons(port);
  707                                 break;
  708                 
  709 #ifdef INET6
  710                         case AF_INET6:
  711                                 ((struct sockaddr_in6 *)&ss)->sin6_port =
  712                                         htons(port);
  713                                 break;
  714 #endif
  715                         }
  716                 }
  717                 break;
  718         default:
  719                 panic("invalid rpcvers %d", rpcvers);
  720         }
  721         /*
  722          * We may have a positive response from the portmapper, but
  723          * the requested service was not found. Make sure we received
  724          * a valid port.
  725          */
  726         switch (ss.ss_family) {
  727         case AF_INET:
  728                 port = ((struct sockaddr_in *)&ss)->sin_port;
  729                 break;
  730 #ifdef INET6
  731         case AF_INET6:
  732                 port = ((struct sockaddr_in6 *)&ss)->sin6_port;
  733                 break;
  734 #endif
  735         }
  736         if (stat != RPC_SUCCESS || !port) {
  737                 /*
  738                  * If we were able to talk to rpcbind or portmap, but the udp
  739                  * variant wasn't available, ask about tcp.
  740                  *
  741                  * XXX - We could also check for a TCP portmapper, but
  742                  * if the host is running a portmapper at all, we should be able
  743                  * to hail it over UDP.
  744                  */
  745                 if (stat == RPC_SUCCESS && !do_tcp) {
  746                         do_tcp = TRUE;
  747                         goto try_tcp;
  748                 }
  749 
  750                 /* Otherwise, bad news. */
  751                 printf("gsstest_get_rpc: failed to contact remote rpcbind, "
  752                     "stat = %d, port = %d\n",
  753                     (int) stat, port);
  754                 CLNT_DESTROY(rpcb);
  755                 return (NULL);
  756         }
  757 
  758         if (do_tcp) {
  759                 /*
  760                  * Destroy the UDP client we used to speak to rpcbind and
  761                  * recreate as a TCP client.
  762                  */
  763                 struct netconfig *nconf = NULL;
  764 
  765                 CLNT_DESTROY(rpcb);
  766 
  767                 switch (ss.ss_family) {
  768                 case AF_INET:
  769                         nconf = getnetconfigent("tcp");
  770                         break;
  771 #ifdef INET6
  772                 case AF_INET6:
  773                         nconf = getnetconfigent("tcp6");
  774                         break;
  775 #endif
  776                 }
  777 
  778                 rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss,
  779                     prog, vers, 0, 0);
  780         } else {
  781                 /*
  782                  * Re-use the client we used to speak to rpcbind.
  783                  */
  784                 CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss);
  785                 CLNT_CONTROL(rpcb, CLSET_PROG, &prog);
  786                 CLNT_CONTROL(rpcb, CLSET_VERS, &vers);
  787         }
  788 
  789         return (rpcb);
  790 }
  791 
  792 /*
  793  * RPCSEC_GSS client
  794  */
  795 static int
  796 gsstest_3(struct thread *td)
  797 {
  798         struct sockaddr_in sin;
  799         char service[128];
  800         CLIENT *client;
  801         AUTH *auth;
  802         rpc_gss_options_ret_t options_ret;
  803         enum clnt_stat stat;
  804         struct timeval tv;
  805         rpc_gss_service_t svc;
  806         int i;
  807 
  808         sin.sin_len = sizeof(sin);
  809         sin.sin_family = AF_INET;
  810         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  811         sin.sin_port = 0;
  812 
  813         client = gsstest_get_rpc((struct sockaddr *) &sin, 123456, 1);
  814         if (!client) {
  815                 uprintf("Can't connect to service\n");
  816                 return(1);
  817         }
  818 
  819         memcpy(service, "host@", 5);
  820         getcredhostname(td->td_ucred, service + 5, sizeof(service) - 5);
  821 
  822         auth = rpc_gss_seccreate(client, curthread->td_ucred,
  823             service, "kerberosv5", rpc_gss_svc_privacy,
  824             NULL, NULL, &options_ret);
  825         if (!auth) {
  826                 gss_OID oid;
  827                 uprintf("Can't authorize to service (mech=%s)\n",
  828                         options_ret.actual_mechanism);
  829                 oid = GSS_C_NO_OID;
  830                 rpc_gss_mech_to_oid(options_ret.actual_mechanism, &oid);
  831                 report_error(oid, options_ret.major_status,
  832                     options_ret.minor_status);
  833                 CLNT_DESTROY(client);
  834                 return (1);
  835         }
  836 
  837         for (svc = rpc_gss_svc_none; svc <= rpc_gss_svc_privacy; svc++) {
  838                 const char *svc_names[] = {
  839                         "rpc_gss_svc_default",
  840                         "rpc_gss_svc_none",
  841                         "rpc_gss_svc_integrity",
  842                         "rpc_gss_svc_privacy"
  843                 };
  844                 int num;
  845 
  846                 rpc_gss_set_defaults(auth, svc, NULL);
  847 
  848                 client->cl_auth = auth;
  849                 tv.tv_sec = 5;
  850                 tv.tv_usec = 0;
  851                 for (i = 42; i < 142; i++) {
  852                         num = i;
  853                         stat = CLNT_CALL(client, 1,
  854                             (xdrproc_t) xdr_int, (char *) &num,
  855                             (xdrproc_t) xdr_int, (char *) &num, tv);
  856                         if (stat == RPC_SUCCESS) {
  857                                 if (num != i + 100)
  858                                         uprintf("unexpected reply %d\n", num);
  859                         } else {
  860                                 uprintf("call failed, stat=%d\n", (int) stat);
  861                                 break;
  862                         }
  863                 }
  864                 if (i == 142)
  865                         uprintf("call succeeded with %s\n", svc_names[svc]);
  866         }
  867 
  868         AUTH_DESTROY(auth);
  869         CLNT_RELEASE(client);
  870 
  871         return (0);
  872 }
  873 
  874 /*
  875  * RPCSEC_GSS server
  876  */
  877 static rpc_gss_principal_t server_acl = NULL;
  878 static bool_t server_new_context(struct svc_req *req, gss_cred_id_t deleg,
  879     gss_ctx_id_t gss_context, rpc_gss_lock_t *lock, void **cookie);
  880 static void server_program_1(struct svc_req *rqstp, register SVCXPRT *transp);
  881 
  882 static int
  883 gsstest_4(struct thread *td)
  884 {
  885         SVCPOOL *pool;
  886         char principal[128 + 5];
  887         const char **mechs;
  888         static rpc_gss_callback_t cb;
  889 
  890         memcpy(principal, "host@", 5);
  891         getcredhostname(td->td_ucred, principal + 5, sizeof(principal) - 5);
  892 
  893         mechs = rpc_gss_get_mechanisms();
  894         while (*mechs) {
  895                 if (!rpc_gss_set_svc_name(principal, *mechs, GSS_C_INDEFINITE,
  896                         123456, 1)) {
  897                         rpc_gss_error_t e;
  898 
  899                         rpc_gss_get_error(&e);
  900                         printf("setting name for %s for %s failed: %d, %d\n",
  901                             principal, *mechs,
  902                             e.rpc_gss_error, e.system_error);
  903                 }
  904                 mechs++;
  905         }
  906 
  907         cb.program = 123456;
  908         cb.version = 1;
  909         cb.callback = server_new_context;
  910         rpc_gss_set_callback(&cb);
  911 
  912         pool = svcpool_create("gsstest", NULL);
  913 
  914         svc_create(pool, server_program_1, 123456, 1, NULL);
  915         svc_run(pool);
  916 
  917         rpc_gss_clear_svc_name(123456, 1);
  918         rpc_gss_clear_callback(&cb);
  919 
  920         svcpool_destroy(pool);
  921 
  922         return (0);
  923 }
  924 
  925 static void
  926 server_program_1(struct svc_req *rqstp, register SVCXPRT *transp)
  927 {
  928         rpc_gss_rawcred_t *rcred;
  929         rpc_gss_ucred_t *ucred;
  930         int             i, num;
  931 
  932         if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS) {
  933                 svcerr_weakauth(rqstp);
  934                 return;
  935         }               
  936                 
  937         if (!rpc_gss_getcred(rqstp, &rcred, &ucred, NULL)) {
  938                 svcerr_systemerr(rqstp);
  939                 return;
  940         }
  941 
  942         printf("svc=%d, mech=%s, uid=%d, gid=%d, gids={",
  943             rcred->service, rcred->mechanism, ucred->uid, ucred->gid);
  944         for (i = 0; i < ucred->gidlen; i++) {
  945                 if (i > 0) printf(",");
  946                 printf("%d", ucred->gidlist[i]);
  947         }
  948         printf("}\n");
  949 
  950         switch (rqstp->rq_proc) {
  951         case 0:
  952                 if (!svc_getargs(rqstp, (xdrproc_t) xdr_void, 0)) {
  953                         svcerr_decode(rqstp);
  954                         goto out;
  955                 }
  956                 if (!svc_sendreply(rqstp, (xdrproc_t) xdr_void, 0)) {
  957                         svcerr_systemerr(rqstp);
  958                 }
  959                 goto out;
  960 
  961         case 1:
  962                 if (!svc_getargs(rqstp, (xdrproc_t) xdr_int,
  963                         (char *) &num)) {
  964                         svcerr_decode(rqstp);
  965                         goto out;
  966                 }
  967                 num += 100;
  968                 if (!svc_sendreply(rqstp, (xdrproc_t) xdr_int,
  969                         (char *) &num)) {
  970                         svcerr_systemerr(rqstp);
  971                 }
  972                 goto out;
  973 
  974         default:
  975                 svcerr_noproc(rqstp);
  976                 goto out;
  977         }
  978 
  979 out:
  980         svc_freereq(rqstp);
  981         return;
  982 }
  983 
  984 static void
  985 print_principal(rpc_gss_principal_t principal)
  986 {
  987         int i, len, n;
  988         uint8_t *p;
  989 
  990         len = principal->len;
  991         p = (uint8_t *) principal->name;
  992         while (len > 0) {
  993                 n = len;
  994                 if (n > 16)
  995                         n = 16;
  996                 for (i = 0; i < n; i++)
  997                         printf("%02x ", p[i]);
  998                 for (; i < 16; i++)
  999                         printf("   ");
 1000                 printf("|");
 1001                 for (i = 0; i < n; i++)
 1002                         printf("%c", isprint(p[i]) ? p[i] : '.');
 1003                 printf("|\n");
 1004                 len -= n;
 1005                 p += n;
 1006         }
 1007 }
 1008 
 1009 static bool_t
 1010 server_new_context(__unused struct svc_req *req,
 1011     gss_cred_id_t deleg,
 1012     __unused gss_ctx_id_t gss_context,
 1013     rpc_gss_lock_t *lock,
 1014     __unused void **cookie)
 1015 {
 1016         rpc_gss_rawcred_t *rcred = lock->raw_cred;
 1017         OM_uint32 junk;
 1018 
 1019         printf("new security context version=%d, mech=%s, qop=%s:\n",
 1020             rcred->version, rcred->mechanism, rcred->qop);
 1021         print_principal(rcred->client_principal);
 1022 
 1023         if (server_acl) {
 1024                 if (rcred->client_principal->len != server_acl->len
 1025                     || memcmp(rcred->client_principal->name, server_acl->name,
 1026                         server_acl->len)) {
 1027                         return (FALSE);
 1028                 }
 1029         }
 1030         gss_release_cred(&junk, &deleg);
 1031 
 1032         return (TRUE);
 1033 }
 1034 
 1035 /*
 1036  * Hook up a syscall for gssapi testing.
 1037  */
 1038 
 1039 struct gsstest_args {
 1040         int a_op;
 1041         void *a_args;
 1042         void *a_res;
 1043 };
 1044 
 1045 struct gsstest_2_args {
 1046         int step;               /* test step number */
 1047         gss_buffer_desc input_token; /* token from userland */
 1048         gss_buffer_desc output_token; /* buffer to receive reply token */
 1049 };
 1050 struct gsstest_2_res {
 1051         OM_uint32 maj_stat;     /* maj_stat from kernel */
 1052         OM_uint32 min_stat;     /* min_stat from kernel */
 1053         gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */
 1054 };
 1055 
 1056 static int
 1057 gsstest(struct thread *td, struct gsstest_args *uap)
 1058 {
 1059         int error;
 1060 
 1061         switch (uap->a_op) {
 1062         case 1:
 1063                 return (gsstest_1(td));
 1064 
 1065         case 2: {
 1066                 struct gsstest_2_args args;
 1067                 struct gsstest_2_res res;
 1068                 gss_buffer_desc input_token, output_token;
 1069                 OM_uint32 junk;
 1070 
 1071                 error = copyin(uap->a_args, &args, sizeof(args));
 1072                 if (error)
 1073                         return (error);
 1074                 input_token.length = args.input_token.length;
 1075                 input_token.value = malloc(input_token.length, M_GSSAPI,
 1076                     M_WAITOK);
 1077                 error = copyin(args.input_token.value, input_token.value,
 1078                     input_token.length);
 1079                 if (error) {
 1080                         gss_release_buffer(&junk, &input_token);
 1081                         return (error);
 1082                 }
 1083                 output_token.length = 0;
 1084                 output_token.value = NULL;
 1085                 gsstest_2(td, args.step, &input_token,
 1086                     &res.maj_stat, &res.min_stat, &output_token);
 1087                 gss_release_buffer(&junk, &input_token);
 1088                 if (output_token.length > args.output_token.length) {
 1089                         gss_release_buffer(&junk, &output_token);
 1090                         return (EOVERFLOW);
 1091                 }
 1092                 res.output_token.length = output_token.length;
 1093                 res.output_token.value = args.output_token.value;
 1094                 error = copyout(output_token.value, res.output_token.value,
 1095                     output_token.length);
 1096                 gss_release_buffer(&junk, &output_token);
 1097                 if (error)
 1098                         return (error);
 1099 
 1100                 return (copyout(&res, uap->a_res, sizeof(res)));
 1101                 
 1102                 break;
 1103         }
 1104         case 3:
 1105                 return (gsstest_3(td));
 1106         case 4:
 1107                 return (gsstest_4(td));
 1108         }
 1109 
 1110         return (EINVAL);
 1111 }
 1112 
 1113 /*
 1114  * The `sysent' for the new syscall
 1115  */
 1116 static struct sysent gsstest_sysent = {
 1117         3,                      /* sy_narg */
 1118         (sy_call_t *) gsstest   /* sy_call */
 1119 };
 1120 
 1121 /*
 1122  * The offset in sysent where the syscall is allocated.
 1123  */
 1124 static int gsstest_offset = NO_SYSCALL;
 1125 
 1126 /*
 1127  * The function called at load/unload.
 1128  */
 1129 
 1130 
 1131 static int
 1132 gsstest_load(struct module *module, int cmd, void *arg)
 1133 {
 1134         int error = 0;
 1135 
 1136         switch (cmd) {
 1137         case MOD_LOAD :
 1138                 break;
 1139         case MOD_UNLOAD :
 1140                 break;
 1141         default :
 1142                 error = EOPNOTSUPP;
 1143                 break;
 1144         }
 1145         return error;
 1146 }
 1147 
 1148 SYSCALL_MODULE(gsstest_syscall, &gsstest_offset, &gsstest_sysent,
 1149     gsstest_load, NULL);

Cache object: a5c0cb7757586b3fbf59fe37460132eb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.