#include "includes.h"
#include "printing.h"
#include "librpc/gen_ndr/messaging.h"
+#include "../librpc/gen_ndr/ndr_spoolss.h"
+#include "nt_printing.h"
extern struct current_user current_user;
extern userdom_struct current_user_info;
return ret;
}
+/****************************************************************************
+ Pack the devicemode to store it in a tdb.
+****************************************************************************/
+static int pack_devicemode(struct spoolss_DeviceMode *devmode, uint8 *buf, int buflen)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ int len = 0;
+
+ if (devmode) {
+ ndr_err = ndr_push_struct_blob(&blob, talloc_tos(),
+ devmode,
+ (ndr_push_flags_fn_t)
+ ndr_push_spoolss_DeviceMode);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(10, ("pack_devicemode: "
+ "error encoding spoolss_DeviceMode\n"));
+ goto done;
+ }
+ } else {
+ ZERO_STRUCT(blob);
+ }
+
+ len = tdb_pack(buf, buflen, "B", blob.length, blob.data);
+
+ if (devmode) {
+ DEBUG(8, ("Packed devicemode [%s]\n", devmode->formname));
+ }
+
+done:
+ return len;
+}
+
+/****************************************************************************
+ Unpack the devicemode to store it in a tdb.
+****************************************************************************/
+static int unpack_devicemode(TALLOC_CTX *mem_ctx,
+ const uint8 *buf, int buflen,
+ struct spoolss_DeviceMode **devmode)
+{
+ struct spoolss_DeviceMode *dm;
+ enum ndr_err_code ndr_err;
+ char *data = NULL;
+ int data_len = 0;
+ DATA_BLOB blob;
+ int len = 0;
+
+ *devmode = NULL;
+
+ len = tdb_unpack(buf, buflen, "B", &data_len, &data);
+ if (!data) {
+ return len;
+ }
+
+ dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
+ if (!dm) {
+ goto done;
+ }
+
+ blob = data_blob_const(data, data_len);
+
+ ndr_err = ndr_pull_struct_blob(&blob, dm, dm,
+ (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(10, ("unpack_devicemode: "
+ "error parsing spoolss_DeviceMode\n"));
+ goto done;
+ }
+
+ DEBUG(8, ("Unpacked devicemode [%s](%s)\n",
+ dm->devicename, dm->formname));
+ if (dm->driverextra_data.data) {
+ DEBUG(8, ("with a private section of %d bytes\n",
+ dm->__driverextra_length));
+ }
+
+ *devmode = dm;
+
+done:
+ SAFE_FREE(data);
+ return len;
+}
+
/***********************************************************************
unpack a pjob from a tdb buffer
***********************************************************************/
return ret;
}
-/****************************************************************************
- Give the fd used for a jobid.
-****************************************************************************/
-
-int print_job_fd(const char* sharename, uint32 jobid)
-{
- struct printjob *pjob = print_job_find(sharename, jobid);
- if (!pjob)
- return -1;
- /* don't allow another process to get this info - it is meaningless */
- if (pjob->pid != sys_getpid())
- return -1;
- return pjob->fd;
-}
-
/****************************************************************************
Give the filename used for a jobid.
Only valid for the process doing the spooling and when the job
Delete a print job.
****************************************************************************/
-bool print_job_delete(struct auth_serversupplied_info *server_info, int snum,
- uint32 jobid, WERROR *errcode)
+WERROR print_job_delete(struct auth_serversupplied_info *server_info,
+ int snum, uint32_t jobid)
{
- const char* sharename = lp_const_servicename( snum );
+ const char* sharename = lp_const_servicename(snum);
struct printjob *pjob;
bool owner;
char *fname;
- *errcode = WERR_OK;
-
owner = is_owner(server_info, lp_const_servicename(snum), jobid);
/* Check access against security descriptor or whether the user
if (!owner &&
!print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("delete denied by security descriptor\n"));
- *errcode = WERR_ACCESS_DENIED;
/* BEGIN_ADMIN_LOG */
sys_adminlog( LOG_ERR,
lp_printername(snum) );
/* END_ADMIN_LOG */
- return False;
+ return WERR_ACCESS_DENIED;
}
/*
* spool file & return.
*/
- if ( (fname = print_job_fname( sharename, jobid )) != NULL )
- {
+ fname = print_job_fname(sharename, jobid);
+ if (fname != NULL) {
/* remove the spool file */
- DEBUG(10,("print_job_delete: Removing spool file [%s]\n", fname ));
- if ( unlink( fname ) == -1 ) {
- *errcode = map_werror_from_unix(errno);
- return False;
+ DEBUG(10, ("print_job_delete: "
+ "Removing spool file [%s]\n", fname));
+ if (unlink(fname) == -1) {
+ return map_werror_from_unix(errno);
}
}
if (!print_job_delete1(snum, jobid)) {
- *errcode = WERR_ACCESS_DENIED;
- return False;
+ return WERR_ACCESS_DENIED;
}
/* force update the database and say the delete failed if the
print_queue_update(snum, True);
pjob = print_job_find(sharename, jobid);
- if ( pjob && (pjob->status != LPQ_DELETING) )
- *errcode = WERR_ACCESS_DENIED;
+ if (pjob && (pjob->status != LPQ_DELETING)) {
+ return WERR_ACCESS_DENIED;
+ }
- return (pjob == NULL );
+ return WERR_PRINTER_HAS_JOBS_QUEUED;
}
/****************************************************************************
if (pjob->pid != sys_getpid())
return -1;
+ /* if SMBD is spooling this can't be allowed */
+ if (pjob->status == PJOB_SMBD_SPOOLING) {
+ return -1;
+ }
+
return_code = write_data_at_offset(pjob->fd, buf, size, pos);
if (return_code>0) {
***************************************************************************/
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;
+ }
- slprintf(*filename, sizeof(*filename)-1, "%s/%s%.8u.XXXXXX",
- lp_pathname(snum), PRINT_SPOOL_PREFIX, (unsigned int)jobid);
- *fd = mkstemp(*filename);
+ /* 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"));
- if (*fd == -1) {
+ /* 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;
}
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)) {
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;
}
*_jobid = jobid;
return WERR_OK;
- fail:
+fail:
if (jobid != -1) {
pjob_delete(sharename, 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;
}
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 */
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;
}
/****************************************************************************