From e90efa315638c45c161e7418b33faebf1c77647f Mon Sep 17 00:00:00 2001 From: Justin Chevrier Date: Thu, 18 Aug 2011 15:56:57 -0400 Subject: [PATCH 1/6] s3-spoolss: Store the correct structure size --- librpc/idl/spoolss.idl | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/librpc/idl/spoolss.idl b/librpc/idl/spoolss.idl index 4599e3a..edd2490 100644 --- a/librpc/idl/spoolss.idl +++ b/librpc/idl/spoolss.idl @@ -3013,11 +3013,11 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") PROTOCOL_LPR_TYPE = 2 } spoolss_PortProtocol; - typedef [public] struct { + typedef [public,gensize] struct { [charset(UTF16)] uint16 portname[64]; [value(0x00000001)] uint32 version; spoolss_PortProtocol protocol; - [value(sizeof(r))] uint32 size; + [value(ndr_size_spoolss_PortData1(r,ndr->flags))] uint32 size; uint32 reserved; [charset(UTF16)] uint16 hostaddress[49]; [charset(UTF16)] uint16 snmpcommunity[33]; @@ -3031,11 +3031,11 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") uint32 snmp_dev_index; } spoolss_PortData1; - typedef [public] struct { + typedef [public,gensize] struct { [charset(UTF16)] uint16 portname[64]; [value(0x00000002)] uint32 version; spoolss_PortProtocol protocol; - [value(sizeof(r))] uint32 size; + [value(ndr_size_spoolss_PortData2(r,ndr->flags))] uint32 size; uint32 reserved; [charset(UTF16)] uint16 hostaddress[128]; [charset(UTF16)] uint16 snmpcommunity[33]; -- 1.7.3.4 From 6def6a2e5099d891308f72147bd7c93a19ac7977 Mon Sep 17 00:00:00 2001 From: Justin Chevrier Date: Thu, 18 Aug 2011 15:57:36 -0400 Subject: [PATCH 2/6] s3-spoolss: Pull printer URI from CUPS and add support for URIs to printer_list --- librpc/idl/printcap.idl | 1 + source3/include/proto.h | 3 +- source3/param/loadparm.c | 3 +- source3/printing/pcap.c | 24 ++++++++++------- source3/printing/pcap.h | 8 +++--- source3/printing/print_cups.c | 20 ++++++++++++- source3/printing/print_iprint.c | 2 +- source3/printing/print_standard.c | 2 +- source3/printing/printer_list.c | 38 +++++++++++++++++++++----- source3/printing/printer_list.h | 4 ++- source3/rpc_server/spoolss/srv_spoolss_nt.c | 2 + 11 files changed, 78 insertions(+), 29 deletions(-) diff --git a/librpc/idl/printcap.idl b/librpc/idl/printcap.idl index d9c34f3..f025eb2 100644 --- a/librpc/idl/printcap.idl +++ b/librpc/idl/printcap.idl @@ -8,6 +8,7 @@ interface printcap [charset(UTF8),string] uint8 *name; [charset(UTF8),string] uint8 *info; [charset(UTF8),string] uint8 *location; + [charset(UTF8),string] uint8 *uri; } pcap_printer; typedef [public] struct { diff --git a/source3/include/proto.h b/source3/include/proto.h index 47321f3..5c073e2 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1597,7 +1597,8 @@ struct parm_struct *lp_get_parameter(const char *param_name); struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters); bool lp_snum_ok(int iService); void lp_add_one_printer(const char *name, const char *comment, - const char *location, void *pdata); + const char *location, const char *uri, + void *pdata); bool lp_loaded(void); void lp_killunused(struct smbd_server_connection *sconn, bool (*snumused) (struct smbd_server_connection *, int)); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index b0c64c7..1fb5d98 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -8092,7 +8092,8 @@ static void lp_add_auto_services(char *str) ***************************************************************************/ void lp_add_one_printer(const char *name, const char *comment, - const char *location, void *pdata) + const char *location, const char *uri, + void *pdata) { int printers = lp_servicenumber(PRINTERS_NAME); int i; diff --git a/source3/printing/pcap.c b/source3/printing/pcap.c index 62db4f5..14ad6c9 100644 --- a/source3/printing/pcap.c +++ b/source3/printing/pcap.c @@ -44,10 +44,11 @@ struct pcap_cache { char *name; char *comment; char *location; + char *uri; struct pcap_cache *next; }; -bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, const char *comment, const char *location) +bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, const char *comment, const char *location, const char *uri) { struct pcap_cache *p; @@ -57,10 +58,12 @@ bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, cons p->name = SMB_STRDUP(name); p->comment = (comment && *comment) ? SMB_STRDUP(comment) : NULL; p->location = (location && *location) ? SMB_STRDUP(location) : NULL; + p->uri = (uri && *uri) ? SMB_STRDUP(uri) : NULL; - DEBUG(11,("pcap_cache_add_specific: Adding name %s info %s, location: %s\n", + DEBUG(11,("pcap_cache_add_specific: Adding name %s info %s, location: %s, uri: %s\n", p->name, p->comment ? p->comment : "", - p->location ? p->location : "")); + p->location ? p->location : "", + p->uri ? p->uri : "")); p->next = *ppcache; *ppcache = p; @@ -78,17 +81,18 @@ void pcap_cache_destroy_specific(struct pcap_cache **pp_cache) SAFE_FREE(p->name); SAFE_FREE(p->comment); SAFE_FREE(p->location); + SAFE_FREE(p->uri); SAFE_FREE(p); } *pp_cache = NULL; } -bool pcap_cache_add(const char *name, const char *comment, const char *location) +bool pcap_cache_add(const char *name, const char *comment, const char *location, const char *uri) { NTSTATUS status; time_t t = time_mono(NULL); - status = printer_list_set_printer(talloc_tos(), name, comment, location, t); + status = printer_list_set_printer(talloc_tos(), name, comment, location, uri, t); return NT_STATUS_IS_OK(status); } @@ -113,7 +117,7 @@ bool pcap_cache_replace(const struct pcap_cache *pcache) } for (p = pcache; p; p = p->next) { - pcap_cache_add(p->name, p->comment, p->location); + pcap_cache_add(p->name, p->comment, p->location, p->uri); } status = printer_list_clean_old(); @@ -209,7 +213,7 @@ bool pcap_printername_ok(const char *printername) { NTSTATUS status; - status = printer_list_get_printer(talloc_tos(), printername, NULL, NULL, 0); + status = printer_list_get_printer(talloc_tos(), printername, NULL, NULL, NULL, 0); return NT_STATUS_IS_OK(status); } @@ -218,18 +222,18 @@ run a function on each printer name in the printcap file. ***************************************************************************/ void pcap_printer_fn_specific(const struct pcap_cache *pc, - void (*fn)(const char *, const char *, const char *, void *), + void (*fn)(const char *, const char *, const char *, const char *, void *), void *pdata) { const struct pcap_cache *p; for (p = pc; p != NULL; p = p->next) - fn(p->name, p->comment, p->location, pdata); + fn(p->name, p->comment, p->location, p->uri, pdata); return; } -void pcap_printer_fn(void (*fn)(const char *, const char *, const char *, void *), void *pdata) +void pcap_printer_fn(void (*fn)(const char *, const char *, const char *, const char *, void *), void *pdata) { NTSTATUS status; diff --git a/source3/printing/pcap.h b/source3/printing/pcap.h index 7056213..6a7cce8 100644 --- a/source3/printing/pcap.h +++ b/source3/printing/pcap.h @@ -33,13 +33,13 @@ struct pcap_cache; /* The following definitions come from printing/pcap.c */ -bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, const char *comment, const char *location); +bool pcap_cache_add_specific(struct pcap_cache **ppcache, const char *name, const char *comment, const char *location, const char *uri); void pcap_cache_destroy_specific(struct pcap_cache **ppcache); -bool pcap_cache_add(const char *name, const char *comment, const char *location); +bool pcap_cache_add(const char *name, const char *comment, const char *location, const char *uri); bool pcap_cache_loaded(void); bool pcap_cache_replace(const struct pcap_cache *cache); -void pcap_printer_fn_specific(const struct pcap_cache *, void (*fn)(const char *, const char *, const char *, void *), void *); -void pcap_printer_fn(void (*fn)(const char *, const char *, const char *, void *), void *); +void pcap_printer_fn_specific(const struct pcap_cache *, void (*fn)(const char *, const char *, const char *, const char *, void *), void *); +void pcap_printer_fn(void (*fn)(const char *, const char *, const char *, const char *, void *), void *); void pcap_cache_reload(struct tevent_context *ev, struct messaging_context *msg_ctx, diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c index b8bbddf..371a752 100644 --- a/source3/printing/print_cups.c +++ b/source3/printing/print_cups.c @@ -164,6 +164,7 @@ static bool process_cups_printers_response(TALLOC_CTX *mem_ctx, char *name; char *info; char *location = NULL; + char *uri = NULL; struct pcap_printer *printer; bool ret_ok = false; @@ -217,6 +218,17 @@ static bool process_cups_printers_response(TALLOC_CTX *mem_ctx, } } + if (strcmp(attr->name, "device-uri") == 0 && + attr->value_tag == IPP_TAG_URI) { + if (!pull_utf8_talloc(mem_ctx, + &uri, + attr->values[0].string.text, + &size)) { + goto err_out; + } + DEBUG(5, ("CUPS DEVICE URI: %s\n", uri)); + } + attr = attr->next; } @@ -241,6 +253,7 @@ static bool process_cups_printers_response(TALLOC_CTX *mem_ctx, pcap_data->printers[pcap_data->count].name = name; pcap_data->printers[pcap_data->count].info = info; pcap_data->printers[pcap_data->count].location = location; + pcap_data->printers[pcap_data->count].uri = uri; pcap_data->count++; } @@ -265,7 +278,8 @@ static bool cups_cache_reload_async(int fd) { "printer-name", "printer-info", - "printer-location" + "printer-location", + "device-uri" }; bool ret = False; enum ndr_err_code ndr_ret; @@ -335,6 +349,7 @@ static bool cups_cache_reload_async(int fd) * attributes-charset * attributes-natural-language * requested-attributes + * device-uri */ request = ippNew(); @@ -492,7 +507,8 @@ static void cups_async_callback(struct event_context *event_ctx, ret_ok = pcap_cache_add_specific(&tmp_pcap_cache, pcap_data.printers[i].name, pcap_data.printers[i].info, - pcap_data.printers[i].location); + pcap_data.printers[i].location, + pcap_data.printers[i].uri); if (!ret_ok) { DEBUG(0, ("failed to add to tmp pcap cache\n")); goto err_out; diff --git a/source3/printing/print_iprint.c b/source3/printing/print_iprint.c index 1392cba..0efd7f6 100644 --- a/source3/printing/print_iprint.c +++ b/source3/printing/print_iprint.c @@ -297,7 +297,7 @@ static int iprint_cache_add_printer(http_t *http, */ if (name != NULL && !secure && smb_enabled) - pcap_cache_add(name, info, NULL); + pcap_cache_add(name, info, NULL, NULL); } out: diff --git a/source3/printing/print_standard.c b/source3/printing/print_standard.c index c4f9c5b..1bbffa8 100644 --- a/source3/printing/print_standard.c +++ b/source3/printing/print_standard.c @@ -117,7 +117,7 @@ bool std_pcap_cache_reload(const char *pcap_name) } } - if (*name && !pcap_cache_add(name, comment, NULL)) { + if (*name && !pcap_cache_add(name, comment, NULL, NULL)) { x_fclose(pcap_file); return false; } diff --git a/source3/printing/printer_list.c b/source3/printing/printer_list.c index 82c43bf..4584da2 100644 --- a/source3/printing/printer_list.c +++ b/source3/printing/printer_list.c @@ -28,7 +28,7 @@ #define PL_KEY_PREFIX "PRINTERLIST/PRN/" #define PL_KEY_FORMAT PL_KEY_PREFIX"%s" #define PL_TIMESTAMP_KEY "PRINTERLIST/GLOBAL/LAST_REFRESH" -#define PL_DATA_FORMAT "ddPPP" +#define PL_DATA_FORMAT "ddPPPP" #define PL_TSTAMP_FORMAT "dd" static struct db_context *get_printer_list_db(void) @@ -67,6 +67,7 @@ NTSTATUS printer_list_get_printer(TALLOC_CTX *mem_ctx, const char *name, const char **comment, const char **location, + const char **uri, time_t *last_refresh) { struct db_context *db; @@ -76,6 +77,7 @@ NTSTATUS printer_list_get_printer(TALLOC_CTX *mem_ctx, char *nstr = NULL; char *cstr = NULL; char *lstr = NULL; + char *ustr = NULL; NTSTATUS status; int ret; @@ -99,7 +101,7 @@ NTSTATUS printer_list_get_printer(TALLOC_CTX *mem_ctx, ret = tdb_unpack(data.dptr, data.dsize, PL_DATA_FORMAT, - &time_h, &time_l, &nstr, &cstr, &lstr); + &time_h, &time_l, &nstr, &cstr, &lstr, &ustr); if (ret == -1) { DEBUG(1, ("Failed to un pack printer data")); status = NT_STATUS_INTERNAL_DB_CORRUPTION; @@ -128,6 +130,15 @@ NTSTATUS printer_list_get_printer(TALLOC_CTX *mem_ctx, } } + if (uri) { + *uri = talloc_strdup(mem_ctx, ustr); + if (*uri == NULL) { + DEBUG(1, ("Failed to strdup uri!\n")); + status = NT_STATUS_NO_MEMORY; + goto done; + } + } + status = NT_STATUS_OK; done: @@ -141,6 +152,7 @@ NTSTATUS printer_list_set_printer(TALLOC_CTX *mem_ctx, const char *name, const char *comment, const char *location, + const char *uri, time_t last_refresh) { struct db_context *db; @@ -150,6 +162,7 @@ NTSTATUS printer_list_set_printer(TALLOC_CTX *mem_ctx, uint32_t time_h, time_l; const char *str = NULL; const char *str2 = NULL; + const char *str3 = NULL; NTSTATUS status; int len; @@ -176,12 +189,17 @@ NTSTATUS printer_list_set_printer(TALLOC_CTX *mem_ctx, str2 = ""; } + if (uri) { + str3 = uri; + } else { + str3 = ""; + } time_64 = last_refresh; time_l = time_64 & 0xFFFFFFFFL; time_h = time_64 >> 32; - len = tdb_pack(NULL, 0, PL_DATA_FORMAT, time_h, time_l, name, str, str2); + len = tdb_pack(NULL, 0, PL_DATA_FORMAT, time_h, time_l, name, str, str2, str3); data.dptr = talloc_array(key, uint8_t, len); if (!data.dptr) { @@ -311,6 +329,7 @@ static int printer_list_clean_fn(struct db_record *rec, void *private_data) char *name; char *comment; char *location; + char *uri; int ret; /* skip anything that does not contain PL_DATA_FORMAT data */ @@ -321,7 +340,7 @@ static int printer_list_clean_fn(struct db_record *rec, void *private_data) ret = tdb_unpack(rec->value.dptr, rec->value.dsize, PL_DATA_FORMAT, &time_h, &time_l, &name, &comment, - &location); + &location, &uri); if (ret == -1) { DEBUG(1, ("Failed to un pack printer data")); state->status = NT_STATUS_INTERNAL_DB_CORRUPTION; @@ -331,6 +350,7 @@ static int printer_list_clean_fn(struct db_record *rec, void *private_data) SAFE_FREE(name); SAFE_FREE(comment); SAFE_FREE(location); + SAFE_FREE(uri); refresh = (time_t)(((uint64_t)time_h << 32) + time_l); @@ -366,7 +386,7 @@ NTSTATUS printer_list_clean_old(void) } struct printer_list_exec_state { - void (*fn)(const char *, const char *, const char *, void *); + void (*fn)(const char *, const char *, const char *, const char *, void *); void *private_data; NTSTATUS status; }; @@ -379,6 +399,7 @@ static int printer_list_exec_fn(struct db_record *rec, void *private_data) char *name; char *comment; char *location; + char *uri; int ret; /* always skip PL_TIMESTAMP_KEY key */ @@ -388,22 +409,23 @@ static int printer_list_exec_fn(struct db_record *rec, void *private_data) ret = tdb_unpack(rec->value.dptr, rec->value.dsize, PL_DATA_FORMAT, &time_h, &time_l, &name, &comment, - &location); + &location, &uri); if (ret == -1) { DEBUG(1, ("Failed to un pack printer data")); state->status = NT_STATUS_INTERNAL_DB_CORRUPTION; return -1; } - state->fn(name, comment, location, state->private_data); + state->fn(name, comment, location, uri, state->private_data); SAFE_FREE(name); SAFE_FREE(comment); SAFE_FREE(location); + SAFE_FREE(uri); return 0; } -NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *, void *), +NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *, const char *, void *), void *private_data) { struct printer_list_exec_state state; diff --git a/source3/printing/printer_list.h b/source3/printing/printer_list.h index fb2e007..c5dd88b 100644 --- a/source3/printing/printer_list.h +++ b/source3/printing/printer_list.h @@ -44,6 +44,7 @@ NTSTATUS printer_list_get_printer(TALLOC_CTX *mem_ctx, const char *name, const char **comment, const char **location, + const char **uri, time_t *last_refresh); /** @@ -67,6 +68,7 @@ NTSTATUS printer_list_set_printer(TALLOC_CTX *mem_ctx, const char *name, const char *comment, const char *location, + const char *uri, time_t last_refresh); /** @@ -100,6 +102,6 @@ NTSTATUS printer_list_mark_reload(void); */ NTSTATUS printer_list_clean_old(void); -NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *, void *), +NTSTATUS printer_list_run_fn(void (*fn)(const char *, const char *, const char *, const char *, void *), void *private_data); #endif /* _PRINTER_LIST_H_ */ diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index a2f8d68..6403805 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -2908,6 +2908,7 @@ static void spoolss_notify_location(struct messaging_context *msg_ctx, pinfo2->sharename, NULL, &loc, + NULL, NULL); if (NT_STATUS_IS_OK(status)) { if (loc == NULL) { @@ -4056,6 +4057,7 @@ static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx, info2->sharename, NULL, &loc, + NULL, NULL); if (NT_STATUS_IS_OK(nt_status)) { if (loc != NULL) { -- 1.7.3.4 From f79729516e904d51b2eec15e575a5fb55e594462 Mon Sep 17 00:00:00 2001 From: Justin Chevrier Date: Thu, 18 Aug 2011 15:58:46 -0400 Subject: [PATCH 3/6] s3-spoolss: Add port registry functions --- source3/registry/reg_backend_db.c | 2 +- source3/rpc_client/cli_winreg_spoolss.c | 615 +++++++++++++++++++++++++ source3/rpc_client/cli_winreg_spoolss.h | 108 +++++ source3/rpc_server/spoolss/srv_spoolss_util.c | 51 ++ source3/rpc_server/spoolss/srv_spoolss_util.h | 15 + 5 files changed, 790 insertions(+), 1 deletions(-) diff --git a/source3/registry/reg_backend_db.c b/source3/registry/reg_backend_db.c index 58e7b33..9a1a3fb 100644 --- a/source3/registry/reg_backend_db.c +++ b/source3/registry/reg_backend_db.c @@ -89,7 +89,7 @@ static const char *builtin_registry_paths[] = { KEY_GP_USER_POLICY, KEY_GP_USER_WIN_POLICY, "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions", - "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors", + "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\Standard TCP/IP Port\\Ports", KEY_PROD_OPTIONS, "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\DefaultUserConfiguration", KEY_TCPIP_PARAMS, diff --git a/source3/rpc_client/cli_winreg_spoolss.c b/source3/rpc_client/cli_winreg_spoolss.c index 2a6a8d1..3159e0b 100644 --- a/source3/rpc_client/cli_winreg_spoolss.c +++ b/source3/rpc_client/cli_winreg_spoolss.c @@ -36,6 +36,8 @@ #define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers" #define TOP_LEVEL_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print" #define TOP_LEVEL_CONTROL_FORMS_KEY TOP_LEVEL_CONTROL_KEY "\\Forms" +#define TOP_LEVEL_PORT_KEY "\\Monitors\\Standard TCP/IP Port" +#define TOP_LEVEL_PORT_PORTS_KEY TOP_LEVEL_CONTROL_KEY TOP_LEVEL_PORT_KEY "\\Ports" #define EMPTY_STRING "" @@ -3979,3 +3981,616 @@ done: TALLOC_FREE(tmp_ctx); return result; } + +/** + * @brief Create the registry keyname for the given port. + * + * @param[in] mem_ctx The memory context to use. + * + * @param[in] port The name of the port to get the registry key. + * + * @return The registry key or NULL on error. + */ +static char *winreg_port_data_keyname(TALLOC_CTX *mem_ctx, const char *port) { + return talloc_asprintf(mem_ctx, "%s\\%s", TOP_LEVEL_PORT_PORTS_KEY, port); +} + +WERROR winreg_update_port(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *winreg_handle, + const char *portname, + uint32_t data1_mask, + struct spoolss_PortData1 *data1) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + int snum = lp_servicenumber(portname); + enum ndr_err_code ndr_err; + DATA_BLOB blob; + char *path; + WERROR result = WERR_OK; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_port_data_keyname(tmp_ctx, portname); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + winreg_handle, + path, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_update_port: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + if (data1_mask & SPOOLSS_PORT_DATA_DBLSPOOL) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "Double Spool", + data1->dblspool, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_HOSTNAME) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "HostName", + data1->hostaddress, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_HWADDRESS) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "HWAddress", + data1->hardware_address, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_IPADDRESS) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "IPAddress", + data1->ip_address, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_PORTNUMBER) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "PortNumber", + data1->port_number, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_PROTOCOL) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "Protocol", + data1->protocol, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_QUEUE) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Queue", + data1->queue, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_SNMPCOMMUNITY) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "SNMP Community", + data1->snmpcommunity, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_SNMPENABLED) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "SNMP Enabled", + data1->snmp_enabled, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_SNMPINDEX) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "SNMP Index", + data1->snmp_dev_index, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + if (data1_mask & SPOOLSS_PORT_DATA_VERSION) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "Version", + data1->version, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_get_port(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *winreg_handle, + const char *port, + struct spoolss_PortData1 **pdata1) +{ + struct spoolss_PortData1 *data1; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + struct spoolss_PrinterEnumValues enum_value; + struct spoolss_PrinterEnumValues *v = NULL; + enum ndr_err_code ndr_err; + uint32_t num_values = 0; + uint32_t i; + char *path; + NTSTATUS status; + WERROR result = WERR_OK; + TALLOC_CTX *tmp_ctx; + + const char **enum_names = NULL; + enum winreg_Type *enum_types = NULL; + DATA_BLOB *enum_data_blobs = NULL; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_port_data_keyname(tmp_ctx, port); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + result = winreg_printer_openkey(tmp_ctx, + winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_get_port: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_enumvals(tmp_ctx, + winreg_handle, + &key_hnd, + &num_values, + &enum_names, + &enum_types, + &enum_data_blobs, + &result); + + if (!NT_STATUS_IS_OK(status)){ + result = ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_get_port: Could not enumerate values in %s: %s\n", + path, win_errstr(result))); + goto done; + } + + data1 = talloc_zero(tmp_ctx, struct spoolss_PortData1); + if (data1 == NULL) { + result = WERR_NOMEM; + goto done; + } + + FILL_STRING(data1, port, data1->portname); + FILL_STRING(data1, EMPTY_STRING, data1->hostaddress); + FILL_STRING(data1, EMPTY_STRING, data1->hardware_address); + FILL_STRING(data1, EMPTY_STRING, data1->ip_address); + FILL_STRING(data1, EMPTY_STRING, data1->queue); + FILL_STRING(data1, EMPTY_STRING, data1->snmpcommunity); + FILL_STRING(data1, EMPTY_STRING, data1->device_type); + + for (i = 0; i < num_values; i++) { + enum_value.value_name = enum_names[i]; + enum_value.value_name_len = 2*strlen_m_term(enum_names[i]); + enum_value.type = enum_types[i]; + enum_value.data_length = enum_data_blobs[i].length; + enum_value.data = NULL; + if (enum_value.data_length != 0){ + enum_value.data = &enum_data_blobs[i]; + } + v = &enum_value; + + result = winreg_enumval_to_dword(data1, + v, + "Double Spool", + &data1->dblspool); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(data1, + v, + "HostName", + &data1->hostaddress); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(data1, + v, + "HWAddress", + &data1->hardware_address); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(data1, + v, + "IPAddress", + &data1->ip_address); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(data1, + v, + "PortNumber", + &data1->port_number); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(data1, + v, + "Protocol", + &data1->protocol); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(data1, + v, + "Queue", + &data1->queue); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(data1, + v, + "SNMP Community", + &data1->snmpcommunity); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(data1, + v, + "SNMP Enabled", + &data1->snmp_enabled); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(data1, + v, + "SNMP Index", + &data1->snmp_dev_index); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(data1, + v, + "Version", + &data1->version); + CHECK_ERROR(result); + } + + if (pdata1) { + *pdata1 = talloc_move(mem_ctx, &data1); + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_create_port(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *winreg_handle, + const char *portname, + const char *ipaddress) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + struct spoolss_PortData1 *data1; + struct winreg_String wkey, wkeyclass; + const char *path; + uint32_t i; + uint32_t data1_mask = 0; + WERROR result = WERR_OK; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_port_data_keyname(tmp_ctx, portname); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_create_port: Skipping, %s already exists\n", path)); + goto done; + } else if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + DEBUG(2, ("winreg_create_port: Creating default values in %s\n", path)); + } else if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_create_port: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + /* Create the main key */ + result = winreg_printer_openkey(tmp_ctx, + winreg_handle, + path, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_create_port: Could not create key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); + } + + data1 = talloc_zero(tmp_ctx, struct spoolss_PortData1); + if (data1 == NULL) { + result = WERR_NOMEM; + goto done; + } + + data1->hostaddress = ""; + data1_mask |= SPOOLSS_PORT_DATA_HOSTNAME; + + data1->hardware_address = ""; + data1_mask |= SPOOLSS_PORT_DATA_HWADDRESS; + + data1->ip_address = ipaddress; + data1_mask |= SPOOLSS_PORT_DATA_IPADDRESS; + + data1->port_number = 9100; + data1_mask |= SPOOLSS_PORT_DATA_PORTNUMBER; + + data1->protocol = 1; + data1_mask |= SPOOLSS_PORT_DATA_PROTOCOL; + + data1->snmpcommunity = "public"; + data1_mask |= SPOOLSS_PORT_DATA_SNMPCOMMUNITY; + + data1->snmp_enabled = 1; + data1_mask |= SPOOLSS_PORT_DATA_SNMPENABLED; + + data1->snmp_dev_index = 1; + data1_mask |= SPOOLSS_PORT_DATA_SNMPINDEX; + + data1->version = 1; + data1_mask |= SPOOLSS_PORT_DATA_VERSION; + + result = winreg_update_port(tmp_ctx, + winreg_handle, + portname, + data1_mask, + data1); + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + talloc_free(tmp_ctx); + return result; +} + +/* Enumerate the subkeys of a given key */ +WERROR winreg_enum_ports_key(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *winreg_handle, + uint32_t *pnum_subkeys, + const char ***psubkeys) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + char *path; + const char **subkeys = NULL; + uint32_t num_subkeys = -1; + + WERROR result = WERR_OK; + NTSTATUS status; + + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = TOP_LEVEL_PORT_PORTS_KEY; + + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_enum_ports: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_enum_keys(tmp_ctx, + winreg_handle, + &key_hnd, + &num_subkeys, + &subkeys, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_enum_ports: Could not enumerate subkeys in %s: %s\n", + path, win_errstr(result))); + goto done; + } + + *pnum_subkeys = num_subkeys; + if (psubkeys) { + *psubkeys = talloc_move(mem_ctx, &subkeys); + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} diff --git a/source3/rpc_client/cli_winreg_spoolss.h b/source3/rpc_client/cli_winreg_spoolss.h index aa4d98f..6cd6863 100644 --- a/source3/rpc_client/cli_winreg_spoolss.h +++ b/source3/rpc_client/cli_winreg_spoolss.h @@ -24,6 +24,34 @@ struct dcerpc_binding_handle; +enum spoolss_PortData1Mask { + SPOOLSS_PORT_DATA_DBLSPOOL = (int)(0x00000001), + SPOOLSS_PORT_DATA_HOSTNAME = (int)(0x00000002), + SPOOLSS_PORT_DATA_HWADDRESS = (int)(0x00000004), + SPOOLSS_PORT_DATA_IPADDRESS = (int)(0x00000008), + SPOOLSS_PORT_DATA_PORTNUMBER = (int)(0x00000010), + SPOOLSS_PORT_DATA_PROTOCOL = (int)(0x00000020), + SPOOLSS_PORT_DATA_QUEUE = (int)(0x00000040), + SPOOLSS_PORT_DATA_SNMPCOMMUNITY = (int)(0x00000080), + SPOOLSS_PORT_DATA_SNMPENABLED = (int)(0x00000100), + SPOOLSS_PORT_DATA_SNMPINDEX = (int)(0x00000200), + SPOOLSS_PORT_DATA_VERSION = (int)(0x00000400), +}; + +#define SPOOLSS_PORT_DATA_ALL SPOOLSS_PORT_DATA_DBLSPOOL | \ + SPOOLSS_PORT_DATA_HOSTNAME | \ + SPOOLSS_PORT_DATA_HWADDRESS | \ + SPOOLSS_PORT_DATA_IPADDRESS | \ + SPOOLSS_PORT_DATA_PORTNUMBER | \ + SPOOLSS_PORT_DATA_PROTOCOL | \ + SPOOLSS_PORT_DATA_QUEUE | \ + SPOOLSS_PORT_DATA_SNMPCOMMUNITY | \ + SPOOLSS_PORT_DATA_SNMPENABLED | \ + SPOOLSS_PORT_DATA_SNMPINDEX | \ + SPOOLSS_PORT_DATA_VERSION + + + enum spoolss_PrinterInfo2Mask { SPOOLSS_PRINTER_INFO_ATTRIBUTES = (int)(0x00000001), SPOOLSS_PRINTER_INFO_AVERAGEPPM = (int)(0x00000002), @@ -566,4 +594,84 @@ WERROR winreg_get_driver_list(TALLOC_CTX *mem_ctx, uint32_t *num_drivers, const char ***drivers); +/** + * @brief Get the inforamtion of a port stored in the registry. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] b The dcerpc binding handle + * + * @param[in] port The name of the port to get. + * + * @param[out] pdata1 A pointer to store a PRINTER_INFO_2 structure. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_get_port(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *b, + const char *port, + struct spoolss_PortData1 **pdata1); + +/** + * @brief Create a new port in the registry. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] b The dcerpc binding handle + * + * @param[in] portname The name of the port to get. + * + * @param[in] ipaddress The IP address of the port + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_create_port(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *b, + const char *portname, + const char *ipaddress); + +/** + * @brief Update the information of a port in the registry. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] b The dcerpc binding handle + * + * @param[in] portname The name of the port to get. + * + * @param[in] data1_mask A bitmask which defines which values should be set. + * + * @param[out] data1 The structure that holds the port information + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_update_port(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *b, + const char *portname, + uint32_t data1_mask, + struct spoolss_PortData1 *data1); + +/** + * @brief Enumerate a list of ports from the registry. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] b The dcerpc binding handle + * + * @param[out] pnum_subkeys A pointer to store the number of subkeys found. + * + * @param[in] psubkeys A pointer to an array to store the names of the subkeys + * found. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_enum_ports_key(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *b, + uint32_t *pnum_subkeys, + const char ***psubkeys); + #endif /* _RPC_CLIENT_CLI_WINREG_SPOOLSS_H_ */ diff --git a/source3/rpc_server/spoolss/srv_spoolss_util.c b/source3/rpc_server/spoolss/srv_spoolss_util.c index 8f346a9..ed7bfa1 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_util.c +++ b/source3/rpc_server/spoolss/srv_spoolss_util.c @@ -754,3 +754,54 @@ WERROR winreg_enum_printer_key_internal(TALLOC_CTX *mem_ctx, talloc_free(tmp_ctx); return result; } + +WERROR winreg_enum_ports_key_internal(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + uint32_t *pnum_subkeys, + const char ***psubkeys) +{ + WERROR result; + struct dcerpc_binding_handle *b; + + result = winreg_printer_binding_handle(mem_ctx, session_info, msg_ctx, &b); + W_ERROR_NOT_OK_RETURN(result); + + return winreg_enum_ports_key(mem_ctx, b, + pnum_subkeys, + psubkeys); +} + +WERROR winreg_get_port_internal(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *port, + struct spoolss_PortData1 **pdata1) +{ + WERROR result; + struct dcerpc_binding_handle *b; + + result = winreg_printer_binding_handle(mem_ctx, session_info, msg_ctx, &b); + W_ERROR_NOT_OK_RETURN(result); + + return winreg_get_port(mem_ctx, b, + port, + pdata1); +} + +WERROR winreg_create_port_internal(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *portname, + const char *ipaddress) +{ + WERROR result; + struct dcerpc_binding_handle *b; + + result = winreg_printer_binding_handle(mem_ctx, session_info, msg_ctx, &b); + W_ERROR_NOT_OK_RETURN(result); + + return winreg_create_port(mem_ctx, b, + portname, + ipaddress); +} diff --git a/source3/rpc_server/spoolss/srv_spoolss_util.h b/source3/rpc_server/spoolss/srv_spoolss_util.h index 8d6fb78..a43c133 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_util.h +++ b/source3/rpc_server/spoolss/srv_spoolss_util.h @@ -157,4 +157,19 @@ WERROR winreg_enum_printer_key_internal(TALLOC_CTX *mem_ctx, const char *key, uint32_t *pnum_subkeys, const char ***psubkeys); +WERROR winreg_enum_ports_key_internal(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + uint32_t *pnum_subkeys, + const char ***psubkeys); +WERROR winreg_get_port_internal(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *port, + struct spoolss_PortData1 **pdata1); +WERROR winreg_create_port_internal(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *portname, + const char *ipaddress); #endif /* _SRV_SPOOLSS_UITL_H */ -- 1.7.3.4 From 1b35cc68e378c5022bb2c36940102940dc6d1e5c Mon Sep 17 00:00:00 2001 From: Justin Chevrier Date: Tue, 30 Aug 2011 11:22:41 -0400 Subject: [PATCH 4/6] s3-spoolss: Hookup port creation basing name on parsed CUPS URIs --- source3/rpc_client/cli_winreg_spoolss.c | 5 +- source3/rpc_client/cli_winreg_spoolss.h | 3 +- source3/rpc_server/spoolss/srv_spoolss_nt.c | 169 +++++++++++++++++++++---- source3/rpc_server/spoolss/srv_spoolss_util.c | 6 +- source3/rpc_server/spoolss/srv_spoolss_util.h | 3 +- 5 files changed, 154 insertions(+), 32 deletions(-) diff --git a/source3/rpc_client/cli_winreg_spoolss.c b/source3/rpc_client/cli_winreg_spoolss.c index 3159e0b..0d04a1a 100644 --- a/source3/rpc_client/cli_winreg_spoolss.c +++ b/source3/rpc_client/cli_winreg_spoolss.c @@ -589,7 +589,8 @@ static WERROR winreg_printer_ver_to_dword(const char *str, uint64_t *data) WERROR winreg_create_printer(TALLOC_CTX *mem_ctx, struct dcerpc_binding_handle *winreg_handle, - const char *sharename) + const char *sharename, + const char *portname) { uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; struct policy_handle hive_hnd, key_hnd; @@ -865,7 +866,7 @@ WERROR winreg_create_printer(TALLOC_CTX *mem_ctx, info2->sharename = sharename; info2_mask |= SPOOLSS_PRINTER_INFO_SHARENAME; - info2->portname = SAMBA_PRINTER_PORT_NAME; + info2->portname = portname; info2_mask |= SPOOLSS_PRINTER_INFO_PORTNAME; info2->printprocessor = "winprint"; diff --git a/source3/rpc_client/cli_winreg_spoolss.h b/source3/rpc_client/cli_winreg_spoolss.h index 6cd6863..93bfb65 100644 --- a/source3/rpc_client/cli_winreg_spoolss.h +++ b/source3/rpc_client/cli_winreg_spoolss.h @@ -102,7 +102,8 @@ enum spoolss_PrinterInfo2Mask { WERROR winreg_create_printer(TALLOC_CTX *mem_ctx, struct dcerpc_binding_handle *b, - const char *sharename); + const char *sharename, + const char *portname); /** * @internal diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index 6403805..3619e6c 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -1697,6 +1697,76 @@ static WERROR copy_devicemode(TALLOC_CTX *mem_ctx, return WERR_OK; } +/******************************************************************** +********************************************************************/ + +static bool get_printer_port(TALLOC_CTX *mem_ctx, + const char *printername, + const char **portname, + const char **ipaddress) +{ + const char *uri = NULL; + char *p, *tmpuri; + NTSTATUS nt_status; + + nt_status = printer_list_get_printer(mem_ctx, + printername, + NULL, + NULL, + &uri, + NULL); + + if (NT_STATUS_IS_OK(nt_status)) { + if (uri != NULL) { + /* We only care about network URIs */ + if (uri == strstr(uri, "ipp://") || uri == strstr(uri, "http://") || + uri == strstr(uri, "lpd://") || uri == strstr(uri, "https://") || + uri == strstr(uri, "socket://")) { + uri = strchr(uri, ':'); + uri += 3; + + p = talloc_strdup(mem_ctx, uri); + if (p == NULL) { + return false; + } + + if ((tmpuri = strchr(p, ':')) != NULL) { + *tmpuri = '\0'; + } + if ((tmpuri = strchr(p, '/')) != NULL) { + *tmpuri = '\0'; + } + + /* If what's left after stripping extra characters isn't a valid + * IP address, give up. Should we do a DNS lookup on the string? */ + if (inet_addr(p) == -1) { + goto done; + } + + if (portname) { + *portname = talloc_asprintf(mem_ctx, "IP_%s", p); + if(*portname == NULL) { + return false; + } + } + if (ipaddress) { + *ipaddress = talloc_strdup(mem_ctx, p); + if(*ipaddress == NULL) { + return false; + } + } + + talloc_free(p); + return true; + } + } + } + +done: + DEBUGADD(2,("Printer URI references a local printer or is not recognized.\n")); + return false; +} + /**************************************************************** _spoolss_OpenPrinterEx ****************************************************************/ @@ -1707,6 +1777,7 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p, int snum; char *raddr; char *rhost; + const char *portname, *ipaddress; struct printer_handle *Printer=NULL; WERROR result; int rc; @@ -1923,11 +1994,23 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p, DEBUG(4,("Setting printer access = %s\n", (r->in.access_mask == PRINTER_ACCESS_ADMINISTER) ? "PRINTER_ACCESS_ADMINISTER" : "PRINTER_ACCESS_USE" )); + + if (get_printer_port(p->mem_ctx, lp_const_servicename(snum), &portname, &ipaddress)) { + winreg_create_port_internal(p->mem_ctx, + get_session_info_system(), + p->msg_ctx, + portname, + ipaddress); + } else { + portname = talloc_strdup(p->mem_ctx, SAMBA_PRINTER_PORT_NAME); + W_ERROR_HAVE_NO_MEMORY(portname); + } winreg_create_printer_internal(p->mem_ctx, get_session_info_system(), p->msg_ctx, - lp_const_servicename(snum)); + lp_const_servicename(snum), + portname); break; @@ -4307,6 +4390,7 @@ static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx, for (snum = 0; snum < n_services; snum++) { + const char *portname; const char *printer; struct spoolss_PrinterInfo2 *info2; @@ -4329,8 +4413,14 @@ static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx, } } + if(!get_printer_port(tmp_ctx, printer, &portname, NULL)) { + portname = talloc_strdup(tmp_ctx, SAMBA_PRINTER_PORT_NAME); + W_ERROR_HAVE_NO_MEMORY(portname); + } + result = winreg_create_printer(tmp_ctx, b, - printer); + printer, + portname); if (!W_ERROR_IS_OK(result)) { goto out; } @@ -7755,49 +7845,61 @@ static WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines) ****************************************************************************/ static WERROR enumports_level_1(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, union spoolss_PortInfo **info_p, uint32_t *count) { + uint32_t num_keys; union spoolss_PortInfo *info = NULL; int i=0; WERROR result = WERR_OK; - char **qlines = NULL; - int numlines = 0; + const char **array = NULL; + DATA_BLOB blob; - result = enumports_hook(talloc_tos(), &numlines, &qlines ); + result = winreg_enum_ports_key_internal(mem_ctx, + session_info, + msg_ctx, + &num_keys, + &array); if (!W_ERROR_IS_OK(result)) { goto out; } - if (numlines) { - info = talloc_array(mem_ctx, union spoolss_PortInfo, numlines); + if (!push_reg_multi_sz(mem_ctx, &blob, array)) { + result = WERR_NOMEM; + goto out; + } + + if (num_keys) { + info = talloc_array(mem_ctx, union spoolss_PortInfo, num_keys); if (!info) { DEBUG(10,("Returning WERR_NOMEM\n")); result = WERR_NOMEM; goto out; } - for (i=0; iin.level) { case 1: - result = enumports_level_1(p->mem_ctx, r->out.info, + result = enumports_level_1(p->mem_ctx, session_info, + p->msg_ctx, r->out.info, r->out.count); break; case 2: - result = enumports_level_2(p->mem_ctx, r->out.info, + result = enumports_level_2(p->mem_ctx, session_info, + p->msg_ctx, r->out.info, r->out.count); break; default: diff --git a/source3/rpc_server/spoolss/srv_spoolss_util.c b/source3/rpc_server/spoolss/srv_spoolss_util.c index ed7bfa1..4bb370a 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_util.c +++ b/source3/rpc_server/spoolss/srv_spoolss_util.c @@ -182,7 +182,8 @@ WERROR winreg_get_printer_internal(TALLOC_CTX *mem_ctx, WERROR winreg_create_printer_internal(TALLOC_CTX *mem_ctx, const struct auth_session_info *session_info, struct messaging_context *msg_ctx, - const char *sharename) + const char *sharename, + const char *portname) { WERROR result; struct dcerpc_binding_handle *b; @@ -201,7 +202,8 @@ WERROR winreg_create_printer_internal(TALLOC_CTX *mem_ctx, result = winreg_create_printer(mem_ctx, b, - sharename); + sharename, + portname); talloc_free(tmp_ctx); return result; diff --git a/source3/rpc_server/spoolss/srv_spoolss_util.h b/source3/rpc_server/spoolss/srv_spoolss_util.h index a43c133..ac0107b 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_util.h +++ b/source3/rpc_server/spoolss/srv_spoolss_util.h @@ -52,7 +52,8 @@ WERROR winreg_get_printer_internal(TALLOC_CTX *mem_ctx, WERROR winreg_create_printer_internal(TALLOC_CTX *mem_ctx, const struct auth_session_info *session_info, struct messaging_context *msg_ctx, - const char *sharename); + const char *sharename, + const char *portname); WERROR winreg_update_printer_internal(TALLOC_CTX *mem_ctx, const struct auth_session_info *session_info, struct messaging_context *msg_ctx, -- 1.7.3.4 From 26bb259076c0fc40ee16c85d7d8e61910e483068 Mon Sep 17 00:00:00 2001 From: Justin Chevrier Date: Tue, 30 Aug 2011 12:34:11 -0400 Subject: [PATCH 5/6] s3-spoolss: Support opening ports via OpenPrinterEx --- librpc/idl/spoolss.idl | 1 + source3/rpc_server/spoolss/srv_spoolss_nt.c | 43 +++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/librpc/idl/spoolss.idl b/librpc/idl/spoolss.idl index edd2490..46efe69 100644 --- a/librpc/idl/spoolss.idl +++ b/librpc/idl/spoolss.idl @@ -2102,6 +2102,7 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") const string SPL_TCPIP_PORT = "Standard TCP/IP Port"; const string SPL_XCV_MONITOR_LOCALMON = ",XcvMonitor Local Port"; const string SPL_XCV_MONITOR_TCPMON = ",XcvMonitor Standard TCP/IP Port"; + const string SPL_XCV_PORT = ",XcvPort "; typedef [public,gensize] struct { [relative] nstring *port_name; diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index 3619e6c..db1d96a 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -539,9 +539,9 @@ static void prune_printername_cache(void) /**************************************************************************** Set printer handle name.. Accept names like \\server, \\server\printer, - \\server\SHARE, & "\\server\,XcvMonitor Standard TCP/IP Port" See - the MSDN docs regarding OpenPrinter() for details on the XcvData() and - XcvDataPort() interface. + \\server\SHARE, "\\server\,XcvMonitor Standard TCP/IP Port", & + "\\server\,XcvPort portname" See the MSDN docs regarding OpenPrinter() + for details on the XcvData() and XcvDataPort() interface. ****************************************************************************/ static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx, @@ -553,10 +553,12 @@ static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx, int snum; int n_services=lp_numservices(); char *aprinter; + const char *portname; const char *printername; const char *servername = NULL; fstring sname; bool found = false; + struct spoolss_PortData1 *data1 = NULL; struct spoolss_PrinterInfo2 *info2 = NULL; WERROR result; char *p; @@ -578,6 +580,11 @@ static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx, if ( (aprinter = strchr_m( servername, '\\' )) != NULL ) { *aprinter = '\0'; aprinter++; + /* Ensure there isn't a second backslash */ + if ( *aprinter == '\\' ) { + *aprinter = '\0'; + aprinter++; + } } if (!is_myname_or_ipaddr(servername)) { return WERR_INVALID_PRINTER_NAME; @@ -627,7 +634,36 @@ static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx, fstrcpy(sname, SPL_XCV_MONITOR_LOCALMON); found = true; } + else if ( strstr(aprinter, SPL_XCV_PORT) ) { + if ((portname = strchr_m(aprinter, ' ')) != NULL ) { + portname++; + /* Don't bother searching the registry for + dummy port name: "Samba Printer Port" */ + if (!strequal(portname, SAMBA_PRINTER_PORT_NAME)) { + + result = winreg_get_port_internal(mem_ctx, + session_info, + msg_ctx, + portname, + &data1); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2,("set_printer_hnd_name: failed to lookup port [%s] -- result [%s]\n", + portname, win_errstr(result))); + return WERR_INVALID_PRINTER_NAME; + } + DEBUG(4, ("Found Port: [%s]\n", portname)); + fstrcpy(sname, portname); + Printer->printer_type = SPLHND_PORTMON_TCP; + + TALLOC_FREE(data1); + goto done; + } + } + + DEBUGADD(4,("Port %s not found\n", portname)); + return WERR_INVALID_PRINTER_NAME; + } /* * With hundreds of printers, the "for" loop iterating all * shares can be quite expensive, as it is done on every @@ -722,6 +758,7 @@ static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx, TALLOC_FREE(cache_key); } +done: DEBUGADD(4,("set_printer_hnd_name: Printer found: %s -> %s\n", aprinter, sname)); strlcpy(Printer->sharename, sname, sizeof(Printer->sharename)); -- 1.7.3.4 From 6c2c1f7b6282433561fa2748f5c94fafc874018f Mon Sep 17 00:00:00 2001 From: Justin Chevrier Date: Tue, 30 Aug 2011 16:55:59 -0400 Subject: [PATCH 6/6] s3-spoolss: Add support for IPAddress and GetConfigInfo XcvData commands --- librpc/idl/spoolss.idl | 4 + source3/rpc_server/spoolss/srv_spoolss_nt.c | 154 ++++++++++++++++++++++++--- 2 files changed, 144 insertions(+), 14 deletions(-) diff --git a/librpc/idl/spoolss.idl b/librpc/idl/spoolss.idl index 46efe69..7cec577 100644 --- a/librpc/idl/spoolss.idl +++ b/librpc/idl/spoolss.idl @@ -3053,6 +3053,10 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") nstring dll_name; } spoolss_MonitorUi; + typedef [public] struct { + nstring ip_address; + } spoolss_IPAddress; + WERROR spoolss_XcvData( [in,ref] policy_handle *handle, [in] [string,charset(UTF16)] uint16 function_name[], diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index db1d96a..6e2b57b 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -166,7 +166,9 @@ const struct standard_mapping printserver_std_mapping = { struct xcv_api_table { const char *name; - WERROR(*fn) (TALLOC_CTX *mem_ctx, struct security_token *token, DATA_BLOB *in, DATA_BLOB *out, uint32_t *needed); + WERROR(*fn) (TALLOC_CTX *mem_ctx, const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, struct security_token *token, const char *printername, + DATA_BLOB *in, DATA_BLOB *out, uint32_t *needed); }; static void prune_printername_cache(void); @@ -10078,7 +10080,10 @@ static bool push_monitorui_buf(TALLOC_CTX *mem_ctx, DATA_BLOB *buf, *******************************************************************/ static WERROR xcvtcp_monitorui(TALLOC_CTX *mem_ctx, - struct security_token *token, DATA_BLOB *in, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + struct security_token *token, + const char *printername, DATA_BLOB *in, DATA_BLOB *out, uint32_t *needed) { const char *dllname = "tcpmonui.dll"; @@ -10099,6 +10104,21 @@ static WERROR xcvtcp_monitorui(TALLOC_CTX *mem_ctx, /******************************************************************* ********************************************************************/ +static bool push_port_data_1(TALLOC_CTX *mem_ctx, DATA_BLOB *buf, + struct spoolss_PortData1 *port1) +{ + enum ndr_err_code ndr_err; + ndr_err = ndr_push_struct_blob(buf, mem_ctx, port1, + (ndr_push_flags_fn_t)ndr_push_spoolss_PortData1); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) { + NDR_PRINT_DEBUG(spoolss_PortData1, port1); + } + return NDR_ERR_CODE_IS_SUCCESS(ndr_err); +} + +/******************************************************************* + ********************************************************************/ + static bool pull_port_data_1(TALLOC_CTX *mem_ctx, struct spoolss_PortData1 *port1, const DATA_BLOB *buf) @@ -10133,8 +10153,11 @@ static bool pull_port_data_2(TALLOC_CTX *mem_ctx, *******************************************************************/ static WERROR xcvtcp_addport(TALLOC_CTX *mem_ctx, - struct security_token *token, DATA_BLOB *in, - DATA_BLOB *out, uint32_t *needed) + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + struct security_token *token, + const char *printername, + DATA_BLOB *in, DATA_BLOB *out, uint32_t *needed) { struct spoolss_PortData1 port1; struct spoolss_PortData2 port2; @@ -10216,16 +10239,110 @@ static WERROR xcvtcp_addport(TALLOC_CTX *mem_ctx, } /******************************************************************* + Streams the PortData1 structure of the port +*******************************************************************/ + +static WERROR xcvtcp_getconfiginfo(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + struct security_token *token, + const char *printername, DATA_BLOB *in, + DATA_BLOB *out, uint32_t *needed) +{ + WERROR result; + struct spoolss_PortData1 *port1 = NULL; + /* Windows appears to set needed to 0 */ + *needed = 0; + + result = winreg_get_port_internal(mem_ctx, + session_info, + msg_ctx, + printername, + &port1); + + if (!W_ERROR_IS_OK(result)) { + return WERR_UNKNOWN_PORT; + } + + if (!push_port_data_1(mem_ctx, out, port1)) { + return WERR_NOMEM; + } + + TALLOC_FREE(port1); + + return WERR_OK; +} + +/******************************************************************* + ********************************************************************/ + +static bool push_ipaddress_buf(TALLOC_CTX *mem_ctx, DATA_BLOB *buf, + const char *ipaddress) +{ + enum ndr_err_code ndr_err; + struct spoolss_IPAddress ip; + + ip.ip_address = ipaddress; + + ndr_err = ndr_push_struct_blob(buf, mem_ctx, &ip, + (ndr_push_flags_fn_t)ndr_push_spoolss_IPAddress); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) { + NDR_PRINT_DEBUG(spoolss_IPAddress, &ip); + } + return NDR_ERR_CODE_IS_SUCCESS(ndr_err); +} + +/******************************************************************* + Streams the IP Address of the port +*******************************************************************/ + +static WERROR xcvtcp_ipaddress(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + struct security_token *token, + const char *printername, DATA_BLOB *in, + DATA_BLOB *out, uint32_t *needed) +{ + WERROR result; + struct spoolss_PortData1 *port1 = NULL; + /* Windows appears to set needed to 0 */ + *needed = 0; + + result = winreg_get_port_internal(mem_ctx, + session_info, + msg_ctx, + printername, + &port1); + + if (!W_ERROR_IS_OK(result)) { + return WERR_UNKNOWN_PORT; + } + + if (!push_ipaddress_buf(mem_ctx, out, port1->ip_address)) { + return WERR_NOMEM; + } + + TALLOC_FREE(port1); + + return WERR_OK; +} + +/******************************************************************* *******************************************************************/ struct xcv_api_table xcvtcp_cmds[] = { - { "MonitorUI", xcvtcp_monitorui }, - { "AddPort", xcvtcp_addport}, - { NULL, NULL } + { "MonitorUI", xcvtcp_monitorui }, + { "AddPort", xcvtcp_addport }, + { "GetConfigInfo", xcvtcp_getconfiginfo }, + { "IPAddress", xcvtcp_ipaddress }, + { NULL, NULL } }; static WERROR process_xcvtcp_command(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, struct security_token *token, const char *command, + const char *printername, DATA_BLOB *inbuf, DATA_BLOB *outbuf, uint32_t *needed ) @@ -10236,7 +10353,7 @@ static WERROR process_xcvtcp_command(TALLOC_CTX *mem_ctx, for ( i=0; xcvtcp_cmds[i].name; i++ ) { if ( strcmp( command, xcvtcp_cmds[i].name ) == 0 ) - return xcvtcp_cmds[i].fn(mem_ctx, token, inbuf, outbuf, needed); + return xcvtcp_cmds[i].fn(mem_ctx, session_info, msg_ctx, token, printername, inbuf, outbuf, needed); } return WERR_BADFUNC; @@ -10247,7 +10364,7 @@ static WERROR process_xcvtcp_command(TALLOC_CTX *mem_ctx, #if 0 /* don't support management using the "Local Port" monitor */ static WERROR xcvlocal_monitorui(TALLOC_CTX *mem_ctx, - struct security_token *token, DATA_BLOB *in, + struct security_token *token, const char *printername, DATA_BLOB *in, DATA_BLOB *out, uint32_t *needed) { const char *dllname = "localui.dll"; @@ -10284,8 +10401,10 @@ struct xcv_api_table xcvlocal_cmds[] = { *******************************************************************/ static WERROR process_xcvlocal_command(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, struct security_token *token, const char *command, - DATA_BLOB *inbuf, DATA_BLOB *outbuf, + const char *printername, DATA_BLOB *inbuf, DATA_BLOB *outbuf, uint32_t *needed) { int i; @@ -10294,7 +10413,7 @@ static WERROR process_xcvlocal_command(TALLOC_CTX *mem_ctx, for ( i=0; xcvlocal_cmds[i].name; i++ ) { if ( strcmp( command, xcvlocal_cmds[i].name ) == 0 ) - return xcvlocal_cmds[i].fn(mem_ctx, token, inbuf, outbuf, needed); + return xcvlocal_cmds[i].fn(mem_ctx, session_info, msg_ctx, token, printername, inbuf, outbuf, needed); } return WERR_BADFUNC; } @@ -10323,9 +10442,10 @@ WERROR _spoolss_XcvData(struct pipes_struct *p, return WERR_BADFID; } - /* requires administrative access to the server */ - - if ( !(Printer->access_granted & SERVER_ACCESS_ADMINISTER) ) { + /* AddPort, ConfigPort, DeletePort and MonitorUI require administrative access to the server */ + if ( !(Printer->access_granted & SERVER_ACCESS_ADMINISTER) && + (strequal(r->in.function_name, "AddPort") || strequal(r->in.function_name, "ConfigPort") || + strequal(r->in.function_name, "DeletePort") || strequal(r->in.function_name, "MonitorUI")) ) { DEBUG(2,("_spoolss_XcvData: denied by handle permissions.\n")); return WERR_ACCESS_DENIED; } @@ -10342,15 +10462,21 @@ WERROR _spoolss_XcvData(struct pipes_struct *p, switch ( Printer->printer_type ) { case SPLHND_PORTMON_TCP: werror = process_xcvtcp_command(p->mem_ctx, + p->session_info, + p->msg_ctx, p->session_info->security_token, r->in.function_name, + Printer->sharename, &r->in.in_data, &out_data, r->out.needed); break; case SPLHND_PORTMON_LOCAL: werror = process_xcvlocal_command(p->mem_ctx, + p->session_info, + p->msg_ctx, p->session_info->security_token, r->in.function_name, + Printer->sharename, &r->in.in_data, &out_data, r->out.needed); break; -- 1.7.3.4