Coverage Report

Created: 2025-07-11 06:33

/src/PROJ/curl/lib/vauth/vauth.c
Line
Count
Source (jump to first uncovered line)
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
0
{
61
0
  char *spn = NULL;
62
63
  /* Generate our SPN */
64
0
  if(host && realm)
65
0
    spn = aprintf("%s/%s@%s", service, host, realm);
66
0
  else if(host)
67
0
    spn = aprintf("%s/%s", service, host);
68
0
  else if(realm)
69
0
    spn = aprintf("%s@%s", service, realm);
70
71
  /* Return our newly allocated SPN */
72
0
  return spn;
73
0
}
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
0
{
132
0
  bool valid = FALSE;
133
134
0
  if(user && *user) {
135
    /* Check we have a domain name or UPN present */
136
0
    char *p = strpbrk(user, "\\/@");
137
138
0
    valid = (p != NULL && p > user && p < user + strlen(user) - 1);
139
0
  }
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
0
  return valid;
148
0
}
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
0
{
156
0
  struct connectdata *conn = data->conn;
157
0
  return !data->state.this_is_a_follow ||
158
0
         data->set.allow_auth_to_other_hosts ||
159
0
         (data->state.first_host &&
160
0
          curl_strequal(data->state.first_host, conn->host.name) &&
161
0
          (data->state.first_remote_port == conn->remote_port) &&
162
0
          (data->state.first_remote_protocol == conn->handler->protocol));
163
0
}
164
165
#ifdef USE_NTLM
166
167
static void ntlm_conn_dtor(void *key, size_t klen, void *entry)
168
0
{
169
0
  struct ntlmdata *ntlm = entry;
170
0
  (void)key;
171
0
  (void)klen;
172
0
  DEBUGASSERT(ntlm);
173
0
  Curl_auth_cleanup_ntlm(ntlm);
174
0
  free(ntlm);
175
0
}
176
177
struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy)
178
0
{
179
0
  const char *key = proxy ? CURL_META_NTLM_PROXY_CONN :
180
0
                    CURL_META_NTLM_CONN;
181
0
  struct ntlmdata *ntlm = Curl_conn_meta_get(conn, key);
182
0
  if(!ntlm) {
183
0
    ntlm = calloc(1, sizeof(*ntlm));
184
0
    if(!ntlm ||
185
0
       Curl_conn_meta_set(conn, key, ntlm, ntlm_conn_dtor))
186
0
      return NULL;
187
0
  }
188
0
  return ntlm;
189
0
}
190
191
void Curl_auth_ntlm_remove(struct connectdata *conn, bool proxy)
192
0
{
193
0
  Curl_conn_meta_remove(conn, proxy ?
194
0
    CURL_META_NTLM_PROXY_CONN : CURL_META_NTLM_CONN);
195
0
}
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 */