2
Unix SMB/CIFS implementation.
4
Generic Authentication Interface
6
Copyright (C) Andrew Tridgell 2003
7
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
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.
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.
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/>.
24
#include "auth/auth.h"
25
#include "lib/events/events.h"
26
#include "librpc/rpc/dcerpc.h"
27
#include "auth/credentials/credentials.h"
28
#include "auth/gensec/gensec.h"
29
#include "auth/gensec/gensec_proto.h"
30
#include "param/param.h"
32
/* the list of currently registered GENSEC backends */
33
static struct gensec_security_ops **generic_security_ops;
34
static int gensec_num_backends;
36
/* Return all the registered mechs. Don't modify the return pointer,
37
* but you may talloc_reference it if convient */
38
_PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
40
return generic_security_ops;
43
bool gensec_security_ops_enabled(struct gensec_security_ops *ops,
44
struct loadparm_context *lp_ctx)
46
return lp_parm_bool(lp_ctx, NULL, "gensec", ops->name, ops->enabled);
49
/* Sometimes we want to force only kerberos, sometimes we want to
50
* force it's avoidance. The old list could be either
51
* gensec_security_all(), or from cli_credentials_gensec_list() (ie,
52
* an existing list we have trimmed down) */
54
_PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
55
struct gensec_security_ops **old_gensec_list,
56
struct cli_credentials *creds)
58
struct gensec_security_ops **new_gensec_list;
59
int i, j, num_mechs_in;
60
enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
63
use_kerberos = cli_credentials_get_kerberos_state(creds);
66
if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
67
if (!talloc_reference(mem_ctx, old_gensec_list)) {
70
return old_gensec_list;
73
for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
77
new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
78
if (!new_gensec_list) {
83
for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
86
for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
87
if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
88
new_gensec_list[j] = old_gensec_list[i];
93
switch (use_kerberos) {
94
case CRED_DONT_USE_KERBEROS:
95
if (old_gensec_list[i]->kerberos == false) {
96
new_gensec_list[j] = old_gensec_list[i];
100
case CRED_MUST_USE_KERBEROS:
101
if (old_gensec_list[i]->kerberos == true) {
102
new_gensec_list[j] = old_gensec_list[i];
107
/* Can't happen or invalid parameter */
111
new_gensec_list[j] = NULL;
113
return new_gensec_list;
116
struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
119
struct gensec_security_ops **backends;
120
backends = gensec_security_all();
121
if (!gensec_security) {
122
if (!talloc_reference(mem_ctx, backends)) {
127
struct cli_credentials *creds = gensec_get_credentials(gensec_security);
129
if (!talloc_reference(mem_ctx, backends)) {
134
return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
138
static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
142
struct gensec_security_ops **backends;
143
const struct gensec_security_ops *backend;
144
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
148
backends = gensec_security_mechs(gensec_security, mem_ctx);
149
for (i=0; backends && backends[i]; i++) {
150
if (!gensec_security_ops_enabled(backends[i],
151
gensec_security->settings->lp_ctx))
153
if (backends[i]->auth_type == auth_type) {
154
backend = backends[i];
155
talloc_free(mem_ctx);
159
talloc_free(mem_ctx);
164
const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
165
const char *oid_string)
168
struct gensec_security_ops **backends;
169
const struct gensec_security_ops *backend;
170
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
174
backends = gensec_security_mechs(gensec_security, mem_ctx);
175
for (i=0; backends && backends[i]; i++) {
176
if (gensec_security != NULL &&
177
!gensec_security_ops_enabled(backends[i],
178
gensec_security->settings->lp_ctx))
180
if (backends[i]->oid) {
181
for (j=0; backends[i]->oid[j]; j++) {
182
if (backends[i]->oid[j] &&
183
(strcmp(backends[i]->oid[j], oid_string) == 0)) {
184
backend = backends[i];
185
talloc_free(mem_ctx);
191
talloc_free(mem_ctx);
196
const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
197
const char *sasl_name)
200
struct gensec_security_ops **backends;
201
const struct gensec_security_ops *backend;
202
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
206
backends = gensec_security_mechs(gensec_security, mem_ctx);
207
for (i=0; backends && backends[i]; i++) {
208
if (!gensec_security_ops_enabled(backends[i], gensec_security->settings->lp_ctx))
210
if (backends[i]->sasl_name
211
&& (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
212
backend = backends[i];
213
talloc_free(mem_ctx);
217
talloc_free(mem_ctx);
222
static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
226
struct gensec_security_ops **backends;
227
const struct gensec_security_ops *backend;
228
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
232
backends = gensec_security_mechs(gensec_security, mem_ctx);
233
for (i=0; backends && backends[i]; i++) {
234
if (gensec_security != NULL &&
235
!gensec_security_ops_enabled(backends[i], gensec_security->settings->lp_ctx))
237
if (backends[i]->name
238
&& (strcmp(backends[i]->name, name) == 0)) {
239
backend = backends[i];
240
talloc_free(mem_ctx);
244
talloc_free(mem_ctx);
249
* Return a unique list of security subsystems from those specified in
250
* the list of SASL names.
252
* Use the list of enabled GENSEC mechanisms from the credentials
253
* attached to the gensec_security, and return in our preferred order.
256
const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
258
const char **sasl_names)
260
const struct gensec_security_ops **backends_out;
261
struct gensec_security_ops **backends;
263
int num_backends_out = 0;
269
backends = gensec_security_mechs(gensec_security, mem_ctx);
271
backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
275
backends_out[0] = NULL;
277
/* Find backends in our preferred order, by walking our list,
278
* then looking in the supplied list */
279
for (i=0; backends && backends[i]; i++) {
280
if (gensec_security != NULL &&
281
!gensec_security_ops_enabled(backends[i], gensec_security->settings->lp_ctx))
283
for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
284
if (!backends[i]->sasl_name ||
285
!(strcmp(backends[i]->sasl_name,
286
sasl_names[sasl_idx]) == 0)) {
290
for (k=0; backends_out[k]; k++) {
291
if (backends_out[k] == backends[i]) {
296
if (k < num_backends_out) {
297
/* already in there */
301
backends_out = talloc_realloc(mem_ctx, backends_out,
302
const struct gensec_security_ops *,
303
num_backends_out + 2);
308
backends_out[num_backends_out] = backends[i];
310
backends_out[num_backends_out] = NULL;
317
* Return a unique list of security subsystems from those specified in
318
* the OID list. That is, where two OIDs refer to the same module,
319
* return that module only once.
321
* Use the list of enabled GENSEC mechanisms from the credentials
322
* attached to the gensec_security, and return in our preferred order.
325
const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
327
const char **oid_strings,
330
struct gensec_security_ops_wrapper *backends_out;
331
struct gensec_security_ops **backends;
332
int i, j, k, oid_idx;
333
int num_backends_out = 0;
339
backends = gensec_security_mechs(gensec_security, gensec_security);
341
backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
345
backends_out[0].op = NULL;
346
backends_out[0].oid = NULL;
348
/* Find backends in our preferred order, by walking our list,
349
* then looking in the supplied list */
350
for (i=0; backends && backends[i]; i++) {
351
if (gensec_security != NULL &&
352
!gensec_security_ops_enabled(backends[i], gensec_security->settings->lp_ctx))
354
if (!backends[i]->oid) {
357
for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
358
if (strcmp(oid_strings[oid_idx], skip) == 0) {
362
for (j=0; backends[i]->oid[j]; j++) {
363
if (!backends[i]->oid[j] ||
364
!(strcmp(backends[i]->oid[j],
365
oid_strings[oid_idx]) == 0)) {
369
for (k=0; backends_out[k].op; k++) {
370
if (backends_out[k].op == backends[i]) {
375
if (k < num_backends_out) {
376
/* already in there */
380
backends_out = talloc_realloc(mem_ctx, backends_out,
381
struct gensec_security_ops_wrapper,
382
num_backends_out + 2);
387
backends_out[num_backends_out].op = backends[i];
388
backends_out[num_backends_out].oid = backends[i]->oid[j];
390
backends_out[num_backends_out].op = NULL;
391
backends_out[num_backends_out].oid = NULL;
399
* Return OIDS from the security subsystems listed
402
const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security,
404
struct gensec_security_ops **ops,
410
const char **oid_list;
414
oid_list = talloc_array(mem_ctx, const char *, 1);
419
for (i=0; ops && ops[i]; i++) {
420
if (gensec_security != NULL &&
421
!gensec_security_ops_enabled(ops[i], gensec_security->settings->lp_ctx)) {
428
for (k = 0; ops[i]->oid[k]; k++) {
429
if (skip && strcmp(skip, ops[i]->oid[k])==0) {
431
oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
435
oid_list[j] = ops[i]->oid[k];
446
* Return OIDS from the security subsystems listed
449
const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
450
const struct gensec_security_ops_wrapper *wops)
455
const char **oid_list;
459
oid_list = talloc_array(mem_ctx, const char *, 1);
464
for (i=0; wops[i].op; i++) {
465
if (!wops[i].op->oid) {
469
for (k = 0; wops[i].op->oid[k]; k++) {
470
oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
474
oid_list[j] = wops[i].op->oid[k];
484
* Return all the security subsystems currently enabled on a GENSEC context.
486
* This is taken from a list attached to the cli_credentials, and
487
* skips the OID in 'skip'. (Typically the SPNEGO OID)
491
const char **gensec_security_oids(struct gensec_security *gensec_security,
495
struct gensec_security_ops **ops
496
= gensec_security_mechs(gensec_security, mem_ctx);
497
return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
503
Start the GENSEC system, returning a context pointer.
504
@param mem_ctx The parent TALLOC memory context.
505
@param gensec_security Returned GENSEC context pointer.
506
@note The mem_ctx is only a parent and may be NULL.
508
static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
509
struct tevent_context *ev,
510
struct gensec_settings *settings,
511
struct auth_context *auth_context,
512
struct gensec_security **gensec_security)
515
DEBUG(0, ("No event context available!\n"));
516
return NT_STATUS_INTERNAL_ERROR;
519
(*gensec_security) = talloc(mem_ctx, struct gensec_security);
520
NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
522
(*gensec_security)->ops = NULL;
523
(*gensec_security)->private_data = NULL;
525
ZERO_STRUCT((*gensec_security)->target);
526
ZERO_STRUCT((*gensec_security)->peer_addr);
527
ZERO_STRUCT((*gensec_security)->my_addr);
529
(*gensec_security)->subcontext = false;
530
(*gensec_security)->want_features = 0;
532
(*gensec_security)->event_ctx = ev;
533
SMB_ASSERT(settings->lp_ctx != NULL);
534
(*gensec_security)->settings = talloc_reference(*gensec_security, settings);
535
(*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
541
* Start a GENSEC subcontext, with a copy of the properties of the parent
542
* @param mem_ctx The parent TALLOC memory context.
543
* @param parent The parent GENSEC context
544
* @param gensec_security Returned GENSEC context pointer.
545
* @note Used by SPNEGO in particular, for the actual implementation mechanism
548
_PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
549
struct gensec_security *parent,
550
struct gensec_security **gensec_security)
552
(*gensec_security) = talloc(mem_ctx, struct gensec_security);
553
NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
555
(**gensec_security) = *parent;
556
(*gensec_security)->ops = NULL;
557
(*gensec_security)->private_data = NULL;
559
(*gensec_security)->subcontext = true;
560
(*gensec_security)->want_features = parent->want_features;
561
(*gensec_security)->event_ctx = parent->event_ctx;
562
(*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
563
(*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
564
(*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
570
Start the GENSEC system, in client mode, returning a context pointer.
571
@param mem_ctx The parent TALLOC memory context.
572
@param gensec_security Returned GENSEC context pointer.
573
@note The mem_ctx is only a parent and may be NULL.
575
_PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
576
struct gensec_security **gensec_security,
577
struct tevent_context *ev,
578
struct gensec_settings *settings)
582
if (settings == NULL) {
583
DEBUG(0,("gensec_client_start: no settings given!\n"));
584
return NT_STATUS_INTERNAL_ERROR;
587
status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security);
588
if (!NT_STATUS_IS_OK(status)) {
591
(*gensec_security)->gensec_role = GENSEC_CLIENT;
597
Start the GENSEC system, in server mode, returning a context pointer.
598
@param mem_ctx The parent TALLOC memory context.
599
@param gensec_security Returned GENSEC context pointer.
600
@note The mem_ctx is only a parent and may be NULL.
602
_PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
603
struct tevent_context *ev,
604
struct gensec_settings *settings,
605
struct auth_context *auth_context,
606
struct gensec_security **gensec_security)
611
DEBUG(0,("gensec_server_start: no event context given!\n"));
612
return NT_STATUS_INTERNAL_ERROR;
616
DEBUG(0,("gensec_server_start: no settings given!\n"));
617
return NT_STATUS_INTERNAL_ERROR;
620
status = gensec_start(mem_ctx, ev, settings, auth_context, gensec_security);
621
if (!NT_STATUS_IS_OK(status)) {
624
(*gensec_security)->gensec_role = GENSEC_SERVER;
629
static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
632
DEBUG(5, ("Starting GENSEC %smechanism %s\n",
633
gensec_security->subcontext ? "sub" : "",
634
gensec_security->ops->name));
635
switch (gensec_security->gensec_role) {
637
if (gensec_security->ops->client_start) {
638
status = gensec_security->ops->client_start(gensec_security);
639
if (!NT_STATUS_IS_OK(status)) {
640
DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
641
gensec_security->ops->name, nt_errstr(status)));
647
if (gensec_security->ops->server_start) {
648
status = gensec_security->ops->server_start(gensec_security);
649
if (!NT_STATUS_IS_OK(status)) {
650
DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
651
gensec_security->ops->name, nt_errstr(status)));
657
return NT_STATUS_INVALID_PARAMETER;
661
* Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
662
* @param gensec_security GENSEC context pointer.
663
* @param auth_type DCERPC auth type
664
* @param auth_level DCERPC auth level
667
_PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
668
uint8_t auth_type, uint8_t auth_level)
670
gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
671
if (!gensec_security->ops) {
672
DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
673
return NT_STATUS_INVALID_PARAMETER;
675
gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
676
gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
677
if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
678
gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
679
} else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
680
gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
681
gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
682
} else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
683
/* Default features */
685
DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
687
return NT_STATUS_INVALID_PARAMETER;
690
return gensec_start_mech(gensec_security);
693
_PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
695
const struct gensec_security_ops *ops;
696
ops = gensec_security_by_authtype(gensec_security, authtype);
704
_PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
705
const char *oid_string)
707
const struct gensec_security_ops *ops;
708
ops = gensec_security_by_oid(gensec_security, oid_string);
717
* Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
721
NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
722
const struct gensec_security_ops *ops)
724
gensec_security->ops = ops;
725
return gensec_start_mech(gensec_security);
729
* Start a GENSEC sub-mechanism by OID, used in SPNEGO
731
* @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
732
* well-known #define to hook it in.
735
_PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
736
const char *mech_oid)
738
SMB_ASSERT(gensec_security != NULL);
740
gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
741
if (!gensec_security->ops) {
742
DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
743
return NT_STATUS_INVALID_PARAMETER;
745
return gensec_start_mech(gensec_security);
749
* Start a GENSEC sub-mechanism by a well know SASL name
753
_PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
754
const char *sasl_name)
756
gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
757
if (!gensec_security->ops) {
758
DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
759
return NT_STATUS_INVALID_PARAMETER;
761
return gensec_start_mech(gensec_security);
765
* Start a GENSEC sub-mechanism with the preferred option from a SASL name list
769
_PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
770
const char **sasl_names)
772
NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
773
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
774
const struct gensec_security_ops **ops;
777
return NT_STATUS_NO_MEMORY;
779
ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
781
DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
782
str_list_join(mem_ctx,
784
talloc_free(mem_ctx);
785
return NT_STATUS_INVALID_PARAMETER;
787
for (i=0; ops[i]; i++) {
788
nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
789
if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
793
talloc_free(mem_ctx);
798
* Start a GENSEC sub-mechanism by an internal name
802
_PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
805
gensec_security->ops = gensec_security_by_name(gensec_security, name);
806
if (!gensec_security->ops) {
807
DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
808
return NT_STATUS_INVALID_PARAMETER;
810
return gensec_start_mech(gensec_security);
814
wrappers for the gensec function pointers
816
_PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
818
uint8_t *data, size_t length,
819
const uint8_t *whole_pdu, size_t pdu_length,
820
const DATA_BLOB *sig)
822
if (!gensec_security->ops->unseal_packet) {
823
return NT_STATUS_NOT_IMPLEMENTED;
825
if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
826
return NT_STATUS_INVALID_PARAMETER;
829
return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
831
whole_pdu, pdu_length,
835
_PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
837
const uint8_t *data, size_t length,
838
const uint8_t *whole_pdu, size_t pdu_length,
839
const DATA_BLOB *sig)
841
if (!gensec_security->ops->check_packet) {
842
return NT_STATUS_NOT_IMPLEMENTED;
844
if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
845
return NT_STATUS_INVALID_PARAMETER;
848
return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
851
_PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
853
uint8_t *data, size_t length,
854
const uint8_t *whole_pdu, size_t pdu_length,
857
if (!gensec_security->ops->seal_packet) {
858
return NT_STATUS_NOT_IMPLEMENTED;
860
if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
861
return NT_STATUS_INVALID_PARAMETER;
864
return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
867
_PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
869
const uint8_t *data, size_t length,
870
const uint8_t *whole_pdu, size_t pdu_length,
873
if (!gensec_security->ops->sign_packet) {
874
return NT_STATUS_NOT_IMPLEMENTED;
876
if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
877
return NT_STATUS_INVALID_PARAMETER;
880
return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
883
_PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
885
if (!gensec_security->ops->sig_size) {
888
if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
892
return gensec_security->ops->sig_size(gensec_security, data_size);
895
size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
897
if (!gensec_security->ops->max_wrapped_size) {
901
return gensec_security->ops->max_wrapped_size(gensec_security);
904
size_t gensec_max_input_size(struct gensec_security *gensec_security)
906
if (!gensec_security->ops->max_input_size) {
907
return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
910
return gensec_security->ops->max_input_size(gensec_security);
913
_PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
918
if (!gensec_security->ops->wrap) {
919
return NT_STATUS_NOT_IMPLEMENTED;
921
return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
924
_PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
929
if (!gensec_security->ops->unwrap) {
930
return NT_STATUS_NOT_IMPLEMENTED;
932
return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
935
_PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
936
DATA_BLOB *session_key)
938
if (!gensec_security->ops->session_key) {
939
return NT_STATUS_NOT_IMPLEMENTED;
941
if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
942
return NT_STATUS_NO_USER_SESSION_KEY;
945
return gensec_security->ops->session_key(gensec_security, session_key);
949
* Return the credentials of a logged on user, including session keys
952
* Only valid after a successful authentication
954
* May only be called once per authentication.
958
_PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
959
struct auth_session_info **session_info)
961
if (!gensec_security->ops->session_info) {
962
return NT_STATUS_NOT_IMPLEMENTED;
964
return gensec_security->ops->session_info(gensec_security, session_info);
968
* Next state function for the GENSEC state machine
970
* @param gensec_security GENSEC State
971
* @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
972
* @param in The request, as a DATA_BLOB
973
* @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
974
* @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
975
* or NT_STATUS_OK if the user is authenticated.
978
_PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
979
const DATA_BLOB in, DATA_BLOB *out)
981
return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
984
static void gensec_update_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te,
985
struct timeval t, void *ptr)
987
struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
988
req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
989
req->callback.fn(req, req->callback.private_data);
993
* Next state function for the GENSEC state machine async version
995
* @param gensec_security GENSEC State
996
* @param in The request, as a DATA_BLOB
997
* @param callback The function that will be called when the operation is
998
* finished, it should return gensec_update_recv() to get output
999
* @param private_data A private pointer that will be passed to the callback function
1002
_PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
1003
void (*callback)(struct gensec_update_request *req, void *private_data),
1006
struct gensec_update_request *req = NULL;
1007
struct tevent_timer *te = NULL;
1009
req = talloc(gensec_security, struct gensec_update_request);
1010
if (!req) goto failed;
1011
req->gensec_security = gensec_security;
1013
req->out = data_blob(NULL, 0);
1014
req->callback.fn = callback;
1015
req->callback.private_data = private_data;
1017
te = event_add_timed(gensec_security->event_ctx, req,
1019
gensec_update_async_timed_handler, req);
1020
if (!te) goto failed;
1026
callback(NULL, private_data);
1030
* Next state function for the GENSEC state machine
1032
* @param req GENSEC update request state
1033
* @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
1034
* @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1035
* @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
1036
* or NT_STATUS_OK if the user is authenticated.
1038
_PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1042
NT_STATUS_HAVE_NO_MEMORY(req);
1045
talloc_steal(out_mem_ctx, out->data);
1046
status = req->status;
1053
* Set the requirement for a certain feature on the connection
1057
_PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1060
if (!gensec_security->ops || !gensec_security->ops->want_feature) {
1061
gensec_security->want_features |= feature;
1064
gensec_security->ops->want_feature(gensec_security, feature);
1068
* Check the requirement for a certain feature on the connection
1072
_PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1075
if (!gensec_security->ops->have_feature) {
1079
/* We might 'have' features that we don't 'want', because the
1080
* other end demanded them, or we can't neotiate them off */
1081
return gensec_security->ops->have_feature(gensec_security, feature);
1085
* Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1089
_PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1091
gensec_security->credentials = talloc_reference(gensec_security, credentials);
1092
NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1093
gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1094
return NT_STATUS_OK;
1098
* Return the credentials structure associated with a GENSEC context
1102
_PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1104
if (!gensec_security) {
1107
return gensec_security->credentials;
1111
* Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1115
_PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1117
gensec_security->target.service = talloc_strdup(gensec_security, service);
1118
if (!gensec_security->target.service) {
1119
return NT_STATUS_NO_MEMORY;
1121
return NT_STATUS_OK;
1124
_PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1126
if (gensec_security->target.service) {
1127
return gensec_security->target.service;
1134
* Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1138
_PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1140
gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1141
if (hostname && !gensec_security->target.hostname) {
1142
return NT_STATUS_NO_MEMORY;
1144
return NT_STATUS_OK;
1147
_PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1149
/* We allow the target hostname to be overriden for testing purposes */
1150
if (gensec_security->settings->target_hostname) {
1151
return gensec_security->settings->target_hostname;
1154
if (gensec_security->target.hostname) {
1155
return gensec_security->target.hostname;
1158
/* We could add use the 'set sockaddr' call, and do a reverse
1159
* lookup, but this would be both insecure (compromising the
1160
* way kerberos works) and add DNS timeouts */
1165
* Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1167
* This is so that kerberos can include these addresses in
1168
* cryptographic tokens, to avoid certain attacks.
1171
_PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1173
gensec_security->my_addr = my_addr;
1174
if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1175
return NT_STATUS_NO_MEMORY;
1177
return NT_STATUS_OK;
1180
_PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1182
gensec_security->peer_addr = peer_addr;
1183
if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1184
return NT_STATUS_NO_MEMORY;
1186
return NT_STATUS_OK;
1189
struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1191
if (gensec_security->my_addr) {
1192
return gensec_security->my_addr;
1195
/* We could add a 'set sockaddr' call, and do a lookup. This
1196
* would avoid needing to do system calls if nothing asks. */
1200
_PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1202
if (gensec_security->peer_addr) {
1203
return gensec_security->peer_addr;
1206
/* We could add a 'set sockaddr' call, and do a lookup. This
1207
* would avoid needing to do system calls if nothing asks.
1208
* However, this is not appropriate for the peer addres on
1209
* datagram sockets */
1216
* Set the target principal (assuming it it known, say from the SPNEGO reply)
1217
* - ensures it is talloc()ed
1221
NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1223
gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1224
if (!gensec_security->target.principal) {
1225
return NT_STATUS_NO_MEMORY;
1227
return NT_STATUS_OK;
1230
const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1232
if (gensec_security->target.principal) {
1233
return gensec_security->target.principal;
1240
register a GENSEC backend.
1242
The 'name' can be later used by other backends to find the operations
1243
structure for this backend.
1245
NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1247
if (gensec_security_by_name(NULL, ops->name) != NULL) {
1248
/* its already registered! */
1249
DEBUG(0,("GENSEC backend '%s' already registered\n",
1251
return NT_STATUS_OBJECT_NAME_COLLISION;
1254
generic_security_ops = talloc_realloc(talloc_autofree_context(),
1255
generic_security_ops,
1256
struct gensec_security_ops *,
1257
gensec_num_backends+2);
1258
if (!generic_security_ops) {
1259
return NT_STATUS_NO_MEMORY;
1262
generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1263
gensec_num_backends++;
1264
generic_security_ops[gensec_num_backends] = NULL;
1266
DEBUG(3,("GENSEC backend '%s' registered\n",
1269
return NT_STATUS_OK;
1273
return the GENSEC interface version, and the size of some critical types
1274
This can be used by backends to either detect compilation errors, or provide
1275
multiple implementations for different smbd compilation options in one module
1277
const struct gensec_critical_sizes *gensec_interface_version(void)
1279
static const struct gensec_critical_sizes critical_sizes = {
1280
GENSEC_INTERFACE_VERSION,
1281
sizeof(struct gensec_security_ops),
1282
sizeof(struct gensec_security),
1285
return &critical_sizes;
1288
static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1289
return (*gs2)->priority - (*gs1)->priority;
1292
int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1294
return lp_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1297
bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1299
return lp_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1303
initialise the GENSEC subsystem
1305
_PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1307
static bool initialized = false;
1308
extern NTSTATUS gensec_sasl_init(void);
1309
extern NTSTATUS gensec_krb5_init(void);
1310
extern NTSTATUS gensec_schannel_init(void);
1311
extern NTSTATUS gensec_spnego_init(void);
1312
extern NTSTATUS gensec_gssapi_init(void);
1313
extern NTSTATUS gensec_ntlmssp_init(void);
1315
init_module_fn static_init[] = { STATIC_gensec_MODULES };
1316
init_module_fn *shared_init;
1318
if (initialized) return NT_STATUS_OK;
1321
shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1323
run_init_functions(static_init);
1324
run_init_functions(shared_init);
1326
talloc_free(shared_init);
1328
qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1330
return NT_STATUS_OK;