From 660506d359d76700f6f6ae5b7e9c4d05fe505fb6 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 4 May 2010 02:51:12 -0400 Subject: s3-printing: Handled case when smbd spools a file on behalf of spoolss. --- source3/include/proto.h | 2 +- source3/include/smb.h | 19 +++++- source3/printing/printing.c | 126 +++++++++++++++++++++++++++--------- source3/printing/printspoolss.c | 1 + source3/rpc_server/srv_spoolss_nt.c | 11 +++- 5 files changed, 124 insertions(+), 35 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index 8912e5e46e..df512e50ed 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -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); diff --git a/source3/include/smb.h b/source3/include/smb.h index 4d60a3ad11..5266192f0d 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -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 diff --git a/source3/printing/printing.c b/source3/printing/printing.c index ebb91876fc..5f537c5d03 100644 --- a/source3/printing/printing.c +++ b/source3/printing/printing.c @@ -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; + + /* 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] == '/')) { + + /* 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; + } - slprintf(*filename, sizeof(*filename)-1, "%s/%s%.8u.XXXXXX", - lp_pathname(snum), PRINT_SPOOL_PREFIX, (unsigned int)jobid); - *fd = mkstemp(*filename); + fstrcpy(pjob->filename, output_file); - if (*fd == -1) { + 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; } /**************************************************************************** diff --git a/source3/printing/printspoolss.c b/source3/printing/printspoolss.c index aaec8918ee..939b627029 100644 --- a/source3/printing/printspoolss.c +++ b/source3/printing/printspoolss.c @@ -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); diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 24d1716d42..1f0b36450f 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -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); } /**************************************************************** -- cgit