1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

s3-printing: Handled case when smbd spools a file on behalf of spoolss.

This commit is contained in:
Simo Sorce 2010-05-04 02:51:12 -04:00 committed by Simo Sorce
parent 94ee35f9cc
commit 660506d359
5 changed files with 124 additions and 35 deletions

View File

@ -4763,7 +4763,7 @@ WERROR print_job_start(struct auth_serversupplied_info *server_info,
int snum, const char *docname, const char *filename,
struct spoolss_DeviceMode *devmode, uint32_t *_jobid);
void print_job_endpage(int snum, uint32 jobid);
bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type);
NTSTATUS print_job_end(int snum, uint32 jobid, enum file_close_type close_type);
int print_queue_status(int snum,
print_queue_struct **ppqueue,
print_status_struct *status);

View File

@ -635,8 +635,23 @@ typedef struct {
/* Extra fields above "LPQ_PRINTING" are used to map extra NT status codes. */
enum {LPQ_QUEUED=0,LPQ_PAUSED,LPQ_SPOOLING,LPQ_PRINTING,LPQ_ERROR,LPQ_DELETING,
LPQ_OFFLINE,LPQ_PAPEROUT,LPQ_PRINTED,LPQ_DELETED,LPQ_BLOCKED,LPQ_USER_INTERVENTION};
enum {
LPQ_QUEUED = 0,
LPQ_PAUSED,
LPQ_SPOOLING,
LPQ_PRINTING,
LPQ_ERROR,
LPQ_DELETING,
LPQ_OFFLINE,
LPQ_PAPEROUT,
LPQ_PRINTED,
LPQ_DELETED,
LPQ_BLOCKED,
LPQ_USER_INTERVENTION,
/* smbd is dooing the file spooling before passing control to spoolss */
PJOB_SMBD_SPOOLING
};
typedef struct _print_queue_struct {
int job; /* normally the UNIX jobid -- see note in

View File

@ -2483,25 +2483,64 @@ static WERROR print_job_checks(struct auth_serversupplied_info *server_info,
***************************************************************************/
static WERROR print_job_spool_file(int snum, uint32_t jobid,
fstring *filename, int *fd)
const char *output_file,
struct printjob *pjob)
{
WERROR werr;
SMB_STRUCT_STAT st;
const char *path;
int len;
slprintf(*filename, sizeof(*filename)-1, "%s/%s%.8u.XXXXXX",
lp_pathname(snum), PRINT_SPOOL_PREFIX, (unsigned int)jobid);
*fd = mkstemp(*filename);
/* if this file is within the printer path, it means that smbd
* is spooling it and will pass us control when it is finished.
* Verify that the file name is ok, within path, and it is
* already already there */
if (output_file) {
path = lp_pathname(snum);
len = strlen(path);
if (strncmp(output_file, path, len) == 0 &&
(output_file[len - 1] == '/' || output_file[len] == '/')) {
if (*fd == -1) {
/* verify path is not too long */
if (strlen(output_file) >= sizeof(pjob->filename)) {
return WERR_INVALID_NAME;
}
/* verify that the file exists */
if (sys_stat(output_file, &st, false) != 0) {
return WERR_INVALID_NAME;
}
fstrcpy(pjob->filename, output_file);
DEBUG(3, ("print_job_spool_file:"
"External spooling activated"));
/* we do not open the file until spooling is done */
pjob->fd = -1;
pjob->status = PJOB_SMBD_SPOOLING;
return WERR_OK;
}
}
slprintf(pjob->filename, sizeof(pjob->filename)-1,
"%s/%s%.8u.XXXXXX", lp_pathname(snum),
PRINT_SPOOL_PREFIX, (unsigned int)jobid);
pjob->fd = mkstemp(pjob->filename);
if (pjob->fd == -1) {
werr = map_werror_from_unix(errno);
if (W_ERROR_EQUAL(werr, WERR_ACCESS_DENIED)) {
/* Common setup error, force a report. */
DEBUG(0, ("print_job_spool_file: "
"insufficient permissions to open spool "
"file %s.\n", *filename));
"file %s.\n", pjob->filename));
} else {
/* Normal case, report at level 3 and above. */
DEBUG(3, ("print_job_spool_file: "
"can't open spool file %s\n", *filename));
"can't open spool file %s\n",
pjob->filename));
}
return werr;
}
@ -2537,8 +2576,9 @@ WERROR print_job_start(struct auth_serversupplied_info *server_info,
return werr;
}
DEBUG(10,("print_job_start: Queue %s number of jobs (%d), max printjobs = %d\n",
sharename, njobs, lp_maxprintjobs(snum) ));
DEBUG(10, ("print_job_start: "
"Queue %s number of jobs (%d), max printjobs = %d\n",
sharename, njobs, lp_maxprintjobs(snum)));
werr = allocate_print_jobid(pdb, snum, sharename, &jobid);
if (!W_ERROR_IS_OK(werr)) {
@ -2573,7 +2613,7 @@ WERROR print_job_start(struct auth_serversupplied_info *server_info,
fstrcpy(pjob.queuename, lp_const_servicename(snum));
/* we have a job entry - now create the spool file */
werr = print_job_spool_file(snum, jobid, &pjob.filename, &pjob.fd);
werr = print_job_spool_file(snum, jobid, filename, &pjob);
if (!W_ERROR_IS_OK(werr)) {
goto fail;
}
@ -2591,7 +2631,7 @@ WERROR print_job_start(struct auth_serversupplied_info *server_info,
*_jobid = jobid;
return WERR_OK;
fail:
fail:
if (jobid != -1) {
pjob_delete(sharename, jobid);
}
@ -2629,36 +2669,61 @@ void print_job_endpage(int snum, uint32 jobid)
error.
****************************************************************************/
bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
NTSTATUS print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
{
const char* sharename = lp_const_servicename(snum);
struct printjob *pjob;
int ret;
SMB_STRUCT_STAT sbuf;
struct printif *current_printif = get_printer_fns( snum );
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
pjob = print_job_find(sharename, jobid);
if (!pjob)
return False;
if (!pjob) {
return NT_STATUS_PRINT_CANCELLED;
}
if (pjob->spooled || pjob->pid != sys_getpid())
return False;
if (pjob->spooled || pjob->pid != sys_getpid()) {
return NT_STATUS_ACCESS_DENIED;
}
if (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) {
if (pjob->status == PJOB_SMBD_SPOOLING) {
/* take over the file now, smbd is done */
if (sys_stat(pjob->filename, &sbuf, false) != 0) {
status = map_nt_error_from_unix(errno);
DEBUG(3, ("print_job_end: "
"stat file failed for jobid %d\n",
jobid));
goto fail;
}
pjob->status = LPQ_SPOOLING;
} else {
if ((sys_fstat(pjob->fd, &sbuf, false) != 0)) {
status = map_nt_error_from_unix(errno);
close(pjob->fd);
DEBUG(3, ("print_job_end: "
"stat file failed for jobid %d\n",
jobid));
goto fail;
}
close(pjob->fd);
}
if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
(sys_fstat(pjob->fd, &sbuf, false) == 0)) {
pjob->size = sbuf.st_ex_size;
close(pjob->fd);
pjob->fd = -1;
} else {
/*
* Not a normal close or we couldn't stat the job file,
* so something has gone wrong. Cleanup.
* Not a normal close, something has gone wrong. Cleanup.
*/
close(pjob->fd);
pjob->fd = -1;
DEBUG(3,("print_job_end: failed to stat file for jobid %d\n", jobid ));
if (pjob->fd != -1) {
close(pjob->fd);
}
goto fail;
}
@ -2671,13 +2736,15 @@ bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
pjob->filename, pjob->size ? "deleted" : "zero length" ));
unlink(pjob->filename);
pjob_delete(sharename, jobid);
return True;
return NT_STATUS_OK;
}
ret = (*(current_printif->job_submit))(snum, pjob);
if (ret)
if (ret) {
status = NT_STATUS_PRINT_CANCELLED;
goto fail;
}
/* The print job has been successfully handed over to the back-end */
@ -2689,15 +2756,16 @@ bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
if (print_cache_expired(lp_const_servicename(snum), True))
print_queue_update(snum, False);
return True;
return NT_STATUS_OK;
fail:
/* The print job was not successfully started. Cleanup */
/* Still need to add proper error return propagation! 010122:JRR */
pjob->fd = -1;
unlink(pjob->filename);
pjob_delete(sharename, jobid);
return False;
return status;
}
/****************************************************************************

View File

@ -275,6 +275,7 @@ void print_spool_end(files_struct *fsp, enum file_close_type close_type)
switch (close_type) {
case NORMAL_CLOSE:
case SHUTDOWN_CLOSE:
/* this also automatically calls spoolss_EndDocPrinter */
status = rpccli_spoolss_ClosePrinter(cli, fsp->print_file,
&fsp->print_file->handle,
&werr);

View File

@ -5188,6 +5188,7 @@ WERROR _spoolss_EndDocPrinter(pipes_struct *p,
struct spoolss_EndDocPrinter *r)
{
Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
NTSTATUS status;
int snum;
if (!Printer) {
@ -5201,11 +5202,15 @@ WERROR _spoolss_EndDocPrinter(pipes_struct *p,
}
Printer->document_started = false;
print_job_end(snum, Printer->jobid, NORMAL_CLOSE);
/* error codes unhandled so far ... */
status = print_job_end(snum, Printer->jobid, NORMAL_CLOSE);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(2, ("_spoolss_EndDocPrinter: "
"print_job_end failed [%s]\n",
nt_errstr(status)));
}
Printer->jobid = 0;
return WERR_OK;
return ntstatus_to_werror(status);
}
/****************************************************************