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