X-Git-Url: http://git.samba.org/?p=samba.git;a=blobdiff_plain;f=source3%2Fprinting%2Fnt_printing.c;h=2572a98bdea495315df7d9fa91ddaece0b6511a5;hp=a39ca39778226dc86b94076cacde4fa7302232ef;hb=3380ffae9c231a34406dd694c9ab03bb0b6d8070;hpb=588d802877ec5c1969d8f0a79875382bfa91c032 diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index a39ca397782..2572a98bdea 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -1,21 +1,21 @@ #define OLD_NTDOMAIN 1 -/* +/* * Unix SMB/Netbios implementation. * Version 1.9. * RPC Pipe client / server routines * Copyright (C) Andrew Tridgell 1992-2000, * Copyright (C) Jean François Micouleau 1998-2000. - * + * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -25,7 +25,7 @@ extern int DEBUGLEVEL; extern pstring global_myname; -extern DOM_SID global_sid_World; +extern DOM_SID global_sid_World; static TDB_CONTEXT *tdb; /* used for driver files */ @@ -35,11 +35,21 @@ static TDB_CONTEXT *tdb; /* used for driver files */ #define DATABASE_VERSION 1 -/* we need to have a small set of default forms to support our - default printer */ +/* Map generic permissions to printer object specific permissions */ + +struct generic_mapping printer_generic_mapping = { + PRINTER_READ, + PRINTER_WRITE, + PRINTER_EXECUTE, + PRINTER_ALL_ACCESS +}; + +/* 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} }; @@ -49,6 +59,7 @@ open the NT printing tdb 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); @@ -60,17 +71,17 @@ BOOL nt_printing_init(void) 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; } - + /**************************************************************************** get a form struct list ****************************************************************************/ @@ -79,10 +90,11 @@ int get_ntforms(nt_forms_struct **list) TDB_DATA kbuf, newkey, dbuf; nt_forms_struct form; int ret; + int i; int n = 0; - for (kbuf = tdb_firstkey(tdb); - kbuf.dptr; + for (kbuf = tdb_firstkey(tdb); + kbuf.dptr; newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) { if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0) continue; @@ -90,15 +102,18 @@ int get_ntforms(nt_forms_struct **list) 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 */ @@ -122,12 +137,14 @@ int write_ntforms(nt_forms_struct **list, int number) int i; for (i=0;i sizeof(buf)) break; slprintf(key, sizeof(key), "%s%s", FORMS_PREFIX, (*list)[i].name); + dos_to_unix(key, True); /* Convert key to unix-codepage */ kbuf.dsize = strlen(key)+1; kbuf.dptr = key; dbuf.dsize = len; @@ -147,8 +164,8 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count) BOOL update; fstring form_name; - /* - * NT tries to add forms even when + /* + * NT tries to add forms even when * they are already in the base * only update the values if already present */ @@ -156,17 +173,15 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count) update=False; 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))) - { + for (n=0; n<*count; n++) { + if (!strncmp((*list)[n].name, form_name, strlen(form_name))) { DEBUG(103, ("NT workaround, [%s] already exists\n", form_name)); update=True; + break; } } - if (update==False) - { + if (update==False) { 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); @@ -185,7 +200,7 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count) } /**************************************************************************** - delete a named form struct + delete a named form struct ****************************************************************************/ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32 *ret) { @@ -221,6 +236,7 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32 } slprintf(key, sizeof(key), "%s%s", FORMS_PREFIX, (*list)[n].name); + dos_to_unix(key, True); /* Convert key to unix-codepage */ kbuf.dsize = strlen(key)+1; kbuf.dptr = key; if (tdb_delete(tdb, kbuf) != 0) { @@ -232,7 +248,7 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32 } /**************************************************************************** -update a form struct +update a form struct ****************************************************************************/ void update_a_form(nt_forms_struct **list, const FORM *form, int count) { @@ -258,7 +274,7 @@ void update_a_form(nt_forms_struct **list, const FORM *form, int count) (*list)[n].right=form->right; (*list)[n].bottom=form->bottom; } - + /**************************************************************************** get the nt drivers list @@ -274,8 +290,8 @@ int get_ntdrivers(fstring **list, char *architecture, uint32 version) get_short_archi(short_archi, architecture); slprintf(key, sizeof(key), "%s%s/%d/", DRIVERS_PREFIX, short_archi, version); - for (kbuf = tdb_firstkey(tdb); - kbuf.dptr; + for (kbuf = tdb_firstkey(tdb); + kbuf.dptr; newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) { if (strncmp(kbuf.dptr, key, strlen(key)) != 0) continue; @@ -315,7 +331,7 @@ BOOL get_short_archi(char *short_archi, char *long_archi) DEBUG(107,("Getting architecture dependant directory\n")); do { i++; - } while ( (archi_table[i].long_archi!=NULL ) && + } while ( (archi_table[i].long_archi!=NULL ) && StrCaseCmp(long_archi, archi_table[i].long_archi) ); if (archi_table[i].long_archi==NULL) { @@ -332,18 +348,236 @@ BOOL get_short_archi(char *short_archi, char *long_archi) return TRUE; } +/**************************************************************************** +Determine the correct cVersion associated with an architecture and driver +****************************************************************************/ +static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in, + struct current_user *user, uint32 *perr) +{ + int cversion; + int access_mode; + int action; + int ecode; + char buf[PE_HEADER_SIZE]; + ssize_t byte_count; + pstring driverpath; + fstring user_name; + fstring null_pw; + files_struct *fsp = NULL; + BOOL bad_path; + SMB_STRUCT_STAT st; + struct passwd *pass; + connection_struct *conn; + + ZERO_STRUCT(st); + + /* 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; + } + + become_root(); + pass = getpwuid(user->uid); + if(pass == NULL) { + DEBUG(0,("get_correct_cversion: Unable to get passwd entry for uid %u\n", + (unsigned int)user->uid )); + unbecome_root(); + *perr = ERROR_ACCESS_DENIED; + return -1; + } + unbecome_root(); + + /* connect to the print$ share under the same account as the user connected + * to the rpc pipe */ + fstrcpy(user_name, pass->pw_name ); + DEBUG(10,("get_correct_cversion: uid %d -> user %s\n", (int)user->uid, user_name)); + + /* Null password is ok - we are already an authenticated user... */ + *null_pw = '\0'; + conn = make_connection("print$", user_name, null_pw, 0, "A:", user->vuid, &ecode); + + if (conn == NULL) { + DEBUG(0,("get_correct_cversion: Unable to connect\n")); + *perr = (uint32)ecode; + return -1; + } + + /* Save who we are - we are temporarily becoming the connection user. */ + push_sec_ctx(); + + if (!become_user(conn, conn->vuid)) { + DEBUG(0,("get_correct_cversion: Can't become user %s\n", user_name )); + *perr = ERROR_ACCESS_DENIED; + pop_sec_ctx(); + return -1; + } + + /* Open the driver file (Portable Executable format) and determine the + * deriver the cversion. */ + slprintf(driverpath, sizeof(driverpath), "%s/%s", architecture, driverpath_in); + + unix_convert(driverpath,conn,NULL,&bad_path,&st); + + fsp = open_file_shared(conn, driverpath, &st, + SET_OPEN_MODE(DOS_OPEN_RDONLY), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + 0, 0, &access_mode, &action); + if (!fsp) { + DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n", + driverpath, errno)); + *perr = ERROR_ACCESS_DENIED; + goto error_exit; + } + + if ((byte_count = vfs_read_data(fsp, 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)); + *perr = NT_STATUS_FILE_INVALID; + 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))); + *perr = NT_STATUS_FILE_INVALID; + goto error_exit; + } + + /* Skip OEM header (if any) and the DOS stub to start of Windows header */ + if (fsp->conn->vfs_ops.lseek(fsp, fsp->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)); + *perr = NT_STATUS_FILE_INVALID; + goto error_exit; + } + + if ((byte_count = vfs_read_data(fsp, 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)); + *perr = NT_STATUS_FILE_INVALID; + goto error_exit; + } + + /* 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))); + *perr = NT_STATUS_FILE_INVALID; + 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))); + *perr = NT_STATUS_FILE_INVALID; + 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))); + *perr = NT_STATUS_FILE_INVALID; + 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))); + *perr = NT_STATUS_FILE_INVALID; + goto error_exit; + } + + } else { + DEBUG(6,("get_correct_cversion: Unknown file format [%s], signature = 0x%x\n", + driverpath, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET))); + *perr = NT_STATUS_FILE_INVALID; + goto error_exit; + } + + DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n", + driverpath, cversion)); + + fsp->conn->vfs_ops.close(fsp, fsp->fd); + file_free(fsp); + close_cnum(conn, user->vuid); + pop_sec_ctx(); + return cversion; + + + error_exit: + if(fsp) { + if(fsp->fd != -1) + fsp->conn->vfs_ops.close(fsp, fsp->fd); + file_free(fsp); + } + + close_cnum(conn, user->vuid); + pop_sec_ctx(); + return -1; +} + /**************************************************************************** ****************************************************************************/ -static void clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver) +static uint32 clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver, + struct current_user *user) { fstring architecture; fstring new_name; char *p; int i; + uint32 err; + + /* 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) @@ -352,17 +586,23 @@ static void clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *drive * NT 4: cversion=2 * NT2K: cversion=3 */ + if ((driver->cversion = get_correct_cversion( architecture, + driver->driverpath, user, &err)) == -1) + return err; - 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. - */ - - if (StrCaseCmp(driver->environment, "Windows 4.0")==0) - driver->cversion=0; - else - driver->cversion=2; + return NT_STATUS_NO_PROBLEMO; +} + +/**************************************************************************** +****************************************************************************/ +static uint32 clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, + struct current_user *user) +{ + fstring architecture; + fstring new_name; + char *p; + int i; + uint32 err; /* clean up the driver name. * we can get .\driver.dll @@ -397,34 +637,47 @@ static void clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *drive } } } -} -/**************************************************************************** -****************************************************************************/ -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, user, &err)) == -1) + return err; + + 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, struct current_user *user) { switch (level) { case 3: { NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver; driver=driver_abstract.info_3; - clean_up_driver_struct_level_3(driver); - break; + return clean_up_driver_struct_level_3(driver, user); } case 6: { NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver; driver=driver_abstract.info_6; - clean_up_driver_struct_level_6(driver); - break; + return clean_up_driver_struct_level_6(driver, user); } + default: + return ERROR_INVALID_PARAMETER; } } @@ -447,6 +700,377 @@ static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PR dst->dependentfiles = src->dependentfiles; } +#if 0 /* Debugging function */ + +static char* ffmt(unsigned char *c){ + int i; + static char ffmt_str[17]; + + for (i=0; i<16; i++) { + if ((c[i] < ' ') || (c[i] > '~')) + ffmt_str[i]='.'; + else + ffmt_str[i]=c[i]; + } + ffmt_str[16]='\0'; + return ffmt_str; +} + +#endif + +/**************************************************************************** +Version information in Microsoft files is held in a VS_VERSION_INFO structure. +There are two case to be covered here: PE (Portable Executable) and NE (New +Executable) files. Both files support the same INFO structure, but PE files +store the signature in unicode, and NE files store it as !unicode. +****************************************************************************/ +static BOOL get_file_version(files_struct *fsp, char *fname,uint32 *major, + uint32 *minor) +{ + int i; + char *buf; + ssize_t byte_count; + + if ((buf=malloc(PE_HEADER_SIZE)) == NULL) { + DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n", + fname, PE_HEADER_SIZE)); + goto error_exit; + } + + /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */ + if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) { + DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %d\n", + fname, byte_count)); + goto no_version_info; + } + + /* Is this really a DOS header? */ + if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) { + DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n", + fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET))); + goto no_version_info; + } + + /* Skip OEM header (if any) and the DOS stub to start of Windows header */ + if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) { + DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n", + fname, errno)); + /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ + goto no_version_info; + } + + if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) { + DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %d\n", + fname, byte_count)); + /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ + goto no_version_info; + } + + /* The header may be a PE (Portable Executable) or an NE (New Executable) */ + if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) { + int num_sections; + int section_table_bytes; + + if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) { + DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n", + fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET))); + /* At this point, we assume the file is in error. It still could be somthing + * else besides a PE file, but it unlikely at this point. + */ + goto error_exit; + } + + /* get the section table */ + num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS); + section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE; + free(buf); + if ((buf=malloc(section_table_bytes)) == NULL) { + DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n", + fname, section_table_bytes)); + goto error_exit; + } + + if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) { + DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %d\n", + fname, byte_count)); + goto error_exit; + } + + /* Iterate the section table looking for the resource section ".rsrc" */ + for (i = 0; i < num_sections; i++) { + int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE; + + if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) { + int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET); + int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET); + + free(buf); + if ((buf=malloc(section_bytes)) == NULL) { + DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n", + fname, section_bytes)); + goto error_exit; + } + + /* Seek to the start of the .rsrc section info */ + if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) { + DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n", + fname, errno)); + goto error_exit; + } + + if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) { + DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %d\n", + fname, byte_count)); + goto error_exit; + } + + for (i=0; i>16)&0xffff, *major&0xffff, + (*minor>>16)&0xffff, *minor&0xffff)); + free(buf); + return True; + } + } + } + } + } + + /* Version info not found, fall back to origin date/time */ + DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname)); + free(buf); + return False; + + } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) { + if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) { + DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n", + fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET))); + /* At this point, we assume the file is in error. It still could be somthing + * else besides a NE file, but it unlikely at this point. */ + goto error_exit; + } + + /* Allocate a bit more space to speed up things */ + free(buf); + if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) { + DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n", + fname, PE_HEADER_SIZE)); + goto error_exit; + } + + /* This is a HACK! I got tired of trying to sort through the messy + * 'NE' file format. If anyone wants to clean this up please have at + * it, but this works. 'NE' files will eventually fade away. JRR */ + while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) { + /* Cover case that should not occur in a well formed 'NE' .dll file */ + if (byte_count-VS_VERSION_INFO_SIZE <= 0) break; + + for(i=0; ibyte_count-VS_VERSION_INFO_SIZE) { + int bc; + + memcpy(buf, &buf[i], byte_count-i); + if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE- + (byte_count-i))) < 0) { + + DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n", + fname, errno)); + goto error_exit; + } + + byte_count = bc + (byte_count - i); + if (byte_countconn->vfs_ops.lseek(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) + + sizeof(VS_SIGNATURE)) & 3; + if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue; + + *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET); + *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET); + DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n", + fname, *major, *minor, + (*major>>16)&0xffff, *major&0xffff, + (*minor>>16)&0xffff, *minor&0xffff)); + free(buf); + return True; + } + } + } + + /* Version info not found, fall back to origin date/time */ + DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname)); + free(buf); + return False; + + } else + /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ + DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n", + fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET))); + + no_version_info: + free(buf); + return False; + + error_exit: + free(buf); + return -1; +} + +/**************************************************************************** +Drivers for Microsoft systems contain multiple files. Often, multiple drivers +share one or more files. During the MS installation process files are checked +to insure that only a newer version of a shared file is installed over an +older version. There are several possibilities for this comparison. If there +is no previous version, the new one is newer (obviously). If either file is +missing the version info structure, compare the creation date (on Unix use +the modification date). Otherwise chose the numerically larger version number. +****************************************************************************/ +static int file_version_is_newer(connection_struct *conn, fstring new_file, + fstring old_file) +{ + BOOL use_version = True; + pstring filepath; + + uint32 new_major; + uint32 new_minor; + time_t new_create_time; + + uint32 old_major; + uint32 old_minor; + time_t old_create_time; + + int access_mode; + int action; + files_struct *fsp = NULL; + SMB_STRUCT_STAT st; + SMB_STRUCT_STAT stat_buf; + BOOL bad_path; + + ZERO_STRUCT(st); + ZERO_STRUCT(stat_buf); + new_create_time = (time_t)0; + old_create_time = (time_t)0; + + /* Get file version info (if available) for previous file (if it exists) */ + pstrcpy(filepath, old_file); + + unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); + + fsp = open_file_shared(conn, filepath, &stat_buf, + SET_OPEN_MODE(DOS_OPEN_RDONLY), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + 0, 0, &access_mode, &action); + if (!fsp) { + /* Old file not found, so by definition new file is in fact newer */ + DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n", + filepath, errno)); + return True; + + } else { + int ret = get_file_version(fsp, old_file, &old_major, &old_minor); + if (ret == -1) goto error_exit; + + if (!ret) { + DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n", + old_file)); + use_version = False; + if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit; + old_create_time = st.st_mtime; + DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time)); + } + } + fsp->conn->vfs_ops.close(fsp, fsp->fd); + file_free(fsp); + + + /* Get file version info (if available) for new file */ + pstrcpy(filepath, new_file); + unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); + + fsp = open_file_shared(conn, filepath, &stat_buf, + SET_OPEN_MODE(DOS_OPEN_RDONLY), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + 0, 0, &access_mode, &action); + if (!fsp) { + /* New file not found, this shouldn't occur if the caller did its job */ + DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n", + filepath, errno)); + goto error_exit; + + } else { + int ret = get_file_version(fsp, new_file, &new_major, &new_minor); + if (ret == -1) goto error_exit; + + if (!ret) { + DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n", + new_file)); + use_version = False; + if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit; + new_create_time = st.st_mtime; + DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time)); + } + } + fsp->conn->vfs_ops.close(fsp, fsp->fd); + file_free(fsp); + + if (use_version) { + /* Compare versions and choose the larger version number */ + if (new_major > old_major || + (new_major == old_major && new_minor > old_minor)) { + + DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file)); + return True; + } + else { + DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file)); + return False; + } + + } else { + /* Compare modification time/dates and choose the newest time/date */ + if (new_create_time > old_create_time) { + DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file)); + return True; + } + else { + DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file)); + return False; + } + } + + error_exit: + if(fsp) { + file_free(fsp); + if(fsp->fd != -1) + fsp->conn->vfs_ops.close(fsp, fsp->fd); + } + return -1; +} + /**************************************************************************** ****************************************************************************/ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, struct current_user *user, uint32 *perr) @@ -462,8 +1086,9 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, connection_struct *conn; pstring inbuf; pstring outbuf; - struct smb_passwd *smb_pass; + struct passwd *pass; int ecode; + int ver = 0; int outsize = 0; int i; @@ -484,9 +1109,9 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, get_short_archi(architecture, driver->environment); become_root(); - smb_pass = getsmbpwuid(user->uid); - if(smb_pass == NULL) { - DEBUG(0,("move_driver_to_download_area: Unable to get smbpasswd entry for uid %u\n", + pass = getpwuid(user->uid); + if(pass == NULL) { + DEBUG(0,("move_driver_to_download_area: Unable to get passwd entry for uid %u\n", (unsigned int)user->uid )); unbecome_root(); return False; @@ -494,7 +1119,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, unbecome_root(); /* connect to the print$ share under the same account as the user connected to the rpc pipe */ - fstrcpy(user_name, smb_pass->smb_name ); + fstrcpy(user_name, pass->pw_name ); DEBUG(10,("move_driver_to_download_area: uid %d -> user %s\n", (int)user->uid, user_name)); /* Null password is ok - we are already an authenticated user... */ @@ -519,86 +1144,112 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, return False; } - /* - * make the directories version and version\driver_name + /* + * make the directories version and version\driver_name * under the architecture directory. */ DEBUG(5,("Creating first directory\n")); - slprintf(new_dir, sizeof(new_dir), "%s\\%d", architecture, driver->cversion); + slprintf(new_dir, sizeof(new_dir), "%s/%d", architecture, driver->cversion); mkdir_internal(conn, inbuf, outbuf, new_dir); - /* move all the files, one by one, - * from archi\filexxx.yyy to - * archi\version\filexxx.yyy + /* For each driver file, archi\filexxx.yyy, if there is a duplicate file + * listed for this driver which has already been moved, skip it (note: + * drivers may list the same file name several times. Then check if the + * file already exists in archi\cversion\, if so, check that the version + * info (or time stamps if version info is unavailable) is newer (or the + * date is later). If it is, move it to archi\cversion\filexxx.yyy. + * Otherwise, delete the file. * - * Note: drivers may list the same file name in several places. This - * causes problems on a second attempt to move the file. JRR - * - * Note: use the replace flag on rename_internals() call, otherwise it - * is very difficult to change previously installed drivers... the Windows - * GUI offers the user the choice to replace or keep exisitng driver. JRR + * If a file is not moved to archi\cversion\ because of an error, all the + * rest of the 'unmoved' driver files are removed from archi\. If one or + * more of the driver's files was already moved to archi\cversion\, it + * potentially leaves the driver in a partially updated state. Version + * trauma will most likely occur if an client attempts to use any printer + * bound to the driver. Perhaps a rewrite to make sure the moves can be + * done is appropriate... later JRR */ - DEBUG(5,("Moving file now !\n")); - 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) { - DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n", - old_name, new_name )); - close_cnum(conn, user->vuid); - pop_sec_ctx(); - *perr = (uint32)SVAL(outbuf,smb_err); - return False; - } - - 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); - if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) { - DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n", - old_name, new_name )); - close_cnum(conn, user->vuid); - pop_sec_ctx(); - *perr = (uint32)SVAL(outbuf,smb_err); - return False; + DEBUG(5,("Moving files now !\n")); + + if (driver->driverpath && strlen(driver->driverpath)) { + slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->driverpath); + slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->driverpath); + if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { + if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) { + DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", + new_name, old_name)); + *perr = (uint32)SVAL(outbuf,smb_err); + unlink_internals(conn, inbuf, outbuf, 0, new_name); + ver = -1; + } + } + else + unlink_internals(conn, inbuf, outbuf, 0, new_name); + } + + if (driver->datafile && strlen(driver->datafile)) { + if (!strequal(driver->datafile, driver->driverpath)) { + slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->datafile); + slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->datafile); + if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { + if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) { + DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", + new_name, old_name)); + *perr = (uint32)SVAL(outbuf,smb_err); + unlink_internals(conn, inbuf, outbuf, 0, new_name); + ver = -1; + } + } + else + unlink_internals(conn, inbuf, outbuf, 0, new_name); } } - if (!strequal(driver->configfile, driver->driverpath) && - !strequal(driver->configfile, driver->datafile)) { - slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->configfile); - slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->configfile); - if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) { - DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n", - old_name, new_name )); - close_cnum(conn, user->vuid); - pop_sec_ctx(); - *perr = (uint32)SVAL(outbuf,smb_err); - return False; + if (driver->configfile && strlen(driver->configfile)) { + if (!strequal(driver->configfile, driver->driverpath) && + !strequal(driver->configfile, driver->datafile)) { + slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->configfile); + slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->configfile); + if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { + if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) { + DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", + new_name, old_name)); + *perr = (uint32)SVAL(outbuf,smb_err); + unlink_internals(conn, inbuf, outbuf, 0, new_name); + ver = -1; + } + } + else + unlink_internals(conn, inbuf, outbuf, 0, new_name); } } - if (!strequal(driver->helpfile, driver->driverpath) && + if (driver->helpfile && strlen(driver->helpfile)) { + if (!strequal(driver->helpfile, driver->driverpath) && !strequal(driver->helpfile, driver->datafile) && !strequal(driver->helpfile, driver->configfile)) { - slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->helpfile); - slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->helpfile); - if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) { - DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n", - old_name, new_name )); - close_cnum(conn, user->vuid); - pop_sec_ctx(); - *perr = (uint32)SVAL(outbuf,smb_err); - return False; + slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->helpfile); + slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->helpfile); + if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { + if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) { + DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", + new_name, old_name)); + *perr = (uint32)SVAL(outbuf,smb_err); + unlink_internals(conn, inbuf, outbuf, 0, new_name); + ver = -1; + } + } + else + unlink_internals(conn, inbuf, outbuf, 0, new_name); } } if (driver->dependentfiles) { for (i=0; *driver->dependentfiles[i]; i++) { if (!strequal(driver->dependentfiles[i], driver->driverpath) && - !strequal(driver->dependentfiles[i], driver->datafile) && - !strequal(driver->dependentfiles[i], driver->configfile) && - !strequal(driver->dependentfiles[i], driver->helpfile)) { + !strequal(driver->dependentfiles[i], driver->datafile) && + !strequal(driver->dependentfiles[i], driver->configfile) && + !strequal(driver->dependentfiles[i], driver->helpfile)) { int j; for (j=0; j < i; j++) { if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) { @@ -606,25 +1257,28 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, } } - slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->dependentfiles[i]); - slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->dependentfiles[i]); - if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) { - DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n", - old_name, new_name )); - close_cnum(conn, user->vuid); - pop_sec_ctx(); - *perr = (uint32)SVAL(outbuf,smb_err); - return False; + slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->dependentfiles[i]); + slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->dependentfiles[i]); + if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { + if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) { + DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", + new_name, old_name)); + *perr = (uint32)SVAL(outbuf,smb_err); + unlink_internals(conn, inbuf, outbuf, 0, new_name); + ver = -1; + } } + else + unlink_internals(conn, inbuf, outbuf, 0, new_name); } - NextDriver: + NextDriver: ; } } close_cnum(conn, user->vuid); pop_sec_ctx(); - return True; + return ver == -1 ? False : True; } /**************************************************************************** @@ -649,34 +1303,50 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver) slprintf(directory, sizeof(directory), "\\print$\\%s\\%d\\", architecture, driver->cversion); - - fstrcpy(temp_name, driver->driverpath); - slprintf(driver->driverpath, sizeof(driver->driverpath), "%s%s", directory, temp_name); + /* .inf files do not always list a file for each of the four standard files. + * Don't prepend a path to a null filename, or client claims: + * "The server on which the printer resides does not have a suitable + * printer driver installed. Click OK if you + * wish to install the driver on your local machine." + */ + if (strlen(driver->driverpath)) { + fstrcpy(temp_name, driver->driverpath); + slprintf(driver->driverpath, sizeof(driver->driverpath), "%s%s", directory, temp_name); + } - fstrcpy(temp_name, driver->datafile); - slprintf(driver->datafile, sizeof(driver->datafile), "%s%s", directory, temp_name); + if (strlen(driver->datafile)) { + fstrcpy(temp_name, driver->datafile); + slprintf(driver->datafile, sizeof(driver->datafile), "%s%s", directory, temp_name); + } - fstrcpy(temp_name, driver->configfile); - slprintf(driver->configfile, sizeof(driver->configfile), "%s%s", directory, temp_name); + if (strlen(driver->configfile)) { + fstrcpy(temp_name, driver->configfile); + slprintf(driver->configfile, sizeof(driver->configfile), "%s%s", directory, temp_name); + } - fstrcpy(temp_name, driver->helpfile); - slprintf(driver->helpfile, sizeof(driver->helpfile), "%s%s", directory, temp_name); + if (strlen(driver->helpfile)) { + fstrcpy(temp_name, driver->helpfile); + slprintf(driver->helpfile, sizeof(driver->helpfile), "%s%s", directory, temp_name); + } if (driver->dependentfiles) { for (i=0; *driver->dependentfiles[i]; i++) { - fstrcpy(temp_name, driver->dependentfiles[i]); - slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i]), "%s%s", directory, temp_name); + fstrcpy(temp_name, driver->dependentfiles[i]); + slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i]), "%s%s", directory, temp_name); } } slprintf(key, sizeof(key), "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name); + dos_to_unix(key, True); /* Convert key to unix-codepage */ + + DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key )); buf = NULL; len = buflen = 0; again: len = 0; - len += tdb_pack(buf+len, buflen-len, "dffffffff", + len += tdb_pack(buf+len, buflen-len, "dffffffff", driver->cversion, driver->name, driver->environment, @@ -689,7 +1359,7 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver) if (driver->dependentfiles) { for (i=0; *driver->dependentfiles[i]; i++) { - len += tdb_pack(buf+len, buflen-len, "f", + len += tdb_pack(buf+len, buflen-len, "f", driver->dependentfiles[i]); } } @@ -708,6 +1378,9 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver) 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; } @@ -720,6 +1393,7 @@ static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver) 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); @@ -775,17 +1449,6 @@ static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, get_short_archi(architecture, in_arch); - /* - * Note - the version sent here for Win2k is probably (3). Due to the - * hack done in clean_up_driver_struct_level_3() we need to - * do the same hack so we can find the correctly stored driver. JRA. - */ - - if (StrCaseCmp(in_arch, "Windows 4.0")==0) - version=0; - else - version=2; - DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, in_prt)); slprintf(key, sizeof(key), "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, in_prt); @@ -799,7 +1462,7 @@ static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, #else if (!dbuf.dptr) return 5; #endif - len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff", + len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff", &driver.cversion, driver.name, driver.environment, @@ -817,7 +1480,7 @@ static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, if (driver.dependentfiles == NULL) break; - len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f", + len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f", &driver.dependentfiles[i]); i++; } @@ -903,7 +1566,7 @@ debugging function, dump at level 6 the struct in the logs ****************************************************************************/ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level) { - uint32 success; + uint32 result; NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3; int i; @@ -911,10 +1574,10 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 switch (level) { - case 3: + case 3: { if (driver.info_3 == NULL) - success=5; + result=5; else { info3=driver.info_3; @@ -930,20 +1593,20 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 for (i=0; info3->dependentfiles && *info3->dependentfiles[i]; i++) { - DEBUGADD(106,("dependentfile:[%s]\n", + DEBUGADD(106,("dependentfile:[%s]\n", info3->dependentfiles[i])); } - success=0; + result=0; } break; } default: DEBUGADD(1,("Level not implemented\n")); - success=1; + result=1; break; } - return (success); + return result; } /**************************************************************************** @@ -1016,8 +1679,8 @@ static int pack_specifics(NT_PRINTER_PARAM *param, char *buf, int buflen) while (param != NULL) { len += tdb_pack(buf+len, buflen-len, "pfdB", param, - param->value, - param->type, + param->value, + param->type, param->data_len, param->data); param=param->next; @@ -1038,8 +1701,8 @@ uint32 del_a_printer(char *sharename) pstring key; TDB_DATA kbuf; - slprintf(key, sizeof(key), "%s%s", - PRINTERS_PREFIX, sharename); + slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, sharename); + dos_to_unix(key, True); /* Convert key to unix-codepage */ kbuf.dptr=key; kbuf.dsize=strlen(key)+1; @@ -1050,16 +1713,14 @@ uint32 del_a_printer(char *sharename) /**************************************************************************** ****************************************************************************/ -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 * in setprinter: servername is \\server * and printer is \\server\\printer @@ -1084,10 +1745,6 @@ static uint32 add_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info) * behind a SAMBA share. */ - unix_to_nt_time(&time_nt, time_unix); - info->changeid=time_nt.low; - info->c_setprinter++; - buf = NULL; buflen = 0; @@ -1127,8 +1784,8 @@ static uint32 add_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info) } - slprintf(key, sizeof(key), "%s%s", - PRINTERS_PREFIX, info->sharename); + slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, info->sharename); + dos_to_unix(key, True); /* Convert key to unix-codepage */ kbuf.dptr = key; kbuf.dsize = strlen(key)+1; @@ -1142,7 +1799,7 @@ static uint32 add_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info) safe_free(buf); - DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n", + DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n", info->sharename, info->drivername, info->portname, len)); return ret; @@ -1151,17 +1808,17 @@ static uint32 add_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info) /**************************************************************************** ****************************************************************************/ -BOOL add_a_specific_param(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *param) +void add_a_specific_param(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM **param) { NT_PRINTER_PARAM *current; DEBUG(108,("add_a_specific_param\n")); - param->next=NULL; + (*param)->next=NULL; if (info_2->specific == NULL) { - info_2->specific=param; + info_2->specific=*param; } else { @@ -1169,9 +1826,10 @@ BOOL add_a_specific_param(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *par while (current->next != NULL) { current=current->next; } - current->next=param; + current->next=*param; } - return (True); + + *param = NULL; } /**************************************************************************** @@ -1186,7 +1844,7 @@ BOOL unlink_specific_param_if_exist(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_ if (current==NULL) return (False); - if ( !strcmp(current->value, param->value) && + if ( !strcmp(current->value, param->value) && (strlen(current->value)==strlen(param->value)) ) { DEBUG(109,("deleting first value\n")); info_2->specific=current->next; @@ -1218,7 +1876,7 @@ BOOL unlink_specific_param_if_exist(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_ /**************************************************************************** Clean up and deallocate a (maybe partially) allocated NT_PRINTER_PARAM. ****************************************************************************/ -static void free_nt_printer_param(NT_PRINTER_PARAM **param_ptr) +void free_nt_printer_param(NT_PRINTER_PARAM **param_ptr) { NT_PRINTER_PARAM *param = *param_ptr; @@ -1255,9 +1913,8 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename) 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"); @@ -1265,8 +1922,8 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename) nt_devmode->driverversion = 0x0400; nt_devmode->size = 0x00DC; nt_devmode->driverextra = 0x0000; - nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY | - DEFAULTSOURCE | COPIES | SCALE | + nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY | + DEFAULTSOURCE | COPIES | SCALE | PAPERSIZE | ORIENTATION; nt_devmode->orientation = 1; nt_devmode->papersize = PAPER_LETTER; @@ -1275,7 +1932,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename) 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; @@ -1412,7 +2069,7 @@ static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen) &devmode.ttoption, &devmode.collate, &devmode.logpixels, - + &devmode.fields, &devmode.bitsperpel, &devmode.pelswidth, @@ -1435,6 +2092,11 @@ static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen) */ len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private); devmode.driverextra=(uint16)extra_len; + + /* check to catch an invalid TDB entry so we don't segfault */ + if (devmode.driverextra == 0) { + devmode.private = NULL; + } } *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode)); @@ -1460,8 +2122,8 @@ static int unpack_specifics(NT_PRINTER_PARAM **list, char *buf, int buflen) if (!p) break; len += tdb_unpack(buf+len, buflen-len, "fdB", - param.value, - ¶m.type, + param.value, + ¶m.type, ¶m.data_len, ¶m.data); param.next = *list; @@ -1487,22 +2149,32 @@ static uint32 get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin 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)); + + if (!*info.drivername) + fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER"); + + DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername)); + pstrcpy(info.comment, ""); fstrcpy(info.printprocessor, "winprint"); fstrcpy(info.datatype, "RAW"); 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; @@ -1535,21 +2207,19 @@ static uint32 get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen NT_PRINTER_INFO_LEVEL_2 info; int len = 0; TDB_DATA kbuf, dbuf; + fstring printername; ZERO_STRUCT(info); slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, sharename); + dos_to_unix(key, True); /* Convert key to unix-codepage */ kbuf.dptr = key; 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, @@ -1578,18 +2248,22 @@ static uint32 get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen /* Samba has to have shared raw drivers. */ info.attributes |= (PRINTER_ATTRIBUTE_SHARED|PRINTER_ATTRIBUTE_RAW_ONLY); + /* Restore the stripped strings. */ + slprintf(info.servername, sizeof(info.servername), "\\\\%s", global_myname); + slprintf(printername, sizeof(printername), "\\\\%s\\%s", global_myname, + info.printername); + fstrcpy(info.printername, printername); + 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)); - DEBUG(9,("Unpacked printer [%s] running driver [%s]\n", - sharename, info.drivername)); + DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n", + sharename, info.printername, info.drivername)); return 0; @@ -1600,17 +2274,17 @@ debugging function, dump at level 6 the struct in the logs ****************************************************************************/ static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level) { - uint32 success; + uint32 result; NT_PRINTER_INFO_LEVEL_2 *info2; DEBUG(106,("Dumping printer at level [%d]\n", level)); switch (level) { - case 2: + case 2: { if (printer.info_2 == NULL) - success=5; + result=5; else { info2=printer.info_2; @@ -1638,17 +2312,17 @@ static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level) DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor)); DEBUGADD(106,("datatype:[%s]\n", info2->datatype)); DEBUGADD(106,("parameters:[%s]\n", info2->parameters)); - success=0; + result=0; } break; } default: DEBUGADD(1,("Level not implemented\n")); - success=1; + result=1; break; } - return (success); + return result; } /**************************************************************************** @@ -1678,26 +2352,65 @@ void get_printer_subst_params(int snum, fstring *printername, fstring *sharename */ /**************************************************************************** + Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA. +****************************************************************************/ + +uint32 mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level) +{ + uint32 result; + + dump_a_printer(printer, level); + + switch (level) + { + case 2: + { + printer.info_2->c_setprinter++; + result=update_a_printer_2(printer.info_2); + break; + } + default: + result=1; + break; + } + + return result; +} + +/**************************************************************************** + 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; + uint32 result; dump_a_printer(printer, level); switch (level) { - case 2: + 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++; + result=update_a_printer_2(printer.info_2); break; } default: - success=1; + result=1; break; } - return (success); + return result; } /**************************************************************************** @@ -1706,7 +2419,7 @@ uint32 add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level) uint32 get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring sharename) { - uint32 success; + uint32 result; NT_PRINTER_INFO_LEVEL *printer = NULL; *pp_printer = NULL; @@ -1715,15 +2428,15 @@ uint32 get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring s switch (level) { - case 2: + case 2: { if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) { DEBUG(0,("get_a_printer: malloc fail.\n")); return 1; } ZERO_STRUCTP(printer); - success=get_a_printer_2(&printer->info_2, sharename); - if (success == 0) { + result=get_a_printer_2(&printer->info_2, sharename); + if (result == 0) { dump_a_printer(*printer, level); *pp_printer = printer; } else { @@ -1732,13 +2445,13 @@ uint32 get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring s break; } default: - success=1; + result=1; break; } - DEBUG(10,("get_a_printer: [%s] level %u returning %u\n", sharename, (unsigned int)level, (unsigned int)success)); + DEBUG(10,("get_a_printer: [%s] level %u returning %u\n", sharename, (unsigned int)level, (unsigned int)result)); - return (success); + return result; } /**************************************************************************** @@ -1747,7 +2460,7 @@ uint32 get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring s uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level) { - uint32 success; + uint32 result; NT_PRINTER_INFO_LEVEL *printer = *pp_printer; DEBUG(104,("freeing a printer at level [%d]\n", level)); @@ -1757,91 +2470,90 @@ uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level) switch (level) { - case 2: + case 2: { if (printer->info_2 != NULL) { free_nt_printer_info_level_2(&printer->info_2); - success=0; + result=0; } else { - success=4; + result=4; } break; } default: - success=1; + result=1; break; } safe_free(printer); *pp_printer = NULL; - return (success); + return result; } /**************************************************************************** ****************************************************************************/ uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level) { - uint32 success; + uint32 result; DEBUG(104,("adding a printer at level [%d]\n", level)); dump_a_printer_driver(driver, level); switch (level) { - case 3: + case 3: { - success=add_a_printer_driver_3(driver.info_3); + result=add_a_printer_driver_3(driver.info_3); break; } - case 6: + case 6: { - success=add_a_printer_driver_6(driver.info_6); + result=add_a_printer_driver_6(driver.info_6); break; } default: - success=1; + result=1; break; } - return (success); + return result; } /**************************************************************************** ****************************************************************************/ -uint32 get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level, +uint32 get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level, fstring printername, fstring architecture, uint32 version) { - uint32 success; + uint32 result; switch (level) { - case 3: + case 3: { - success=get_a_printer_driver_3(&(driver->info_3), - printername, - architecture, version); + result=get_a_printer_driver_3(&driver->info_3, printername, architecture, version); break; } default: - success=1; + result=1; break; } - if (success == 0) dump_a_printer_driver(*driver, level); - return (success); + if (result == 0) + dump_a_printer_driver(*driver, level); + return result; } /**************************************************************************** ****************************************************************************/ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level) { - uint32 success; + uint32 result; switch (level) { - case 3: + case 3: { NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3; if (driver.info_3 != NULL) @@ -1850,15 +2562,15 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level) safe_free(info3->dependentfiles); ZERO_STRUCTP(info3); safe_free(info3); - success=0; + result=0; } else { - success=4; + result=4; } break; } - case 6: + case 6: { NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6; if (driver.info_6 != NULL) @@ -1868,19 +2580,19 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level) safe_free(info6->previousnames); ZERO_STRUCTP(info6); safe_free(info6); - success=0; + result=0; } else { - success=4; + result=4; } break; } default: - success=1; + result=1; break; } - return (success); + return result; } /**************************************************************************** @@ -1916,7 +2628,7 @@ BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, ui /**************************************************************************** ****************************************************************************/ -BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level, +BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level, fstring value, uint8 **data, uint32 *type, uint32 *len) { /* right now that's enough ! */ @@ -1928,7 +2640,11 @@ BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level, while (param != NULL) { - if ( !strcmp(value, param->value) +#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; @@ -1978,6 +2694,7 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr) if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) { DOM_SID *owner_sid, *group_sid; + SEC_ACL *dacl, *sacl; SEC_DESC *psd = NULL; size_t size; @@ -1993,13 +2710,20 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr) secdesc_ctr->sec->grp_sid : old_secdesc_ctr->sec->grp_sid; + dacl = secdesc_ctr->sec->dacl ? + secdesc_ctr->sec->dacl : + old_secdesc_ctr->sec->dacl; + + sacl = secdesc_ctr->sec->sacl ? + secdesc_ctr->sec->sacl : + old_secdesc_ctr->sec->sacl; + /* 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, + sacl, + dacl, &size); new_secdesc_ctr = make_sec_desc_buf(size, psd); @@ -2016,10 +2740,10 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr) /* 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(new_secdesc_ctr->sec) + sizeof(SEC_DESC_BUF), 4, mem_ctx, MARSHALL); - if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr, + if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr, &ps, 1)) { status = ERROR_INVALID_FUNCTION; goto out; @@ -2055,7 +2779,7 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr) static SEC_DESC_BUF *construct_default_printer_sdb(void) { - SEC_ACE ace[2]; + SEC_ACE ace[3]; SEC_ACCESS sa; SEC_ACL *psa = NULL; SEC_DESC_BUF *sdb = NULL; @@ -2070,7 +2794,6 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void) init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, SEC_ACE_FLAG_CONTAINER_INHERIT); - /* Make the security descriptor owned by the Administrators group on the PDC of the domain. */ @@ -2090,8 +2813,13 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void) } } - init_sec_access(&sa, PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT); + init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL); init_sec_ace(&ace[1], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, + sa, SEC_ACE_FLAG_OBJECT_INHERIT | + SEC_ACE_FLAG_INHERIT_ONLY); + + init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL); + init_sec_ace(&ace[2], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, sa, SEC_ACE_FLAG_CONTAINER_INHERIT); /* The ACL revision number in rpc_secdesc.h differs from the one @@ -2101,10 +2829,8 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void) #define NT4_ACL_REVISION 0x2 - if ((psa = make_sec_acl(NT4_ACL_REVISION, 2, ace)) != NULL) { - psd = make_sec_desc(SEC_DESC_REVISION, - SEC_DESC_SELF_RELATIVE | - SEC_DESC_DACL_PRESENT, + if ((psa = make_sec_acl(NT4_ACL_REVISION, 3, ace)) != NULL) { + psd = make_sec_desc(SEC_DESC_REVISION, &owner_sid, NULL, NULL, psa, &sd_size); free_sec_acl(&psa); @@ -2117,7 +2843,7 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void) sdb = make_sec_desc_buf(sd_size, psd); - DEBUG(4,("construct_default_printer_sdb: size = %u.\n", + DEBUG(4,("construct_default_printer_sdb: size = %u.\n", (unsigned int)sd_size)); free_sec_desc(&psd); @@ -2133,11 +2859,16 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr) prs_struct ps; TALLOC_CTX *mem_ctx = NULL; fstring key; + char *temp; mem_ctx = talloc_init(); if (mem_ctx == NULL) return False; + if ((temp = strchr(printername + 2, '\\'))) { + printername = temp + 1; + } + /* Fetch security descriptor from tdb */ slprintf(key, sizeof(key), "SECDESC/%s", printername); @@ -2177,7 +2908,6 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr) sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN); psd = make_sec_desc((*secdesc_ctr)->sec->revision, - (*secdesc_ctr)->sec->type, &owner_sid, (*secdesc_ctr)->sec->grp_sid, (*secdesc_ctr)->sec->sacl, @@ -2199,6 +2929,24 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr) } } + if (DEBUGLEVEL >= 10) { + SEC_ACL *acl = (*secdesc_ctr)->sec->dacl; + int i; + + DEBUG(10, ("secdesc_ctr for %s has %d aces:\n", + printername, acl->num_aces)); + + for (i = 0; i < acl->num_aces; i++) { + fstring sid_str; + + sid_to_string(sid_str, &acl->ace[i].sid); + + DEBUG(10, ("%s %d %d 0x%08x\n", sid_str, + acl->ace[i].type, acl->ace[i].flags, + acl->ace[i].info.mask)); + } + } + prs_mem_free(&ps); talloc_destroy(mem_ctx); return True; @@ -2219,7 +2967,7 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr) Why ? Simply because it's easier and it makes sense ! Now explanation: You have 3 printers behind your samba server, - 2 of them are the same make and model (laser A and B). But laser B + 2 of them are the same make and model (laser A and B). But laser B has an 3000 sheet feeder and laser A doesn't such an option. Your third printer is an old dot-matrix model for the accounting :-). @@ -2234,12 +2982,26 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr) NTdriver_printer model X NTdriver_printer model Y -jfm: I should use this comment for the text file to explain +jfm: I should use this comment for the text file to explain same thing for the forms BTW. Je devrais mettre mes commentaires en francais, ca serait mieux :-) */ +/* Convert generic access rights to printer object specific access rights. + It turns out that NT4 security descriptors use generic access rights and + NT5 the object specific ones. */ + +void map_printer_permissions(SEC_DESC *sd) +{ + int i; + + for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { + se_map_generic(&sd->dacl->ace[i].info.mask, + &printer_generic_mapping); + } +} + /**************************************************************************** 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 @@ -2249,11 +3011,11 @@ jfm: I should use this comment for the text file to explain 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: + PRINTER_ACCESS_ADMINISTER (should really be JOB_ACCESS_ADMINISTER): print_job_delete, print_job_pause, print_job_resume, print_queue_purge @@ -2261,10 +3023,9 @@ jfm: I should use this comment for the text file to explain BOOL print_access_check(struct current_user *user, int snum, int access_type) { SEC_DESC_BUF *secdesc = NULL; - uint32 access_granted, status, required_access = 0; + uint32 access_granted, status; BOOL result; char *pname; - int i; extern struct current_user current_user; /* If user is NULL then use the current_user structure */ @@ -2293,91 +3054,14 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) /* Get printer security descriptor */ nt_printing_getsec(pname, &secdesc); + + map_printer_permissions(secdesc->sec); - /* 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; - default: - DEBUG(0, ("invalid value passed to print_access_check()\n")); - return False; - } - - /* 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 - values, i.e PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT. - This would cause the access check to simply fall out when we - check against any subset of these bits. To get things to work, - change every ACE mask of PRINTER_ACE_FULL_CONTROL to - PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT before - performing the access check. I'm sure there is a better way to - do this! */ - - if (secdesc && secdesc->sec && secdesc->sec->dacl && - secdesc->sec->dacl->ace) { - for(i = 0; i < secdesc->sec->dacl->num_aces; i++) { - if (secdesc->sec->dacl->ace[i].info.mask == - PRINTER_ACE_FULL_CONTROL) { - secdesc->sec->dacl->ace[i].info.mask = - PRINTER_ACE_MANAGE_DOCUMENTS | - PRINTER_ACE_PRINT; - } - } - } - - 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, + result = se_access_check(secdesc->sec, user, access_type, &access_granted, &status); /* Check access */ - done: DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE")); /* Free mallocated memory */ @@ -2416,6 +3100,9 @@ BOOL print_time_access_check(int snum) free_a_printer(&printer, 2); + if (!ok) + errno = EACCES; + return ok; }