1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, 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 * https://davenport.sourceforge.io/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_core.h" 41 #include "curl_ntlm_wb.h" 42 #include "vauth/vauth.h" 43 #include "url.h" 44 45 /* SSL backend-specific #if branches in this file must be kept in the order 46 documented in curl_ntlm_core. */ 47 #if defined(NTLM_NEEDS_NSS_INIT) 48 #include "vtls/nssg.h" 49 #elif defined(USE_WINDOWS_SSPI) 50 #include "curl_sspi.h" 51 #endif 52 53 /* The last 3 #include files should be in this order */ 54 #include "curl_printf.h" 55 #include "curl_memory.h" 56 #include "memdebug.h" 57 58 #if DEBUG_ME 59 # define DEBUG_OUT(x) x 60 #else 61 # define DEBUG_OUT(x) Curl_nop_stmt 62 #endif 63 64 CURLcode Curl_input_ntlm(struct connectdata *conn, 65 bool proxy, /* if proxy or not */ 66 const char *header) /* rest of the www-authenticate: 67 header */ 68 { 69 /* point to the correct struct with this */ 70 struct ntlmdata *ntlm; 71 CURLcode result = CURLE_OK; 72 73 ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; 74 75 if(checkprefix("NTLM", header)) { 76 header += strlen("NTLM"); 77 78 while(*header && ISSPACE(*header)) 79 header++; 80 81 if(*header) { 82 result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm); 83 if(result) 84 return result; 85 86 ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ 87 } 88 else { 89 if(ntlm->state == NTLMSTATE_LAST) { 90 infof(conn->data, "NTLM auth restarted\n"); 91 Curl_http_ntlm_cleanup(conn); 92 } 93 else if(ntlm->state == NTLMSTATE_TYPE3) { 94 infof(conn->data, "NTLM handshake rejected\n"); 95 Curl_http_ntlm_cleanup(conn); 96 ntlm->state = NTLMSTATE_NONE; 97 return CURLE_REMOTE_ACCESS_DENIED; 98 } 99 else if(ntlm->state >= NTLMSTATE_TYPE1) { 100 infof(conn->data, "NTLM handshake failure (internal error)\n"); 101 return CURLE_REMOTE_ACCESS_DENIED; 102 } 103 104 ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ 105 } 106 } 107 108 return result; 109 } 110 111 /* 112 * This is for creating ntlm header output 113 */ 114 CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) 115 { 116 char *base64 = NULL; 117 size_t len = 0; 118 CURLcode result; 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 #if defined(NTLM_NEEDS_NSS_INIT) 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->http_proxy.user; 143 passwdp = conn->http_proxy.passwd; 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 result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp, 177 ntlm, &base64, &len); 178 if(result) 179 return result; 180 181 if(base64) { 182 free(*allocuserpwd); 183 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 184 proxy ? "Proxy-" : "", 185 base64); 186 free(base64); 187 if(!*allocuserpwd) 188 return CURLE_OUT_OF_MEMORY; 189 190 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); 191 } 192 break; 193 194 case NTLMSTATE_TYPE2: 195 /* We already received the type-2 message, create a type-3 message */ 196 result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp, 197 ntlm, &base64, &len); 198 if(result) 199 return result; 200 201 if(base64) { 202 free(*allocuserpwd); 203 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 204 proxy ? "Proxy-" : "", 205 base64); 206 free(base64); 207 if(!*allocuserpwd) 208 return CURLE_OUT_OF_MEMORY; 209 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 ntlm->state = NTLMSTATE_LAST; 221 /* fall-through */ 222 case NTLMSTATE_LAST: 223 Curl_safefree(*allocuserpwd); 224 authp->done = TRUE; 225 break; 226 } 227 228 return CURLE_OK; 229 } 230 231 void Curl_http_ntlm_cleanup(struct connectdata *conn) 232 { 233 Curl_auth_ntlm_cleanup(&conn->ntlm); 234 Curl_auth_ntlm_cleanup(&conn->proxyntlm); 235 236 #if defined(NTLM_WB_ENABLED) 237 Curl_ntlm_wb_cleanup(conn); 238 #endif 239 } 240 241 #endif /* !CURL_DISABLE_HTTP && USE_NTLM */ 242