LCOV - code coverage report
Current view: top level - lib/gs2 - server.c (source / functions) Hit Total Coverage
Test: GNU SASL Lines: 134 165 81.2 %
Date: 2010-09-27 Functions: 6 6 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 62 102 60.8 %

           Branch data     Line data    Source code
       1                 :            : /* server.c --- SASL mechanism GS2, server side.
       2                 :            :  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2010  Simon Josefsson
       3                 :            :  *
       4                 :            :  * This file is part of GNU SASL Library.
       5                 :            :  *
       6                 :            :  * GNU SASL Library is free software; you can redistribute it and/or
       7                 :            :  * modify it under the terms of the GNU Lesser General Public License
       8                 :            :  * as published by the Free Software Foundation; either version 2.1 of
       9                 :            :  * the License, or (at your option) any later version.
      10                 :            :  *
      11                 :            :  * GNU SASL Library is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :            :  * Lesser General Public License for more details.
      15                 :            :  *
      16                 :            :  * You should have received a copy of the GNU Lesser General Public
      17                 :            :  * License along with GNU SASL Library; if not, write to the Free
      18                 :            :  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      19                 :            :  * Boston, MA 02110-1301, USA.
      20                 :            :  *
      21                 :            :  */
      22                 :            : 
      23                 :            : #ifdef HAVE_CONFIG_H
      24                 :            : # include "config.h"
      25                 :            : #endif
      26                 :            : 
      27                 :            : /* Get specification. */
      28                 :            : #include "gs2.h"
      29                 :            : 
      30                 :            : /* Get malloc, free. */
      31                 :            : #include <stdlib.h>
      32                 :            : 
      33                 :            : /* Get memcpy, strlen. */
      34                 :            : #include <string.h>
      35                 :            : 
      36                 :            : #include "gss-extra.h"
      37                 :            : #include "gs2helper.h"
      38                 :            : 
      39                 :            : struct _Gsasl_gs2_server_state
      40                 :            : {
      41                 :            :   /* steps: 0 = first state, 1 = initial, 2 = processing, 3 = done */
      42                 :            :   int step;
      43                 :            :   gss_name_t client;
      44                 :            :   gss_cred_id_t cred;
      45                 :            :   gss_ctx_id_t context;
      46                 :            :   gss_OID mech_oid;
      47                 :            :   struct gss_channel_bindings_struct cb;
      48                 :            : };
      49                 :            : typedef struct _Gsasl_gs2_server_state _Gsasl_gs2_server_state;
      50                 :            : 
      51                 :            : /* Populate state->cred with credential to use for connection.  Return
      52                 :            :    GSASL_OK on success or an error code.  */
      53                 :            : static int
      54                 :          8 : gs2_get_cred (Gsasl_session * sctx, _Gsasl_gs2_server_state * state)
      55                 :            : {
      56                 :            :   OM_uint32 maj_stat, min_stat;
      57                 :            :   gss_buffer_desc bufdesc;
      58                 :          8 :   const char *service = gsasl_property_get (sctx, GSASL_SERVICE);
      59                 :          8 :   const char *hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
      60                 :            :   gss_name_t server;
      61                 :            :   gss_OID_set_desc oid_set;
      62                 :            :   gss_OID_set actual_mechs;
      63                 :            :   int present;
      64                 :            : 
      65         [ +  + ]:          8 :   if (!service)
      66                 :          2 :     return GSASL_NO_SERVICE;
      67         [ -  + ]:          6 :   if (!hostname)
      68                 :          0 :     return GSASL_NO_HOSTNAME;
      69                 :            : 
      70                 :          6 :   bufdesc.length = asprintf ((char **) &bufdesc.value, "%s@%s",
      71                 :            :                              service, hostname);
      72   [ +  -  -  + ]:          6 :   if (bufdesc.length <= 0 || bufdesc.value == NULL)
      73                 :          0 :     return GSASL_MALLOC_ERROR;
      74                 :            : 
      75                 :          6 :   maj_stat = gss_import_name (&min_stat, &bufdesc,
      76                 :            :                               GSS_C_NT_HOSTBASED_SERVICE, &server);
      77                 :          6 :   free (bufdesc.value);
      78         [ -  + ]:          6 :   if (GSS_ERROR (maj_stat))
      79                 :          0 :     return GSASL_GSSAPI_IMPORT_NAME_ERROR;
      80                 :            : 
      81                 :            :   /* Attempt to get a credential for our mechanism.  */
      82                 :            : 
      83                 :          6 :   oid_set.count = 1;
      84                 :          6 :   oid_set.elements = state->mech_oid;
      85                 :            : 
      86                 :          6 :   maj_stat = gss_acquire_cred (&min_stat, server, 0,
      87                 :            :                                &oid_set, GSS_C_ACCEPT,
      88                 :            :                                &state->cred, &actual_mechs, NULL);
      89                 :          6 :   gss_release_name (&min_stat, &server);
      90         [ +  + ]:          6 :   if (GSS_ERROR (maj_stat))
      91                 :          1 :     return GSASL_GSSAPI_ACQUIRE_CRED_ERROR;
      92                 :            : 
      93                 :            :   /* Now double check that the credential actually was for our
      94                 :            :      mechanism... */
      95                 :            : 
      96                 :          5 :   maj_stat = gss_test_oid_set_member (&min_stat, state->mech_oid,
      97                 :            :                                       actual_mechs, &present);
      98         [ -  + ]:          5 :   if (GSS_ERROR (maj_stat))
      99                 :            :     {
     100                 :          0 :       gss_release_oid_set (&min_stat, &actual_mechs);
     101                 :          0 :       return GSASL_GSSAPI_TEST_OID_SET_MEMBER_ERROR;
     102                 :            :     }
     103                 :            : 
     104                 :          5 :   maj_stat = gss_release_oid_set (&min_stat, &actual_mechs);
     105         [ -  + ]:          5 :   if (GSS_ERROR (maj_stat))
     106                 :          0 :     return GSASL_GSSAPI_RELEASE_OID_SET_ERROR;
     107                 :            : 
     108         [ -  + ]:          5 :   if (!present)
     109                 :          0 :     return GSASL_GSSAPI_ACQUIRE_CRED_ERROR;
     110                 :            : 
     111                 :          8 :   return GSASL_OK;
     112                 :            : }
     113                 :            : 
     114                 :            : /* Initialize GS2 state into MECH_DATA.  Return GSASL_OK if GS2 is
     115                 :            :    ready and initialization succeeded, or an error code. */
     116                 :            : int
     117                 :          8 : _gsasl_gs2_server_start (Gsasl_session * sctx, void **mech_data)
     118                 :            : {
     119                 :            :   _Gsasl_gs2_server_state *state;
     120                 :            :   int res;
     121                 :            : 
     122                 :          8 :   state = (_Gsasl_gs2_server_state *) malloc (sizeof (*state));
     123         [ -  + ]:          8 :   if (state == NULL)
     124                 :          0 :     return GSASL_MALLOC_ERROR;
     125                 :            : 
     126                 :          8 :   res = gs2_get_oid (sctx, &state->mech_oid);
     127         [ -  + ]:          8 :   if (res != GSASL_OK)
     128                 :            :     {
     129                 :          0 :       free (state);
     130                 :          0 :       return res;
     131                 :            :     }
     132                 :            : 
     133                 :          8 :   res = gs2_get_cred (sctx, state);
     134         [ +  + ]:          8 :   if (res != GSASL_OK)
     135                 :            :     {
     136                 :          3 :       free (state);
     137                 :          3 :       return res;
     138                 :            :     }
     139                 :            : 
     140                 :          5 :   state->step = 0;
     141                 :          5 :   state->context = GSS_C_NO_CONTEXT;
     142                 :          5 :   state->client = NULL;
     143                 :            :   /* The initiator-address-type and acceptor-address-type fields of
     144                 :            :      the GSS-CHANNEL-BINDINGS structure MUST be set to 0.  The
     145                 :            :      initiator-address and acceptor-address fields MUST be the empty
     146                 :            :      string. */
     147                 :          5 :   state->cb.initiator_addrtype = 0;
     148                 :          5 :   state->cb.initiator_address.length = 0;
     149                 :          5 :   state->cb.initiator_address.value = NULL;
     150                 :          5 :   state->cb.acceptor_addrtype = 0;
     151                 :          5 :   state->cb.acceptor_address.length = 0;
     152                 :          5 :   state->cb.acceptor_address.value = NULL;
     153                 :          5 :   state->cb.application_data.length = 0;
     154                 :          5 :   state->cb.application_data.value = NULL;
     155                 :            : 
     156                 :          5 :   *mech_data = state;
     157                 :            : 
     158                 :          8 :   return GSASL_OK;
     159                 :            : }
     160                 :            : 
     161                 :            : /* Create in AUTHZID a newly allocated copy of STR where =2C is
     162                 :            :    replaced with , and =3D is replaced with =.  Return GSASL_OK on
     163                 :            :    success, GSASL_MALLOC_ERROR on memory errors, GSASL_PARSE_ERRORS if
     164                 :            :    string contains any unencoded ',' or incorrectly encoded
     165                 :            :    sequence.  */
     166                 :            : static int
     167                 :          4 : unescape_authzid (const char *str, size_t len, char **authzid)
     168                 :            : {
     169                 :            :   char *p;
     170                 :            : 
     171         [ -  + ]:          4 :   if (memchr (str, ',', len) != NULL)
     172                 :          0 :     return GSASL_MECHANISM_PARSE_ERROR;
     173                 :            : 
     174                 :          4 :   p = *authzid = malloc (len + 1);
     175         [ -  + ]:          4 :   if (!p)
     176                 :          0 :     return GSASL_MALLOC_ERROR;
     177                 :            : 
     178 [ +  + ][ +  - ]:         19 :   while (len > 0 && *str)
     179                 :            :     {
     180 [ +  + ][ +  + ]:         15 :       if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
         [ +  + ][ +  - ]
     181                 :            :         {
     182                 :          3 :           *p++ = ',';
     183                 :          3 :           str += 3;
     184                 :          3 :           len -= 3;
     185                 :            :         }
     186 [ +  + ][ +  + ]:         12 :       else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
         [ +  - ][ +  - ]
     187                 :            :         {
     188                 :          3 :           *p++ = '=';
     189                 :          3 :           str += 3;
     190                 :          3 :           len -= 3;
     191                 :            :         }
     192         [ -  + ]:          9 :       else if (str[0] == '=')
     193                 :            :         {
     194                 :          0 :           free (*authzid);
     195                 :          0 :           *authzid = NULL;
     196                 :          0 :           return GSASL_MECHANISM_PARSE_ERROR;
     197                 :            :         }
     198                 :            :       else
     199                 :            :         {
     200                 :          9 :           *p++ = *str;
     201                 :          9 :           str++;
     202                 :          9 :           len--;
     203                 :            :         }
     204                 :            :     }
     205                 :          4 :   *p = '\0';
     206                 :            : 
     207                 :          4 :   return GSASL_OK;
     208                 :            : }
     209                 :            : 
     210                 :            : /* Parse the GS2 header containing flags and authorization identity.
     211                 :            :    Put authorization identity (or NULL) in AUTHZID and length of
     212                 :            :    header in HEADERLEN.  Return GSASL_OK on success or an error
     213                 :            :    code.*/
     214                 :            : static int
     215                 :          5 : parse_gs2_header (const char *data, size_t len,
     216                 :            :                   char **authzid, size_t * headerlen)
     217                 :            : {
     218                 :            :   char *authzid_endptr;
     219                 :            : 
     220         [ -  + ]:          5 :   if (len < 3)
     221                 :          0 :     return GSASL_MECHANISM_PARSE_ERROR;
     222                 :            : 
     223         [ +  + ]:          5 :   if (strncmp (data, "n,,", 3) == 0)
     224                 :            :     {
     225                 :          1 :       *headerlen = 3;
     226                 :          1 :       *authzid = NULL;
     227                 :            :     }
     228 [ +  - ][ +  - ]:          8 :   else if (strncmp (data, "n,a=", 4) == 0 &&
     229                 :          4 :            (authzid_endptr = memchr (data + 4, ',', len - 4)))
     230                 :            :     {
     231                 :            :       int res;
     232                 :            : 
     233         [ -  + ]:          4 :       if (authzid_endptr == NULL)
     234                 :          0 :         return GSASL_MECHANISM_PARSE_ERROR;
     235                 :            : 
     236                 :          4 :       res = unescape_authzid (data + 4, authzid_endptr - (data + 4), authzid);
     237         [ -  + ]:          4 :       if (res != GSASL_OK)
     238                 :          0 :         return res;
     239                 :            : 
     240                 :          4 :       *headerlen = authzid_endptr - data + 1;
     241                 :            :     }
     242                 :            :   else
     243                 :          0 :     return GSASL_MECHANISM_PARSE_ERROR;
     244                 :            : 
     245                 :          5 :   return GSASL_OK;
     246                 :            : }
     247                 :            : 
     248                 :            : /* Perform one GS2 step.  GS2 state is in MECH_DATA.  Any data from
     249                 :            :    client is provided in INPUT/INPUT_LEN and output from server is
     250                 :            :    expected to be put in newly allocated OUTPUT/OUTPUT_LEN.  Return
     251                 :            :    GSASL_NEEDS_MORE or GSASL_OK on success, or an error code.  */
     252                 :            : int
     253                 :          7 : _gsasl_gs2_server_step (Gsasl_session * sctx,
     254                 :            :                         void *mech_data,
     255                 :            :                         const char *input, size_t input_len,
     256                 :            :                         char **output, size_t * output_len)
     257                 :            : {
     258                 :          7 :   _Gsasl_gs2_server_state *state = mech_data;
     259                 :            :   gss_buffer_desc bufdesc1, bufdesc2;
     260                 :            :   OM_uint32 maj_stat, min_stat;
     261                 :            :   gss_buffer_desc client_name;
     262                 :            :   gss_OID mech_type;
     263                 :            :   int res;
     264                 :            :   OM_uint32 ret_flags;
     265                 :          7 :   int free_bufdesc1 = 0;
     266                 :            : 
     267                 :          7 :   *output = NULL;
     268                 :          7 :   *output_len = 0;
     269                 :          7 :   bufdesc1.value = input;
     270                 :          7 :   bufdesc1.length = input_len;
     271                 :            : 
     272   [ +  -  -  - ]:          7 :   switch (state->step)
     273                 :            :     {
     274                 :            :     case 0:
     275         [ +  + ]:          7 :       if (input_len == 0)
     276                 :            :         {
     277                 :          2 :           res = GSASL_NEEDS_MORE;
     278                 :          2 :           break;
     279                 :            :         }
     280                 :          5 :       state->step++;
     281                 :            :       /* fall through */
     282                 :            : 
     283                 :            :     case 1:
     284                 :            :       {
     285                 :            :         char *authzid;
     286                 :            :         size_t headerlen;
     287                 :            : 
     288                 :          5 :         res = parse_gs2_header (input, input_len, &authzid, &headerlen);
     289         [ -  + ]:          5 :         if (res != GSASL_OK)
     290                 :          0 :           return res;
     291                 :            : 
     292         [ +  + ]:          5 :         if (authzid)
     293                 :            :           {
     294                 :          4 :             gsasl_property_set (sctx, GSASL_AUTHZID, authzid);
     295                 :          4 :             free (authzid);
     296                 :            :           }
     297                 :            : 
     298                 :          5 :         state->cb.application_data.value = input;
     299                 :          5 :         state->cb.application_data.length = headerlen;
     300                 :            : 
     301                 :          5 :         bufdesc2.value = input + headerlen;
     302                 :          5 :         bufdesc2.length = input_len - headerlen;
     303                 :            : 
     304                 :          5 :         maj_stat = gss_encapsulate_token (&bufdesc2, state->mech_oid,
     305                 :            :                                           &bufdesc1);
     306         [ -  + ]:          5 :         if (GSS_ERROR (maj_stat))
     307                 :          0 :           return GSASL_GSSAPI_ENCAPSULATE_TOKEN_ERROR;
     308                 :            : 
     309                 :          5 :         free_bufdesc1 = 1;
     310                 :            :       }
     311                 :          5 :       state->step++;
     312                 :            :       /* fall through */
     313                 :            : 
     314                 :            :     case 2:
     315         [ -  + ]:          5 :       if (state->client)
     316                 :            :         {
     317                 :          0 :           gss_release_name (&min_stat, &state->client);
     318                 :          0 :           state->client = GSS_C_NO_NAME;
     319                 :            :         }
     320                 :            : 
     321                 :          5 :       maj_stat = gss_accept_sec_context (&min_stat,
     322                 :            :                                          &state->context,
     323                 :            :                                          state->cred,
     324                 :            :                                          &bufdesc1,
     325                 :            :                                          &state->cb,
     326                 :            :                                          &state->client,
     327                 :            :                                          &mech_type,
     328                 :            :                                          &bufdesc2, &ret_flags, NULL, NULL);
     329   [ -  +  #  # ]:          5 :       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
     330                 :          0 :         return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR;
     331                 :            : 
     332         [ +  - ]:          5 :       if (maj_stat == GSS_S_COMPLETE)
     333                 :            :         {
     334                 :          5 :           state->step++;
     335                 :            : 
     336         [ -  + ]:          5 :           if (!(ret_flags & GSS_C_MUTUAL_FLAG))
     337                 :          0 :             return GSASL_MECHANISM_PARSE_ERROR;
     338                 :            : 
     339                 :          5 :           maj_stat = gss_display_name (&min_stat, state->client,
     340                 :            :                                        &client_name, &mech_type);
     341         [ -  + ]:          5 :           if (GSS_ERROR (maj_stat))
     342                 :          0 :             return GSASL_GSSAPI_DISPLAY_NAME_ERROR;
     343                 :            : 
     344                 :          5 :           gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
     345                 :          5 :                                   client_name.value, client_name.length);
     346                 :            : 
     347                 :          5 :           res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);
     348                 :            :         }
     349                 :            :       else
     350                 :          0 :         res = GSASL_NEEDS_MORE;
     351                 :            : 
     352         [ +  - ]:          5 :       if (free_bufdesc1)
     353                 :            :         {
     354                 :          5 :           maj_stat = gss_release_buffer (&min_stat, &bufdesc1);
     355         [ -  + ]:          5 :           if (GSS_ERROR (maj_stat))
     356                 :          0 :             return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
     357                 :            :         }
     358                 :            : 
     359                 :          5 :       *output = malloc (bufdesc2.length);
     360         [ -  + ]:          5 :       if (!*output)
     361                 :          0 :         return GSASL_MALLOC_ERROR;
     362                 :          5 :       memcpy (*output, bufdesc2.value, bufdesc2.length);
     363                 :          5 :       *output_len = bufdesc2.length;
     364                 :            : 
     365                 :          5 :       maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
     366         [ -  + ]:          5 :       if (GSS_ERROR (maj_stat))
     367                 :          0 :         return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;
     368                 :          5 :       break;
     369                 :            : 
     370                 :            :     default:
     371                 :          0 :       res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
     372                 :            :       break;
     373                 :            :     }
     374                 :            : 
     375                 :          7 :   return res;
     376                 :            : }
     377                 :            : 
     378                 :            : /* Cleanup GS2 state context, i.e., release memory associated with
     379                 :            :    buffers in MECH_DATA state. */
     380                 :            : void
     381                 :          8 : _gsasl_gs2_server_finish (Gsasl_session * sctx, void *mech_data)
     382                 :            : {
     383                 :          8 :   _Gsasl_gs2_server_state *state = mech_data;
     384                 :            :   OM_uint32 min_stat;
     385                 :            : 
     386         [ +  + ]:          8 :   if (!state)
     387                 :          3 :     return;
     388                 :            : 
     389         [ +  - ]:          5 :   if (state->context != GSS_C_NO_CONTEXT)
     390                 :          5 :     gss_delete_sec_context (&min_stat, &state->context, GSS_C_NO_BUFFER);
     391                 :            : 
     392         [ +  - ]:          5 :   if (state->cred != GSS_C_NO_CREDENTIAL)
     393                 :          5 :     gss_release_cred (&min_stat, &state->cred);
     394                 :            : 
     395         [ +  - ]:          5 :   if (state->client != GSS_C_NO_NAME)
     396                 :          5 :     gss_release_name (&min_stat, &state->client);
     397                 :            : 
     398                 :          8 :   free (state);
     399                 :            : }

Generated by: LCOV version 1.8