7d03dc77403ac87a203dd78e63c58ed881b67cc0
[samba.git] / source4 / auth / session.c
1 /* 
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
9
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.
14    
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.
19    
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/>.
22 */
23
24 #include "includes.h"
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"
39
40 #undef DBGC_CLASS
41 #define DBGC_CLASS DBGC_AUTH
42
43 _PUBLIC_ struct auth_session_info *anonymous_session(TALLOC_CTX *mem_ctx, 
44                                             struct loadparm_context *lp_ctx)
45 {
46         NTSTATUS nt_status;
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)) {
50                 return NULL;
51         }
52         return session_info;
53 }
54
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)
61 {
62         struct security_token *security_token = NULL;
63         NTSTATUS nt_status;
64         uint32_t i;
65         uint32_t num_sids = 0;
66         const char *filter = NULL;
67         struct auth_SidAttr *sids = NULL;
68
69         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
70         if (tmp_ctx == NULL) {
71                 return NT_STATUS_NO_MEMORY;
72         }
73
74         sids = talloc_array(tmp_ctx, struct auth_SidAttr, user_info_dc->num_sids);
75         if (sids == NULL) {
76                 TALLOC_FREE(tmp_ctx);
77                 return NT_STATUS_NO_MEMORY;
78         }
79
80         num_sids = user_info_dc->num_sids;
81
82         for (i=0; i < user_info_dc->num_sids; i++) {
83                 sids[i] = user_info_dc->sids[i];
84         }
85
86         /*
87          * Finally add the "standard" sids.
88          * The only difference between guest and "anonymous"
89          * is the addition of Authenticated_Users.
90          */
91
92         if (session_info_flags & AUTH_SESSION_INFO_DEFAULT_GROUPS) {
93                 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 2);
94                 if (sids == NULL) {
95                         TALLOC_FREE(tmp_ctx);
96                         return NT_STATUS_NO_MEMORY;
97                 }
98
99                 sid_copy(&sids[num_sids].sid, &global_sid_World);
100                 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
101                 num_sids++;
102
103                 sid_copy(&sids[num_sids].sid, &global_sid_Network);
104                 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
105                 num_sids++;
106         }
107
108         if (session_info_flags & AUTH_SESSION_INFO_AUTHENTICATED) {
109                 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 1);
110                 if (sids == NULL) {
111                         TALLOC_FREE(tmp_ctx);
112                         return NT_STATUS_NO_MEMORY;
113                 }
114
115                 sid_copy(&sids[num_sids].sid, &global_sid_Authenticated_Users);
116                 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
117                 num_sids++;
118         }
119
120         if (session_info_flags & AUTH_SESSION_INFO_NTLM) {
121                 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 1);
122                 if (sids == NULL) {
123                         TALLOC_FREE(tmp_ctx);
124                         return NT_STATUS_NO_MEMORY;
125                 }
126
127                 if (!dom_sid_parse(SID_NT_NTLM_AUTHENTICATION, &sids[num_sids].sid)) {
128                         TALLOC_FREE(tmp_ctx);
129                         return NT_STATUS_INTERNAL_ERROR;
130                 }
131                 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
132                 num_sids++;
133         }
134
135
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);
143
144                 /* Search for each group in the token */
145                 for (i = 0; i < num_sids; i++) {
146                         struct dom_sid_buf buf;
147                         const char *sid_dn;
148                         DATA_BLOB sid_blob;
149
150                         sid_dn = talloc_asprintf(
151                                 tmp_ctx,
152                                 "<SID=%s>",
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;
157                         }
158                         sid_blob = data_blob_string_const(sid_dn);
159
160                         /* This function takes in memberOf values and expands
161                          * them, as long as they meet the filter - so only
162                          * builtin groups
163                          *
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);
170                                 return nt_status;
171                         }
172                 }
173         }
174
175         nt_status = security_token_create(mem_ctx,
176                                           lp_ctx,
177                                           num_sids,
178                                           sids,
179                                           0 /* num_device_sids */,
180                                           NULL /* device_sids */,
181                                           (struct auth_claims) {},
182                                           session_info_flags,
183                                           &security_token);
184         if (!NT_STATUS_IS_OK(nt_status)) {
185                 TALLOC_FREE(tmp_ctx);
186                 return nt_status;
187         }
188
189         talloc_steal(mem_ctx, security_token);
190         *_security_token = security_token;
191         talloc_free(tmp_ctx);
192         return NT_STATUS_OK;
193 }
194
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)
201 {
202         struct auth_session_info *session_info;
203         NTSTATUS nt_status;
204
205         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
206         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
207
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;
212         }
213
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;
218         }
219
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;
224         }
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;
230         }
231
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;
238         }
239
240         nt_status = auth_generate_security_token(session_info,
241                                                  lp_ctx,
242                                                  sam_ctx,
243                                                  user_info_dc,
244                                                  session_info_flags,
245                                                  &session_info->security_token);
246         if (!NT_STATUS_IS_OK(nt_status)) {
247                 TALLOC_FREE(tmp_ctx);
248                 return nt_status;
249         }
250
251         session_info->unique_session_token = GUID_random();
252
253         session_info->credentials = NULL;
254
255         session_info->ticket_type = user_info_dc->ticket_type;
256
257         talloc_steal(mem_ctx, session_info);
258         *_session_info = session_info;
259         talloc_free(tmp_ctx);
260         return NT_STATUS_OK;
261 }
262
263
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.
266  *
267  * NOTE: The structure members of session_info_transport are stolen
268  * with talloc_move() into auth_session_info for long term use
269  */
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,
273                                                            const char **reason)
274 {
275         struct auth_session_info *session_info;
276         session_info = talloc_steal(mem_ctx, session_info_transport->session_info);
277         /*
278          * This is to allow us to check the type of this pointer using
279          * talloc_get_type()
280          */
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;
289                 int ret;
290                 bool ok;
291
292                 DEBUG(10, ("Delegated credentials supplied by client\n"));
293
294                 cred_token.value = session_info_transport->exported_gssapi_credentials.data;
295                 cred_token.length = session_info_transport->exported_gssapi_credentials.length;
296
297                 ret = gss_import_cred(&minor_status,
298                                       &cred_token,
299                                       &cred_handle);
300                 if (ret != GSS_S_COMPLETE) {
301                         *reason = "Internal error in gss_import_cred()";
302                         return NULL;
303                 }
304
305                 creds = cli_credentials_init(session_info);
306                 if (!creds) {
307                         *reason = "Out of memory in cli_credentials_init()";
308                         return NULL;
309                 }
310                 session_info->credentials = creds;
311
312                 ok = cli_credentials_set_conf(creds, lp_ctx);
313                 if (!ok) {
314                         *reason = "Failed to load smb.conf";
315                         return NULL;
316                 }
317
318                 /* Just so we don't segfault trying to get at a username */
319                 cli_credentials_set_anonymous(creds);
320
321                 ret = cli_credentials_set_client_gss_creds(creds,
322                                                            lp_ctx,
323                                                            cred_handle,
324                                                            CRED_SPECIFIED,
325                                                            &error_string);
326                 if (ret) {
327                         *reason = talloc_asprintf(mem_ctx,
328                                                   "Failed to set pipe forwarded "
329                                                   "creds: %s\n", error_string);
330                         return NULL;
331                 }
332
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,
337                                                    CRED_SPECIFIED);
338
339         }
340 #endif
341         return session_info;
342 }
343
344
345 /* Create a auth_session_info_transport from an auth_session_info.
346  *
347  * NOTE: Members of the auth_session_info_transport structure are
348  * talloc_referenced() into this structure, and should not be changed.
349  */
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)
355 {
356
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;
361         };
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;
365         };
366 #ifdef HAVE_GSS_EXPORT_CRED
367         if (session_info->credentials) {
368                 struct gssapi_creds_container *gcc;
369                 OM_uint32 gret;
370                 OM_uint32 minor_status;
371                 gss_buffer_desc cred_token;
372                 const char *error_string;
373                 int ret;
374
375                 ret = cli_credentials_get_client_gss_creds(session_info->credentials,
376                                                            event_ctx,
377                                                            lp_ctx,
378                                                            &gcc, &error_string);
379                 if (ret != 0) {
380                         *transport_out = session_info_transport;
381                         return NT_STATUS_OK;
382                 }
383
384                 gret = gss_export_cred(&minor_status,
385                                        gcc->creds,
386                                        &cred_token);
387                 if (gret != GSS_S_COMPLETE) {
388                         return NT_STATUS_INTERNAL_ERROR;
389                 }
390
391                 if (cred_token.length) {
392                         session_info_transport->exported_gssapi_credentials
393                                 = data_blob_talloc(session_info_transport,
394                                                    cred_token.value,
395                                                    cred_token.length);
396                         gss_release_buffer(&minor_status, &cred_token);
397                         NT_STATUS_HAVE_NO_MEMORY(session_info_transport->exported_gssapi_credentials.data);
398                 }
399         }
400 #endif
401         *transport_out = session_info_transport;
402         return NT_STATUS_OK;
403 }
404
405
406 /* Produce a session_info for an arbitrary DN or principal in the local
407  * DB, assuming the local DB holds all the groups
408  *
409  * Supply either a principal or a DN
410  */
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)
418 {
419         NTSTATUS nt_status;
420         struct auth_user_info_dc *user_info_dc;
421         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
422         if (!tmp_ctx) {
423                 return NT_STATUS_NO_MEMORY;
424         }
425         nt_status = authsam_get_user_info_dc_principal(tmp_ctx, lp_ctx, sam_ctx,
426                                                       principal, user_dn,
427                                                       &user_info_dc);
428         if (!NT_STATUS_IS_OK(nt_status)) {
429                 talloc_free(tmp_ctx);
430                 return nt_status;
431         }
432
433         nt_status = auth_generate_session_info(tmp_ctx, lp_ctx, sam_ctx,
434                                                user_info_dc,
435                                                session_info_flags,
436                                                session_info);
437
438         if (NT_STATUS_IS_OK(nt_status)) {
439                 talloc_steal(mem_ctx, *session_info);
440         }
441         talloc_free(tmp_ctx);
442         return nt_status;
443 }
444
445 /**
446  * prints a struct auth_session_info security token to debug output.
447  */
448 void auth_session_info_debug(int dbg_lev, 
449                              const struct auth_session_info *session_info)
450 {
451         if (!session_info) {
452                 DEBUG(dbg_lev, ("Session Info: (NULL)\n"));
453                 return; 
454         }
455
456         security_token_debug(DBGC_AUTH, dbg_lev,
457                              session_info->security_token);
458 }
459
460 NTSTATUS encode_claims_set(TALLOC_CTX *mem_ctx,
461                            struct CLAIMS_SET *claims_set,
462                            DATA_BLOB *claims_blob)
463 {
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;
469
470         if (claims_blob == NULL) {
471                 return NT_STATUS_INVALID_PARAMETER_3;
472         }
473
474         tmp_ctx = talloc_new(mem_ctx);
475         if (tmp_ctx == NULL) {
476                 return NT_STATUS_NO_MEMORY;
477         }
478
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;
483         }
484
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;
489         }
490
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;
495         }
496
497         metadata_ndr->claims.metadata = metadata;
498
499         metadata->claims_set = claims_set_info;
500         metadata->compression_format = CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF;
501
502         claims_set_info->claims.claims = claims_set;
503
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));
510
511                 talloc_free(tmp_ctx);
512                 return nt_status;
513         }
514
515         talloc_free(tmp_ctx);
516         return NT_STATUS_OK;
517 }
518
519 /*
520  * Construct a ‘claims_data’ structure from a claims blob, such as is found in a
521  * PAC.
522  */
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)
526 {
527         struct claims_data *claims_data = NULL;
528         DATA_BLOB data = {};
529
530         if (out == NULL) {
531                 return NT_STATUS_INVALID_PARAMETER;
532         }
533
534         *out = NULL;
535
536         claims_data = talloc(claims_data_ctx, struct claims_data);
537         if (claims_data == NULL) {
538                 return NT_STATUS_NO_MEMORY;
539         }
540
541         if (encoded_claims_set != NULL) {
542                 /*
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().
546                  */
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;
551                 }
552         }
553
554         *claims_data = (struct claims_data) {
555                 .encoded_claims_set = data,
556                 .flags = CLAIMS_DATA_ENCODED_CLAIMS_PRESENT,
557         };
558
559         *out = claims_data;
560
561         return NT_STATUS_OK;
562 }
563
564 /*
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.
568  */
569 NTSTATUS claims_data_from_claims_set(TALLOC_CTX *claims_data_ctx,
570                                      struct CLAIMS_SET *claims_set,
571                                      struct claims_data **out)
572 {
573         struct claims_data *claims_data = NULL;
574
575         if (out == NULL) {
576                 return NT_STATUS_INVALID_PARAMETER;
577         }
578
579         *out = NULL;
580
581         claims_data = talloc(claims_data_ctx, struct claims_data);
582         if (claims_data == NULL) {
583                 return NT_STATUS_NO_MEMORY;
584         }
585         *claims_data = (struct claims_data) {
586                 .claims_set = talloc_steal(claims_data, claims_set),
587                 .flags = CLAIMS_DATA_CLAIMS_PRESENT,
588         };
589
590         *out = claims_data;
591
592         return NT_STATUS_OK;
593 }
594
595 /*
596  * From a ‘claims_data’ structure, return an encoded claims blob that can be put
597  * into a PAC.
598  */
599 NTSTATUS claims_data_encoded_claims_set(struct claims_data *claims_data,
600                                         DATA_BLOB *encoded_claims_set_out)
601 {
602         if (encoded_claims_set_out == NULL) {
603                 return NT_STATUS_INVALID_PARAMETER;
604         }
605
606         *encoded_claims_set_out = data_blob_null;
607
608         if (claims_data == NULL) {
609                 return NT_STATUS_OK;
610         }
611
612         if (!(claims_data->flags & CLAIMS_DATA_ENCODED_CLAIMS_PRESENT)) {
613                 NTSTATUS status;
614
615                 /* See whether we have a claims set that we can encode. */
616                 if (!(claims_data->flags & CLAIMS_DATA_CLAIMS_PRESENT)) {
617                         return NT_STATUS_OK;
618                 }
619
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)) {
624                         return status;
625                 }
626
627                 claims_data->flags |= CLAIMS_DATA_ENCODED_CLAIMS_PRESENT;
628         }
629
630         *encoded_claims_set_out = claims_data->encoded_claims_set;
631         return NT_STATUS_OK;
632 }
633
634 /*
635  * From a ‘claims_data’ structure, return an array of security claims that can
636  * be put in a security token for access checks.
637  */
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)
642 {
643         struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *security_claims = NULL;
644         uint32_t n_security_claims;
645         NTSTATUS status;
646
647         if (security_claims_out == NULL) {
648                 return NT_STATUS_INVALID_PARAMETER;
649         }
650
651         if (n_security_claims_out == NULL) {
652                 return NT_STATUS_INVALID_PARAMETER;
653         }
654
655         *security_claims_out = NULL;
656         *n_security_claims_out = 0;
657
658         if (claims_data == NULL) {
659                 return NT_STATUS_OK;
660         }
661
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;
665
666                 /* See whether we have a claims set that we can convert. */
667                 if (!(claims_data->flags & CLAIMS_DATA_CLAIMS_PRESENT)) {
668
669                         /*
670                          * See whether we have an encoded claims set that we can
671                          * decode.
672                          */
673                         if (!(claims_data->flags & CLAIMS_DATA_ENCODED_CLAIMS_PRESENT)) {
674                                 /* We don’t have anything. */
675                                 return NT_STATUS_OK;
676                         }
677
678                         /* Decode an existing claims set. */
679
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;
685
686                                 tmp_ctx = talloc_new(claims_data);
687                                 if (tmp_ctx == NULL) {
688                                         return NT_STATUS_NO_MEMORY;
689                                 }
690
691                                 ndr_err = ndr_pull_struct_blob(&claims_data->encoded_claims_set,
692                                                                tmp_ctx,
693                                                                &claims,
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",
698                                                 nt_errstr(status));
699                                         talloc_free(tmp_ctx);
700                                         return status;
701                                 }
702
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;
708
709                                                 claims_data->claims_set = talloc_move(claims_data, claims_set);
710                                         }
711                                 }
712
713                                 talloc_free(tmp_ctx);
714                         }
715
716                         claims_data->flags |= CLAIMS_DATA_CLAIMS_PRESENT;
717                 }
718
719                 /*
720                  * Convert the decoded claims set to the security attribute
721                  * claims format.
722                  */
723                 status = token_claims_to_claims_v1(claims_data,
724                                                    claims_data->claims_set,
725                                                    &decoded_claims,
726                                                    &n_decoded_claims);
727                 if (!NT_STATUS_IS_OK(status)) {
728                         return status;
729                 }
730
731                 claims_data->security_claims = decoded_claims;
732                 claims_data->n_security_claims = n_decoded_claims;
733
734                 claims_data->flags |= CLAIMS_DATA_SECURITY_CLAIMS_PRESENT;
735         }
736
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;
741                 }
742         }
743         n_security_claims = claims_data->n_security_claims;
744
745         *security_claims_out = security_claims;
746         *n_security_claims_out = n_security_claims;
747
748         return NT_STATUS_OK;
749 }