fstring machine;
fstring user;
} client;
+
+ /* devmode sent in the OpenPrinter() call */
+ NT_DEVICEMODE *nt_devmode;
+
} Printer_entry;
static Printer_entry *printers_list;
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;
free_spool_notify_option(&Printer->notify.option);
Printer->notify.option=NULL;
Printer->notify.client_connected=False;
+
+ free_nt_devicemode( &Printer->nt_devmode );
/* Remove from the internal list. */
DLIST_REMOVE(printers_list, Printer);
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;
}
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;
}
/***********************************************************************
**********************************************************************/
-static SPOOLSS_NOTIFY_MSG_GROUP* notify_ctr_getgroup( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 index )
+static SPOOLSS_NOTIFY_MSG_GROUP* notify_ctr_getgroup( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
{
if ( !ctr || !ctr->msg_groups )
return NULL;
- if ( index >= ctr->num_groups )
+ if ( idx >= ctr->num_groups )
return NULL;
- return &ctr->msg_groups[index];
+ return &ctr->msg_groups[idx];
}
back registered
**********************************************************************/
-static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 index )
+static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
{
Printer_entry *p;
TALLOC_CTX *mem_ctx = notify_ctr_getctx( ctr );
- SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, index );
+ SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, idx );
SPOOLSS_NOTIFY_MSG *messages;
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 );
WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u)
{
- UNISTR2 *printername = NULL;
- PRINTER_DEFAULT *printer_default = &q_u->printer_default;
- POLICY_HND *handle = &r_u->handle;
+ UNISTR2 *printername = NULL;
+ PRINTER_DEFAULT *printer_default = &q_u->printer_default;
+ POLICY_HND *handle = &r_u->handle;
fstring name;
int snum;
}
Printer->access_granted = printer_default->access_required;
+
+ /*
+ * If the client sent a devmode in the OpenPrinter() call, then
+ * save it here in case we get a job submission on this handle
+ */
+
+ if ( (Printer->printer_type != PRINTER_HANDLE_IS_PRINTSERVER)
+ && q_u->printer_default.devmode_cont.devmode_ptr )
+ {
+ convert_devicemode( Printer->dev.handlename, q_u->printer_default.devmode_cont.devmode,
+ &Printer->nt_devmode );
+ }
return WERR_OK;
}
goto done;
}
}
+ /* otherwise it was a failure */
+ else {
+ status = WERR_UNKNOWN_PRINTER_DRIVER;
+ goto done;
+ }
+
}
if (printer_driver_in_use(info.info_3)) {
if ( !W_ERROR_IS_OK(status) )
{
- /* if the client asked for a specific version, then we've failed */
+ /*
+ * if the client asked for a specific version,
+ * or this is something other than Windows NT x86,
+ * then we've failed
+ */
- if ( flags & DPD_DELETE_SPECIFIC_VERSION )
+ if ( (flags&DPD_DELETE_SPECIFIC_VERSION) || (version !=2) )
goto done;
/* try for Win2k driver if "Windows NT x86" */
- if ( version == 2 )
- {
- version = 3;
- if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) {
- status = WERR_UNKNOWN_PRINTER_DRIVER;
- goto done;
- }
+ version = 3;
+ if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) {
+ status = WERR_UNKNOWN_PRINTER_DRIVER;
+ goto done;
}
}
if ( delete_files && printer_driver_files_in_use(info_win2k.info_3) & (flags&DPD_DELETE_ALL_FILES) ) {
/* no idea of the correct error here */
+ free_a_printer_driver( info_win2k, 3 );
status = WERR_ACCESS_DENIED;
goto done;
}
/* if we get to here, we now have 2 driver info structures to remove */
/* remove the Win2k driver first*/
- status_win2k = delete_printer_driver(info.info_3, &user, 3, delete_files);
+ status_win2k = delete_printer_driver(info_win2k.info_3, &user, 3, delete_files);
free_a_printer_driver( info_win2k, 3 );
/* this should not have failed---if it did, report to client */
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, const char *remote_machine)
{
extern pstring global_myname;
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",
remote_machine));
+ cli_shutdown(the_cli);
return False;
}
* Now start the NT Domain stuff :-).
*/
- if(cli_nt_session_open(the_cli, PIPE_SPOOLSS) == False) {
+ if(cli_nt_session_open(the_cli, PI_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)));
cli_nt_session_close(the_cli);
cli_ulogoff(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)
{
WERROR result;
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;
/* 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;
+
+ if(!srv_spoolss_replyopenprinter(snum, Printer->notify.localmachine,
Printer->notify.printerlocal, 1,
&Printer->notify.client_hnd))
return WERR_SERVER_UNAVAILABLE;
SAFE_FREE(dev);
}
+
/****************************************************************************
- Create a DEVMODE struct. Returns malloced memory.
+ Convert an NT_DEVICEMODE to a DEVICEMODE structure. Both pointers
+ should be valid upon entry
****************************************************************************/
-DEVICEMODE *construct_dev_mode(int snum)
+static BOOL convert_nt_devicemode( DEVICEMODE *devmode, NT_DEVICEMODE *ntdevmode )
{
- char adevice[32];
- char aform[32];
- NT_PRINTER_INFO_LEVEL *printer = NULL;
- NT_DEVICEMODE *ntdevmode = NULL;
- DEVICEMODE *devmode = NULL;
-
- DEBUG(7,("construct_dev_mode\n"));
-
- DEBUGADD(8,("getting printer characteristics\n"));
-
- if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) == NULL) {
- DEBUG(2,("construct_dev_mode: malloc fail.\n"));
- return NULL;
- }
-
- ZERO_STRUCTP(devmode);
-
- if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
- goto fail;
-
- if (printer->info_2->devmode)
- ntdevmode = dup_nt_devicemode(printer->info_2->devmode);
-
- if (ntdevmode == NULL) {
- DEBUG(5, ("BONG! There was no device mode!\n"));
- goto fail;
- }
-
- DEBUGADD(8,("loading DEVICEMODE\n"));
-
- slprintf(adevice, sizeof(adevice)-1, printer->info_2->printername);
- init_unistr(&devmode->devicename, adevice);
+ if ( !devmode || !ntdevmode )
+ return False;
+
+ init_unistr(&devmode->devicename, ntdevmode->devicename);
- slprintf(aform, sizeof(aform)-1, ntdevmode->formname);
- init_unistr(&devmode->formname, aform);
+ init_unistr(&devmode->formname, ntdevmode->formname);
devmode->specversion = ntdevmode->specversion;
devmode->driverversion = ntdevmode->driverversion;
if (ntdevmode->private != NULL) {
if ((devmode->private=(uint8 *)memdup(ntdevmode->private, ntdevmode->driverextra)) == NULL)
- goto fail;
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Create a DEVMODE struct. Returns malloced memory.
+****************************************************************************/
+
+DEVICEMODE *construct_dev_mode(int snum)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ DEVICEMODE *devmode = NULL;
+
+ DEBUG(7,("construct_dev_mode\n"));
+
+ DEBUGADD(8,("getting printer characteristics\n"));
+
+ if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+ return NULL;
+
+ if ( !printer->info_2->devmode ) {
+ DEBUG(5, ("BONG! There was no device mode!\n"));
+ goto done;
}
- free_nt_devicemode(&ntdevmode);
- free_a_printer(&printer,2);
+ if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) == NULL) {
+ DEBUG(2,("construct_dev_mode: malloc fail.\n"));
+ goto done;
+ }
- return devmode;
+ ZERO_STRUCTP(devmode);
+
+ DEBUGADD(8,("loading DEVICEMODE\n"));
- fail:
+ if ( !convert_nt_devicemode( devmode, printer->info_2->devmode ) ) {
+ free_dev_mode( devmode );
+ devmode = NULL;
+ }
- if (ntdevmode)
- free_nt_devicemode(&ntdevmode);
- if (printer)
- free_a_printer(&printer,2);
- free_dev_mode(devmode);
+done:
+ free_a_printer(&printer,2);
- return NULL;
+ return devmode;
}
/********************************************************************
* in EMF format.
*
* So I add checks like in NT Server ...
- *
- * lkclXXXX jean-francois, i love this kind of thing. oh, well,
- * there's a bug in NT client-side code, so we'll fix it in the
- * server-side code. *nnnnnggggh!*
*/
if (info_1->p_datatype != 0) {
unistr2_to_ascii(jobname, &info_1->docname, sizeof(jobname));
- Printer->jobid = print_job_start(&user, snum, jobname);
+ Printer->jobid = print_job_start(&user, snum, jobname, Printer->nt_devmode);
/* An error occured in print_job_start() so return an appropriate
NT error code. */
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);
result = WERR_NOMEM;
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);
}
/* Do sanity check on the requested changes for Samba */
}
/* 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;
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;
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,
return WERR_PRINTER_ALREADY_EXISTS;
}
- 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;
return WERR_NOMEM;
}
- for (i=0; i<count && found==False; i++) {
+ for (i=0; i<count && found==False; i++) {
if (queue[i].job==(int)jobid)
found=True;
}
fill_job_info_1(info_1, &(queue[i-1]), i, snum);
- SAFE_FREE(queue);
-
*needed += spoolss_size_job_info_1(info_1);
if (!alloc_buffer_size(buffer, *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;
- JOB_INFO_2 *info_2;
+ int i = 0;
+ BOOL found = False;
+ JOB_INFO_2 *info_2;
NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
- WERROR ret;
- DEVICEMODE *devmode = NULL;
+ WERROR ret;
+ DEVICEMODE *devmode = NULL;
+ NT_DEVICEMODE *nt_devmode = NULL;
info_2=(JOB_INFO_2 *)malloc(sizeof(JOB_INFO_2));
goto done;
}
- for (i=0; i<count && found==False; i++) {
- if (queue[i].job==(int)jobid)
- found=True;
+ for ( i=0; i<count && found==False; i++ )
+ {
+ if (queue[i].job == (int)jobid)
+ found = True;
}
- if (found==False) {
+ if ( !found )
+ {
/* NT treats not found as bad param... yet another bad
choice */
ret = WERR_INVALID_PARAM;
ret = get_a_printer(&ntprinter, 2, lp_servicename(snum));
if (!W_ERROR_IS_OK(ret))
goto done;
- if (construct_dev_mode(snum) == NULL) {
- ret = WERR_NOMEM;
- goto done;
+
+ /*
+ * if the print job does not have a DEVMODE associated with it,
+ * just use the one for the printer. A NULL devicemode is not
+ * a failure condition
+ */
+
+ if ( !(nt_devmode=print_job_devmode( snum, jobid )) )
+ devmode = construct_dev_mode(snum);
+ else {
+ if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) != NULL) {
+ ZERO_STRUCTP( devmode );
+ convert_nt_devicemode( devmode, nt_devmode );
+ }
}
-
+
fill_job_info_2(info_2, &(queue[i-1]), i, snum, ntprinter, devmode);
*needed += spoolss_size_job_info_2(info_2);
done:
/* Cleanup allocated memory */
- SAFE_FREE(queue);
free_job_info_2(info_2); /* Also frees devmode */
SAFE_FREE(info_2);
free_a_printer(&ntprinter, 2);
NEW_BUFFER *buffer = NULL;
uint32 offered = q_u->offered;
uint32 *needed = &r_u->needed;
+ WERROR wstatus = WERR_OK;
int snum;
int count;
- print_queue_struct *queue=NULL;
+ print_queue_struct *queue = NULL;
print_status_struct prt_status;
/* that's an [in out] buffer */
DEBUG(5,("spoolss_getjob\n"));
- *needed=0;
+ *needed = 0;
if (!get_printer_snum(p, handle, &snum))
return WERR_BADFID;
DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n",
count, prt_status.status, prt_status.message));
- switch (level) {
+ switch ( level ) {
case 1:
- return getjob_level_1(queue, count, snum, jobid, buffer, offered, needed);
+ wstatus = getjob_level_1(queue, count, snum, jobid,
+ buffer, offered, needed);
+ break;
case 2:
- return getjob_level_2(queue, count, snum, jobid, buffer, offered, needed);
+ wstatus = getjob_level_2(queue, count, snum, jobid,
+ buffer, offered, needed);
+ break;
default:
- SAFE_FREE(queue);
- return WERR_UNKNOWN_LEVEL;
+ wstatus = WERR_UNKNOWN_LEVEL;
+ break;
}
+
+ SAFE_FREE(queue);
+ return wstatus;
}
/********************************************************************
case 1:
result = getprintprocessordirectory_level_1
(&q_u->name, &q_u->environment, buffer, offered, needed);
+ break;
default:
result = WERR_UNKNOWN_LEVEL;
}