s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.git] / source4 / auth / session.c
index c56917a6f1e06c09efa56d5325c0d5929d05cf29..9c9d8c4aaffdb3339f52836227ea3de36d203662 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    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"
@@ -37,7 +40,7 @@
 #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;
@@ -53,6 +56,8 @@ _PUBLIC_ NTSTATUS auth_generate_security_token(TALLOC_CTX *mem_ctx,
                                               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)
 {
@@ -60,8 +65,10 @@ _PUBLIC_ NTSTATUS auth_generate_security_token(TALLOC_CTX *mem_ctx,
        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) {
@@ -169,10 +176,68 @@ _PUBLIC_ NTSTATUS auth_generate_security_token(TALLOC_CTX *mem_ctx,
                }
        }
 
+       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)) {
@@ -235,6 +300,8 @@ _PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
                                                 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)) {
@@ -425,7 +492,8 @@ NTSTATUS authsam_get_session_info_principal(TALLOC_CTX *mem_ctx,
        }
 
        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)) {
@@ -438,14 +506,323 @@ NTSTATUS authsam_get_session_info_principal(TALLOC_CTX *mem_ctx,
 /**
  * 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;
+}