xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_print.c (revision 3ba944265c4ae1fcf23ef758537c2e4f4feec16e)
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 2013 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_2(op__OpenPrintFile__start, smb_request_t *, sr,
82 	    struct open_param *, op);
83 
84 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
85 }
86 
87 void
88 smb_post_open_print_file(smb_request_t *sr)
89 {
90 	DTRACE_SMB_1(op__OpenPrintFile__done, smb_request_t *, sr);
91 }
92 
93 /*
94  * Creates a new spool file which will be later copied and
95  * deleted by cupsd.  After the file is created, information
96  * related to the file will be placed in a spooldoc list
97  * to be later used by cupsd
98  *
99  * Return values
100  * 	rc 0 SDRC_SUCCESS
101  *	rc non-zero SDRC_ERROR
102  */
103 
104 smb_sdrc_t
105 smb_com_open_print_file(smb_request_t *sr)
106 {
107 	int 		rc;
108 	smb_kspooldoc_t *sp;
109 	smb_kshare_t 	*si;
110 	struct open_param *op = &sr->arg.open;
111 
112 	if (sr->sr_server->sv_cfg.skc_print_enable == 0 ||
113 	    !STYPE_ISPRN(sr->tid_tree->t_res_type)) {
114 		cmn_err(CE_WARN, "smb_com_open_print_file: bad device");
115 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
116 		    ERRDOS, ERROR_BAD_DEV_TYPE);
117 		return (SDRC_ERROR);
118 	}
119 	if ((rc = smb_common_create(sr)) != NT_STATUS_SUCCESS) {
120 		cmn_err(CE_WARN, "smb_com_open_print_file: error rc=%d", rc);
121 		return (SDRC_ERROR);
122 	}
123 	if ((rc = smbsr_encode_result(sr, 1, 0,
124 	    "bww", 1, sr->smb_fid, 0)) == 0) {
125 		si = smb_kshare_lookup(sr->sr_server, SMB_SHARE_PRINT);
126 		if (si == NULL) {
127 			cmn_err(CE_NOTE, "smb_com_open_print_file: SDRC_ERROR");
128 			return (SDRC_ERROR);
129 		}
130 		sp = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP);
131 		(void) snprintf(sp->sd_path, MAXPATHLEN, "%s/%s", si->shr_path,
132 		    op->fqi.fq_path.pn_path);
133 		/* sp->sd_spool_num set by smb_spool_add_doc() */
134 		sp->sd_ipaddr = sr->session->ipaddr;
135 		(void) strlcpy(sp->sd_username, sr->uid_user->u_name,
136 		    MAXNAMELEN);
137 		sp->sd_fid = sr->smb_fid;
138 		if (smb_spool_add_doc(sr->tid_tree, sp))
139 			kmem_free(sp, sizeof (smb_kspooldoc_t));
140 		smb_kshare_release(sr->sr_server, si);
141 	}
142 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
143 }
144 
145 /*
146  * Close the specified file handle and queue the file for printing.
147  * The fid refers to a file previously created as a print spool file.
148  * On successful completion of this request, the file is queued for
149  * printing by the server.
150  *
151  * Servers that negotiate LANMAN1.0 or later allow all the the fid
152  * to be closed and printed via any close request.
153  */
154 smb_sdrc_t
155 smb_pre_close_print_file(smb_request_t *sr)
156 {
157 	int rc;
158 
159 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
160 
161 	DTRACE_SMB_1(op__ClosePrintFile__start, smb_request_t *, sr);
162 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
163 }
164 
165 void
166 smb_post_close_print_file(smb_request_t *sr)
167 {
168 	DTRACE_SMB_1(op__ClosePrintFile__done, smb_request_t *, sr);
169 }
170 
171 /*
172  *
173  * Adds the print file fid to a list to be used as a search
174  * key in the spooldoc list.  It then wakes up the smbd
175  * spool monitor thread to copy the spool file.
176  *
177  * Return values
178  * rc - 0 success
179  *
180  */
181 
182 smb_sdrc_t
183 smb_com_close_print_file(smb_request_t *sr)
184 {
185 	smb_sdrc_t rc;
186 
187 	/*
188 	 * If sv_cfg.skc_print_enable somehow went false while
189 	 * we have a print FID open, close the FID.  In this
190 	 * situation, smb_spool_add_fid() will do nothing.
191 	 */
192 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
193 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
194 		    ERRDOS, ERROR_BAD_DEV_TYPE);
195 		cmn_err(CE_WARN, "smb_com_close_print_file: SDRC_ERROR");
196 		return (SDRC_ERROR);
197 	}
198 	rc = smb_com_close(sr);
199 
200 	smb_spool_add_fid(sr->sr_server, sr->smb_fid);
201 
202 	return (rc);
203 }
204 
205 /*
206  * Get a list of print queue entries on the server.  Support for
207  * this request is optional (not required for Windows clients).
208  */
209 smb_sdrc_t
210 smb_pre_get_print_queue(smb_request_t *sr)
211 {
212 	DTRACE_SMB_1(op__GetPrintQueue__start, smb_request_t *, sr);
213 	return (SDRC_SUCCESS);
214 }
215 
216 void
217 smb_post_get_print_queue(smb_request_t *sr)
218 {
219 	DTRACE_SMB_1(op__GetPrintQueue__done, smb_request_t *, sr);
220 }
221 
222 smb_sdrc_t
223 smb_com_get_print_queue(smb_request_t *sr)
224 {
225 	unsigned short max_count, start_ix;
226 
227 	if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0)
228 		return (SDRC_ERROR);
229 
230 	if (smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0))
231 		return (SDRC_ERROR);
232 
233 	return (SDRC_SUCCESS);
234 }
235 
236 /*
237  * Write (append) data to a print spool file.  The fid must refer to
238  * a print spool file.
239  *
240  * The first SetupLength bytes (see SMB_COM_OPEN_PRINT_FILE) in the
241  * print spool file contain printer setup data.
242  *
243  * Servers that negotiate LANMAN1.0 or later also support the use of
244  * normal write requests with print spool files.
245  */
246 smb_sdrc_t
247 smb_pre_write_print_file(smb_request_t *sr)
248 {
249 	smb_rw_param_t	*param;
250 	int		rc;
251 
252 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
253 	sr->arg.rw = param;
254 	param->rw_magic = SMB_RW_MAGIC;
255 
256 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
257 
258 	DTRACE_SMB_1(op__WritePrintFile__start, smb_request_t *, sr);
259 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
260 }
261 
262 void
263 smb_post_write_print_file(smb_request_t *sr)
264 {
265 	DTRACE_SMB_1(op__WritePrintFile__done, smb_request_t *, sr);
266 
267 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
268 }
269 
270 smb_sdrc_t
271 smb_com_write_print_file(smb_request_t *sr)
272 {
273 	smb_rw_param_t	*param = sr->arg.rw;
274 	smb_node_t	*node;
275 	smb_attr_t	attr;
276 	int		rc;
277 
278 	if (sr->sr_server->sv_cfg.skc_print_enable == 0 ||
279 	    !STYPE_ISPRN(sr->tid_tree->t_res_type)) {
280 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
281 		    ERRDOS, ERROR_BAD_DEV_TYPE);
282 		return (SDRC_ERROR);
283 	}
284 
285 	smbsr_lookup_file(sr);
286 	if (sr->fid_ofile == NULL) {
287 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
288 		return (SDRC_ERROR);
289 	}
290 
291 	node = sr->fid_ofile->f_node;
292 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
293 
294 	bzero(&attr, sizeof (attr));
295 	attr.sa_mask = SMB_AT_SIZE;
296 	rc = smb_node_getattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
297 	if (rc != 0) {
298 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
299 		    ERRDOS, ERROR_INTERNAL_ERROR);
300 		return (SDRC_ERROR);
301 	}
302 
303 	if ((smbsr_decode_data(sr, "D", &param->rw_vdb)) != 0) {
304 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
305 		    ERRDOS, ERROR_INVALID_PARAMETER);
306 		return (SDRC_ERROR);
307 	}
308 
309 	param->rw_count = param->rw_vdb.vdb_len;
310 	param->rw_offset = attr.sa_vattr.va_size;
311 	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
312 
313 	if ((rc = smb_common_write(sr, param)) != 0) {
314 		if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
315 			smbsr_errno(sr, rc);
316 		return (SDRC_ERROR);
317 	}
318 
319 	rc = smbsr_encode_empty_result(sr);
320 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
321 }
322