xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_print.c (revision cb174861876aea6950a7ab4ce944aff84b1914cd)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23da6c28aaSamw  */
24da6c28aaSamw 
25da6c28aaSamw /*
26da6c28aaSamw  * SMB print interface.
27da6c28aaSamw  */
28da6c28aaSamw 
29bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
30*cb174861Sjoyce mcintosh #include <sys/unistd.h>
31*cb174861Sjoyce mcintosh #include <sys/stat.h>
32*cb174861Sjoyce mcintosh #include <sys/types.h>
33*cb174861Sjoyce mcintosh #include <sys/fcntl.h>
34*cb174861Sjoyce mcintosh #include <smbsrv/smb_share.h>
35da6c28aaSamw 
36da6c28aaSamw /*
37*cb174861Sjoyce mcintosh  * Starts the creation of a new printer file, which will be deleted
38*cb174861Sjoyce mcintosh  * automatically once it has been closed and printed.
39da6c28aaSamw  *
40da6c28aaSamw  * SetupLength is the number of bytes in the first part of the resulting
41da6c28aaSamw  * print spool file which contains printer-specific control strings.
42da6c28aaSamw  *
43da6c28aaSamw  * Mode can have the following values:
44da6c28aaSamw  *      0     Text mode.  The server may optionally
45da6c28aaSamw  *            expand tabs to a series of spaces.
46da6c28aaSamw  *      1     Graphics mode.  No conversion of data
47da6c28aaSamw  *            should be done by the server.
48da6c28aaSamw  *
49f96bd5c8SAlan Wright  * IdentifierString can be used by the server to provide some sort of
50f96bd5c8SAlan Wright  * per-client identifying component to the print file.
51da6c28aaSamw  *
52f96bd5c8SAlan Wright  * When the file is closed, it will be sent to the spooler and printed.
53da6c28aaSamw  */
54faa1795aSjb150015 smb_sdrc_t
55faa1795aSjb150015 smb_pre_open_print_file(smb_request_t *sr)
56da6c28aaSamw {
57f96bd5c8SAlan Wright 	struct open_param	*op = &sr->arg.open;
58f96bd5c8SAlan Wright 	char			*path;
59f96bd5c8SAlan Wright 	char			*identifier;
60148c5f43SAlan Wright 	uint32_t		new_id;
61f96bd5c8SAlan Wright 	uint16_t		setup;
62f96bd5c8SAlan Wright 	uint16_t		mode;
63f96bd5c8SAlan Wright 	int			rc;
64*cb174861Sjoyce mcintosh 	static uint32_t		tmp_id = 10000;
65f96bd5c8SAlan Wright 
66f96bd5c8SAlan Wright 	bzero(op, sizeof (sr->arg.open));
67f96bd5c8SAlan Wright 	rc = smbsr_decode_vwv(sr, "ww", &setup, &mode);
68f96bd5c8SAlan Wright 	if (rc == 0)
69f96bd5c8SAlan Wright 		rc = smbsr_decode_data(sr, "%S", sr, &identifier);
70f96bd5c8SAlan Wright 
71148c5f43SAlan Wright 	if (rc == 0) {
729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		path = smb_srm_zalloc(sr, MAXPATHLEN);
73f96bd5c8SAlan Wright 		op->fqi.fq_path.pn_path = path;
74148c5f43SAlan Wright 		new_id = atomic_inc_32_nv(&tmp_id);
75148c5f43SAlan Wright 		(void) snprintf(path, MAXPATHLEN, "%s%05u", identifier, new_id);
76148c5f43SAlan Wright 	}
77f96bd5c8SAlan Wright 
78f96bd5c8SAlan Wright 	op->create_disposition = FILE_OVERWRITE_IF;
79f96bd5c8SAlan Wright 	op->create_options = FILE_NON_DIRECTORY_FILE;
80f96bd5c8SAlan Wright 	DTRACE_SMB_2(op__OpenPrintFile__start, smb_request_t *, sr,
81f96bd5c8SAlan Wright 	    struct open_param *, op);
82f96bd5c8SAlan Wright 
83f96bd5c8SAlan Wright 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
84faa1795aSjb150015 }
85faa1795aSjb150015 
86faa1795aSjb150015 void
87faa1795aSjb150015 smb_post_open_print_file(smb_request_t *sr)
88faa1795aSjb150015 {
89faa1795aSjb150015 	DTRACE_SMB_1(op__OpenPrintFile__done, smb_request_t *, sr);
90faa1795aSjb150015 }
91faa1795aSjb150015 
92*cb174861Sjoyce mcintosh /*
93*cb174861Sjoyce mcintosh  * Creates a new spool file which will be later copied and
94*cb174861Sjoyce mcintosh  * deleted by cupsd.  After the file is created, information
95*cb174861Sjoyce mcintosh  * related to the file will be placed in a spooldoc list
96*cb174861Sjoyce mcintosh  * to be later used by cupsd
97*cb174861Sjoyce mcintosh  *
98*cb174861Sjoyce mcintosh  * Return values
99*cb174861Sjoyce mcintosh  * 	rc 0 SDRC_SUCCESS
100*cb174861Sjoyce mcintosh  *	rc non-zero SDRC_ERROR
101*cb174861Sjoyce mcintosh  */
102*cb174861Sjoyce mcintosh 
103f96bd5c8SAlan Wright smb_sdrc_t
104faa1795aSjb150015 smb_com_open_print_file(smb_request_t *sr)
105faa1795aSjb150015 {
106f96bd5c8SAlan Wright 	int 		rc;
107*cb174861Sjoyce mcintosh 	smb_kspooldoc_t *sp;
108*cb174861Sjoyce mcintosh 	smb_kshare_t 	*si;
109*cb174861Sjoyce mcintosh 	struct open_param *op = &sr->arg.open;
110f96bd5c8SAlan Wright 
111f96bd5c8SAlan Wright 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
112*cb174861Sjoyce mcintosh 		cmn_err(CE_WARN, "smb_com_open_print_file: bad device");
113f96bd5c8SAlan Wright 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
114f96bd5c8SAlan Wright 		    ERRDOS, ERROR_BAD_DEV_TYPE);
115f96bd5c8SAlan Wright 		return (SDRC_ERROR);
116da6c28aaSamw 	}
117*cb174861Sjoyce mcintosh 	if ((rc = smb_common_create(sr)) != NT_STATUS_SUCCESS) {
118*cb174861Sjoyce mcintosh 		cmn_err(CE_WARN, "smb_com_open_print_file: error rc=%d", rc);
119f96bd5c8SAlan Wright 		return (SDRC_ERROR);
120*cb174861Sjoyce mcintosh 	}
121*cb174861Sjoyce mcintosh 	if ((rc = smbsr_encode_result(sr, 1, 0,
122*cb174861Sjoyce mcintosh 	    "bww", 1, sr->smb_fid, 0)) == 0) {
123*cb174861Sjoyce mcintosh 		if ((si = smb_kshare_lookup(SMB_SHARE_PRINT)) == NULL) {
124*cb174861Sjoyce mcintosh 			cmn_err(CE_NOTE, "smb_com_open_print_file: SDRC_ERROR");
125*cb174861Sjoyce mcintosh 			return (SDRC_ERROR);
126*cb174861Sjoyce mcintosh 		}
127*cb174861Sjoyce mcintosh 		sp = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP);
128*cb174861Sjoyce mcintosh 		(void) snprintf(sp->sd_path, MAXPATHLEN, "%s/%s", si->shr_path,
129*cb174861Sjoyce mcintosh 		    op->fqi.fq_path.pn_path);
130*cb174861Sjoyce mcintosh 		sp->sd_spool_num = sr->sr_server->sp_info.sp_cnt;
131*cb174861Sjoyce mcintosh 		sp->sd_ipaddr = sr->session->ipaddr;
132*cb174861Sjoyce mcintosh 		(void) strlcpy(sp->sd_username, sr->uid_user->u_name,
133*cb174861Sjoyce mcintosh 		    MAXNAMELEN);
134*cb174861Sjoyce mcintosh 		sp->sd_fid = sr->smb_fid;
135*cb174861Sjoyce mcintosh 		if (smb_spool_add_doc(sp))
136*cb174861Sjoyce mcintosh 			kmem_free(sp, sizeof (smb_kspooldoc_t));
137*cb174861Sjoyce mcintosh 		smb_kshare_release(si);
138*cb174861Sjoyce mcintosh 	}
139f96bd5c8SAlan Wright 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
140f96bd5c8SAlan Wright }
141da6c28aaSamw 
142da6c28aaSamw /*
143f96bd5c8SAlan Wright  * Close the specified file handle and queue the file for printing.
144f96bd5c8SAlan Wright  * The fid refers to a file previously created as a print spool file.
145da6c28aaSamw  * On successful completion of this request, the file is queued for
146da6c28aaSamw  * printing by the server.
147da6c28aaSamw  *
148f96bd5c8SAlan Wright  * Servers that negotiate LANMAN1.0 or later allow all the the fid
149f96bd5c8SAlan Wright  * to be closed and printed via any close request.
150da6c28aaSamw  */
151faa1795aSjb150015 smb_sdrc_t
152faa1795aSjb150015 smb_pre_close_print_file(smb_request_t *sr)
153da6c28aaSamw {
154f96bd5c8SAlan Wright 	int rc;
155f96bd5c8SAlan Wright 
156f96bd5c8SAlan Wright 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
157f96bd5c8SAlan Wright 
158faa1795aSjb150015 	DTRACE_SMB_1(op__ClosePrintFile__start, smb_request_t *, sr);
159f96bd5c8SAlan Wright 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
160faa1795aSjb150015 }
161faa1795aSjb150015 
162faa1795aSjb150015 void
163faa1795aSjb150015 smb_post_close_print_file(smb_request_t *sr)
164faa1795aSjb150015 {
165faa1795aSjb150015 	DTRACE_SMB_1(op__ClosePrintFile__done, smb_request_t *, sr);
166faa1795aSjb150015 }
167faa1795aSjb150015 
168*cb174861Sjoyce mcintosh /*
169*cb174861Sjoyce mcintosh  *
170*cb174861Sjoyce mcintosh  * Adds the print file fid to a list to be used as a search
171*cb174861Sjoyce mcintosh  * key in the spooldoc list.  It then wakes up the smbd
172*cb174861Sjoyce mcintosh  * spool monitor thread to copy the spool file.
173*cb174861Sjoyce mcintosh  *
174*cb174861Sjoyce mcintosh  * Return values
175*cb174861Sjoyce mcintosh  * rc - 0 success
176*cb174861Sjoyce mcintosh  *
177*cb174861Sjoyce mcintosh  */
178*cb174861Sjoyce mcintosh 
179f96bd5c8SAlan Wright smb_sdrc_t
180faa1795aSjb150015 smb_com_close_print_file(smb_request_t *sr)
181faa1795aSjb150015 {
182*cb174861Sjoyce mcintosh 	smb_sdrc_t rc;
183*cb174861Sjoyce mcintosh 
184f96bd5c8SAlan Wright 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
185f96bd5c8SAlan Wright 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
186f96bd5c8SAlan Wright 		    ERRDOS, ERROR_BAD_DEV_TYPE);
187*cb174861Sjoyce mcintosh 		cmn_err(CE_WARN, "smb_com_close_print_file: SDRC_ERROR");
188f96bd5c8SAlan Wright 		return (SDRC_ERROR);
189da6c28aaSamw 	}
190*cb174861Sjoyce mcintosh 	rc = smb_com_close(sr);
191da6c28aaSamw 
192*cb174861Sjoyce mcintosh 	(void) smb_spool_add_fid(sr->smb_fid);
193*cb174861Sjoyce mcintosh 	cv_broadcast(&sr->sr_server->sp_info.sp_cv);
194*cb174861Sjoyce mcintosh 
195*cb174861Sjoyce mcintosh 	return (rc);
196f96bd5c8SAlan Wright }
197da6c28aaSamw 
198da6c28aaSamw /*
199f96bd5c8SAlan Wright  * Get a list of print queue entries on the server.  Support for
200f96bd5c8SAlan Wright  * this request is optional (not required for Windows clients).
201da6c28aaSamw  */
2027b59d02dSjb150015 smb_sdrc_t
203faa1795aSjb150015 smb_pre_get_print_queue(smb_request_t *sr)
204faa1795aSjb150015 {
205faa1795aSjb150015 	DTRACE_SMB_1(op__GetPrintQueue__start, smb_request_t *, sr);
206faa1795aSjb150015 	return (SDRC_SUCCESS);
207faa1795aSjb150015 }
208faa1795aSjb150015 
209faa1795aSjb150015 void
210faa1795aSjb150015 smb_post_get_print_queue(smb_request_t *sr)
211faa1795aSjb150015 {
212faa1795aSjb150015 	DTRACE_SMB_1(op__GetPrintQueue__done, smb_request_t *, sr);
213faa1795aSjb150015 }
214faa1795aSjb150015 
215faa1795aSjb150015 smb_sdrc_t
216faa1795aSjb150015 smb_com_get_print_queue(smb_request_t *sr)
217da6c28aaSamw {
218da6c28aaSamw 	unsigned short max_count, start_ix;
219da6c28aaSamw 
2207b59d02dSjb150015 	if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0)
221faa1795aSjb150015 		return (SDRC_ERROR);
222da6c28aaSamw 
2237b59d02dSjb150015 	if (smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0))
224faa1795aSjb150015 		return (SDRC_ERROR);
2257b59d02dSjb150015 
226faa1795aSjb150015 	return (SDRC_SUCCESS);
227da6c28aaSamw }
228da6c28aaSamw 
229da6c28aaSamw /*
230f96bd5c8SAlan Wright  * Write (append) data to a print spool file.  The fid must refer to
231f96bd5c8SAlan Wright  * a print spool file.
232da6c28aaSamw  *
233f96bd5c8SAlan Wright  * The first SetupLength bytes (see SMB_COM_OPEN_PRINT_FILE) in the
234f96bd5c8SAlan Wright  * print spool file contain printer setup data.
235da6c28aaSamw  *
236f96bd5c8SAlan Wright  * Servers that negotiate LANMAN1.0 or later also support the use of
237f96bd5c8SAlan Wright  * normal write requests with print spool files.
238da6c28aaSamw  */
239faa1795aSjb150015 smb_sdrc_t
240faa1795aSjb150015 smb_pre_write_print_file(smb_request_t *sr)
241da6c28aaSamw {
242f96bd5c8SAlan Wright 	smb_rw_param_t	*param;
243f96bd5c8SAlan Wright 	int		rc;
244f96bd5c8SAlan Wright 
245f96bd5c8SAlan Wright 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
246f96bd5c8SAlan Wright 	sr->arg.rw = param;
247f96bd5c8SAlan Wright 	param->rw_magic = SMB_RW_MAGIC;
248f96bd5c8SAlan Wright 
249f96bd5c8SAlan Wright 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
250f96bd5c8SAlan Wright 
251faa1795aSjb150015 	DTRACE_SMB_1(op__WritePrintFile__start, smb_request_t *, sr);
252f96bd5c8SAlan Wright 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
253faa1795aSjb150015 }
254faa1795aSjb150015 
255faa1795aSjb150015 void
256faa1795aSjb150015 smb_post_write_print_file(smb_request_t *sr)
257faa1795aSjb150015 {
258faa1795aSjb150015 	DTRACE_SMB_1(op__WritePrintFile__done, smb_request_t *, sr);
259f96bd5c8SAlan Wright 
260f96bd5c8SAlan Wright 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
261faa1795aSjb150015 }
262faa1795aSjb150015 
263f96bd5c8SAlan Wright smb_sdrc_t
264faa1795aSjb150015 smb_com_write_print_file(smb_request_t *sr)
265faa1795aSjb150015 {
266f96bd5c8SAlan Wright 	smb_rw_param_t	*param = sr->arg.rw;
267f96bd5c8SAlan Wright 	smb_node_t	*node;
268f96bd5c8SAlan Wright 	smb_attr_t	attr;
269f96bd5c8SAlan Wright 	int		rc;
270f96bd5c8SAlan Wright 
271f96bd5c8SAlan Wright 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
272f96bd5c8SAlan Wright 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
273f96bd5c8SAlan Wright 		    ERRDOS, ERROR_BAD_DEV_TYPE);
274f96bd5c8SAlan Wright 		return (SDRC_ERROR);
275f96bd5c8SAlan Wright 	}
276f96bd5c8SAlan Wright 
277f96bd5c8SAlan Wright 	smbsr_lookup_file(sr);
278f96bd5c8SAlan Wright 	if (sr->fid_ofile == NULL) {
279f96bd5c8SAlan Wright 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
280f96bd5c8SAlan Wright 		return (SDRC_ERROR);
281f96bd5c8SAlan Wright 	}
282f96bd5c8SAlan Wright 
283f96bd5c8SAlan Wright 	node = sr->fid_ofile->f_node;
284f96bd5c8SAlan Wright 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
285f96bd5c8SAlan Wright 
286f96bd5c8SAlan Wright 	if (smb_node_getattr(sr, node, &attr) != 0) {
287f96bd5c8SAlan Wright 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
288f96bd5c8SAlan Wright 		    ERRDOS, ERROR_INTERNAL_ERROR);
289f96bd5c8SAlan Wright 		return (SDRC_ERROR);
290f96bd5c8SAlan Wright 	}
291f96bd5c8SAlan Wright 
292f96bd5c8SAlan Wright 	if ((smbsr_decode_data(sr, "D", &param->rw_vdb)) != 0) {
293f96bd5c8SAlan Wright 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
294f96bd5c8SAlan Wright 		    ERRDOS, ERROR_INVALID_PARAMETER);
295f96bd5c8SAlan Wright 		return (SDRC_ERROR);
296f96bd5c8SAlan Wright 	}
297f96bd5c8SAlan Wright 
298f96bd5c8SAlan Wright 	param->rw_count = param->rw_vdb.vdb_len;
299f96bd5c8SAlan Wright 	param->rw_offset = attr.sa_vattr.va_size;
300f96bd5c8SAlan Wright 	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
301f96bd5c8SAlan Wright 
302f96bd5c8SAlan Wright 	if ((rc = smb_common_write(sr, param)) != 0) {
303f96bd5c8SAlan Wright 		if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
304f96bd5c8SAlan Wright 			smbsr_errno(sr, rc);
305f96bd5c8SAlan Wright 		return (SDRC_ERROR);
306f96bd5c8SAlan Wright 	}
307f96bd5c8SAlan Wright 
308f96bd5c8SAlan Wright 	rc = smbsr_encode_empty_result(sr);
309f96bd5c8SAlan Wright 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
310da6c28aaSamw }
311