Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/auth/gensec/gensec_util.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   Generic Authentication Interface
5
6
   Copyright (C) Andrew Tridgell 2003
7
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
8
9
   This program is free software; you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation; either version 3 of the License, or
12
   (at your option) any later version.
13
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
19
   You should have received a copy of the GNU General Public License
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
*/
22
23
#include "includes.h"
24
#include "auth/gensec/gensec.h"
25
#include "auth/gensec/gensec_internal.h"
26
#include "auth/credentials/credentials.h"
27
#include "auth/common_auth.h"
28
#include "../lib/util/asn1.h"
29
#include "param/param.h"
30
#include "libds/common/roles.h"
31
#include "lib/util/util_net.h"
32
33
#undef strcasecmp
34
35
#undef DBGC_CLASS
36
0
#define DBGC_CLASS DBGC_AUTH
37
38
NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx,
39
            struct gensec_security *gensec_security,
40
            struct smb_krb5_context *smb_krb5_context,
41
            DATA_BLOB *pac_blob,
42
            const char *principal_string,
43
            const struct tsocket_address *remote_address,
44
            struct auth_session_info **session_info)
45
0
{
46
0
  uint32_t session_info_flags = 0;
47
0
  struct auth4_context *auth_context = NULL;
48
0
  NTSTATUS status;
49
50
0
  if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) {
51
0
    session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
52
0
  }
53
54
0
  session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
55
56
0
  if (!pac_blob) {
57
0
    enum server_role server_role =
58
0
      lpcfg_server_role(gensec_security->settings->lp_ctx);
59
60
    /*
61
     * For any domain setup (DC or member) we require having
62
     * a PAC, as the service ticket comes from an AD DC,
63
     * which will always provide a PAC, unless
64
     * UF_NO_AUTH_DATA_REQUIRED is configured for our
65
     * account, but that's just an invalid configuration,
66
     * the admin configured for us!
67
     *
68
     * As a legacy case, we still allow kerberos tickets from an MIT
69
     * realm, but only in standalone mode. In that mode we'll only
70
     * ever accept a kerberos authentication with a keytab file
71
     * being explicitly configured via the 'keytab method' option.
72
     */
73
0
    if (server_role != ROLE_STANDALONE) {
74
0
      DBG_WARNING("Unable to find PAC in ticket from %s, "
75
0
            "failing to allow access\n",
76
0
            principal_string);
77
0
      return NT_STATUS_NO_IMPERSONATION_TOKEN;
78
0
    }
79
0
    DBG_NOTICE("Unable to find PAC for %s, resorting to local "
80
0
         "user lookup\n", principal_string);
81
0
  }
82
83
0
  auth_context = gensec_security->auth_context;
84
85
0
  if ((auth_context == NULL) ||
86
0
      (auth_context->generate_session_info_pac == NULL)) {
87
0
    DBG_ERR("Cannot generate a session_info without "
88
0
      "the auth_context\n");
89
0
    return NT_STATUS_INTERNAL_ERROR;
90
0
  }
91
92
0
  status = auth_context->generate_session_info_pac(
93
0
    auth_context,
94
0
    mem_ctx,
95
0
    smb_krb5_context,
96
0
    pac_blob,
97
0
    principal_string,
98
0
    remote_address,
99
0
    session_info_flags,
100
0
    session_info);
101
0
  return status;
102
0
}
103
104
/*
105
  magic check a GSS-API wrapper packet for an Kerberos OID
106
*/
107
static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid)
108
0
{
109
0
  bool ret = false;
110
0
  struct asn1_data *data = asn1_init(NULL, ASN1_MAX_TREE_DEPTH);
111
112
0
  if (!data) return false;
113
114
0
  if (!asn1_load(data, *blob)) goto err;
115
0
  if (!asn1_start_tag(data, ASN1_APPLICATION(0))) goto err;
116
0
  if (!asn1_check_OID(data, oid)) goto err;
117
118
0
  ret = !asn1_has_error(data);
119
120
0
  err:
121
122
0
  asn1_free(data);
123
0
  return ret;
124
0
}
125
126
/**
127
 * Check if the packet is one for the KRB5 mechanism
128
 *
129
 * NOTE: This is a helper that can be employed by multiple mechanisms, do
130
 * not make assumptions about the private_data
131
 *
132
 * @param gensec_security GENSEC state, unused
133
 * @param in The request, as a DATA_BLOB
134
 * @return Error, INVALID_PARAMETER if it's not a packet for us
135
 *                or NT_STATUS_OK if the packet is ok.
136
 */
137
138
NTSTATUS gensec_magic_check_krb5_oid(struct gensec_security *unused,
139
          const DATA_BLOB *blob)
140
0
{
141
0
  if (gensec_gssapi_check_oid(blob, GENSEC_OID_KERBEROS5)) {
142
0
    return NT_STATUS_OK;
143
0
  } else {
144
0
    return NT_STATUS_INVALID_PARAMETER;
145
0
  }
146
0
}
147
148
void gensec_child_want_feature(struct gensec_security *gensec_security,
149
             uint32_t feature)
150
0
{
151
0
  struct gensec_security *child_security = gensec_security->child_security;
152
153
0
  gensec_security->want_features |= feature;
154
0
  if (child_security == NULL) {
155
0
    return;
156
0
  }
157
0
  gensec_want_feature(child_security, feature);
158
0
}
159
160
bool gensec_child_have_feature(struct gensec_security *gensec_security,
161
             uint32_t feature)
162
0
{
163
0
  struct gensec_security *child_security = gensec_security->child_security;
164
165
0
  if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
166
    /*
167
     * All mechs with sub (child) mechs need to provide DCERPC
168
     * header signing! This is required because the negotiation
169
     * of header signing is done before the authentication
170
     * is completed.
171
     */
172
0
    return true;
173
0
  }
174
175
0
  if (child_security == NULL) {
176
0
    return false;
177
0
  }
178
179
0
  return gensec_have_feature(child_security, feature);
180
0
}
181
182
NTSTATUS gensec_child_unseal_packet(struct gensec_security *gensec_security,
183
            uint8_t *data, size_t length,
184
            const uint8_t *whole_pdu, size_t pdu_length,
185
            const DATA_BLOB *sig)
186
0
{
187
0
  if (gensec_security->child_security == NULL) {
188
0
    return NT_STATUS_INVALID_PARAMETER;
189
0
  }
190
191
0
  return gensec_unseal_packet(gensec_security->child_security,
192
0
            data, length,
193
0
            whole_pdu, pdu_length,
194
0
            sig);
195
0
}
196
197
NTSTATUS gensec_child_check_packet(struct gensec_security *gensec_security,
198
           const uint8_t *data, size_t length,
199
           const uint8_t *whole_pdu, size_t pdu_length,
200
           const DATA_BLOB *sig)
201
0
{
202
0
  if (gensec_security->child_security == NULL) {
203
0
    return NT_STATUS_INVALID_PARAMETER;
204
0
  }
205
206
0
  return gensec_check_packet(gensec_security->child_security,
207
0
           data, length,
208
0
           whole_pdu, pdu_length,
209
0
           sig);
210
0
}
211
212
NTSTATUS gensec_child_seal_packet(struct gensec_security *gensec_security,
213
          TALLOC_CTX *mem_ctx,
214
          uint8_t *data, size_t length,
215
          const uint8_t *whole_pdu, size_t pdu_length,
216
          DATA_BLOB *sig)
217
0
{
218
0
  if (gensec_security->child_security == NULL) {
219
0
    return NT_STATUS_INVALID_PARAMETER;
220
0
  }
221
222
0
  return gensec_seal_packet(gensec_security->child_security,
223
0
          mem_ctx,
224
0
          data, length,
225
0
          whole_pdu, pdu_length,
226
0
          sig);
227
0
}
228
229
NTSTATUS gensec_child_sign_packet(struct gensec_security *gensec_security,
230
          TALLOC_CTX *mem_ctx,
231
          const uint8_t *data, size_t length,
232
          const uint8_t *whole_pdu, size_t pdu_length,
233
          DATA_BLOB *sig)
234
0
{
235
0
  if (gensec_security->child_security == NULL) {
236
0
    return NT_STATUS_INVALID_PARAMETER;
237
0
  }
238
239
0
  return gensec_sign_packet(gensec_security->child_security,
240
0
          mem_ctx,
241
0
          data, length,
242
0
          whole_pdu, pdu_length,
243
0
          sig);
244
0
}
245
246
NTSTATUS gensec_child_wrap(struct gensec_security *gensec_security,
247
         TALLOC_CTX *mem_ctx,
248
         const DATA_BLOB *in,
249
         DATA_BLOB *out)
250
0
{
251
0
  if (gensec_security->child_security == NULL) {
252
0
    return NT_STATUS_INVALID_PARAMETER;
253
0
  }
254
255
0
  return gensec_wrap(gensec_security->child_security,
256
0
         mem_ctx, in, out);
257
0
}
258
259
NTSTATUS gensec_child_unwrap(struct gensec_security *gensec_security,
260
           TALLOC_CTX *mem_ctx,
261
           const DATA_BLOB *in,
262
           DATA_BLOB *out)
263
0
{
264
0
  if (gensec_security->child_security == NULL) {
265
0
    return NT_STATUS_INVALID_PARAMETER;
266
0
  }
267
268
0
  return gensec_unwrap(gensec_security->child_security,
269
0
           mem_ctx, in, out);
270
0
}
271
272
size_t gensec_child_sig_size(struct gensec_security *gensec_security,
273
           size_t data_size)
274
0
{
275
0
  if (gensec_security->child_security == NULL) {
276
0
    return 0;
277
0
  }
278
279
0
  return gensec_sig_size(gensec_security->child_security, data_size);
280
0
}
281
282
size_t gensec_child_max_input_size(struct gensec_security *gensec_security)
283
0
{
284
0
  if (gensec_security->child_security == NULL) {
285
0
    return 0;
286
0
  }
287
288
0
  return gensec_max_input_size(gensec_security->child_security);
289
0
}
290
291
size_t gensec_child_max_wrapped_size(struct gensec_security *gensec_security)
292
0
{
293
0
  if (gensec_security->child_security == NULL) {
294
0
    return 0;
295
0
  }
296
297
0
  return gensec_max_wrapped_size(gensec_security->child_security);
298
0
}
299
300
NTSTATUS gensec_child_session_key(struct gensec_security *gensec_security,
301
          TALLOC_CTX *mem_ctx,
302
          DATA_BLOB *session_key)
303
0
{
304
0
  if (gensec_security->child_security == NULL) {
305
0
    return NT_STATUS_INVALID_PARAMETER;
306
0
  }
307
308
0
  return gensec_session_key(gensec_security->child_security,
309
0
          mem_ctx,
310
0
          session_key);
311
0
}
312
313
NTSTATUS gensec_child_session_info(struct gensec_security *gensec_security,
314
           TALLOC_CTX *mem_ctx,
315
           struct auth_session_info **session_info)
316
0
{
317
0
  if (gensec_security->child_security == NULL) {
318
0
    return NT_STATUS_INVALID_PARAMETER;
319
0
  }
320
321
0
  return gensec_session_info(gensec_security->child_security,
322
0
           mem_ctx,
323
0
           session_info);
324
0
}
325
326
NTTIME gensec_child_expire_time(struct gensec_security *gensec_security)
327
0
{
328
0
  if (gensec_security->child_security == NULL) {
329
0
    return GENSEC_EXPIRE_TIME_INFINITY;
330
0
  }
331
332
0
  return gensec_expire_time(gensec_security->child_security);
333
0
}
334
335
const char *gensec_child_final_auth_type(struct gensec_security *gensec_security)
336
0
{
337
0
  if (gensec_security->child_security == NULL) {
338
0
    return "NONE";
339
0
  }
340
341
0
  return gensec_final_auth_type(gensec_security->child_security);
342
0
}
343
344
char *gensec_get_unparsed_target_principal(struct gensec_security *gensec_security,
345
             TALLOC_CTX *mem_ctx)
346
0
{
347
0
  const char *target_principal = gensec_get_target_principal(gensec_security);
348
0
  const char *service = gensec_get_target_service(gensec_security);
349
0
  const char *hostname = gensec_get_target_hostname(gensec_security);
350
351
0
  if (target_principal != NULL) {
352
0
    return talloc_strdup(mem_ctx, target_principal);
353
0
  } else if (service != NULL && hostname != NULL) {
354
0
    return talloc_asprintf(mem_ctx, "%s/%s", service, hostname);
355
0
  } else if (hostname != NULL) {
356
0
    return talloc_strdup(mem_ctx, target_principal);
357
0
  }
358
359
0
  return NULL;
360
0
}
361
362
NTSTATUS gensec_kerberos_possible(struct gensec_security *gensec_security)
363
0
{
364
0
  struct cli_credentials *creds = gensec_get_credentials(gensec_security);
365
0
  bool auth_requested = cli_credentials_authentication_requested(creds);
366
0
  enum credentials_use_kerberos krb5_state =
367
0
    cli_credentials_get_kerberos_state(creds);
368
0
  char *user_principal = NULL;
369
0
  const char *client_realm = cli_credentials_get_realm(creds);
370
0
  const char *target_principal = gensec_get_target_principal(gensec_security);
371
0
  const char *hostname = gensec_get_target_hostname(gensec_security);
372
373
0
  if (!auth_requested) {
374
0
    return NT_STATUS_INVALID_PARAMETER;
375
0
  }
376
377
0
  if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
378
0
    return NT_STATUS_INVALID_PARAMETER;
379
0
  }
380
381
0
  errno = 0;
382
0
  user_principal = cli_credentials_get_principal(creds, gensec_security);
383
0
  if (errno != 0) {
384
0
    TALLOC_FREE(user_principal);
385
0
    return NT_STATUS_NO_MEMORY;
386
0
  }
387
388
0
  if (user_principal == NULL) {
389
0
    return NT_STATUS_INVALID_PARAMETER;
390
0
  }
391
0
  TALLOC_FREE(user_principal);
392
393
0
  if (target_principal != NULL) {
394
0
    return NT_STATUS_OK;
395
0
  }
396
397
0
  if (client_realm == NULL) {
398
0
    return NT_STATUS_INVALID_PARAMETER;
399
0
  }
400
401
0
  if (hostname == NULL) {
402
0
    return NT_STATUS_INVALID_PARAMETER;
403
0
  }
404
405
0
  if (strcasecmp(hostname, "localhost") == 0) {
406
0
    return NT_STATUS_INVALID_PARAMETER;
407
0
  }
408
409
0
#define STAR_SMBSERVER "*SMBSERVER"
410
0
  if (strcmp(hostname, STAR_SMBSERVER) == 0) {
411
0
    return NT_STATUS_INVALID_PARAMETER;
412
0
  }
413
414
0
  if (is_ipaddress(hostname)) {
415
0
    return NT_STATUS_INVALID_PARAMETER;
416
0
  }
417
418
0
  return NT_STATUS_OK;
419
0
}