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 
31 /*
32  * Create a new printer file, which should be deleted automatically once
33  * it has been closed and printed.
34  *
35  * SetupLength is the number of bytes in the first part of the resulting
36  * print spool file which contains printer-specific control strings.
37  *
38  * Mode can have the following values:
39  *      0     Text mode.  The server may optionally
40  *            expand tabs to a series of spaces.
41  *      1     Graphics mode.  No conversion of data
42  *            should be done by the server.
43  *
44  * IdentifierString can be used by the server to provide some sort of
45  * per-client identifying component to the print file.
46  *
47  * When the file is closed, it will be sent to the spooler and printed.
48  */
49 smb_sdrc_t
50 smb_pre_open_print_file(smb_request_t *sr)
51 {
52 	static uint32_t		tmp_id = 10000;
53 	struct open_param	*op = &sr->arg.open;
54 	char			*path;
55 	char			*identifier;
56 	uint32_t		new_id;
57 	uint16_t		setup;
58 	uint16_t		mode;
59 	int			rc;
60 
61 	bzero(op, sizeof (sr->arg.open));
62 
63 	rc = smbsr_decode_vwv(sr, "ww", &setup, &mode);
64 	if (rc == 0)
65 		rc = smbsr_decode_data(sr, "%S", sr, &identifier);
66 
67 	if (rc == 0) {
68 		path = smb_srm_zalloc(sr, MAXPATHLEN);
69 		op->fqi.fq_path.pn_path = path;
70 		new_id = atomic_inc_32_nv(&tmp_id);
71 		(void) snprintf(path, MAXPATHLEN, "%s%05u", identifier, new_id);
72 	}
73 
74 	op->create_disposition = FILE_OVERWRITE_IF;
75 	op->create_options = FILE_NON_DIRECTORY_FILE;
76 
77 	DTRACE_SMB_2(op__OpenPrintFile__start, smb_request_t *, sr,
78 	    struct open_param *, op);
79 
80 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
81 }
82 
83 void
84 smb_post_open_print_file(smb_request_t *sr)
85 {
86 	DTRACE_SMB_1(op__OpenPrintFile__done, smb_request_t *, sr);
87 }
88 
89 smb_sdrc_t
90 smb_com_open_print_file(smb_request_t *sr)
91 {
92 	int rc;
93 
94 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
95 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
96 		    ERRDOS, ERROR_BAD_DEV_TYPE);
97 		return (SDRC_ERROR);
98 	}
99 
100 	if (smb_common_create(sr) != NT_STATUS_SUCCESS)
101 		return (SDRC_ERROR);
102 
103 	rc = smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0);
104 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
105 }
106 
107 /*
108  * Close the specified file handle and queue the file for printing.
109  * The fid refers to a file previously created as a print spool file.
110  * On successful completion of this request, the file is queued for
111  * printing by the server.
112  *
113  * Servers that negotiate LANMAN1.0 or later allow all the the fid
114  * to be closed and printed via any close request.
115  */
116 smb_sdrc_t
117 smb_pre_close_print_file(smb_request_t *sr)
118 {
119 	int rc;
120 
121 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
122 
123 	DTRACE_SMB_1(op__ClosePrintFile__start, smb_request_t *, sr);
124 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
125 }
126 
127 void
128 smb_post_close_print_file(smb_request_t *sr)
129 {
130 	DTRACE_SMB_1(op__ClosePrintFile__done, smb_request_t *, sr);
131 }
132 
133 smb_sdrc_t
134 smb_com_close_print_file(smb_request_t *sr)
135 {
136 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
137 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
138 		    ERRDOS, ERROR_BAD_DEV_TYPE);
139 		return (SDRC_ERROR);
140 	}
141 
142 	return (smb_com_close(sr));
143 }
144 
145 /*
146  * Get a list of print queue entries on the server.  Support for
147  * this request is optional (not required for Windows clients).
148  */
149 smb_sdrc_t
150 smb_pre_get_print_queue(smb_request_t *sr)
151 {
152 	DTRACE_SMB_1(op__GetPrintQueue__start, smb_request_t *, sr);
153 	return (SDRC_SUCCESS);
154 }
155 
156 void
157 smb_post_get_print_queue(smb_request_t *sr)
158 {
159 	DTRACE_SMB_1(op__GetPrintQueue__done, smb_request_t *, sr);
160 }
161 
162 smb_sdrc_t
163 smb_com_get_print_queue(smb_request_t *sr)
164 {
165 	unsigned short max_count, start_ix;
166 
167 	if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0)
168 		return (SDRC_ERROR);
169 
170 	if (smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0))
171 		return (SDRC_ERROR);
172 
173 	return (SDRC_SUCCESS);
174 }
175 
176 /*
177  * Write (append) data to a print spool file.  The fid must refer to
178  * a print spool file.
179  *
180  * The first SetupLength bytes (see SMB_COM_OPEN_PRINT_FILE) in the
181  * print spool file contain printer setup data.
182  *
183  * Servers that negotiate LANMAN1.0 or later also support the use of
184  * normal write requests with print spool files.
185  */
186 smb_sdrc_t
187 smb_pre_write_print_file(smb_request_t *sr)
188 {
189 	smb_rw_param_t	*param;
190 	int		rc;
191 
192 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
193 	sr->arg.rw = param;
194 	param->rw_magic = SMB_RW_MAGIC;
195 
196 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
197 
198 	DTRACE_SMB_1(op__WritePrintFile__start, smb_request_t *, sr);
199 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
200 }
201 
202 void
203 smb_post_write_print_file(smb_request_t *sr)
204 {
205 	DTRACE_SMB_1(op__WritePrintFile__done, smb_request_t *, sr);
206 
207 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
208 }
209 
210 smb_sdrc_t
211 smb_com_write_print_file(smb_request_t *sr)
212 {
213 	smb_rw_param_t	*param = sr->arg.rw;
214 	smb_node_t	*node;
215 	smb_attr_t	attr;
216 	int		rc;
217 
218 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
219 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
220 		    ERRDOS, ERROR_BAD_DEV_TYPE);
221 		return (SDRC_ERROR);
222 	}
223 
224 	smbsr_lookup_file(sr);
225 	if (sr->fid_ofile == NULL) {
226 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
227 		return (SDRC_ERROR);
228 	}
229 
230 	node = sr->fid_ofile->f_node;
231 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
232 
233 	if (smb_node_getattr(sr, node, &attr) != 0) {
234 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
235 		    ERRDOS, ERROR_INTERNAL_ERROR);
236 		return (SDRC_ERROR);
237 	}
238 
239 	if ((smbsr_decode_data(sr, "D", &param->rw_vdb)) != 0) {
240 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
241 		    ERRDOS, ERROR_INVALID_PARAMETER);
242 		return (SDRC_ERROR);
243 	}
244 
245 	param->rw_count = param->rw_vdb.vdb_len;
246 	param->rw_offset = attr.sa_vattr.va_size;
247 	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
248 
249 	if ((rc = smb_common_write(sr, param)) != 0) {
250 		if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
251 			smbsr_errno(sr, rc);
252 		return (SDRC_ERROR);
253 	}
254 
255 	rc = smbsr_encode_empty_result(sr);
256 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
257 }
258