smb_print.c revision 86d7016b0051dd58772baafe5b5bcee51d560b05
849N/A/*
849N/A * CDDL HEADER START
849N/A *
849N/A * The contents of this file are subject to the terms of the
849N/A * Common Development and Distribution License (the "License").
849N/A * You may not use this file except in compliance with the License.
849N/A *
849N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
849N/A * or http://www.opensolaris.org/os/licensing.
849N/A * See the License for the specific language governing permissions
849N/A * and limitations under the License.
849N/A *
849N/A * When distributing Covered Code, include this CDDL HEADER in each
849N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
849N/A * If applicable, add the following below this CDDL HEADER, with the
849N/A * fields enclosed by brackets "[]" replaced with your own identifying
849N/A * information: Portions Copyright [yyyy] [name of copyright owner]
849N/A *
873N/A * CDDL HEADER END
849N/A */
849N/A/*
849N/A * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
849N/A * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
849N/A */
3232N/A
5827N/A/*
849N/A * SMB print interface.
849N/A */
849N/A
849N/A#include <smbsrv/smb_kproto.h>
849N/A#include <sys/unistd.h>
3853N/A#include <sys/stat.h>
3853N/A#include <sys/types.h>
849N/A#include <sys/fcntl.h>
849N/A#include <smbsrv/smb_share.h>
849N/A
849N/A/*
849N/A * Starts the creation of a new printer file, which will be deleted
1008N/A * automatically once it has been closed and printed.
3853N/A *
3853N/A * SetupLength is the number of bytes in the first part of the resulting
849N/A * print spool file which contains printer-specific control strings.
849N/A *
849N/A * Mode can have the following values:
849N/A * 0 Text mode. The server may optionally
849N/A * expand tabs to a series of spaces.
849N/A * 1 Graphics mode. No conversion of data
3853N/A * should be done by the server.
849N/A *
3853N/A * IdentifierString can be used by the server to provide some sort of
849N/A * per-client identifying component to the print file.
849N/A *
849N/A * When the file is closed, it will be sent to the spooler and printed.
849N/A */
849N/Asmb_sdrc_t
849N/Asmb_pre_open_print_file(smb_request_t *sr)
3853N/A{
3853N/A struct open_param *op = &sr->arg.open;
3853N/A char *path;
849N/A char *identifier;
849N/A uint32_t new_id;
849N/A uint16_t setup;
849N/A uint16_t mode;
849N/A int rc;
849N/A static uint32_t tmp_id = 10000;
849N/A
849N/A bzero(op, sizeof (sr->arg.open));
849N/A rc = smbsr_decode_vwv(sr, "ww", &setup, &mode);
849N/A if (rc == 0)
849N/A rc = smbsr_decode_data(sr, "%S", sr, &identifier);
849N/A
849N/A if (rc == 0) {
849N/A path = smb_srm_zalloc(sr, MAXPATHLEN);
849N/A op->fqi.fq_path.pn_path = path;
849N/A new_id = atomic_inc_32_nv(&tmp_id);
849N/A (void) snprintf(path, MAXPATHLEN, "%s%05u", identifier, new_id);
849N/A }
849N/A
849N/A op->create_disposition = FILE_OVERWRITE_IF;
849N/A op->create_options = FILE_NON_DIRECTORY_FILE;
849N/A DTRACE_SMB_2(op__OpenPrintFile__start, smb_request_t *, sr,
849N/A struct open_param *, op);
849N/A
849N/A return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
849N/A}
849N/A
849N/Avoid
849N/Asmb_post_open_print_file(smb_request_t *sr)
849N/A{
849N/A DTRACE_SMB_1(op__OpenPrintFile__done, smb_request_t *, sr);
849N/A}
849N/A
849N/A/*
849N/A * Creates a new spool file which will be later copied and
849N/A * deleted by cupsd. After the file is created, information
849N/A * related to the file will be placed in a spooldoc list
849N/A * to be later used by cupsd
849N/A *
849N/A * Return values
849N/A * rc 0 SDRC_SUCCESS
2624N/A * rc non-zero SDRC_ERROR
849N/A */
2624N/A
849N/Asmb_sdrc_t
849N/Asmb_com_open_print_file(smb_request_t *sr)
849N/A{
849N/A int rc;
849N/A smb_kspooldoc_t *sp;
849N/A smb_kshare_t *si;
849N/A struct open_param *op = &sr->arg.open;
2624N/A
849N/A if (sr->sr_server->sv_cfg.skc_print_enable == 0 ||
2624N/A !STYPE_ISPRN(sr->tid_tree->t_res_type)) {
2624N/A cmn_err(CE_WARN, "smb_com_open_print_file: bad device");
849N/A smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
849N/A ERRDOS, ERROR_BAD_DEV_TYPE);
849N/A return (SDRC_ERROR);
849N/A }
849N/A if ((rc = smb_common_create(sr)) != NT_STATUS_SUCCESS) {
849N/A cmn_err(CE_WARN, "smb_com_open_print_file: error rc=%d", rc);
849N/A return (SDRC_ERROR);
2624N/A }
849N/A if ((rc = smbsr_encode_result(sr, 1, 0,
2624N/A "bww", 1, sr->smb_fid, 0)) == 0) {
2624N/A if ((si = smb_kshare_lookup(SMB_SHARE_PRINT)) == NULL) {
849N/A cmn_err(CE_NOTE, "smb_com_open_print_file: SDRC_ERROR");
849N/A return (SDRC_ERROR);
849N/A }
849N/A sp = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP);
849N/A (void) snprintf(sp->sd_path, MAXPATHLEN, "%s/%s", si->shr_path,
849N/A op->fqi.fq_path.pn_path);
849N/A /* sp->sd_spool_num set by smb_spool_add_doc() */
2624N/A sp->sd_ipaddr = sr->session->ipaddr;
849N/A (void) strlcpy(sp->sd_username, sr->uid_user->u_name,
2624N/A MAXNAMELEN);
2624N/A sp->sd_fid = sr->smb_fid;
849N/A if (smb_spool_add_doc(sp))
849N/A kmem_free(sp, sizeof (smb_kspooldoc_t));
849N/A smb_kshare_release(si);
849N/A }
849N/A return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
849N/A}
849N/A
2624N/A/*
849N/A * Close the specified file handle and queue the file for printing.
2624N/A * The fid refers to a file previously created as a print spool file.
2624N/A * On successful completion of this request, the file is queued for
849N/A * printing by the server.
849N/A *
849N/A * Servers that negotiate LANMAN1.0 or later allow all the the fid
849N/A * to be closed and printed via any close request.
849N/A */
849N/Asmb_sdrc_t
849N/Asmb_pre_close_print_file(smb_request_t *sr)
2624N/A{
849N/A int rc;
2624N/A
2624N/A rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
2624N/A
849N/A DTRACE_SMB_1(op__ClosePrintFile__start, smb_request_t *, sr);
849N/A return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
849N/A}
849N/A
849N/Avoid
849N/Asmb_post_close_print_file(smb_request_t *sr)
849N/A{
2624N/A DTRACE_SMB_1(op__ClosePrintFile__done, smb_request_t *, sr);
849N/A}
2624N/A
2624N/A/*
2624N/A *
849N/A * Adds the print file fid to a list to be used as a search
849N/A * key in the spooldoc list. It then wakes up the smbd
849N/A * spool monitor thread to copy the spool file.
849N/A *
849N/A * Return values
849N/A * rc - 0 success
849N/A *
2624N/A */
849N/A
2624N/Asmb_sdrc_t
2624N/Asmb_com_close_print_file(smb_request_t *sr)
2624N/A{
849N/A smb_sdrc_t rc;
849N/A
849N/A /*
849N/A * If sv_cfg.skc_print_enable somehow went false while
849N/A * we have a print FID open, close the FID. In this
849N/A * situation, smb_spool_add_fid() will do nothing.
849N/A */
849N/A if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
849N/A smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
849N/A ERRDOS, ERROR_BAD_DEV_TYPE);
849N/A cmn_err(CE_WARN, "smb_com_close_print_file: SDRC_ERROR");
849N/A return (SDRC_ERROR);
849N/A }
849N/A rc = smb_com_close(sr);
849N/A
849N/A smb_spool_add_fid(sr->sr_server, sr->smb_fid);
849N/A
849N/A return (rc);
849N/A}
849N/A
849N/A/*
849N/A * Get a list of print queue entries on the server. Support for
849N/A * this request is optional (not required for Windows clients).
849N/A */
849N/Asmb_sdrc_t
849N/Asmb_pre_get_print_queue(smb_request_t *sr)
849N/A{
1008N/A DTRACE_SMB_1(op__GetPrintQueue__start, smb_request_t *, sr);
1008N/A return (SDRC_SUCCESS);
1008N/A}
1008N/A
849N/Avoid
849N/Asmb_post_get_print_queue(smb_request_t *sr)
849N/A{
1008N/A DTRACE_SMB_1(op__GetPrintQueue__done, smb_request_t *, sr);
849N/A}
849N/A
849N/Asmb_sdrc_t
849N/Asmb_com_get_print_queue(smb_request_t *sr)
849N/A{
849N/A unsigned short max_count, start_ix;
849N/A
849N/A if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0)
849N/A return (SDRC_ERROR);
849N/A
849N/A if (smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0))
849N/A return (SDRC_ERROR);
849N/A
849N/A return (SDRC_SUCCESS);
849N/A}
849N/A
849N/A/*
849N/A * Write (append) data to a print spool file. The fid must refer to
849N/A * a print spool file.
849N/A *
849N/A * The first SetupLength bytes (see SMB_COM_OPEN_PRINT_FILE) in the
849N/A * print spool file contain printer setup data.
849N/A *
849N/A * Servers that negotiate LANMAN1.0 or later also support the use of
849N/A * normal write requests with print spool files.
849N/A */
849N/Asmb_sdrc_t
849N/Asmb_pre_write_print_file(smb_request_t *sr)
849N/A{
849N/A smb_rw_param_t *param;
849N/A int rc;
849N/A
3824N/A param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
849N/A sr->arg.rw = param;
3824N/A param->rw_magic = SMB_RW_MAGIC;
849N/A
849N/A rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
849N/A
849N/A DTRACE_SMB_1(op__WritePrintFile__start, smb_request_t *, sr);
3634N/A return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
849N/A}
849N/A
849N/Avoid
849N/Asmb_post_write_print_file(smb_request_t *sr)
849N/A{
849N/A DTRACE_SMB_1(op__WritePrintFile__done, smb_request_t *, sr);
849N/A
849N/A kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
849N/A}
849N/A
849N/Asmb_sdrc_t
849N/Asmb_com_write_print_file(smb_request_t *sr)
849N/A{
849N/A smb_rw_param_t *param = sr->arg.rw;
849N/A smb_node_t *node;
849N/A smb_attr_t attr;
849N/A int rc;
849N/A
849N/A if (sr->sr_server->sv_cfg.skc_print_enable == 0 ||
849N/A !STYPE_ISPRN(sr->tid_tree->t_res_type)) {
849N/A smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
849N/A ERRDOS, ERROR_BAD_DEV_TYPE);
849N/A return (SDRC_ERROR);
849N/A }
849N/A
849N/A smbsr_lookup_file(sr);
849N/A if (sr->fid_ofile == NULL) {
849N/A smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
849N/A return (SDRC_ERROR);
849N/A }
849N/A
849N/A node = sr->fid_ofile->f_node;
849N/A sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
849N/A
849N/A if (smb_node_getattr(sr, node, &attr) != 0) {
849N/A smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
849N/A ERRDOS, ERROR_INTERNAL_ERROR);
849N/A return (SDRC_ERROR);
849N/A }
849N/A
849N/A if ((smbsr_decode_data(sr, "D", &param->rw_vdb)) != 0) {
849N/A smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
849N/A ERRDOS, ERROR_INVALID_PARAMETER);
849N/A return (SDRC_ERROR);
849N/A }
849N/A
849N/A param->rw_count = param->rw_vdb.vdb_len;
849N/A param->rw_offset = attr.sa_vattr.va_size;
849N/A param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
849N/A
849N/A if ((rc = smb_common_write(sr, param)) != 0) {
849N/A if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
849N/A smbsr_errno(sr, rc);
3824N/A return (SDRC_ERROR);
849N/A }
3824N/A
849N/A rc = smbsr_encode_empty_result(sr);
849N/A return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
849N/A}
849N/A