diff options
-rw-r--r-- | source3/printing/nt_printing.c | 1041 | ||||
-rw-r--r-- | source3/printing/printing.c | 2 | ||||
-rw-r--r-- | source3/rpc_parse/parse_spoolss.c | 2 | ||||
-rw-r--r-- | source3/rpc_server/srv_spoolss_nt.c | 27 |
4 files changed, 668 insertions, 404 deletions
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index ba42309633..5482d1608a 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -26,20 +26,19 @@ extern int DEBUGLEVEL; extern pstring global_myname; extern DOM_SID global_sid_World; -/*static TDB_CONTEXT *tdb; *//* used for driver files */ - static TDB_CONTEXT *tdb_forms; /* used for forms files */ static TDB_CONTEXT *tdb_drivers; /* used for driver files */ static TDB_CONTEXT *tdb_printers; /* used for printers files */ #define FORMS_PREFIX "FORMS/" #define DRIVERS_PREFIX "DRIVERS/" +#define DRIVER_INIT_PREFIX "DRIVER_INIT/" #define PRINTERS_PREFIX "PRINTERS/" #define SECDESC_PREFIX "SECDESC/" - + #define NTDRIVERS_DATABASE_VERSION_1 1 #define NTDRIVERS_DATABASE_VERSION_2 2 - + #define NTDRIVERS_DATABASE_VERSION NTDRIVERS_DATABASE_VERSION_2 /* Map generic permissions to printer object specific permissions */ @@ -237,55 +236,46 @@ BOOL nt_printing_init(void) static pid_t local_pid; char *vstring = "INFO/version"; - if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid()) return True; - + if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid()) + return True; + tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, USE_TDB_MMAP_FLAG, O_RDWR|O_CREAT, 0600); if (!tdb_drivers) { - DEBUG(0,("Failed to open nt drivers database %s (%s)\n", + DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n", lock_path("ntdrivers.tdb"), strerror(errno) )); return False; } - + tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, USE_TDB_MMAP_FLAG, O_RDWR|O_CREAT, 0600); if (!tdb_printers) { - DEBUG(0,("Failed to open nt printers database %s (%s)\n", + DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n", lock_path("ntprinters.tdb"), strerror(errno) )); return False; } - + tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, USE_TDB_MMAP_FLAG, O_RDWR|O_CREAT, 0600); if (!tdb_forms) { - DEBUG(0,("Failed to open nt forms database %s (%s)\n", + DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n", lock_path("ntforms.tdb"), strerror(errno) )); return False; } - + local_pid = sys_getpid(); - + /* handle a Samba upgrade */ tdb_lock_bystring(tdb_drivers, vstring); if (tdb_fetch_int(tdb_drivers, vstring) != NTDRIVERS_DATABASE_VERSION) { - + if (tdb_fetch_int(tdb_drivers, vstring) == NTDRIVERS_DATABASE_VERSION_1) { if (!upgrade_to_version_2()) return False; } else tdb_traverse(tdb_drivers, (tdb_traverse_func)tdb_delete, NULL); - + tdb_store_int(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION); } tdb_unlock_bystring(tdb_drivers, vstring); -/* - tdb_create_index(tdb, "DRIVERS/"); - - tdb_lookup_index(tdb, "DRIVERS/", &list, &count); - - DEBUG(0,("nt_printing_init: got %d drivers\n", count)); - - for (i=0;i<count;i++) - DEBUG(0,("nt_printing_init: [%s]\n", list[i])); -*/ return True; } @@ -558,7 +548,7 @@ BOOL get_short_archi(char *short_archi, char *long_archi) if (archi_table[i].long_archi==NULL) { DEBUGADD(107,("Unknown architecture [%s] !\n", long_archi)); - return FALSE; + return False; } StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi)); @@ -571,372 +561,6 @@ BOOL get_short_archi(char *short_archi, char *long_archi) } /**************************************************************************** -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 = sys_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 = ERRnoaccess; - 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 = ERRnoaccess; - pop_sec_ctx(); - return -1; - } - - /* Open the driver file (Portable Executable format) and determine the - * deriver the cversion. */ - slprintf(driverpath, sizeof(driverpath)-1, "%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 = ERRnoaccess; - 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)); - - close_file(fsp, True); - close_cnum(conn, user->vuid); - pop_sec_ctx(); - return cversion; - - - error_exit: - if(fsp) - close_file(fsp, True); - - close_cnum(conn, user->vuid); - pop_sec_ctx(); - return -1; -} - -/**************************************************************************** -****************************************************************************/ -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_m(driver->driverpath,'\\')) != NULL) { - fstrcpy(new_name, p+1); - fstrcpy(driver->driverpath, new_name); - } - - if ((p = strrchr_m(driver->datafile,'\\')) != NULL) { - fstrcpy(new_name, p+1); - fstrcpy(driver->datafile, new_name); - } - - if ((p = strrchr_m(driver->configfile,'\\')) != NULL) { - fstrcpy(new_name, p+1); - fstrcpy(driver->configfile, new_name); - } - - if ((p = strrchr_m(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_m(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. - * - * 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->cversion = get_correct_cversion( architecture, - driver->driverpath, user, &err)) == -1) - return err; - - return ERRsuccess; -} - -/**************************************************************************** -****************************************************************************/ -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 - * or worse c:\windows\system\driver.dll ! - */ - /* using an intermediate string to not have overlaping memcpy()'s */ - if ((p = strrchr_m(driver->driverpath,'\\')) != NULL) { - fstrcpy(new_name, p+1); - fstrcpy(driver->driverpath, new_name); - } - - if ((p = strrchr_m(driver->datafile,'\\')) != NULL) { - fstrcpy(new_name, p+1); - fstrcpy(driver->datafile, new_name); - } - - if ((p = strrchr_m(driver->configfile,'\\')) != NULL) { - fstrcpy(new_name, p+1); - fstrcpy(driver->configfile, new_name); - } - - if ((p = strrchr_m(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_m(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. - * - * 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 ERRsuccess; -} - -/**************************************************************************** -****************************************************************************/ -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; - return clean_up_driver_struct_level_3(driver, user); - } - case 6: - { - NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver; - driver=driver_abstract.info_6; - return clean_up_driver_struct_level_6(driver, user); - } - 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; -} - -#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 @@ -1284,6 +908,327 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, } /**************************************************************************** +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; + 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/ME, 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 = sys_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 = ERRnoaccess; + 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 = ERRnoaccess; + pop_sec_ctx(); + return -1; + } + + /* Open the driver file (Portable Executable format) and determine the + * deriver the cversion. */ + slprintf(driverpath, sizeof(driverpath)-1, "%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 = ERRnoaccess; + goto error_exit; + } + else { + uint32 major; + uint32 minor; + int ret = get_file_version(fsp, driverpath, &major, &minor); + if (ret == -1) goto error_exit; + + if (!ret) { + DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath)); + goto error_exit; + } + + /* + * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION + * for more details. Version in this case is not just the version of the + * file, but the version in the sense of kernal mode (2) vs. user mode + * (3) drivers. Other bits of the version fields are the version info. + * JRR 010716 + */ + cversion = major & 0x0000ffff; + switch (cversion) { + case 2: /* WinNT drivers */ + case 3: /* Win2K drivers */ + break; + + default: + DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n", + driverpath, cversion)); + goto error_exit; + } + + DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n", + driverpath, major, minor)); + } + + DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n", + driverpath, cversion)); + + close_file(fsp, True); + close_cnum(conn, user->vuid); + pop_sec_ctx(); + return cversion; + + + error_exit: + if(fsp) + close_file(fsp, True); + + close_cnum(conn, user->vuid); + pop_sec_ctx(); + return -1; +} + +/**************************************************************************** +****************************************************************************/ +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. + * + * 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->cversion = get_correct_cversion( architecture, + driver->driverpath, user, &err)) == -1) + return err; + + return NT_STATUS_NOPROBLEMO; +} + +/**************************************************************************** +****************************************************************************/ +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 + * 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. + * + * 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_NOPROBLEMO; +} + +/**************************************************************************** +****************************************************************************/ +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; + return clean_up_driver_struct_level_3(driver, user); + } + case 6: + { + NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver; + driver=driver_abstract.info_6; + return clean_up_driver_struct_level_6(driver, user); + } + default: + return ERRinvalidparam; + } +} + +/**************************************************************************** + 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; +} + +#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 + +/**************************************************************************** ****************************************************************************/ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, struct current_user *user, uint32 *perr) { @@ -2381,7 +2326,7 @@ static void map_to_os2_driver(fstring drivername) for( i = 0; i < numlines; i++) { char *nt_name = lines[i]; - char *os2_name = strchr_m(nt_name,'='); + char *os2_name = strchr(nt_name,'='); if (!os2_name) continue; @@ -2391,7 +2336,7 @@ static void map_to_os2_driver(fstring drivername) while (isspace(*nt_name)) nt_name++; - if (!*nt_name || strchr_m("#;",*nt_name)) + if (!*nt_name || strchr("#;",*nt_name)) continue; { @@ -2736,6 +2681,304 @@ uint32 add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level) } /**************************************************************************** + Initialize printer devmode & data with previously saved driver init values. +****************************************************************************/ +static uint32 set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr) +{ + int len = 0; + pstring key; + TDB_DATA kbuf, dbuf; + NT_PRINTER_PARAM *current; + NT_PRINTER_INFO_LEVEL_2 info; + + ZERO_STRUCT(info); + + slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername); + + kbuf.dptr = key; + kbuf.dsize = strlen(key)+1; + + dbuf = tdb_fetch(tdb_drivers, kbuf); + if (!dbuf.dptr) + return False; + + /* + * Get the saved DEVMODE.. + */ + len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len); + + /* + * The saved DEVMODE contains the devicename from the printer used during + * the initialization save. Change it to reflect the new printer. + */ + ZERO_STRUCT(info.devmode->devicename); + fstrcpy(info.devmode->devicename, info_ptr->printername); + + /* + * Bind the saved DEVMODE to the new the printer. + */ + free_nt_devicemode(&info_ptr->devmode); + info_ptr->devmode = info.devmode; + + DEBUG(10,("set_driver_init_2: Set printer [%s] init DEVMODE for driver [%s]\n", + info_ptr->printername, info_ptr->drivername)); + + /* + * There should not be any printer data 'specifics' already set during the + * add printer operation, if there are delete them. + */ + while ( (current=info_ptr->specific) != NULL ) { + info_ptr->specific=current->next; + safe_free(current->data); + safe_free(current); + } + + /* + * Add the printer data 'specifics' to the new printer + */ + len += unpack_specifics(&info_ptr->specific,dbuf.dptr+len, dbuf.dsize-len); + + safe_free(dbuf.dptr); + + return True; +} + +/**************************************************************************** + Initialize printer devmode & data with previously saved driver init values. + When a printer is created using AddPrinter, the drivername bound to the + printer is used to lookup previously saved driver initialization info, which + is bound to the new printer. +****************************************************************************/ + +uint32 set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level) +{ + uint32 result; + + switch (level) + { + case 2: + { + result=set_driver_init_2(printer->info_2); + break; + } + default: + result=1; + break; + } + + return result; +} + +/**************************************************************************** + Pack up the DEVMODE and specifics for a printer into a 'driver init' entry + in the tdb. Note: this is different from the driver entry and the printer + entry. There should be a single driver init entry for each driver regardless + of whether it was installed from NT or 2K. Technically, they should be + different, but they work out to the same struct. +****************************************************************************/ +static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info) +{ + pstring key; + char *buf; + int buflen, len, ret; + TDB_DATA kbuf, dbuf; + + buf = NULL; + buflen = 0; + + again: + len = 0; + len += pack_devicemode(info->devmode, buf+len, buflen-len); + + len += pack_specifics(info->specific, buf+len, buflen-len); + + if (buflen != len) { + buf = (char *)Realloc(buf, len); + buflen = len; + goto again; + } + + slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername); + + kbuf.dptr = key; + kbuf.dsize = strlen(key)+1; + dbuf.dptr = buf; + dbuf.dsize = len; + + ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE); + + if (ret == -1) + DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n")); + + safe_free(buf); + + DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & specifics for driver [%s]\n", + info->sharename, info->drivername)); + + return ret; +} + +/**************************************************************************** + Update (i.e. save) the driver init info (DEVMODE and specifics) for a printer +****************************************************************************/ + +static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level) +{ + uint32 result; + + dump_a_printer(printer, level); + + switch (level) + { + case 2: + { + result=update_driver_init_2(printer.info_2); + break; + } + default: + result=1; + break; + } + + return result; +} + +/**************************************************************************** + Convert the printer data value, a REG_BINARY array, into an initialization + DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc... + got to keep the endians happy :). +****************************************************************************/ + +static BOOL convert_driver_init(NT_PRINTER_PARAM *param, TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode) +{ + BOOL result = False; + prs_struct ps; + DEVICEMODE devmode; + + ZERO_STRUCT(devmode); + + prs_init(&ps, 0, ctx, UNMARSHALL); + ps.data_p = param->data; + ps.buffer_size = param->data_len; + + if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode)) + result = convert_devicemode("", &devmode, &nt_devmode); + else + DEBUG(10,("convert_driver_init: error parsing DEVMODE\n")); + + return result; +} + +/**************************************************************************** + Set the DRIVER_INIT info in the tdb. Requires Win32 client code that: + + 1. Use the driver's config DLL to this UNC printername and: + a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE + b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE + 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data. + + The last step triggers saving the "driver initialization" information for + this printer into the tdb. Later, new printers that use this driver will + have this initialization information bound to them. This simulates the + driver initialization, as if it had run on the Samba server (as it would + have done on NT). + + The Win32 client side code requirement sucks! But until we can run arbitrary + Win32 printer driver code on any Unix that Samba runs on, we are stuck with it. + + It would have been easier to use SetPrinter because all the UNMARSHALLING of + the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think + about it and you will realize why. JRR 010720 +****************************************************************************/ + +static uint32 save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, NT_PRINTER_PARAM *param) +{ + uint32 status = ERRsuccess; + TALLOC_CTX *ctx = NULL; + NT_DEVICEMODE *nt_devmode = NULL; + NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode; + + /* + * Set devmode on printer info, so entire printer initialization can be + * saved to tdb. + */ + if ((ctx = talloc_init()) == NULL) + return ERRnomem; + + if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) { + status = ERRnomem; + goto done; + } + + ZERO_STRUCTP(nt_devmode); + + /* + * The DEVMODE is held in the 'data' component of the param in raw binary. + * Convert it to to a devmode structure + */ + if (!convert_driver_init(param, ctx, nt_devmode)) { + DEBUG(10,("save_driver_init_2: error converting DEVMODE\n")); + status = ERRinvalidparam; + goto done; + } + + /* + * Pack up and add (or update) the DEVMODE and any current printer data to + * a 'driver init' element in the tdb + * + */ + printer->info_2->devmode = nt_devmode; + if (update_driver_init(*printer, 2)!=0) { + DEBUG(10,("save_driver_init_2: error updating DEVMODE\n")); + status = ERRnomem; + goto done; + } + + /* + * If driver initialization info was successfully saved, set the current + * printer to match it. This allows initialization of the current printer + * as well as the driver. + */ + if (mod_a_printer(*printer, 2)!=0) { + DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n", + printer->info_2->printername)); + status = ERRinvalidparam; + } + + done: + talloc_destroy(ctx); + if (nt_devmode) + safe_free(nt_devmode->private); + safe_free(nt_devmode); + printer->info_2->devmode = tmp_devmode; + + return status; +} + +/**************************************************************************** + Update the driver init info (DEVMODE and specifics) for a printer +****************************************************************************/ + +uint32 save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, NT_PRINTER_PARAM *param) +{ + uint32 status = ERRsuccess; + + switch (level) + { + case 2: + { + status=save_driver_init_2(printer, param); + break; + } + default: + status=ERRunknownlevel; + break; + } + + return status; +} + +/**************************************************************************** Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory. ****************************************************************************/ @@ -3023,7 +3266,7 @@ uint32 delete_printer_driver (NT_PRINTER_DRIVER_INFO_LEVEL_3 *i) DEBUG(5,("delete_printer_driver: [%s] driver delete successful.\n", i->name)); - return ERRsuccess; + return NT_STATUS_NOPROBLEMO; } /**************************************************************************** ****************************************************************************/ @@ -3174,7 +3417,7 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr) goto out; } - slprintf(key, sizeof(key)-1, "%s%s", SECDESC_PREFIX, printername); + slprintf(key, sizeof(key)-1, "SECDESC/%s", printername); if (tdb_prs_store(tdb_printers, key, &ps)==0) { status = 0; @@ -3279,13 +3522,13 @@ BOOL nt_printing_getsec(TALLOC_CTX *ctx, char *printername, SEC_DESC_BUF **secde fstring key; char *temp; - if ((temp = strchr_m(printername + 2, '\\'))) { + if ((temp = strchr(printername + 2, '\\'))) { printername = temp + 1; } /* Fetch security descriptor from tdb */ - slprintf(key, sizeof(key)-1, "%s%s", SECDESC_PREFIX, printername); + slprintf(key, sizeof(key)-1, "SECDESC/%s", printername); if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 || !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) { @@ -3577,7 +3820,7 @@ uint32 printer_write_default_dev(int snum, const PRINTER_DEFAULT *printer_defaul DEBUG(5,("printer_write_default_dev: Access denied for printer %s\n", lp_servicename(snum) )); result = ERRnoaccess; - /*result = ERRsuccess;*/ + /*result = NT_STATUS_NO_PROBLEMO;*/ goto done; } diff --git a/source3/printing/printing.c b/source3/printing/printing.c index 17bea61f86..f1eaf3723c 100644 --- a/source3/printing/printing.c +++ b/source3/printing/printing.c @@ -55,7 +55,7 @@ BOOL print_backend_init(void) char *sversion = "INFO/version"; if (tdb && local_pid == sys_getpid()) return True; - tdb = tdb_open_log(lock_path("printing.tdb"), 0, 0, O_RDWR|O_CREAT, 0600); + tdb = tdb_open_log(lock_path("printing.tdb"), 0, USE_TDB_MMAP_FLAG, O_RDWR|O_CREAT, 0600); if (!tdb) { DEBUG(0,("print_backend_init: Failed to open printing backend database. Error = [%s]\n", tdb_errorstr(tdb))); diff --git a/source3/rpc_parse/parse_spoolss.c b/source3/rpc_parse/parse_spoolss.c index b303bf108e..b568995752 100644 --- a/source3/rpc_parse/parse_spoolss.c +++ b/source3/rpc_parse/parse_spoolss.c @@ -539,7 +539,7 @@ static BOOL spool_io_user_level(char *desc, SPOOL_USER_CTR *q_u, prs_struct *ps, * on reading allocate memory for the private member ********************************************************************/ -static BOOL spoolss_io_devmode(char *desc, prs_struct *ps, int depth, DEVICEMODE *devmode) +BOOL spoolss_io_devmode(char *desc, prs_struct *ps, int depth, DEVICEMODE *devmode) { prs_debug(ps, depth, desc, "spoolss_io_devmode"); depth++; diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index a0f14a9e64..f002ceabd2 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -34,6 +34,7 @@ extern pstring global_myname; #define MAX_OPEN_PRINTER_EXS 50 #endif +#define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_" #define PRINTER_HANDLE_IS_PRINTER 0 #define PRINTER_HANDLE_IS_PRINTSERVER 1 @@ -5736,6 +5737,13 @@ static uint32 spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_ return ERRinvalidparam; } + /* + * When a printer is created, the drivername bound to the printer is used + * to lookup previously saved driver initialization info, which is then + * bound to the new printer, simulating what happens in the Windows arch. + */ + set_driver_init(printer, 2); + /* write the ASCII on disk */ if (add_a_printer(*printer, 2) != 0) { free_a_printer(&printer,2); @@ -6132,10 +6140,23 @@ uint32 _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP } unlink_specific_param_if_exist(printer->info_2, param); - - add_a_specific_param(printer->info_2, ¶m); - status = mod_a_printer(*printer, 2); + /* + * When client side code sets a magic printer data key, detect it and save + * the current printer data and the magic key's data (its the DEVMODE) for + * future printer/driver initializations. + */ + if (param->type==3 && !strcmp( param->value, PHANTOM_DEVMODE_KEY)) { + /* + * Set devmode and printer initialization info + */ + status = save_driver_init(printer, 2, param); + } + else { + add_a_specific_param(printer->info_2, ¶m); + status = mod_a_printer(*printer, 2); + } + done: free_a_printer(&printer, 2); if (param) |