2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "auth/auth.h"
26 #include "lib/events/events.h"
28 /* the list of currently registered GENSEC backends */
29 const static struct gensec_security_ops
**generic_security_ops
;
30 static int gensec_num_backends
;
32 static const struct gensec_security_ops
*gensec_security_by_authtype(uint8_t auth_type
)
35 for (i
=0; i
< gensec_num_backends
; i
++) {
36 if (generic_security_ops
[i
]->auth_type
== auth_type
) {
37 return generic_security_ops
[i
];
44 static const struct gensec_security_ops
*gensec_security_by_oid(const char *oid_string
)
47 for (i
=0; i
< gensec_num_backends
; i
++) {
48 if (generic_security_ops
[i
]->oid
) {
49 for (j
=0; generic_security_ops
[i
]->oid
[j
]; j
++) {
50 if (generic_security_ops
[i
]->oid
[j
] &&
51 (strcmp(generic_security_ops
[i
]->oid
[j
], oid_string
) == 0)) {
52 return generic_security_ops
[i
];
61 static const struct gensec_security_ops
*gensec_security_by_sasl_name(const char *sasl_name
)
64 for (i
=0; i
< gensec_num_backends
; i
++) {
65 if (generic_security_ops
[i
]->sasl_name
66 && (strcmp(generic_security_ops
[i
]->sasl_name
, sasl_name
) == 0)) {
67 return generic_security_ops
[i
];
74 static const struct gensec_security_ops
*gensec_security_by_name(const char *name
)
77 for (i
=0; i
< gensec_num_backends
; i
++) {
78 if (generic_security_ops
[i
]->name
79 && (strcmp(generic_security_ops
[i
]->name
, name
) == 0)) {
80 return generic_security_ops
[i
];
87 const struct gensec_security_ops
**gensec_security_all(int *num_backends_out
)
89 *num_backends_out
= gensec_num_backends
;
90 return generic_security_ops
;
94 * Return a unique list of security subsystems from those specified in
95 * the OID list. That is, where two OIDs refer to the same module,
96 * return that module only once
98 * The list is in the exact order of the OIDs asked for, where available.
101 const struct gensec_security_ops_wrapper
*gensec_security_by_oid_list(TALLOC_CTX
*mem_ctx
,
102 const char **oid_strings
,
105 struct gensec_security_ops_wrapper
*backends_out
;
106 const struct gensec_security_ops
**backends
;
107 int i
, j
, k
, oid_idx
;
108 int num_backends_out
= 0;
115 backends
= gensec_security_all(&num_backends
);
117 backends_out
= talloc_array(mem_ctx
, struct gensec_security_ops_wrapper
, 1);
121 backends_out
[0].op
= NULL
;
122 backends_out
[0].oid
= NULL
;
124 for (oid_idx
= 0; oid_strings
[oid_idx
]; oid_idx
++) {
125 if (strcmp(oid_strings
[oid_idx
], skip
) == 0) {
129 for (i
=0; i
< num_backends
; i
++) {
130 if (!backends
[i
]->oid
) {
133 for (j
=0; backends
[i
]->oid
[j
]; j
++) {
134 if (!backends
[i
]->oid
[j
] ||
135 !(strcmp(backends
[i
]->oid
[j
],
136 oid_strings
[oid_idx
]) == 0)) {
140 for (k
=0; backends_out
[k
].op
; k
++) {
141 if (backends_out
[k
].op
== backends
[i
]) {
146 if (k
< num_backends_out
) {
147 /* already in there */
151 backends_out
= talloc_realloc(mem_ctx
, backends_out
,
152 struct gensec_security_ops_wrapper
,
153 num_backends_out
+ 2);
158 backends_out
[num_backends_out
].op
= backends
[i
];
159 backends_out
[num_backends_out
].oid
= backends
[i
]->oid
[j
];
161 backends_out
[num_backends_out
].op
= NULL
;
162 backends_out
[num_backends_out
].oid
= NULL
;
170 * Return OIDS from the security subsystems listed
173 const char **gensec_security_oids_from_ops(TALLOC_CTX
*mem_ctx
,
174 const struct gensec_security_ops
**ops
,
181 const char **oid_list
;
185 oid_list
= talloc_array(mem_ctx
, const char *, 1);
190 for (i
=0; i
<num_backends
; i
++) {
195 for (k
= 0; ops
[i
]->oid
[k
]; k
++) {
196 if (skip
&& strcmp(skip
, ops
[i
]->oid
[k
])==0) {
198 oid_list
= talloc_realloc(mem_ctx
, oid_list
, const char *, j
+ 2);
202 oid_list
[j
] = ops
[i
]->oid
[k
];
213 * Return all the security subsystems currently enabled in GENSEC
216 const char **gensec_security_oids(TALLOC_CTX
*mem_ctx
, const char *skip
)
219 const struct gensec_security_ops
**ops
= gensec_security_all(&num_backends
);
220 return gensec_security_oids_from_ops(mem_ctx
, ops
,
227 Start the GENSEC system, returning a context pointer.
228 @param mem_ctx The parent TALLOC memory context.
229 @param gensec_security Returned GENSEC context pointer.
230 @note The mem_ctx is only a parent and may be NULL.
232 static NTSTATUS
gensec_start(TALLOC_CTX
*mem_ctx
,
233 struct gensec_security
**gensec_security
,
234 struct event_context
*ev
)
236 (*gensec_security
) = talloc(mem_ctx
, struct gensec_security
);
237 NT_STATUS_HAVE_NO_MEMORY(*gensec_security
);
239 (*gensec_security
)->ops
= NULL
;
241 ZERO_STRUCT((*gensec_security
)->target
);
243 (*gensec_security
)->subcontext
= False
;
244 (*gensec_security
)->want_features
= 0;
247 ev
= event_context_init(*gensec_security
);
249 talloc_free(*gensec_security
);
250 return NT_STATUS_NO_MEMORY
;
254 (*gensec_security
)->event_ctx
= ev
;
260 * Start a GENSEC subcontext, with a copy of the properties of the parent
261 * @param mem_ctx The parent TALLOC memory context.
262 * @param parent The parent GENSEC context
263 * @param gensec_security Returned GENSEC context pointer.
264 * @note Used by SPNEGO in particular, for the actual implementation mechanism
267 NTSTATUS
gensec_subcontext_start(TALLOC_CTX
*mem_ctx
,
268 struct gensec_security
*parent
,
269 struct gensec_security
**gensec_security
)
271 (*gensec_security
) = talloc(mem_ctx
, struct gensec_security
);
272 NT_STATUS_HAVE_NO_MEMORY(*gensec_security
);
274 (**gensec_security
) = *parent
;
275 (*gensec_security
)->ops
= NULL
;
276 (*gensec_security
)->private_data
= NULL
;
278 (*gensec_security
)->subcontext
= True
;
279 (*gensec_security
)->event_ctx
= parent
->event_ctx
;
285 Start the GENSEC system, in client mode, returning a context pointer.
286 @param mem_ctx The parent TALLOC memory context.
287 @param gensec_security Returned GENSEC context pointer.
288 @note The mem_ctx is only a parent and may be NULL.
290 NTSTATUS
gensec_client_start(TALLOC_CTX
*mem_ctx
,
291 struct gensec_security
**gensec_security
,
292 struct event_context
*ev
)
295 status
= gensec_start(mem_ctx
, gensec_security
, ev
);
296 if (!NT_STATUS_IS_OK(status
)) {
299 (*gensec_security
)->gensec_role
= GENSEC_CLIENT
;
305 Start the GENSEC system, in server mode, returning a context pointer.
306 @param mem_ctx The parent TALLOC memory context.
307 @param gensec_security Returned GENSEC context pointer.
308 @note The mem_ctx is only a parent and may be NULL.
310 NTSTATUS
gensec_server_start(TALLOC_CTX
*mem_ctx
,
311 struct gensec_security
**gensec_security
,
312 struct event_context
*ev
)
315 status
= gensec_start(mem_ctx
, gensec_security
, ev
);
316 if (!NT_STATUS_IS_OK(status
)) {
319 (*gensec_security
)->gensec_role
= GENSEC_SERVER
;
324 static NTSTATUS
gensec_start_mech(struct gensec_security
*gensec_security
)
327 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
328 gensec_security
->subcontext
? "sub" : "",
329 gensec_security
->ops
->name
));
330 switch (gensec_security
->gensec_role
) {
332 if (gensec_security
->ops
->client_start
) {
333 status
= gensec_security
->ops
->client_start(gensec_security
);
334 if (!NT_STATUS_IS_OK(status
)) {
335 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
336 gensec_security
->ops
->name
, nt_errstr(status
)));
341 if (gensec_security
->ops
->server_start
) {
342 status
= gensec_security
->ops
->server_start(gensec_security
);
343 if (!NT_STATUS_IS_OK(status
)) {
344 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
345 gensec_security
->ops
->name
, nt_errstr(status
)));
350 return NT_STATUS_INVALID_PARAMETER
;
354 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
355 * @param gensec_security GENSEC context pointer.
356 * @param auth_type DCERPC auth type
357 * @param auth_level DCERPC auth level
360 NTSTATUS
gensec_start_mech_by_authtype(struct gensec_security
*gensec_security
,
361 uint8_t auth_type
, uint8_t auth_level
)
363 gensec_security
->ops
= gensec_security_by_authtype(auth_type
);
364 if (!gensec_security
->ops
) {
365 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type
));
366 return NT_STATUS_INVALID_PARAMETER
;
368 gensec_want_feature(gensec_security
, GENSEC_FEATURE_DCE_STYLE
);
369 if (auth_level
== DCERPC_AUTH_LEVEL_INTEGRITY
) {
370 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
371 } else if (auth_level
== DCERPC_AUTH_LEVEL_PRIVACY
) {
372 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
373 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
374 } else if (auth_level
== DCERPC_AUTH_LEVEL_CONNECT
) {
375 /* Default features */
377 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
379 return NT_STATUS_INVALID_PARAMETER
;
382 return gensec_start_mech(gensec_security
);
385 const char *gensec_get_name_by_authtype(uint8_t authtype
)
387 const struct gensec_security_ops
*ops
;
388 ops
= gensec_security_by_authtype(authtype
);
396 const char *gensec_get_name_by_oid(const char *oid_string
)
398 const struct gensec_security_ops
*ops
;
399 ops
= gensec_security_by_oid(oid_string
);
408 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
412 NTSTATUS
gensec_start_mech_by_ops(struct gensec_security
*gensec_security
,
413 const struct gensec_security_ops
*ops
)
415 gensec_security
->ops
= ops
;
416 return gensec_start_mech(gensec_security
);
420 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
422 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
423 * well-known #define to hook it in.
426 NTSTATUS
gensec_start_mech_by_oid(struct gensec_security
*gensec_security
,
427 const char *mech_oid
)
429 gensec_security
->ops
= gensec_security_by_oid(mech_oid
);
430 if (!gensec_security
->ops
) {
431 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid
));
432 return NT_STATUS_INVALID_PARAMETER
;
434 return gensec_start_mech(gensec_security
);
438 * Start a GENSEC sub-mechanism by a well know SASL name
442 NTSTATUS
gensec_start_mech_by_sasl_name(struct gensec_security
*gensec_security
,
443 const char *sasl_name
)
445 gensec_security
->ops
= gensec_security_by_sasl_name(sasl_name
);
446 if (!gensec_security
->ops
) {
447 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name
));
448 return NT_STATUS_INVALID_PARAMETER
;
450 return gensec_start_mech(gensec_security
);
454 wrappers for the gensec function pointers
456 NTSTATUS
gensec_unseal_packet(struct gensec_security
*gensec_security
,
458 uint8_t *data
, size_t length
,
459 const uint8_t *whole_pdu
, size_t pdu_length
,
460 const DATA_BLOB
*sig
)
462 if (!gensec_security
->ops
->unseal_packet
) {
463 return NT_STATUS_NOT_IMPLEMENTED
;
465 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
)) {
466 if (gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
467 return gensec_check_packet(gensec_security
, mem_ctx
,
469 whole_pdu
, pdu_length
,
472 return NT_STATUS_INVALID_PARAMETER
;
475 return gensec_security
->ops
->unseal_packet(gensec_security
, mem_ctx
,
477 whole_pdu
, pdu_length
,
481 NTSTATUS
gensec_check_packet(struct gensec_security
*gensec_security
,
483 const uint8_t *data
, size_t length
,
484 const uint8_t *whole_pdu
, size_t pdu_length
,
485 const DATA_BLOB
*sig
)
487 if (!gensec_security
->ops
->check_packet
) {
488 return NT_STATUS_NOT_IMPLEMENTED
;
490 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
491 return NT_STATUS_INVALID_PARAMETER
;
494 return gensec_security
->ops
->check_packet(gensec_security
, mem_ctx
, data
, length
, whole_pdu
, pdu_length
, sig
);
497 NTSTATUS
gensec_seal_packet(struct gensec_security
*gensec_security
,
499 uint8_t *data
, size_t length
,
500 const uint8_t *whole_pdu
, size_t pdu_length
,
503 if (!gensec_security
->ops
->seal_packet
) {
504 return NT_STATUS_NOT_IMPLEMENTED
;
506 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
)) {
507 if (gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
508 return gensec_sign_packet(gensec_security
, mem_ctx
,
510 whole_pdu
, pdu_length
,
513 return NT_STATUS_INVALID_PARAMETER
;
516 return gensec_security
->ops
->seal_packet(gensec_security
, mem_ctx
, data
, length
, whole_pdu
, pdu_length
, sig
);
519 NTSTATUS
gensec_sign_packet(struct gensec_security
*gensec_security
,
521 const uint8_t *data
, size_t length
,
522 const uint8_t *whole_pdu
, size_t pdu_length
,
525 if (!gensec_security
->ops
->sign_packet
) {
526 return NT_STATUS_NOT_IMPLEMENTED
;
528 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
529 return NT_STATUS_INVALID_PARAMETER
;
532 return gensec_security
->ops
->sign_packet(gensec_security
, mem_ctx
, data
, length
, whole_pdu
, pdu_length
, sig
);
535 size_t gensec_sig_size(struct gensec_security
*gensec_security
)
537 if (!gensec_security
->ops
->sig_size
) {
540 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
544 return gensec_security
->ops
->sig_size(gensec_security
);
547 NTSTATUS
gensec_wrap(struct gensec_security
*gensec_security
,
552 if (!gensec_security
->ops
->wrap
) {
553 return NT_STATUS_NOT_IMPLEMENTED
;
555 return gensec_security
->ops
->wrap(gensec_security
, mem_ctx
, in
, out
);
558 NTSTATUS
gensec_unwrap(struct gensec_security
*gensec_security
,
563 if (!gensec_security
->ops
->unwrap
) {
564 return NT_STATUS_NOT_IMPLEMENTED
;
566 return gensec_security
->ops
->unwrap(gensec_security
, mem_ctx
, in
, out
);
569 NTSTATUS
gensec_session_key(struct gensec_security
*gensec_security
,
570 DATA_BLOB
*session_key
)
572 if (!gensec_security
->ops
->session_key
) {
573 return NT_STATUS_NOT_IMPLEMENTED
;
575 return gensec_security
->ops
->session_key(gensec_security
, session_key
);
579 * Return the credentials of a logged on user, including session keys
582 * Only valid after a successful authentication
584 * May only be called once per authentication.
588 NTSTATUS
gensec_session_info(struct gensec_security
*gensec_security
,
589 struct auth_session_info
**session_info
)
591 if (!gensec_security
->ops
->session_info
) {
592 return NT_STATUS_NOT_IMPLEMENTED
;
594 return gensec_security
->ops
->session_info(gensec_security
, session_info
);
598 * Next state function for the GENSEC state machine
600 * @param gensec_security GENSEC State
601 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
602 * @param in The request, as a DATA_BLOB
603 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
604 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
605 * or NT_STATUS_OK if the user is authenticated.
608 NTSTATUS
gensec_update(struct gensec_security
*gensec_security
, TALLOC_CTX
*out_mem_ctx
,
609 const DATA_BLOB in
, DATA_BLOB
*out
)
611 return gensec_security
->ops
->update(gensec_security
, out_mem_ctx
, in
, out
);
615 * Set the requirement for a certain feature on the connection
619 void gensec_want_feature(struct gensec_security
*gensec_security
,
622 gensec_security
->want_features
|= feature
;
626 * Check the requirement for a certain feature on the connection
630 BOOL
gensec_have_feature(struct gensec_security
*gensec_security
,
633 if (!gensec_security
->ops
->have_feature
) {
636 return gensec_security
->ops
->have_feature(gensec_security
, feature
);
640 * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
644 NTSTATUS
gensec_set_credentials(struct gensec_security
*gensec_security
, struct cli_credentials
*credentials
)
646 gensec_security
->credentials
= talloc_reference(gensec_security
, credentials
);
651 * Return the credentails structure associated with a GENSEC context
655 struct cli_credentials
*gensec_get_credentials(struct gensec_security
*gensec_security
)
657 return gensec_security
->credentials
;
661 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
665 NTSTATUS
gensec_set_target_service(struct gensec_security
*gensec_security
, const char *service
)
667 gensec_security
->target
.service
= talloc_strdup(gensec_security
, service
);
668 if (!gensec_security
->target
.service
) {
669 return NT_STATUS_NO_MEMORY
;
675 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
679 NTSTATUS
gensec_set_target_hostname(struct gensec_security
*gensec_security
, const char *hostname
)
681 gensec_security
->target
.hostname
= talloc_strdup(gensec_security
, hostname
);
682 if (!gensec_security
->target
.hostname
) {
683 return NT_STATUS_NO_MEMORY
;
688 const char *gensec_get_target_hostname(struct gensec_security
*gensec_security
)
690 if (gensec_security
->target
.hostname
) {
691 return gensec_security
->target
.hostname
;
694 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
698 const char *gensec_get_target_service(struct gensec_security
*gensec_security
)
700 if (gensec_security
->target
.service
) {
701 return gensec_security
->target
.service
;
708 register a GENSEC backend.
710 The 'name' can be later used by other backends to find the operations
711 structure for this backend.
713 NTSTATUS
gensec_register(const void *_ops
)
715 const struct gensec_security_ops
*ops
= _ops
;
717 if (!lp_parm_bool(-1, "gensec", ops
->name
, ops
->enabled
)) {
718 DEBUG(2,("gensec subsystem %s is disabled\n", ops
->name
));
722 if (gensec_security_by_name(ops
->name
) != NULL
) {
723 /* its already registered! */
724 DEBUG(0,("GENSEC backend '%s' already registered\n",
726 return NT_STATUS_OBJECT_NAME_COLLISION
;
729 generic_security_ops
= realloc_p(generic_security_ops
,
730 const struct gensec_security_ops
*,
731 gensec_num_backends
+1);
732 if (!generic_security_ops
) {
733 smb_panic("out of memory in gensec_register");
736 generic_security_ops
[gensec_num_backends
] = ops
;
738 gensec_num_backends
++;
740 DEBUG(3,("GENSEC backend '%s' registered\n",
747 return the GENSEC interface version, and the size of some critical types
748 This can be used by backends to either detect compilation errors, or provide
749 multiple implementations for different smbd compilation options in one module
751 const struct gensec_critical_sizes
*gensec_interface_version(void)
753 static const struct gensec_critical_sizes critical_sizes
= {
754 GENSEC_INTERFACE_VERSION
,
755 sizeof(struct gensec_security_ops
),
756 sizeof(struct gensec_security
),
759 return &critical_sizes
;
763 initialise the GENSEC subsystem
765 NTSTATUS
gensec_init(void)