vauth.c (7755B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Steve Holme, <steve_holme@hotmail.com>. 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.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 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "../curl_setup.h" 26 27 #include <curl/curl.h> 28 29 #include "vauth.h" 30 #include "../strdup.h" 31 #include "../urldata.h" 32 #include "../curlx/multibyte.h" 33 #include "../curl_printf.h" 34 #include "../url.h" 35 36 /* The last #include files should be: */ 37 #include "../curl_memory.h" 38 #include "../memdebug.h" 39 40 /* 41 * Curl_auth_build_spn() 42 * 43 * This is used to build an SPN string in the following formats: 44 * 45 * service/host@realm (Not currently used) 46 * service/host (Not used by GSS-API) 47 * service@realm (Not used by Windows SSPI) 48 * 49 * Parameters: 50 * 51 * service [in] - The service type such as http, smtp, pop or imap. 52 * host [in] - The hostname. 53 * realm [in] - The realm. 54 * 55 * Returns a pointer to the newly allocated SPN. 56 */ 57 #if !defined(USE_WINDOWS_SSPI) 58 char *Curl_auth_build_spn(const char *service, const char *host, 59 const char *realm) 60 { 61 char *spn = NULL; 62 63 /* Generate our SPN */ 64 if(host && realm) 65 spn = aprintf("%s/%s@%s", service, host, realm); 66 else if(host) 67 spn = aprintf("%s/%s", service, host); 68 else if(realm) 69 spn = aprintf("%s@%s", service, realm); 70 71 /* Return our newly allocated SPN */ 72 return spn; 73 } 74 #else 75 TCHAR *Curl_auth_build_spn(const char *service, const char *host, 76 const char *realm) 77 { 78 char *utf8_spn = NULL; 79 TCHAR *tchar_spn = NULL; 80 TCHAR *dupe_tchar_spn = NULL; 81 82 (void) realm; 83 84 /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather 85 than doing this ourselves but the first is only available in Windows XP 86 and Windows Server 2003 and the latter is only available in Windows 2000 87 but not Windows95/98/ME or Windows NT4.0 unless the Active Directory 88 Client Extensions are installed. As such it is far simpler for us to 89 formulate the SPN instead. */ 90 91 /* Generate our UTF8 based SPN */ 92 utf8_spn = aprintf("%s/%s", service, host); 93 if(!utf8_spn) 94 return NULL; 95 96 /* Allocate and return a TCHAR based SPN. Since curlx_convert_UTF8_to_tchar 97 must be freed by curlx_unicodefree we will dupe the result so that the 98 pointer this function returns can be normally free'd. */ 99 tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn); 100 free(utf8_spn); 101 if(!tchar_spn) 102 return NULL; 103 dupe_tchar_spn = _tcsdup(tchar_spn); 104 curlx_unicodefree(tchar_spn); 105 return dupe_tchar_spn; 106 } 107 #endif /* USE_WINDOWS_SSPI */ 108 109 /* 110 * Curl_auth_user_contains_domain() 111 * 112 * This is used to test if the specified user contains a Windows domain name as 113 * follows: 114 * 115 * Domain\User (Down-level Logon Name) 116 * Domain/User (curl Down-level format - for compatibility with existing code) 117 * User@Domain (User Principal Name) 118 * 119 * Note: The username may be empty when using a GSS-API library or Windows 120 * SSPI as the user and domain are either obtained from the credentials cache 121 * when using GSS-API or via the currently logged in user's credentials when 122 * using Windows SSPI. 123 * 124 * Parameters: 125 * 126 * user [in] - The username. 127 * 128 * Returns TRUE on success; otherwise FALSE. 129 */ 130 bool Curl_auth_user_contains_domain(const char *user) 131 { 132 bool valid = FALSE; 133 134 if(user && *user) { 135 /* Check we have a domain name or UPN present */ 136 char *p = strpbrk(user, "\\/@"); 137 138 valid = (p != NULL && p > user && p < user + strlen(user) - 1); 139 } 140 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) 141 else 142 /* User and domain are obtained from the GSS-API credentials cache or the 143 currently logged in user from Windows */ 144 valid = TRUE; 145 #endif 146 147 return valid; 148 } 149 150 /* 151 * Curl_auth_ollowed_to_host() tells if authentication, cookies or other 152 * "sensitive data" can (still) be sent to this host. 153 */ 154 bool Curl_auth_allowed_to_host(struct Curl_easy *data) 155 { 156 struct connectdata *conn = data->conn; 157 return !data->state.this_is_a_follow || 158 data->set.allow_auth_to_other_hosts || 159 (data->state.first_host && 160 curl_strequal(data->state.first_host, conn->host.name) && 161 (data->state.first_remote_port == conn->remote_port) && 162 (data->state.first_remote_protocol == conn->handler->protocol)); 163 } 164 165 #ifdef USE_NTLM 166 167 static void ntlm_conn_dtor(void *key, size_t klen, void *entry) 168 { 169 struct ntlmdata *ntlm = entry; 170 (void)key; 171 (void)klen; 172 DEBUGASSERT(ntlm); 173 Curl_auth_cleanup_ntlm(ntlm); 174 free(ntlm); 175 } 176 177 struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy) 178 { 179 const char *key = proxy ? CURL_META_NTLM_PROXY_CONN : 180 CURL_META_NTLM_CONN; 181 struct ntlmdata *ntlm = Curl_conn_meta_get(conn, key); 182 if(!ntlm) { 183 ntlm = calloc(1, sizeof(*ntlm)); 184 if(!ntlm || 185 Curl_conn_meta_set(conn, key, ntlm, ntlm_conn_dtor)) 186 return NULL; 187 } 188 return ntlm; 189 } 190 191 void Curl_auth_ntlm_remove(struct connectdata *conn, bool proxy) 192 { 193 Curl_conn_meta_remove(conn, proxy ? 194 CURL_META_NTLM_PROXY_CONN : CURL_META_NTLM_CONN); 195 } 196 197 #endif /* USE_NTLM */ 198 199 #ifdef USE_KERBEROS5 200 201 static void krb5_conn_dtor(void *key, size_t klen, void *entry) 202 { 203 struct kerberos5data *krb5 = entry; 204 (void)key; 205 (void)klen; 206 DEBUGASSERT(krb5); 207 Curl_auth_cleanup_gssapi(krb5); 208 free(krb5); 209 } 210 211 struct kerberos5data *Curl_auth_krb5_get(struct connectdata *conn) 212 { 213 struct kerberos5data *krb5 = Curl_conn_meta_get(conn, CURL_META_KRB5_CONN); 214 if(!krb5) { 215 krb5 = calloc(1, sizeof(*krb5)); 216 if(!krb5 || 217 Curl_conn_meta_set(conn, CURL_META_KRB5_CONN, krb5, krb5_conn_dtor)) 218 return NULL; 219 } 220 return krb5; 221 } 222 223 #endif /* USE_KERBEROS5 */ 224 225 #ifdef USE_GSASL 226 227 static void gsasl_conn_dtor(void *key, size_t klen, void *entry) 228 { 229 struct gsasldata *gsasl = entry; 230 (void)key; 231 (void)klen; 232 DEBUGASSERT(gsasl); 233 Curl_auth_gsasl_cleanup(gsasl); 234 free(gsasl); 235 } 236 237 struct gsasldata *Curl_auth_gsasl_get(struct connectdata *conn) 238 { 239 struct gsasldata *gsasl = Curl_conn_meta_get(conn, CURL_META_GSASL_CONN); 240 if(!gsasl) { 241 gsasl = calloc(1, sizeof(*gsasl)); 242 if(!gsasl || 243 Curl_conn_meta_set(conn, CURL_META_GSASL_CONN, gsasl, gsasl_conn_dtor)) 244 return NULL; 245 } 246 return gsasl; 247 } 248 249 #endif /* USE_GSASL */ 250 251 #ifdef USE_SPNEGO 252 253 static void nego_conn_dtor(void *key, size_t klen, void *entry) 254 { 255 struct negotiatedata *nego = entry; 256 (void)key; 257 (void)klen; 258 DEBUGASSERT(nego); 259 Curl_auth_cleanup_spnego(nego); 260 free(nego); 261 } 262 263 struct negotiatedata *Curl_auth_nego_get(struct connectdata *conn, bool proxy) 264 { 265 const char *key = proxy ? CURL_META_NEGO_PROXY_CONN : 266 CURL_META_NEGO_CONN; 267 struct negotiatedata *nego = Curl_conn_meta_get(conn, key); 268 if(!nego) { 269 nego = calloc(1, sizeof(*nego)); 270 if(!nego || 271 Curl_conn_meta_set(conn, key, nego, nego_conn_dtor)) 272 return NULL; 273 } 274 return nego; 275 } 276 277 #endif /* USE_SPNEGO */