113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "curl_setup.h"
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#include <curl/curl.h>
2813498266Sopenharmony_ci
2913498266Sopenharmony_ci#include "vauth.h"
3013498266Sopenharmony_ci#include "urldata.h"
3113498266Sopenharmony_ci#include "strcase.h"
3213498266Sopenharmony_ci#include "curl_multibyte.h"
3313498266Sopenharmony_ci#include "curl_printf.h"
3413498266Sopenharmony_ci
3513498266Sopenharmony_ci/* The last #include files should be: */
3613498266Sopenharmony_ci#include "curl_memory.h"
3713498266Sopenharmony_ci#include "memdebug.h"
3813498266Sopenharmony_ci
3913498266Sopenharmony_ci/*
4013498266Sopenharmony_ci * Curl_auth_build_spn()
4113498266Sopenharmony_ci *
4213498266Sopenharmony_ci * This is used to build a SPN string in the following formats:
4313498266Sopenharmony_ci *
4413498266Sopenharmony_ci * service/host@realm (Not currently used)
4513498266Sopenharmony_ci * service/host       (Not used by GSS-API)
4613498266Sopenharmony_ci * service@realm      (Not used by Windows SSPI)
4713498266Sopenharmony_ci *
4813498266Sopenharmony_ci * Parameters:
4913498266Sopenharmony_ci *
5013498266Sopenharmony_ci * service  [in] - The service type such as http, smtp, pop or imap.
5113498266Sopenharmony_ci * host     [in] - The host name.
5213498266Sopenharmony_ci * realm    [in] - The realm.
5313498266Sopenharmony_ci *
5413498266Sopenharmony_ci * Returns a pointer to the newly allocated SPN.
5513498266Sopenharmony_ci */
5613498266Sopenharmony_ci#if !defined(USE_WINDOWS_SSPI)
5713498266Sopenharmony_cichar *Curl_auth_build_spn(const char *service, const char *host,
5813498266Sopenharmony_ci                          const char *realm)
5913498266Sopenharmony_ci{
6013498266Sopenharmony_ci  char *spn = NULL;
6113498266Sopenharmony_ci
6213498266Sopenharmony_ci  /* Generate our SPN */
6313498266Sopenharmony_ci  if(host && realm)
6413498266Sopenharmony_ci    spn = aprintf("%s/%s@%s", service, host, realm);
6513498266Sopenharmony_ci  else if(host)
6613498266Sopenharmony_ci    spn = aprintf("%s/%s", service, host);
6713498266Sopenharmony_ci  else if(realm)
6813498266Sopenharmony_ci    spn = aprintf("%s@%s", service, realm);
6913498266Sopenharmony_ci
7013498266Sopenharmony_ci  /* Return our newly allocated SPN */
7113498266Sopenharmony_ci  return spn;
7213498266Sopenharmony_ci}
7313498266Sopenharmony_ci#else
7413498266Sopenharmony_ciTCHAR *Curl_auth_build_spn(const char *service, const char *host,
7513498266Sopenharmony_ci                           const char *realm)
7613498266Sopenharmony_ci{
7713498266Sopenharmony_ci  char *utf8_spn = NULL;
7813498266Sopenharmony_ci  TCHAR *tchar_spn = NULL;
7913498266Sopenharmony_ci  TCHAR *dupe_tchar_spn = NULL;
8013498266Sopenharmony_ci
8113498266Sopenharmony_ci  (void) realm;
8213498266Sopenharmony_ci
8313498266Sopenharmony_ci  /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather
8413498266Sopenharmony_ci     than doing this ourselves but the first is only available in Windows XP
8513498266Sopenharmony_ci     and Windows Server 2003 and the latter is only available in Windows 2000
8613498266Sopenharmony_ci     but not Windows95/98/ME or Windows NT4.0 unless the Active Directory
8713498266Sopenharmony_ci     Client Extensions are installed. As such it is far simpler for us to
8813498266Sopenharmony_ci     formulate the SPN instead. */
8913498266Sopenharmony_ci
9013498266Sopenharmony_ci  /* Generate our UTF8 based SPN */
9113498266Sopenharmony_ci  utf8_spn = aprintf("%s/%s", service, host);
9213498266Sopenharmony_ci  if(!utf8_spn)
9313498266Sopenharmony_ci    return NULL;
9413498266Sopenharmony_ci
9513498266Sopenharmony_ci  /* Allocate and return a TCHAR based SPN. Since curlx_convert_UTF8_to_tchar
9613498266Sopenharmony_ci     must be freed by curlx_unicodefree we'll dupe the result so that the
9713498266Sopenharmony_ci     pointer this function returns can be normally free'd. */
9813498266Sopenharmony_ci  tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn);
9913498266Sopenharmony_ci  free(utf8_spn);
10013498266Sopenharmony_ci  if(!tchar_spn)
10113498266Sopenharmony_ci    return NULL;
10213498266Sopenharmony_ci  dupe_tchar_spn = _tcsdup(tchar_spn);
10313498266Sopenharmony_ci  curlx_unicodefree(tchar_spn);
10413498266Sopenharmony_ci  return dupe_tchar_spn;
10513498266Sopenharmony_ci}
10613498266Sopenharmony_ci#endif /* USE_WINDOWS_SSPI */
10713498266Sopenharmony_ci
10813498266Sopenharmony_ci/*
10913498266Sopenharmony_ci * Curl_auth_user_contains_domain()
11013498266Sopenharmony_ci *
11113498266Sopenharmony_ci * This is used to test if the specified user contains a Windows domain name as
11213498266Sopenharmony_ci * follows:
11313498266Sopenharmony_ci *
11413498266Sopenharmony_ci * Domain\User (Down-level Logon Name)
11513498266Sopenharmony_ci * Domain/User (curl Down-level format - for compatibility with existing code)
11613498266Sopenharmony_ci * User@Domain (User Principal Name)
11713498266Sopenharmony_ci *
11813498266Sopenharmony_ci * Note: The user name may be empty when using a GSS-API library or Windows
11913498266Sopenharmony_ci * SSPI as the user and domain are either obtained from the credentials cache
12013498266Sopenharmony_ci * when using GSS-API or via the currently logged in user's credentials when
12113498266Sopenharmony_ci * using Windows SSPI.
12213498266Sopenharmony_ci *
12313498266Sopenharmony_ci * Parameters:
12413498266Sopenharmony_ci *
12513498266Sopenharmony_ci * user  [in] - The user name.
12613498266Sopenharmony_ci *
12713498266Sopenharmony_ci * Returns TRUE on success; otherwise FALSE.
12813498266Sopenharmony_ci */
12913498266Sopenharmony_cibool Curl_auth_user_contains_domain(const char *user)
13013498266Sopenharmony_ci{
13113498266Sopenharmony_ci  bool valid = FALSE;
13213498266Sopenharmony_ci
13313498266Sopenharmony_ci  if(user && *user) {
13413498266Sopenharmony_ci    /* Check we have a domain name or UPN present */
13513498266Sopenharmony_ci    char *p = strpbrk(user, "\\/@");
13613498266Sopenharmony_ci
13713498266Sopenharmony_ci    valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE :
13813498266Sopenharmony_ci                                                                    FALSE);
13913498266Sopenharmony_ci  }
14013498266Sopenharmony_ci#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
14113498266Sopenharmony_ci  else
14213498266Sopenharmony_ci    /* User and domain are obtained from the GSS-API credentials cache or the
14313498266Sopenharmony_ci       currently logged in user from Windows */
14413498266Sopenharmony_ci    valid = TRUE;
14513498266Sopenharmony_ci#endif
14613498266Sopenharmony_ci
14713498266Sopenharmony_ci  return valid;
14813498266Sopenharmony_ci}
14913498266Sopenharmony_ci
15013498266Sopenharmony_ci/*
15113498266Sopenharmony_ci * Curl_auth_ollowed_to_host() tells if authentication, cookies or other
15213498266Sopenharmony_ci * "sensitive data" can (still) be sent to this host.
15313498266Sopenharmony_ci */
15413498266Sopenharmony_cibool Curl_auth_allowed_to_host(struct Curl_easy *data)
15513498266Sopenharmony_ci{
15613498266Sopenharmony_ci  struct connectdata *conn = data->conn;
15713498266Sopenharmony_ci  return (!data->state.this_is_a_follow ||
15813498266Sopenharmony_ci          data->set.allow_auth_to_other_hosts ||
15913498266Sopenharmony_ci          (data->state.first_host &&
16013498266Sopenharmony_ci           strcasecompare(data->state.first_host, conn->host.name) &&
16113498266Sopenharmony_ci           (data->state.first_remote_port == conn->remote_port) &&
16213498266Sopenharmony_ci           (data->state.first_remote_protocol == conn->handler->protocol)));
16313498266Sopenharmony_ci}
164