s3-spoolss: Added winreg security descriptor functions.
authorAndreas Schneider <asn@samba.org>
Tue, 4 May 2010 09:44:12 +0000 (11:44 +0200)
committerGünther Deschner <gd@samba.org>
Wed, 5 May 2010 16:21:54 +0000 (18:21 +0200)
Signed-off-by: Günther Deschner <gd@samba.org>
source3/rpc_server/srv_spoolss_util.c
source3/rpc_server/srv_spoolss_util.h

index 0f6c30513cc8109fcc35dbd6f9eae746a8fabac6..6a96cb90b54fbd9c0bd8bd24531963ebd1230436 100644 (file)
@@ -1779,19 +1779,10 @@ WERROR winreg_update_printer(TALLOC_CTX *mem_ctx,
                                goto done;
                        }
                }
-               ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, NULL, secdesc,
-                               (ndr_push_flags_fn_t) ndr_push_security_descriptor);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       DEBUG(0, ("winreg_update_printer: Failed to marshall security descriptor\n"));
-                       result = WERR_NOMEM;
-                       goto done;
-               }
-
-               result = winreg_printer_write_binary(tmp_ctx,
-                                                    winreg_pipe,
-                                                    &key_hnd,
-                                                    "Security",
-                                                    blob);
+               result = winreg_set_printer_secdesc(tmp_ctx,
+                                                   server_info,
+                                                   sharename,
+                                                   secdesc);
                if (!W_ERROR_IS_OK(result)) {
                        goto done;
                }
@@ -2095,29 +2086,6 @@ WERROR winreg_get_printer(TALLOC_CTX *mem_ctx,
                        }
                }
                CHECK_ERROR(result);
-
-               result = winreg_enumval_to_blob(info2,
-                                               v,
-                                               "Security",
-                                               &blob);
-               if (W_ERROR_IS_OK(result)) {
-                       info2->secdesc = talloc_zero(mem_ctx, struct spoolss_security_descriptor);
-                       if (info2->secdesc == NULL) {
-                               result = WERR_NOMEM;
-                               goto done;
-                       }
-                       ndr_err = ndr_pull_struct_blob(&blob,
-                                                      mem_ctx,
-                                                      NULL,
-                                                      info2->secdesc,
-                                                      (ndr_pull_flags_fn_t) ndr_pull_security_descriptor);
-                       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                               DEBUG(0, ("winreg_get_printer: Failed to unmarshall security descriptor\n"));
-                               result = WERR_NOMEM;
-                               goto done;
-                       }
-               }
-               CHECK_ERROR(result);
        }
 
        if (!W_ERROR_IS_OK(result)) {
@@ -2128,6 +2096,14 @@ WERROR winreg_get_printer(TALLOC_CTX *mem_ctx,
                goto done;
        }
 
+       result = winreg_get_printer_secdesc(info2,
+                                           server_info,
+                                           printer,
+                                           &info2->secdesc);
+       if (!W_ERROR_IS_OK(result)) {
+               goto done;
+       }
+
        if (pinfo2) {
                *pinfo2 = talloc_move(mem_ctx, &info2);
        }
@@ -2147,6 +2123,285 @@ done:
        return result;
 }
 
+WERROR winreg_get_printer_secdesc(TALLOC_CTX *mem_ctx,
+                                 struct auth_serversupplied_info *server_info,
+                                 const char *sharename,
+                                 struct spoolss_security_descriptor **psecdesc)
+{
+       struct spoolss_security_descriptor *secdesc;
+       uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       struct rpc_pipe_client *winreg_pipe = NULL;
+       struct policy_handle hive_hnd, key_hnd;
+       enum ndr_err_code ndr_err;
+       const char *path;
+       DATA_BLOB blob;
+       TALLOC_CTX *tmp_ctx;
+       WERROR result;
+
+       tmp_ctx = talloc_new(mem_ctx);
+       if (tmp_ctx == NULL) {
+               return WERR_NOMEM;
+       }
+
+       path = winreg_printer_data_keyname(tmp_ctx, sharename);
+       if (path == NULL) {
+               talloc_free(tmp_ctx);
+               return WERR_NOMEM;
+       }
+
+       ZERO_STRUCT(hive_hnd);
+       ZERO_STRUCT(key_hnd);
+
+       result = winreg_printer_openkey(tmp_ctx,
+                                       server_info,
+                                       &winreg_pipe,
+                                       path,
+                                       "",
+                                       false,
+                                       access_mask,
+                                       &hive_hnd,
+                                       &key_hnd);
+       if (!W_ERROR_IS_OK(result)) {
+               if (W_ERROR_EQUAL(result, WERR_BADFILE)) {
+                       goto create_default;
+               }
+               goto done;
+       }
+
+       result = winreg_printer_query_binary(tmp_ctx,
+                                            winreg_pipe,
+                                            &key_hnd,
+                                            "Security",
+                                            &blob);
+       if (!W_ERROR_IS_OK(result)) {
+               if (W_ERROR_EQUAL(result, WERR_BADFILE)) {
+                       goto create_default;
+               }
+               goto done;
+       }
+
+       secdesc = talloc_zero(tmp_ctx, struct spoolss_security_descriptor);
+       if (secdesc == NULL) {
+               result = WERR_NOMEM;
+               goto done;
+       }
+       ndr_err = ndr_pull_struct_blob(&blob,
+                                      secdesc,
+                                      NULL,
+                                      secdesc,
+                                      (ndr_pull_flags_fn_t) ndr_pull_security_descriptor);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0, ("winreg_get_secdesc: Failed to unmarshall security descriptor\n"));
+               result = WERR_NOMEM;
+               goto done;
+       }
+
+       if (psecdesc) {
+               *psecdesc = talloc_move(mem_ctx, &secdesc);
+       }
+
+       result = WERR_OK;
+       goto done;
+
+create_default:
+       result = spoolss_create_default_secdesc(tmp_ctx, &secdesc);
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       /* If security descriptor is owned by S-1-1-0 and winbindd is up,
+          this security descriptor has been created when winbindd was
+          down.  Take ownership of security descriptor. */
+       if (sid_equal(secdesc->owner_sid, &global_sid_World)) {
+               DOM_SID owner_sid;
+
+               /* Change sd owner to workgroup administrator */
+
+               if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
+                       struct spoolss_security_descriptor *new_secdesc;
+                       size_t size;
+
+                       /* Create new sd */
+                       sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
+
+                       new_secdesc = make_sec_desc(tmp_ctx,
+                                                   secdesc->revision,
+                                                   secdesc->type,
+                                                   &owner_sid,
+                                                   secdesc->group_sid,
+                                                   secdesc->sacl,
+                                                   secdesc->dacl,
+                                                   &size);
+
+                       if (new_secdesc == NULL) {
+                               result = WERR_NOMEM;
+                               goto done;
+                       }
+
+                       /* Swap with other one */
+                       secdesc = new_secdesc;
+               }
+       }
+
+       ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, NULL, secdesc,
+                       (ndr_push_flags_fn_t) ndr_push_security_descriptor);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0, ("winreg_set_secdesc: Failed to marshall security descriptor\n"));
+               result = WERR_NOMEM;
+               goto done;
+       }
+
+       result = winreg_printer_write_binary(tmp_ctx,
+                                            winreg_pipe,
+                                            &key_hnd,
+                                            "Security",
+                                            blob);
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       if (psecdesc) {
+               *psecdesc = talloc_move(mem_ctx, &secdesc);
+       }
+
+       result = WERR_OK;
+done:
+       if (winreg_pipe != NULL) {
+               if (is_valid_policy_hnd(&key_hnd)) {
+                       rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
+               }
+               if (is_valid_policy_hnd(&hive_hnd)) {
+                       rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
+               }
+       }
+
+       talloc_free(tmp_ctx);
+       return result;
+}
+
+WERROR winreg_set_printer_secdesc(TALLOC_CTX *mem_ctx,
+                                 struct auth_serversupplied_info *server_info,
+                                 const char *sharename,
+                                 const struct spoolss_security_descriptor *secdesc)
+{
+       const struct spoolss_security_descriptor *new_secdesc = secdesc;
+       struct spoolss_security_descriptor *old_secdesc;
+       uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       struct rpc_pipe_client *winreg_pipe = NULL;
+       struct policy_handle hive_hnd, key_hnd;
+       enum ndr_err_code ndr_err;
+       const char *path;
+       DATA_BLOB blob;
+       TALLOC_CTX *tmp_ctx;
+       WERROR result;
+
+       tmp_ctx = talloc_new(mem_ctx);
+       if (tmp_ctx == NULL) {
+               return WERR_NOMEM;
+       }
+
+       path = winreg_printer_data_keyname(tmp_ctx, sharename);
+       if (path == NULL) {
+               talloc_free(tmp_ctx);
+               return WERR_NOMEM;
+       }
+
+       /*
+        * The old owner and group sids of the security descriptor are not
+        * present when new ACEs are added or removed by changing printer
+        * permissions through NT.  If they are NULL in the new security
+        * descriptor then copy them over from the old one.
+        */
+       if (!secdesc->owner_sid || !secdesc->group_sid) {
+               DOM_SID *owner_sid, *group_sid;
+               SEC_ACL *dacl, *sacl;
+               size_t size;
+
+               result = winreg_get_printer_secdesc(tmp_ctx,
+                                                   server_info,
+                                                   sharename,
+                                                   &old_secdesc);
+               if (!W_ERROR_IS_OK(result)) {
+                       talloc_free(tmp_ctx);
+                       return result;
+               }
+
+               /* Pick out correct owner and group sids */
+               owner_sid = secdesc->owner_sid ?
+                           secdesc->owner_sid :
+                           old_secdesc->owner_sid;
+
+               group_sid = secdesc->group_sid ?
+                           secdesc->group_sid :
+                           old_secdesc->group_sid;
+
+               dacl = secdesc->dacl ?
+                      secdesc->dacl :
+                      old_secdesc->dacl;
+
+               sacl = secdesc->sacl ?
+                      secdesc->sacl :
+                      old_secdesc->sacl;
+
+               /* Make a deep copy of the security descriptor */
+               new_secdesc = make_sec_desc(tmp_ctx,
+                                           secdesc->revision,
+                                           secdesc->type,
+                                           owner_sid,
+                                           group_sid,
+                                           sacl,
+                                           dacl,
+                                           &size);
+               if (new_secdesc == NULL) {
+                       talloc_free(tmp_ctx);
+                       return WERR_NOMEM;
+               }
+       }
+
+       ZERO_STRUCT(hive_hnd);
+       ZERO_STRUCT(key_hnd);
+
+       result = winreg_printer_openkey(tmp_ctx,
+                                       server_info,
+                                       &winreg_pipe,
+                                       path,
+                                       "",
+                                       false,
+                                       access_mask,
+                                       &hive_hnd,
+                                       &key_hnd);
+       if (!W_ERROR_IS_OK(result)) {
+               goto done;
+       }
+
+       ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, NULL, new_secdesc,
+                       (ndr_push_flags_fn_t) ndr_push_security_descriptor);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0, ("winreg_set_secdesc: Failed to marshall security descriptor\n"));
+               result = WERR_NOMEM;
+               goto done;
+       }
+
+       result = winreg_printer_write_binary(tmp_ctx,
+                                            winreg_pipe,
+                                            &key_hnd,
+                                            "Security",
+                                            blob);
+
+done:
+       if (winreg_pipe != NULL) {
+               if (is_valid_policy_hnd(&key_hnd)) {
+                       rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &key_hnd, NULL);
+               }
+               if (is_valid_policy_hnd(&hive_hnd)) {
+                       rpccli_winreg_CloseKey(winreg_pipe, tmp_ctx, &hive_hnd, NULL);
+               }
+       }
+
+       talloc_free(tmp_ctx);
+       return result;
+}
+
 /* Set printer data over the winreg pipe. */
 WERROR winreg_set_printer_dataex(TALLOC_CTX *mem_ctx,
                                 struct auth_serversupplied_info *server_info,
index fbb34bb1587e307962e4da56651630c74a5b523b..9b79ce5b67abcaf08ad42434500944cabc0d9a69 100644 (file)
@@ -129,6 +129,44 @@ WERROR winreg_get_printer(TALLOC_CTX *mem_ctx,
                          const char *printer,
                          struct spoolss_PrinterInfo2 **pinfo2);
 
+/**
+ * @brief Get the security descriptor for a printer.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to use.
+ *
+ * @param[in]  server_info The server supplied session info.
+ *
+ * @param[in]  sharename  The share name.
+ *
+ * @param[out] psecdesc   A pointer to store the security descriptor.
+ *
+ * @return              On success WERR_OK, a corresponding DOS error is
+ *                      something went wrong.
+ */
+WERROR winreg_get_printer_secdesc(TALLOC_CTX *mem_ctx,
+                                 struct auth_serversupplied_info *server_info,
+                                 const char *sharename,
+                                 struct spoolss_security_descriptor **psecdesc);
+
+/**
+ * @brief Set the security descriptor for a printer.
+ *
+ * @param[in]  mem_ctx  The talloc memory context to use.
+ *
+ * @param[in]  server_info The server supplied session info.
+ *
+ * @param[in]  sharename  The share name.
+ *
+ * @param[in]  secdesc  The security descriptor to save.
+ *
+ * @return              On success WERR_OK, a corresponding DOS error is
+ *                      something went wrong.
+ */
+WERROR winreg_set_printer_secdesc(TALLOC_CTX *mem_ctx,
+                                 struct auth_serversupplied_info *server_info,
+                                 const char *sharename,
+                                 const struct spoolss_security_descriptor *secdesc);
+
 /**
  * @internal
  *