#define DATABASE_VERSION 1
-/* we need to have a small set of default forms to support our
- default printer */
+/* We need one default form to support our default printer. Msoft adds the
+forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
+array index). Letter is always first, so (for the current code) additions
+always put things in the correct order. */
static nt_forms_struct default_forms[] = {
{"Letter", 0x2, 0x34b5b, 0x44367, 0x0, 0x0, 0x34b5b, 0x44367},
- {"A4", 0x2, 0x3354f, 0x4884e, 0x0, 0x0, 0x3354f, 0x4884e}
};
BOOL nt_printing_init(void)
{
static pid_t local_pid;
+ char *vstring = "INFO/version";
if (tdb && local_pid == sys_getpid()) return True;
tdb = tdb_open(lock_path("ntdrivers.tdb"), 0, 0, O_RDWR|O_CREAT, 0600);
local_pid = sys_getpid();
/* handle a Samba upgrade */
- tdb_writelock(tdb);
- if (tdb_fetch_int(tdb, "INFO/version") != DATABASE_VERSION) {
+ tdb_lock_bystring(tdb, vstring);
+ if (tdb_fetch_int(tdb, vstring) != DATABASE_VERSION) {
tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
- tdb_store_int(tdb, "INFO/version", DATABASE_VERSION);
+ tdb_store_int(tdb, vstring, DATABASE_VERSION);
}
- tdb_writeunlock(tdb);
+ tdb_unlock_bystring(tdb, vstring);
return True;
}
TDB_DATA kbuf, newkey, dbuf;
nt_forms_struct form;
int ret;
+ int i;
int n = 0;
for (kbuf = tdb_firstkey(tdb);
if (!dbuf.dptr) continue;
fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
- ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddddddd",
- &form.flag, &form.width, &form.length, &form.left,
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
+ &i, &form.flag, &form.width, &form.length, &form.left,
&form.top, &form.right, &form.bottom);
safe_free(dbuf.dptr);
if (ret != dbuf.dsize) continue;
- *list = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
- (*list)[n] = form;
- n++;
+ /* allocate space and populate the list in correct order */
+ if (i+1 > n) {
+ *list = Realloc(*list, sizeof(nt_forms_struct)*(i+1));
+ n = i+1;
+ }
+ (*list)[i] = form;
}
/* we should never return a null forms list or NT gets unhappy */
int i;
for (i=0;i<number;i++) {
- len = tdb_pack(buf, sizeof(buf), "ddddddd",
- (*list)[i].flag, (*list)[i].width, (*list)[i].length,
+ /* save index, so list is rebuilt in correct order */
+ len = tdb_pack(buf, sizeof(buf), "dddddddd",
+ i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
(*list)[i].left, (*list)[i].top, (*list)[i].right,
(*list)[i].bottom);
if (len > sizeof(buf)) break;
update=False;
- unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
+ unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
for (n=0; n<*count && update==False; n++)
{
if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
{
if((*list=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL)
return False;
- unistr2_to_ascii((*list)[n].name, &(form->name), sizeof((*list)[n].name)-1);
+ unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
(*count)++;
}
return True;
}
+/****************************************************************************
+ delete a named form struct
+****************************************************************************/
+BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32 *ret)
+{
+ pstring key;
+ TDB_DATA kbuf;
+ int n=0;
+ fstring form_name;
+
+ *ret = 0;
+
+ if (*count == 1) {
+ /*
+ * Don't delete the last form (no empty lists).
+ * CHECKME ! Is this correct ? JRA.
+ */
+ *ret = ERROR_INVALID_PARAMETER;
+ return False;
+ }
+
+ unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
+
+ for (n=0; n<*count; n++) {
+ if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
+ DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
+ break;
+ }
+ }
+
+ if (n == *count) {
+ DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
+ *ret = ERROR_INVALID_PARAMETER;
+ return False;
+ }
+
+ slprintf(key, sizeof(key), "%s%s", FORMS_PREFIX, (*list)[n].name);
+ kbuf.dsize = strlen(key)+1;
+ kbuf.dptr = key;
+ if (tdb_delete(tdb, kbuf) != 0) {
+ *ret = ERROR_NOT_ENOUGH_MEMORY;
+ return False;
+ }
+
+ return True;
+}
+
/****************************************************************************
update a form struct
****************************************************************************/
}
/****************************************************************************
+Determine the correct cVersion associated with an architecture and driver
****************************************************************************/
-static void clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
+static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in)
+{
+ int fd = -1;
+ int service;
+ int cversion;
+ ssize_t byte_count;
+ char buf[PE_HEADER_SIZE];
+ pstring driverpath;
+
+ /* If architecture is Windows 95/98, the version is always 0. */
+ if (strcmp(architecture, "WIN40") == 0) {
+ DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
+ return 0;
+ }
+
+ /* Open the driver file (Portable Executable format) and determine the
+ * deriver the cversion.
+ */
+ if ((service = find_service("print$")) == -1) {
+ DEBUG(3,("get_correct_cversion: Can't find print$ service\n"));
+ goto error_exit;
+ }
+
+ slprintf(driverpath, sizeof(driverpath), "%s/%s/%s",
+ lp_pathname(service), architecture, driverpath_in);
+
+ dos_to_unix(driverpath, True);
+
+ if ((fd = sys_open(driverpath, O_RDONLY, 0)) == -1) {
+ DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
+ driverpath, errno));
+ goto error_exit;
+ }
+
+ if ((byte_count = read(fd, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
+ DEBUG(3,("get_correct_cversion: File [%s] DOS header too short, bytes read = %d\n",
+ driverpath, byte_count));
+ goto error_exit;
+ }
+
+ /* Is this really a DOS header? */
+ if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
+ DEBUG(6,("get_correct_cversion: File [%s] bad DOS magic = 0x%x\n",
+ driverpath, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
+ goto error_exit;
+ }
+
+ /* Skip OEM header (if any) and the DOS stub to start of Windows header */
+ if (sys_lseek(fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
+ DEBUG(3,("get_correct_cversion: File [%s] too short, errno = %d\n",
+ driverpath, errno));
+ goto error_exit;
+ }
+
+ if ((byte_count = read(fd, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
+ DEBUG(3,("get_correct_cversion: File [%s] Windows header too short, bytes read = %d\n",
+ driverpath, byte_count));
+ goto error_exit;
+ }
+ close(fd);
+
+ /* The header may be a PE (Portable Executable) or an NE (New Executable) */
+ if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
+ if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) == PE_HEADER_MACHINE_I386) {
+
+ switch (SVAL(buf,PE_HEADER_MAJOR_OS_VER_OFFSET)) {
+ case 4: cversion = 2; break; /* Win NT 4 */
+ case 5: cversion = 3; break; /* Win 2000 */
+ default:
+ DEBUG(6,("get_correct_cversion: PE formated file [%s] bad version = %d\n",
+ driverpath, SVAL(buf,PE_HEADER_MAJOR_OS_VER_OFFSET)));
+ goto error_exit;
+ }
+ } else {
+ DEBUG(6,("get_correct_cversion: PE formatted file [%s] wrong machine = 0x%x\n",
+ driverpath, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
+ goto error_exit;
+ }
+
+ } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
+ if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) == NE_HEADER_TARGOS_WIN ) {
+
+ switch (CVAL(buf,NE_HEADER_MAJOR_VER_OFFSET)) {
+ case 3: cversion = 0; break; /* Win 3.x / Win 9x / Win ME */
+ /* case ?: cversion = 1; break;*/ /* Win NT 3.51 ... needs research JRR */
+ default:
+ DEBUG(6,("get_correct_cversion: NE formated file [%s] bad version = %d\n",
+ driverpath, CVAL(buf,NE_HEADER_MAJOR_VER_OFFSET)));
+ goto error_exit;
+ }
+ } else {
+ DEBUG(6,("get_correct_cversion: NE formatted file [%s] wrong target OS = 0x%x\n",
+ driverpath, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
+ goto error_exit;
+ }
+
+ } else {
+ DEBUG(6,("get_correct_cversion: Unknown file format [%s], signature = 0x%x\n",
+ driverpath, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
+ goto error_exit;
+ }
+
+ DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
+ driverpath, cversion));
+ return cversion;
+
+
+ error_exit:
+ if(fd != -1)
+ close(fd);
+ return -1;
+}
+
+/****************************************************************************
+****************************************************************************/
+static uint32 clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
{
fstring architecture;
fstring new_name;
char *p;
int i;
+
+ /* clean up the driver name.
+ * we can get .\driver.dll
+ * or worse c:\windows\system\driver.dll !
+ */
+ /* using an intermediate string to not have overlaping memcpy()'s */
+ if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->driverpath, new_name);
+ }
+
+ if ((p = strrchr(driver->datafile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->datafile, new_name);
+ }
+
+ if ((p = strrchr(driver->configfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->configfile, new_name);
+ }
+
+ if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->helpfile, new_name);
+ }
+
+ if (driver->dependentfiles) {
+ for (i=0; *driver->dependentfiles[i]; i++) {
+ if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
+ fstrcpy(new_name, p+1);
+ fstrcpy(driver->dependentfiles[i], new_name);
+ }
+ }
+ }
+
+ get_short_archi(architecture, driver->environment);
/* jfm:7/16/2000 the client always sends the cversion=0.
- * The server should check which version the driver is by reading the PE header
- * of driver->driverpath.
+ * The server should check which version the driver is by reading
+ * the PE header of driver->driverpath.
*
* For Windows 95/98 the version is 0 (so the value sent is correct)
* For Windows NT (the architecture doesn't matter)
* NT 4: cversion=2
* NT2K: cversion=3
*/
+ if ((driver->cversion = get_correct_cversion(architecture,
+ driver->driverpath)) == -1)
+ return NT_STATUS_FILE_INVALID; /* Not the best error. Fix JRR */
- get_short_archi(architecture, driver->environment);
-
- /* if it's Windows 95/98, we keep the version at 0
- * jfmxxx: I need to redo that more correctly for NT2K.
- */
+ return NT_STATUS_NO_PROBLEMO;
+}
- if (StrCaseCmp(driver->environment, "Windows 4.0")==0)
- driver->cversion=0;
- else
- driver->cversion=2;
+/****************************************************************************
+****************************************************************************/
+static uint32 clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
+{
+ fstring architecture;
+ fstring new_name;
+ char *p;
+ int i;
/* clean up the driver name.
* we can get .\driver.dll
}
}
}
-}
-/****************************************************************************
-****************************************************************************/
-static void clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
-{
+ get_short_archi(architecture, driver->environment);
+
+ /* jfm:7/16/2000 the client always sends the cversion=0.
+ * The server should check which version the driver is by reading
+ * the PE header of driver->driverpath.
+ *
+ * For Windows 95/98 the version is 0 (so the value sent is correct)
+ * For Windows NT (the architecture doesn't matter)
+ * NT 3.1: cversion=0
+ * NT 3.5/3.51: cversion=1
+ * NT 4: cversion=2
+ * NT2K: cversion=3
+ */
+ if ((driver->version = get_correct_cversion(architecture,
+ driver->driverpath)) == -1)
+ return NT_STATUS_FILE_INVALID; /* Not the best error. Fix JRR */
+ return NT_STATUS_NO_PROBLEMO;
}
/****************************************************************************
****************************************************************************/
-void clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level)
+uint32 clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level)
{
switch (level) {
case 3:
{
NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
driver=driver_abstract.info_3;
- clean_up_driver_struct_level_3(driver);
+ return clean_up_driver_struct_level_3(driver);
break;
}
case 6:
{
NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
driver=driver_abstract.info_6;
- clean_up_driver_struct_level_6(driver);
+ return clean_up_driver_struct_level_6(driver);
break;
}
+ default:
+ return ERROR_INVALID_PARAMETER;
}
}
+/****************************************************************************
+ This function sucks and should be replaced. JRA.
+****************************************************************************/
+
+static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
+{
+ dst->cversion = src->version;
+
+ fstrcpy( dst->name, src->name);
+ fstrcpy( dst->environment, src->environment);
+ fstrcpy( dst->driverpath, src->driverpath);
+ fstrcpy( dst->datafile, src->datafile);
+ fstrcpy( dst->configfile, src->configfile);
+ fstrcpy( dst->helpfile, src->helpfile);
+ fstrcpy( dst->monitorname, src->monitorname);
+ fstrcpy( dst->defaultdatatype, src->defaultdatatype);
+ dst->dependentfiles = src->dependentfiles;
+}
+
+
/****************************************************************************
****************************************************************************/
BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, struct current_user *user, uint32 *perr)
{
NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
+ NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
fstring architecture;
pstring new_dir;
pstring old_name;
if (level==3)
driver=driver_abstract.info_3;
-
+ else if (level==6) {
+ convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
+ driver = &converted_driver;
+ } else {
+ DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
+ return False;
+ }
+
get_short_archi(architecture, driver->environment);
become_root();
*/
DEBUG(5,("Moving file now !\n"));
+
+ if (driver->driverpath && strlen(driver->driverpath)) {
slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->driverpath);
slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->driverpath);
if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
*perr = (uint32)SVAL(outbuf,smb_err);
return False;
}
+ }
+ if (driver->datafile && strlen(driver->datafile)) {
if (!strequal(driver->datafile, driver->driverpath)) {
slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->datafile);
slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->datafile);
return False;
}
}
+ }
+ if (driver->configfile && strlen(driver->configfile)) {
if (!strequal(driver->configfile, driver->driverpath) &&
!strequal(driver->configfile, driver->datafile)) {
slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->configfile);
return False;
}
}
+ }
+ if (driver->helpfile && strlen(driver->helpfile)) {
if (!strequal(driver->helpfile, driver->driverpath) &&
!strequal(driver->helpfile, driver->datafile) &&
!strequal(driver->helpfile, driver->configfile)) {
return False;
}
}
+ }
if (driver->dependentfiles) {
for (i=0; *driver->dependentfiles[i]; i++) {
return False;
}
}
- NextDriver:
+ NextDriver: ;
}
}
slprintf(key, sizeof(key), "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
+ DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
+
buf = NULL;
len = buflen = 0;
ret = tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ if (ret)
+ DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
+
safe_free(buf);
return ret;
}
ZERO_STRUCT(info3);
info3.cversion = driver->version;
+ fstrcpy(info3.name,driver->name);
fstrcpy(info3.environment,driver->environment);
fstrcpy(info3.driverpath,driver->driverpath);
fstrcpy(info3.datafile,driver->datafile);
/****************************************************************************
****************************************************************************/
-static uint32 add_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
+static uint32 update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
{
pstring key;
char *buf;
int buflen, len, ret;
TDB_DATA kbuf, dbuf;
- NTTIME time_nt;
- time_t time_unix = time(NULL);
/*
* in addprinter: no servername and the printer is the name
* behind a SAMBA share.
*/
- unix_to_nt_time(&time_nt, time_unix);
- info->changeid=time_nt.low;
- info->c_setprinter++;
-
buf = NULL;
buflen = 0;
ZERO_STRUCTP(nt_devmode);
- snprintf(adevice, sizeof(adevice), "\\\\%s\\%s", global_myname, default_devicename);
- fstrcpy(nt_devmode->devicename, adevice);
-
+ safe_strcpy(adevice, default_devicename, sizeof(adevice));
+ fstrcpy(nt_devmode->devicename, adevice);
fstrcpy(nt_devmode->formname, "Letter");
nt_devmode->scale = 0x64;
nt_devmode->copies = 01;
nt_devmode->defaultsource = BIN_FORMSOURCE;
- nt_devmode->printquality = 0x0258;
+ nt_devmode->printquality = RES_HIGH; /* 0x0258 */
nt_devmode->color = COLOR_MONOCHROME;
nt_devmode->duplex = DUP_SIMPLEX;
nt_devmode->yresolution = 0;
snum = lp_servicenumber(sharename);
- fstrcpy(info.servername, global_myname);
- fstrcpy(info.printername, sharename);
+ slprintf(info.servername, sizeof(info.servername), "\\\\%s", global_myname);
+ slprintf(info.printername, sizeof(info.printername), "\\\\%s\\%s",
+ global_myname, sharename);
+ fstrcpy(info.sharename, sharename);
fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
fstrcpy(info.drivername, lp_printerdriver(snum));
pstrcpy(info.comment, "");
info.attributes = PRINTER_ATTRIBUTE_SHARED \
| PRINTER_ATTRIBUTE_LOCAL \
- | PRINTER_ATTRIBUTE_RAW_ONLY ; /* attributes */
+ | PRINTER_ATTRIBUTE_RAW_ONLY \
+ | PRINTER_ATTRIBUTE_QUEUED ; /* attributes */
info.starttime = 0; /* Minutes since 12:00am GMT */
info.untiltime = 0; /* Minutes since 12:00am GMT */
info.priority = 1;
info.default_priority = 1;
+ info.setuptime = (uint32)time(NULL);
if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL)
goto fail;
kbuf.dsize = strlen(key)+1;
dbuf = tdb_fetch(tdb, kbuf);
-#if 1 /* JRATEST */
if (!dbuf.dptr)
return get_a_printer_2_default(info_ptr, sharename);
-#else
- if (!dbuf.dptr) return 1;
-#endif
len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
&info.attributes,
len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
len += unpack_specifics(&info.specific,dbuf.dptr+len, dbuf.dsize-len);
-#if 1 /* JRATEST */
nt_printing_getsec(sharename, &info.secdesc_buf);
-#endif /* JRATEST */
safe_free(dbuf.dptr);
*info_ptr=memdup(&info, sizeof(info));
*/
/****************************************************************************
+ Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
+****************************************************************************/
+
+uint32 mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+{
+ uint32 success;
+
+ dump_a_printer(printer, level);
+
+ switch (level)
+ {
+ case 2:
+ {
+ printer.info_2->c_setprinter++;
+ success=update_a_printer_2(printer.info_2);
+ break;
+ }
+ default:
+ success=1;
+ break;
+ }
+
+ return (success);
+}
+
+/****************************************************************************
+ Add a printer. This is called from ADDPRINTER(EX) and also SETPRINTER.
+ We split this out from mod_a_printer as it updates the id's and timestamps.
****************************************************************************/
+
uint32 add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
{
uint32 success;
{
case 2:
{
- success=add_a_printer_2(printer.info_2);
+ /*
+ * Update the changestamp.
+ * Note we must *not* do this in mod_a_printer().
+ */
+ NTTIME time_nt;
+ time_t time_unix = time(NULL);
+ unix_to_nt_time(&time_nt, time_unix);
+ printer.info_2->changeid=time_nt.low;
+
+ printer.info_2->c_setprinter++;
+ success=update_a_printer_2(printer.info_2);
break;
}
default:
{
case 3:
{
- success=get_a_printer_driver_3(&(driver->info_3),
- printername,
- architecture, version);
+ success=get_a_printer_driver_3(&driver->info_3, printername, architecture, version);
break;
}
default:
break;
}
- if (success == 0) dump_a_printer_driver(*driver, level);
+ if (success == 0)
+ dump_a_printer_driver(*driver, level);
return (success);
}
while (param != NULL)
{
+#if 1 /* JRA - I think this should be case insensitive.... */
+ if ( strequal(value, param->value)
+#else
if ( !strcmp(value, param->value)
+#endif
&& strlen(value)==strlen(param->value))
break;
uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
{
- SEC_DESC_BUF *new_secdesc_ctr = NULL;
- SEC_DESC_BUF *old_secdesc_ctr = NULL;
prs_struct ps;
TALLOC_CTX *mem_ctx = NULL;
fstring key;
uint32 status;
mem_ctx = talloc_init();
- if (mem_ctx == NULL)
- return False;
-
- /* The old owner and group sids of the security descriptor are not
- present when new ACEs are added or removed by changing printer
- permissions through NT. If they are NULL in the new security
- descriptor then copy them over from the old one. */
-
- if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
- DOM_SID *owner_sid, *group_sid;
- SEC_DESC *psd = NULL;
- size_t size;
-
- nt_printing_getsec(printername, &old_secdesc_ctr);
-
- /* Pick out correct owner and group sids */
-
- owner_sid = secdesc_ctr->sec->owner_sid ?
- secdesc_ctr->sec->owner_sid :
- old_secdesc_ctr->sec->owner_sid;
-
- group_sid = secdesc_ctr->sec->grp_sid ?
- secdesc_ctr->sec->grp_sid :
- old_secdesc_ctr->sec->grp_sid;
-
- /* Make a deep copy of the security descriptor */
-
- psd = make_sec_desc(secdesc_ctr->sec->revision,
- secdesc_ctr->sec->type,
- owner_sid, group_sid,
- secdesc_ctr->sec->sacl,
- secdesc_ctr->sec->dacl,
- &size);
-
- new_secdesc_ctr = make_sec_desc_buf(size, psd);
-
- /* Free up memory */
-
- free_sec_desc(&psd);
- free_sec_desc_buf(&old_secdesc_ctr);
- }
-
- if (!new_secdesc_ctr) {
- new_secdesc_ctr = secdesc_ctr;
- }
+ if (mem_ctx == NULL) return False;
/* Store the security descriptor in a tdb */
- prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
+ prs_init(&ps, (uint32)sec_desc_size(secdesc_ctr->sec) +
sizeof(SEC_DESC_BUF), 4, mem_ctx, MARSHALL);
- if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
- &ps, 1)) {
+ if (!sec_io_desc_buf("nt_printing_setsec", &secdesc_ctr, &ps, 1)) {
status = ERROR_INVALID_FUNCTION;
- goto out;
+ goto done;
}
slprintf(key, sizeof(key), "SECDESC/%s", printername);
/* Free mallocated memory */
- out:
- free_sec_desc_buf(&old_secdesc_ctr);
+ done:
+ prs_mem_free(&ps);
- if (new_secdesc_ctr != secdesc_ctr) {
- free_sec_desc_buf(&new_secdesc_ctr);
- }
+ if (mem_ctx) talloc_destroy(mem_ctx);
- prs_mem_free(&ps);
- if (mem_ctx)
- talloc_destroy(mem_ctx);
return status;
}
*/
/****************************************************************************
- Check a user has permissions to perform the given operation
+ Check a user has permissions to perform the given operation. We use some
+ constants defined in include/rpc_spoolss.h that look relevant to check
+ the various actions we perform when checking printer access.
+
+ PRINTER_ACCESS_ADMINISTER:
+ print_queue_pause, print_queue_resume, update_printer_sec,
+ update_printer, spoolss_addprinterex_level_2,
+ _spoolss_setprinterdata
+
+ PRINTER_ACCESS_USE:
+ print_job_start
+
+ JOB_ACCESS_ADMINISTER:
+ print_job_delete, print_job_pause, print_job_resume,
+ print_queue_purge
- if user is NULL then use the current_user structure
****************************************************************************/
-BOOL print_access_check(struct current_user *user, int snum,
- uint32 required_access)
+BOOL print_access_check(struct current_user *user, int snum, int access_type)
{
SEC_DESC_BUF *secdesc = NULL;
- uint32 access_granted, status;
+ uint32 access_granted, status, required_access = 0;
BOOL result;
char *pname;
int i;
extern struct current_user current_user;
+ /* If user is NULL then use the current_user structure */
+
if (!user) user = ¤t_user;
- /* always allow root or printer admins to do anything */
- if (user->uid==0 ||
+ /* Always allow root or printer admins to do anything */
+
+ if (user->uid == 0 ||
user_in_list(uidtoname(user->uid), lp_printer_admin(snum))) {
return True;
}
/* Get printer name */
+
pname = PRINTERNAME(snum);
+
if (!pname || !*pname)
pname = SERVICE(snum);
}
/* Get printer security descriptor */
+
nt_printing_getsec(pname, &secdesc);
+ /* Check against NT4 ACE mask values. From observation these
+ values are:
+
+ Access Type ACE Mask Constant
+ -------------------------------------
+ Full Control 0x10000000 PRINTER_ACE_FULL_CONTROL
+ Print 0xe0000000 PRINTER_ACE_PRINT
+ Manage Documents 0x00020000 PRINTER_ACE_MANAGE_DOCUMENTS
+ */
+
+ switch (access_type) {
+ case PRINTER_ACCESS_USE:
+ required_access = PRINTER_ACE_PRINT;
+ break;
+ case PRINTER_ACCESS_ADMINISTER:
+ required_access = PRINTER_ACE_MANAGE_DOCUMENTS |
+ PRINTER_ACE_PRINT;
+ break;
+ case JOB_ACCESS_ADMINISTER:
+ required_access = PRINTER_ACE_MANAGE_DOCUMENTS;
+ break;
+ default:
+ DEBUG(0, ("invalid value passed to print_access_check()\n"));
+ result = False;
+ goto done;
+ }
+
/* The ACE for Full Control in a printer security descriptor
doesn't seem to map properly to the access checking model. For
it to work properly it should be the logical OR of all the other
performing the access check. I'm sure there is a better way to
do this! */
- /* You forgot to also change the *required access* from PRINTER_ACE_FULL_CONTROL
- to PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT before doing the check.
- This took me 3 hours to find !!!!! JRA.
- */
-
- if (required_access & PRINTER_ACE_FULL_CONTROL) {
- required_access |= (PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT);
- required_access &= ~PRINTER_ACE_FULL_CONTROL;
- }
-
if (secdesc && secdesc->sec && secdesc->sec->dacl &&
secdesc->sec->dacl->ace) {
for(i = 0; i < secdesc->sec->dacl->num_aces; i++) {
}
}
- /* Check access */
+ if ((result = se_access_check(secdesc->sec, user, required_access,
+ &access_granted, &status))) {
+ goto done;
+ }
+
+ /* Check against NT5 ACE mask values. From observation these
+ values are:
+
+ Access Type ACE Mask Constant
+ -------------------------------------
+ Full Control 0x000f000c PRINTER_ACE_NT5_FULL_CONTROL
+ Print 0x00020008 PRINTER_ACE_NT5_PRINT
+ Manage Documents 0x00020000 PRINTER_ACE_NT5_MANAGE_DOCUMENTS
+
+ NT5 likes to rewrite the security descriptor and change the ACE
+ masks from NT4 format to NT5 format making them unreadable by
+ NT4 clients. */
+
+ switch (access_type) {
+ case PRINTER_ACCESS_USE:
+ required_access = PRINTER_ACE_NT5_PRINT;
+ break;
+ case PRINTER_ACCESS_ADMINISTER:
+ required_access = PRINTER_ACE_NT5_FULL_CONTROL;
+ break;
+ case JOB_ACCESS_ADMINISTER:
+ required_access = PRINTER_ACE_NT5_MANAGE_DOCUMENTS;
+ break;
+ }
result = se_access_check(secdesc->sec, user, required_access,
&access_granted, &status);
+ /* Check access */
+
+ done:
DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
-
+
/* Free mallocated memory */
+
free_sec_desc_buf(&secdesc);
if (!result)
free_a_printer(&printer, 2);
+ if (!ok)
+ errno = EACCES;
+
return ok;
}