Создание строки для 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 21:26 (внешнее изменение)
 
За исключением случаев, когда указано иное, содержимое этой вики предоставляется на условиях следующей лицензии:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki
окна века москва
юридические услуги москва
как поменять фамилию
турагентство одинцово