X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source%2Fprinting%2Fnt_printing.c;h=1a4a26ee6f2c226e8177d14f666dd5bbf16d1a46;hb=0b86c420be94d295f6917a220b5d699f65b46711;hp=a72f63009a4d05051c90407ea6e3bc27ff1d591f;hpb=1cad5250932b963c2eb9b775221b13db386d601b;p=ira%2Fwip.git diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index a72f63009a4..1a4a26ee6f2 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -3,11 +3,11 @@ * RPC Pipe client / server routines * Copyright (C) Andrew Tridgell 1992-2000, * Copyright (C) Jean François Micouleau 1998-2000. - * Copyright (C) Gerald Carter 2002-2003. + * Copyright (C) Gerald Carter 2002-2005. * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -16,13 +16,12 @@ * 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. + * along with this program; if not, see . */ #include "includes.h" -extern DOM_SID global_sid_World; +extern struct current_user current_user; static TDB_CONTEXT *tdb_forms; /* used for forms files */ static TDB_CONTEXT *tdb_drivers; /* used for driver files */ @@ -38,19 +37,19 @@ static TDB_CONTEXT *tdb_printers; /* used for printers files */ #define NTDRIVERS_DATABASE_VERSION_1 1 #define NTDRIVERS_DATABASE_VERSION_2 2 #define NTDRIVERS_DATABASE_VERSION_3 3 /* little endian version of v2 */ - -#define NTDRIVERS_DATABASE_VERSION NTDRIVERS_DATABASE_VERSION_3 +#define NTDRIVERS_DATABASE_VERSION_4 4 /* fix generic bits in security descriptors */ +#define NTDRIVERS_DATABASE_VERSION_5 5 /* normalize keys in ntprinters.tdb */ /* Map generic permissions to printer object specific permissions */ -GENERIC_MAPPING printer_generic_mapping = { +const struct generic_mapping printer_generic_mapping = { PRINTER_READ, PRINTER_WRITE, PRINTER_EXECUTE, PRINTER_ALL_ACCESS }; -STANDARD_MAPPING printer_std_mapping = { +const struct standard_mapping printer_std_mapping = { PRINTER_READ, PRINTER_WRITE, PRINTER_EXECUTE, @@ -59,14 +58,14 @@ STANDARD_MAPPING printer_std_mapping = { /* Map generic permissions to print server object specific permissions */ -GENERIC_MAPPING printserver_generic_mapping = { +const struct generic_mapping printserver_generic_mapping = { SERVER_READ, SERVER_WRITE, SERVER_EXECUTE, SERVER_ALL_ACCESS }; -STANDARD_MAPPING printserver_std_mapping = { +const struct generic_mapping printserver_std_mapping = { SERVER_READ, SERVER_WRITE, SERVER_EXECUTE, @@ -224,7 +223,50 @@ static const struct table_node archi_table[]= { {NULL, "", -1 } }; -static BOOL upgrade_to_version_3(void) + +/**************************************************************************** + generate a new TDB_DATA key for storing a printer +****************************************************************************/ + +static TDB_DATA make_printer_tdbkey(TALLOC_CTX *ctx, const char *sharename ) +{ + fstring share; + char *keystr = NULL; + TDB_DATA key; + + fstrcpy(share, sharename); + strlower_m(share); + + keystr = talloc_asprintf(ctx, "%s%s", PRINTERS_PREFIX, share); + key = string_term_tdb_data(keystr ? keystr : ""); + + return key; +} + +/**************************************************************************** + generate a new TDB_DATA key for storing a printer security descriptor +****************************************************************************/ + +static TDB_DATA make_printers_secdesc_tdbkey(TALLOC_CTX *ctx, + const char* sharename ) +{ + fstring share; + char *keystr = NULL; + TDB_DATA key; + + fstrcpy(share, sharename ); + strlower_m(share); + + keystr = talloc_asprintf(ctx, "%s%s", SECDESC_PREFIX, share); + key = string_term_tdb_data(keystr ? keystr : ""); + + return key; +} + +/**************************************************************************** +****************************************************************************/ + +static bool upgrade_to_version_3(void) { TDB_DATA kbuf, newkey, dbuf; @@ -235,7 +277,7 @@ static BOOL upgrade_to_version_3(void) dbuf = tdb_fetch(tdb_drivers, kbuf); - if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) { + if (strncmp((const char *)kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) { DEBUG(0,("upgrade_to_version_3:moving form\n")); if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) { SAFE_FREE(dbuf.dptr); @@ -249,7 +291,7 @@ static BOOL upgrade_to_version_3(void) } } - if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) { + if (strncmp((const char *)kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) { DEBUG(0,("upgrade_to_version_3:moving printer\n")); if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) { SAFE_FREE(dbuf.dptr); @@ -263,7 +305,7 @@ static BOOL upgrade_to_version_3(void) } } - if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) { + if (strncmp((const char *)kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) { DEBUG(0,("upgrade_to_version_3:moving secdesc\n")); if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) { SAFE_FREE(dbuf.dptr); @@ -283,75 +325,305 @@ static BOOL upgrade_to_version_3(void) return True; } +/******************************************************************* + Fix an issue with security descriptors. Printer sec_desc must + use more than the generic bits that were previously used + in <= 3.0.14a. They must also have a owner and group SID assigned. + Otherwise, any printers than have been migrated to a Windows + host using printmig.exe will not be accessible. +*******************************************************************/ + +static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key, + TDB_DATA data, void *state ) +{ + prs_struct ps; + SEC_DESC_BUF *sd_orig = NULL; + SEC_DESC_BUF *sd_new, *sd_store; + SEC_DESC *sec, *new_sec; + TALLOC_CTX *ctx = state; + int result, i; + uint32 sd_size; + size_t size_new_sec; + DOM_SID sid; + + if (!data.dptr || data.dsize == 0) { + return 0; + } + + if ( strncmp((const char *) key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) != 0 ) { + return 0; + } + + /* upgrade the security descriptor */ + + ZERO_STRUCT( ps ); + + prs_init( &ps, 0, ctx, UNMARSHALL ); + prs_give_memory( &ps, (char *)data.dptr, data.dsize, False ); + + if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_orig, &ps, 1 ) ) { + /* delete bad entries */ + DEBUG(0,("sec_desc_upg_fn: Failed to parse original sec_desc for %si. Deleting....\n", + (const char *)key.dptr )); + tdb_delete( tdb_printers, key ); + prs_mem_free( &ps ); + return 0; + } + + if (!sd_orig) { + prs_mem_free( &ps ); + return 0; + } + sec = sd_orig->sd; + + /* is this even valid? */ + + if ( !sec->dacl ) { + prs_mem_free( &ps ); + return 0; + } + + /* update access masks */ + + for ( i=0; idacl->num_aces; i++ ) { + switch ( sec->dacl->aces[i].access_mask ) { + case (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS): + sec->dacl->aces[i].access_mask = PRINTER_ACE_PRINT; + break; + + case GENERIC_ALL_ACCESS: + sec->dacl->aces[i].access_mask = PRINTER_ACE_FULL_CONTROL; + break; + + case READ_CONTROL_ACCESS: + sec->dacl->aces[i].access_mask = PRINTER_ACE_MANAGE_DOCUMENTS; + + default: /* no change */ + break; + } + } + + /* create a new SEC_DESC with the appropriate owner and group SIDs */ + + string_to_sid(&sid, "S-1-5-32-544" ); + new_sec = make_sec_desc( ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, + &sid, &sid, + NULL, NULL, &size_new_sec ); + if (!new_sec) { + prs_mem_free( &ps ); + return 0; + } + sd_new = make_sec_desc_buf( ctx, size_new_sec, new_sec ); + if (!sd_new) { + prs_mem_free( &ps ); + return 0; + } + + if ( !(sd_store = sec_desc_merge( ctx, sd_new, sd_orig )) ) { + DEBUG(0,("sec_desc_upg_fn: Failed to update sec_desc for %s\n", key.dptr )); + prs_mem_free( &ps ); + return 0; + } + + prs_mem_free( &ps ); + + /* store it back */ + + sd_size = ndr_size_security_descriptor(sd_store->sd, 0) + + sizeof(SEC_DESC_BUF); + prs_init(&ps, sd_size, ctx, MARSHALL); + + if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_store, &ps, 1 ) ) { + DEBUG(0,("sec_desc_upg_fn: Failed to parse new sec_desc for %s\n", key.dptr )); + prs_mem_free( &ps ); + return 0; + } + + data.dptr = (uint8 *)prs_data_p( &ps ); + data.dsize = sd_size; + + result = tdb_store( tdb_printers, key, data, TDB_REPLACE ); + + prs_mem_free( &ps ); + + /* 0 to continue and non-zero to stop traversal */ + + return (result == -1); +} + +/******************************************************************* +*******************************************************************/ + +static bool upgrade_to_version_4(void) +{ + TALLOC_CTX *ctx; + int result; + + DEBUG(0,("upgrade_to_version_4: upgrading printer security descriptors\n")); + + if ( !(ctx = talloc_init( "upgrade_to_version_4" )) ) + return False; + + result = tdb_traverse( tdb_printers, sec_desc_upg_fn, ctx ); + + talloc_destroy( ctx ); + + return ( result != -1 ); +} + +/******************************************************************* + Fix an issue with security descriptors. Printer sec_desc must + use more than the generic bits that were previously used + in <= 3.0.14a. They must also have a owner and group SID assigned. + Otherwise, any printers than have been migrated to a Windows + host using printmig.exe will not be accessible. +*******************************************************************/ + +static int normalize_printers_fn( TDB_CONTEXT *the_tdb, TDB_DATA key, + TDB_DATA data, void *state ) +{ + TALLOC_CTX *ctx = talloc_tos(); + TDB_DATA new_key; + + if (!data.dptr || data.dsize == 0) + return 0; + + /* upgrade printer records and security descriptors */ + + if ( strncmp((const char *) key.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX) ) == 0 ) { + new_key = make_printer_tdbkey(ctx, (const char *)key.dptr+strlen(PRINTERS_PREFIX) ); + } + else if ( strncmp((const char *) key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) == 0 ) { + new_key = make_printers_secdesc_tdbkey(ctx, (const char *)key.dptr+strlen(SECDESC_PREFIX) ); + } + else { + /* ignore this record */ + return 0; + } + + /* delete the original record and store under the normalized key */ + + if ( tdb_delete( the_tdb, key ) != 0 ) { + DEBUG(0,("normalize_printers_fn: tdb_delete for [%s] failed!\n", + key.dptr)); + return 1; + } + + if ( tdb_store( the_tdb, new_key, data, TDB_REPLACE) != 0 ) { + DEBUG(0,("normalize_printers_fn: failed to store new record for [%s]!\n", + key.dptr)); + return 1; + } + + return 0; +} + +/******************************************************************* +*******************************************************************/ + +static bool upgrade_to_version_5(void) +{ + TALLOC_CTX *ctx; + int result; + + DEBUG(0,("upgrade_to_version_5: normalizing printer keys\n")); + + if ( !(ctx = talloc_init( "upgrade_to_version_5" )) ) + return False; + + result = tdb_traverse( tdb_printers, normalize_printers_fn, NULL ); + + talloc_destroy( ctx ); + + return ( result != -1 ); +} + /**************************************************************************** Open the NT printing tdbs. Done once before fork(). ****************************************************************************/ -BOOL nt_printing_init(void) +bool nt_printing_init(struct messaging_context *msg_ctx) { - static pid_t local_pid; const char *vstring = "INFO/version"; WERROR win_rc; + int32 vers_id; - if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid()) + if ( tdb_drivers && tdb_printers && tdb_forms ) return True; if (tdb_drivers) tdb_close(tdb_drivers); - tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + tdb_drivers = tdb_open_log(state_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); if (!tdb_drivers) { DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n", - lock_path("ntdrivers.tdb"), strerror(errno) )); + state_path("ntdrivers.tdb"), strerror(errno) )); return False; } if (tdb_printers) tdb_close(tdb_printers); - tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + tdb_printers = tdb_open_log(state_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); if (!tdb_printers) { DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n", - lock_path("ntprinters.tdb"), strerror(errno) )); + state_path("ntprinters.tdb"), strerror(errno) )); return False; } if (tdb_forms) tdb_close(tdb_forms); - tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + tdb_forms = tdb_open_log(state_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); if (!tdb_forms) { DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n", - lock_path("ntforms.tdb"), strerror(errno) )); + state_path("ntforms.tdb"), strerror(errno) )); return False; } - local_pid = sys_getpid(); - /* handle a Samba upgrade */ - tdb_lock_bystring(tdb_drivers, vstring, 0); - { - int32 vers_id; + + vers_id = tdb_fetch_int32(tdb_drivers, vstring); + if (vers_id == -1) { + DEBUG(10, ("Fresh database\n")); + tdb_store_int32( tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5 ); + vers_id = NTDRIVERS_DATABASE_VERSION_5; + } - /* Cope with byte-reversed older versions of the db. */ - vers_id = tdb_fetch_int32(tdb_drivers, vstring); + if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) { + + if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) { + if (!upgrade_to_version_3()) + return False; + tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3); + vers_id = NTDRIVERS_DATABASE_VERSION_3; + } + if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) { /* Written on a bigendian machine with old fetch_int code. Save as le. */ /* The only upgrade between V2 and V3 is to save the version in little-endian. */ - tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION); - vers_id = NTDRIVERS_DATABASE_VERSION; + tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3); + vers_id = NTDRIVERS_DATABASE_VERSION_3; + } + + if (vers_id == NTDRIVERS_DATABASE_VERSION_3 ) { + if ( !upgrade_to_version_4() ) + return False; + tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_4); + vers_id = NTDRIVERS_DATABASE_VERSION_4; + } + + if (vers_id == NTDRIVERS_DATABASE_VERSION_4 ) { + if ( !upgrade_to_version_5() ) + return False; + tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5); + vers_id = NTDRIVERS_DATABASE_VERSION_5; } - if (vers_id != NTDRIVERS_DATABASE_VERSION) { - if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) { - if (!upgrade_to_version_3()) - return False; - } else - tdb_traverse(tdb_drivers, tdb_traverse_delete_fn, NULL); - - tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION); + if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) { + DEBUG(0,("nt_printing_init: Unknown printer database version [%d]\n", vers_id)); + return False; } } - tdb_unlock_bystring(tdb_drivers, vstring); - + update_c_setprinter(True); /* @@ -359,21 +631,16 @@ BOOL nt_printing_init(void) * drivers are installed */ - message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer ); + messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE, + do_drv_upgrade_printer); /* * register callback to handle updating printer data * when a driver is initialized */ - message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata ); - - /* - * register callback to handle invalidating the printer cache - * between smbd processes. - */ - - message_register( MSG_PRINTER_MOD, receive_printer_mod_msg); + messaging_register(msg_ctx, NULL, MSG_PRINTERDATA_INIT_RESET, + reset_all_printerdata); /* of course, none of the message callbacks matter if you don't tell messages.c that you interested in receiving PRINT_GENERAL @@ -393,13 +660,25 @@ BOOL nt_printing_init(void) Function to allow filename parsing "the old way". ********************************************************************/ -static BOOL driver_unix_convert(char *name,connection_struct *conn, - char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst) +static char *driver_unix_convert(connection_struct *conn, + const char *old_name, + SMB_STRUCT_STAT *pst) { + TALLOC_CTX *ctx = talloc_tos(); + char *name = talloc_strdup(ctx, old_name); + char *new_name = NULL; + + if (!name) { + return NULL; + } unix_format(name); - unix_clean_name(name); + name = unix_clean_name(ctx, name); + if (!name) { + return NULL; + } trim_string(name,"/","/"); - return unix_convert(name, conn, saved_last_component, bad_path, pst); + unix_convert(ctx,conn, name, false, &new_name, NULL, pst); + return new_name; } /******************************************************************* @@ -426,12 +705,12 @@ static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key, each add or delete printer RPC. Only Microsoft knows why... JRR020119 ********************************************************************/ -uint32 update_c_setprinter(BOOL initialize) +uint32 update_c_setprinter(bool initialize) { int32 c_setprinter; int32 printer_count = 0; - tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER, 0); + tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER); /* Traverse the tdb, counting the printers */ tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count); @@ -475,6 +754,9 @@ uint32 get_c_setprinter(void) int get_builtin_ntforms(nt_forms_struct **list) { *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms)); + if (!*list) { + return 0; + } return sizeof(default_forms) / sizeof(default_forms[0]); } @@ -482,11 +764,11 @@ int get_builtin_ntforms(nt_forms_struct **list) get a builtin form struct ****************************************************************************/ -BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form) +bool get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form) { int i,count; fstring form_name; - unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1); + unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)); DEBUGADD(6,("Looking for builtin form %s \n", form_name)); count = sizeof(default_forms) / sizeof(default_forms[0]); for (i=0;i sizeof(buf)) break; - slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name); - kbuf.dsize = strlen(key)+1; - kbuf.dptr = key; + key = talloc_asprintf(ctx, "%s%s", FORMS_PREFIX, (*list)[i].name); + if (!key) { + return 0; + } dbuf.dsize = len; - dbuf.dptr = buf; - if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break; + dbuf.dptr = (uint8 *)buf; + if (tdb_store_bystring(tdb_forms, key, dbuf, TDB_REPLACE) != 0) { + TALLOC_FREE(key); + TALLOC_FREE(buf); + break; + } + TALLOC_FREE(key); + TALLOC_FREE(buf); } return i; @@ -576,12 +879,11 @@ int write_ntforms(nt_forms_struct **list, int number) /**************************************************************************** add a form struct at the end of the list ****************************************************************************/ -BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count) +bool add_a_form(nt_forms_struct **list, const FORM *form, int *count) { int n=0; - BOOL update; + bool update; fstring form_name; - nt_forms_struct *tl; /* * NT tries to add forms even when @@ -591,7 +893,7 @@ 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); + unistr2_to_ascii(form_name, &form->name, sizeof(form_name)); for (n=0; n<*count; n++) { if ( strequal((*list)[n].name, form_name) ) { update=True; @@ -600,12 +902,11 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count) } if (update==False) { - if((tl=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) { + if((*list=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) { DEBUG(0,("add_a_form: failed to enlarge forms list!\n")); return False; } - *list = tl; - unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1); + unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)); (*count)++; } @@ -627,16 +928,15 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count) Delete a named form struct. ****************************************************************************/ -BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret) +bool delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret) { - pstring key; - TDB_DATA kbuf; + char *key = NULL; int n=0; fstring form_name; *ret = WERR_OK; - unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1); + unistr2_to_ascii(form_name, del_name, sizeof(form_name)); for (n=0; n<*count; n++) { if (!strncmp((*list)[n].name, form_name, strlen(form_name))) { @@ -651,15 +951,17 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR return False; } - slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name); - kbuf.dsize = strlen(key)+1; - kbuf.dptr = key; - if (tdb_delete(tdb_forms, kbuf) != 0) { + if (asprintf(&key, "%s%s", FORMS_PREFIX, (*list)[n].name) < 0) { + *ret = WERR_NOMEM; + return false; + } + if (tdb_delete_bystring(tdb_forms, key) != 0) { + SAFE_FREE(key); *ret = WERR_NOMEM; return False; } - - return True; + SAFE_FREE(key); + return true; } /**************************************************************************** @@ -670,7 +972,7 @@ void update_a_form(nt_forms_struct **list, const FORM *form, int count) { int n=0; fstring form_name; - unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1); + unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)); DEBUG(106, ("[%s]\n", form_name)); for (n=0; nfd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) { + if (SMB_VFS_LSEEK(fsp, 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) { + /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */ + if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) { DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n", fname, (unsigned long)byte_count)); /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ @@ -807,13 +1116,13 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) { unsigned int num_sections; unsigned 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. - */ + + /* Just skip over optional header to get to section table */ + if (SMB_VFS_LSEEK(fsp, + SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE), + SEEK_CUR) == (SMB_OFF_T)-1) { + DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n", + fname, errno)); goto error_exit; } @@ -824,7 +1133,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 goto error_exit; SAFE_FREE(buf); - if ((buf=SMB_MALLOC(section_table_bytes)) == NULL) { + if ((buf=(char *)SMB_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; @@ -848,14 +1157,14 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 goto error_exit; SAFE_FREE(buf); - if ((buf=SMB_MALLOC(section_bytes)) == NULL) { + if ((buf=(char *)SMB_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 (SMB_VFS_LSEEK(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) { + if (SMB_VFS_LSEEK(fsp, 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; @@ -879,7 +1188,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 if (IVAL(buf,pos) == VS_MAGIC_VALUE) { *major = IVAL(buf,pos+VS_MAJOR_OFFSET); *minor = IVAL(buf,pos+VS_MINOR_OFFSET); - + DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n", fname, *major, *minor, (*major>>16)&0xffff, *major&0xffff, @@ -908,7 +1217,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 /* Allocate a bit more space to speed up things */ SAFE_FREE(buf); - if ((buf=SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) { + if ((buf=(char *)SMB_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; @@ -951,7 +1260,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 * twice, as it is simpler to read the code. */ if (strcmp(&buf[i], VS_SIGNATURE) == 0) { /* Compute skip alignment to next long address */ - int skip = -(SMB_VFS_LSEEK(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) + + int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) + sizeof(VS_SIGNATURE)) & 3; if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue; @@ -998,8 +1307,8 @@ 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; + bool use_version = true; + char *filepath = NULL; uint32 new_major; uint32 new_minor; @@ -1009,57 +1318,73 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr 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); + NTSTATUS status; + + SET_STAT_INVALID(st); + SET_STAT_INVALID(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); + filepath = driver_unix_convert(conn,old_file,&stat_buf); + if (!filepath) { + goto error_exit; + } - driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); + status = open_file_ntcreate(conn, NULL, filepath, &stat_buf, + FILE_GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + NULL, &fsp); - fsp = open_file_shared(conn, filepath, &stat_buf, - SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); - if (!fsp) { + if (!NT_STATUS_IS_OK(status)) { /* 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; + return 1; } else { int ret = get_file_version(fsp, old_file, &old_major, &old_minor); - if (ret == -1) goto error_exit; + 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 (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit; + use_version = false; + if (SMB_VFS_FSTAT(fsp, &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)); } } - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); /* Get file version info (if available) for new file */ - pstrcpy(filepath, new_file); - driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); - - fsp = open_file_shared(conn, filepath, &stat_buf, - SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); - if (!fsp) { + filepath = driver_unix_convert(conn,new_file,&stat_buf); + if (!filepath) { + goto error_exit; + } + + status = open_file_ntcreate(conn, NULL, filepath, &stat_buf, + FILE_GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + NULL, &fsp); + + if (!NT_STATUS_IS_OK(status)) { /* 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)); @@ -1067,47 +1392,51 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr } else { int ret = get_file_version(fsp, new_file, &new_major, &new_minor); - if (ret == -1) goto error_exit; + 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 (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit; + use_version = false; + if (SMB_VFS_FSTAT(fsp, &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)); } } - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); if (use_version && (new_major != old_major || new_minor != old_minor)) { /* 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; + return 1; } else { DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file)); - return False; + return 0; } } 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; + return 1; } else { DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file)); - return False; + return 0; } } error_exit: if(fsp) - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); return -1; } @@ -1118,35 +1447,40 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ struct current_user *user, WERROR *perr) { int cversion; - int access_mode; - int action; NTSTATUS nt_status; - pstring driverpath; + char *driverpath = NULL; DATA_BLOB null_pw; fstring res_type; files_struct *fsp = NULL; - BOOL bad_path; SMB_STRUCT_STAT st; connection_struct *conn; + NTSTATUS status; - ZERO_STRUCT(st); + SET_STAT_INVALID(st); *perr = WERR_INVALID_PARAM; /* If architecture is Windows 95/98/ME, the version is always 0. */ - if (strcmp(architecture, "WIN40") == 0) { + if (strcmp(architecture, SPL_ARCH_WIN40) == 0) { DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n")); *perr = WERR_OK; return 0; } + /* If architecture is Windows x64, the version is always 3. */ + if (strcmp(architecture, SPL_ARCH_X64) == 0) { + DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n")); + *perr = WERR_OK; + return 3; + } + /* * Connect to the print$ share under the same account as the user connected * to the rpc pipe. Note we must still be root to do this. */ /* Null password is ok - we are already an authenticated user... */ - null_pw = data_blob(NULL, 0); + null_pw = data_blob_null; fstrcpy(res_type, "A:"); become_root(); conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status); @@ -1167,21 +1501,41 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ /* Open the driver file (Portable Executable format) and determine the * deriver the cversion. */ - slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in); + driverpath = talloc_asprintf(talloc_tos(), + "%s/%s", + architecture, + driverpath_in); + if (!driverpath) { + *perr = WERR_NOMEM; + goto error_exit; + } + + driverpath = driver_unix_convert(conn,driverpath,&st); + if (!driverpath) { + *perr = WERR_NOMEM; + goto error_exit; + } - driver_unix_convert(driverpath,conn,NULL,&bad_path,&st); + if (!vfs_file_exist(conn, driverpath, &st)) { + *perr = WERR_BADFILE; + goto error_exit; + } - fsp = open_file_shared(conn, driverpath, &st, - SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); - if (!fsp) { + status = open_file_ntcreate(conn, NULL, driverpath, &st, + FILE_GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + NULL, &fsp); + + if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n", driverpath, errno)); *perr = WERR_ACCESS_DENIED; goto error_exit; - } - else { + } else { uint32 major; uint32 minor; int ret = get_file_version(fsp, driverpath, &major, &minor); @@ -1215,10 +1569,10 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ driverpath, major, minor)); } - DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n", - driverpath, cversion)); + DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n", + driverpath, cversion)); - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); close_cnum(conn, user->vuid); unbecome_user(); *perr = WERR_OK; @@ -1228,7 +1582,7 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ error_exit: if(fsp) - close_file(fsp, True); + close_file(fsp, NORMAL_CLOSE); close_cnum(conn, user->vuid); unbecome_user(); @@ -1281,6 +1635,9 @@ static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri } architecture = get_short_archi(driver->environment); + if (!architecture) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } /* jfm:7/16/2000 the client always sends the cversion=0. * The server should check which version the driver is by reading @@ -1293,8 +1650,7 @@ static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri * NT 4: cversion=2 * NT2K: cversion=3 */ - if ((driver->cversion = get_correct_cversion( architecture, - driver->driverpath, user, &err)) == -1) + if ((driver->cversion = get_correct_cversion( architecture, driver->driverpath, user, &err)) == -1) return err; return WERR_OK; @@ -1345,6 +1701,9 @@ static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *dri } architecture = get_short_archi(driver->environment); + if (!architecture) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } /* jfm:7/16/2000 the client always sends the cversion=0. * The server should check which version the driver is by reading @@ -1357,8 +1716,9 @@ static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *dri * NT 4: cversion=2 * NT2K: cversion=3 */ + if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1) - return err; + return err; return WERR_OK; } @@ -1425,28 +1785,24 @@ static char* ffmt(unsigned char *c){ /**************************************************************************** ****************************************************************************/ -BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, +WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, struct current_user *user, WERROR *perr) { NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver; NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver; const char *architecture; - pstring new_dir; - pstring old_name; - pstring new_name; + char *new_dir = NULL; + char *old_name = NULL; + char *new_name = NULL; DATA_BLOB null_pw; connection_struct *conn; NTSTATUS nt_status; - pstring inbuf; - pstring outbuf; fstring res_type; - BOOL bad_path; SMB_STRUCT_STAT st; - int ver = 0; int i; + TALLOC_CTX *ctx = talloc_tos(); + int ver = 0; - memset(inbuf, '\0', sizeof(inbuf)); - memset(outbuf, '\0', sizeof(outbuf)); *perr = WERR_OK; if (level==3) @@ -1456,17 +1812,20 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, driver = &converted_driver; } else { DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level )); - return False; + return WERR_UNKNOWN_LEVEL; } architecture = get_short_archi(driver->environment); + if (!architecture) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } /* * Connect to the print$ share under the same account as the user connected to the rpc pipe. * Note we must be root to do this. */ - null_pw = data_blob(NULL, 0); + null_pw = data_blob_null; fstrcpy(res_type, "A:"); become_root(); conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status); @@ -1475,7 +1834,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, if (conn == NULL) { DEBUG(0,("move_driver_to_download_area: Unable to connect\n")); *perr = ntstatus_to_werror(nt_status); - return False; + return WERR_NO_SUCH_SHARE; } /* @@ -1484,17 +1843,31 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, if (!become_user(conn, conn->vuid)) { DEBUG(0,("move_driver_to_download_area: Can't become user!\n")); - return False; + return WERR_ACCESS_DENIED; } + /* WE ARE NOW RUNNING AS USER conn->vuid !!!!! */ + /* * make the directories version and version\driver_name * under the architecture directory. */ DEBUG(5,("Creating first directory\n")); - slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion); - driver_unix_convert(new_dir, conn, NULL, &bad_path, &st); - mkdir_internal(conn, new_dir); + new_dir = talloc_asprintf(ctx, + "%s/%d", + architecture, + driver->cversion); + if (!new_dir) { + *perr = WERR_NOMEM; + goto err_exit; + } + new_dir = driver_unix_convert(conn,new_dir,&st); + if (!new_dir) { + *perr = WERR_NOMEM; + goto err_exit; + } + + create_directory(conn, NULL, new_dir); /* 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: @@ -1516,43 +1889,70 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, DEBUG(5,("Moving files now !\n")); if (driver->driverpath && strlen(driver->driverpath)) { - slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath); - slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath); + new_name = talloc_asprintf(ctx, + "%s/%s", + architecture, + driver->driverpath); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + old_name = talloc_asprintf(ctx, + "%s/%s", + new_dir, + driver->driverpath); + if (!old_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - NTSTATUS status; - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - status = rename_internals(conn, new_name, old_name, 0, True); - if (!NT_STATUS_IS_OK(status)) { + new_name = driver_unix_convert(conn,new_name,&st); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); - *perr = ntstatus_to_werror(status); - unlink_internals(conn, 0, new_name); + *perr = WERR_ACCESS_DENIED; ver = -1; } - } else { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - unlink_internals(conn, 0, new_name); } } if (driver->datafile && strlen(driver->datafile)) { if (!strequal(driver->datafile, driver->driverpath)) { - slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile); - slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile); + new_name = talloc_asprintf(ctx, + "%s/%s", + architecture, + driver->datafile); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + old_name = talloc_asprintf(ctx, + "%s/%s", + new_dir, + driver->datafile); + if (!old_name) { + *perr = WERR_NOMEM; + goto err_exit; + } if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - NTSTATUS status; - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - status = rename_internals(conn, new_name, old_name, 0, True); - if (!NT_STATUS_IS_OK(status)) { + new_name = driver_unix_convert(conn,new_name,&st); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); - *perr = ntstatus_to_werror(status); - unlink_internals(conn, 0, new_name); + *perr = WERR_ACCESS_DENIED; ver = -1; } - } else { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - unlink_internals(conn, 0, new_name); } } } @@ -1560,22 +1960,35 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, if (driver->configfile && strlen(driver->configfile)) { if (!strequal(driver->configfile, driver->driverpath) && !strequal(driver->configfile, driver->datafile)) { - slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile); - slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile); + new_name = talloc_asprintf(ctx, + "%s/%s", + architecture, + driver->configfile); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + old_name = talloc_asprintf(ctx, + "%s/%s", + new_dir, + driver->configfile); + if (!old_name) { + *perr = WERR_NOMEM; + goto err_exit; + } if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - NTSTATUS status; - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - status = rename_internals(conn, new_name, old_name, 0, True); - if (!NT_STATUS_IS_OK(status)) { + new_name = driver_unix_convert(conn,new_name,&st); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); - *perr = ntstatus_to_werror(status); - unlink_internals(conn, 0, new_name); + *perr = WERR_ACCESS_DENIED; ver = -1; } - } else { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - unlink_internals(conn, 0, new_name); } } } @@ -1584,22 +1997,35 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, if (!strequal(driver->helpfile, driver->driverpath) && !strequal(driver->helpfile, driver->datafile) && !strequal(driver->helpfile, driver->configfile)) { - slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile); - slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile); + new_name = talloc_asprintf(ctx, + "%s/%s", + architecture, + driver->helpfile); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + old_name = talloc_asprintf(ctx, + "%s/%s", + new_dir, + driver->helpfile); + if (!old_name) { + *perr = WERR_NOMEM; + goto err_exit; + } if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - NTSTATUS status; - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - status = rename_internals(conn, new_name, old_name, 0, True); - if (!NT_STATUS_IS_OK(status)) { + new_name = driver_unix_convert(conn,new_name,&st); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); - *perr = ntstatus_to_werror(status); - unlink_internals(conn, 0, new_name); + *perr = WERR_ACCESS_DENIED; ver = -1; } - } else { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - unlink_internals(conn, 0, new_name); } } } @@ -1617,55 +2043,86 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, } } - slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]); - slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]); + new_name = talloc_asprintf(ctx, + "%s/%s", + architecture, + driver->dependentfiles[i]); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + old_name = talloc_asprintf(ctx, + "%s/%s", + new_dir, + driver->dependentfiles[i]); + if (!old_name) { + *perr = WERR_NOMEM; + goto err_exit; + } if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - NTSTATUS status; - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - status = rename_internals(conn, new_name, old_name, 0, True); - if (!NT_STATUS_IS_OK(status)) { + new_name = driver_unix_convert(conn,new_name,&st); + if (!new_name) { + *perr = WERR_NOMEM; + goto err_exit; + } + if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, + OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); - *perr = ntstatus_to_werror(status); - unlink_internals(conn, 0, new_name); + *perr = WERR_ACCESS_DENIED; ver = -1; } - } else { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - unlink_internals(conn, 0, new_name); } } NextDriver: ; } } + err_exit: + close_cnum(conn, user->vuid); unbecome_user(); - return ver == -1 ? False : True; + if (W_ERROR_EQUAL(*perr, WERR_OK)) { + return WERR_OK; + } + if (ver == -1) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } + return (*perr); } /**************************************************************************** ****************************************************************************/ + static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver) { + TALLOC_CTX *ctx = talloc_tos(); int len, buflen; const char *architecture; - pstring directory; + char *directory = NULL; fstring temp_name; - pstring key; - char *buf; + char *key = NULL; + uint8 *buf; int i, ret; - TDB_DATA kbuf, dbuf; + TDB_DATA dbuf; architecture = get_short_archi(driver->environment); + if (!architecture) { + return (uint32)-1; + } /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx * \\server is added in the rpc server layer. * It does make sense to NOT store the server's name in the printer TDB. */ - slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion); + directory = talloc_asprintf(ctx, "\\print$\\%s\\%d\\", + architecture, driver->cversion); + if (!directory) { + return (uint32)-1; + } /* .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: @@ -1700,7 +2157,11 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver) } } - slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name); + key = talloc_asprintf(ctx, "%s%s/%d/%s", DRIVERS_PREFIX, + architecture, driver->cversion, driver->name); + if (!key) { + return (uint32)-1; + } DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key )); @@ -1728,26 +2189,20 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver) } if (len != buflen) { - char *tb; - - tb = (char *)SMB_REALLOC(buf, len); - if (!tb) { + buf = (uint8 *)SMB_REALLOC(buf, len); + if (!buf) { DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!")); ret = -1; goto done; } - else buf = tb; buflen = len; goto again; } - - kbuf.dptr = key; - kbuf.dsize = strlen(key)+1; dbuf.dptr = buf; dbuf.dsize = len; - - ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE); + + ret = tdb_store_bystring(tdb_drivers, key, dbuf, TDB_REPLACE); done: if (ret) @@ -1801,7 +2256,11 @@ static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **in memset(info.dependentfiles, '\0', 2*sizeof(fstring)); fstrcpy(info.dependentfiles[0], ""); - *info_ptr = memdup(&info, sizeof(info)); + *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&info, sizeof(info)); + if (!*info_ptr) { + SAFE_FREE(info.dependentfiles); + return WERR_NOMEM; + } return WERR_OK; } @@ -1811,31 +2270,36 @@ static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **in static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version) { NT_PRINTER_DRIVER_INFO_LEVEL_3 driver; - TDB_DATA kbuf, dbuf; + TDB_DATA dbuf; const char *architecture; int len = 0; int i; - pstring key; + char *key = NULL; ZERO_STRUCT(driver); architecture = get_short_archi(arch); - + if ( !architecture ) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } + /* Windows 4.0 (i.e. win9x) should always use a version of 0 */ - + if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 ) version = 0; DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername)); - slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername); + if (asprintf(&key, "%s%s/%d/%s", DRIVERS_PREFIX, + architecture, version, drivername) < 0) { + return WERR_NOMEM; + } - kbuf.dptr = key; - kbuf.dsize = strlen(key)+1; - - dbuf = tdb_fetch(tdb_drivers, kbuf); - if (!dbuf.dptr) + dbuf = tdb_fetch_bystring(tdb_drivers, key); + if (!dbuf.dptr) { + SAFE_FREE(key); return WERR_UNKNOWN_PRINTER_DRIVER; + } len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff", &driver.cversion, @@ -1850,24 +2314,22 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, i=0; while (len < dbuf.dsize) { - fstring *tddfs; - - tddfs = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2); - if (tddfs == NULL) { + driver.dependentfiles = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2); + if ( !driver.dependentfiles ) { DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n")); break; } - else driver.dependentfiles = tddfs; len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f", &driver.dependentfiles[i]); i++; } - - if (driver.dependentfiles != NULL) - fstrcpy(driver.dependentfiles[i], ""); + + if ( driver.dependentfiles ) + fstrcpy( driver.dependentfiles[i], "" ); SAFE_FREE(dbuf.dptr); + SAFE_FREE(key); if (len != dbuf.dsize) { SAFE_FREE(driver.dependentfiles); @@ -1876,6 +2338,10 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, } *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver)); + if (!*info_ptr) { + SAFE_FREE(driver.dependentfiles); + return WERR_NOMEM; + } return WERR_OK; } @@ -1931,7 +2397,7 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 /**************************************************************************** ****************************************************************************/ -int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen) +int pack_devicemode(NT_DEVICEMODE *nt_devmode, uint8 *buf, int buflen) { int len = 0; @@ -1977,13 +2443,12 @@ int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen) nt_devmode->reserved2, nt_devmode->panningwidth, nt_devmode->panningheight, - nt_devmode->private); + nt_devmode->nt_dev_private); - - if (nt_devmode->private) { + if (nt_devmode->nt_dev_private) { len += tdb_pack(buf+len, buflen-len, "B", nt_devmode->driverextra, - nt_devmode->private); + nt_devmode->nt_dev_private); } DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname)); @@ -1994,47 +2459,61 @@ int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen) /**************************************************************************** Pack all values in all printer keys ***************************************************************************/ - -static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen) + +static int pack_values(NT_PRINTER_DATA *data, uint8 *buf, int buflen) { int len = 0; int i, j; REGISTRY_VALUE *val; REGVAL_CTR *val_ctr; - pstring path; + char *path = NULL; int num_values; if ( !data ) return 0; /* loop over all keys */ - - for ( i=0; inum_keys; i++ ) { - val_ctr = &data->keys[i].values; + + for ( i=0; inum_keys; i++ ) { + val_ctr = data->keys[i].values; num_values = regval_ctr_numvals( val_ctr ); - - /* loop over all values */ - + + /* pack the keyname followed by a empty value */ + + len += tdb_pack(buf+len, buflen-len, "pPdB", + &data->keys[i].name, + data->keys[i].name, + REG_NONE, + 0, + NULL); + + /* now loop over all values */ + for ( j=0; j\ */ - + val = regval_ctr_specific_value( val_ctr, j ); - pstrcpy( path, data->keys[i].name ); - pstrcat( path, "\\" ); - pstrcat( path, regval_name(val) ); - + if (asprintf(&path, "%s\\%s", + data->keys[i].name, + regval_name(val)) < 0) { + return -1; + } + len += tdb_pack(buf+len, buflen-len, "pPdB", val, path, regval_type(val), regval_size(val), regval_data_p(val) ); + + DEBUG(8,("specific: [%s], len: %d\n", regval_name(val), regval_size(val))); + SAFE_FREE(path); } - + } /* terminator */ - + len += tdb_pack(buf+len, buflen-len, "p", NULL); return len; @@ -2048,28 +2527,26 @@ static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen) uint32 del_a_printer(const char *sharename) { - pstring key; TDB_DATA kbuf; - pstring printdb_path; + char *printdb_path = NULL; + TALLOC_CTX *ctx = talloc_tos(); - slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename); - kbuf.dptr=key; - kbuf.dsize=strlen(key)+1; + kbuf = make_printer_tdbkey(ctx, sharename); tdb_delete(tdb_printers, kbuf); - slprintf(key, sizeof(key)-1, "%s%s", SECDESC_PREFIX, sharename); - kbuf.dptr=key; - kbuf.dsize=strlen(key)+1; + kbuf= make_printers_secdesc_tdbkey(ctx, sharename); tdb_delete(tdb_printers, kbuf); close_all_print_db(); if (geteuid() == 0) { - pstrcpy(printdb_path, lock_path("printing/")); - pstrcat(printdb_path, sharename); - pstrcat(printdb_path, ".tdb"); - + if (asprintf(&printdb_path, "%s%s.tdb", + lock_path("printing/"), + sharename) < 0) { + return (uint32)-1; + } unlink(printdb_path); + SAFE_FREE(printdb_path); } return 0; @@ -2079,9 +2556,9 @@ uint32 del_a_printer(const char *sharename) ****************************************************************************/ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info) { - pstring key; - char *buf; + uint8 *buf; int buflen, len; + int retlen; WERROR ret; TDB_DATA kbuf, dbuf; @@ -2116,7 +2593,7 @@ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info) buf = NULL; buflen = 0; - again: + again: len = 0; len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff", info->attributes, @@ -2143,28 +2620,26 @@ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info) info->parameters); len += pack_devicemode(info->devmode, buf+len, buflen-len); - - len += pack_values( &info->data, buf+len, buflen-len ); + retlen = pack_values( info->data, buf+len, buflen-len ); + if (retlen == -1) { + ret = WERR_NOMEM; + goto done; + } + len += retlen; if (buflen != len) { - char *tb; - - tb = (char *)SMB_REALLOC(buf, len); - if (!tb) { + buf = (uint8 *)SMB_REALLOC(buf, len); + if (!buf) { DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n")); ret = WERR_NOMEM; goto done; } - else buf = tb; buflen = len; goto again; } - - slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename); + kbuf = make_printer_tdbkey(talloc_tos(), info->sharename ); - kbuf.dptr = key; - kbuf.dsize = strlen(key)+1; dbuf.dptr = buf; dbuf.dsize = len; @@ -2242,7 +2717,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename) nt_devmode->panningwidth = 0; nt_devmode->panningheight = 0; - nt_devmode->private = NULL; + nt_devmode->nt_dev_private = NULL; return nt_devmode; } @@ -2262,9 +2737,9 @@ NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode) return NULL; } - new_nt_devicemode->private = NULL; - if (nt_devicemode->private != NULL) { - if ((new_nt_devicemode->private = memdup(nt_devicemode->private, nt_devicemode->driverextra)) == NULL) { + new_nt_devicemode->nt_dev_private = NULL; + if (nt_devicemode->nt_dev_private != NULL) { + if ((new_nt_devicemode->nt_dev_private = (uint8 *)memdup(nt_devicemode->nt_dev_private, nt_devicemode->driverextra)) == NULL) { SAFE_FREE(new_nt_devicemode); DEBUG(0,("dup_nt_devicemode: malloc fail.\n")); return NULL; @@ -2287,44 +2762,30 @@ void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr) DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n")); - SAFE_FREE(nt_devmode->private); + SAFE_FREE(nt_devmode->nt_dev_private); SAFE_FREE(*devmode_ptr); } /**************************************************************************** Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2. ****************************************************************************/ + static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr) { NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr; - NT_PRINTER_DATA *data; - int i; if ( !info ) return; - DEBUG(106,("free_nt_printer_info_level_2: deleting info\n")); - free_nt_devicemode(&info->devmode); - /* clean up all registry keys */ - - data = &info->data; - for ( i=0; inum_keys; i++ ) { - SAFE_FREE( data->keys[i].name ); - regval_ctr_destroy( &data->keys[i].values ); - } - SAFE_FREE( data->keys ); - - /* finally the top level structure */ - - SAFE_FREE( *info_ptr ); + TALLOC_FREE( *info_ptr ); } /**************************************************************************** ****************************************************************************/ -int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen) +int unpack_devicemode(NT_DEVICEMODE **nt_devmode, const uint8 *buf, int buflen) { int len = 0; int extra_len = 0; @@ -2373,25 +2834,29 @@ int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen) &devmode.reserved2, &devmode.panningwidth, &devmode.panningheight, - &devmode.private); + &devmode.nt_dev_private); - if (devmode.private) { + if (devmode.nt_dev_private) { /* the len in tdb_unpack is an int value and * devmode.driverextra is only a short */ - len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private); + len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.nt_dev_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; + devmode.nt_dev_private = NULL; } } *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode)); + if (!*nt_devmode) { + SAFE_FREE(devmode.nt_dev_private); + return -1; + } DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname)); - if (devmode.private) + if (devmode.nt_dev_private) DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra)); return len; @@ -2401,36 +2866,69 @@ int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen) Allocate and initialize a new slot. ***************************************************************************/ -static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name ) +int add_new_printer_key( NT_PRINTER_DATA *data, const char *name ) { NT_PRINTER_KEY *d; int key_index; - if ( !data || !name ) + if ( !name || !data ) return -1; - + /* allocate another slot in the NT_PRINTER_KEY array */ - d = SMB_REALLOC_ARRAY( data->keys, NT_PRINTER_KEY, data->num_keys+1); - if ( d ) - data->keys = d; + if ( !(d = TALLOC_REALLOC_ARRAY( data, data->keys, NT_PRINTER_KEY, data->num_keys+1)) ) { + DEBUG(0,("add_new_printer_key: Realloc() failed!\n")); + return -1; + } + + data->keys = d; key_index = data->num_keys; /* initialze new key */ - data->num_keys++; - data->keys[key_index].name = SMB_STRDUP( name ); - - ZERO_STRUCTP( &data->keys[key_index].values ); + data->keys[key_index].name = talloc_strdup( data, name ); - regval_ctr_init( &data->keys[key_index].values ); + if ( !(data->keys[key_index].values = TALLOC_ZERO_P( data, REGVAL_CTR )) ) + return -1; + data->num_keys++; + DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name )); return key_index; } +/**************************************************************************** + search for a registry key name in the existing printer data + ***************************************************************************/ + +int delete_printer_key( NT_PRINTER_DATA *data, const char *name ) +{ + int i; + + for ( i=0; inum_keys; i++ ) { + if ( strequal( data->keys[i].name, name ) ) { + + /* cleanup memory */ + + TALLOC_FREE( data->keys[i].name ); + TALLOC_FREE( data->keys[i].values ); + + /* if not the end of the array, move remaining elements down one slot */ + + data->num_keys--; + if ( data->num_keys && (i < data->num_keys) ) + memmove( &data->keys[i], &data->keys[i+1], sizeof(NT_PRINTER_KEY)*(data->num_keys-i) ); + + break; + } + } + + + return data->num_keys; +} + /**************************************************************************** search for a registry key name in the existing printer data ***************************************************************************/ @@ -2462,25 +2960,53 @@ int lookup_printerkey( NT_PRINTER_DATA *data, const char *name ) /**************************************************************************** ***************************************************************************/ -uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys ) +int get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys ) { int i, j; int key_len; int num_subkeys = 0; char *p; - fstring *ptr, *subkeys_ptr = NULL; + fstring *subkeys_ptr = NULL; fstring subkeyname; + *subkeys = NULL; + if ( !data ) return 0; + + if ( !key ) + return -1; + + /* special case of asking for the top level printer data registry key names */ + + if ( strlen(key) == 0 ) { + for ( i=0; inum_keys; i++ ) { + + /* found a match, so allocate space and copy the name */ + + if ( !(subkeys_ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) { + DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n", + num_subkeys+1)); + return -1; + } + + fstrcpy( subkeys_ptr[num_subkeys], data->keys[i].name ); + num_subkeys++; + } + + goto done; + } + /* asking for the subkeys of some key */ + /* subkey paths are stored in the key name using '\' as the delimiter */ + for ( i=0; inum_keys; i++ ) { if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) { - /* match sure it is a subkey and not the key itself */ + /* if we found the exact key, then break */ key_len = strlen( key ); if ( strlen(data->keys[i].name) == key_len ) - continue; + break; /* get subkey path */ @@ -2503,21 +3029,27 @@ uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **su /* found a match, so allocate space and copy the name */ - if ( !(ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) { + if ( !(subkeys_ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) { DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n", num_subkeys+1)); - SAFE_FREE( subkeys ); return 0; } - subkeys_ptr = ptr; fstrcpy( subkeys_ptr[num_subkeys], subkeyname ); num_subkeys++; } } - /* tag of the end */ + /* return error if the key was not found */ + + if ( i == data->num_keys ) { + SAFE_FREE(subkeys_ptr); + return -1; + } + +done: + /* tag off the end */ if (num_subkeys) fstrcpy(subkeys_ptr[num_subkeys], "" ); @@ -2550,7 +3082,7 @@ static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name, } static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name, - BOOL b) + bool b) { uint8 bin_bool = (b ? 1 : 0); regval_ctr_delvalue(ctr, val_name); @@ -2588,25 +3120,36 @@ static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name, * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing. * * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified - * @return BOOL indicating success or failure + * @return bool indicating success or failure ***************************************************************************/ -static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2) +static bool map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2) { REGVAL_CTR *ctr = NULL; fstring longname; + const char *dnssuffix; char *allocated_string = NULL; const char *ascii_str; int i; - if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0) - i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY); - ctr = &info2->data.keys[i].values; + if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0) + i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY); + ctr = info2->data->keys[i].values; map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename); map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname()); - get_mydnsfullname(longname); + /* we make the assumption that the netbios name is the same + as the DNS name sinc ethe former will be what we used to + join the domain */ + + dnssuffix = get_mydnsdomname(talloc_tos()); + if (dnssuffix && *dnssuffix) { + fstr_sprintf( longname, "%s.%s", global_myname(), dnssuffix ); + } else { + fstrcpy( longname, global_myname() ); + } + map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname); asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename); @@ -2645,33 +3188,48 @@ static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2) return True; } +/***************************************************************** + ****************************************************************/ + static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, - struct uuid guid) + struct GUID guid) { int i; REGVAL_CTR *ctr=NULL; + UNISTR2 unistr_guid; /* find the DsSpooler key */ - if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0) - i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY); - ctr = &info2->data.keys[i].values; + if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0) + i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY); + ctr = info2->data->keys[i].values; regval_ctr_delvalue(ctr, "objectGUID"); - regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY, - (char *) &guid, sizeof(struct uuid)); + + /* We used to store this as a REG_BINARY but that causes + Vista to whine */ + + ZERO_STRUCT( unistr_guid ); + + init_unistr2( &unistr_guid, smb_uuid_string(talloc_tos(), guid), + UNI_STR_TERMINATE ); + + regval_ctr_addvalue(ctr, "objectGUID", REG_SZ, + (char *)unistr_guid.buffer, + unistr_guid.uni_max_len*2); + } static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, NT_PRINTER_INFO_LEVEL *printer) { ADS_STATUS ads_rc; - void *res; - char *prt_dn = NULL, *srv_dn, *srv_cn_0; + LDAPMessage *res; + char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped; char *srv_dn_utf8, **srv_cn_utf8; TALLOC_CTX *ctx; ADS_MODLIST mods; const char *attrs[] = {"objectGUID", NULL}; - struct uuid guid; + struct GUID guid; WERROR win_rc = WERR_OK; DEBUG(5, ("publishing printer %s\n", printer->info_2->printername)); @@ -2682,7 +3240,7 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, /* We use ldap_get_dn here as we need the answer * in utf8 to call ldap_explode_dn(). JRA. */ - srv_dn_utf8 = ldap_get_dn(ads->ld, res); + srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res); if (!srv_dn_utf8) { ads_destroy(&ads); return WERR_SERVER_UNAVAILABLE; @@ -2712,18 +3270,46 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, ldap_memfree(srv_dn_utf8); ldap_memfree(srv_cn_utf8); - asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_0, - printer->info_2->sharename, srv_dn); + srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0); + if (!srv_cn_escaped) { + SAFE_FREE(srv_cn_0); + ldap_memfree(srv_dn_utf8); + ads_destroy(&ads); + return WERR_SERVER_UNAVAILABLE; + } + sharename_escaped = escape_rdn_val_string_alloc(printer->info_2->sharename); + if (!sharename_escaped) { + SAFE_FREE(srv_cn_escaped); + SAFE_FREE(srv_cn_0); + ldap_memfree(srv_dn_utf8); + ads_destroy(&ads); + return WERR_SERVER_UNAVAILABLE; + } + + + asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn); SAFE_FREE(srv_dn); SAFE_FREE(srv_cn_0); + SAFE_FREE(srv_cn_escaped); + SAFE_FREE(sharename_escaped); /* build the ads mods */ ctx = talloc_init("nt_printer_publish_ads"); + if (ctx == NULL) { + SAFE_FREE(prt_dn); + return WERR_NOMEM; + } + mods = ads_init_mods(ctx); - get_local_printer_publishing_data(ctx, &mods, - &printer->info_2->data); + if (mods == NULL) { + SAFE_FREE(prt_dn); + talloc_destroy(ctx); + return WERR_NOMEM; + } + + get_local_printer_publishing_data(ctx, &mods, printer->info_2->data); ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer->info_2->sharename); @@ -2754,7 +3340,7 @@ static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads, NT_PRINTER_INFO_LEVEL *printer) { ADS_STATUS ads_rc; - void *res; + LDAPMessage *res; char *prt_dn = NULL; DEBUG(5, ("unpublishing printer %s\n", printer->info_2->printername)); @@ -2765,6 +3351,10 @@ static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads, if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) { prt_dn = ads_get_dn(ads, res); + if (!prt_dn) { + ads_msgfree(ads, res); + return WERR_NOMEM; + } ads_rc = ads_del_dn(ads, prt_dn); ads_memfree(ads, prt_dn); } @@ -2816,7 +3406,7 @@ WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action) goto done; } - ads = ads_init(NULL, NULL, NULL); + ads = ads_init(lp_realm(), lp_workgroup(), NULL); if (!ads) { DEBUG(3, ("ads_init() failed\n")); win_rc = WERR_SERVER_UNAVAILABLE; @@ -2859,7 +3449,7 @@ WERROR check_published_printers(void) int n_services = lp_numservices(); NT_PRINTER_INFO_LEVEL *printer = NULL; - ads = ads_init(NULL, NULL, NULL); + ads = ads_init(lp_realm(), lp_workgroup(), NULL); if (!ads) { DEBUG(3, ("ads_init() failed\n")); return WERR_SERVER_UNAVAILABLE; @@ -2874,6 +3464,7 @@ WERROR check_published_printers(void) if (!ADS_ERR_OK(ads_rc)) { DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc))); ads_destroy(&ads); + ads_kdestroy("MEMORY:prtpub_cache"); return WERR_ACCESS_DENIED; } @@ -2890,36 +3481,62 @@ WERROR check_published_printers(void) } ads_destroy(&ads); + ads_kdestroy("MEMORY:prtpub_cache"); return WERR_OK; } -BOOL is_printer_published(Printer_entry *print_hnd, int snum, - struct uuid *guid) +bool is_printer_published(Printer_entry *print_hnd, int snum, + struct GUID *guid) { NT_PRINTER_INFO_LEVEL *printer = NULL; REGVAL_CTR *ctr; REGISTRY_VALUE *guid_val; WERROR win_rc; int i; + bool ret = False; win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum)); if (!W_ERROR_IS_OK(win_rc) || !(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) || - ((i = lookup_printerkey(&printer->info_2->data, - SPOOL_DSSPOOLER_KEY)) < 0) || - !(ctr = &printer->info_2->data.keys[i].values) || - !(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) { + ((i = lookup_printerkey(printer->info_2->data, SPOOL_DSSPOOLER_KEY)) < 0) || + !(ctr = printer->info_2->data->keys[i].values) || + !(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) + { free_a_printer(&printer, 2); return False; } - /* fetching printer guids really ought to be a separate function.. */ - if (guid && regval_size(guid_val) == sizeof(struct uuid)) - memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid)); + /* fetching printer guids really ought to be a separate function. */ + + if ( guid ) { + fstring guid_str; + + /* We used to store the guid as REG_BINARY, then swapped + to REG_SZ for Vista compatibility so check for both */ + + switch ( regval_type(guid_val) ){ + case REG_SZ: + rpcstr_pull( guid_str, regval_data_p(guid_val), + sizeof(guid_str)-1, -1, STR_TERMINATE ); + ret = smb_string_to_uuid( guid_str, guid ); + break; + case REG_BINARY: + if ( regval_size(guid_val) != sizeof(struct GUID) ) { + ret = False; + break; + } + memcpy(guid, regval_data_p(guid_val), sizeof(struct GUID)); + break; + default: + DEBUG(0,("is_printer_published: GUID value stored as " + "invaluid type (%d)\n", regval_type(guid_val) )); + break; + } + } free_a_printer(&printer, 2); - return True; + return ret; } #else WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action) @@ -2932,8 +3549,8 @@ WERROR check_published_printers(void) return WERR_OK; } -BOOL is_printer_published(Printer_entry *print_hnd, int snum, - struct uuid *guid) +bool is_printer_published(Printer_entry *print_hnd, int snum, + struct GUID *guid) { return False; } @@ -2949,7 +3566,7 @@ WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key ) int removed_keys = 0; int empty_slot; - data = &p2->data; + data = p2->data; empty_slot = data->num_keys; if ( !key ) @@ -2958,20 +3575,14 @@ WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key ) /* remove all keys */ if ( !strlen(key) ) { - for ( i=0; inum_keys; i++ ) { - DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n", - data->keys[i].name)); - - SAFE_FREE( data->keys[i].name ); - regval_ctr_destroy( &data->keys[i].values ); - } + TALLOC_FREE( data ); + + p2->data = NULL; + DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n", p2->printername )); - SAFE_FREE( data->keys ); - ZERO_STRUCTP( data ); - return WERR_OK; } @@ -2982,9 +3593,9 @@ WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key ) DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n", data->keys[i].name)); - SAFE_FREE( data->keys[i].name ); - regval_ctr_destroy( &data->keys[i].values ); - + TALLOC_FREE( data->keys[i].name ); + TALLOC_FREE( data->keys[i].values ); + /* mark the slot as empty */ ZERO_STRUCTP( &data->keys[i] ); @@ -3047,16 +3658,16 @@ WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const /* find the printer key first */ - key_index = lookup_printerkey( &p2->data, key ); + key_index = lookup_printerkey( p2->data, key ); if ( key_index == -1 ) return WERR_OK; /* make sure the value exists so we can return the correct error code */ - if ( !regval_ctr_getvalue( &p2->data.keys[key_index].values, value ) ) + if ( !regval_ctr_getvalue( p2->data->keys[key_index].values, value ) ) return WERR_BADFILE; - regval_ctr_delvalue( &p2->data.keys[key_index].values, value ); + regval_ctr_delvalue( p2->data->keys[key_index].values, value ); DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n", key, value )); @@ -3080,116 +3691,157 @@ WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const cha /* find the printer key first */ - key_index = lookup_printerkey( &p2->data, key ); + key_index = lookup_printerkey( p2->data, key ); if ( key_index == -1 ) - key_index = add_new_printer_key( &p2->data, key ); + key_index = add_new_printer_key( p2->data, key ); if ( key_index == -1 ) return WERR_NOMEM; - regval_ctr_addvalue( &p2->data.keys[key_index].values, value, + regval_ctr_addvalue( p2->data->keys[key_index].values, value, type, (const char *)data, real_len ); DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n", key, value, type, real_len )); - + return result; } /**************************************************************************** ***************************************************************************/ - + REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value ) { int key_index; - if ( (key_index = lookup_printerkey( &p2->data, key )) == -1 ) + if ( (key_index = lookup_printerkey( p2->data, key )) == -1 ) return NULL; DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n", key, value )); - return regval_ctr_getvalue( &p2->data.keys[key_index].values, value ); + return regval_ctr_getvalue( p2->data->keys[key_index].values, value ); } /**************************************************************************** Unpack a list of registry values frem the TDB ***************************************************************************/ - -static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen) + +static int unpack_values(NT_PRINTER_DATA *printer_data, const uint8 *buf, int buflen) { int len = 0; uint32 type; - pstring string, valuename, keyname; + fstring string; + const char *valuename = NULL; + const char *keyname = NULL; char *str; int size; uint8 *data_p; REGISTRY_VALUE *regval_p; int key_index; - + /* add the "PrinterDriverData" key first for performance reasons */ - + add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY ); /* loop and unpack the rest of the registry values */ - + while ( True ) { - + /* check to see if there are any more registry values */ - + regval_p = NULL; - len += tdb_unpack(buf+len, buflen-len, "p", ®val_p); - if ( !regval_p ) + len += tdb_unpack(buf+len, buflen-len, "p", ®val_p); + if ( !regval_p ) break; /* unpack the next regval */ - + len += tdb_unpack(buf+len, buflen-len, "fdB", string, &type, &size, &data_p); - + + /* lookup for subkey names which have a type of REG_NONE */ + /* there's no data with this entry */ + + if ( type == REG_NONE ) { + if ( (key_index=lookup_printerkey( printer_data, string)) == -1 ) + add_new_printer_key( printer_data, string ); + continue; + } + /* - * break of the keyname from the value name. + * break of the keyname from the value name. * Valuenames can have embedded '\'s so be careful. - * only support one level of keys. See the + * only support one level of keys. See the * "Konica Fiery S300 50C-K v1.1. enu" 2k driver. * -- jerry - */ - + */ + str = strchr_m( string, '\\'); - + /* Put in "PrinterDriverData" is no key specified */ - + if ( !str ) { - pstrcpy( keyname, SPOOL_PRINTERDATA_KEY ); - pstrcpy( valuename, string ); + keyname = SPOOL_PRINTERDATA_KEY; + valuename = string; } else { *str = '\0'; - pstrcpy( keyname, string ); - pstrcpy( valuename, str+1 ); + keyname = string; + valuename = str+1; } - + /* see if we need a new key */ - + if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 ) key_index = add_new_printer_key( printer_data, keyname ); - + if ( key_index == -1 ) { DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n", keyname)); break; } - - /* add the new value */ - - regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, (const char *)data_p, size ); + + DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size)); + + /* Vista doesn't like unknown REG_BINARY values in DsSpooler. + Thanks to Martin Zielinski for the hint. */ + + if ( type == REG_BINARY && + strequal( keyname, SPOOL_DSSPOOLER_KEY ) && + strequal( valuename, "objectGUID" ) ) + { + struct GUID guid; + UNISTR2 unistr_guid; + + ZERO_STRUCT( unistr_guid ); + + /* convert the GUID to a UNICODE string */ + + memcpy( &guid, data_p, sizeof(struct GUID) ); + + init_unistr2( &unistr_guid, + smb_uuid_string(talloc_tos(), guid), + UNI_STR_TERMINATE ); + + regval_ctr_addvalue( printer_data->keys[key_index].values, + valuename, REG_SZ, + (const char *)unistr_guid.buffer, + unistr_guid.uni_str_len*2 ); + + } else { + /* add the value */ + + regval_ctr_addvalue( printer_data->keys[key_index].values, + valuename, type, (const char *)data_p, + size ); + } SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */ - DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size)); } return len; @@ -3198,10 +3850,46 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen) /**************************************************************************** ***************************************************************************/ +static char *last_from; +static char *last_to; + +static const char *get_last_from(void) +{ + if (!last_from) { + return ""; + } + return last_from; +} + +static const char *get_last_to(void) +{ + if (!last_to) { + return ""; + } + return last_to; +} + +static bool set_last_from_to(const char *from, const char *to) +{ + char *orig_from = last_from; + char *orig_to = last_to; + + last_from = SMB_STRDUP(from); + last_to = SMB_STRDUP(to); + + SAFE_FREE(orig_from); + SAFE_FREE(orig_to); + + if (!last_from || !last_to) { + SAFE_FREE(last_from); + SAFE_FREE(last_to); + return false; + } + return true; +} + static void map_to_os2_driver(fstring drivername) { - static BOOL initialised=False; - static fstring last_from,last_to; char *mapfile = lp_os2_driver_map(); char **lines = NULL; int numlines = 0; @@ -3213,20 +3901,17 @@ static void map_to_os2_driver(fstring drivername) if (!*mapfile) return; - if (!initialised) { - *last_from = *last_to = 0; - initialised = True; - } - - if (strequal(drivername,last_from)) { - DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to)); - fstrcpy(drivername,last_to); + if (strequal(drivername,get_last_from())) { + DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n", + drivername,get_last_to())); + fstrcpy(drivername,get_last_to()); return; } - lines = file_lines_load(mapfile, &numlines); - if (numlines == 0) { + lines = file_lines_load(mapfile, &numlines,0); + if (numlines == 0 || lines == NULL) { DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile)); + SAFE_FREE(lines); return; } @@ -3268,8 +3953,7 @@ static void map_to_os2_driver(fstring drivername) if (strequal(nt_name,drivername)) { DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name)); - fstrcpy(last_from,drivername); - fstrcpy(last_to,os2_name); + set_last_from_to(drivername,os2_name); fstrcpy(drivername,os2_name); file_lines_free(lines); return; @@ -3282,44 +3966,48 @@ static void map_to_os2_driver(fstring drivername) /**************************************************************************** Get a default printer info 2 struct. ****************************************************************************/ -static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *servername, const char* sharename) +static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info, const char *servername, const char* sharename) { - int snum; - NT_PRINTER_INFO_LEVEL_2 info; - - ZERO_STRUCT(info); - - snum = lp_servicenumber(sharename); + int snum = lp_servicenumber(sharename); - slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", servername); - slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s", + slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername); + slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s", servername, sharename); - fstrcpy(info.sharename, sharename); - fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME); + fstrcpy(info->sharename, sharename); + fstrcpy(info->portname, SAMBA_PRINTER_PORT_NAME); /* by setting the driver name to an empty string, a local NT admin can now run the **local** APW to install a local printer driver for a Samba shared printer in 2.2. Without this, drivers **must** be installed on the Samba server for NT clients --jerry */ #if 0 /* JERRY --do not uncomment-- */ - if (!*info.drivername) - fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER"); + if (!*info->drivername) + fstrcpy(info->drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER"); #endif - DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername)); + 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"); + strlcpy(info->comment, "", sizeof(info->comment)); + fstrcpy(info->printprocessor, "winprint"); + fstrcpy(info->datatype, "RAW"); - info.attributes = PRINTER_ATTRIBUTE_SAMBA; +#ifdef HAVE_CUPS + if ( (enum printing_types)lp_printing(snum) == PRINT_CUPS ) { + /* Pull the location and comment strings from cups if we don't + already have one */ + if ( !strlen(info->location) || !strlen(info->comment) ) + cups_pull_comment_location( info ); + } +#endif - 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); + info->attributes = PRINTER_ATTRIBUTE_SAMBA; + + 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); /* * I changed this as I think it is better to have a generic @@ -3332,95 +4020,98 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const */ if (lp_default_devmode(snum)) { - if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL) + if ((info->devmode = construct_nt_devicemode(info->printername)) == NULL) { goto fail; + } + } else { + info->devmode = NULL; } - else { - info.devmode = NULL; - } - - /* This will get the current RPC talloc context, but we should be - passing this as a parameter... fixme... JRA ! */ - - if (!nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf)) - goto fail; - *info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info)); - if (! *info_ptr) { - DEBUG(0,("get_a_printer_2_default: malloc fail.\n")); + if (!nt_printing_getsec(info, sharename, &info->secdesc_buf)) { goto fail; } return WERR_OK; - fail: - if (info.devmode) - free_nt_devicemode(&info.devmode); +fail: + if (info->devmode) + free_nt_devicemode(&info->devmode); + return WERR_ACCESS_DENIED; } /**************************************************************************** ****************************************************************************/ -static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *servername, const char *sharename) +static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info, const char *servername, const char *sharename) { - pstring key; - NT_PRINTER_INFO_LEVEL_2 info; int len = 0; int snum = lp_servicenumber(sharename); TDB_DATA kbuf, dbuf; fstring printername; char adevice[MAXDEVICENAME]; - - ZERO_STRUCT(info); + char *comment = NULL; - slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename); - - kbuf.dptr = key; - kbuf.dsize = strlen(key)+1; + kbuf = make_printer_tdbkey(talloc_tos(), sharename); dbuf = tdb_fetch(tdb_printers, kbuf); - if (!dbuf.dptr) - return get_a_printer_2_default(info_ptr, servername, sharename); + if (!dbuf.dptr) { + return get_a_printer_2_default(info, servername, sharename); + } len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff", - &info.attributes, - &info.priority, - &info.default_priority, - &info.starttime, - &info.untiltime, - &info.status, - &info.cjobs, - &info.averageppm, - &info.changeid, - &info.c_setprinter, - &info.setuptime, - info.servername, - info.printername, - info.sharename, - info.portname, - info.drivername, - info.comment, - info.location, - info.sepfile, - info.printprocessor, - info.datatype, - info.parameters); + &info->attributes, + &info->priority, + &info->default_priority, + &info->starttime, + &info->untiltime, + &info->status, + &info->cjobs, + &info->averageppm, + &info->changeid, + &info->c_setprinter, + &info->setuptime, + info->servername, + info->printername, + info->sharename, + info->portname, + info->drivername, + &comment, + info->location, + info->sepfile, + info->printprocessor, + info->datatype, + info->parameters); + + if (comment) { + strlcpy(info->comment, comment, sizeof(info->comment)); + SAFE_FREE(comment); + } /* Samba has to have shared raw drivers. */ - info.attributes |= PRINTER_ATTRIBUTE_SAMBA; - info.attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA; + info->attributes |= PRINTER_ATTRIBUTE_SAMBA; + info->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA; /* Restore the stripped strings. */ - slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", servername); + slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername); - if ( lp_force_printername(snum) ) + if ( lp_force_printername(snum) ) { slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, sharename ); - else - slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info.printername); + } else { + slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info->printername); + } - fstrcpy(info.printername, printername); + fstrcpy(info->printername, printername); - len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len); +#ifdef HAVE_CUPS + if ( (enum printing_types)lp_printing(snum) == PRINT_CUPS ) { + /* Pull the location and comment strings from cups if we don't + already have one */ + if ( !strlen(info->location) || !strlen(info->comment) ) + cups_pull_comment_location( info ); + } +#endif + + len += unpack_devicemode(&info->devmode,dbuf.dptr+len, dbuf.dsize-len); /* * Some client drivers freak out if there is a NULL devmode @@ -3430,34 +4121,42 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *se * See comments in get_a_printer_2_default() */ - if (lp_default_devmode(snum) && !info.devmode) { + if (lp_default_devmode(snum) && !info->devmode) { DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n", printername)); - info.devmode = construct_nt_devicemode(printername); + info->devmode = construct_nt_devicemode(printername); } - slprintf( adevice, sizeof(adevice), "%s", info.printername ); - if (info.devmode) { - fstrcpy(info.devmode->devicename, adevice); + slprintf( adevice, sizeof(adevice), "%s", info->printername ); + if (info->devmode) { + fstrcpy(info->devmode->devicename, adevice); } - len += unpack_values( &info.data, dbuf.dptr+len, dbuf.dsize-len ); + if ( !(info->data = TALLOC_ZERO_P( info, NT_PRINTER_DATA )) ) { + DEBUG(0,("unpack_values: talloc() failed!\n")); + SAFE_FREE(dbuf.dptr); + return WERR_NOMEM; + } + len += unpack_values( info->data, dbuf.dptr+len, dbuf.dsize-len ); /* This will get the current RPC talloc context, but we should be passing this as a parameter... fixme... JRA ! */ - nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf); + if (!nt_printing_getsec(info, sharename, &info->secdesc_buf)) { + SAFE_FREE(dbuf.dptr); + return WERR_NOMEM; + } /* Fix for OS/2 drivers. */ - if (get_remote_arch() == RA_OS2) - map_to_os2_driver(info.drivername); + if (get_remote_arch() == RA_OS2) { + map_to_os2_driver(info->drivername); + } SAFE_FREE(dbuf.dptr); - *info_ptr=memdup(&info, sizeof(info)); DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n", - sharename, info.printername, info.drivername)); + sharename, info->printername, info->drivername)); return WERR_OK; } @@ -3544,26 +4243,6 @@ static uint32 rev_changeid(void) #endif } -/******************************************************************** - Send a message to all smbds about the printer that just changed - ********************************************************************/ - -static BOOL send_printer_mod_msg( char* printername ) -{ - int len = strlen(printername); - - if (!len) - return False; - - DEBUG(10,("send_printer_mod_msg: Sending message about printer change [%s]\n", - printername)); - - /* spam everyone that we just changed this printer */ - - message_send_all( conn_tdb_ctx(), MSG_PRINTER_MOD, printername, len+1, False, NULL ); - - return True; -} /* * The function below are the high level ones. @@ -3581,15 +4260,6 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level) dump_a_printer(printer, level); - /* - * invalidate cache for all open handles to this printer. - * cache for a given handle will be updated on the next - * get_a_printer() - */ - - invalidate_printer_hnd_cache( printer->info_2->sharename ); - send_printer_mod_msg( printer->info_2->sharename ); - switch (level) { case 2: { @@ -3625,14 +4295,13 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level) */ result=update_a_printer_2(printer->info_2); - break; } default: result=WERR_UNKNOWN_LEVEL; break; } - + return result; } @@ -3640,11 +4309,11 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level) Initialize printer devmode & data with previously saved driver init values. ****************************************************************************/ -static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr ) +static bool set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr ) { int len = 0; - pstring key; - TDB_DATA kbuf, dbuf; + char *key = NULL; + TDB_DATA dbuf; NT_PRINTER_INFO_LEVEL_2 info; @@ -3655,35 +4324,38 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr ) * replace, there will generally be some, but during an add printer, there * should not be any (if there are delete them). */ - - delete_all_printer_data( info_ptr, "" ); - - slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername); - kbuf.dptr = key; - kbuf.dsize = strlen(key)+1; + if ( info_ptr->data ) + delete_all_printer_data( info_ptr, "" ); + + if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX, + info_ptr->drivername) < 0) { + return false; + } - dbuf = tdb_fetch(tdb_drivers, kbuf); + dbuf = tdb_fetch_bystring(tdb_drivers, key); if (!dbuf.dptr) { /* * When changing to a driver that has no init info in the tdb, remove * the previous drivers init info and leave the new on blank. */ free_nt_devicemode(&info_ptr->devmode); - return False; + SAFE_FREE(key); + return false; } - + + SAFE_FREE(key); /* * 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. */ - + if ( info.devmode ) { ZERO_STRUCT(info.devmode->devicename); fstrcpy(info.devmode->devicename, info_ptr->printername); @@ -3691,18 +4363,18 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr ) /* * NT/2k does not change out the entire DeviceMode of a printer - * when changing the driver. Only the driverextra, private, & + * when changing the driver. Only the driverextra, private, & * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002) * * Later examination revealed that Windows NT/2k does reset the - * the printer's device mode, bit **only** when you change a + * the printer's device mode, bit **only** when you change a * property of the device mode such as the page orientation. * --jerry */ /* Bind the saved DEVMODE to the new the printer */ - + free_nt_devicemode(&info_ptr->devmode); info_ptr->devmode = info.devmode; @@ -3710,13 +4382,17 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr ) info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername)); /* Add the printer data 'values' to the new printer */ - - len += unpack_values( &info_ptr->data, dbuf.dptr+len, dbuf.dsize-len ); - + + if ( !(info_ptr->data = TALLOC_ZERO_P( info_ptr, NT_PRINTER_DATA )) ) { + DEBUG(0,("set_driver_init_2: talloc() failed!\n")); + return False; + } + + len += unpack_values( info_ptr->data, dbuf.dptr+len, dbuf.dsize-len ); SAFE_FREE(dbuf.dptr); - return True; + return true; } /**************************************************************************** @@ -3726,21 +4402,21 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr ) is bound to the new printer. ****************************************************************************/ -BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level) +bool set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level) { - BOOL result = False; - + bool result = False; + switch (level) { case 2: result = set_driver_init_2(printer->info_2); break; - + default: DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n", level)); break; } - + return result; } @@ -3748,24 +4424,26 @@ BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level) Delete driver init data stored for a specified driver ****************************************************************************/ -BOOL del_driver_init(char *drivername) +bool del_driver_init(char *drivername) { - pstring key; - TDB_DATA kbuf; + char *key; + bool ret; if (!drivername || !*drivername) { DEBUG(3,("del_driver_init: No drivername specified!\n")); - return False; + return false; } - slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername); - - kbuf.dptr = key; - kbuf.dsize = strlen(key)+1; + if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX, drivername) < 0) { + return false; + } - DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername)); + DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", + drivername)); - return (tdb_delete(tdb_drivers, kbuf) == 0); + ret = (tdb_delete_bystring(tdb_drivers, key) == 0); + SAFE_FREE(key); + return ret; } /**************************************************************************** @@ -3778,43 +4456,47 @@ BOOL del_driver_init(char *drivername) static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info) { - pstring key; - char *buf; + char *key = NULL; + uint8 *buf; int buflen, len, ret; - TDB_DATA kbuf, dbuf; + int retlen; + TDB_DATA dbuf; buf = NULL; buflen = 0; - again: + again: len = 0; len += pack_devicemode(info->devmode, buf+len, buflen-len); - len += pack_values( &info->data, buf+len, buflen-len ); + retlen = pack_values( info->data, buf+len, buflen-len ); + if (retlen == -1) { + ret = -1; + goto done; + } + len += retlen; if (buflen < len) { - char *tb; - - tb = (char *)SMB_REALLOC(buf, len); - if (!tb) { + buf = (uint8 *)SMB_REALLOC(buf, len); + if (!buf) { DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n")); ret = -1; goto done; } - else - buf = tb; buflen = len; goto again; } - slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername); + SAFE_FREE(key); + if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX, info->drivername) < 0) { + ret = (uint32)-1; + goto done; + } - kbuf.dptr = key; - kbuf.dsize = strlen(key)+1; dbuf.dptr = buf; dbuf.dsize = len; - ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE); + ret = tdb_store_bystring(tdb_drivers, key, dbuf, TDB_REPLACE); done: if (ret == -1) @@ -3856,9 +4538,9 @@ static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level) got to keep the endians happy :). ****************************************************************************/ -static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len ) +static bool convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len ) { - BOOL result = False; + bool result = False; prs_struct ps; DEVICEMODE devmode; @@ -3991,72 +4673,6 @@ WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *dat return status; } -/**************************************************************************** - Deep copy a NT_PRINTER_DATA -****************************************************************************/ - -static NTSTATUS copy_printer_data( NT_PRINTER_DATA *dst, NT_PRINTER_DATA *src ) -{ - int i, j, num_vals, new_key_index; - REGVAL_CTR *src_key, *dst_key; - - if ( !dst || !src ) - return NT_STATUS_NO_MEMORY; - - for ( i=0; inum_keys; i++ ) { - - /* create a new instance of the printerkey in the destination - printer_data object */ - - new_key_index = add_new_printer_key( dst, src->keys[i].name ); - dst_key = &dst->keys[new_key_index].values; - - src_key = &src->keys[i].values; - num_vals = regval_ctr_numvals( src_key ); - - /* dup the printer entire printer key */ - - for ( j=0; jdevmode = dup_nt_devicemode( printer->devmode ); - - ZERO_STRUCT( copy->data ); - copy_printer_data( ©->data, &printer->data ); - - /* this is talloc()'d; very ugly that we have a structure that - is half malloc()'d and half talloc()'d but that is the way - that the PRINTER_INFO stuff is written right now. --jerry */ - - copy->secdesc_buf = dup_sec_desc_buf( ctx, printer->secdesc_buf ); - - return copy; -} - /**************************************************************************** Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory. @@ -4075,104 +4691,53 @@ WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_print const char *sharename) { WERROR result; - NT_PRINTER_INFO_LEVEL *printer = NULL; fstring servername; - *pp_printer = NULL; - DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level)); + if ( !(*pp_printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) { + DEBUG(0,("get_a_printer: talloc() fail.\n")); + return WERR_NOMEM; + } + switch (level) { case 2: - if ((printer = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL)) == NULL) { - DEBUG(0,("get_a_printer: malloc fail.\n")); + if ( !((*pp_printer)->info_2 = TALLOC_ZERO_P(*pp_printer, NT_PRINTER_INFO_LEVEL_2)) ) { + DEBUG(0,("get_a_printer: talloc() fail.\n")); + TALLOC_FREE( *pp_printer ); return WERR_NOMEM; } - ZERO_STRUCTP(printer); if ( print_hnd ) fstrcpy( servername, print_hnd->servername ); else { fstrcpy( servername, "%L" ); - standard_sub_basic( "", servername, sizeof(servername)-1 ); - } - - /* - * check for cache first. A Printer handle cannot changed - * to another printer object so we only check that the printer - * is actually for a printer and that the printer_info pointer - * is valid - */ - if ( print_hnd - && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER) - && print_hnd->printer_info ) - { - /* get_talloc_ctx() works here because we need a short - lived talloc context */ - - if ( !(printer->info_2 = dup_printer_2(get_talloc_ctx(), print_hnd->printer_info->info_2)) ) - { - DEBUG(0,("get_a_printer: unable to copy cached printer info!\n")); - - SAFE_FREE(printer); - return WERR_NOMEM; - } - - DEBUG(10,("get_a_printer: using cached copy of printer_info_2\n")); - - *pp_printer = printer; - result = WERR_OK; - - break; + standard_sub_basic( "", "", servername, + sizeof(servername)-1 ); } - /* no cache for this handle; see if we can match one from another handle. - Make sure to use a short lived talloc ctx */ - - if ( print_hnd ) - result = find_printer_in_print_hnd_cache(get_talloc_ctx(), &printer->info_2, servername, sharename); - - /* fail to disk if we don't have it with any open handle */ - - if ( !print_hnd || !W_ERROR_IS_OK(result) ) - result = get_a_printer_2(&printer->info_2, servername, sharename ); + result = get_a_printer_2( (*pp_printer)->info_2, servername, sharename ); + /* we have a new printer now. Save it with this handle */ - if ( W_ERROR_IS_OK(result) ) { - dump_a_printer(printer, level); - - /* save a copy in cache */ - if ( print_hnd && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)) { - if ( !print_hnd->printer_info ) - print_hnd->printer_info = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL); - - if ( print_hnd->printer_info ) { - /* make sure to use the handle's talloc ctx here since - the printer_2 object must last until the handle is closed */ - - print_hnd->printer_info->info_2 = dup_printer_2(print_hnd->ctx, printer->info_2); - - /* don't fail the lookup just because the cache update failed */ - if ( !print_hnd->printer_info->info_2 ) - DEBUG(0,("get_a_printer: unable to copy new printer info!\n")); - } - } - *pp_printer = printer; + if ( !W_ERROR_IS_OK(result) ) { + TALLOC_FREE( *pp_printer ); + DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", + sharename, (unsigned int)level, dos_errstr(result))); + return result; } - else - SAFE_FREE(printer); + + dump_a_printer( *pp_printer, level); break; default: - result=WERR_UNKNOWN_LEVEL; - break; + TALLOC_FREE( *pp_printer ); + return WERR_UNKNOWN_LEVEL; } - DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", sharename, (unsigned int)level, dos_errstr(result))); - - return result; + return WERR_OK; } /**************************************************************************** @@ -4181,30 +4746,25 @@ WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_print uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level) { - uint32 result; NT_PRINTER_INFO_LEVEL *printer = *pp_printer; - DEBUG(104,("freeing a printer at level [%d]\n", level)); - - if (printer == NULL) + if ( !printer ) return 0; switch (level) { case 2: - if (printer->info_2 != NULL) { + if ( printer->info_2 ) free_nt_printer_info_level_2(&printer->info_2); - result=0; - } else - result=4; break; default: - result=1; - break; + DEBUG(0,("free_a_printer: unknown level! [%d]\n", level )); + return 1; } - SAFE_FREE(*pp_printer); - return result; + TALLOC_FREE(*pp_printer); + + return 0; } /**************************************************************************** @@ -4319,39 +4879,75 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level) to a printer ****************************************************************************/ -BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 ) +bool printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 ) { int snum; int n_services = lp_numservices(); NT_PRINTER_INFO_LEVEL *printer = NULL; + bool in_use = False; if ( !info_3 ) return False; - DEBUG(5,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n")); + DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n")); /* loop through the printers.tdb and check for the drivername */ - for (snum=0; snumname, printer->info_2->drivername) ) { - free_a_printer( &printer, 2 ); - return True; - } + if ( strequal(info_3->name, printer->info_2->drivername) ) + in_use = True; free_a_printer( &printer, 2 ); } - DEBUG(5,("printer_driver_in_use: Completed search through ntprinters.tdb...\n")); + DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n")); + + if ( in_use ) { + NT_PRINTER_DRIVER_INFO_LEVEL d; + WERROR werr; + + DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", info_3->name)); + + /* we can still remove the driver if there is one of + "Windows NT x86" version 2 or 3 left */ + + if ( !strequal( "Windows NT x86", info_3->environment ) ) { + werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", DRIVER_ANY_VERSION ); + } + else { + switch ( info_3->cversion ) { + case 2: + werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 3 ); + break; + case 3: + werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 2 ); + break; + default: + DEBUG(0,("printer_driver_in_use: ERROR! unknown driver version (%d)\n", + info_3->cversion)); + werr = WERR_UNKNOWN_PRINTER_DRIVER; + break; + } + } + + /* now check the error code */ + + if ( W_ERROR_IS_OK(werr) ) { + /* it's ok to remove the driver, we have other architctures left */ + in_use = False; + free_a_printer_driver( d, 3 ); + } + } /* report that the driver is not in use by default */ - return False; + return in_use; } @@ -4359,7 +4955,7 @@ BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 ) Check to see if a ogiven file is in use by *info *********************************************************************/ -static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info ) +static bool drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info ) { int i = 0; @@ -4417,10 +5013,10 @@ static void trim_dependent_file( fstring files[], int idx ) Check if any of the files used by src are also used by drv *********************************************************************/ -static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src, +static bool trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src, NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv ) { - BOOL in_use = False; + bool in_use = False; int i = 0; if ( !src || !drv ) @@ -4480,7 +5076,7 @@ static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src, which are not in use ****************************************************************************/ -BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info ) +bool printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info ) { int i; int ndrivers; @@ -4527,61 +5123,66 @@ BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info ) return True; } } - + free_a_printer_driver(driver, 3); - } - + } + SAFE_FREE(list); - + DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n")); - + driver.info_3 = info; - + if ( DEBUGLEVEL >= 20 ) dump_a_printer_driver( driver, 3 ); - + return False; } /**************************************************************************** - Actually delete the driver files. Make sure that - printer_driver_files_in_use() return False before calling + Actually delete the driver files. Make sure that + printer_driver_files_in_use() return False before calling this. ****************************************************************************/ -static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user ) +static bool delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user ) { int i = 0; char *s; + const char *file; connection_struct *conn; DATA_BLOB null_pw; NTSTATUS nt_status; fstring res_type; - BOOL bad_path; SMB_STRUCT_STAT st; if ( !info_3 ) return False; - + DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion)); - + /* - * Connect to the print$ share under the same account as the - * user connected to the rpc pipe. Note we must be root to + * Connect to the print$ share under the same account as the + * user connected to the rpc pipe. Note we must be root to * do this. */ - - null_pw = data_blob( NULL, 0 ); + + null_pw = data_blob_null; fstrcpy(res_type, "A:"); become_root(); conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status ); unbecome_root(); - + if ( !conn ) { DEBUG(0,("delete_driver_files: Unable to connect\n")); return False; } + if ( !CAN_WRITE(conn) ) { + DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n")); + return False; + } + /* Save who we are - we are temporarily becoming the connection user. */ if ( !become_user(conn, conn->vuid) ) { @@ -4589,62 +5190,67 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct return False; } - /* now delete the files; must strip the '\print$' string from + /* now delete the files; must strip the '\print$' string from fron of path */ - + if ( *info_3->driverpath ) { if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) { - driver_unix_convert(s, conn, NULL, &bad_path, &st); + file = s; + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting driverfile [%s]\n", s)); - unlink_internals(conn, 0, s); + unlink_internals(conn, NULL, 0, file, False); } } - + if ( *info_3->configfile ) { if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) { - driver_unix_convert(s, conn, NULL, &bad_path, &st); + file = s; + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting configfile [%s]\n", s)); - unlink_internals(conn, 0, s); + unlink_internals(conn, NULL, 0, file, False); } } - + if ( *info_3->datafile ) { if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) { - driver_unix_convert(s, conn, NULL, &bad_path, &st); + file = s; + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting datafile [%s]\n", s)); - unlink_internals(conn, 0, s); + unlink_internals(conn, NULL, 0, file, False); } } - + if ( *info_3->helpfile ) { if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) { - driver_unix_convert(s, conn, NULL, &bad_path, &st); + file = s; + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting helpfile [%s]\n", s)); - unlink_internals(conn, 0, s); + unlink_internals(conn, NULL, 0, file, False); } } - + /* check if we are done removing files */ - + if ( info_3->dependentfiles ) { - while ( *info_3->dependentfiles[i] ) { - char *file; + while ( info_3->dependentfiles[i][0] ) { + char *p; /* bypass the "\print$" portion of the path */ - - if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) { - driver_unix_convert(file, conn, NULL, &bad_path, &st); + + if ( (p = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) { + file = p; + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting dependent file [%s]\n", file)); - unlink_internals(conn, 0, file ); + unlink_internals(conn, NULL, 0, file, False); } - + i++; } } unbecome_user(); - - return True; + + return true; } /**************************************************************************** @@ -4653,18 +5259,23 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct ***************************************************************************/ WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user, - uint32 version, BOOL delete_files ) + uint32 version, bool delete_files ) { - pstring key; + char *key = NULL; const char *arch; - TDB_DATA kbuf, dbuf; + TDB_DATA dbuf; NT_PRINTER_DRIVER_INFO_LEVEL ctr; /* delete the tdb data first */ arch = get_short_archi(info_3->environment); - slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, - arch, version, info_3->name); + if (!arch) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } + if (asprintf(&key, "%s%s/%d/%s", DRIVERS_PREFIX, + arch, version, info_3->name) < 0) { + return WERR_NOMEM; + } DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n", key, delete_files ? "TRUE" : "FALSE" )); @@ -4672,23 +5283,22 @@ WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct cur ctr.info_3 = info_3; dump_a_printer_driver( ctr, 3 ); - kbuf.dptr=key; - kbuf.dsize=strlen(key)+1; - /* check if the driver actually exists for this environment */ - - dbuf = tdb_fetch( tdb_drivers, kbuf ); + + dbuf = tdb_fetch_bystring( tdb_drivers, key ); if ( !dbuf.dptr ) { DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key)); + SAFE_FREE(key); return WERR_UNKNOWN_PRINTER_DRIVER; } - + SAFE_FREE( dbuf.dptr ); - + /* ok... the driver exists so the delete should return success */ - - if (tdb_delete(tdb_drivers, kbuf) == -1) { + + if (tdb_delete_bystring(tdb_drivers, key) == -1) { DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key)); + SAFE_FREE(key); return WERR_ACCESS_DENIED; } @@ -4700,24 +5310,24 @@ WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct cur if ( delete_files ) delete_driver_files( info_3, user ); - - + DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key)); + SAFE_FREE(key); return WERR_OK; - } - +} + /**************************************************************************** Store a security desc for a printer. ****************************************************************************/ -WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr) +WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr) { SEC_DESC_BUF *new_secdesc_ctr = NULL; SEC_DESC_BUF *old_secdesc_ctr = NULL; prs_struct ps; TALLOC_CTX *mem_ctx = NULL; - fstring key; + TDB_DATA kbuf; WERROR status; mem_ctx = talloc_init("nt_printing_setsec"); @@ -4729,40 +5339,48 @@ WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr) permissions through NT. If they are NULL in the new security descriptor then copy them over from the old one. */ - if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) { + if (!secdesc_ctr->sd->owner_sid || !secdesc_ctr->sd->group_sid) { DOM_SID *owner_sid, *group_sid; SEC_ACL *dacl, *sacl; SEC_DESC *psd = NULL; size_t size; - nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr); + if (!nt_printing_getsec(mem_ctx, sharename, &old_secdesc_ctr)) { + status = WERR_NOMEM; + goto out; + } /* Pick out correct owner and group sids */ - owner_sid = secdesc_ctr->sec->owner_sid ? - secdesc_ctr->sec->owner_sid : - old_secdesc_ctr->sec->owner_sid; + owner_sid = secdesc_ctr->sd->owner_sid ? + secdesc_ctr->sd->owner_sid : + old_secdesc_ctr->sd->owner_sid; - group_sid = secdesc_ctr->sec->grp_sid ? - secdesc_ctr->sec->grp_sid : - old_secdesc_ctr->sec->grp_sid; + group_sid = secdesc_ctr->sd->group_sid ? + secdesc_ctr->sd->group_sid : + old_secdesc_ctr->sd->group_sid; - dacl = secdesc_ctr->sec->dacl ? - secdesc_ctr->sec->dacl : - old_secdesc_ctr->sec->dacl; + dacl = secdesc_ctr->sd->dacl ? + secdesc_ctr->sd->dacl : + old_secdesc_ctr->sd->dacl; - sacl = secdesc_ctr->sec->sacl ? - secdesc_ctr->sec->sacl : - old_secdesc_ctr->sec->sacl; + sacl = secdesc_ctr->sd->sacl ? + secdesc_ctr->sd->sacl : + old_secdesc_ctr->sd->sacl; /* Make a deep copy of the security descriptor */ - psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision, secdesc_ctr->sec->type, + psd = make_sec_desc(mem_ctx, secdesc_ctr->sd->revision, secdesc_ctr->sd->type, owner_sid, group_sid, sacl, dacl, &size); + if (!psd) { + status = WERR_NOMEM; + goto out; + } + new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd); } @@ -4772,8 +5390,9 @@ WERROR nt_printing_setsec(const 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) + - sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL); + prs_init(&ps, + (uint32)ndr_size_security_descriptor(new_secdesc_ctr->sd, 0) + + sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL); if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr, &ps, 1)) { @@ -4781,12 +5400,12 @@ WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr) goto out; } - slprintf(key, sizeof(key)-1, "SECDESC/%s", printername); + kbuf = make_printers_secdesc_tdbkey(mem_ctx, sharename ); - if (tdb_prs_store(tdb_printers, key, &ps)==0) { + if (tdb_prs_store(tdb_printers, kbuf, &ps)==0) { status = WERR_OK; } else { - DEBUG(1,("Failed to store secdesc for %s\n", printername)); + DEBUG(1,("Failed to store secdesc for %s\n", sharename)); status = WERR_BADFUNC; } @@ -4806,53 +5425,69 @@ WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr) static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx) { - SEC_ACE ace[3]; + SEC_ACE ace[5]; /* max number of ace entries */ + int i = 0; SEC_ACCESS sa; SEC_ACL *psa = NULL; SEC_DESC_BUF *sdb = NULL; SEC_DESC *psd = NULL; - DOM_SID owner_sid; + DOM_SID adm_sid; size_t sd_size; /* Create an ACE where Everyone is allowed to print */ init_sec_access(&sa, PRINTER_ACE_PRINT); - init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, + init_sec_ace(&ace[i++], &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. */ - - if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) { - sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN); - } else { - - /* Backup plan - make printer owned by admins. - This should emulate a lanman printer as security - settings can't be changed. */ + /* Add the domain admins group if we are a DC */ + + if ( IS_DC ) { + DOM_SID domadmins_sid; + + sid_copy(&domadmins_sid, get_global_sam_sid()); + sid_append_rid(&domadmins_sid, DOMAIN_GROUP_RID_ADMINS); + + init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL); + init_sec_ace(&ace[i++], &domadmins_sid, + SEC_ACE_TYPE_ACCESS_ALLOWED, sa, + SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY); + init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, + sa, SEC_ACE_FLAG_CONTAINER_INHERIT); + } + else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) { + sid_append_rid(&adm_sid, DOMAIN_USER_RID_ADMIN); - sid_copy(&owner_sid, get_global_sam_sid()); - sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN); + init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL); + init_sec_ace(&ace[i++], &adm_sid, + SEC_ACE_TYPE_ACCESS_ALLOWED, sa, + SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY); + init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, + sa, SEC_ACE_FLAG_CONTAINER_INHERIT); } - 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); + /* add BUILTIN\Administrators as FULL CONTROL */ 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); + init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, + SEC_ACE_TYPE_ACCESS_ALLOWED, sa, + SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY); + init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, + SEC_ACE_TYPE_ACCESS_ALLOWED, + sa, SEC_ACE_FLAG_CONTAINER_INHERIT); + + /* Make the security descriptor owned by the BUILTIN\Administrators */ /* The ACL revision number in rpc_secdesc.h differs from the one created by NT when setting ACE entries in printer descriptors. NT4 complains about the property being edited by a NT5 machine. */ - if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) != NULL) { + if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) != NULL) { psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, - &owner_sid, NULL, - NULL, psa, &sd_size); + &global_sid_Builtin_Administrators, + &global_sid_Builtin_Administrators, + NULL, psa, &sd_size); } if (!psd) { @@ -4872,24 +5507,28 @@ static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx) Get a security desc for a printer. ****************************************************************************/ -BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF **secdesc_ctr) +bool nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **secdesc_ctr) { prs_struct ps; - fstring key; + TDB_DATA kbuf; char *temp; - if (strlen(printername) > 2 && (temp = strchr(printername + 2, '\\'))) { - printername = temp + 1; + if (strlen(sharename) > 2 && (temp = strchr(sharename + 2, '\\'))) { + sharename = temp + 1; } + ZERO_STRUCT(ps); + /* Fetch security descriptor from tdb */ - slprintf(key, sizeof(key)-1, "SECDESC/%s", printername); + kbuf = make_printers_secdesc_tdbkey(ctx, sharename ); - if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 || + if (tdb_prs_fetch(tdb_printers, kbuf, &ps, ctx)!=0 || !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) { - DEBUG(4,("using default secdesc for %s\n", printername)); + prs_mem_free(&ps); + + DEBUG(4,("using default secdesc for %s\n", sharename)); if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) { return False; @@ -4897,22 +5536,25 @@ BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF * /* Save default security descriptor for later */ - prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) + + prs_init(&ps, (uint32)ndr_size_security_descriptor((*secdesc_ctr)->sd, 0) + sizeof(SEC_DESC_BUF), ctx, MARSHALL); - if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) - tdb_prs_store(tdb_printers, key, &ps); + if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) { + tdb_prs_store(tdb_printers, kbuf, &ps); + } prs_mem_free(&ps); return True; } + prs_mem_free(&ps); + /* If security descriptor is owned by S-1-1-0 and winbindd is up, this security descriptor has been created when winbindd was down. Take ownership of security descriptor. */ - if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) { + if (sid_equal((*secdesc_ctr)->sd->owner_sid, &global_sid_World)) { DOM_SID owner_sid; /* Change sd owner to workgroup administrator */ @@ -4926,14 +5568,21 @@ BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF * sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN); - psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision, (*secdesc_ctr)->sec->type, + psd = make_sec_desc(ctx, (*secdesc_ctr)->sd->revision, (*secdesc_ctr)->sd->type, &owner_sid, - (*secdesc_ctr)->sec->grp_sid, - (*secdesc_ctr)->sec->sacl, - (*secdesc_ctr)->sec->dacl, + (*secdesc_ctr)->sd->group_sid, + (*secdesc_ctr)->sd->sacl, + (*secdesc_ctr)->sd->dacl, &size); + if (!psd) { + return False; + } + new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd); + if (!new_secdesc_ctr) { + return False; + } /* Swap with other one */ @@ -4941,29 +5590,25 @@ BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF * /* Set it */ - nt_printing_setsec(printername, *secdesc_ctr); + nt_printing_setsec(sharename, *secdesc_ctr); } } if (DEBUGLEVEL >= 10) { - SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl; + SEC_ACL *the_acl = (*secdesc_ctr)->sd->dacl; int i; DEBUG(10, ("secdesc_ctr for %s has %d aces:\n", - printername, the_acl->num_aces)); + sharename, the_acl->num_aces)); for (i = 0; i < the_acl->num_aces; i++) { - fstring sid_str; - - sid_to_string(sid_str, &the_acl->ace[i].trustee); - - DEBUG(10, ("%s %d %d 0x%08x\n", sid_str, - the_acl->ace[i].type, the_acl->ace[i].flags, - the_acl->ace[i].info.mask)); + DEBUG(10, ("%s %d %d 0x%08x\n", + sid_string_dbg(&the_acl->aces[i].trustee), + the_acl->aces[i].type, the_acl->aces[i].flags, + the_acl->aces[i].access_mask)); } } - prs_mem_free(&ps); return True; } @@ -5012,7 +5657,7 @@ 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, + se_map_generic(&sd->dacl->aces[i].access_mask, &printer_generic_mapping); } } @@ -5034,26 +5679,30 @@ void map_printer_permissions(SEC_DESC *sd) print_job_delete, print_job_pause, print_job_resume, print_queue_purge + Try access control in the following order (for performance reasons): + 1) root ans SE_PRINT_OPERATOR can do anything (easy check) + 2) check security descriptor (bit comparisons in memory) + 3) "printer admins" (may result in numerous calls to winbind) + ****************************************************************************/ -BOOL print_access_check(struct current_user *user, int snum, int access_type) +bool print_access_check(struct current_user *user, int snum, int access_type) { SEC_DESC_BUF *secdesc = NULL; uint32 access_granted; NTSTATUS status; - BOOL result; + bool result; const char *pname; TALLOC_CTX *mem_ctx = NULL; - extern struct current_user current_user; + SE_PRIV se_printop = SE_PRINT_OPERATOR; /* If user is NULL then use the current_user structure */ if (!user) user = ¤t_user; - /* Always allow root or printer admins to do anything */ + /* Always allow root or SE_PRINT_OPERATROR to do anything */ - if (user->uid == 0 || - user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups)) { + if ( user->ut.uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) { return True; } @@ -5073,7 +5722,11 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) return False; } - nt_printing_getsec(mem_ctx, pname, &secdesc); + if (!nt_printing_getsec(mem_ctx, pname, &secdesc)) { + talloc_destroy(mem_ctx); + errno = ENOMEM; + return False; + } if (access_type == JOB_ACCESS_ADMINISTER) { SEC_DESC_BUF *parent_secdesc = secdesc; @@ -5082,7 +5735,13 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) against. This is because print jobs are child objects objects of a printer. */ - secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False); + secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sd, False); + + if (!secdesc) { + talloc_destroy(mem_ctx); + errno = ENOMEM; + return False; + } /* Now this is the bit that really confuses me. The access type needs to be changed from JOB_ACCESS_ADMINISTER to @@ -5095,17 +5754,28 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) /* Check access */ - map_printer_permissions(secdesc->sec); + map_printer_permissions(secdesc->sd); - result = se_access_check(secdesc->sec, user->nt_user_token, access_type, + result = se_access_check(secdesc->sd, user->nt_user_token, access_type, &access_granted, &status); DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE")); + /* see if we need to try the printer admin list */ + + if ((access_granted == 0) && + (token_contains_name_in_list(uidtoname(user->ut.uid), NULL, + user->nt_user_token, + lp_printer_admin(snum)))) { + talloc_destroy(mem_ctx); + return True; + } + talloc_destroy(mem_ctx); - if (!result) + if (!result) { errno = EACCES; + } return result; } @@ -5114,15 +5784,15 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type) Check the time parameters allow a print operation. *****************************************************************************/ -BOOL print_time_access_check(int snum) +bool print_time_access_check(const char *servicename) { NT_PRINTER_INFO_LEVEL *printer = NULL; - BOOL ok = False; + bool ok = False; time_t now = time(NULL); struct tm *t; uint32 mins; - if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum)))) + if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename))) return False; if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0) @@ -5145,7 +5815,10 @@ BOOL print_time_access_check(int snum) /**************************************************************************** Fill in the servername sent in the _spoolss_open_printer_ex() call ****************************************************************************/ + char* get_server_name( Printer_entry *printer ) { return printer->servername; } + +