2 Unix SMB/CIFS implementation.
3 Authentication utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001-2010
6 Copyright (C) Jeremy Allison 2000-2001
7 Copyright (C) Rafal Szczesniak 2002
8 Copyright (C) Stefan Metzmacher 2005
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "auth/auth.h"
26 #include "auth/auth_sam.h"
27 #include "auth/credentials/credentials.h"
28 #include "auth/credentials/credentials_krb5.h"
29 #include "libcli/security/security.h"
30 #include "libcli/security/claims-conversions.h"
31 #include "libcli/auth/libcli_auth.h"
32 #include "librpc/gen_ndr/claims.h"
33 #include "librpc/gen_ndr/ndr_claims.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "auth/session_proto.h"
36 #include "system/kerberos.h"
37 #include <gssapi/gssapi.h>
38 #include "libcli/wbclient/wbclient.h"
41 #define DBGC_CLASS DBGC_AUTH
43 _PUBLIC_ struct auth_session_info *anonymous_session(TALLOC_CTX *mem_ctx,
44 struct loadparm_context *lp_ctx)
47 struct auth_session_info *session_info = NULL;
48 nt_status = auth_anonymous_session_info(mem_ctx, lp_ctx, &session_info);
49 if (!NT_STATUS_IS_OK(nt_status)) {
55 _PUBLIC_ NTSTATUS auth_generate_security_token(TALLOC_CTX *mem_ctx,
56 struct loadparm_context *lp_ctx, /* Optional, if you don't want privileges */
57 struct ldb_context *sam_ctx, /* Optional, if you don't want local groups */
58 const struct auth_user_info_dc *user_info_dc,
59 uint32_t session_info_flags,
60 struct security_token **_security_token)
62 struct security_token *security_token = NULL;
65 uint32_t num_sids = 0;
66 const char *filter = NULL;
67 struct auth_SidAttr *sids = NULL;
69 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
70 if (tmp_ctx == NULL) {
71 return NT_STATUS_NO_MEMORY;
74 sids = talloc_array(tmp_ctx, struct auth_SidAttr, user_info_dc->num_sids);
77 return NT_STATUS_NO_MEMORY;
80 num_sids = user_info_dc->num_sids;
82 for (i=0; i < user_info_dc->num_sids; i++) {
83 sids[i] = user_info_dc->sids[i];
87 * Finally add the "standard" sids.
88 * The only difference between guest and "anonymous"
89 * is the addition of Authenticated_Users.
92 if (session_info_flags & AUTH_SESSION_INFO_DEFAULT_GROUPS) {
93 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 2);
96 return NT_STATUS_NO_MEMORY;
99 sid_copy(&sids[num_sids].sid, &global_sid_World);
100 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
103 sid_copy(&sids[num_sids].sid, &global_sid_Network);
104 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
108 if (session_info_flags & AUTH_SESSION_INFO_AUTHENTICATED) {
109 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 1);
111 TALLOC_FREE(tmp_ctx);
112 return NT_STATUS_NO_MEMORY;
115 sid_copy(&sids[num_sids].sid, &global_sid_Authenticated_Users);
116 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
120 if (session_info_flags & AUTH_SESSION_INFO_NTLM) {
121 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 1);
123 TALLOC_FREE(tmp_ctx);
124 return NT_STATUS_NO_MEMORY;
127 if (!dom_sid_parse(SID_NT_NTLM_AUTHENTICATION, &sids[num_sids].sid)) {
128 TALLOC_FREE(tmp_ctx);
129 return NT_STATUS_INTERNAL_ERROR;
131 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
136 if (num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(&global_sid_Anonymous, &sids[PRIMARY_USER_SID_INDEX].sid)) {
137 /* Don't expand nested groups of system, anonymous etc*/
138 } else if (num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(&global_sid_System, &sids[PRIMARY_USER_SID_INDEX].sid)) {
139 /* Don't expand nested groups of system, anonymous etc*/
140 } else if (sam_ctx != NULL) {
141 filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:"LDB_OID_COMPARATOR_AND":=%u))",
142 GROUP_TYPE_BUILTIN_LOCAL_GROUP);
144 /* Search for each group in the token */
145 for (i = 0; i < num_sids; i++) {
146 struct dom_sid_buf buf;
150 sid_dn = talloc_asprintf(
153 dom_sid_str_buf(&sids[i].sid, &buf));
154 if (sid_dn == NULL) {
155 TALLOC_FREE(tmp_ctx);
156 return NT_STATUS_NO_MEMORY;
158 sid_blob = data_blob_string_const(sid_dn);
160 /* This function takes in memberOf values and expands
161 * them, as long as they meet the filter - so only
164 * We already have the SID in the token, so set
165 * 'only childs' flag to true */
166 nt_status = dsdb_expand_nested_groups(sam_ctx, &sid_blob, true, filter,
167 tmp_ctx, &sids, &num_sids);
168 if (!NT_STATUS_IS_OK(nt_status)) {
169 talloc_free(tmp_ctx);
175 nt_status = security_token_create(mem_ctx,
179 0 /* num_device_sids */,
180 NULL /* device_sids */,
181 (struct auth_claims) {},
184 if (!NT_STATUS_IS_OK(nt_status)) {
185 TALLOC_FREE(tmp_ctx);
189 talloc_steal(mem_ctx, security_token);
190 *_security_token = security_token;
191 talloc_free(tmp_ctx);
195 _PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
196 struct loadparm_context *lp_ctx, /* Optional, if you don't want privileges */
197 struct ldb_context *sam_ctx, /* Optional, if you don't want local groups */
198 const struct auth_user_info_dc *user_info_dc,
199 uint32_t session_info_flags,
200 struct auth_session_info **_session_info)
202 struct auth_session_info *session_info;
205 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
206 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
208 session_info = talloc_zero(tmp_ctx, struct auth_session_info);
209 if (session_info == NULL) {
210 TALLOC_FREE(tmp_ctx);
211 return NT_STATUS_NO_MEMORY;
214 session_info->info = talloc_reference(session_info, user_info_dc->info);
215 if (session_info->info == NULL) {
216 TALLOC_FREE(tmp_ctx);
217 return NT_STATUS_NO_MEMORY;
220 session_info->torture = talloc_zero(session_info, struct auth_user_info_torture);
221 if (session_info->torture == NULL) {
222 TALLOC_FREE(tmp_ctx);
223 return NT_STATUS_NO_MEMORY;
225 session_info->torture->num_dc_sids = user_info_dc->num_sids;
226 session_info->torture->dc_sids = talloc_reference(session_info, user_info_dc->sids);
227 if (session_info->torture->dc_sids == NULL) {
228 TALLOC_FREE(tmp_ctx);
229 return NT_STATUS_NO_MEMORY;
232 /* unless set otherwise, the session key is the user session
233 * key from the auth subsystem */
234 session_info->session_key = data_blob_talloc(session_info, user_info_dc->user_session_key.data, user_info_dc->user_session_key.length);
235 if (!session_info->session_key.data && user_info_dc->user_session_key.length) {
236 TALLOC_FREE(tmp_ctx);
237 return NT_STATUS_NO_MEMORY;
240 nt_status = auth_generate_security_token(session_info,
245 &session_info->security_token);
246 if (!NT_STATUS_IS_OK(nt_status)) {
247 TALLOC_FREE(tmp_ctx);
251 session_info->unique_session_token = GUID_random();
253 session_info->credentials = NULL;
255 session_info->ticket_type = user_info_dc->ticket_type;
257 talloc_steal(mem_ctx, session_info);
258 *_session_info = session_info;
259 talloc_free(tmp_ctx);
264 /* Fill out the auth_session_info with a cli_credentials based on the
265 * auth_session_info we were forwarded over named pipe forwarding.
267 * NOTE: The structure members of session_info_transport are stolen
268 * with talloc_move() into auth_session_info for long term use
270 struct auth_session_info *auth_session_info_from_transport(TALLOC_CTX *mem_ctx,
271 struct auth_session_info_transport *session_info_transport,
272 struct loadparm_context *lp_ctx,
275 struct auth_session_info *session_info;
276 session_info = talloc_steal(mem_ctx, session_info_transport->session_info);
278 * This is to allow us to check the type of this pointer using
281 talloc_set_name(session_info, "struct auth_session_info");
282 #ifdef HAVE_GSS_IMPORT_CRED
283 if (session_info_transport->exported_gssapi_credentials.length) {
284 struct cli_credentials *creds;
285 OM_uint32 minor_status;
286 gss_buffer_desc cred_token;
287 gss_cred_id_t cred_handle;
288 const char *error_string;
292 DEBUG(10, ("Delegated credentials supplied by client\n"));
294 cred_token.value = session_info_transport->exported_gssapi_credentials.data;
295 cred_token.length = session_info_transport->exported_gssapi_credentials.length;
297 ret = gss_import_cred(&minor_status,
300 if (ret != GSS_S_COMPLETE) {
301 *reason = "Internal error in gss_import_cred()";
305 creds = cli_credentials_init(session_info);
307 *reason = "Out of memory in cli_credentials_init()";
310 session_info->credentials = creds;
312 ok = cli_credentials_set_conf(creds, lp_ctx);
314 *reason = "Failed to load smb.conf";
318 /* Just so we don't segfault trying to get at a username */
319 cli_credentials_set_anonymous(creds);
321 ret = cli_credentials_set_client_gss_creds(creds,
327 *reason = talloc_asprintf(mem_ctx,
328 "Failed to set pipe forwarded "
329 "creds: %s\n", error_string);
333 /* This credential handle isn't useful for password
334 * authentication, so ensure nobody tries to do that */
335 cli_credentials_set_kerberos_state(creds,
336 CRED_USE_KERBEROS_REQUIRED,
345 /* Create a auth_session_info_transport from an auth_session_info.
347 * NOTE: Members of the auth_session_info_transport structure are
348 * talloc_referenced() into this structure, and should not be changed.
350 NTSTATUS auth_session_info_transport_from_session(TALLOC_CTX *mem_ctx,
351 struct auth_session_info *session_info,
352 struct tevent_context *event_ctx,
353 struct loadparm_context *lp_ctx,
354 struct auth_session_info_transport **transport_out)
357 struct auth_session_info_transport *session_info_transport
358 = talloc_zero(mem_ctx, struct auth_session_info_transport);
359 if (!session_info_transport) {
360 return NT_STATUS_NO_MEMORY;
362 session_info_transport->session_info = talloc_reference(session_info_transport, session_info);
363 if (!session_info_transport->session_info) {
364 return NT_STATUS_NO_MEMORY;
366 #ifdef HAVE_GSS_EXPORT_CRED
367 if (session_info->credentials) {
368 struct gssapi_creds_container *gcc;
370 OM_uint32 minor_status;
371 gss_buffer_desc cred_token;
372 const char *error_string;
375 ret = cli_credentials_get_client_gss_creds(session_info->credentials,
378 &gcc, &error_string);
380 *transport_out = session_info_transport;
384 gret = gss_export_cred(&minor_status,
387 if (gret != GSS_S_COMPLETE) {
388 return NT_STATUS_INTERNAL_ERROR;
391 if (cred_token.length) {
392 session_info_transport->exported_gssapi_credentials
393 = data_blob_talloc(session_info_transport,
396 gss_release_buffer(&minor_status, &cred_token);
397 NT_STATUS_HAVE_NO_MEMORY(session_info_transport->exported_gssapi_credentials.data);
401 *transport_out = session_info_transport;
406 /* Produce a session_info for an arbitrary DN or principal in the local
407 * DB, assuming the local DB holds all the groups
409 * Supply either a principal or a DN
411 NTSTATUS authsam_get_session_info_principal(TALLOC_CTX *mem_ctx,
412 struct loadparm_context *lp_ctx,
413 struct ldb_context *sam_ctx,
414 const char *principal,
415 struct ldb_dn *user_dn,
416 uint32_t session_info_flags,
417 struct auth_session_info **session_info)
420 struct auth_user_info_dc *user_info_dc;
421 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
423 return NT_STATUS_NO_MEMORY;
425 nt_status = authsam_get_user_info_dc_principal(tmp_ctx, lp_ctx, sam_ctx,
428 if (!NT_STATUS_IS_OK(nt_status)) {
429 talloc_free(tmp_ctx);
433 nt_status = auth_generate_session_info(tmp_ctx, lp_ctx, sam_ctx,
438 if (NT_STATUS_IS_OK(nt_status)) {
439 talloc_steal(mem_ctx, *session_info);
441 talloc_free(tmp_ctx);
446 * prints a struct auth_session_info security token to debug output.
448 void auth_session_info_debug(int dbg_lev,
449 const struct auth_session_info *session_info)
452 DEBUG(dbg_lev, ("Session Info: (NULL)\n"));
456 security_token_debug(DBGC_AUTH, dbg_lev,
457 session_info->security_token);
460 NTSTATUS encode_claims_set(TALLOC_CTX *mem_ctx,
461 struct CLAIMS_SET *claims_set,
462 DATA_BLOB *claims_blob)
464 TALLOC_CTX *tmp_ctx = NULL;
465 enum ndr_err_code ndr_err;
466 struct CLAIMS_SET_NDR *claims_set_info = NULL;
467 struct CLAIMS_SET_METADATA *metadata = NULL;
468 struct CLAIMS_SET_METADATA_NDR *metadata_ndr = NULL;
470 if (claims_blob == NULL) {
471 return NT_STATUS_INVALID_PARAMETER_3;
474 tmp_ctx = talloc_new(mem_ctx);
475 if (tmp_ctx == NULL) {
476 return NT_STATUS_NO_MEMORY;
479 metadata_ndr = talloc_zero(tmp_ctx, struct CLAIMS_SET_METADATA_NDR);
480 if (metadata_ndr == NULL) {
481 talloc_free(tmp_ctx);
482 return NT_STATUS_NO_MEMORY;
485 metadata = talloc_zero(metadata_ndr, struct CLAIMS_SET_METADATA);
486 if (metadata == NULL) {
487 talloc_free(tmp_ctx);
488 return NT_STATUS_NO_MEMORY;
491 claims_set_info = talloc_zero(metadata, struct CLAIMS_SET_NDR);
492 if (claims_set_info == NULL) {
493 talloc_free(tmp_ctx);
494 return NT_STATUS_NO_MEMORY;
497 metadata_ndr->claims.metadata = metadata;
499 metadata->claims_set = claims_set_info;
500 metadata->compression_format = CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF;
502 claims_set_info->claims.claims = claims_set;
504 ndr_err = ndr_push_struct_blob(claims_blob, mem_ctx, metadata_ndr,
505 (ndr_push_flags_fn_t)ndr_push_CLAIMS_SET_METADATA_NDR);
506 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
507 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
508 DBG_ERR("CLAIMS_SET_METADATA_NDR push failed: %s\n",
509 nt_errstr(nt_status));
511 talloc_free(tmp_ctx);
515 talloc_free(tmp_ctx);
520 * Construct a ‘claims_data’ structure from a claims blob, such as is found in a
523 NTSTATUS claims_data_from_encoded_claims_set(TALLOC_CTX *claims_data_ctx,
524 const DATA_BLOB *encoded_claims_set,
525 struct claims_data **out)
527 struct claims_data *claims_data = NULL;
531 return NT_STATUS_INVALID_PARAMETER;
536 claims_data = talloc(claims_data_ctx, struct claims_data);
537 if (claims_data == NULL) {
538 return NT_STATUS_NO_MEMORY;
541 if (encoded_claims_set != NULL) {
543 * We make a copy of the data, for it might not be
544 * talloc‐allocated — we might have obtained it directly with
545 * krb5_pac_get_buffer().
547 data = data_blob_dup_talloc(claims_data, *encoded_claims_set);
548 if (data.length != encoded_claims_set->length) {
549 talloc_free(claims_data);
550 return NT_STATUS_NO_MEMORY;
554 *claims_data = (struct claims_data) {
555 .encoded_claims_set = data,
556 .flags = CLAIMS_DATA_ENCODED_CLAIMS_PRESENT,
565 * Construct a ‘claims_data’ structure from a talloc‐allocated claims set, such
566 * as we might build from searching the database. If this function returns
567 * successfully, it assumes ownership of the claims set.
569 NTSTATUS claims_data_from_claims_set(TALLOC_CTX *claims_data_ctx,
570 struct CLAIMS_SET *claims_set,
571 struct claims_data **out)
573 struct claims_data *claims_data = NULL;
576 return NT_STATUS_INVALID_PARAMETER;
581 claims_data = talloc(claims_data_ctx, struct claims_data);
582 if (claims_data == NULL) {
583 return NT_STATUS_NO_MEMORY;
585 *claims_data = (struct claims_data) {
586 .claims_set = talloc_steal(claims_data, claims_set),
587 .flags = CLAIMS_DATA_CLAIMS_PRESENT,
596 * From a ‘claims_data’ structure, return an encoded claims blob that can be put
599 NTSTATUS claims_data_encoded_claims_set(struct claims_data *claims_data,
600 DATA_BLOB *encoded_claims_set_out)
602 if (encoded_claims_set_out == NULL) {
603 return NT_STATUS_INVALID_PARAMETER;
606 *encoded_claims_set_out = data_blob_null;
608 if (claims_data == NULL) {
612 if (!(claims_data->flags & CLAIMS_DATA_ENCODED_CLAIMS_PRESENT)) {
615 /* See whether we have a claims set that we can encode. */
616 if (!(claims_data->flags & CLAIMS_DATA_CLAIMS_PRESENT)) {
620 status = encode_claims_set(claims_data,
621 claims_data->claims_set,
622 &claims_data->encoded_claims_set);
623 if (!NT_STATUS_IS_OK(status)) {
627 claims_data->flags |= CLAIMS_DATA_ENCODED_CLAIMS_PRESENT;
630 *encoded_claims_set_out = claims_data->encoded_claims_set;
635 * From a ‘claims_data’ structure, return an array of security claims that can
636 * be put in a security token for access checks.
638 NTSTATUS claims_data_security_claims(TALLOC_CTX *mem_ctx,
639 struct claims_data *claims_data,
640 struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **security_claims_out,
641 uint32_t *n_security_claims_out)
643 struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *security_claims = NULL;
644 uint32_t n_security_claims;
647 if (security_claims_out == NULL) {
648 return NT_STATUS_INVALID_PARAMETER;
651 if (n_security_claims_out == NULL) {
652 return NT_STATUS_INVALID_PARAMETER;
655 *security_claims_out = NULL;
656 *n_security_claims_out = 0;
658 if (claims_data == NULL) {
662 if (!(claims_data->flags & CLAIMS_DATA_SECURITY_CLAIMS_PRESENT)) {
663 struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *decoded_claims = NULL;
664 uint32_t n_decoded_claims = 0;
666 /* See whether we have a claims set that we can convert. */
667 if (!(claims_data->flags & CLAIMS_DATA_CLAIMS_PRESENT)) {
670 * See whether we have an encoded claims set that we can
673 if (!(claims_data->flags & CLAIMS_DATA_ENCODED_CLAIMS_PRESENT)) {
674 /* We don’t have anything. */
678 /* Decode an existing claims set. */
680 if (claims_data->encoded_claims_set.length) {
681 TALLOC_CTX *tmp_ctx = NULL;
682 struct CLAIMS_SET_METADATA_NDR claims;
683 const struct CLAIMS_SET_METADATA *metadata = NULL;
684 enum ndr_err_code ndr_err;
686 tmp_ctx = talloc_new(claims_data);
687 if (tmp_ctx == NULL) {
688 return NT_STATUS_NO_MEMORY;
691 ndr_err = ndr_pull_struct_blob(&claims_data->encoded_claims_set,
694 (ndr_pull_flags_fn_t)ndr_pull_CLAIMS_SET_METADATA_NDR);
695 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
696 status = ndr_map_error2ntstatus(ndr_err);
697 DBG_ERR("Failed to parse encoded claims set: %s\n",
699 talloc_free(tmp_ctx);
703 metadata = claims.claims.metadata;
704 if (metadata != NULL) {
705 struct CLAIMS_SET_NDR *claims_set_ndr = metadata->claims_set;
706 if (claims_set_ndr != NULL) {
707 struct CLAIMS_SET **claims_set = &claims_set_ndr->claims.claims;
709 claims_data->claims_set = talloc_move(claims_data, claims_set);
713 talloc_free(tmp_ctx);
716 claims_data->flags |= CLAIMS_DATA_CLAIMS_PRESENT;
720 * Convert the decoded claims set to the security attribute
723 status = token_claims_to_claims_v1(claims_data,
724 claims_data->claims_set,
727 if (!NT_STATUS_IS_OK(status)) {
731 claims_data->security_claims = decoded_claims;
732 claims_data->n_security_claims = n_decoded_claims;
734 claims_data->flags |= CLAIMS_DATA_SECURITY_CLAIMS_PRESENT;
737 if (claims_data->security_claims != NULL) {
738 security_claims = talloc_reference(mem_ctx, claims_data->security_claims);
739 if (security_claims == NULL) {
740 return NT_STATUS_NO_MEMORY;
743 n_security_claims = claims_data->n_security_claims;
745 *security_claims_out = security_claims;
746 *n_security_claims_out = n_security_claims;