| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "ne_ntlm.h" |
| |
| #ifdef HAVE_NTLM |
| |
| #include "ne_string.h" |
| |
| typedef enum { |
| NTLMSTATE_NONE, |
| NTLMSTATE_TYPE1, |
| NTLMSTATE_TYPE2, |
| NTLMSTATE_TYPE3, |
| NTLMSTATE_LAST |
| } NTLMState; |
| |
| struct ne_ntlm_context_s { |
| NTLMState state; |
| unsigned char nonce[8]; |
| char *user; |
| char *passwd; |
| char *requestToken; |
| }; |
| |
| typedef enum { |
| NTLM_NONE, |
| NTLM_BAD, |
| NTLM_FIRST, |
| NTLM_FINE, |
| |
| NTLM_LAST |
| } ntlm; |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_OEM (1<<1) |
| |
| |
| #define NTLMFLAG_REQUEST_TARGET (1<<2) |
| |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_SIGN (1<<4) |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_SEAL (1<<5) |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6) |
| |
| |
| #define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7) |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_NETWARE (1<<8) |
| |
| |
| #define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9) |
| |
| |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12) |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13) |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14) |
| |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15) |
| |
| |
| |
| #define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16) |
| |
| |
| |
| #define NTLMFLAG_TARGET_TYPE_SERVER (1<<17) |
| |
| |
| |
| #define NTLMFLAG_TARGET_TYPE_SHARE (1<<18) |
| |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19) |
| |
| |
| |
| #define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20) |
| |
| |
| #define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21) |
| |
| |
| #define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22) |
| |
| |
| #define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define NTLMFLAG_NEGOTIATE_128 (1<<29) |
| |
| |
| #define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30) |
| |
| |
| #define NTLMFLAG_NEGOTIATE_56 (1<<31) |
| |
| |
| #ifdef HAVE_OPENSSL |
| |
| |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| |
| #include <openssl/des.h> |
| #include <openssl/md4.h> |
| #include <openssl/ssl.h> |
| |
| #if OPENSSL_VERSION_NUMBER < 0x00907001L |
| #define DES_key_schedule des_key_schedule |
| #define DES_cblock des_cblock |
| #define DES_set_odd_parity des_set_odd_parity |
| #define DES_set_key des_set_key |
| #define DES_ecb_encrypt des_ecb_encrypt |
| |
| |
| #define DESKEY(x) x |
| #define DESKEYARG(x) x |
| #else |
| |
| #define DESKEYARG(x) *x |
| #define DESKEY(x) &x |
| #endif |
| |
| |
| #define USE_NTRESPONSES 1 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static ntlm ne_input_ntlm(ne_ntlm_context *ctx, |
| const char *responseToken) |
| { |
| if(responseToken) { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| unsigned char * buffer = NULL; |
| |
| int size = ne_unbase64(responseToken, &buffer); |
| |
| ctx->state = NTLMSTATE_TYPE2; |
| |
| if(size >= 48) |
| |
| memcpy(ctx->nonce, &buffer[24], 8); |
| |
| |
| |
| if (buffer) ne_free(buffer); |
| } |
| else { |
| if(ctx->state >= NTLMSTATE_TYPE1) |
| return NTLM_BAD; |
| |
| ctx->state = NTLMSTATE_TYPE1; |
| } |
| return NTLM_FINE; |
| } |
| |
| |
| |
| |
| |
| static void setup_des_key(unsigned char *key_56, |
| DES_key_schedule DESKEYARG(ks)) |
| { |
| DES_cblock key; |
| |
| key[0] = key_56[0]; |
| key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1); |
| key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2); |
| key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3); |
| key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4); |
| key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5); |
| key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6); |
| key[7] = (key_56[6] << 1) & 0xFF; |
| |
| DES_set_odd_parity(&key); |
| DES_set_key(&key, ks); |
| } |
| |
| |
| |
| |
| |
| |
| static void calc_resp(unsigned char *keys, |
| unsigned char *plaintext, |
| unsigned char *results) |
| { |
| DES_key_schedule ks; |
| |
| setup_des_key(keys, DESKEY(ks)); |
| DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, |
| DESKEY(ks), DES_ENCRYPT); |
| |
| setup_des_key(keys+7, DESKEY(ks)); |
| DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8), |
| DESKEY(ks), DES_ENCRYPT); |
| |
| setup_des_key(keys+14, DESKEY(ks)); |
| DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16), |
| DESKEY(ks), DES_ENCRYPT); |
| } |
| |
| |
| |
| |
| static void mkhash(char *password, |
| unsigned char *nonce, |
| unsigned char *lmresp |
| #ifdef USE_NTRESPONSES |
| , unsigned char *ntresp |
| #endif |
| ) |
| { |
| unsigned char lmbuffer[21]; |
| #ifdef USE_NTRESPONSES |
| unsigned char ntbuffer[21]; |
| #endif |
| unsigned char *pw; |
| static const unsigned char magic[] = { |
| 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 |
| }; |
| int i; |
| int len = strlen(password); |
| |
| |
| pw = ne_malloc(len<7?14:len*2); |
| if(!pw) |
| return; |
| |
| if (len > 14) |
| len = 14; |
| |
| for (i=0; i<len; i++) |
| pw[i] = toupper(password[i]); |
| |
| for (; i<14; i++) |
| pw[i] = 0; |
| |
| { |
| |
| DES_key_schedule ks; |
| |
| setup_des_key(pw, DESKEY(ks)); |
| DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, |
| DESKEY(ks), DES_ENCRYPT); |
| |
| setup_des_key(pw+7, DESKEY(ks)); |
| DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8), |
| DESKEY(ks), DES_ENCRYPT); |
| |
| memset(lmbuffer+16, 0, 5); |
| } |
| |
| calc_resp(lmbuffer, nonce, lmresp); |
| |
| #ifdef USE_NTRESPONSES |
| { |
| |
| MD4_CTX md4; |
| |
| len = strlen(password); |
| |
| for (i=0; i<len; i++) { |
| pw[2*i] = password[i]; |
| pw[2*i+1] = 0; |
| } |
| |
| MD4_Init(&md4); |
| MD4_Update(&md4, pw, 2*len); |
| MD4_Final(ntbuffer, &md4); |
| |
| memset(ntbuffer+16, 0, 5); |
| } |
| |
| calc_resp(ntbuffer, nonce, ntresp); |
| #endif |
| |
| ne_free(pw); |
| } |
| |
| #define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8) |
| #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \ |
| (((x) >>16)&0xff), ((x)>>24) |
| |
| |
| static int ne_output_ntlm(ne_ntlm_context *ctx) |
| { |
| const char *domain=""; |
| const char *host=""; |
| int domlen=strlen(domain); |
| int hostlen = strlen(host); |
| int hostoff; |
| int domoff; |
| int size; |
| unsigned char ntlmbuf[256]; |
| |
| if(!ctx->user || !ctx->passwd) |
| |
| return 0; |
| |
| switch(ctx->state) { |
| case NTLMSTATE_TYPE1: |
| default: |
| hostoff = 32; |
| domoff = hostoff + hostlen; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| ne_snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c" |
| "\x01%c%c%c" |
| "%c%c%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%s" |
| "%s", |
| 0, |
| 0,0,0, |
| |
| LONGQUARTET( |
| NTLMFLAG_NEGOTIATE_OEM| |
| NTLMFLAG_NEGOTIATE_NTLM_KEY |
| |
| ), |
| SHORTPAIR(domlen), |
| SHORTPAIR(domlen), |
| SHORTPAIR(domoff), |
| 0,0, |
| SHORTPAIR(hostlen), |
| SHORTPAIR(hostlen), |
| SHORTPAIR(hostoff), |
| 0,0, |
| host, domain); |
| |
| |
| size = 32 + hostlen + domlen; |
| |
| |
| if (ctx->requestToken) ne_free(ctx->requestToken); |
| ctx->requestToken = ne_base64(ntlmbuf, size); |
| |
| break; |
| |
| case NTLMSTATE_TYPE2: |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| { |
| int lmrespoff; |
| int ntrespoff; |
| int useroff; |
| unsigned char lmresp[0x18]; |
| #ifdef USE_NTRESPONSES |
| unsigned char ntresp[0x18]; |
| #endif |
| const char *user; |
| int userlen; |
| |
| user = strchr(ctx->user, '\\'); |
| if(!user) |
| user = strchr(ctx->user, '/'); |
| |
| if (user) { |
| domain = ctx->user; |
| domlen = user - domain; |
| user++; |
| } |
| else |
| user = ctx->user; |
| userlen = strlen(user); |
| |
| mkhash(ctx->passwd, &ctx->nonce[0], lmresp |
| #ifdef USE_NTRESPONSES |
| , ntresp |
| #endif |
| ); |
| |
| domoff = 64; |
| useroff = domoff + domlen; |
| hostoff = useroff + userlen; |
| lmrespoff = hostoff + hostlen; |
| ntrespoff = lmrespoff + 0x18; |
| |
| |
| size = ne_snprintf((char *)ntlmbuf, sizeof(ntlmbuf), |
| "NTLMSSP%c" |
| "\x03%c%c%c" |
| |
| "%c%c%c%c" |
| "%c%c" |
| "%c%c" |
| |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| |
| "%c%c" |
| "%c%c" |
| "%c%c" |
| "%c%c%c%c%c%c" |
| |
| "\xff\xff" |
| "%c%c" |
| |
| "\x01\x82" |
| "%c%c" |
| |
| |
| |
| |
| |
| |
| , |
| 0, |
| 0,0,0, |
| |
| SHORTPAIR(0x18), |
| SHORTPAIR(0x18), |
| SHORTPAIR(lmrespoff), |
| 0x0, 0x0, |
| |
| #ifdef USE_NTRESPONSES |
| SHORTPAIR(0x18), |
| SHORTPAIR(0x18), |
| #else |
| 0x0, 0x0, |
| 0x0, 0x0, |
| #endif |
| SHORTPAIR(ntrespoff), |
| 0x0, 0x0, |
| |
| SHORTPAIR(domlen), |
| SHORTPAIR(domlen), |
| SHORTPAIR(domoff), |
| 0x0, 0x0, |
| |
| SHORTPAIR(userlen), |
| SHORTPAIR(userlen), |
| SHORTPAIR(useroff), |
| 0x0, 0x0, |
| |
| SHORTPAIR(hostlen), |
| SHORTPAIR(hostlen), |
| SHORTPAIR(hostoff), |
| 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
| |
| 0x0, 0x0, |
| |
| 0x0, 0x0); |
| |
| |
| size=64; |
| ntlmbuf[62]=ntlmbuf[63]=0; |
| |
| |
| |
| if((size_t)size + userlen + domlen >= sizeof(ntlmbuf)) { |
| return -1; |
| } |
| |
| memcpy(&ntlmbuf[size], domain, domlen); |
| size += domlen; |
| |
| memcpy(&ntlmbuf[size], user, userlen); |
| size += userlen; |
| |
| |
| if(size < ((int)sizeof(ntlmbuf) - 0x18)) { |
| memcpy(&ntlmbuf[size], lmresp, 0x18); |
| size += 0x18; |
| } |
| |
| #ifdef USE_NTRESPONSES |
| if(size < ((int)sizeof(ntlmbuf) - 0x18)) { |
| memcpy(&ntlmbuf[size], ntresp, 0x18); |
| size += 0x18; |
| } |
| #endif |
| |
| ntlmbuf[56] = size & 0xff; |
| ntlmbuf[57] = size >> 8; |
| |
| |
| ctx->requestToken = ne_base64(ntlmbuf, size); |
| |
| ctx->state = NTLMSTATE_TYPE3; |
| } |
| break; |
| |
| case NTLMSTATE_TYPE3: |
| |
| |
| if (ctx->requestToken) ne_free(ctx->requestToken); |
| ctx->requestToken = NULL; |
| break; |
| } |
| |
| return 0; |
| } |
| |
| ne_ntlm_context *ne__ntlm_create_context(const char *userName, const char *password) |
| { |
| ne_ntlm_context *ctx = ne_calloc(sizeof(ne_ntlm_context)); |
| |
| ctx->state = NTLMSTATE_NONE; |
| ctx->user = ne_strdup(userName); |
| ctx->passwd = ne_strdup(password); |
| |
| return ctx; |
| } |
| |
| void ne__ntlm_destroy_context(ne_ntlm_context *context) |
| { |
| if (context->user) |
| ne_free(context->user); |
| |
| if (context->passwd) |
| ne_free(context->passwd); |
| |
| if (context->requestToken) |
| ne_free(context->requestToken); |
| |
| ne_free(context); |
| } |
| |
| int ne__ntlm_authenticate(ne_ntlm_context *context, const char *responseToken) |
| { |
| if (context == NULL) { |
| return -1; |
| } else { |
| if (!responseToken && (context->state == NTLMSTATE_TYPE3)) |
| context->state = NTLMSTATE_NONE; |
| |
| if (context->state <= NTLMSTATE_TYPE3) { |
| ntlm ntlmstatus = ne_input_ntlm(context, responseToken); |
| |
| if (ntlmstatus != NTLM_FINE) { |
| return -1; |
| } |
| } |
| } |
| return ne_output_ntlm(context); |
| } |
| |
| char *ne__ntlm_getRequestToken(ne_ntlm_context *context) |
| { |
| char *ret; |
| |
| if (context == NULL || !context->requestToken) { |
| return NULL; |
| } |
| |
| ret = ne_strdup(context->requestToken); |
| ne_free(context->requestToken); |
| context->requestToken = NULL; |
| return ret; |
| } |
| |
| #endif /* HAVE_OPENSSL */ |
| #endif /* HAVE_NTLM */ |