Line data Source code
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 7 : _PUBLIC_ struct auth_session_info *anonymous_session(TALLOC_CTX *mem_ctx,
44 : struct loadparm_context *lp_ctx)
45 : {
46 0 : NTSTATUS nt_status;
47 7 : struct auth_session_info *session_info = NULL;
48 7 : nt_status = auth_anonymous_session_info(mem_ctx, lp_ctx, &session_info);
49 7 : if (!NT_STATUS_IS_OK(nt_status)) {
50 0 : return NULL;
51 : }
52 7 : return session_info;
53 : }
54 :
55 95967 : _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 : const struct auth_user_info_dc *device_info_dc,
60 : const struct auth_claims auth_claims,
61 : uint32_t session_info_flags,
62 : struct security_token **_security_token)
63 : {
64 95967 : struct security_token *security_token = NULL;
65 2164 : NTSTATUS nt_status;
66 2164 : uint32_t i;
67 95967 : uint32_t num_sids = 0;
68 95967 : uint32_t num_device_sids = 0;
69 95967 : const char *filter = NULL;
70 95967 : struct auth_SidAttr *sids = NULL;
71 95967 : struct auth_SidAttr *device_sids = NULL;
72 :
73 95967 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
74 95967 : if (tmp_ctx == NULL) {
75 0 : return NT_STATUS_NO_MEMORY;
76 : }
77 :
78 95967 : sids = talloc_array(tmp_ctx, struct auth_SidAttr, user_info_dc->num_sids);
79 95967 : if (sids == NULL) {
80 0 : TALLOC_FREE(tmp_ctx);
81 0 : return NT_STATUS_NO_MEMORY;
82 : }
83 :
84 95967 : num_sids = user_info_dc->num_sids;
85 :
86 531519 : for (i=0; i < user_info_dc->num_sids; i++) {
87 435552 : sids[i] = user_info_dc->sids[i];
88 : }
89 :
90 : /*
91 : * Finally add the "standard" sids.
92 : * The only difference between guest and "anonymous"
93 : * is the addition of Authenticated_Users.
94 : */
95 :
96 95967 : if (session_info_flags & AUTH_SESSION_INFO_DEFAULT_GROUPS) {
97 47601 : sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 2);
98 47601 : if (sids == NULL) {
99 0 : TALLOC_FREE(tmp_ctx);
100 0 : return NT_STATUS_NO_MEMORY;
101 : }
102 :
103 47601 : sid_copy(&sids[num_sids].sid, &global_sid_World);
104 47601 : sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
105 47601 : num_sids++;
106 :
107 47601 : sid_copy(&sids[num_sids].sid, &global_sid_Network);
108 47601 : sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
109 47601 : num_sids++;
110 : }
111 :
112 95967 : if (session_info_flags & AUTH_SESSION_INFO_AUTHENTICATED) {
113 47449 : sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 1);
114 47449 : if (sids == NULL) {
115 0 : TALLOC_FREE(tmp_ctx);
116 0 : return NT_STATUS_NO_MEMORY;
117 : }
118 :
119 47449 : sid_copy(&sids[num_sids].sid, &global_sid_Authenticated_Users);
120 47449 : sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
121 47449 : num_sids++;
122 : }
123 :
124 95967 : if (session_info_flags & AUTH_SESSION_INFO_NTLM) {
125 12464 : sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 1);
126 12464 : if (sids == NULL) {
127 0 : TALLOC_FREE(tmp_ctx);
128 0 : return NT_STATUS_NO_MEMORY;
129 : }
130 :
131 12464 : if (!dom_sid_parse(SID_NT_NTLM_AUTHENTICATION, &sids[num_sids].sid)) {
132 0 : TALLOC_FREE(tmp_ctx);
133 0 : return NT_STATUS_INTERNAL_ERROR;
134 : }
135 12464 : sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
136 12464 : num_sids++;
137 : }
138 :
139 :
140 95967 : if (num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(&global_sid_Anonymous, &sids[PRIMARY_USER_SID_INDEX].sid)) {
141 : /* Don't expand nested groups of system, anonymous etc*/
142 53040 : } else if (num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(&global_sid_System, &sids[PRIMARY_USER_SID_INDEX].sid)) {
143 : /* Don't expand nested groups of system, anonymous etc*/
144 47156 : } else if (sam_ctx != NULL) {
145 44799 : filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:"LDB_OID_COMPARATOR_AND":=%u))",
146 : GROUP_TYPE_BUILTIN_LOCAL_GROUP);
147 :
148 : /* Search for each group in the token */
149 685109 : for (i = 0; i < num_sids; i++) {
150 15261 : struct dom_sid_buf buf;
151 15261 : const char *sid_dn;
152 15261 : DATA_BLOB sid_blob;
153 :
154 639259 : sid_dn = talloc_asprintf(
155 : tmp_ctx,
156 : "<SID=%s>",
157 639259 : dom_sid_str_buf(&sids[i].sid, &buf));
158 639259 : if (sid_dn == NULL) {
159 0 : TALLOC_FREE(tmp_ctx);
160 0 : return NT_STATUS_NO_MEMORY;
161 : }
162 639259 : sid_blob = data_blob_string_const(sid_dn);
163 :
164 : /* This function takes in memberOf values and expands
165 : * them, as long as they meet the filter - so only
166 : * builtin groups
167 : *
168 : * We already have the SID in the token, so set
169 : * 'only childs' flag to true */
170 639259 : nt_status = dsdb_expand_nested_groups(sam_ctx, &sid_blob, true, filter,
171 : tmp_ctx, &sids, &num_sids);
172 639259 : if (!NT_STATUS_IS_OK(nt_status)) {
173 0 : talloc_free(tmp_ctx);
174 0 : return nt_status;
175 : }
176 : }
177 : }
178 :
179 95967 : if (device_info_dc != NULL) {
180 : /*
181 : * Make a copy of the device SIDs in case we need to add extra SIDs on
182 : * the end. One can never have too much copying.
183 : */
184 233 : num_device_sids = device_info_dc->num_sids;
185 233 : device_sids = talloc_array(tmp_ctx,
186 : struct auth_SidAttr,
187 : num_device_sids);
188 233 : if (device_sids == NULL) {
189 0 : TALLOC_FREE(tmp_ctx);
190 0 : return NT_STATUS_NO_MEMORY;
191 : }
192 :
193 1361 : for (i = 0; i < num_device_sids; i++) {
194 1128 : device_sids[i] = device_info_dc->sids[i];
195 : }
196 :
197 233 : if (session_info_flags & AUTH_SESSION_INFO_DEVICE_DEFAULT_GROUPS) {
198 233 : device_sids = talloc_realloc(tmp_ctx,
199 : device_sids,
200 : struct auth_SidAttr,
201 : num_device_sids + 2);
202 233 : if (device_sids == NULL) {
203 0 : TALLOC_FREE(tmp_ctx);
204 0 : return NT_STATUS_NO_MEMORY;
205 : }
206 :
207 233 : device_sids[num_device_sids++] = (struct auth_SidAttr) {
208 : .sid = global_sid_World,
209 : .attrs = SE_GROUP_DEFAULT_FLAGS,
210 : };
211 233 : device_sids[num_device_sids++] = (struct auth_SidAttr) {
212 : .sid = global_sid_Network,
213 : .attrs = SE_GROUP_DEFAULT_FLAGS,
214 : };
215 : }
216 :
217 233 : if (session_info_flags & AUTH_SESSION_INFO_DEVICE_AUTHENTICATED) {
218 233 : device_sids = talloc_realloc(tmp_ctx,
219 : device_sids,
220 : struct auth_SidAttr,
221 : num_device_sids + 1);
222 233 : if (device_sids == NULL) {
223 0 : TALLOC_FREE(tmp_ctx);
224 0 : return NT_STATUS_NO_MEMORY;
225 : }
226 :
227 233 : device_sids[num_device_sids++] = (struct auth_SidAttr) {
228 : .sid = global_sid_Authenticated_Users,
229 : .attrs = SE_GROUP_DEFAULT_FLAGS,
230 : };
231 : }
232 : }
233 :
234 95967 : nt_status = security_token_create(mem_ctx,
235 : lp_ctx,
236 : num_sids,
237 : sids,
238 : num_device_sids,
239 : device_sids,
240 : auth_claims,
241 : session_info_flags,
242 : &security_token);
243 95967 : if (!NT_STATUS_IS_OK(nt_status)) {
244 17 : TALLOC_FREE(tmp_ctx);
245 17 : return nt_status;
246 : }
247 :
248 95950 : talloc_steal(mem_ctx, security_token);
249 95950 : *_security_token = security_token;
250 95950 : talloc_free(tmp_ctx);
251 95950 : return NT_STATUS_OK;
252 : }
253 :
254 95191 : _PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
255 : struct loadparm_context *lp_ctx, /* Optional, if you don't want privileges */
256 : struct ldb_context *sam_ctx, /* Optional, if you don't want local groups */
257 : const struct auth_user_info_dc *user_info_dc,
258 : uint32_t session_info_flags,
259 : struct auth_session_info **_session_info)
260 : {
261 2164 : struct auth_session_info *session_info;
262 2164 : NTSTATUS nt_status;
263 :
264 95191 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
265 95191 : NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
266 :
267 95191 : session_info = talloc_zero(tmp_ctx, struct auth_session_info);
268 95191 : if (session_info == NULL) {
269 0 : TALLOC_FREE(tmp_ctx);
270 0 : return NT_STATUS_NO_MEMORY;
271 : }
272 :
273 95191 : session_info->info = talloc_reference(session_info, user_info_dc->info);
274 95191 : if (session_info->info == NULL) {
275 0 : TALLOC_FREE(tmp_ctx);
276 0 : return NT_STATUS_NO_MEMORY;
277 : }
278 :
279 95191 : session_info->torture = talloc_zero(session_info, struct auth_user_info_torture);
280 95191 : if (session_info->torture == NULL) {
281 0 : TALLOC_FREE(tmp_ctx);
282 0 : return NT_STATUS_NO_MEMORY;
283 : }
284 95191 : session_info->torture->num_dc_sids = user_info_dc->num_sids;
285 95191 : session_info->torture->dc_sids = talloc_reference(session_info, user_info_dc->sids);
286 95191 : if (session_info->torture->dc_sids == NULL) {
287 0 : TALLOC_FREE(tmp_ctx);
288 0 : return NT_STATUS_NO_MEMORY;
289 : }
290 :
291 : /* unless set otherwise, the session key is the user session
292 : * key from the auth subsystem */
293 95191 : session_info->session_key = data_blob_talloc(session_info, user_info_dc->user_session_key.data, user_info_dc->user_session_key.length);
294 95191 : if (!session_info->session_key.data && user_info_dc->user_session_key.length) {
295 0 : TALLOC_FREE(tmp_ctx);
296 0 : return NT_STATUS_NO_MEMORY;
297 : }
298 :
299 95191 : nt_status = auth_generate_security_token(session_info,
300 : lp_ctx,
301 : sam_ctx,
302 : user_info_dc,
303 : NULL /*device_info_dc */,
304 95191 : (struct auth_claims) {},
305 : session_info_flags,
306 : &session_info->security_token);
307 95191 : if (!NT_STATUS_IS_OK(nt_status)) {
308 0 : TALLOC_FREE(tmp_ctx);
309 0 : return nt_status;
310 : }
311 :
312 95191 : session_info->unique_session_token = GUID_random();
313 :
314 95191 : session_info->credentials = NULL;
315 :
316 95191 : session_info->ticket_type = user_info_dc->ticket_type;
317 :
318 95191 : talloc_steal(mem_ctx, session_info);
319 95191 : *_session_info = session_info;
320 95191 : talloc_free(tmp_ctx);
321 95191 : return NT_STATUS_OK;
322 : }
323 :
324 :
325 : /* Fill out the auth_session_info with a cli_credentials based on the
326 : * auth_session_info we were forwarded over named pipe forwarding.
327 : *
328 : * NOTE: The structure members of session_info_transport are stolen
329 : * with talloc_move() into auth_session_info for long term use
330 : */
331 7813 : struct auth_session_info *auth_session_info_from_transport(TALLOC_CTX *mem_ctx,
332 : struct auth_session_info_transport *session_info_transport,
333 : struct loadparm_context *lp_ctx,
334 : const char **reason)
335 : {
336 628 : struct auth_session_info *session_info;
337 7813 : session_info = talloc_steal(mem_ctx, session_info_transport->session_info);
338 : /*
339 : * This is to allow us to check the type of this pointer using
340 : * talloc_get_type()
341 : */
342 7813 : talloc_set_name(session_info, "struct auth_session_info");
343 : #ifdef HAVE_GSS_IMPORT_CRED
344 7813 : if (session_info_transport->exported_gssapi_credentials.length) {
345 0 : struct cli_credentials *creds;
346 0 : OM_uint32 minor_status;
347 0 : gss_buffer_desc cred_token;
348 0 : gss_cred_id_t cred_handle;
349 0 : const char *error_string;
350 0 : int ret;
351 0 : bool ok;
352 :
353 1123 : DEBUG(10, ("Delegated credentials supplied by client\n"));
354 :
355 1123 : cred_token.value = session_info_transport->exported_gssapi_credentials.data;
356 1123 : cred_token.length = session_info_transport->exported_gssapi_credentials.length;
357 :
358 1123 : ret = gss_import_cred(&minor_status,
359 : &cred_token,
360 : &cred_handle);
361 1123 : if (ret != GSS_S_COMPLETE) {
362 0 : *reason = "Internal error in gss_import_cred()";
363 0 : return NULL;
364 : }
365 :
366 1123 : creds = cli_credentials_init(session_info);
367 1123 : if (!creds) {
368 0 : *reason = "Out of memory in cli_credentials_init()";
369 0 : return NULL;
370 : }
371 1123 : session_info->credentials = creds;
372 :
373 1123 : ok = cli_credentials_set_conf(creds, lp_ctx);
374 1123 : if (!ok) {
375 0 : *reason = "Failed to load smb.conf";
376 0 : return NULL;
377 : }
378 :
379 : /* Just so we don't segfault trying to get at a username */
380 1123 : cli_credentials_set_anonymous(creds);
381 :
382 1123 : ret = cli_credentials_set_client_gss_creds(creds,
383 : lp_ctx,
384 : cred_handle,
385 : CRED_SPECIFIED,
386 : &error_string);
387 1123 : if (ret) {
388 0 : *reason = talloc_asprintf(mem_ctx,
389 : "Failed to set pipe forwarded "
390 : "creds: %s\n", error_string);
391 0 : return NULL;
392 : }
393 :
394 : /* This credential handle isn't useful for password
395 : * authentication, so ensure nobody tries to do that */
396 1123 : cli_credentials_set_kerberos_state(creds,
397 : CRED_USE_KERBEROS_REQUIRED,
398 : CRED_SPECIFIED);
399 :
400 : }
401 : #endif
402 7185 : return session_info;
403 : }
404 :
405 :
406 : /* Create a auth_session_info_transport from an auth_session_info.
407 : *
408 : * NOTE: Members of the auth_session_info_transport structure are
409 : * talloc_referenced() into this structure, and should not be changed.
410 : */
411 1330 : NTSTATUS auth_session_info_transport_from_session(TALLOC_CTX *mem_ctx,
412 : struct auth_session_info *session_info,
413 : struct tevent_context *event_ctx,
414 : struct loadparm_context *lp_ctx,
415 : struct auth_session_info_transport **transport_out)
416 : {
417 :
418 0 : struct auth_session_info_transport *session_info_transport
419 1330 : = talloc_zero(mem_ctx, struct auth_session_info_transport);
420 1330 : if (!session_info_transport) {
421 0 : return NT_STATUS_NO_MEMORY;
422 0 : };
423 1330 : session_info_transport->session_info = talloc_reference(session_info_transport, session_info);
424 1330 : if (!session_info_transport->session_info) {
425 0 : return NT_STATUS_NO_MEMORY;
426 0 : };
427 : #ifdef HAVE_GSS_EXPORT_CRED
428 1330 : if (session_info->credentials) {
429 0 : struct gssapi_creds_container *gcc;
430 0 : OM_uint32 gret;
431 0 : OM_uint32 minor_status;
432 0 : gss_buffer_desc cred_token;
433 0 : const char *error_string;
434 0 : int ret;
435 :
436 1207 : ret = cli_credentials_get_client_gss_creds(session_info->credentials,
437 : event_ctx,
438 : lp_ctx,
439 : &gcc, &error_string);
440 1207 : if (ret != 0) {
441 0 : *transport_out = session_info_transport;
442 0 : return NT_STATUS_OK;
443 : }
444 :
445 1207 : gret = gss_export_cred(&minor_status,
446 1207 : gcc->creds,
447 : &cred_token);
448 1207 : if (gret != GSS_S_COMPLETE) {
449 0 : return NT_STATUS_INTERNAL_ERROR;
450 : }
451 :
452 1207 : if (cred_token.length) {
453 0 : session_info_transport->exported_gssapi_credentials
454 1207 : = data_blob_talloc(session_info_transport,
455 : cred_token.value,
456 : cred_token.length);
457 1207 : gss_release_buffer(&minor_status, &cred_token);
458 1207 : NT_STATUS_HAVE_NO_MEMORY(session_info_transport->exported_gssapi_credentials.data);
459 : }
460 : }
461 : #endif
462 1330 : *transport_out = session_info_transport;
463 1330 : return NT_STATUS_OK;
464 : }
465 :
466 :
467 : /* Produce a session_info for an arbitrary DN or principal in the local
468 : * DB, assuming the local DB holds all the groups
469 : *
470 : * Supply either a principal or a DN
471 : */
472 471 : NTSTATUS authsam_get_session_info_principal(TALLOC_CTX *mem_ctx,
473 : struct loadparm_context *lp_ctx,
474 : struct ldb_context *sam_ctx,
475 : const char *principal,
476 : struct ldb_dn *user_dn,
477 : uint32_t session_info_flags,
478 : struct auth_session_info **session_info)
479 : {
480 41 : NTSTATUS nt_status;
481 41 : struct auth_user_info_dc *user_info_dc;
482 471 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
483 471 : if (!tmp_ctx) {
484 0 : return NT_STATUS_NO_MEMORY;
485 : }
486 471 : nt_status = authsam_get_user_info_dc_principal(tmp_ctx, lp_ctx, sam_ctx,
487 : principal, user_dn,
488 : &user_info_dc);
489 471 : if (!NT_STATUS_IS_OK(nt_status)) {
490 0 : talloc_free(tmp_ctx);
491 0 : return nt_status;
492 : }
493 :
494 471 : nt_status = auth_generate_session_info(tmp_ctx, lp_ctx, sam_ctx,
495 : user_info_dc,
496 : session_info_flags,
497 : session_info);
498 :
499 471 : if (NT_STATUS_IS_OK(nt_status)) {
500 471 : talloc_steal(mem_ctx, *session_info);
501 : }
502 471 : talloc_free(tmp_ctx);
503 471 : return nt_status;
504 : }
505 :
506 : /**
507 : * prints a struct auth_session_info security token to debug output.
508 : */
509 0 : void auth_session_info_debug(int dbg_lev,
510 : const struct auth_session_info *session_info)
511 : {
512 0 : if (!session_info) {
513 0 : DEBUG(dbg_lev, ("Session Info: (NULL)\n"));
514 0 : return;
515 : }
516 :
517 0 : security_token_debug(DBGC_AUTH, dbg_lev,
518 0 : session_info->security_token);
519 : }
520 :
521 324 : NTSTATUS encode_claims_set(TALLOC_CTX *mem_ctx,
522 : struct CLAIMS_SET *claims_set,
523 : DATA_BLOB *claims_blob)
524 : {
525 324 : TALLOC_CTX *tmp_ctx = NULL;
526 0 : enum ndr_err_code ndr_err;
527 324 : struct CLAIMS_SET_NDR *claims_set_info = NULL;
528 324 : struct CLAIMS_SET_METADATA *metadata = NULL;
529 324 : struct CLAIMS_SET_METADATA_NDR *metadata_ndr = NULL;
530 :
531 324 : if (claims_blob == NULL) {
532 0 : return NT_STATUS_INVALID_PARAMETER_3;
533 : }
534 :
535 324 : tmp_ctx = talloc_new(mem_ctx);
536 324 : if (tmp_ctx == NULL) {
537 0 : return NT_STATUS_NO_MEMORY;
538 : }
539 :
540 324 : metadata_ndr = talloc(tmp_ctx, struct CLAIMS_SET_METADATA_NDR);
541 324 : if (metadata_ndr == NULL) {
542 0 : talloc_free(tmp_ctx);
543 0 : return NT_STATUS_NO_MEMORY;
544 : }
545 :
546 324 : metadata = talloc(metadata_ndr, struct CLAIMS_SET_METADATA);
547 324 : if (metadata == NULL) {
548 0 : talloc_free(tmp_ctx);
549 0 : return NT_STATUS_NO_MEMORY;
550 : }
551 :
552 324 : claims_set_info = talloc(metadata, struct CLAIMS_SET_NDR);
553 324 : if (claims_set_info == NULL) {
554 0 : talloc_free(tmp_ctx);
555 0 : return NT_STATUS_NO_MEMORY;
556 : }
557 :
558 324 : *metadata_ndr = (struct CLAIMS_SET_METADATA_NDR) {
559 : .claims.metadata = metadata,
560 : };
561 :
562 324 : *metadata = (struct CLAIMS_SET_METADATA) {
563 : .claims_set = claims_set_info,
564 : .compression_format = CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF,
565 : };
566 :
567 324 : *claims_set_info = (struct CLAIMS_SET_NDR) {
568 : .claims.claims = claims_set,
569 : };
570 :
571 324 : ndr_err = ndr_push_struct_blob(claims_blob, mem_ctx, metadata_ndr,
572 : (ndr_push_flags_fn_t)ndr_push_CLAIMS_SET_METADATA_NDR);
573 324 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
574 0 : NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
575 0 : DBG_ERR("CLAIMS_SET_METADATA_NDR push failed: %s\n",
576 : nt_errstr(nt_status));
577 :
578 0 : talloc_free(tmp_ctx);
579 0 : return nt_status;
580 : }
581 :
582 324 : talloc_free(tmp_ctx);
583 324 : return NT_STATUS_OK;
584 : }
585 :
586 : /*
587 : * Construct a ‘claims_data’ structure from a claims blob, such as is found in a
588 : * PAC.
589 : */
590 341 : NTSTATUS claims_data_from_encoded_claims_set(TALLOC_CTX *claims_data_ctx,
591 : const DATA_BLOB *encoded_claims_set,
592 : struct claims_data **out)
593 : {
594 341 : struct claims_data *claims_data = NULL;
595 341 : DATA_BLOB data = {};
596 :
597 341 : if (out == NULL) {
598 0 : return NT_STATUS_INVALID_PARAMETER;
599 : }
600 :
601 341 : *out = NULL;
602 :
603 341 : claims_data = talloc(claims_data_ctx, struct claims_data);
604 341 : if (claims_data == NULL) {
605 0 : return NT_STATUS_NO_MEMORY;
606 : }
607 :
608 341 : if (encoded_claims_set != NULL) {
609 : /*
610 : * We make a copy of the data, for it might not be
611 : * talloc‐allocated — we might have obtained it directly with
612 : * krb5_pac_get_buffer().
613 : */
614 341 : data = data_blob_dup_talloc(claims_data, *encoded_claims_set);
615 341 : if (data.length != encoded_claims_set->length) {
616 0 : talloc_free(claims_data);
617 0 : return NT_STATUS_NO_MEMORY;
618 : }
619 : }
620 :
621 341 : *claims_data = (struct claims_data) {
622 : .encoded_claims_set = data,
623 : .flags = CLAIMS_DATA_ENCODED_CLAIMS_PRESENT,
624 : };
625 :
626 341 : *out = claims_data;
627 :
628 341 : return NT_STATUS_OK;
629 : }
630 :
631 : /*
632 : * Construct a ‘claims_data’ structure from a talloc‐allocated claims set, such
633 : * as we might build from searching the database. If this function returns
634 : * successfully, it assumes ownership of the claims set.
635 : */
636 324 : NTSTATUS claims_data_from_claims_set(TALLOC_CTX *claims_data_ctx,
637 : struct CLAIMS_SET *claims_set,
638 : struct claims_data **out)
639 : {
640 324 : struct claims_data *claims_data = NULL;
641 :
642 324 : if (out == NULL) {
643 0 : return NT_STATUS_INVALID_PARAMETER;
644 : }
645 :
646 324 : *out = NULL;
647 :
648 324 : claims_data = talloc(claims_data_ctx, struct claims_data);
649 324 : if (claims_data == NULL) {
650 0 : return NT_STATUS_NO_MEMORY;
651 : }
652 324 : *claims_data = (struct claims_data) {
653 324 : .claims_set = talloc_steal(claims_data, claims_set),
654 : .flags = CLAIMS_DATA_CLAIMS_PRESENT,
655 : };
656 :
657 324 : *out = claims_data;
658 :
659 324 : return NT_STATUS_OK;
660 : }
661 :
662 : /*
663 : * From a ‘claims_data’ structure, return an encoded claims blob that can be put
664 : * into a PAC.
665 : */
666 31144 : NTSTATUS claims_data_encoded_claims_set(TALLOC_CTX *mem_ctx,
667 : struct claims_data *claims_data,
668 : DATA_BLOB *encoded_claims_set_out)
669 : {
670 31144 : uint8_t *data = NULL;
671 1170 : size_t len;
672 :
673 31144 : if (encoded_claims_set_out == NULL) {
674 0 : return NT_STATUS_INVALID_PARAMETER;
675 : }
676 :
677 31144 : *encoded_claims_set_out = data_blob_null;
678 :
679 31144 : if (claims_data == NULL) {
680 30794 : return NT_STATUS_OK;
681 : }
682 :
683 350 : if (!(claims_data->flags & CLAIMS_DATA_ENCODED_CLAIMS_PRESENT)) {
684 0 : NTSTATUS status;
685 :
686 : /* See whether we have a claims set that we can encode. */
687 324 : if (!(claims_data->flags & CLAIMS_DATA_CLAIMS_PRESENT)) {
688 0 : return NT_STATUS_OK;
689 : }
690 :
691 324 : status = encode_claims_set(claims_data,
692 : claims_data->claims_set,
693 : &claims_data->encoded_claims_set);
694 324 : if (!NT_STATUS_IS_OK(status)) {
695 0 : return status;
696 : }
697 :
698 324 : claims_data->flags |= CLAIMS_DATA_ENCODED_CLAIMS_PRESENT;
699 : }
700 :
701 350 : if (claims_data->encoded_claims_set.data != NULL) {
702 350 : data = talloc_reference(mem_ctx, claims_data->encoded_claims_set.data);
703 350 : if (data == NULL) {
704 0 : return NT_STATUS_NO_MEMORY;
705 : }
706 : }
707 350 : len = claims_data->encoded_claims_set.length;
708 :
709 350 : *encoded_claims_set_out = data_blob_const(data, len);
710 350 : return NT_STATUS_OK;
711 : }
712 :
713 : /*
714 : * From a ‘claims_data’ structure, return an array of security claims that can
715 : * be put in a security token for access checks.
716 : */
717 33425 : NTSTATUS claims_data_security_claims(TALLOC_CTX *mem_ctx,
718 : struct claims_data *claims_data,
719 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **security_claims_out,
720 : uint32_t *n_security_claims_out)
721 : {
722 33425 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *security_claims = NULL;
723 881 : uint32_t n_security_claims;
724 881 : NTSTATUS status;
725 :
726 33425 : if (security_claims_out == NULL) {
727 0 : return NT_STATUS_INVALID_PARAMETER;
728 : }
729 :
730 33425 : if (n_security_claims_out == NULL) {
731 0 : return NT_STATUS_INVALID_PARAMETER;
732 : }
733 :
734 33425 : *security_claims_out = NULL;
735 33425 : *n_security_claims_out = 0;
736 :
737 33425 : if (claims_data == NULL) {
738 33127 : return NT_STATUS_OK;
739 : }
740 :
741 298 : if (!(claims_data->flags & CLAIMS_DATA_SECURITY_CLAIMS_PRESENT)) {
742 298 : struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *decoded_claims = NULL;
743 298 : uint32_t n_decoded_claims = 0;
744 :
745 : /* See whether we have a claims set that we can convert. */
746 298 : if (!(claims_data->flags & CLAIMS_DATA_CLAIMS_PRESENT)) {
747 :
748 : /*
749 : * See whether we have an encoded claims set that we can
750 : * decode.
751 : */
752 298 : if (!(claims_data->flags & CLAIMS_DATA_ENCODED_CLAIMS_PRESENT)) {
753 : /* We don’t have anything. */
754 0 : return NT_STATUS_OK;
755 : }
756 :
757 : /* Decode an existing claims set. */
758 :
759 298 : if (claims_data->encoded_claims_set.length) {
760 298 : TALLOC_CTX *tmp_ctx = NULL;
761 0 : struct CLAIMS_SET_METADATA_NDR claims;
762 298 : const struct CLAIMS_SET_METADATA *metadata = NULL;
763 0 : enum ndr_err_code ndr_err;
764 :
765 298 : tmp_ctx = talloc_new(claims_data);
766 298 : if (tmp_ctx == NULL) {
767 0 : return NT_STATUS_NO_MEMORY;
768 : }
769 :
770 298 : ndr_err = ndr_pull_struct_blob(&claims_data->encoded_claims_set,
771 : tmp_ctx,
772 : &claims,
773 : (ndr_pull_flags_fn_t)ndr_pull_CLAIMS_SET_METADATA_NDR);
774 298 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
775 0 : status = ndr_map_error2ntstatus(ndr_err);
776 0 : DBG_ERR("Failed to parse encoded claims set: %s\n",
777 : nt_errstr(status));
778 0 : talloc_free(tmp_ctx);
779 0 : return status;
780 : }
781 :
782 298 : metadata = claims.claims.metadata;
783 298 : if (metadata != NULL) {
784 298 : struct CLAIMS_SET_NDR *claims_set_ndr = metadata->claims_set;
785 298 : if (claims_set_ndr != NULL) {
786 298 : struct CLAIMS_SET **claims_set = &claims_set_ndr->claims.claims;
787 :
788 298 : claims_data->claims_set = talloc_move(claims_data, claims_set);
789 : }
790 : }
791 :
792 298 : talloc_free(tmp_ctx);
793 : }
794 :
795 298 : claims_data->flags |= CLAIMS_DATA_CLAIMS_PRESENT;
796 : }
797 :
798 : /*
799 : * Convert the decoded claims set to the security attribute
800 : * claims format.
801 : */
802 298 : status = token_claims_to_claims_v1(claims_data,
803 298 : claims_data->claims_set,
804 : &decoded_claims,
805 : &n_decoded_claims);
806 298 : if (!NT_STATUS_IS_OK(status)) {
807 17 : return status;
808 : }
809 :
810 281 : claims_data->security_claims = decoded_claims;
811 281 : claims_data->n_security_claims = n_decoded_claims;
812 :
813 281 : claims_data->flags |= CLAIMS_DATA_SECURITY_CLAIMS_PRESENT;
814 : }
815 :
816 281 : if (claims_data->security_claims != NULL) {
817 281 : security_claims = talloc_reference(mem_ctx, claims_data->security_claims);
818 281 : if (security_claims == NULL) {
819 0 : return NT_STATUS_NO_MEMORY;
820 : }
821 : }
822 281 : n_security_claims = claims_data->n_security_claims;
823 :
824 281 : *security_claims_out = security_claims;
825 281 : *n_security_claims_out = n_security_claims;
826 :
827 281 : return NT_STATUS_OK;
828 : }
|