1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, 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 "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 "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 /* skip initial whitespaces */ 81 while(*header && ISSPACE(*header)) 82 header++; 83 84 if(checkprefix("NTLM", header)) { 85 header += strlen("NTLM"); 86 87 while(*header && ISSPACE(*header)) 88 header++; 89 90 if(*header) { 91 result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm); 92 if(CURLE_OK != result) 93 return result; 94 95 ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ 96 } 97 else { 98 if(ntlm->state >= NTLMSTATE_TYPE1) { 99 infof(conn->data, "NTLM handshake failure (internal error)\n"); 100 return CURLE_REMOTE_ACCESS_DENIED; 101 } 102 103 ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ 104 } 105 } 106 107 return result; 108} 109 110/* 111 * This is for creating ntlm header output 112 */ 113CURLcode Curl_output_ntlm(struct connectdata *conn, 114 bool proxy) 115{ 116 char *base64 = NULL; 117 size_t len = 0; 118 CURLcode error; 119 120 /* point to the address of the pointer that holds the string to send to the 121 server, which is for a plain host or for a HTTP proxy */ 122 char **allocuserpwd; 123 124 /* point to the name and password for this */ 125 const char *userp; 126 const char *passwdp; 127 128 /* point to the correct struct with this */ 129 struct ntlmdata *ntlm; 130 struct auth *authp; 131 132 DEBUGASSERT(conn); 133 DEBUGASSERT(conn->data); 134 135#ifdef USE_NSS 136 if(CURLE_OK != Curl_nss_force_init(conn->data)) 137 return CURLE_OUT_OF_MEMORY; 138#endif 139 140 if(proxy) { 141 allocuserpwd = &conn->allocptr.proxyuserpwd; 142 userp = conn->proxyuser; 143 passwdp = conn->proxypasswd; 144 ntlm = &conn->proxyntlm; 145 authp = &conn->data->state.authproxy; 146 } 147 else { 148 allocuserpwd = &conn->allocptr.userpwd; 149 userp = conn->user; 150 passwdp = conn->passwd; 151 ntlm = &conn->ntlm; 152 authp = &conn->data->state.authhost; 153 } 154 authp->done = FALSE; 155 156 /* not set means empty */ 157 if(!userp) 158 userp = ""; 159 160 if(!passwdp) 161 passwdp = ""; 162 163#ifdef USE_WINDOWS_SSPI 164 if(s_hSecDll == NULL) { 165 /* not thread safe and leaks - use curl_global_init() to avoid */ 166 CURLcode err = Curl_sspi_global_init(); 167 if(s_hSecDll == NULL) 168 return err; 169 } 170#endif 171 172 switch(ntlm->state) { 173 case NTLMSTATE_TYPE1: 174 default: /* for the weird cases we (re)start here */ 175 /* Create a type-1 message */ 176 error = Curl_ntlm_create_type1_message(userp, passwdp, ntlm, &base64, 177 &len); 178 179 if(error) 180 return error; 181 182 if(base64) { 183 Curl_safefree(*allocuserpwd); 184 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 185 proxy ? "Proxy-" : "", 186 base64); 187 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); 188 free(base64); 189 } 190 break; 191 192 case NTLMSTATE_TYPE2: 193 /* We already received the type-2 message, create a type-3 message */ 194 error = Curl_ntlm_create_type3_message(conn->data, userp, passwdp, 195 ntlm, &base64, &len); 196 if(error) 197 return error; 198 199 if(base64) { 200 Curl_safefree(*allocuserpwd); 201 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 202 proxy ? "Proxy-" : "", 203 base64); 204 DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); 205 free(base64); 206 207 ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ 208 authp->done = TRUE; 209 } 210 break; 211 212 case NTLMSTATE_TYPE3: 213 /* connection is already authenticated, 214 * don't send a header in future requests */ 215 if(*allocuserpwd) { 216 free(*allocuserpwd); 217 *allocuserpwd = NULL; 218 } 219 authp->done = TRUE; 220 break; 221 } 222 223 return CURLE_OK; 224} 225 226void Curl_http_ntlm_cleanup(struct connectdata *conn) 227{ 228#ifdef USE_WINDOWS_SSPI 229 Curl_ntlm_sspi_cleanup(&conn->ntlm); 230 Curl_ntlm_sspi_cleanup(&conn->proxyntlm); 231#elif defined(NTLM_WB_ENABLED) 232 Curl_ntlm_wb_cleanup(conn); 233#else 234 (void)conn; 235#endif 236} 237 238#endif /* USE_NTLM */ 239