The branch, master has been updated via b475ef0 torture: support printer publish pending responses via 56b0246 torture: add AD printer publishing test via 002d1a4 Fix bug 9900: is_printer_published GUID retrieval via f9b6b09 printing: explicitly clear PUBLISHED attribute from 1f269fc tdb: Add another overflow check to tdb_expand_adjust
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit b475ef008b1a2d2095c9b2276a55e9fbd38a5ca5 Author: David Disseldorp <dd...@samba.org> Date: Wed May 29 10:43:35 2013 +0200 torture: support printer publish pending responses Windows (tested against 2k8r2) returns WERR_IO_PENDING and DSPRINT_PENDING when a publish or unpublish is requested via setprinter(level=7). Modify the AD printer publishing test to support these responses. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> Autobuild-User(master): Andreas Schneider <a...@cryptomilk.org> Autobuild-Date(master): Mon Jun 3 16:06:15 CEST 2013 on sn-devel-104 commit 56b02461626a0d49c47ff5e909b60d10b93afecf Author: David Disseldorp <dd...@samba.org> Date: Wed May 29 10:43:34 2013 +0200 torture: add AD printer publishing test This test publishes and unpublishes a printer using setprinter(level=7). Printer info2.attributes and info7.action flags are check at each point to ensure MS-RPRN conformance. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 002d1a44672c9b3247a68a86899ce6644b696a48 Author: David Disseldorp <dd...@samba.org> Date: Wed May 29 10:43:33 2013 +0200 Fix bug 9900: is_printer_published GUID retrieval Samba currently always responds to GetPrinter(level = 7) requests with DSPRINT_UNPUBLISH, regardless of the AD publish status tracked via the PRINTER_ATTRIBUTE_PUBLISHED flag. This is due to erroneous "objectGUID" unmarshalling in is_printer_published(). This change splits "objectGUID" retrieval into a separate function, and adds a pull_reg_sz() call to correctly unmarshall the GUID. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit f9b6b09e4e4e15257ce0a21caa46e26e119667d4 Author: David Disseldorp <dd...@samba.org> Date: Wed May 29 10:43:32 2013 +0200 printing: explicitly clear PUBLISHED attribute Currently nt_printer_publish(DSPRINT_UNPUBLISH) flips (via xor) the info2->attributes PRINTER_ATTRIBUTE_PUBLISHED flag, rather than explicitly clearing it. Signed-off-by: David Disseldorp <dd...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> ----------------------------------------------------------------------- Summary of changes: selftest/knownfail | 1 + source3/include/nt_printing.h | 6 +- source3/printing/nt_printing_ads.c | 131 +++++++++++++++--------- source3/rpc_server/spoolss/srv_spoolss_nt.c | 40 ++++++-- source3/smbd/server_reload.c | 2 +- source4/torture/rpc/spoolss.c | 148 ++++++++++++++++++++++++++- 6 files changed, 269 insertions(+), 59 deletions(-) Changeset truncated at 500 lines: diff --git a/selftest/knownfail b/selftest/knownfail index a06bab6..313d6c9 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -215,6 +215,7 @@ ^samba3.raw.session.*reauth2 # maybe fix this? ^samba3.rpc.spoolss.printer.addprinter.driver_info_winreg # knownfail or flapping? ^samba3.rpc.spoolss.printer.addprinterex.driver_info_winreg # knownfail or flapping? +^samba3.rpc.spoolss.printer.*.publish_toggle\(.*\)$ # needs spoolss AD member env ^samba3.rpc.spoolss.printserver.*.add_processor\(.*\)$ # # The following tests fail against plugin_s4_dc (aka s3fs) currently. diff --git a/source3/include/nt_printing.h b/source3/include/nt_printing.h index 2243a3d..2a0e883 100644 --- a/source3/include/nt_printing.h +++ b/source3/include/nt_printing.h @@ -132,6 +132,11 @@ bool print_access_check(const struct auth_session_info *server_info, struct messaging_context *msg_ctx, int snum, int access_type); +WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *printer, struct GUID *guid); + WERROR nt_printer_publish(TALLOC_CTX *mem_ctx, const struct auth_session_info *server_info, struct messaging_context *msg_ctx, @@ -143,7 +148,6 @@ bool is_printer_published(TALLOC_CTX *mem_ctx, struct messaging_context *msg_ctx, const char *servername, const char *printer, - struct GUID *guid, struct spoolss_PrinterInfo2 **info2); WERROR check_published_printers(struct messaging_context *msg_ctx); diff --git a/source3/printing/nt_printing_ads.c b/source3/printing/nt_printing_ads.c index 3a2baf4..dcd31b7 100644 --- a/source3/printing/nt_printing_ads.c +++ b/source3/printing/nt_printing_ads.c @@ -87,6 +87,80 @@ done: talloc_free(tmp_ctx); } +WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *printer, struct GUID *guid) +{ + TALLOC_CTX *tmp_ctx; + enum winreg_Type type; + DATA_BLOB blob; + uint32_t len; + NTSTATUS status; + WERROR result; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + DEBUG(0, ("out of memory?!\n")); + return WERR_NOMEM; + } + + result = winreg_get_printer_dataex_internal(tmp_ctx, session_info, + msg_ctx, printer, + SPOOL_DSSPOOLER_KEY, + "objectGUID", + &type, + &blob.data, + &len); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("Failed to get GUID for printer %s\n", printer)); + goto out_ctx_free; + } + blob.length = (size_t)len; + + /* We used to store the guid as REG_BINARY, then swapped + to REG_SZ for Vista compatibility so check for both */ + + switch (type) { + case REG_SZ: { + bool ok; + const char *guid_str; + ok = pull_reg_sz(tmp_ctx, &blob, &guid_str); + if (!ok) { + DEBUG(0, ("Failed to unmarshall GUID for printer %s\n", + printer)); + result = WERR_REG_CORRUPT; + goto out_ctx_free; + } + status = GUID_from_string(guid_str, guid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("bad GUID for printer %s\n", printer)); + result = ntstatus_to_werror(status); + goto out_ctx_free; + } + break; + } + case REG_BINARY: + if (blob.length != sizeof(struct GUID)) { + DEBUG(0, ("bad GUID for printer %s\n", printer)); + result = WERR_REG_CORRUPT; + goto out_ctx_free; + } + memcpy(guid, blob.data, sizeof(struct GUID)); + break; + default: + DEBUG(0,("GUID value stored as invalid type (%d)\n", type)); + result = WERR_REG_CORRUPT; + goto out_ctx_free; + break; + } + result = WERR_OK; + +out_ctx_free: + talloc_free(tmp_ctx); + return result; +} + static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx, struct spoolss_PrinterInfo2 *info2, ADS_MODLIST *mods) @@ -355,7 +429,7 @@ WERROR nt_printer_publish(TALLOC_CTX *mem_ctx, pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED; break; case DSPRINT_UNPUBLISH: - pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED; + pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED); break; default: win_rc = WERR_NOT_SUPPORTED; @@ -481,15 +555,10 @@ bool is_printer_published(TALLOC_CTX *mem_ctx, struct messaging_context *msg_ctx, const char *servername, const char *printer, - struct GUID *guid, struct spoolss_PrinterInfo2 **info2) { struct spoolss_PrinterInfo2 *pinfo2 = NULL; - enum winreg_Type type; - uint8_t *data; - uint32_t data_size; WERROR result; - NTSTATUS status; struct dcerpc_binding_handle *b; result = winreg_printer_binding_handle(mem_ctx, @@ -511,47 +580,6 @@ bool is_printer_published(TALLOC_CTX *mem_ctx, return false; } - if (!guid) { - goto done; - } - - /* fetching printer guids really ought to be a separate function. */ - - result = winreg_get_printer_dataex(mem_ctx, b, - printer, - SPOOL_DSSPOOLER_KEY, "objectGUID", - &type, &data, &data_size); - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(pinfo2); - return false; - } - - /* We used to store the guid as REG_BINARY, then swapped - to REG_SZ for Vista compatibility so check for both */ - - switch (type) { - case REG_SZ: - status = GUID_from_string((char *)data, guid); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(pinfo2); - return false; - } - break; - - case REG_BINARY: - if (data_size != sizeof(struct GUID)) { - TALLOC_FREE(pinfo2); - return false; - } - memcpy(guid, data, sizeof(struct GUID)); - break; - default: - DEBUG(0,("is_printer_published: GUID value stored as " - "invaluid type (%d)\n", type)); - break; - } - -done: if (info2) { *info2 = talloc_move(mem_ctx, &pinfo2); } @@ -559,6 +587,14 @@ done: return true; } #else +WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *printer, struct GUID *guid) +{ + return WERR_NOT_SUPPORTED; +} + WERROR nt_printer_publish(TALLOC_CTX *mem_ctx, const struct auth_session_info *session_info, struct messaging_context *msg_ctx, @@ -578,7 +614,6 @@ bool is_printer_published(TALLOC_CTX *mem_ctx, struct messaging_context *msg_ctx, const char *servername, const char *printer, - struct GUID *guid, struct spoolss_PrinterInfo2 **info2) { return False; diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index 7482443..03c966b 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -4177,21 +4177,47 @@ static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx, struct spoolss_PrinterInfo7 *r, int snum) { - const struct auth_session_info *session_info = get_session_info_system(); - struct GUID guid; + const struct auth_session_info *session_info; + char *printer; + WERROR werr; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + session_info = get_session_info_system(); + SMB_ASSERT(session_info != NULL); - if (is_printer_published(mem_ctx, session_info, msg_ctx, - servername, - lp_servicename(talloc_tos(), snum), &guid, NULL)) { + printer = lp_servicename(tmp_ctx, snum); + if (printer == NULL) { + DEBUG(0, ("invalid printer snum %d\n", snum)); + werr = WERR_INVALID_PARAM; + goto out_tmp_free; + } + + if (is_printer_published(tmp_ctx, session_info, msg_ctx, + servername, printer, NULL)) { + struct GUID guid; + werr = nt_printer_guid_get(tmp_ctx, session_info, msg_ctx, + printer, &guid); + if (!W_ERROR_IS_OK(werr)) { + goto out_tmp_free; + } r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid)); r->action = DSPRINT_PUBLISH; } else { r->guid = talloc_strdup(mem_ctx, ""); r->action = DSPRINT_UNPUBLISH; } - W_ERROR_HAVE_NO_MEMORY(r->guid); + if (r->guid == NULL) { + werr = WERR_NOMEM; + goto out_tmp_free; + } - return WERR_OK; + werr = WERR_OK; +out_tmp_free: + talloc_free(tmp_ctx); + return werr; } /******************************************************************** diff --git a/source3/smbd/server_reload.c b/source3/smbd/server_reload.c index 3a8f5bb..1d6f9c2 100644 --- a/source3/smbd/server_reload.c +++ b/source3/smbd/server_reload.c @@ -106,7 +106,7 @@ void delete_and_reload_printers(struct tevent_context *ev, NULL, lp_servicename(session_info, snum), - NULL, &pinfo2)) { + &pinfo2)) { nt_printer_publish(session_info, session_info, msg_ctx, diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c index 5e6c4c7..4c84bc0 100644 --- a/source4/torture/rpc/spoolss.c +++ b/source4/torture/rpc/spoolss.c @@ -1247,8 +1247,9 @@ static bool test_SetPrinter(struct torture_context *tctx, torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r), "failed to call SetPrinter"); - torture_assert_werr_ok(tctx, r.out.result, - "failed to call SetPrinter"); + torture_assert(tctx, (W_ERROR_EQUAL(r.out.result, WERR_OK) + || W_ERROR_EQUAL(r.out.result, WERR_IO_PENDING)), + "SetPrinter failed"); return true; } @@ -8525,6 +8526,147 @@ static bool test_printer_bidi(struct torture_context *tctx, return true; } +static bool test_printer_set_publish(struct torture_context *tctx, + struct dcerpc_binding_handle *b, + struct policy_handle *handle) +{ + union spoolss_PrinterInfo info; + struct spoolss_SetPrinterInfo7 info7; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_DevmodeContainer devmode_ctr; + struct sec_desc_buf secdesc_ctr; + + info7.guid = ""; + info7.action = DSPRINT_PUBLISH; + + ZERO_STRUCT(info_ctr); + ZERO_STRUCT(devmode_ctr); + ZERO_STRUCT(secdesc_ctr); + info_ctr.level = 7; + info_ctr.info.info7 = &info7; + + torture_assert(tctx, + test_SetPrinter(tctx, b, handle, &info_ctr, + &devmode_ctr, &secdesc_ctr, 0), ""); + + torture_assert(tctx, + test_GetPrinter_level(tctx, b, handle, 2, &info), + ""); + torture_assert(tctx, + (info.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED), + "info2 publish flag not set"); + torture_assert(tctx, + test_GetPrinter_level(tctx, b, handle, 7, &info), + ""); + if (info.info7.action & DSPRINT_PENDING) { + torture_comment(tctx, "publish is pending\n"); + torture_assert_int_equal(tctx, + info.info7.action, + (DSPRINT_PENDING | DSPRINT_PUBLISH), + "info7 publish flag not set"); + } else { + struct GUID guid; + torture_assert_int_equal(tctx, + info.info7.action, + DSPRINT_PUBLISH, + "info7 publish flag not set"); + torture_assert_ntstatus_ok(tctx, + GUID_from_string(info.info7.guid, + &guid), + "invalid published printer GUID"); + } + + return true; +} + +static bool test_printer_set_unpublish(struct torture_context *tctx, + struct dcerpc_binding_handle *b, + struct policy_handle *handle) +{ + union spoolss_PrinterInfo info; + struct spoolss_SetPrinterInfo7 info7; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_DevmodeContainer devmode_ctr; + struct sec_desc_buf secdesc_ctr; + + info7.action = DSPRINT_UNPUBLISH; + info7.guid = ""; + + ZERO_STRUCT(info_ctr); + ZERO_STRUCT(devmode_ctr); + ZERO_STRUCT(secdesc_ctr); + info_ctr.level = 7; + info_ctr.info.info7 = &info7; + + torture_assert(tctx, + test_SetPrinter(tctx, b, handle, &info_ctr, + &devmode_ctr, &secdesc_ctr, 0), ""); + + torture_assert(tctx, + test_GetPrinter_level(tctx, b, handle, 2, &info), + ""); + torture_assert(tctx, + !(info.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED), + "info2 publish flag still set"); + torture_assert(tctx, + test_GetPrinter_level(tctx, b, handle, 7, &info), + ""); + + if (info.info7.action & DSPRINT_PENDING) { + struct GUID guid; + torture_comment(tctx, "unpublish is pending\n"); + torture_assert_int_equal(tctx, + info.info7.action, + (DSPRINT_PENDING | DSPRINT_UNPUBLISH), + "info7 unpublish flag not set"); + torture_assert_ntstatus_ok(tctx, + GUID_from_string(info.info7.guid, + &guid), + "invalid printer GUID"); + } else { + torture_assert_int_equal(tctx, + info.info7.action, DSPRINT_UNPUBLISH, + "info7 unpublish flag not set"); + } + + return true; +} + +static bool test_printer_publish_toggle(struct torture_context *tctx, + void *private_data) +{ + struct torture_printer_context *t = + talloc_get_type_abort(private_data, + struct torture_printer_context); + struct dcerpc_pipe *p = t->spoolss_pipe; + struct dcerpc_binding_handle *b = p->binding_handle; + struct policy_handle *handle = &t->handle; + union spoolss_PrinterInfo info7; + union spoolss_PrinterInfo info2; + + /* check publish status via level 7 and level 2 */ + torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 7, &info7), + ""); + torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info2), + ""); + + if (info2.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED) { + torture_assert_int_equal(tctx, + info7.info7.action, DSPRINT_PUBLISH, + "info7 publish flag not set"); + torture_assert(tctx, test_printer_set_unpublish(tctx, b, handle), ""); + torture_assert(tctx, test_printer_set_publish(tctx, b, handle), ""); + } else { + torture_assert_int_equal(tctx, + info7.info7.action, DSPRINT_UNPUBLISH, + "info7 unpublish flag not set"); + torture_assert(tctx, test_printer_set_publish(tctx, b, handle), ""); + torture_assert(tctx, test_printer_set_unpublish(tctx, b, handle), ""); + } + + return true; +} + static bool test_driver_info_winreg(struct torture_context *tctx, void *private_data) { @@ -8568,6 +8710,8 @@ void torture_tcase_printer(struct torture_tcase *tcase) torture_tcase_add_simple_test(tcase, "printer_rename", test_printer_rename); torture_tcase_add_simple_test(tcase, "printer_ic", test_printer_ic); torture_tcase_add_simple_test(tcase, "bidi", test_printer_bidi); + torture_tcase_add_simple_test(tcase, "publish_toggle", + test_printer_publish_toggle); } struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx) -- Samba Shared Repository