1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23#include "curl_setup.h" 24 25#ifdef USE_NTLM 26 27/* 28 * NTLM details: 29 * 30 * http://davenport.sourceforge.net/ntlm.html 31 * http://www.innovation.ch/java/ntlm.html 32 */ 33 34#define DEBUG_ME 0 35 36#include "urldata.h" 37#include "sendf.h" 38#include "rawstr.h" 39#include "curl_ntlm.h" 40#include "curl_ntlm_msgs.h" 41#include "curl_ntlm_wb.h" 42#include "url.h" 43#include "curl_memory.h" 44 45#define _MPRINTF_REPLACE /* use our functions only */ 46#include <curl/mprintf.h> 47 48#if defined(USE_NSS) 49#include "vtls/nssg.h" 50#elif defined(USE_WINDOWS_SSPI) 51#include "curl_sspi.h" 52#endif 53 54/* The last #include file should be: */ 55#include "memdebug.h" 56 57#if DEBUG_ME 58# define DEBUG_OUT(x) x 59#else 60# define DEBUG_OUT(x) Curl_nop_stmt 61#endif 62 63CURLcode Curl_input_ntlm(struct connectdata *conn, 64 bool proxy, /* if proxy or not */ 65 const char *header) /* rest of the www-authenticate: 66 header */ 67{ 68 /* point to the correct struct with this */ 69 struct ntlmdata *ntlm; 70 CURLcode result = CURLE_OK; 71 72#ifdef USE_NSS 73 result = Curl_nss_force_init(conn->data); 74 if(result) 75 return result; 76#endif 77 78 ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; 79 80 if(checkprefix("NTLM", header)) { 81 header += strlen("NTLM"); 82 83 while(*header && ISSPACE(*header)) 84 header++; 85 86 if(*header) { 87 result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm); 88 if(CURLE_OK != result) 89 return result; 90 91 ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ 92 } 93 else { 94 if(ntlm->state == NTLMSTATE_TYPE3) { 95 infof(conn->data, "NTLM handshake rejected\n"); 96 Curl_http_ntlm_cleanup(conn); 97 ntlm->state = NTLMSTATE_NONE; 98 return CURLE_REMOTE_ACCESS_DENIED; 99 } 100 else if(ntlm->state >= NTLMSTATE_TYPE1) { 101 infof(conn->data, "NTLM handshake failure (internal error)\n"); 102 return CURLE_REMOTE_ACCESS_DENIED; 103 } 104 105 ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ 106 } 107 } 108 109 return result; 110} 111 112/* 113 * This is for creating ntlm header output 114 */ 115CURLcode Curl_output_ntlm(struct connectdata *conn, 116 bool proxy) 117{ 118 char *base64 = NULL; 119 size_t len = 0; 120 CURLcode error; 121 122 /* point to the address of the pointer that holds the string to send to the 123 server, which is for a plain host or for a HTTP proxy */ 124 char **allocuserpwd; 125 126 /* point to the name and password for this */ 127 const char *userp; 128 const char *passwdp; 129 130 /* point to the correct struct with this */ 131 struct ntlmdata *ntlm; 132 struct auth *authp; 133 134 DEBUGASSERT(conn); 135 DEBUGASSERT(conn->data); 136 137#ifdef USE_NSS 138 if(CURLE_OK != Curl_nss_force_init(conn->data)) 139 return CURLE_OUT_OF_MEMORY; 140#endif 141 142 if(proxy) { 143 allocuserpwd = &conn->allocptr.proxyuserpwd; 144 userp = conn->proxyuser; 145 passwdp = conn->proxypasswd; 146 ntlm = &conn->proxyntlm; 147 authp = &conn->data->state.authproxy; 148 } 149 else { 150 allocuserpwd = &conn->allocptr.userpwd; 151 userp = conn->user; 152 passwdp = conn->passwd; 153 ntlm = &conn->ntlm; 154 authp = &conn->data->state.authhost; 155 } 156 authp->done = FALSE; 157 158 /* not set means empty */ 159 if(!userp) 160 userp = ""; 161 162 if(!passwdp) 163 passwdp = ""; 164 165#ifdef USE_WINDOWS_SSPI 166 if(s_hSecDll == NULL) { 167 /* not thread safe and leaks - use curl_global_init() to avoid */ 168 CURLcode err = Curl_sspi_global_init(); 169 if(s_hSecDll == NULL) 170 return err; 171 } 172#endif 173 174 switch(ntlm->state) { 175 case NTLMSTATE_TYPE1: 176 default: /* for the weird cases we (re)start here */ 177 /* Create a type-1 message */ 178 error = Curl_ntlm_create_type1_message(userp, passwdp, ntlm, &base64, 179 &len); 180 if(error) 181 return error; 182 183 if(base64) { 184 Curl_safefree(*allocuserpwd); 185 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 186 proxy ? "Proxy-" : "", 187 base64); 188 free(base64); 189 if(!*allocuserpwd) 190 return CURLE_OUT_OF_MEMORY; 191 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); 192 } 193 break; 194 195 case NTLMSTATE_TYPE2: 196 /* We already received the type-2 message, create a type-3 message */ 197 error = Curl_ntlm_create_type3_message(conn->data, userp, passwdp, 198 ntlm, &base64, &len); 199 if(error) 200 return error; 201 202 if(base64) { 203 Curl_safefree(*allocuserpwd); 204 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 205 proxy ? "Proxy-" : "", 206 base64); 207 free(base64); 208 if(!*allocuserpwd) 209 return CURLE_OUT_OF_MEMORY; 210 DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); 211 212 ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ 213 authp->done = TRUE; 214 } 215 break; 216 217 case NTLMSTATE_TYPE3: 218 /* connection is already authenticated, 219 * don't send a header in future requests */ 220 Curl_safefree(*allocuserpwd); 221 authp->done = TRUE; 222 break; 223 } 224 225 return CURLE_OK; 226} 227 228void Curl_http_ntlm_cleanup(struct connectdata *conn) 229{ 230#ifdef USE_WINDOWS_SSPI 231 Curl_ntlm_sspi_cleanup(&conn->ntlm); 232 Curl_ntlm_sspi_cleanup(&conn->proxyntlm); 233#elif defined(NTLM_WB_ENABLED) 234 Curl_ntlm_wb_cleanup(conn); 235#else 236 (void)conn; 237#endif 238 239#ifndef USE_WINDOWS_SSPI 240 Curl_safefree(conn->ntlm.target_info); 241 conn->ntlm.target_info_len = 0; 242 243 Curl_safefree(conn->proxyntlm.target_info); 244 conn->proxyntlm.target_info_len = 0; 245#endif 246} 247 248#endif /* USE_NTLM */ 249