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 2013 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
smb_pre_open_print_file(smb_request_t * sr)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
smb_post_open_print_file(smb_request_t * sr)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
smb_com_open_print_file(smb_request_t * sr)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 si = smb_kshare_lookup(sr->sr_server, SMB_SHARE_PRINT);
126 if (si == NULL) {
127 cmn_err(CE_NOTE, "smb_com_open_print_file: SDRC_ERROR");
128 return (SDRC_ERROR);
129 }
130 sp = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP);
131 (void) snprintf(sp->sd_path, MAXPATHLEN, "%s/%s", si->shr_path,
132 op->fqi.fq_path.pn_path);
133 /* sp->sd_spool_num set by smb_spool_add_doc() */
134 sp->sd_ipaddr = sr->session->ipaddr;
135 (void) strlcpy(sp->sd_username, sr->uid_user->u_name,
136 MAXNAMELEN);
137 sp->sd_fid = sr->smb_fid;
138 if (smb_spool_add_doc(sr->tid_tree, sp))
139 kmem_free(sp, sizeof (smb_kspooldoc_t));
140 smb_kshare_release(sr->sr_server, si);
141 }
142 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
143 }
144
145 /*
146 * Close the specified file handle and queue the file for printing.
147 * The fid refers to a file previously created as a print spool file.
148 * On successful completion of this request, the file is queued for
149 * printing by the server.
150 *
151 * Servers that negotiate LANMAN1.0 or later allow all the the fid
152 * to be closed and printed via any close request.
153 */
154 smb_sdrc_t
smb_pre_close_print_file(smb_request_t * sr)155 smb_pre_close_print_file(smb_request_t *sr)
156 {
157 int rc;
158
159 rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
160
161 DTRACE_SMB_1(op__ClosePrintFile__start, smb_request_t *, sr);
162 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
163 }
164
165 void
smb_post_close_print_file(smb_request_t * sr)166 smb_post_close_print_file(smb_request_t *sr)
167 {
168 DTRACE_SMB_1(op__ClosePrintFile__done, smb_request_t *, sr);
169 }
170
171 /*
172 *
173 * Adds the print file fid to a list to be used as a search
174 * key in the spooldoc list. It then wakes up the smbd
175 * spool monitor thread to copy the spool file.
176 *
177 * Return values
178 * rc - 0 success
179 *
180 */
181
182 smb_sdrc_t
smb_com_close_print_file(smb_request_t * sr)183 smb_com_close_print_file(smb_request_t *sr)
184 {
185 smb_sdrc_t rc;
186
187 /*
188 * If sv_cfg.skc_print_enable somehow went false while
189 * we have a print FID open, close the FID. In this
190 * situation, smb_spool_add_fid() will do nothing.
191 */
192 if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
193 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
194 ERRDOS, ERROR_BAD_DEV_TYPE);
195 cmn_err(CE_WARN, "smb_com_close_print_file: SDRC_ERROR");
196 return (SDRC_ERROR);
197 }
198 rc = smb_com_close(sr);
199
200 smb_spool_add_fid(sr->sr_server, sr->smb_fid);
201
202 return (rc);
203 }
204
205 /*
206 * Get a list of print queue entries on the server. Support for
207 * this request is optional (not required for Windows clients).
208 */
209 smb_sdrc_t
smb_pre_get_print_queue(smb_request_t * sr)210 smb_pre_get_print_queue(smb_request_t *sr)
211 {
212 DTRACE_SMB_1(op__GetPrintQueue__start, smb_request_t *, sr);
213 return (SDRC_SUCCESS);
214 }
215
216 void
smb_post_get_print_queue(smb_request_t * sr)217 smb_post_get_print_queue(smb_request_t *sr)
218 {
219 DTRACE_SMB_1(op__GetPrintQueue__done, smb_request_t *, sr);
220 }
221
222 smb_sdrc_t
smb_com_get_print_queue(smb_request_t * sr)223 smb_com_get_print_queue(smb_request_t *sr)
224 {
225 unsigned short max_count, start_ix;
226
227 if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0)
228 return (SDRC_ERROR);
229
230 if (smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0))
231 return (SDRC_ERROR);
232
233 return (SDRC_SUCCESS);
234 }
235
236 /*
237 * Write (append) data to a print spool file. The fid must refer to
238 * a print spool file.
239 *
240 * The first SetupLength bytes (see SMB_COM_OPEN_PRINT_FILE) in the
241 * print spool file contain printer setup data.
242 *
243 * Servers that negotiate LANMAN1.0 or later also support the use of
244 * normal write requests with print spool files.
245 */
246 smb_sdrc_t
smb_pre_write_print_file(smb_request_t * sr)247 smb_pre_write_print_file(smb_request_t *sr)
248 {
249 smb_rw_param_t *param;
250 int rc;
251
252 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
253 sr->arg.rw = param;
254 param->rw_magic = SMB_RW_MAGIC;
255
256 rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
257
258 DTRACE_SMB_1(op__WritePrintFile__start, smb_request_t *, sr);
259 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
260 }
261
262 void
smb_post_write_print_file(smb_request_t * sr)263 smb_post_write_print_file(smb_request_t *sr)
264 {
265 DTRACE_SMB_1(op__WritePrintFile__done, smb_request_t *, sr);
266
267 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
268 }
269
270 smb_sdrc_t
smb_com_write_print_file(smb_request_t * sr)271 smb_com_write_print_file(smb_request_t *sr)
272 {
273 smb_rw_param_t *param = sr->arg.rw;
274 smb_node_t *node;
275 smb_attr_t attr;
276 int rc;
277
278 if (sr->sr_server->sv_cfg.skc_print_enable == 0 ||
279 !STYPE_ISPRN(sr->tid_tree->t_res_type)) {
280 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
281 ERRDOS, ERROR_BAD_DEV_TYPE);
282 return (SDRC_ERROR);
283 }
284
285 smbsr_lookup_file(sr);
286 if (sr->fid_ofile == NULL) {
287 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
288 return (SDRC_ERROR);
289 }
290
291 node = sr->fid_ofile->f_node;
292 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
293
294 bzero(&attr, sizeof (attr));
295 attr.sa_mask = SMB_AT_SIZE;
296 rc = smb_node_getattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
297 if (rc != 0) {
298 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
299 ERRDOS, ERROR_INTERNAL_ERROR);
300 return (SDRC_ERROR);
301 }
302
303 if ((smbsr_decode_data(sr, "D", ¶m->rw_vdb)) != 0) {
304 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
305 ERRDOS, ERROR_INVALID_PARAMETER);
306 return (SDRC_ERROR);
307 }
308
309 param->rw_count = param->rw_vdb.vdb_len;
310 param->rw_offset = attr.sa_vattr.va_size;
311 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
312
313 if ((rc = smb_common_write(sr, param)) != 0) {
314 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
315 smbsr_errno(sr, rc);
316 return (SDRC_ERROR);
317 }
318
319 rc = smbsr_encode_empty_result(sr);
320 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
321 }
322