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