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  */
54 smb_sdrc_t
55 smb_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 
86 void
87 smb_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 
103 smb_sdrc_t
104 smb_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  */
151 smb_sdrc_t
152 smb_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 
162 void
163 smb_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 
179 smb_sdrc_t
180 smb_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  */
202 smb_sdrc_t
203 smb_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 
209 void
210 smb_post_get_print_queue(smb_request_t *sr)
211 {
212 	DTRACE_SMB_1(op__GetPrintQueue__done, smb_request_t *, sr);
213 }
214 
215 smb_sdrc_t
216 smb_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  */
239 smb_sdrc_t
240 smb_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 
255 void
256 smb_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 
263 smb_sdrc_t
264 smb_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