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$");
   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         case 1:
  433                 if (server_context == GSS_C_NO_CONTEXT) {
  434                         static char sbuf[512];
  435                         memcpy(sbuf, "nfs@", 4);
  436                         getcredhostname(td->td_ucred, sbuf + 4,
  437                             sizeof(sbuf) - 4);
  438                         name_desc.value = sbuf;
  439                         name_desc.length = strlen((const char *)
  440                             name_desc.value);
  441                         maj_stat = gss_import_name(&min_stat, &name_desc,
  442                             GSS_C_NT_HOSTBASED_SERVICE, &name);
  443                         if (GSS_ERROR(maj_stat)) {
  444                                 printf("gss_import_name failed\n");
  445                                 report_error(mech_type, maj_stat, min_stat);
  446                                 goto out;
  447                         }
  448 
  449                         maj_stat = gss_acquire_cred(&min_stat,
  450                             name, 0, GSS_C_NO_OID_SET, GSS_C_ACCEPT,
  451                             &server_cred, NULL, NULL);
  452                         if (GSS_ERROR(maj_stat)) {
  453                                 printf("gss_acquire_cred (server) failed\n");
  454                                 report_error(mech_type, maj_stat, min_stat);
  455                                 goto out;
  456                         }
  457 
  458                         enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff;
  459                         enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff;
  460                         enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff;
  461                         enctype[3] = ETYPE_DES_CBC_CRC & 0xff;
  462                         message_buf.length = sizeof(enctype);
  463                         message_buf.value = enctype;
  464                         maj_stat = gss_set_cred_option(&min_stat, &server_cred,
  465                             GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf);
  466                         if (GSS_ERROR(maj_stat)) {
  467                                 printf("gss_set_cred_option failed\n");
  468                                 report_error(mech_type, maj_stat, min_stat);
  469                                 goto out;
  470                         }
  471                 }
  472 
  473                 maj_stat = gss_accept_sec_context(&min_stat,
  474                     &server_context,
  475                     server_cred,
  476                     input_token,
  477                     GSS_C_NO_CHANNEL_BINDINGS,
  478                     NULL,
  479                     &mech_type,
  480                     output_token,
  481                     NULL,
  482                     NULL,
  483                     NULL);
  484                 if (GSS_ERROR(maj_stat)) {
  485                         printf("gss_accept_sec_context failed\n");
  486                         report_error(mech_type, maj_stat, min_stat);
  487                         goto out;
  488                 }
  489 
  490                 if (maj_stat == GSS_S_COMPLETE) {
  491                         context_established = 1;
  492                 }
  493                 *maj_stat_res = maj_stat;
  494                 *min_stat_res = min_stat;
  495                 break;
  496 
  497         case 2:
  498                 message_buf.length = strlen("Hello world");
  499                 message_buf.value = (void *) "Hello world";
  500 
  501                 maj_stat = gss_verify_mic(&min_stat, server_context,
  502                     &message_buf, input_token, NULL);
  503                 if (GSS_ERROR(maj_stat)) {
  504                         printf("gss_verify_mic failed\n");
  505                         report_error(mech_type, maj_stat, min_stat);
  506                         goto out;
  507                 }
  508 
  509                 maj_stat = gss_get_mic(&min_stat, server_context,
  510                     GSS_C_QOP_DEFAULT, &message_buf, output_token);
  511                 if (GSS_ERROR(maj_stat)) {
  512                         printf("gss_get_mic failed\n");
  513                         report_error(mech_type, maj_stat, min_stat);
  514                         goto out;
  515                 }
  516                 break;
  517 
  518         case 3:
  519                 maj_stat = gss_unwrap(&min_stat, server_context,
  520                     input_token, &message_buf, NULL, NULL);
  521                 if (GSS_ERROR(maj_stat)) {
  522                         printf("gss_unwrap failed\n");
  523                         report_error(mech_type, maj_stat, min_stat);
  524                         goto out;
  525                 }
  526                 gss_release_buffer(&min_stat, &message_buf);
  527 
  528                 message_buf.length = strlen("Hello world");
  529                 message_buf.value = (void *) "Hello world";
  530                 maj_stat = gss_wrap(&min_stat, server_context,
  531                     TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token);
  532                 if (GSS_ERROR(maj_stat)) {
  533                         printf("gss_wrap failed\n");
  534                         report_error(mech_type, maj_stat, min_stat);
  535                         goto out;
  536                 }
  537                 break;
  538 
  539         case 4:
  540                 maj_stat = gss_unwrap(&min_stat, server_context,
  541                     input_token, &message_buf, NULL, NULL);
  542                 if (GSS_ERROR(maj_stat)) {
  543                         printf("gss_unwrap failed\n");
  544                         report_error(mech_type, maj_stat, min_stat);
  545                         goto out;
  546                 }
  547                 gss_release_buffer(&min_stat, &message_buf);
  548 
  549                 message_buf.length = strlen("Hello world");
  550                 message_buf.value = (void *) "Hello world";
  551                 maj_stat = gss_wrap(&min_stat, server_context,
  552                     FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token);
  553                 if (GSS_ERROR(maj_stat)) {
  554                         printf("gss_wrap failed\n");
  555                         report_error(mech_type, maj_stat, min_stat);
  556                         goto out;
  557                 }
  558                 break;
  559 
  560         case 5:
  561                 error = 0;
  562                 goto out;
  563         }
  564         *maj_stat_res = maj_stat;
  565         *min_stat_res = min_stat;
  566         return (0);
  567 
  568 out:
  569         *maj_stat_res = maj_stat;
  570         *min_stat_res = min_stat;
  571         if (server_context)
  572                 gss_delete_sec_context(&min_stat, &server_context,
  573                     GSS_C_NO_BUFFER);
  574         if (server_cred)
  575                 gss_release_cred(&min_stat, &server_cred);
  576         if (name)
  577                 gss_release_name(&min_stat, &name);
  578 
  579         return (error);
  580 }
  581 
  582 /*
  583  * Create an RPC client handle for the given (address,prog,vers)
  584  * triple using UDP.
  585  */
  586 static CLIENT *
  587 gsstest_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers)
  588 {
  589         struct thread *td = curthread;
  590         const char* protofmly;
  591         struct sockaddr_storage ss;
  592         struct socket *so;
  593         CLIENT *rpcb;
  594         struct timeval timo;
  595         RPCB parms;
  596         char *uaddr;
  597         enum clnt_stat stat = RPC_SUCCESS;
  598         int rpcvers = RPCBVERS4;
  599         bool_t do_tcp = FALSE;
  600         struct portmap mapping;
  601         u_short port = 0;
  602 
  603         /*
  604          * First we need to contact the remote RPCBIND service to find
  605          * the right port.
  606          */
  607         memcpy(&ss, sa, sa->sa_len);
  608         switch (ss.ss_family) {
  609         case AF_INET:
  610                 ((struct sockaddr_in *)&ss)->sin_port = htons(111);
  611                 protofmly = "inet";
  612                 socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td);
  613                 break;
  614                 
  615 #ifdef INET6
  616         case AF_INET6:
  617                 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111);
  618                 protofmly = "inet6";
  619                 socreate(AF_INET6, &so, SOCK_DGRAM, 0, td->td_ucred, td);
  620                 break;
  621 #endif
  622 
  623         default:
  624                 /*
  625                  * Unsupported address family - fail.
  626                  */
  627                 return (NULL);
  628         }
  629 
  630         rpcb = clnt_dg_create(so, (struct sockaddr *)&ss,
  631             RPCBPROG, rpcvers, 0, 0);
  632         if (!rpcb)
  633                 return (NULL);
  634 
  635 try_tcp:
  636         parms.r_prog = prog;
  637         parms.r_vers = vers;
  638         if (do_tcp)
  639                 parms.r_netid = "tcp";
  640         else
  641                 parms.r_netid = "udp";
  642         parms.r_addr = "";
  643         parms.r_owner = "";
  644 
  645         /*
  646          * Use the default timeout.
  647          */
  648         timo.tv_sec = 25;
  649         timo.tv_usec = 0;
  650 again:
  651         switch (rpcvers) {
  652         case RPCBVERS4:
  653         case RPCBVERS:
  654                 /*
  655                  * Try RPCBIND 4 then 3.
  656                  */
  657                 uaddr = NULL;
  658                 stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR,
  659                     (xdrproc_t) xdr_rpcb, &parms,
  660                     (xdrproc_t) xdr_wrapstring, &uaddr, timo);
  661                 if (stat == RPC_PROGVERSMISMATCH) {
  662                         if (rpcvers == RPCBVERS4)
  663                                 rpcvers = RPCBVERS;
  664                         else if (rpcvers == RPCBVERS)
  665                                 rpcvers = PMAPVERS;
  666                         CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers);
  667                         goto again;
  668                 } else if (stat == RPC_SUCCESS) {
  669                         /*
  670                          * We have a reply from the remote RPCBIND - turn it
  671                          * into an appropriate address and make a new client
  672                          * that can talk to the remote service.
  673                          *
  674                          * XXX fixup IPv6 scope ID.
  675                          */
  676                         struct netbuf *a;
  677                         a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr);
  678                         xdr_free((xdrproc_t) xdr_wrapstring, &uaddr);
  679                         if (!a) {
  680                                 CLNT_DESTROY(rpcb);
  681                                 return (NULL);
  682                         }
  683                         memcpy(&ss, a->buf, a->len);
  684                         free(a->buf, M_RPC);
  685                         free(a, M_RPC);
  686                 }
  687                 break;
  688         case PMAPVERS:
  689                 /*
  690                  * Try portmap.
  691                  */
  692                 mapping.pm_prog = parms.r_prog;
  693                 mapping.pm_vers = parms.r_vers;
  694                 mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP;
  695                 mapping.pm_port = 0;
  696 
  697                 stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT,
  698                     (xdrproc_t) xdr_portmap, &mapping,
  699                     (xdrproc_t) xdr_u_short, &port, timo);
  700 
  701                 if (stat == RPC_SUCCESS) {
  702                         switch (ss.ss_family) {
  703                         case AF_INET:
  704                                 ((struct sockaddr_in *)&ss)->sin_port =
  705                                         htons(port);
  706                                 break;
  707                 
  708 #ifdef INET6
  709                         case AF_INET6:
  710                                 ((struct sockaddr_in6 *)&ss)->sin6_port =
  711                                         htons(port);
  712                                 break;
  713 #endif
  714                         }
  715                 }
  716                 break;
  717         default:
  718                 panic("invalid rpcvers %d", rpcvers);
  719         }
  720         /*
  721          * We may have a positive response from the portmapper, but
  722          * the requested service was not found. Make sure we received
  723          * a valid port.
  724          */
  725         switch (ss.ss_family) {
  726         case AF_INET:
  727                 port = ((struct sockaddr_in *)&ss)->sin_port;
  728                 break;
  729 #ifdef INET6
  730         case AF_INET6:
  731                 port = ((struct sockaddr_in6 *)&ss)->sin6_port;
  732                 break;
  733 #endif
  734         }
  735         if (stat != RPC_SUCCESS || !port) {
  736                 /*
  737                  * If we were able to talk to rpcbind or portmap, but the udp
  738                  * variant wasn't available, ask about tcp.
  739                  *
  740                  * XXX - We could also check for a TCP portmapper, but
  741                  * if the host is running a portmapper at all, we should be able
  742                  * to hail it over UDP.
  743                  */
  744                 if (stat == RPC_SUCCESS && !do_tcp) {
  745                         do_tcp = TRUE;
  746                         goto try_tcp;
  747                 }
  748 
  749                 /* Otherwise, bad news. */
  750                 printf("gsstest_get_rpc: failed to contact remote rpcbind, "
  751                     "stat = %d, port = %d\n",
  752                     (int) stat, port);
  753                 CLNT_DESTROY(rpcb);
  754                 return (NULL);
  755         }
  756 
  757         if (do_tcp) {
  758                 /*
  759                  * Destroy the UDP client we used to speak to rpcbind and
  760                  * recreate as a TCP client.
  761                  */
  762                 struct netconfig *nconf = NULL;
  763 
  764                 CLNT_DESTROY(rpcb);
  765 
  766                 switch (ss.ss_family) {
  767                 case AF_INET:
  768                         nconf = getnetconfigent("tcp");
  769                         break;
  770 #ifdef INET6
  771                 case AF_INET6:
  772                         nconf = getnetconfigent("tcp6");
  773                         break;
  774 #endif
  775                 }
  776 
  777                 rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss,
  778                     prog, vers, 0, 0);
  779         } else {
  780                 /*
  781                  * Re-use the client we used to speak to rpcbind.
  782                  */
  783                 CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss);
  784                 CLNT_CONTROL(rpcb, CLSET_PROG, &prog);
  785                 CLNT_CONTROL(rpcb, CLSET_VERS, &vers);
  786         }
  787 
  788         return (rpcb);
  789 }
  790 
  791 /*
  792  * RPCSEC_GSS client
  793  */
  794 static int
  795 gsstest_3(struct thread *td)
  796 {
  797         struct sockaddr_in sin;
  798         char service[128];
  799         CLIENT *client;
  800         AUTH *auth;
  801         rpc_gss_options_ret_t options_ret;
  802         enum clnt_stat stat;
  803         struct timeval tv;
  804         rpc_gss_service_t svc;
  805         int i;
  806 
  807         sin.sin_len = sizeof(sin);
  808         sin.sin_family = AF_INET;
  809         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  810         sin.sin_port = 0;
  811 
  812         client = gsstest_get_rpc((struct sockaddr *) &sin, 123456, 1);
  813         if (!client) {
  814                 uprintf("Can't connect to service\n");
  815                 return(1);
  816         }
  817 
  818         memcpy(service, "host@", 5);
  819         getcredhostname(td->td_ucred, service + 5, sizeof(service) - 5);
  820 
  821         auth = rpc_gss_seccreate(client, curthread->td_ucred,
  822             service, "kerberosv5", rpc_gss_svc_privacy,
  823             NULL, NULL, &options_ret);
  824         if (!auth) {
  825                 gss_OID oid;
  826                 uprintf("Can't authorize to service (mech=%s)\n",
  827                         options_ret.actual_mechanism);
  828                 oid = GSS_C_NO_OID;
  829                 rpc_gss_mech_to_oid(options_ret.actual_mechanism, &oid);
  830                 report_error(oid, options_ret.major_status,
  831                     options_ret.minor_status);
  832                 CLNT_DESTROY(client);
  833                 return (1);
  834         }
  835 
  836         for (svc = rpc_gss_svc_none; svc <= rpc_gss_svc_privacy; svc++) {
  837                 const char *svc_names[] = {
  838                         "rpc_gss_svc_default",
  839                         "rpc_gss_svc_none",
  840                         "rpc_gss_svc_integrity",
  841                         "rpc_gss_svc_privacy"
  842                 };
  843                 int num;
  844 
  845                 rpc_gss_set_defaults(auth, svc, NULL);
  846 
  847                 client->cl_auth = auth;
  848                 tv.tv_sec = 5;
  849                 tv.tv_usec = 0;
  850                 for (i = 42; i < 142; i++) {
  851                         num = i;
  852                         stat = CLNT_CALL(client, 1,
  853                             (xdrproc_t) xdr_int, (char *) &num,
  854                             (xdrproc_t) xdr_int, (char *) &num, tv);
  855                         if (stat == RPC_SUCCESS) {
  856                                 if (num != i + 100)
  857                                         uprintf("unexpected reply %d\n", num);
  858                         } else {
  859                                 uprintf("call failed, stat=%d\n", (int) stat);
  860                                 break;
  861                         }
  862                 }
  863                 if (i == 142)
  864                         uprintf("call succeeded with %s\n", svc_names[svc]);
  865         }
  866 
  867         AUTH_DESTROY(auth);
  868         CLNT_RELEASE(client);
  869 
  870         return (0);
  871 }
  872 
  873 /*
  874  * RPCSEC_GSS server
  875  */
  876 static rpc_gss_principal_t server_acl = NULL;
  877 static bool_t server_new_context(struct svc_req *req, gss_cred_id_t deleg,
  878     gss_ctx_id_t gss_context, rpc_gss_lock_t *lock, void **cookie);
  879 static void server_program_1(struct svc_req *rqstp, register SVCXPRT *transp);
  880 
  881 static int
  882 gsstest_4(struct thread *td)
  883 {
  884         SVCPOOL *pool;
  885         char principal[128 + 5];
  886         const char **mechs;
  887         static rpc_gss_callback_t cb;
  888 
  889         memcpy(principal, "host@", 5);
  890         getcredhostname(td->td_ucred, principal + 5, sizeof(principal) - 5);
  891 
  892         mechs = rpc_gss_get_mechanisms();
  893         while (*mechs) {
  894                 if (!rpc_gss_set_svc_name(principal, *mechs, GSS_C_INDEFINITE,
  895                         123456, 1)) {
  896                         rpc_gss_error_t e;
  897 
  898                         rpc_gss_get_error(&e);
  899                         printf("setting name for %s for %s failed: %d, %d\n",
  900                             principal, *mechs,
  901                             e.rpc_gss_error, e.system_error);
  902                 }
  903                 mechs++;
  904         }
  905 
  906         cb.program = 123456;
  907         cb.version = 1;
  908         cb.callback = server_new_context;
  909         rpc_gss_set_callback(&cb);
  910 
  911         pool = svcpool_create("gsstest", NULL);
  912 
  913         svc_create(pool, server_program_1, 123456, 1, NULL);
  914         svc_run(pool);
  915 
  916         rpc_gss_clear_svc_name(123456, 1);
  917         rpc_gss_clear_callback(&cb);
  918 
  919         svcpool_destroy(pool);
  920 
  921         return (0);
  922 }
  923 
  924 static void
  925 server_program_1(struct svc_req *rqstp, register SVCXPRT *transp)
  926 {
  927         rpc_gss_rawcred_t *rcred;
  928         rpc_gss_ucred_t *ucred;
  929         int             i, num;
  930 
  931         if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS) {
  932                 svcerr_weakauth(rqstp);
  933                 return;
  934         }               
  935                 
  936         if (!rpc_gss_getcred(rqstp, &rcred, &ucred, NULL)) {
  937                 svcerr_systemerr(rqstp);
  938                 return;
  939         }
  940 
  941         printf("svc=%d, mech=%s, uid=%d, gid=%d, gids={",
  942             rcred->service, rcred->mechanism, ucred->uid, ucred->gid);
  943         for (i = 0; i < ucred->gidlen; i++) {
  944                 if (i > 0) printf(",");
  945                 printf("%d", ucred->gidlist[i]);
  946         }
  947         printf("}\n");
  948 
  949         switch (rqstp->rq_proc) {
  950         case 0:
  951                 if (!svc_getargs(rqstp, (xdrproc_t) xdr_void, 0)) {
  952                         svcerr_decode(rqstp);
  953                         goto out;
  954                 }
  955                 if (!svc_sendreply(rqstp, (xdrproc_t) xdr_void, 0)) {
  956                         svcerr_systemerr(rqstp);
  957                 }
  958                 goto out;
  959 
  960         case 1:
  961                 if (!svc_getargs(rqstp, (xdrproc_t) xdr_int,
  962                         (char *) &num)) {
  963                         svcerr_decode(rqstp);
  964                         goto out;
  965                 }
  966                 num += 100;
  967                 if (!svc_sendreply(rqstp, (xdrproc_t) xdr_int,
  968                         (char *) &num)) {
  969                         svcerr_systemerr(rqstp);
  970                 }
  971                 goto out;
  972 
  973         default:
  974                 svcerr_noproc(rqstp);
  975                 goto out;
  976         }
  977 
  978 out:
  979         svc_freereq(rqstp);
  980         return;
  981 }
  982 
  983 static void
  984 print_principal(rpc_gss_principal_t principal)
  985 {
  986         int i, len, n;
  987         uint8_t *p;
  988 
  989         len = principal->len;
  990         p = (uint8_t *) principal->name;
  991         while (len > 0) {
  992                 n = len;
  993                 if (n > 16)
  994                         n = 16;
  995                 for (i = 0; i < n; i++)
  996                         printf("%02x ", p[i]);
  997                 for (; i < 16; i++)
  998                         printf("   ");
  999                 printf("|");
 1000                 for (i = 0; i < n; i++)
 1001                         printf("%c", isprint(p[i]) ? p[i] : '.');
 1002                 printf("|\n");
 1003                 len -= n;
 1004                 p += n;
 1005         }
 1006 }
 1007 
 1008 static bool_t
 1009 server_new_context(__unused struct svc_req *req,
 1010     gss_cred_id_t deleg,
 1011     __unused gss_ctx_id_t gss_context,
 1012     rpc_gss_lock_t *lock,
 1013     __unused void **cookie)
 1014 {
 1015         rpc_gss_rawcred_t *rcred = lock->raw_cred;
 1016         OM_uint32 junk;
 1017 
 1018         printf("new security context version=%d, mech=%s, qop=%s:\n",
 1019             rcred->version, rcred->mechanism, rcred->qop);
 1020         print_principal(rcred->client_principal);
 1021 
 1022         if (server_acl) {
 1023                 if (rcred->client_principal->len != server_acl->len
 1024                     || memcmp(rcred->client_principal->name, server_acl->name,
 1025                         server_acl->len)) {
 1026                         return (FALSE);
 1027                 }
 1028         }
 1029         gss_release_cred(&junk, &deleg);
 1030 
 1031         return (TRUE);
 1032 }
 1033 
 1034 /*
 1035  * Hook up a syscall for gssapi testing.
 1036  */
 1037 
 1038 struct gsstest_args {
 1039         int a_op;
 1040         void *a_args;
 1041         void *a_res;
 1042 };
 1043 
 1044 struct gsstest_2_args {
 1045         int step;               /* test step number */
 1046         gss_buffer_desc input_token; /* token from userland */
 1047         gss_buffer_desc output_token; /* buffer to receive reply token */
 1048 };
 1049 struct gsstest_2_res {
 1050         OM_uint32 maj_stat;     /* maj_stat from kernel */
 1051         OM_uint32 min_stat;     /* min_stat from kernel */
 1052         gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */
 1053 };
 1054 
 1055 static int
 1056 gsstest(struct thread *td, struct gsstest_args *uap)
 1057 {
 1058         int error;
 1059 
 1060         switch (uap->a_op) {
 1061         case 1:
 1062                 return (gsstest_1(td));
 1063 
 1064         case 2: {
 1065                 struct gsstest_2_args args;
 1066                 struct gsstest_2_res res;
 1067                 gss_buffer_desc input_token, output_token;
 1068                 OM_uint32 junk;
 1069 
 1070                 error = copyin(uap->a_args, &args, sizeof(args));
 1071                 if (error)
 1072                         return (error);
 1073                 input_token.length = args.input_token.length;
 1074                 input_token.value = malloc(input_token.length, M_GSSAPI,
 1075                     M_WAITOK);
 1076                 error = copyin(args.input_token.value, input_token.value,
 1077                     input_token.length);
 1078                 if (error) {
 1079                         gss_release_buffer(&junk, &input_token);
 1080                         return (error);
 1081                 }
 1082                 output_token.length = 0;
 1083                 output_token.value = NULL;
 1084                 gsstest_2(td, args.step, &input_token,
 1085                     &res.maj_stat, &res.min_stat, &output_token);
 1086                 gss_release_buffer(&junk, &input_token);
 1087                 if (output_token.length > args.output_token.length) {
 1088                         gss_release_buffer(&junk, &output_token);
 1089                         return (EOVERFLOW);
 1090                 }
 1091                 res.output_token.length = output_token.length;
 1092                 res.output_token.value = args.output_token.value;
 1093                 error = copyout(output_token.value, res.output_token.value,
 1094                     output_token.length);
 1095                 gss_release_buffer(&junk, &output_token);
 1096                 if (error)
 1097                         return (error);
 1098 
 1099                 return (copyout(&res, uap->a_res, sizeof(res)));
 1100                 
 1101                 break;
 1102         }
 1103         case 3:
 1104                 return (gsstest_3(td));
 1105         case 4:
 1106                 return (gsstest_4(td));
 1107         }
 1108 
 1109         return (EINVAL);
 1110 }
 1111 
 1112 /*
 1113  * The `sysent' for the new syscall
 1114  */
 1115 static struct sysent gsstest_sysent = {
 1116         3,                      /* sy_narg */
 1117         (sy_call_t *) gsstest   /* sy_call */
 1118 };
 1119 
 1120 /*
 1121  * The offset in sysent where the syscall is allocated.
 1122  */
 1123 static int gsstest_offset = NO_SYSCALL;
 1124 
 1125 /*
 1126  * The function called at load/unload.
 1127  */
 1128 
 1129 static int
 1130 gsstest_load(struct module *module, int cmd, void *arg)
 1131 {
 1132         int error = 0;
 1133 
 1134         switch (cmd) {
 1135         case MOD_LOAD :
 1136                 break;
 1137         case MOD_UNLOAD :
 1138                 break;
 1139         default :
 1140                 error = EOPNOTSUPP;
 1141                 break;
 1142         }
 1143         return error;
 1144 }
 1145 
 1146 SYSCALL_MODULE(gsstest_syscall, &gsstest_offset, &gsstest_sysent,
 1147     gsstest_load, NULL);

Cache object: 0885a3c515c535ae8d7f56f34c65434a


[ 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.