summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2010-05-04 02:51:12 -0400
committerSimo Sorce <idra@samba.org>2010-07-27 10:27:13 -0400
commit660506d359d76700f6f6ae5b7e9c4d05fe505fb6 (patch)
treee9b93712fe3d2dad8ddf412039892b0e55c08c5a /source3
parent94ee35f9cc0880c267bee14047d559948eb14ede (diff)
downloadsamba-660506d359d76700f6f6ae5b7e9c4d05fe505fb6.tar.gz
samba-660506d359d76700f6f6ae5b7e9c4d05fe505fb6.tar.bz2
samba-660506d359d76700f6f6ae5b7e9c4d05fe505fb6.zip
s3-printing: Handled case when smbd spools a file on behalf of spoolss.
Diffstat (limited to 'source3')
-rw-r--r--source3/include/proto.h2
-rw-r--r--source3/include/smb.h19
-rw-r--r--source3/printing/printing.c126
-rw-r--r--source3/printing/printspoolss.c1
-rw-r--r--source3/rpc_server/srv_spoolss_nt.c11
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);
}
/****************************************************************