Инструменты пользователя

Инструменты сайта


dev:cpp:gssapi_krb5:sozdanie_stroki_dlja_negotiate_autentifikacii

Создание строки для Negotiate аутентификации

Версии (Ubuntu 8.10):

  • запуск: libkrb53;
  • сборка: libkrb5-dev.

Код

/***************************************************************************
        negotiate.c
 
    Author        : Blake-R (c) 2009
    Last update    : Птн Мар 13 15:08:11 MSK 2009
    Licence        : GPL v3
***************************************************************************/
 
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <gssapi/gssapi.h>
 
char * getNegotiateToken(const char *service,const char *server)
{
    char *token=NULL;
    OM_uint32 major,minor;
    gss_buffer_desc gss_buffer;
    gss_name_t gss_name;
    gss_ctx_id_t gss_context=GSS_C_NO_CONTEXT;
    gss_buffer_desc gss_input_token=GSS_C_EMPTY_BUFFER;
    gss_buffer_desc gss_output_token=GSS_C_EMPTY_BUFFER;
 
    if(!service||!server)
    {
        fprintf(stderr,"Service and server values cannot be NULL!\n");
        return NULL;
    }
 
    gss_buffer.length=strlen(service)+strlen(server)+2;
    gss_buffer.value=malloc(gss_buffer.length);
    if(!gss_buffer.value)
    {
        fprintf(stderr,"malloc() failed\n");
    }
    else
    {
        sprintf(gss_buffer.value,"%s@%s",service,server);
 
        major=gss_import_name(&minor,&gss_buffer,GSS_C_NT_HOSTBASED_SERVICE,&gss_name);
        if(major!=GSS_S_COMPLETE)
        {
            fprintf(stderr,"gss_import_name() error: %#x\n",major);
        }
        else
        {
            major=gss_init_sec_context(&minor,
                GSS_C_NO_CREDENTIAL,&gss_context,gss_name,GSS_C_NO_OID,
                GSS_C_DELEG_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS,
                &gss_input_token,NULL,&gss_output_token,NULL,NULL);
            if(major!=GSS_S_COMPLETE)
            {
                fprintf(stderr,"gss_init_sec_context() error: %#x\n",major);
            }
            else
            {
                if(gss_output_token.length==0)
                {
                    fprintf(stderr,"Token don't need to be send.");
                }
                else
                {
                    // TODO: Need to make SPNEGO token (spnegohelp)
                    base64_encode(gss_output_token.value,gss_output_token.length,&token);
                }
 
                major=gss_delete_sec_context(&minor,&gss_context,GSS_C_NO_BUFFER);
                if(major!=GSS_S_COMPLETE)
                {
                    fprintf(stderr,"gss_delete_sec_context() error: %#x\n",major);
                }
            }
 
            major=gss_release_name(&minor,&gss_name);
            if(major!=GSS_S_COMPLETE)
            {
                fprintf(stderr,"gss_release_name() error: %#x\n",major);
            }
        }
 
        free(gss_buffer.value);
    }
    return token;
}

Код функции base64_encode взят из проекта libcurl (функция Curl_base64_encode в файле base64.c).

/* ---- Base64 Encoding/Decoding Table --- */
static const char table64[]=
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
size_t base64_encode(const char *inp, size_t insize, char **outptr)
{
  unsigned char ibuf[3];
  unsigned char obuf[4];
  int i;
  int inputparts;
  char *output;
  char *base64data;
 
  char *indata = (char *)inp;
 
  *outptr = NULL; /* set to NULL in case of failure before we reach the end */
 
  if(0 == insize)
    insize = strlen(indata);
 
  base64data = output = (char*)malloc(insize*4/3+4);
  if(NULL == output)
    return 0;
 
  while(insize > 0) {
    for (i = inputparts = 0; i < 3; i++) {
      if(insize > 0) {
        inputparts++;
        ibuf[i] = *indata;
        indata++;
        insize--;
      }
      else
        ibuf[i] = 0;
    }
 
    obuf[0] = (unsigned char)  ((ibuf[0] & 0xFC) >> 2);
    obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
                               ((ibuf[1] & 0xF0) >> 4));
    obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
                               ((ibuf[2] & 0xC0) >> 6));
    obuf[3] = (unsigned char)   (ibuf[2] & 0x3F);
 
    switch(inputparts) {
    case 1: /* only one byte read */
      snprintf(output, 5, "%c%c==",
               table64[obuf[0]],
               table64[obuf[1]]);
      break;
    case 2: /* two bytes read */
      snprintf(output, 5, "%c%c%c=",
               table64[obuf[0]],
               table64[obuf[1]],
               table64[obuf[2]]);
      break;
    default:
      snprintf(output, 5, "%c%c%c%c",
               table64[obuf[0]],
               table64[obuf[1]],
               table64[obuf[2]],
               table64[obuf[3]] );
      break;
    }
    output += 4;
  }
  *output=0;
  *outptr = base64data; /* make it return the actual data memory */
 
  return strlen(base64data); /* return the length of the new data */
}
/* ---- End of Base64 Encoding ---- */

Использование

После включения приведённого кода в свой проект, можно использовать функцию getNegotiateToken, например, для формирования заголовка Proxy-Authorization:

char *negotiateString;
negotiateString=getNegotiateToken("HTTP","proxyserver");
if(negotiateString)
{
        printf("Proxy-Authorization: Negotiate %s\r\n",negotiateString);
        free(negotiateString);
}

Разумеется, на момент вызова функции уже должен быть получен билет Kerberos.

Замечания

  • Строка, которую возвращает эта функция отличается от таковой в Mozilla Firefox (по-моему, Mozilla всё-таки использует SPNEGO). Однако, насколько я понял, верны обе. По-крайней мере, так считает helper от Squid squid_kerb_auth.
  • Несмотря на то, что кусок кода подсмотрен в libcurl, сама библиотека по невыясненным причинам не хочет авторизовываться методом Negotiate.

TODO

  • Разобраться и по возможности добавить дополнительное преобразование SPNEGO. Функции для этого есть в spnegohelp (взять можно из того же squid_kerb_auth). При первой попытке реализации сервер при преобразовании SPNEGO возвращает rc=101 (собственно, с Firefox тоже самое), при этом контекст gss становится неверным (а вот с этим в Firefox всё нормально). … Или оно вообще не нужно?

Дискуссия

Enter your comment
 
dev/cpp/gssapi_krb5/sozdanie_stroki_dlja_negotiate_autentifikacii.txt · Последние изменения: 16.11.2009 20:26 (внешнее изменение)

Инструменты страницы