Coverage Report

Created: 2026-06-01 07:00

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