* Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
* Copyright (C) Jean François Micouleau 1998-2000,
* Copyright (C) Jeremy Allison 2001-2002,
- * Copyright (C) Gerald Carter 2000-2002,
+ * Copyright (C) Gerald Carter 2000-2003,
* Copyright (C) Tim Potter 2001-2002.
*
* This program is free software; you can redistribute it and/or modify
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
-/* #define EMULATE_WIN2K_HACK 1 */
#ifndef MAX_OPEN_PRINTER_EXS
#define MAX_OPEN_PRINTER_EXS 50
#define MAGIC_DISPLAY_FREQUENCY 0xfade2bad
#define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_"
-#define PRINTER_HANDLE_IS_PRINTER 0
-#define PRINTER_HANDLE_IS_PRINTSERVER 1
+
/* Table to map the driver version */
/* to OS */
-char * drv_ver_to_os[] = {
+static const char * drv_ver_to_os[] = {
"WIN9X", /* driver version/cversion 0 */
"", /* unused ? */
"WINNT", /* driver version/cversion 2 */
"WIN2K", /* driver version/cversion 3 */
};
+static const char *get_drv_ver_to_os(int ver)
+{
+ if (ver < 0 || ver > 3)
+ return "";
+ return drv_ver_to_os[ver];
+}
+
struct table_node {
- char *long_archi;
- char *short_archi;
+ const char *long_archi;
+ const char *short_archi;
int version;
};
-
-/* structure to store the printer handles */
-/* and a reference to what it's pointing to */
-/* and the notify info asked about */
-/* that's the central struct */
-typedef struct _Printer{
- struct _Printer *prev, *next;
- BOOL document_started;
- BOOL page_started;
- uint32 jobid; /* jobid in printing backend */
- BOOL printer_type;
- union {
- fstring handlename;
- fstring printerservername;
- } dev;
- uint32 type;
- uint32 access_granted;
- struct {
- uint32 flags;
- uint32 options;
- fstring localmachine;
- uint32 printerlocal;
- SPOOL_NOTIFY_OPTION *option;
- POLICY_HND client_hnd;
- uint32 client_connected;
- uint32 change;
- } notify;
- struct {
- fstring machine;
- fstring user;
- } client;
-
- /* devmode sent in the OpenPrinter() call */
- NT_DEVICEMODE *nt_devmode;
-
-} Printer_entry;
-
static Printer_entry *printers_list;
typedef struct _counter_printer_0 {
Disconnect from the client
****************************************************************************/
-static void srv_spoolss_replycloseprinter(POLICY_HND *handle)
+static void srv_spoolss_replycloseprinter(int snum, POLICY_HND *handle)
{
WERROR result;
+ /*
+ * Tell the specific printing tdb we no longer want messages for this printer
+ * by deregistering our PID.
+ */
+
+ if (!print_notify_deregister_pid(snum))
+ DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", lp_const_servicename(snum) ));
+
/* weird if the test succeds !!! */
if (smb_connections==0) {
DEBUG(0,("srv_spoolss_replycloseprinter:Trying to close non-existant notify backchannel !\n"));
{
Printer_entry *Printer = (Printer_entry *)ptr;
- if (Printer->notify.client_connected==True)
- srv_spoolss_replycloseprinter(&Printer->notify.client_hnd);
+ if (Printer->notify.client_connected==True) {
+ int snum = -1;
+
+ if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) {
+ snum = -1;
+ srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd);
+ } else if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTER) {
+ snum = print_queue_snum(Printer->dev.handlename);
+ if (snum != -1)
+ srv_spoolss_replycloseprinter(snum,
+ &Printer->notify.client_hnd);
+ }
+ }
Printer->notify.flags=0;
Printer->notify.options=0;
Printer->notify.client_connected=False;
free_nt_devicemode( &Printer->nt_devmode );
+ free_a_printer( &Printer->printer_info, 2 );
+
+ talloc_destroy( Printer->ctx );
/* Remove from the internal list. */
DLIST_REMOVE(printers_list, Printer);
Functions to duplicate a SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
****************************************************************************/
-SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
+static SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
{
SPOOL_NOTIFY_OPTION *new_sp = NULL;
return find_printer;
}
+/****************************************************************************
+ look for a printer object cached on an open printer handle
+****************************************************************************/
+
+WERROR find_printer_in_print_hnd_cache( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2 **info2,
+ const char *printername )
+{
+ Printer_entry *p;
+
+ DEBUG(10,("find_printer_in_print_hnd_cache: printer [%s]\n", printername));
+
+ for ( p=printers_list; p; p=p->next )
+ {
+ if ( p->printer_type==PRINTER_HANDLE_IS_PRINTER
+ && p->printer_info
+ && StrCaseCmp(p->dev.handlename, printername) == 0 )
+ {
+ DEBUG(10,("Found printer\n"));
+ *info2 = dup_printer_2( ctx, p->printer_info->info_2 );
+ if ( *info2 )
+ return WERR_OK;
+ }
+ }
+
+ return WERR_INVALID_PRINTER_NAME;
+}
+
+/****************************************************************************
+ destroy any cached printer_info_2 structures on open handles
+****************************************************************************/
+
+void invalidate_printer_hnd_cache( char *printername )
+{
+ Printer_entry *p;
+
+ DEBUG(10,("invalidate_printer_hnd_cache: printer [%s]\n", printername));
+
+ for ( p=printers_list; p; p=p->next )
+ {
+ if ( p->printer_type==PRINTER_HANDLE_IS_PRINTER
+ && StrCaseCmp(p->dev.handlename, printername)==0)
+ {
+ DEBUG(10,("invalidating printer_info cache for handl:\n"));
+ free_a_printer( &p->printer_info, 2 );
+ p->printer_info = NULL;
+ }
+ }
+
+ return;
+}
/****************************************************************************
Close printer index by handle.
****************************************************************************/
return WERR_BADFID;
}
- if (del_a_printer(Printer->dev.handlename) != 0) {
- DEBUG(3,("Error deleting printer %s\n", Printer->dev.handlename));
- return WERR_BADFID;
+ /*
+ * It turns out that Windows allows delete printer on a handle
+ * opened by an admin user, then used on a pipe handle created
+ * by an anonymous user..... but they're working on security.... riiight !
+ * JRA.
+ */
+
+ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+ DEBUG(3, ("delete_printer_handle: denied by handle\n"));
+ return WERR_ACCESS_DENIED;
}
+#if 0
/* Check calling user has permission to delete printer. Note that
since we set the snum parameter to -1 only administrators can
delete the printer. This stops people with the Full Control
DEBUG(3, ("printer delete denied by security descriptor\n"));
return WERR_ACCESS_DENIED;
}
+#endif
+
+ if (del_a_printer(Printer->dev.handlename) != 0) {
+ DEBUG(3,("Error deleting printer %s\n", Printer->dev.handlename));
+ return WERR_BADFID;
+ }
if (*lp_deleteprinter_cmd()) {
/* Send SIGHUP to process group... is there a better way? */
kill(0, SIGHUP);
- if ( ( i = lp_servicenumber( Printer->dev.handlename ) ) >= 0 ) {
- lp_killservice( i );
- return WERR_OK;
- } else
+ /* go ahead and re-read the services immediately */
+ reload_services( False );
+
+ if ( ( i = lp_servicenumber( Printer->dev.handlename ) ) < 0 )
return WERR_ACCESS_DENIED;
}
fstring sname;
BOOL found=False;
- DEBUG(4,("Setting printer name=%s (len=%d)\n", handlename, strlen(handlename)));
+ DEBUG(4,("Setting printer name=%s (len=%lu)\n", handlename, (unsigned long)strlen(handlename)));
if (Printer->printer_type==PRINTER_HANDLE_IS_PRINTSERVER) {
ZERO_STRUCT(Printer->dev.printerservername);
aprinter=handlename;
}
- DEBUGADD(5,("searching for [%s] (len=%d)\n", aprinter, strlen(aprinter)));
+ DEBUGADD(5,("searching for [%s] (len=%lu)\n", aprinter, (unsigned long)strlen(aprinter)));
/*
* The original code allowed smbd to store a printer name that
ZERO_STRUCTP(new_printer);
- new_printer->notify.option=NULL;
-
- /* Add to the internal list. */
- DLIST_ADD(printers_list, new_printer);
-
if (!create_policy_hnd(p, hnd, free_printer_entry, new_printer)) {
SAFE_FREE(new_printer);
return False;
}
-
+
+ /* Add to the internal list. */
+ DLIST_ADD(printers_list, new_printer);
+
+ new_printer->notify.option=NULL;
+
+ if ( !(new_printer->ctx = talloc_init("Printer Entry [%p]", hnd)) ) {
+ DEBUG(0,("open_printer_hnd: talloc_init() failed!\n"));
+ close_printer_handle(p, hnd);
+ return False;
+ }
+
if (!set_printer_hnd_printertype(new_printer, name)) {
close_printer_handle(p, hnd);
return False;
/*
* Flags should always be zero when the change notify
- * is registered by the cliebnt's spooler. A user Win32 app
+ * is registered by the client's spooler. A user Win32 app
* might use the flags though instead of the NOTIFY_OPTION_INFO
* --jerry
*/
return;
}
- if (!make_systemtime(&systime, localtime((time_t *)msg->notify.data))) {
+ if (!make_systemtime(&systime, gmtime((time_t *)msg->notify.data))) {
DEBUG(5, ("notify_system_time: unable to make systemtime\n"));
return;
}
return;
data->notify_data.data.length = prs_offset(&ps);
- data->notify_data.data.string =
- talloc(mem_ctx, prs_offset(&ps));
+ data->notify_data.data.string = talloc(mem_ctx, prs_offset(&ps));
- memcpy(data->notify_data.data.string, prs_data_p(&ps), prs_offset(&ps));
+ prs_copy_all_data_out((char *)data->notify_data.data.string, &ps);
prs_mem_free(&ps);
}
struct notify2_message_table {
- char *name;
+ const char *name;
void (*fn)(struct spoolss_notify_msg *msg,
SPOOL_NOTIFY_INFO_DATA *data, TALLOC_CTX *mem_ctx);
};
if ( !ctr )
return;
- ctr->ctx = talloc_init();
+ ctr->ctx = talloc_init("notify_msg_ctr_init %p", ctr);
return;
}
/* add a new group? */
- if ( i == ctr->num_groups )
- {
+ if ( i == ctr->num_groups ) {
ctr->num_groups++;
if ( !(groups = talloc_realloc( ctr->ctx, ctr->msg_groups, sizeof(SPOOLSS_NOTIFY_MSG_GROUP)*ctr->num_groups)) ) {
TALLOC_CTX *mem_ctx = notify_ctr_getctx( ctr );
SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, idx );
SPOOLSS_NOTIFY_MSG *messages;
-
+ int sending_msg_count;
if ( !msg_group ) {
DEBUG(5,("send_notify2_changes() called with no msg group!\n"));
/* loop over all printers */
- for (p = printers_list; p; p = p->next)
- {
+ for (p = printers_list; p; p = p->next) {
SPOOL_NOTIFY_INFO_DATA *data;
uint32 data_len = 0;
uint32 id;
- int i;
+ int i, event_index;
/* Is there notification on this handle? */
data = talloc( mem_ctx, msg_group->num_msgs*sizeof(SPOOL_NOTIFY_INFO_DATA) );
ZERO_STRUCTP(data);
+ event_index = 0;
+
/* build the array of change notifications */
- for ( i=0; i<msg_group->num_msgs; i++ )
- {
+ sending_msg_count = 0;
+
+ for ( i=0; i<msg_group->num_msgs; i++ ) {
SPOOLSS_NOTIFY_MSG *msg = &messages[i];
- /* Are we monitoring this event? */
+ /* Are we monitoring this event? */
- if (!is_monitoring_event(p, msg->type, msg->field))
- continue;
+ if (!is_monitoring_event(p, msg->type, msg->field))
+ continue;
+ sending_msg_count++;
- DEBUG(10,("process_notify2_message: Sending message type [%x] field [%x] for printer [%s]\n",
- msg->type, msg->field, p->dev.handlename));
+
+ DEBUG(10,("process_notify2_message: Sending message type [%x] field [%x] for printer [%s]\n",
+ msg->type, msg->field, p->dev.handlename));
- /*
- * if the is a printer notification handle and not a job notification
- * type, then set the id to 0. Other wise just use what was specified
- * in the message.
- *
- * When registering change notification on a print server handle
- * we always need to send back the id (snum) matching the printer
- * for which the change took place. For change notify registered
- * on a printer handle, this does not matter and the id should be 0.
- *
- * --jerry
- */
+ /*
+ * if the is a printer notification handle and not a job notification
+ * type, then set the id to 0. Other wise just use what was specified
+ * in the message.
+ *
+ * When registering change notification on a print server handle
+ * we always need to send back the id (snum) matching the printer
+ * for which the change took place. For change notify registered
+ * on a printer handle, this does not matter and the id should be 0.
+ *
+ * --jerry
+ */
- if ( ( p->printer_type == PRINTER_HANDLE_IS_PRINTER ) && ( msg->type == PRINTER_NOTIFY_TYPE ) )
- id = 0;
- else
- id = msg->id;
+ if ( ( p->printer_type == PRINTER_HANDLE_IS_PRINTER ) && ( msg->type == PRINTER_NOTIFY_TYPE ) )
+ id = 0;
+ else
+ id = msg->id;
- /* Convert unix jobid to smb jobid */
+ /* Convert unix jobid to smb jobid */
- if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID)
- {
- id = sysjob_to_jobid(msg->id);
+ if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) {
+ id = sysjob_to_jobid(msg->id);
- if (id == -1) {
- DEBUG(3, ("no such unix jobid %d\n", msg->id));
- goto done;
+ if (id == -1) {
+ DEBUG(3, ("no such unix jobid %d\n", msg->id));
+ goto done;
+ }
}
- }
construct_info_data( &data[data_len], msg->type, msg->field, id );
- switch(msg->type) {
- case PRINTER_NOTIFY_TYPE:
- if ( !printer_notify_table[msg->field].fn )
- goto done;
+ switch(msg->type) {
+ case PRINTER_NOTIFY_TYPE:
+ if ( printer_notify_table[msg->field].fn )
printer_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
-
- break;
+ break;
- case JOB_NOTIFY_TYPE:
- if ( !job_notify_table[msg->field].fn )
- goto done;
+ case JOB_NOTIFY_TYPE:
+ if ( job_notify_table[msg->field].fn )
job_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
-
break;
default:
data_len++;
}
- cli_spoolss_rrpcn( ¬ify_cli, mem_ctx, &p->notify.client_hnd,
- data_len, data, p->notify.change, 0 );
+ if ( sending_msg_count ) {
+ cli_spoolss_rrpcn( ¬ify_cli, mem_ctx, &p->notify.client_hnd,
+ data_len, data, p->notify.change, 0 );
+ }
}
done:
/***********************************************************************
**********************************************************************/
-static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, void *buf, size_t len )
+static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, void *buf, size_t len )
{
- int offset = 0;
+ uint32 tv_sec, tv_usec;
+ size_t offset = 0;
/* Unpack message */
offset += tdb_unpack((char *)buf + offset, len - offset, "f",
msg->printer);
- offset += tdb_unpack((char *)buf + offset, len - offset, "ddddd",
- &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags);
+ offset += tdb_unpack((char *)buf + offset, len - offset, "ddddddd",
+ &tv_sec, &tv_usec,
+ &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags);
if (msg->len == 0)
tdb_unpack((char *)buf + offset, len - offset, "dd",
tdb_unpack((char *)buf + offset, len - offset, "B",
&msg->len, &msg->notify.data);
- DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message, type %d, field 0x%02x, flags 0x%04x\n",
- msg->type, msg->field, msg->flags));
+ DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message for printer %s, jobid %u type %d, field 0x%02x, flags 0x%04x\n",
+ msg->printer, (unsigned int)msg->id, msg->type, msg->field, msg->flags));
+
+ tv->tv_sec = tv_sec;
+ tv->tv_usec = tv_usec;
if (msg->len == 0)
DEBUG(3, ("notify2_unpack_msg: value1 = %d, value2 = %d\n", msg->notify.value[0],
return True;
}
+/* ENUMJOB last timestamp list. */
+struct ejts_list {
+ struct ejts_list *next, *prev;
+ char *printer_name;
+ struct timeval tv;
+};
+
+static struct ejts_list *ejts_head;
+
+static struct ejts_list *find_enumjobs_timestamp(const char *printer_name)
+{
+ struct ejts_list *ejtsl;
+
+ for( ejtsl = ejts_head; ejtsl; ejtsl = ejtsl->next)
+ if (strequal(ejtsl->printer_name, printer_name))
+ return ejtsl;
+ return NULL;
+}
+
+static void set_enumjobs_timestamp(int snum)
+{
+ const char *printer_name = lp_const_servicename(snum);
+ struct ejts_list *ejtsl = find_enumjobs_timestamp(printer_name);
+
+ if (!ejtsl) {
+ ejtsl = (struct ejts_list *)malloc(sizeof(struct ejts_list));
+ if (!ejtsl)
+ return;
+ ejtsl->printer_name = strdup(printer_name);
+ if (!ejtsl->printer_name) {
+ SAFE_FREE(ejtsl);
+ return;
+ }
+ DLIST_ADD(ejts_head, ejtsl);
+ }
+
+ gettimeofday(&ejtsl->tv, NULL);
+}
+
+static int timeval_diff(struct timeval *tv1, struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec)
+ return 1;
+ if (tv1->tv_sec < tv2->tv_sec)
+ return -1;
+ if (tv1->tv_usec > tv2->tv_usec)
+ return 1;
+ if (tv1->tv_usec < tv2->tv_usec)
+ return -1;
+ return 0;
+}
+
/********************************************************************
Receive a notify2 message list
********************************************************************/
msg_count = IVAL(buf, 0);
msg_ptr = buf + 4;
- DEBUG(5, ("receive_notify2_message_list: got %d messages in list\n", msg_count));
+ DEBUG(5, ("receive_notify2_message_list: got %lu messages in list\n", (unsigned long)msg_count));
if (msg_count == 0) {
DEBUG(0,("receive_notify2_message_list: bad message format (msg_count == 0) !\n"));
* call. Therefore messages are grouped according to printer handle.
*/
- for ( i=0; i<msg_count; i++ )
- {
+ for ( i=0; i<msg_count; i++ ) {
+ struct timeval msg_tv;
+
if (msg_ptr + 4 - buf > len) {
DEBUG(0,("receive_notify2_message_list: bad message format (len > buf_size) !\n"));
return;
/* unpack messages */
ZERO_STRUCT( notify );
- notify2_unpack_msg( ¬ify, msg_ptr, msg_len );
+ notify2_unpack_msg( ¬ify, &msg_tv, msg_ptr, msg_len );
msg_ptr += msg_len;
+ /* See if it is still relevent. */
+ if (notify.type == JOB_NOTIFY_TYPE) {
+ BOOL status_is_deleting = False;
+
+ if (notify.field == JOB_NOTIFY_STATUS && (notify.notify.value[0] & (JOB_STATUS_DELETING|JOB_STATUS_DELETED)))
+ status_is_deleting = True;
+
+ if (!status_is_deleting) {
+ struct ejts_list *ejtsl = find_enumjobs_timestamp(notify.printer);
+
+ if (ejtsl && (timeval_diff(&ejtsl->tv, &msg_tv) > 0)) {
+
+ DEBUG(10, ("receive_notify2_message_list: enumjobs ts = %u, %u, msg ts = %u, %u discarding\n",
+ (unsigned int)ejtsl->tv.tv_sec, (unsigned int)ejtsl->tv.tv_usec,
+ (unsigned int)msg_tv.tv_sec, (unsigned int)msg_tv.tv_usec ));
+
+ /* Message no longer relevent. Ignore it. */
+ if ( notify.len != 0 )
+ SAFE_FREE( notify.notify.data );
+ continue;
+ }
+ }
+ }
/* add to correct list in container */
notify_msg_ctr_addmsg( &messages, ¬ify );
/**********************************************************************
callback to receive a MSG_PRINTER_DRVUPGRADE message and interate
- over all printers, upgrading ones as neessary
+ over all printers, upgrading ones as necessary
**********************************************************************/
void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
WERROR result;
NT_PRINTER_INFO_LEVEL *printer = NULL;
- result = get_a_printer(&printer, 2, lp_servicename(snum));
+ result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(result))
continue;
/* all done */
}
+/********************************************************************
+ Update the cache for all printq's with a registered client
+ connection
+ ********************************************************************/
+
+void update_monitored_printq_cache( void )
+{
+ Printer_entry *printer = printers_list;
+ int snum;
+
+ /* loop through all printers and update the cache where
+ client_connected == True */
+ while ( printer )
+ {
+ if ( (printer->printer_type == PRINTER_HANDLE_IS_PRINTER)
+ && printer->notify.client_connected )
+ {
+ snum = print_queue_snum(printer->dev.handlename);
+ print_queue_status( snum, NULL, NULL );
+ }
+
+ printer = printer->next;
+ }
+
+ return;
+}
/********************************************************************
Send a message to ourself about new driver being installed
so we can upgrade the information for each printer bound to this
WERROR result;
NT_PRINTER_INFO_LEVEL *printer = NULL;
- result = get_a_printer( &printer, 2, lp_servicename(snum) );
+ result = get_a_printer( NULL, &printer, 2, lp_const_servicename(snum) );
if ( !W_ERROR_IS_OK(result) )
continue;
DEBUG(5,("reset_all_printerdata: Error resetting printer data for printer [%s], driver [%s]!\n",
printer->info_2->printername, printer->info_2->drivername));
}
+
+ result = mod_a_printer( *printer, 2 );
+ if ( !W_ERROR_IS_OK(result) ) {
+ DEBUG(3,("reset_all_printerdata: mod_a_printer() failed! (%s)\n",
+ get_dos_error_msg(result)));
+ }
}
free_a_printer( &printer, 2 );
/* if the user is not root and not a printer admin, then fail */
if ( user.uid != 0
- && !user_in_list(uidtoname(user.uid), lp_printer_admin(snum)) )
+ && !user_in_list(uidtoname(user.uid), lp_printer_admin(snum), user.groups, user.ngroups) )
{
close_printer_handle(p, handle);
return WERR_ACCESS_DENIED;
/* NT doesn't let us connect to a printer if the connecting user
doesn't have print permission. */
- if (!get_printer_snum(p, handle, &snum))
+ if (!get_printer_snum(p, handle, &snum)) {
+ close_printer_handle(p, handle);
return WERR_BADFID;
+ }
se_map_standard(&printer_default->access_required, &printer_std_mapping);
/* check smb.conf parameters and the the sec_desc */
- if (!user_ok(uidtoname(user.uid), snum) || !print_access_check(&user, snum, printer_default->access_required)) {
+ if (!user_ok(uidtoname(user.uid), snum, user.groups, user.ngroups) || !print_access_check(&user, snum, printer_default->access_required)) {
DEBUG(3, ("access DENIED for printer open\n"));
close_printer_handle(p, handle);
return WERR_ACCESS_DENIED;
&Printer->nt_devmode );
}
+ /* HACK ALERT!!! Sleep for 1/3 of a second to try trigger a LAN/WAN
+ optimization in Windows 2000 clients --jerry */
+
+ if ( (printer_default->access_required == PRINTER_ACCESS_ADMINISTER)
+ && (RA_WIN2K == get_remote_arch()) )
+ {
+ DEBUG(10,("_spoolss_open_printer_ex: Enabling LAN/WAN hack for Win2k clients.\n"));
+ usleep( 500000 );
+ }
+
return WERR_OK;
}
return result;
}
-BOOL convert_devicemode(char *printername, const DEVICEMODE *devmode,
+BOOL convert_devicemode(const char *printername, const DEVICEMODE *devmode,
NT_DEVICEMODE **pp_nt_devmode)
{
NT_DEVICEMODE *nt_devmode = *pp_nt_devmode;
goto done;
}
}
+ /* otherwise it was a failure */
+ else {
+ status = WERR_UNKNOWN_PRINTER_DRIVER;
+ goto done;
+ }
+
}
if (printer_driver_in_use(info.info_3)) {
***************************************************************************/
static WERROR get_printer_dataex( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printer,
- char *key, char *value, uint32 *type, uint8 **data,
+ const char *key, const char *value, uint32 *type, uint8 **data,
uint32 *needed, uint32 in_size )
{
REGISTRY_VALUE *val;
if ( in_size ) {
data_len = (size > in_size) ? in_size : size*sizeof(uint8);
- if ( (*data = (uint8 *)talloc_memdup(ctx, regval_data_p(val), data_len)) == NULL )
- return WERR_NOMEM;
+
+ /* special case for 0 length values */
+ if ( data_len ) {
+ if ( (*data = (uint8 *)talloc_memdup(ctx, regval_data_p(val), data_len)) == NULL )
+ return WERR_NOMEM;
+ }
+ else {
+ if ( (*data = (uint8 *)talloc_zero(ctx, in_size)) == NULL )
+ return WERR_NOMEM;
+ }
}
else
*data = NULL;
Internal routine for removing printerdata
***************************************************************************/
-static WERROR delete_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, char *key, char *value )
+static WERROR delete_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value )
{
- delete_printer_data( printer->info_2, key, value );
-
- return mod_a_printer(*printer, 2);
+ return delete_printer_data( printer->info_2, key, value );
}
/****************************************************************************
Internal routine for storing printerdata
***************************************************************************/
-static WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, char *key, char *value,
+static WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value,
uint32 type, uint8 *data, int real_len )
{
delete_printer_data( printer->info_2, key, value );
- add_printer_data( printer->info_2, key, value, type, data, real_len );
-
- return mod_a_printer(*printer, 2);
+ return add_printer_data( printer->info_2, key, value, type, data, real_len );
}
/********************************************************************
DEBUG(8,("getprinterdata_printer_server:%s\n", value));
- if (!strcmp(value, "W3SvcInstalled")) {
+ if (!StrCaseCmp(value, "W3SvcInstalled")) {
*type = 0x4;
if((*data = (uint8 *)talloc_zero(ctx, 4*sizeof(uint8) )) == NULL)
return WERR_NOMEM;
return WERR_OK;
}
- if (!strcmp(value, "BeepEnabled")) {
+ if (!StrCaseCmp(value, "BeepEnabled")) {
*type = 0x4;
if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
return WERR_NOMEM;
return WERR_OK;
}
- if (!strcmp(value, "EventLog")) {
+ if (!StrCaseCmp(value, "EventLog")) {
*type = 0x4;
if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
return WERR_NOMEM;
return WERR_OK;
}
- if (!strcmp(value, "NetPopup")) {
+ if (!StrCaseCmp(value, "NetPopup")) {
*type = 0x4;
if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
return WERR_NOMEM;
return WERR_OK;
}
- if (!strcmp(value, "MajorVersion")) {
+ if (!StrCaseCmp(value, "MajorVersion")) {
*type = 0x4;
if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
return WERR_NOMEM;
-#ifndef EMULATE_WIN2K_HACK /* JERRY */
- SIVAL(*data, 0, 2);
-#else
- SIVAL(*data, 0, 3);
-#endif
+
+ /* Windows NT 4.0 seems to not allow uploading of drivers
+ to a server that reports 0x3 as the MajorVersion.
+ need to investigate more how Win2k gets around this .
+ -- jerry */
+
+ if ( RA_WINNT == get_remote_arch() )
+ SIVAL(*data, 0, 2);
+ else
+ SIVAL(*data, 0, 3);
+
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "MinorVersion")) {
+ *type = 0x4;
+ if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
+ return WERR_NOMEM;
+ SIVAL(*data, 0, 0);
*needed = 0x4;
return WERR_OK;
}
- if (!strcmp(value, "DefaultSpoolDirectory")) {
- fstring string;
+ /* REG_BINARY
+ * uint32 size = 0x114
+ * uint32 major = 5
+ * uint32 minor = [0|1]
+ * uint32 build = [2195|2600]
+ * extra unicode string = e.g. "Service Pack 3"
+ */
+ if (!StrCaseCmp(value, "OSVersion")) {
+ *type = 0x3;
+ *needed = 0x114;
+
+ if((*data = (uint8 *)talloc(ctx, (*needed)*sizeof(uint8) )) == NULL)
+ return WERR_NOMEM;
+ ZERO_STRUCTP( *data );
+
+ SIVAL(*data, 0, *needed); /* size */
+ SIVAL(*data, 4, 5); /* Windows 2000 == 5.0 */
+ SIVAL(*data, 8, 0);
+ SIVAL(*data, 12, 2195); /* build */
+
+ /* leave extra string empty */
+
+ return WERR_OK;
+ }
+
- fstrcpy(string, string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
+ if (!StrCaseCmp(value, "DefaultSpoolDirectory")) {
+ const char *string="C:\\PRINTERS";
*type = 0x1;
*needed = 2*(strlen(string)+1);
if((*data = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL)
return WERR_OK;
}
- if (!strcmp(value, "Architecture")) {
- pstring string="Windows NT x86";
+ if (!StrCaseCmp(value, "Architecture")) {
+ const char *string="Windows NT x86";
*type = 0x1;
*needed = 2*(strlen(string)+1);
if((*data = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL)
}
return WERR_OK;
}
-
- return WERR_INVALID_PARAM;
+
+ if (!StrCaseCmp(value, "DsPresent")) {
+ *type = 0x4;
+ if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
+ return WERR_NOMEM;
+ SIVAL(*data, 0, 0x01);
+ *needed = 0x4;
+ return WERR_OK;
+ }
+
+ if (!StrCaseCmp(value, "DNSMachineName")) {
+ pstring hostname;
+
+ if (!get_myfullname(hostname))
+ return WERR_BADFILE;
+ *type = 0x1;
+ *needed = 2*(strlen(hostname)+1);
+ if((*data = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL)
+ return WERR_NOMEM;
+ memset(*data, 0, (*needed > in_size) ? *needed:in_size);
+ for (i=0; i<strlen(hostname); i++) {
+ (*data)[2*i]=hostname[i];
+ (*data)[2*i+1]='\0';
+ }
+ return WERR_OK;
+ }
+
+
+ return WERR_BADFILE;
}
/********************************************************************
goto done;
}
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
if ( !W_ERROR_IS_OK(status) )
goto done;
-
- status = get_printer_dataex( p->mem_ctx, printer, SPOOL_PRINTERDATA_KEY, value, type, data, needed, *out_size );
+
+ /* XP sends this and wants to change id value from the PRINTER_INFO_0 */
+
+ if ( strequal(value, "ChangeId") ) {
+ *type = REG_DWORD;
+ *needed = sizeof(uint32);
+ if ( (*data = (uint8*)talloc(p->mem_ctx, sizeof(uint32))) == NULL) {
+ status = WERR_NOMEM;
+ goto done;
+ }
+ SIVAL( *data, 0, printer->info_2->changeid );
+ status = WERR_OK;
+ }
+ else
+ status = get_printer_dataex( p->mem_ctx, printer, SPOOL_PRINTERDATA_KEY, value, type, data, needed, *out_size );
}
if (*needed > *out_size)
done:
if ( !W_ERROR_IS_OK(status) )
{
- DEBUG(5, ("error: allocating %d\n", *out_size));
+ DEBUG(5, ("error %d: allocating %d\n", W_ERROR_V(status),*out_size));
/* reply this param doesn't exist */
Connect to the client machine.
**********************************************************/
-static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_machine)
+static BOOL spoolss_connect_to_client(struct cli_state *the_cli,
+ struct in_addr *client_ip, const char *remote_machine)
{
- extern pstring global_myname;
-
ZERO_STRUCTP(the_cli);
+
if(cli_initialise(the_cli) == NULL) {
- DEBUG(0,("connect_to_client: unable to initialize client connection.\n"));
+ DEBUG(0,("spoolss_connect_to_client: unable to initialize client connection.\n"));
return False;
}
+
+ if ( is_zero_ip(*client_ip) ) {
+ if(!resolve_name( remote_machine, &the_cli->dest_ip, 0x20)) {
+ DEBUG(0,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine));
+ cli_shutdown(the_cli);
+ return False;
+ }
- if(!resolve_name( remote_machine, &the_cli->dest_ip, 0x20)) {
- DEBUG(0,("connect_to_client: Can't resolve address for %s\n", remote_machine));
- cli_shutdown(the_cli);
- return False;
+ if (ismyip(the_cli->dest_ip)) {
+ DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
+ cli_shutdown(the_cli);
+ return False;
+ }
}
-
- if (ismyip(the_cli->dest_ip)) {
- DEBUG(0,("connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
- cli_shutdown(the_cli);
- return False;
+ else {
+ the_cli->dest_ip.s_addr = client_ip->s_addr;
+ DEBUG(5,("spoolss_connect_to_client: Using address %s (no name resolution necessary)\n",
+ inet_ntoa(*client_ip) ));
}
if (!cli_connect(the_cli, remote_machine, &the_cli->dest_ip)) {
- DEBUG(0,("connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+ DEBUG(0,("spoolss_connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
cli_shutdown(the_cli);
return False;
}
- if (!attempt_netbios_session_request(the_cli, global_myname, remote_machine, &the_cli->dest_ip)) {
- DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request.\n",
+ if (!attempt_netbios_session_request(the_cli, global_myname(), remote_machine, &the_cli->dest_ip)) {
+ DEBUG(0,("spoolss_connect_to_client: machine %s rejected the NetBIOS session request.\n",
remote_machine));
cli_shutdown(the_cli);
return False;
the_cli->protocol = PROTOCOL_NT1;
if (!cli_negprot(the_cli)) {
- DEBUG(0,("connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+ DEBUG(0,("spoolss_connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
cli_shutdown(the_cli);
return False;
}
if (the_cli->protocol != PROTOCOL_NT1) {
- DEBUG(0,("connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
+ DEBUG(0,("spoolss_connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
cli_shutdown(the_cli);
return False;
}
*/
if (!cli_session_setup(the_cli, "", "", 0, "", 0, "")) {
- DEBUG(0,("connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+ DEBUG(0,("spoolss_connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
cli_shutdown(the_cli);
return False;
}
if (!(the_cli->sec_mode & 1)) {
- DEBUG(0,("connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
+ DEBUG(0,("spoolss_connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
cli_shutdown(the_cli);
return False;
}
if (!cli_send_tconX(the_cli, "IPC$", "IPC", "", 1)) {
- DEBUG(0,("connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+ DEBUG(0,("spoolss_connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
cli_shutdown(the_cli);
return False;
}
* Now start the NT Domain stuff :-).
*/
- if(cli_nt_session_open(the_cli, PIPE_SPOOLSS) == False) {
- DEBUG(0,("connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli)));
+ if(cli_nt_session_open(the_cli, PI_SPOOLSS) == False) {
+ DEBUG(0,("spoolss_connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli)));
cli_nt_session_close(the_cli);
cli_ulogoff(the_cli);
cli_shutdown(the_cli);
Connect to the client.
****************************************************************************/
-static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uint32 type, POLICY_HND *handle)
+static BOOL srv_spoolss_replyopenprinter(int snum, const char *printer,
+ uint32 localprinter, uint32 type,
+ POLICY_HND *handle, struct in_addr *client_ip)
{
WERROR result;
/*
* If it's the first connection, contact the client
- * and connect to the IPC$ share anonumously
+ * and connect to the IPC$ share anonymously
*/
if (smb_connections==0) {
fstring unix_printer;
fstrcpy(unix_printer, printer+2); /* the +2 is to strip the leading 2 backslashs */
- if(!spoolss_connect_to_client(¬ify_cli, unix_printer))
+ if(!spoolss_connect_to_client(¬ify_cli, client_ip, unix_printer))
return False;
message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message_list);
register_message_flags( True, FLAG_MSG_PRINTING );
}
+ /*
+ * Tell the specific printing tdb we want messages for this printer
+ * by registering our PID.
+ */
+
+ if (!print_notify_register_pid(snum))
+ DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", printer ));
+
smb_connections++;
result = cli_spoolss_reply_open_printer(¬ify_cli, notify_cli.mem_ctx, printer, localprinter,
uint32 options = q_u->options;
UNISTR2 *localmachine = &q_u->localmachine;
uint32 printerlocal = q_u->printerlocal;
+ int snum = -1;
SPOOL_NOTIFY_OPTION *option = q_u->option;
+ struct in_addr client_ip;
/* store the notify value in the printer struct */
/* Connect to the client machine and send a ReplyOpenPrinter */
- if(!srv_spoolss_replyopenprinter(Printer->notify.localmachine,
+ if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
+ snum = -1;
+ else if ( (Printer->printer_type == PRINTER_HANDLE_IS_PRINTER) &&
+ !get_printer_snum(p, handle, &snum) )
+ return WERR_BADFID;
+
+ client_ip.s_addr = inet_addr(p->conn->client_address);
+
+ if(!srv_spoolss_replyopenprinter(snum, Printer->notify.localmachine,
Printer->notify.printerlocal, 1,
- &Printer->notify.client_hnd))
+ &Printer->notify.client_hnd, &client_ip))
return WERR_SERVER_UNAVAILABLE;
Printer->notify.client_connected=True;
* Now we're returning job status codes we just return a "" here. JRA.
*/
- char *p = "";
+ const char *p = "";
pstring temp;
uint32 len;
{
uint16 type;
uint16 field;
- char *name;
+ const char *name;
uint32 size;
void (*fn) (int snum, SPOOL_NOTIFY_INFO_DATA *data,
print_queue_struct *queue,
whether the notification data is a pointer to a variable sized
buffer, a one value uint32 or a two value uint32. */
-struct s_notify_info_data_table notify_info_data_table[] =
+static const struct s_notify_info_data_table notify_info_data_table[] =
{
{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME, "PRINTER_NOTIFY_SERVER_NAME", NOTIFY_STRING, spoolss_notify_server_name },
{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME, "PRINTER_NOTIFY_PRINTER_NAME", NOTIFY_STRING, spoolss_notify_printer_name },
*
********************************************************************/
-static BOOL construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int
+static BOOL construct_notify_printer_info(Printer_entry *print_hnd, SPOOL_NOTIFY_INFO *info, int
snum, SPOOL_NOTIFY_OPTION_TYPE
*option_type, uint32 id,
TALLOC_CTX *mem_ctx)
(option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
option_type->count, lp_servicename(snum)));
- if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &printer, 2, lp_const_servicename(snum))))
return False;
- for(field_num=0; field_num<option_type->count; field_num++)
- {
+ for(field_num=0; field_num<option_type->count; field_num++) {
field = option_type->fields[field_num];
DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field));
if (!search_notify(type, field, &j) )
continue;
- if((tid=(SPOOL_NOTIFY_INFO_DATA *)Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL)
- {
+ if((tid=(SPOOL_NOTIFY_INFO_DATA *)Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) {
DEBUG(2,("construct_notify_printer_info: failed to enlarge buffer info->data!\n"));
return False;
- }
- else
+ } else
info->data = tid;
current_data = &info->data[info->count];
for (snum=0; snum<n_services; snum++)
{
if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
- construct_notify_printer_info ( info, snum, option_type, snum, mem_ctx );
+ construct_notify_printer_info ( Printer, info, snum, option_type, snum, mem_ctx );
}
}
switch ( option_type->type ) {
case PRINTER_NOTIFY_TYPE:
- if(construct_notify_printer_info(info, snum,
+ if(construct_notify_printer_info(Printer, info, snum,
option_type, id,
mem_ctx))
id--;
count = print_queue_status(snum, &queue, &status);
- if (!W_ERROR_IS_OK(get_a_printer(&printer, 2,
- lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum))))
goto done;
for (j=0; j<count; j++) {
/* We need to keep track of the change value to send back in
RRPCN replies otherwise our updates are ignored. */
+ Printer->notify.fnpcn = True;
+
if (Printer->notify.client_connected) {
DEBUG(10,("_spoolss_rfnpcnex: Saving change value in request [%x]\n", q_u->change));
Printer->notify.change = q_u->change;
break;
}
- done:
+ Printer->notify.fnpcn = False;
+
+done:
return result;
}
* fill a printer_info_0 struct
********************************************************************/
-static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum)
+static BOOL construct_printer_info_0(Printer_entry *print_hnd, PRINTER_INFO_0 *printer, int snum)
{
pstring chaine;
int count;
time_t setuptime;
print_status_struct status;
- if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
return False;
count = print_queue_length(snum, &status);
printer->global_counter = global_counter;
printer->total_pages = 0;
-#ifndef EMULATE_WIN2K_HACK /* JERRY */
- printer->major_version = 0x0004; /* NT 4 */
- printer->build_version = 0x0565; /* build 1381 */
-#else
+
+ /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */
printer->major_version = 0x0005; /* NT 5 */
printer->build_version = 0x0893; /* build 2195 */
-#endif
+
printer->unknown7 = 0x1;
printer->unknown8 = 0x0;
printer->unknown9 = 0x0;
* construct_printer_info_1
* fill a printer_info_1 struct
********************************************************************/
-static BOOL construct_printer_info_1(uint32 flags, PRINTER_INFO_1 *printer, int snum)
+static BOOL construct_printer_info_1(Printer_entry *print_hnd, uint32 flags, PRINTER_INFO_1 *printer, int snum)
{
pstring chaine;
pstring chaine2;
NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
- if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
return False;
printer->flags=flags;
DEBUGADD(8,("getting printer characteristics\n"));
- if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
return NULL;
if ( !printer->info_2->devmode ) {
* fill a printer_info_2 struct
********************************************************************/
-static BOOL construct_printer_info_2(PRINTER_INFO_2 *printer, int snum)
+static BOOL construct_printer_info_2(Printer_entry *print_hnd, PRINTER_INFO_2 *printer, int snum)
{
int count;
NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
print_status_struct status;
- if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
return False;
count = print_queue_length(snum, &status);
* fill a printer_info_3 struct
********************************************************************/
-static BOOL construct_printer_info_3(PRINTER_INFO_3 **pp_printer, int snum)
+static BOOL construct_printer_info_3(Printer_entry *print_hnd, PRINTER_INFO_3 **pp_printer, int snum)
{
NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
PRINTER_INFO_3 *printer = NULL;
- if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
return False;
*pp_printer = NULL;
* fill a printer_info_4 struct
********************************************************************/
-static BOOL construct_printer_info_4(PRINTER_INFO_4 *printer, int snum)
+static BOOL construct_printer_info_4(Printer_entry *print_hnd, PRINTER_INFO_4 *printer, int snum)
{
NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
- if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
return False;
init_unistr(&printer->printername, ntprinter->info_2->printername); /* printername*/
* fill a printer_info_5 struct
********************************************************************/
-static BOOL construct_printer_info_5(PRINTER_INFO_5 *printer, int snum)
+static BOOL construct_printer_info_5(Printer_entry *print_hnd, PRINTER_INFO_5 *printer, int snum)
{
NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
- if (!W_ERROR_IS_OK(get_a_printer(&ntprinter, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
return False;
- init_unistr(&printer->printername, ntprinter->info_2->printername); /* printername*/
- init_unistr(&printer->portname, ntprinter->info_2->portname); /* portname */
+ init_unistr(&printer->printername, ntprinter->info_2->printername);
+ init_unistr(&printer->portname, ntprinter->info_2->portname);
printer->attributes = ntprinter->info_2->attributes;
- printer->device_not_selected_timeout = 0x3a98;
- printer->transmission_retry_timeout = 0xafc8;
+
+ /* these two are not used by NT+ according to MSDN */
+
+ printer->device_not_selected_timeout = 0x0; /* have seen 0x3a98 */
+ printer->transmission_retry_timeout = 0x0; /* have seen 0xafc8 */
free_a_printer(&ntprinter, 2);
+
+ return True;
+}
+
+/********************************************************************
+ * construct_printer_info_7
+ * fill a printer_info_7 struct
+ ********************************************************************/
+
+static BOOL construct_printer_info_7(Printer_entry *print_hnd, PRINTER_INFO_7 *printer, int snum)
+{
+ char *guid_str = NULL;
+ GUID guid;
+
+ if (is_printer_published(print_hnd, snum, &guid)) {
+ asprintf(&guid_str, "{%s}", smb_uuid_string_static(guid));
+ strupper_m(guid_str);
+ init_unistr(&printer->guid, guid_str);
+ printer->action = SPOOL_DS_PUBLISH;
+ } else {
+ init_unistr(&printer->guid, "");
+ printer->action = SPOOL_DS_UNPUBLISH;
+ }
+
return True;
}
if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
- if (construct_printer_info_1(flags, ¤t_prt, snum)) {
+ if (construct_printer_info_1(NULL, flags, ¤t_prt, snum)) {
if((tp=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_1))) == NULL) {
DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
SAFE_FREE(printers);
if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
- if (construct_printer_info_2(¤t_prt, snum)) {
+ if (construct_printer_info_2(NULL, ¤t_prt, snum)) {
if((tp=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_2))) == NULL) {
DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
SAFE_FREE(printers);
*/
unistr2_to_ascii(name, servername, sizeof(name)-1);
- strupper(name);
+ strupper_m(name);
switch (level) {
case 1:
/****************************************************************************
****************************************************************************/
-static WERROR getprinter_level_0(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_0(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
{
PRINTER_INFO_0 *printer=NULL;
if((printer=(PRINTER_INFO_0*)malloc(sizeof(PRINTER_INFO_0))) == NULL)
return WERR_NOMEM;
- construct_printer_info_0(printer, snum);
+ construct_printer_info_0(print_hnd, printer, snum);
/* check the required size. */
*needed += spoolss_size_printer_info_0(printer);
/****************************************************************************
****************************************************************************/
-static WERROR getprinter_level_1(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_1(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
{
PRINTER_INFO_1 *printer=NULL;
if((printer=(PRINTER_INFO_1*)malloc(sizeof(PRINTER_INFO_1))) == NULL)
return WERR_NOMEM;
- construct_printer_info_1(PRINTER_ENUM_ICON8, printer, snum);
+ construct_printer_info_1(print_hnd, PRINTER_ENUM_ICON8, printer, snum);
/* check the required size. */
*needed += spoolss_size_printer_info_1(printer);
/****************************************************************************
****************************************************************************/
-static WERROR getprinter_level_2(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_2(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
{
PRINTER_INFO_2 *printer=NULL;
if((printer=(PRINTER_INFO_2*)malloc(sizeof(PRINTER_INFO_2)))==NULL)
return WERR_NOMEM;
- construct_printer_info_2(printer, snum);
+ construct_printer_info_2(print_hnd, printer, snum);
/* check the required size. */
*needed += spoolss_size_printer_info_2(printer);
/****************************************************************************
****************************************************************************/
-static WERROR getprinter_level_3(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_3(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
{
PRINTER_INFO_3 *printer=NULL;
- if (!construct_printer_info_3(&printer, snum))
+ if (!construct_printer_info_3(print_hnd, &printer, snum))
return WERR_NOMEM;
/* check the required size. */
/****************************************************************************
****************************************************************************/
-static WERROR getprinter_level_4(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_4(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
{
PRINTER_INFO_4 *printer=NULL;
if((printer=(PRINTER_INFO_4*)malloc(sizeof(PRINTER_INFO_4)))==NULL)
return WERR_NOMEM;
- if (!construct_printer_info_4(printer, snum))
+ if (!construct_printer_info_4(print_hnd, printer, snum))
return WERR_NOMEM;
/* check the required size. */
/****************************************************************************
****************************************************************************/
-static WERROR getprinter_level_5(int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getprinter_level_5(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
{
PRINTER_INFO_5 *printer=NULL;
if((printer=(PRINTER_INFO_5*)malloc(sizeof(PRINTER_INFO_5)))==NULL)
return WERR_NOMEM;
- if (!construct_printer_info_5(printer, snum))
+ if (!construct_printer_info_5(print_hnd, printer, snum))
return WERR_NOMEM;
/* check the required size. */
return WERR_OK;
}
+static WERROR getprinter_level_7(Printer_entry *print_hnd, int snum, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+{
+ PRINTER_INFO_7 *printer=NULL;
+
+ if((printer=(PRINTER_INFO_7*)malloc(sizeof(PRINTER_INFO_7)))==NULL)
+ return WERR_NOMEM;
+
+ if (!construct_printer_info_7(print_hnd, printer, snum))
+ return WERR_NOMEM;
+
+ /* check the required size. */
+ *needed += spoolss_size_printer_info_7(printer);
+
+ if (!alloc_buffer_size(buffer, *needed)) {
+ free_printer_info_7(printer);
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ /* fill the buffer with the structures */
+ smb_io_printer_info_7("", buffer, printer, 0);
+
+ /* clear memory */
+ free_printer_info_7(printer);
+
+ if (*needed > offered) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ return WERR_OK;
+}
+
/****************************************************************************
****************************************************************************/
NEW_BUFFER *buffer = NULL;
uint32 offered = q_u->offered;
uint32 *needed = &r_u->needed;
+ Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
int snum;
switch (level) {
case 0:
- return getprinter_level_0(snum, buffer, offered, needed);
+ return getprinter_level_0(Printer, snum, buffer, offered, needed);
case 1:
- return getprinter_level_1(snum, buffer, offered, needed);
+ return getprinter_level_1(Printer, snum, buffer, offered, needed);
case 2:
- return getprinter_level_2(snum, buffer, offered, needed);
+ return getprinter_level_2(Printer, snum, buffer, offered, needed);
case 3:
- return getprinter_level_3(snum, buffer, offered, needed);
+ return getprinter_level_3(Printer, snum, buffer, offered, needed);
case 4:
- return getprinter_level_4(snum, buffer, offered, needed);
+ return getprinter_level_4(Printer, snum, buffer, offered, needed);
case 5:
- return getprinter_level_5(snum, buffer, offered, needed);
+ return getprinter_level_5(Printer, snum, buffer, offered, needed);
+ case 7:
+ return getprinter_level_7(Printer, snum, buffer, offered, needed);
}
return WERR_UNKNOWN_LEVEL;
}
ZERO_STRUCT(driver);
- if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
return WERR_INVALID_PRINTER_NAME;
if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version)))
ZERO_STRUCT(printer);
ZERO_STRUCT(driver);
- if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
return WERR_INVALID_PRINTER_NAME;
if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version)))
* convert an array of ascii string to a UNICODE string
********************************************************************/
-static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, char *servername)
+static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, const char *servername)
{
int i=0;
int j=0;
- char *v;
+ const char *v;
pstring line;
uint16 *tuary;
else
pstrcpy( line, v );
- DEBUGADD(6,("%d:%s:%d\n", i, line, strlen(line)));
+ DEBUGADD(6,("%d:%s:%lu\n", i, line, (unsigned long)strlen(line)));
+
+ /* add one extra unit16 for the second terminating NULL */
- if ( (tuary=Realloc(*uni_array, (j+strlen(line)+2)*sizeof(uint16))) == NULL ) {
+ if ( (tuary=Realloc(*uni_array, (j+1+strlen(line)+2)*sizeof(uint16))) == NULL ) {
DEBUG(2,("init_unistr_array: Realloc error\n" ));
return 0;
} else
}
if (*uni_array) {
+ /* special case for ""; we need to add both NULL's here */
+ if (!j)
+ (*uni_array)[j++]=0x0000;
(*uni_array)[j]=0x0000;
}
WERROR status;
ZERO_STRUCT(driver);
- status=get_a_printer(&printer, 2, lp_servicename(snum) );
+ status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
DEBUG(8,("construct_printer_driver_info_3: status: %s\n", dos_errstr(status)));
if (!W_ERROR_IS_OK(status))
return WERR_INVALID_PRINTER_NAME;
ZERO_STRUCT(driver);
- status=get_a_printer(&printer, 2, lp_servicename(snum) );
+ status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
DEBUG(8,("construct_printer_driver_info_6: status: %s\n", dos_errstr(status)));
fill_printer_driver_info_6(info, driver, servername);
free_a_printer(&printer,2);
+ free_a_printer_driver(driver, 3);
return WERR_OK;
}
*servermajorversion = 0;
*serverminorversion = 0;
- pstrcpy(servername, get_called_name());
+ fstrcpy(servername, get_called_name());
unistr2_to_ascii(architecture, uni_arch, sizeof(architecture)-1);
if (!get_printer_snum(p, handle, &snum))
fstrcpy(info->sharename, lp_servicename(snum));
slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
get_called_name(), info->sharename);
- info->attributes = PRINTER_ATTRIBUTE_SHARED | PRINTER_ATTRIBUTE_NETWORK;
+ info->attributes = PRINTER_ATTRIBUTE_SAMBA;
+
return True;
}
char *cmd = lp_addprinter_cmd();
char **qlines;
pstring command;
- pstring driverlocation;
int numlines;
int ret;
int fd;
fstring remote_machine = "%m";
- /* build driver path... only 9X architecture is needed for legacy reasons */
- slprintf(driverlocation, sizeof(driverlocation)-1, "\\\\%s\\print$\\WIN40\\0",
- get_called_name());
- /* change \ to \\ for the shell */
- all_string_sub(driverlocation,"\\","\\\\",sizeof(pstring));
standard_sub_basic(current_user_info.smb_name, remote_machine,sizeof(remote_machine));
slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
cmd, printer->info_2->printername, printer->info_2->sharename,
printer->info_2->portname, printer->info_2->drivername,
- printer->info_2->location, driverlocation, remote_machine);
+ printer->info_2->location, printer->info_2->comment, remote_machine);
DEBUG(10,("Running [%s]\n", command));
ret = smbrun(command, &fd);
/* Send SIGHUP to process group... is there a better way? */
kill(0, SIGHUP);
- add_all_printers();
+
+ /* reload our services immediately */
+ reload_services( False );
}
file_lines_free(qlines);
NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
WERROR result;
+ UNISTR2 buffer;
+ fstring asc_buffer;
DEBUG(8,("update_printer\n"));
result = WERR_OK;
- if (level!=2) {
- DEBUG(0,("update_printer: Send a mail to samba@samba.org\n"));
- DEBUGADD(0,("with the following message: update_printer: level!=2\n"));
- result = WERR_UNKNOWN_LEVEL;
- goto done;
- }
-
if (!Printer) {
result = WERR_BADFID;
goto done;
goto done;
}
- if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))) ||
- (!W_ERROR_IS_OK(get_a_printer(&old_printer, 2, lp_servicename(snum))))) {
+ if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum))) ||
+ (!W_ERROR_IS_OK(get_a_printer(Printer, &old_printer, 2, lp_const_servicename(snum))))) {
result = WERR_BADFID;
goto done;
}
goto done;
}
+ /* FIXME!!! If the driver has changed we really should verify that
+ it is installed before doing much else --jerry */
+
/* Check calling user has permission to update printer description */
if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
}
/* Call addprinter hook */
-
- if (*lp_addprinter_cmd()) {
+ /* Check changes to see if this is really needed */
+
+ if ( *lp_addprinter_cmd()
+ && (!strequal(printer->info_2->drivername, old_printer->info_2->drivername)
+ || !strequal(printer->info_2->comment, old_printer->info_2->comment)
+ || !strequal(printer->info_2->portname, old_printer->info_2->portname)
+ || !strequal(printer->info_2->location, old_printer->info_2->location)) )
+ {
if ( !add_printer_hook(printer) ) {
result = WERR_ACCESS_DENIED;
goto done;
}
+
+ /*
+ * make sure we actually reload the services after
+ * this as smb.conf could have a new section in it
+ * .... shouldn't .... but could
+ */
+ reload_services(False);
}
/*
notify_printer_driver(snum, printer->info_2->drivername);
}
- /* Update printer info */
- result = mod_a_printer(*printer, 2);
+ /*
+ * flag which changes actually occured. This is a small subset of
+ * all the possible changes. We also have to update things in the
+ * DsSpooler key.
+ */
- /* flag which changes actually occured. This is a small subset of
- all the possible changes */
+ if (!strequal(printer->info_2->comment, old_printer->info_2->comment)) {
+ init_unistr2( &buffer, printer->info_2->comment, strlen(printer->info_2->comment)+1 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "description",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
- if (!strequal(printer->info_2->comment, old_printer->info_2->comment))
notify_printer_comment(snum, printer->info_2->comment);
+ }
+
+ if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename)) {
+ init_unistr2( &buffer, printer->info_2->sharename, strlen(printer->info_2->sharename)+1 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "printerName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shareName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
- if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename))
notify_printer_sharename(snum, printer->info_2->sharename);
+ }
+
+ if (!strequal(printer->info_2->portname, old_printer->info_2->portname)) {
+ init_unistr2( &buffer, printer->info_2->portname, strlen(printer->info_2->portname)+1 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "portName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
- if (!strequal(printer->info_2->portname, old_printer->info_2->portname))
notify_printer_port(snum, printer->info_2->portname);
+ }
+
+ if (!strequal(printer->info_2->location, old_printer->info_2->location)) {
+ init_unistr2( &buffer, printer->info_2->location, strlen(printer->info_2->location)+1 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "location",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
- if (!strequal(printer->info_2->location, old_printer->info_2->location))
notify_printer_location(snum, printer->info_2->location);
+ }
+
+ /* here we need to update some more DsSpooler keys */
+ /* uNCName, serverName, shortServerName */
+
+ init_unistr2( &buffer, global_myname(), strlen(global_myname())+1 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "serverName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shortServerName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ slprintf( asc_buffer, sizeof(asc_buffer)-1, "\\\\%s\\%s",
+ global_myname(), printer->info_2->sharename );
+ init_unistr2( &buffer, asc_buffer, strlen(asc_buffer)+1 );
+ set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "uNCName",
+ REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
+
+ /* Update printer info */
+ result = mod_a_printer(*printer, 2);
done:
free_a_printer(&printer, 2);
return result;
}
+/****************************************************************************
+****************************************************************************/
+static WERROR publish_or_unpublish_printer(pipes_struct *p, POLICY_HND *handle,
+ const SPOOL_PRINTER_INFO_LEVEL *info)
+{
+#ifdef HAVE_ADS
+ SPOOL_PRINTER_INFO_LEVEL_7 *info7 = info->info_7;
+ int snum;
+ Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+ WERROR result;
+
+ DEBUG(5,("publish_or_unpublish_printer, action = %d\n",info7->action));
+
+ result = WERR_OK;
+
+ if (!Printer)
+ return WERR_BADFID;
+
+ if (!get_printer_snum(p, handle, &snum))
+ return WERR_BADFID;
+
+ nt_printer_publish(Printer, snum, info7->action);
+
+ return WERR_OK;
+#else
+ return WERR_UNKNOWN_LEVEL;
+#endif
+}
/****************************************************************************
****************************************************************************/
case 3:
return update_printer_sec(handle, level, info, p,
secdesc_ctr);
+ case 7:
+ return publish_or_unpublish_printer(p, handle, info);
default:
return WERR_UNKNOWN_LEVEL;
}
WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u)
{
POLICY_HND *handle = &q_u->handle;
-
Printer_entry *Printer= find_printer_index_by_hnd(p, handle);
if (!Printer) {
return WERR_BADFID;
}
- if (Printer->notify.client_connected==True)
- srv_spoolss_replycloseprinter(&Printer->notify.client_hnd);
+ if (Printer->notify.client_connected==True) {
+ int snum = -1;
+
+ if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
+ snum = -1;
+ else if ( (Printer->printer_type == PRINTER_HANDLE_IS_PRINTER) &&
+ !get_printer_snum(p, handle, &snum) )
+ return WERR_BADFID;
+
+ srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd);
+ }
Printer->notify.flags=0;
Printer->notify.options=0;
DEVICEMODE *devmode)
{
pstring temp_name;
- pstring chaine;
struct tm *t;
t=gmtime(&queue->time);
job_info->jobid=queue->job;
- slprintf(chaine, sizeof(chaine)-1, "\\\\%s\\%s", get_called_name(), ntprinter->info_2->printername);
-
- init_unistr(&job_info->printername, chaine);
+ init_unistr(&job_info->printername, ntprinter->info_2->printername);
init_unistr(&job_info->machinename, temp_name);
init_unistr(&job_info->username, queue->fs_user);
goto done;
}
- result = get_a_printer(&ntprinter, 2, lp_servicename(snum));
+ result = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
if (!W_ERROR_IS_OK(result)) {
*returned = 0;
goto done;
}
- if (!(devmode = construct_dev_mode(snum))) {
- *returned = 0;
- result = WERR_NOMEM;
- goto done;
- }
+ /* this should not be a failure condition if the devmode is NULL */
+
+ devmode = construct_dev_mode(snum);
for (i=0; i<*returned; i++)
fill_job_info_2(&(info[i]), &queue[i], i, snum, ntprinter,
uint32 offered = q_u->offered;
uint32 *needed = &r_u->needed;
uint32 *returned = &r_u->returned;
+ WERROR wret;
int snum;
print_status_struct prt_status;
DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", *returned, prt_status.status, prt_status.message));
if (*returned == 0) {
+ set_enumjobs_timestamp(snum);
SAFE_FREE(queue);
return WERR_OK;
}
switch (level) {
case 1:
- return enumjobs_level1(queue, snum, buffer, offered, needed, returned);
+ wret = enumjobs_level1(queue, snum, buffer, offered, needed, returned);
+ set_enumjobs_timestamp(snum);
+ return wret;
case 2:
- return enumjobs_level2(queue, snum, buffer, offered, needed, returned);
+ wret = enumjobs_level2(queue, snum, buffer, offered, needed, returned);
+ set_enumjobs_timestamp(snum);
+ return wret;
default:
SAFE_FREE(queue);
*returned=0;
/****************************************************************************
****************************************************************************/
-static void fill_port_1(PORT_INFO_1 *port, char *name)
+static void fill_port_1(PORT_INFO_1 *port, const char *name)
{
init_unistr(&port->port_name, name);
}
/****************************************************************************
****************************************************************************/
-static void fill_port_2(PORT_INFO_2 *port, char *name)
+static void fill_port_2(PORT_INFO_2 *port, const char *name)
{
init_unistr(&port->port_name, name);
init_unistr(&port->monitor_name, "Local Monitor");
free_a_printer(&printer, 2);
return WERR_PRINTER_ALREADY_EXISTS;
}
+
+ /* FIXME!!! smbd should check to see if the driver is installed before
+ trying to add a printer like this --jerry */
- if (*lp_addprinter_cmd() )
+ if (*lp_addprinter_cmd() ) {
if ( !add_printer_hook(printer) ) {
free_a_printer(&printer,2);
return WERR_ACCESS_DENIED;
}
+ }
slprintf(name, sizeof(name)-1, "\\\\%s\\%s", get_called_name(),
printer->info_2->sharename);
+
if ((snum = print_queue_snum(printer->info_2->sharename)) == -1) {
free_a_printer(&printer,2);
return WERR_ACCESS_DENIED;
/* BEGIN_ADMIN_LOG */
switch(level) {
case 3:
+ fstrcpy(driver_name, driver.info_3->name ? driver.info_3->name : "");
sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.",
- driver.info_3->name,drv_ver_to_os[driver.info_3->cversion],uidtoname(user.uid));
- fstrcpy(driver_name, driver.info_3->name);
+ driver_name, get_drv_ver_to_os(driver.info_3->cversion),uidtoname(user.uid));
break;
case 6:
+ fstrcpy(driver_name, driver.info_6->name ? driver.info_6->name : "");
sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.",
- driver.info_6->name,drv_ver_to_os[driver.info_6->version],uidtoname(user.uid));
- fstrcpy(driver_name, driver.info_6->name);
+ driver_name, get_drv_ver_to_os(driver.info_6->version),uidtoname(user.uid));
break;
}
/* END_ADMIN_LOG */
{
pstring path;
pstring long_archi;
- pstring short_archi;
+ const char *short_archi;
DRIVER_DIRECTORY_1 *info=NULL;
unistr2_to_ascii(long_archi, uni_environment, sizeof(long_archi)-1);
- if (get_short_archi(short_archi, long_archi)==False)
+ if (!(short_archi = get_short_archi(long_archi)))
return WERR_INVALID_ENVIRONMENT;
if((info=(DRIVER_DIRECTORY_1 *)malloc(sizeof(DRIVER_DIRECTORY_1))) == NULL)
Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
int snum;
WERROR result;
- REGISTRY_VALUE *val;
+ REGISTRY_VALUE *val = NULL;
NT_PRINTER_DATA *p_data;
int i, key_index, num_values;
int name_length;
if (!get_printer_snum(p,handle, &snum))
return WERR_BADFID;
- result = get_a_printer(&printer, 2, lp_servicename(snum));
+ result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(result))
return result;
* cf: MSDN EnumPrinterData remark section
*/
- if ( !in_value_len && !in_data_len )
+ if ( !in_value_len && !in_data_len && (key_index != -1) )
{
DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
* the value len is wrong in NT sp3
* that's the number of bytes not the number of unicode chars
*/
-
- val = regval_ctr_specific_value( &p_data->keys[key_index].values, idx );
+
+ if ( key_index != -1 )
+ val = regval_ctr_specific_value( &p_data->keys[key_index].values, idx );
if ( !val )
{
/* out_value should default to "" or else NT4 has
problems unmarshalling the response */
- *out_max_value_len = (in_value_len/sizeof(uint16));
+ *out_max_value_len=(in_value_len/sizeof(uint16));
- if ( (*out_value=(uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL )
+ if((*out_value=(uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL)
{
result = WERR_NOMEM;
goto done;
*/
/* name */
- *out_max_value_len = ( in_value_len / sizeof(uint16) );
+ *out_max_value_len=(in_value_len/sizeof(uint16));
if ( (*out_value = (uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL )
{
result = WERR_NOMEM;
return WERR_BADFID;
}
+ if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER ) {
+ DEBUG(10,("_spoolss_setprinterdata: Not implemented for server handles yet\n"));
+ return WERR_INVALID_PARAM;
+ }
+
if (!get_printer_snum(p,handle, &snum))
return WERR_BADFID;
goto done;
}
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(status))
return status;
return WERR_ACCESS_DENIED;
}
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(status))
return status;
if (!get_printer_snum(p,handle, &snum))
return WERR_BADFID;
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(status))
goto done;
}
if (!get_printer_snum(p,handle, &snum))
return WERR_BADFID;
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(status))
goto done;
}
if (!get_printer_snum(p,handle, &snum))
return WERR_BADFID;
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(status))
goto done;
}
/****************************************************************************
****************************************************************************/
-static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getjob_level_1(print_queue_struct **queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
{
int i=0;
BOOL found=False;
info_1=(JOB_INFO_1 *)malloc(sizeof(JOB_INFO_1));
if (info_1 == NULL) {
- SAFE_FREE(queue);
return WERR_NOMEM;
}
for (i=0; i<count && found==False; i++) {
- if (queue[i].job==(int)jobid)
+ if ((*queue)[i].job==(int)jobid)
found=True;
}
if (found==False) {
- SAFE_FREE(queue);
SAFE_FREE(info_1);
/* NT treats not found as bad param... yet another bad choice */
return WERR_INVALID_PARAM;
}
- fill_job_info_1(info_1, &(queue[i-1]), i, snum);
+ fill_job_info_1(info_1, &((*queue)[i-1]), i, snum);
*needed += spoolss_size_job_info_1(info_1);
/****************************************************************************
****************************************************************************/
-static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR getjob_level_2(print_queue_struct **queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
{
int i = 0;
BOOL found = False;
for ( i=0; i<count && found==False; i++ )
{
- if (queue[i].job == (int)jobid)
+ if ((*queue)[i].job == (int)jobid)
found = True;
}
goto done;
}
- ret = get_a_printer(&ntprinter, 2, lp_servicename(snum));
+ ret = get_a_printer(NULL, &ntprinter, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(ret))
goto done;
/*
* if the print job does not have a DEVMODE associated with it,
- * just use the one for the printer
+ * just use the one for the printer. A NULL devicemode is not
+ * a failure condition
*/
if ( !(nt_devmode=print_job_devmode( snum, jobid )) )
}
}
- if ( !devmode ) {
- ret = WERR_NOMEM;
- goto done;
- }
-
- fill_job_info_2(info_2, &(queue[i-1]), i, snum, ntprinter, devmode);
+ fill_job_info_2(info_2, &((*queue)[i-1]), i, snum, ntprinter, devmode);
*needed += spoolss_size_job_info_2(info_2);
switch ( level ) {
case 1:
- wstatus = getjob_level_1(queue, count, snum, jobid,
+ wstatus = getjob_level_1(&queue, count, snum, jobid,
buffer, offered, needed);
break;
case 2:
- wstatus = getjob_level_2(queue, count, snum, jobid,
+ wstatus = getjob_level_2(&queue, count, snum, jobid,
buffer, offered, needed);
break;
default:
/* Is the handle to a printer or to the server? */
if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) {
- DEBUG(10,("_spoolss_getprinterdatex: Not implemented for server handles yet\n"));
+ DEBUG(10,("_spoolss_getprinterdataex: Not implemented for server handles yet\n"));
status = WERR_INVALID_PARAM;
goto done;
}
if ( !get_printer_snum(p,handle, &snum) )
return WERR_BADFID;
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
if ( !W_ERROR_IS_OK(status) )
goto done;
SetPrinterData if key is "PrinterDriverData" */
if (!Printer) {
- DEBUG(2,("_spoolss_setprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+ DEBUG(2,("_spoolss_setprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
return WERR_BADFID;
}
+ if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER ) {
+ DEBUG(10,("_spoolss_setprinterdataex: Not implemented for server handles yet\n"));
+ return WERR_INVALID_PARAM;
+ }
+
if ( !get_printer_snum(p,handle, &snum) )
return WERR_BADFID;
return WERR_ACCESS_DENIED;
}
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
if (!W_ERROR_IS_OK(status))
return status;
status = set_printer_dataex( printer, keyname, valuename, type, data, real_len );
- /* save the OID if one was specified and the previous set call succeeded */
-
- if ( W_ERROR_IS_OK(status) && oid_string )
+ if ( W_ERROR_IS_OK(status) )
{
-
+ /* save the OID if one was specified */
+ if ( oid_string ) {
fstrcat( keyname, "\\" );
fstrcat( keyname, SPOOL_OID_KEY );
REG_SZ, (void*)oid_string, strlen(oid_string)+1 );
}
+ status = mod_a_printer(*printer, 2);
+ }
+
free_a_printer(&printer, 2);
return status;
return WERR_ACCESS_DENIED;
}
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(status))
return status;
if ( !get_printer_snum(p,handle, &snum) )
return WERR_BADFID;
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(status))
return status;
return WERR_ACCESS_DENIED;
}
- status = get_a_printer(&printer, 2, lp_servicename(snum));
+ status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(status))
return status;
DEBUG(4,("_spoolss_enumprinterdataex\n"));
if (!Printer) {
- DEBUG(2,("_spoolss_enumprinterdata: Invalid handle (%s:%u:%u1<).\n", OUR_HANDLE(handle)));
+ DEBUG(2,("_spoolss_enumprinterdataex: Invalid handle (%s:%u:%u1<).\n", OUR_HANDLE(handle)));
return WERR_BADFID;
}
- /* first get the printer off of disk */
+ /*
+ * first check for a keyname of NULL or "". Win2k seems to send
+ * this a lot and we should send back WERR_INVALID_PARAM
+ * no need to spend time looking up the printer in this case.
+ * --jerry
+ */
+
+ unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
+ if ( !strlen(key) ) {
+ result = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ /* get the printer off of disk */
if (!get_printer_snum(p,handle, &snum))
return WERR_BADFID;
ZERO_STRUCT(printer);
- result = get_a_printer(&printer, 2, lp_servicename(snum));
+ result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
if (!W_ERROR_IS_OK(result))
return result;
{
if ( (enum_values=talloc(p->mem_ctx, num_entries*sizeof(PRINTER_ENUM_VALUES))) == NULL )
{
- DEBUG(0,("_spoolss_enumprinterdataex: talloc() failed to allocate memory for [%d] bytes!\n",
- num_entries*sizeof(PRINTER_ENUM_VALUES)));
+ DEBUG(0,("_spoolss_enumprinterdataex: talloc() failed to allocate memory for [%lu] bytes!\n",
+ (unsigned long)num_entries*sizeof(PRINTER_ENUM_VALUES)));
result = WERR_NOMEM;
goto done;
}
done:
+ if ( printer )
free_a_printer(&printer, 2);
return result;
{
pstring path;
pstring long_archi;
- pstring short_archi;
+ const char *short_archi;
PRINTPROCESSOR_DIRECTORY_1 *info=NULL;
unistr2_to_ascii(long_archi, environment, sizeof(long_archi)-1);
- if (get_short_archi(short_archi, long_archi)==False)
+ if (!(short_archi = get_short_archi(long_archi)))
return WERR_INVALID_ENVIRONMENT;
if((info=(PRINTPROCESSOR_DIRECTORY_1 *)malloc(sizeof(PRINTPROCESSOR_DIRECTORY_1))) == NULL)
case 1:
result = getprintprocessordirectory_level_1
(&q_u->name, &q_u->environment, buffer, offered, needed);
+ break;
default:
result = WERR_UNKNOWN_LEVEL;
}