The branch, master has been updated via 000e6ba s4-torture: add some basic tests for PlayGDIScriptOnPrinterIC. via 21aa7fe s3-rpcclient: add cmd_spoolss_play_gdi_script_on_printer_ic. via 0364658 spoolss: add UNIVERSAL_FONT_ID_ctr for debugging. via d99b1ee spoolss: Add UNIVERSAL_FONT_ID. via a270e20 spoolss: fill in spoolss_PlayGDIScriptOnPrinterIC IDL. via aab232c s3-rpcclient: decode OsVersion{Ex} binary blobs when displaying printerdata. via ce1a9ae s3-spoolss: Make it easier to manipulate the returned OSVersion at runtime. via 11fba10 spoolss: make spoolss deal with ndr64 StartDocPrinter by using proper container object. via 6bcd3dd spoolss: add more spoolss_DriverAttributes values. from 875a172 docs: ldbsearch.1.xml: Correct meta data.
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 000e6ba14ab1c63278c2a9b10fe271c08f578ccf Author: Günther Deschner <g...@samba.org> Date: Wed Jan 23 10:33:21 2013 +0100 s4-torture: add some basic tests for PlayGDIScriptOnPrinterIC. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> Autobuild-User(master): Andreas Schneider <a...@cryptomilk.org> Autobuild-Date(master): Thu Jan 24 19:20:52 CET 2013 on sn-devel-104 commit 21aa7fe633d2360d529e93b5599988eabff1d7d1 Author: Günther Deschner <g...@samba.org> Date: Wed Jan 23 09:31:01 2013 +0100 s3-rpcclient: add cmd_spoolss_play_gdi_script_on_printer_ic. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 0364658632f8a68537bd3e7c99ecca4c5c968455 Author: Günther Deschner <g...@samba.org> Date: Thu Jan 24 17:10:17 2013 +0100 spoolss: add UNIVERSAL_FONT_ID_ctr for debugging. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit d99b1ee79c6c772e2dfe7152edc7343c806dab6e Author: Günther Deschner <g...@samba.org> Date: Wed Jan 23 11:11:26 2013 +0100 spoolss: Add UNIVERSAL_FONT_ID. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit a270e20b198696c754182fa0c58fd3c4d338e955 Author: Günther Deschner <g...@samba.org> Date: Wed Jan 23 09:01:05 2013 +0100 spoolss: fill in spoolss_PlayGDIScriptOnPrinterIC IDL. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit aab232cb2ea91b3a6c636f4ea47ca9f872848f3f Author: Günther Deschner <g...@samba.org> Date: Tue Jan 22 15:57:22 2013 +0100 s3-rpcclient: decode OsVersion{Ex} binary blobs when displaying printerdata. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit ce1a9ae8abc3e4d49374b5b02c6ec55d2df63f72 Author: Günther Deschner <g...@samba.org> Date: Sat Jan 19 01:37:29 2013 +0100 s3-spoolss: Make it easier to manipulate the returned OSVersion at runtime. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 11fba102082239c5d70b6314b19dab72b49478ed Author: Günther Deschner <g...@samba.org> Date: Fri Jan 18 22:22:13 2013 +0100 spoolss: make spoolss deal with ndr64 StartDocPrinter by using proper container object. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 6bcd3dda2825a8791e7284b3229aa518416e8544 Author: Günther Deschner <g...@samba.org> Date: Fri Jan 18 13:43:05 2013 +0100 spoolss: add more spoolss_DriverAttributes values. The level5 driver does return only one of these flags with a different value, will get fixed later. Guenther Signed-off-by: Günther Deschner <g...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> ----------------------------------------------------------------------- Summary of changes: librpc/idl/spoolss.idl | 43 ++++++++-- source3/printing/printspoolss.c | 25 ++++-- source3/rpc_server/spoolss/srv_spoolss_nt.c | 18 +++- source3/rpcclient/cmd_spoolss.c | 124 +++++++++++++++++++++++++++ source4/torture/rpc/spoolss.c | 119 +++++++++++++++++++++++++- 5 files changed, 306 insertions(+), 23 deletions(-) Changeset truncated at 500 lines: diff --git a/librpc/idl/spoolss.idl b/librpc/idl/spoolss.idl index 29aee27..a43449b 100644 --- a/librpc/idl/spoolss.idl +++ b/librpc/idl/spoolss.idl @@ -1349,7 +1349,17 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") } spoolss_AddDriverInfo4; typedef [bitmap32bit] bitmap { - PRINTER_DRIVER_PACKAGE_AWARE = 0x00000002 + PRINTER_DRIVER_PACKAGE_AWARE = 0x00000001, + PRINTER_DRIVER_XPS = 0x00000002, + PRINTER_DRIVER_SANDBOX_ENABLED = 0x00000004, + PRINTER_DRIVER_CLASS = 0x00000008, + PRINTER_DRIVER_DERIVED = 0x00000010, + PRINTER_DRIVER_NOT_SHAREABLE = 0x00000020, + PRINTER_DRIVER_CATEGORY_FAX = 0x00000040, + PRINTER_DRIVER_CATEGORY_FILE = 0x00000080, + PRINTER_DRIVER_CATEGORY_VIRTUAL = 0x00000100, + PRINTER_DRIVER_CATEGORY_SERVICE = 0x00000200, + PRINTER_DRIVER_SOFT_RESET_REQUIRED = 0x00000400 } spoolss_DriverAttributes; typedef struct { @@ -1411,7 +1421,7 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") [value(((ndr_size_spoolss_StringArray(color_profiles, ndr->flags)-4)/2))] uint32 _ndr_size_color_profiles; spoolss_StringArray *color_profiles; [string,charset(UTF16)] uint16 *inf_path; - uint32 printer_driver_attributes; + spoolss_DriverAttributes printer_driver_attributes; [value(((ndr_size_spoolss_StringArray(core_driver_dependencies, ndr->flags)-4)/2))] uint32 _ndr_size_core_driver_dependencies; spoolss_StringArray *core_driver_dependencies; NTTIME min_inbox_driver_ver_date; @@ -1539,7 +1549,7 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") [relative] nstring *vendor_setup; [relative] nstring_array *color_profiles; [relative] nstring *inf_path; - uint32 printer_driver_attributes; + spoolss_DriverAttributes printer_driver_attributes; [relative] nstring_array *core_driver_dependencies; NTTIME min_inbox_driver_ver_date; hyper min_inbox_driver_ver_version; @@ -1743,10 +1753,14 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") [default]; } spoolss_DocumentInfo; + typedef struct { + uint32 level; + [switch_is(level)] spoolss_DocumentInfo info; + } spoolss_DocumentInfoCtr; + WERROR spoolss_StartDocPrinter( [in,ref] policy_handle *handle, - [in] uint32 level, - [in,switch_is(level)] spoolss_DocumentInfo info, + [in,ref] spoolss_DocumentInfoCtr *info_ctr, [out,ref] uint32 *job_id ); @@ -2306,7 +2320,24 @@ cpp_quote("#define spoolss_security_descriptor security_descriptor") /******************/ /* Function: 0x29 */ - [todo] WERROR spoolss_PlayGDIScriptOnPrinterIC( + + typedef struct { + uint32 Checksum; + uint32 Index; + } UNIVERSAL_FONT_ID; + + typedef [public] struct { + uint32 count; + UNIVERSAL_FONT_ID fonts[count]; + } UNIVERSAL_FONT_ID_ctr; + + WERROR spoolss_PlayGDIScriptOnPrinterIC( + [in,ref] policy_handle *gdi_handle, + [in,ref] [size_is(cIn)] uint8 *pIn, + [in] uint32 cIn, + [out,ref] [size_is(cOut)] uint8 *pOut, + [in] uint32 cOut, + [in] uint32 ul ); /******************/ diff --git a/source3/printing/printspoolss.c b/source3/printing/printspoolss.c index 7a730a5..acf4c0d 100644 --- a/source3/printing/printspoolss.c +++ b/source3/printing/printspoolss.c @@ -64,7 +64,8 @@ NTSTATUS print_spool_open(files_struct *fsp, struct print_file_data *pf; struct dcerpc_binding_handle *b = NULL; struct spoolss_DevmodeContainer devmode_ctr; - union spoolss_DocumentInfo info; + struct spoolss_DocumentInfoCtr info_ctr; + struct spoolss_DocumentInfo1 *info1; int fd = -1; WERROR werr; @@ -173,17 +174,23 @@ NTSTATUS print_spool_open(files_struct *fsp, goto done; } - info.info1 = talloc(tmp_ctx, struct spoolss_DocumentInfo1); - if (!info.info1) { + info1 = talloc(tmp_ctx, struct spoolss_DocumentInfo1); + if (info1 == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } - info.info1->document_name = pf->docname; - info.info1->output_file = pf->filename; - info.info1->datatype = "RAW"; + info1->document_name = pf->docname; + info1->output_file = pf->filename; + info1->datatype = "RAW"; - status = dcerpc_spoolss_StartDocPrinter(b, tmp_ctx, &pf->handle, - 1, info, &pf->jobid, &werr); + info_ctr.level = 1; + info_ctr.info.info1 = info1; + + status = dcerpc_spoolss_StartDocPrinter(b, tmp_ctx, + &pf->handle, + &info_ctr, + &pf->jobid, + &werr); if (!NT_STATUS_IS_OK(status)) { goto done; } diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index 9601ce6..ef203d8 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -2338,9 +2338,13 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx, enum ndr_err_code ndr_err; struct spoolss_OSVersion os; - os.major = 5; /* Windows 2000 == 5.0 */ - os.minor = 0; - os.build = 2195; /* build */ + os.major = lp_parm_int(GLOBAL_SECTION_SNUM, + "spoolss", "os_major", 5); + /* Windows 2000 == 5.0 */ + os.minor = lp_parm_int(GLOBAL_SECTION_SNUM, + "spoolss", "os_minor", 0); + os.build = lp_parm_int(GLOBAL_SECTION_SNUM, + "spoolss", "os_build", 2195); os.extra_string = ""; /* leave extra string empty */ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &os, @@ -2349,6 +2353,10 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx, return WERR_GENERAL_FAILURE; } + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(spoolss_OSVersion, &os); + } + *type = REG_BINARY; data->binary = blob; @@ -5730,11 +5738,11 @@ WERROR _spoolss_StartDocPrinter(struct pipes_struct *p, return WERR_INVALID_HANDLE; } - if (r->in.level != 1) { + if (r->in.info_ctr->level != 1) { return WERR_UNKNOWN_LEVEL; } - info_1 = r->in.info.info1; + info_1 = r->in.info_ctr->info.info1; /* * a nice thing with NT is it doesn't listen to what you tell it. diff --git a/source3/rpcclient/cmd_spoolss.c b/source3/rpcclient/cmd_spoolss.c index ced224b..5c499d4 100644 --- a/source3/rpcclient/cmd_spoolss.c +++ b/source3/rpcclient/cmd_spoolss.c @@ -25,6 +25,7 @@ #include "includes.h" #include "rpcclient.h" #include "../librpc/gen_ndr/ndr_spoolss_c.h" +#include "../librpc/gen_ndr/ndr_spoolss.h" #include "rpc_client/cli_spoolss.h" #include "rpc_client/init_spoolss.h" #include "nt_printing.h" @@ -831,6 +832,7 @@ static void display_printer_data(const char *v, union spoolss_PrinterData r; DATA_BLOB blob = data_blob_const(data, length); WERROR result; + enum ndr_err_code ndr_err; result = pull_spoolss_PrinterData(talloc_tos(), &blob, &r, type); if (!W_ERROR_IS_OK(result)) { @@ -861,6 +863,25 @@ static void display_printer_data(const char *v, } TALLOC_FREE(hex); putchar('\n'); + + if (strequal(v, "OsVersion")) { + struct spoolss_OSVersion os; + ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &os, + (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersion); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + printf("%s: OsVersion:\n", v); + NDR_PRINT_DEBUG(spoolss_OSVersion, &os); + } + } + if (strequal(v, "OsVersionEx")) { + struct spoolss_OSVersionEx os; + ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &os, + (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersionEx); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + printf("%s: OsVersionEx:\n", v); + NDR_PRINT_DEBUG(spoolss_OSVersionEx, &os); + } + } break; } case REG_MULTI_SZ: @@ -3712,6 +3733,108 @@ static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli, return result; } +static WERROR cmd_spoolss_play_gdi_script_on_printer_ic(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + NTSTATUS status; + struct policy_handle handle, gdi_handle; + const char *printername; + struct spoolss_DevmodeContainer devmode_ctr; + struct dcerpc_binding_handle *b = cli->binding_handle; + DATA_BLOB in,out; + uint32_t count = 0; + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + ZERO_STRUCT(devmode_ctr); + + status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx, + &handle, + &gdi_handle, + &devmode_ctr, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + in = data_blob_string_const(""); + out = data_blob_talloc_zero(mem_ctx, 4); + + status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx, + &gdi_handle, + in.data, + in.length, + out.data, + out.length, + 0, /* ul */ + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + count = IVAL(out.data, 0); + + out = data_blob_talloc_zero(mem_ctx, + count * sizeof(struct UNIVERSAL_FONT_ID) + 4); + + status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx, + &gdi_handle, + in.data, + in.length, + out.data, + out.length, + 0, /* ul */ + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + { + enum ndr_err_code ndr_err; + struct UNIVERSAL_FONT_ID_ctr r; + + ndr_err = ndr_pull_struct_blob(&out, mem_ctx, &r, + (ndr_pull_flags_fn_t)ndr_pull_UNIVERSAL_FONT_ID_ctr); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PRINT_DEBUG(UNIVERSAL_FONT_ID_ctr, &r); + } + } + + done: + if (is_valid_policy_hnd(&gdi_handle)) { + WERROR _result; + dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result); + } + if (is_valid_policy_hnd(&handle)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); + } + + return result; +} + /* List of commands exported by this module */ struct cmd_set spoolss_commands[] = { @@ -3753,6 +3876,7 @@ struct cmd_set spoolss_commands[] = { { "enumprocdatatypes", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss, NULL, "Enumerate Print Processor Data Types", "" }, { "enummonitors", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors, &ndr_table_spoolss, NULL, "Enumerate Print Monitors", "" }, { "createprinteric", RPC_RTYPE_WERROR, NULL, cmd_spoolss_create_printer_ic, &ndr_table_spoolss, NULL, "Create Printer IC", "" }, + { "playgdiscriptonprinteric", RPC_RTYPE_WERROR, NULL, cmd_spoolss_play_gdi_script_on_printer_ic, &ndr_table_spoolss, NULL, "Create Printer IC", "" }, { NULL } }; diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c index d13a11d..f08e93b 100644 --- a/source4/torture/rpc/spoolss.c +++ b/source4/torture/rpc/spoolss.c @@ -5,7 +5,7 @@ Copyright (C) Tim Potter 2003 Copyright (C) Stefan Metzmacher 2005 Copyright (C) Jelmer Vernooij 2007 - Copyright (C) Guenther Deschner 2009-2011 + Copyright (C) Guenther Deschner 2009-2011,2013 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3273,6 +3273,7 @@ static bool test_DoPrintTest_add_one_job(struct torture_context *tctx, { NTSTATUS status; struct spoolss_StartDocPrinter s; + struct spoolss_DocumentInfoCtr info_ctr; struct spoolss_DocumentInfo1 info1; struct spoolss_StartPagePrinter sp; struct spoolss_WritePrinter w; @@ -3284,13 +3285,16 @@ static bool test_DoPrintTest_add_one_job(struct torture_context *tctx, torture_comment(tctx, "Testing StartDocPrinter\n"); s.in.handle = handle; - s.in.level = 1; - s.in.info.info1 = &info1; + s.in.info_ctr = &info_ctr; s.out.job_id = job_id; + info1.document_name = document_name; info1.output_file = NULL; info1.datatype = "RAW"; + info_ctr.level = 1; + info_ctr.info.info1 = &info1; + status = dcerpc_spoolss_StartDocPrinter_r(b, tctx, &s); torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed"); torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed"); @@ -7965,6 +7969,114 @@ static bool test_printer_data_dsspooler(struct torture_context *tctx, return true; } +static bool test_printer_ic(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 gdi_handle; + + if (torture_setting_bool(tctx, "samba3", false)) { + torture_skip(tctx, "skip printer information context tests against samba"); + } + + { + struct spoolss_CreatePrinterIC r; + struct spoolss_DevmodeContainer devmode_ctr; + + ZERO_STRUCT(devmode_ctr); + + r.in.handle = &t->handle; + r.in.devmode_ctr = &devmode_ctr; + r.out.gdi_handle = &gdi_handle; + + torture_assert_ntstatus_ok(tctx, + dcerpc_spoolss_CreatePrinterIC_r(b, tctx, &r), + "CreatePrinterIC failed"); + torture_assert_werr_ok(tctx, r.out.result, + "CreatePrinterIC failed"); + } + + { + struct spoolss_PlayGDIScriptOnPrinterIC r; + DATA_BLOB in,out; + int i; + uint32_t num_fonts = 0; + + in = data_blob_string_const(""); + + r.in.gdi_handle = &gdi_handle; + r.in.pIn = in.data; + r.in.cIn = in.length; + r.in.ul = 0; + + for (i = 0; i < 4; i++) { + + out = data_blob_talloc_zero(tctx, i); + + r.in.cOut = out.length; + r.out.pOut = out.data; + + torture_assert_ntstatus_ok(tctx, + dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r), + "PlayGDIScriptOnPrinterIC failed"); + torture_assert_werr_equal(tctx, r.out.result, WERR_NOMEM, + "PlayGDIScriptOnPrinterIC failed"); + } + + out = data_blob_talloc_zero(tctx, 4); + + r.in.cOut = out.length; + r.out.pOut = out.data; + + torture_assert_ntstatus_ok(tctx, + dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r), + "PlayGDIScriptOnPrinterIC failed"); + torture_assert_werr_equal(tctx, r.out.result, WERR_OK, + "PlayGDIScriptOnPrinterIC failed"); + + /* now we should have the required length, so retry with a + * buffer which is large enough to carry all font ids */ + + num_fonts = IVAL(r.out.pOut, 0); + + torture_comment(tctx, "PlayGDIScriptOnPrinterIC gave font count of %d\n", num_fonts); + + out = data_blob_talloc_zero(tctx, + num_fonts * sizeof(struct UNIVERSAL_FONT_ID) + 4); + + r.in.cOut = out.length; + r.out.pOut = out.data; + + torture_assert_ntstatus_ok(tctx, + dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r), + "PlayGDIScriptOnPrinterIC failed"); + torture_assert_werr_equal(tctx, r.out.result, WERR_OK, + "PlayGDIScriptOnPrinterIC failed"); + + } + + { + struct spoolss_DeletePrinterIC r; + + r.in.gdi_handle = &gdi_handle; + r.out.gdi_handle = &gdi_handle; + + torture_assert_ntstatus_ok(tctx, + dcerpc_spoolss_DeletePrinterIC_r(b, tctx, &r), + "DeletePrinterIC failed"); + torture_assert_werr_ok(tctx, r.out.result, + "DeletePrinterIC failed"); + + } + + return true; +} + + static bool test_driver_info_winreg(struct torture_context *tctx, void *private_data) { @@ -8005,6 +8117,7 @@ void torture_tcase_printer(struct torture_tcase *tcase) torture_tcase_add_simple_test(tcase, "printerdata_dsspooler", test_printer_data_dsspooler); torture_tcase_add_simple_test(tcase, "driver_info_winreg", test_driver_info_winreg); torture_tcase_add_simple_test(tcase, "printer_rename", test_printer_rename); + torture_tcase_add_simple_test(tcase, "printer_ic", test_printer_ic); } -- Samba Shared Repository