s3-printing: Handled case when smbd spools a file on behalf of spoolss.
authorSimo Sorce <ssorce@redhat.com>
Tue, 4 May 2010 06:51:12 +0000 (02:51 -0400)
committerSimo Sorce <idra@samba.org>
Tue, 27 Jul 2010 14:27:13 +0000 (10:27 -0400)
source3/include/proto.h
source3/include/smb.h
source3/printing/printing.c
source3/printing/printspoolss.c
source3/rpc_server/srv_spoolss_nt.c

index 8912e5e46e13bc70ecddc3087e86672c73b77f7f..df512e50ed9c0b910766e11fc7dcf943f19f4f74 100644 (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);
                       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);
 int print_queue_status(int snum, 
                       print_queue_struct **ppqueue,
                       print_status_struct *status);
index 4d60a3ad11fb351009c5494ce385eb7a4d49d008..5266192f0d38b30cf4d7ab3ec4988e42caa73b22 100644 (file)
@@ -635,8 +635,23 @@ typedef struct {
 
 /* Extra fields above "LPQ_PRINTING" are used to map extra NT status codes. */
 
 
 /* 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 
 
 typedef struct _print_queue_struct {
        int job;                /* normally the UNIX jobid -- see note in 
index ebb91876fc97933a5fc74dbc64e77411270ab14a..5f537c5d03b7a2d7556ab61071fd2e00214cb9b9 100644 (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,
 ***************************************************************************/
 
 static WERROR print_job_spool_file(int snum, uint32_t jobid,
-                                  fstring *filename, int *fd)
+                                  const char *output_file,
+                                  struct printjob *pjob)
 {
        WERROR werr;
 {
        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 "
                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: "
                } 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;
        }
                }
                return werr;
        }
@@ -2537,8 +2576,9 @@ WERROR print_job_start(struct auth_serversupplied_info *server_info,
                return werr;
        }
 
                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)) {
 
        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 */
        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;
        }
        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;
 
        *_jobid = jobid;
        return WERR_OK;
 
- fail:
+fail:
        if (jobid != -1) {
                pjob_delete(sharename, jobid);
        }
        if (jobid != -1) {
                pjob_delete(sharename, jobid);
        }
@@ -2629,36 +2669,61 @@ void print_job_endpage(int snum, uint32 jobid)
  error.
 ****************************************************************************/
 
  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 );
 {
        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);
 
 
        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;
                pjob->size = sbuf.st_ex_size;
-               close(pjob->fd);
-               pjob->fd = -1;
        } else {
 
                /*
        } 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;
        }
 
                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);
                        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);
 
        }
 
        ret = (*(current_printif->job_submit))(snum, pjob);
 
-       if (ret)
+       if (ret) {
+               status = NT_STATUS_PRINT_CANCELLED;
                goto fail;
                goto fail;
+       }
 
        /* The print job has been successfully handed over to the back-end */
 
 
        /* 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);
 
        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 */
 
 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);
        unlink(pjob->filename);
        pjob_delete(sharename, jobid);
-       return False;
+       return status;
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
index aaec8918ee2fab459cdb68d856faa41eb0898eca..939b627029aa72b0f57b81a19b390cf41d7de0f4 100644 (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:
        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);
                status = rpccli_spoolss_ClosePrinter(cli, fsp->print_file,
                                                &fsp->print_file->handle,
                                                &werr);
index 24d1716d429cd7c87f62f52ddf11c76ce09e1207..1f0b36450f91707aaf568afa4a6325c621f43270 100644 (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);
                              struct spoolss_EndDocPrinter *r)
 {
        Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
+       NTSTATUS status;
        int snum;
 
        if (!Printer) {
        int snum;
 
        if (!Printer) {
@@ -5201,11 +5202,15 @@ WERROR _spoolss_EndDocPrinter(pipes_struct *p,
        }
 
        Printer->document_started = false;
        }
 
        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;
 
        Printer->jobid = 0;
-       return WERR_OK;
+       return ntstatus_to_werror(status);
 }
 
 /****************************************************************
 }
 
 /****************************************************************