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