diff options
-rw-r--r-- | source3/rpc_server/srv_spoolss_util.c | 327 | ||||
-rw-r--r-- | source3/rpc_server/srv_spoolss_util.h | 38 |
2 files changed, 329 insertions, 36 deletions
diff --git a/source3/rpc_server/srv_spoolss_util.c b/source3/rpc_server/srv_spoolss_util.c index 0f6c30513c..6a96cb90b5 100644 --- a/source3/rpc_server/srv_spoolss_util.c +++ b/source3/rpc_server/srv_spoolss_util.c @@ -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, diff --git a/source3/rpc_server/srv_spoolss_util.h b/source3/rpc_server/srv_spoolss_util.h index fbb34bb158..9b79ce5b67 100644 --- a/source3/rpc_server/srv_spoolss_util.h +++ b/source3/rpc_server/srv_spoolss_util.h @@ -130,6 +130,44 @@ WERROR winreg_get_printer(TALLOC_CTX *mem_ctx, 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 * * @brief Set printer data over the winreg pipe. |