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