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 */
24
25/*
26 * SMB print interface.
27 */
28
29#include <smbsrv/smb_kproto.h>
30#include <sys/unistd.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <sys/fcntl.h>
34#include <smbsrv/smb_share.h>
35
36/*
37 * Starts the creation of a new printer file, which will be deleted
38 * automatically once it has been closed and printed.
39 *
40 * SetupLength is the number of bytes in the first part of the resulting
41 * print spool file which contains printer-specific control strings.
42 *
43 * Mode can have the following values:
44 *      0     Text mode.  The server may optionally
45 *            expand tabs to a series of spaces.
46 *      1     Graphics mode.  No conversion of data
47 *            should be done by the server.
48 *
49 * IdentifierString can be used by the server to provide some sort of
50 * per-client identifying component to the print file.
51 *
52 * When the file is closed, it will be sent to the spooler and printed.
53 */
54smb_sdrc_t
55smb_pre_open_print_file(smb_request_t *sr)
56{
57	struct open_param	*op = &sr->arg.open;
58	char			*path;
59	char			*identifier;
60	uint32_t		new_id;
61	uint16_t		setup;
62	uint16_t		mode;
63	int			rc;
64	static uint32_t		tmp_id = 10000;
65
66	bzero(op, sizeof (sr->arg.open));
67	rc = smbsr_decode_vwv(sr, "ww", &setup, &mode);
68	if (rc == 0)
69		rc = smbsr_decode_data(sr, "%S", sr, &identifier);
70
71	if (rc == 0) {
72		path = smb_srm_zalloc(sr, MAXPATHLEN);
73		op->fqi.fq_path.pn_path = path;
74		new_id = atomic_inc_32_nv(&tmp_id);
75		(void) snprintf(path, MAXPATHLEN, "%s%05u", identifier, new_id);
76	}
77
78	op->create_disposition = FILE_OVERWRITE_IF;
79	op->create_options = FILE_NON_DIRECTORY_FILE;
80	DTRACE_SMB_2(op__OpenPrintFile__start, smb_request_t *, sr,
81	    struct open_param *, op);
82
83	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
84}
85
86void
87smb_post_open_print_file(smb_request_t *sr)
88{
89	DTRACE_SMB_1(op__OpenPrintFile__done, 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
103smb_sdrc_t
104smb_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 (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
112		cmn_err(CE_WARN, "smb_com_open_print_file: bad device");
113		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
114		    ERRDOS, ERROR_BAD_DEV_TYPE);
115		return (SDRC_ERROR);
116	}
117	if ((rc = smb_common_create(sr)) != NT_STATUS_SUCCESS) {
118		cmn_err(CE_WARN, "smb_com_open_print_file: error rc=%d", rc);
119		return (SDRC_ERROR);
120	}
121	if ((rc = smbsr_encode_result(sr, 1, 0,
122	    "bww", 1, sr->smb_fid, 0)) == 0) {
123		if ((si = smb_kshare_lookup(SMB_SHARE_PRINT)) == NULL) {
124			cmn_err(CE_NOTE, "smb_com_open_print_file: SDRC_ERROR");
125			return (SDRC_ERROR);
126		}
127		sp = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP);
128		(void) snprintf(sp->sd_path, MAXPATHLEN, "%s/%s", si->shr_path,
129		    op->fqi.fq_path.pn_path);
130		sp->sd_spool_num = sr->sr_server->sp_info.sp_cnt;
131		sp->sd_ipaddr = sr->session->ipaddr;
132		(void) strlcpy(sp->sd_username, sr->uid_user->u_name,
133		    MAXNAMELEN);
134		sp->sd_fid = sr->smb_fid;
135		if (smb_spool_add_doc(sp))
136			kmem_free(sp, sizeof (smb_kspooldoc_t));
137		smb_kshare_release(si);
138	}
139	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
140}
141
142/*
143 * Close the specified file handle and queue the file for printing.
144 * The fid refers to a file previously created as a print spool file.
145 * On successful completion of this request, the file is queued for
146 * printing by the server.
147 *
148 * Servers that negotiate LANMAN1.0 or later allow all the the fid
149 * to be closed and printed via any close request.
150 */
151smb_sdrc_t
152smb_pre_close_print_file(smb_request_t *sr)
153{
154	int rc;
155
156	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
157
158	DTRACE_SMB_1(op__ClosePrintFile__start, smb_request_t *, sr);
159	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
160}
161
162void
163smb_post_close_print_file(smb_request_t *sr)
164{
165	DTRACE_SMB_1(op__ClosePrintFile__done, smb_request_t *, sr);
166}
167
168/*
169 *
170 * Adds the print file fid to a list to be used as a search
171 * key in the spooldoc list.  It then wakes up the smbd
172 * spool monitor thread to copy the spool file.
173 *
174 * Return values
175 * rc - 0 success
176 *
177 */
178
179smb_sdrc_t
180smb_com_close_print_file(smb_request_t *sr)
181{
182	smb_sdrc_t rc;
183
184	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
185		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
186		    ERRDOS, ERROR_BAD_DEV_TYPE);
187		cmn_err(CE_WARN, "smb_com_close_print_file: SDRC_ERROR");
188		return (SDRC_ERROR);
189	}
190	rc = smb_com_close(sr);
191
192	(void) smb_spool_add_fid(sr->smb_fid);
193	cv_broadcast(&sr->sr_server->sp_info.sp_cv);
194
195	return (rc);
196}
197
198/*
199 * Get a list of print queue entries on the server.  Support for
200 * this request is optional (not required for Windows clients).
201 */
202smb_sdrc_t
203smb_pre_get_print_queue(smb_request_t *sr)
204{
205	DTRACE_SMB_1(op__GetPrintQueue__start, smb_request_t *, sr);
206	return (SDRC_SUCCESS);
207}
208
209void
210smb_post_get_print_queue(smb_request_t *sr)
211{
212	DTRACE_SMB_1(op__GetPrintQueue__done, smb_request_t *, sr);
213}
214
215smb_sdrc_t
216smb_com_get_print_queue(smb_request_t *sr)
217{
218	unsigned short max_count, start_ix;
219
220	if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0)
221		return (SDRC_ERROR);
222
223	if (smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0))
224		return (SDRC_ERROR);
225
226	return (SDRC_SUCCESS);
227}
228
229/*
230 * Write (append) data to a print spool file.  The fid must refer to
231 * a print spool file.
232 *
233 * The first SetupLength bytes (see SMB_COM_OPEN_PRINT_FILE) in the
234 * print spool file contain printer setup data.
235 *
236 * Servers that negotiate LANMAN1.0 or later also support the use of
237 * normal write requests with print spool files.
238 */
239smb_sdrc_t
240smb_pre_write_print_file(smb_request_t *sr)
241{
242	smb_rw_param_t	*param;
243	int		rc;
244
245	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
246	sr->arg.rw = param;
247	param->rw_magic = SMB_RW_MAGIC;
248
249	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
250
251	DTRACE_SMB_1(op__WritePrintFile__start, smb_request_t *, sr);
252	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
253}
254
255void
256smb_post_write_print_file(smb_request_t *sr)
257{
258	DTRACE_SMB_1(op__WritePrintFile__done, smb_request_t *, sr);
259
260	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
261}
262
263smb_sdrc_t
264smb_com_write_print_file(smb_request_t *sr)
265{
266	smb_rw_param_t	*param = sr->arg.rw;
267	smb_node_t	*node;
268	smb_attr_t	attr;
269	int		rc;
270
271	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
272		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
273		    ERRDOS, ERROR_BAD_DEV_TYPE);
274		return (SDRC_ERROR);
275	}
276
277	smbsr_lookup_file(sr);
278	if (sr->fid_ofile == NULL) {
279		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
280		return (SDRC_ERROR);
281	}
282
283	node = sr->fid_ofile->f_node;
284	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
285
286	if (smb_node_getattr(sr, node, &attr) != 0) {
287		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
288		    ERRDOS, ERROR_INTERNAL_ERROR);
289		return (SDRC_ERROR);
290	}
291
292	if ((smbsr_decode_data(sr, "D", &param->rw_vdb)) != 0) {
293		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
294		    ERRDOS, ERROR_INVALID_PARAMETER);
295		return (SDRC_ERROR);
296	}
297
298	param->rw_count = param->rw_vdb.vdb_len;
299	param->rw_offset = attr.sa_vattr.va_size;
300	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
301
302	if ((rc = smb_common_write(sr, param)) != 0) {
303		if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
304			smbsr_errno(sr, rc);
305		return (SDRC_ERROR);
306	}
307
308	rc = smbsr_encode_empty_result(sr);
309	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
310}
311