xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_print.c (revision 4a3b1d5b615ff6e54da1cc17f331e1ac794c5191)
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 (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 		if ((si = smb_kshare_lookup(SMB_SHARE_PRINT)) == 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(sp))
138 			kmem_free(sp, sizeof (smb_kspooldoc_t));
139 		smb_kshare_release(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_1(op__ClosePrintFile__start, 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_1(op__ClosePrintFile__done, 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 	if (sr->sr_server->sv_cfg.skc_print_enable == 0 ||
187 	    !STYPE_ISPRN(sr->tid_tree->t_res_type)) {
188 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
189 		    ERRDOS, ERROR_BAD_DEV_TYPE);
190 		cmn_err(CE_WARN, "smb_com_close_print_file: SDRC_ERROR");
191 		return (SDRC_ERROR);
192 	}
193 	rc = smb_com_close(sr);
194 
195 	(void) smb_spool_add_fid(sr->smb_fid);
196 	cv_broadcast(&sr->sr_server->sp_info.sp_cv);
197 
198 	return (rc);
199 }
200 
201 /*
202  * Get a list of print queue entries on the server.  Support for
203  * this request is optional (not required for Windows clients).
204  */
205 smb_sdrc_t
206 smb_pre_get_print_queue(smb_request_t *sr)
207 {
208 	DTRACE_SMB_1(op__GetPrintQueue__start, smb_request_t *, sr);
209 	return (SDRC_SUCCESS);
210 }
211 
212 void
213 smb_post_get_print_queue(smb_request_t *sr)
214 {
215 	DTRACE_SMB_1(op__GetPrintQueue__done, smb_request_t *, sr);
216 }
217 
218 smb_sdrc_t
219 smb_com_get_print_queue(smb_request_t *sr)
220 {
221 	unsigned short max_count, start_ix;
222 
223 	if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0)
224 		return (SDRC_ERROR);
225 
226 	if (smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0))
227 		return (SDRC_ERROR);
228 
229 	return (SDRC_SUCCESS);
230 }
231 
232 /*
233  * Write (append) data to a print spool file.  The fid must refer to
234  * a print spool file.
235  *
236  * The first SetupLength bytes (see SMB_COM_OPEN_PRINT_FILE) in the
237  * print spool file contain printer setup data.
238  *
239  * Servers that negotiate LANMAN1.0 or later also support the use of
240  * normal write requests with print spool files.
241  */
242 smb_sdrc_t
243 smb_pre_write_print_file(smb_request_t *sr)
244 {
245 	smb_rw_param_t	*param;
246 	int		rc;
247 
248 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
249 	sr->arg.rw = param;
250 	param->rw_magic = SMB_RW_MAGIC;
251 
252 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
253 
254 	DTRACE_SMB_1(op__WritePrintFile__start, smb_request_t *, sr);
255 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
256 }
257 
258 void
259 smb_post_write_print_file(smb_request_t *sr)
260 {
261 	DTRACE_SMB_1(op__WritePrintFile__done, smb_request_t *, sr);
262 
263 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
264 }
265 
266 smb_sdrc_t
267 smb_com_write_print_file(smb_request_t *sr)
268 {
269 	smb_rw_param_t	*param = sr->arg.rw;
270 	smb_node_t	*node;
271 	smb_attr_t	attr;
272 	int		rc;
273 
274 	if (sr->sr_server->sv_cfg.skc_print_enable == 0 ||
275 	    !STYPE_ISPRN(sr->tid_tree->t_res_type)) {
276 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
277 		    ERRDOS, ERROR_BAD_DEV_TYPE);
278 		return (SDRC_ERROR);
279 	}
280 
281 	smbsr_lookup_file(sr);
282 	if (sr->fid_ofile == NULL) {
283 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
284 		return (SDRC_ERROR);
285 	}
286 
287 	node = sr->fid_ofile->f_node;
288 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
289 
290 	if (smb_node_getattr(sr, node, &attr) != 0) {
291 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
292 		    ERRDOS, ERROR_INTERNAL_ERROR);
293 		return (SDRC_ERROR);
294 	}
295 
296 	if ((smbsr_decode_data(sr, "D", &param->rw_vdb)) != 0) {
297 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
298 		    ERRDOS, ERROR_INVALID_PARAMETER);
299 		return (SDRC_ERROR);
300 	}
301 
302 	param->rw_count = param->rw_vdb.vdb_len;
303 	param->rw_offset = attr.sa_vattr.va_size;
304 	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
305 
306 	if ((rc = smb_common_write(sr, param)) != 0) {
307 		if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
308 			smbsr_errno(sr, rc);
309 		return (SDRC_ERROR);
310 	}
311 
312 	rc = smbsr_encode_empty_result(sr);
313 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
314 }
315