-/*
+/*
Unix SMB/CIFS implementation.
Authentication utility functions
Copyright (C) Andrew Tridgell 1992-1998
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "auth/credentials/credentials.h"
#include "auth/credentials/credentials_krb5.h"
#include "libcli/security/security.h"
+#include "libcli/security/claims-conversions.h"
#include "libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/claims.h"
+#include "librpc/gen_ndr/ndr_claims.h"
#include "dsdb/samdb/samdb.h"
#include "auth/session_proto.h"
#include "system/kerberos.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
-_PUBLIC_ struct auth_session_info *anonymous_session(TALLOC_CTX *mem_ctx,
+_PUBLIC_ struct auth_session_info *anonymous_session(TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx)
{
NTSTATUS nt_status;
struct loadparm_context *lp_ctx, /* Optional, if you don't want privileges */
struct ldb_context *sam_ctx, /* Optional, if you don't want local groups */
const struct auth_user_info_dc *user_info_dc,
+ const struct auth_user_info_dc *device_info_dc,
+ const struct auth_claims auth_claims,
uint32_t session_info_flags,
struct security_token **_security_token)
{
NTSTATUS nt_status;
uint32_t i;
uint32_t num_sids = 0;
+ uint32_t num_device_sids = 0;
const char *filter = NULL;
struct auth_SidAttr *sids = NULL;
+ struct auth_SidAttr *device_sids = NULL;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
if (tmp_ctx == NULL) {
}
}
+ if (device_info_dc != NULL) {
+ /*
+ * Make a copy of the device SIDs in case we need to add extra SIDs on
+ * the end. One can never have too much copying.
+ */
+ num_device_sids = device_info_dc->num_sids;
+ device_sids = talloc_array(tmp_ctx,
+ struct auth_SidAttr,
+ num_device_sids);
+ if (device_sids == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < num_device_sids; i++) {
+ device_sids[i] = device_info_dc->sids[i];
+ }
+
+ if (session_info_flags & AUTH_SESSION_INFO_DEVICE_DEFAULT_GROUPS) {
+ device_sids = talloc_realloc(tmp_ctx,
+ device_sids,
+ struct auth_SidAttr,
+ num_device_sids + 2);
+ if (device_sids == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ device_sids[num_device_sids++] = (struct auth_SidAttr) {
+ .sid = global_sid_World,
+ .attrs = SE_GROUP_DEFAULT_FLAGS,
+ };
+ device_sids[num_device_sids++] = (struct auth_SidAttr) {
+ .sid = global_sid_Network,
+ .attrs = SE_GROUP_DEFAULT_FLAGS,
+ };
+ }
+
+ if (session_info_flags & AUTH_SESSION_INFO_DEVICE_AUTHENTICATED) {
+ device_sids = talloc_realloc(tmp_ctx,
+ device_sids,
+ struct auth_SidAttr,
+ num_device_sids + 1);
+ if (device_sids == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ device_sids[num_device_sids++] = (struct auth_SidAttr) {
+ .sid = global_sid_Authenticated_Users,
+ .attrs = SE_GROUP_DEFAULT_FLAGS,
+ };
+ }
+ }
+
nt_status = security_token_create(mem_ctx,
lp_ctx,
num_sids,
sids,
+ num_device_sids,
+ device_sids,
+ auth_claims,
session_info_flags,
&security_token);
if (!NT_STATUS_IS_OK(nt_status)) {
lp_ctx,
sam_ctx,
user_info_dc,
+ NULL /*device_info_dc */,
+ (struct auth_claims) {},
session_info_flags,
&session_info->security_token);
if (!NT_STATUS_IS_OK(nt_status)) {
}
nt_status = auth_generate_session_info(tmp_ctx, lp_ctx, sam_ctx,
- user_info_dc, session_info_flags,
+ user_info_dc,
+ session_info_flags,
session_info);
if (NT_STATUS_IS_OK(nt_status)) {
/**
* prints a struct auth_session_info security token to debug output.
*/
-void auth_session_info_debug(int dbg_lev,
+void auth_session_info_debug(int dbg_lev,
const struct auth_session_info *session_info)
{
if (!session_info) {
DEBUG(dbg_lev, ("Session Info: (NULL)\n"));
- return;
+ return;
}
security_token_debug(DBGC_AUTH, dbg_lev,
session_info->security_token);
}
+
+NTSTATUS encode_claims_set(TALLOC_CTX *mem_ctx,
+ struct CLAIMS_SET *claims_set,
+ DATA_BLOB *claims_blob)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ enum ndr_err_code ndr_err;
+ struct CLAIMS_SET_NDR *claims_set_info = NULL;
+ struct CLAIMS_SET_METADATA *metadata = NULL;
+ struct CLAIMS_SET_METADATA_NDR *metadata_ndr = NULL;
+
+ if (claims_blob == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_3;
+ }
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ metadata_ndr = talloc(tmp_ctx, struct CLAIMS_SET_METADATA_NDR);
+ if (metadata_ndr == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ metadata = talloc(metadata_ndr, struct CLAIMS_SET_METADATA);
+ if (metadata == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ claims_set_info = talloc(metadata, struct CLAIMS_SET_NDR);
+ if (claims_set_info == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *metadata_ndr = (struct CLAIMS_SET_METADATA_NDR) {
+ .claims.metadata = metadata,
+ };
+
+ *metadata = (struct CLAIMS_SET_METADATA) {
+ .claims_set = claims_set_info,
+ .compression_format = CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF,
+ };
+
+ *claims_set_info = (struct CLAIMS_SET_NDR) {
+ .claims.claims = claims_set,
+ };
+
+ ndr_err = ndr_push_struct_blob(claims_blob, mem_ctx, metadata_ndr,
+ (ndr_push_flags_fn_t)ndr_push_CLAIMS_SET_METADATA_NDR);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
+ DBG_ERR("CLAIMS_SET_METADATA_NDR push failed: %s\n",
+ nt_errstr(nt_status));
+
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+/*
+ * Construct a ‘claims_data’ structure from a claims blob, such as is found in a
+ * PAC.
+ */
+NTSTATUS claims_data_from_encoded_claims_set(TALLOC_CTX *claims_data_ctx,
+ const DATA_BLOB *encoded_claims_set,
+ struct claims_data **out)
+{
+ struct claims_data *claims_data = NULL;
+ DATA_BLOB data = {};
+
+ if (out == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *out = NULL;
+
+ claims_data = talloc(claims_data_ctx, struct claims_data);
+ if (claims_data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (encoded_claims_set != NULL) {
+ /*
+ * We make a copy of the data, for it might not be
+ * talloc‐allocated — we might have obtained it directly with
+ * krb5_pac_get_buffer().
+ */
+ data = data_blob_dup_talloc(claims_data, *encoded_claims_set);
+ if (data.length != encoded_claims_set->length) {
+ talloc_free(claims_data);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ *claims_data = (struct claims_data) {
+ .encoded_claims_set = data,
+ .flags = CLAIMS_DATA_ENCODED_CLAIMS_PRESENT,
+ };
+
+ *out = claims_data;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Construct a ‘claims_data’ structure from a talloc‐allocated claims set, such
+ * as we might build from searching the database. If this function returns
+ * successfully, it assumes ownership of the claims set.
+ */
+NTSTATUS claims_data_from_claims_set(TALLOC_CTX *claims_data_ctx,
+ struct CLAIMS_SET *claims_set,
+ struct claims_data **out)
+{
+ struct claims_data *claims_data = NULL;
+
+ if (out == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *out = NULL;
+
+ claims_data = talloc(claims_data_ctx, struct claims_data);
+ if (claims_data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ *claims_data = (struct claims_data) {
+ .claims_set = talloc_steal(claims_data, claims_set),
+ .flags = CLAIMS_DATA_CLAIMS_PRESENT,
+ };
+
+ *out = claims_data;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * From a ‘claims_data’ structure, return an encoded claims blob that can be put
+ * into a PAC.
+ */
+NTSTATUS claims_data_encoded_claims_set(TALLOC_CTX *mem_ctx,
+ struct claims_data *claims_data,
+ DATA_BLOB *encoded_claims_set_out)
+{
+ uint8_t *data = NULL;
+ size_t len;
+
+ if (encoded_claims_set_out == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *encoded_claims_set_out = data_blob_null;
+
+ if (claims_data == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ if (!(claims_data->flags & CLAIMS_DATA_ENCODED_CLAIMS_PRESENT)) {
+ NTSTATUS status;
+
+ /* See whether we have a claims set that we can encode. */
+ if (!(claims_data->flags & CLAIMS_DATA_CLAIMS_PRESENT)) {
+ return NT_STATUS_OK;
+ }
+
+ status = encode_claims_set(claims_data,
+ claims_data->claims_set,
+ &claims_data->encoded_claims_set);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ claims_data->flags |= CLAIMS_DATA_ENCODED_CLAIMS_PRESENT;
+ }
+
+ if (claims_data->encoded_claims_set.data != NULL) {
+ data = talloc_reference(mem_ctx, claims_data->encoded_claims_set.data);
+ if (data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ len = claims_data->encoded_claims_set.length;
+
+ *encoded_claims_set_out = data_blob_const(data, len);
+ return NT_STATUS_OK;
+}
+
+/*
+ * From a ‘claims_data’ structure, return an array of security claims that can
+ * be put in a security token for access checks.
+ */
+NTSTATUS claims_data_security_claims(TALLOC_CTX *mem_ctx,
+ struct claims_data *claims_data,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **security_claims_out,
+ uint32_t *n_security_claims_out)
+{
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *security_claims = NULL;
+ uint32_t n_security_claims;
+ NTSTATUS status;
+
+ if (security_claims_out == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (n_security_claims_out == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *security_claims_out = NULL;
+ *n_security_claims_out = 0;
+
+ if (claims_data == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ if (!(claims_data->flags & CLAIMS_DATA_SECURITY_CLAIMS_PRESENT)) {
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *decoded_claims = NULL;
+ uint32_t n_decoded_claims = 0;
+
+ /* See whether we have a claims set that we can convert. */
+ if (!(claims_data->flags & CLAIMS_DATA_CLAIMS_PRESENT)) {
+
+ /*
+ * See whether we have an encoded claims set that we can
+ * decode.
+ */
+ if (!(claims_data->flags & CLAIMS_DATA_ENCODED_CLAIMS_PRESENT)) {
+ /* We don’t have anything. */
+ return NT_STATUS_OK;
+ }
+
+ /* Decode an existing claims set. */
+
+ if (claims_data->encoded_claims_set.length) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct CLAIMS_SET_METADATA_NDR claims;
+ const struct CLAIMS_SET_METADATA *metadata = NULL;
+ enum ndr_err_code ndr_err;
+
+ tmp_ctx = talloc_new(claims_data);
+ if (tmp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_pull_struct_blob(&claims_data->encoded_claims_set,
+ tmp_ctx,
+ &claims,
+ (ndr_pull_flags_fn_t)ndr_pull_CLAIMS_SET_METADATA_NDR);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DBG_ERR("Failed to parse encoded claims set: %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return status;
+ }
+
+ metadata = claims.claims.metadata;
+ if (metadata != NULL) {
+ struct CLAIMS_SET_NDR *claims_set_ndr = metadata->claims_set;
+ if (claims_set_ndr != NULL) {
+ struct CLAIMS_SET **claims_set = &claims_set_ndr->claims.claims;
+
+ claims_data->claims_set = talloc_move(claims_data, claims_set);
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ }
+
+ claims_data->flags |= CLAIMS_DATA_CLAIMS_PRESENT;
+ }
+
+ /*
+ * Convert the decoded claims set to the security attribute
+ * claims format.
+ */
+ status = token_claims_to_claims_v1(claims_data,
+ claims_data->claims_set,
+ &decoded_claims,
+ &n_decoded_claims);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ claims_data->security_claims = decoded_claims;
+ claims_data->n_security_claims = n_decoded_claims;
+
+ claims_data->flags |= CLAIMS_DATA_SECURITY_CLAIMS_PRESENT;
+ }
+
+ if (claims_data->security_claims != NULL) {
+ security_claims = talloc_reference(mem_ctx, claims_data->security_claims);
+ if (security_claims == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ n_security_claims = claims_data->n_security_claims;
+
+ *security_claims_out = security_claims;
+ *n_security_claims_out = n_security_claims;
+
+ return NT_STATUS_OK;
+}