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