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
smb_pre_open_print_file(smb_request_t * sr)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
smb_post_open_print_file(smb_request_t * sr)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
smb_com_open_print_file(smb_request_t * sr)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
smb_pre_close_print_file(smb_request_t * sr)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
smb_post_close_print_file(smb_request_t * sr)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
smb_com_close_print_file(smb_request_t * sr)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
smb_pre_get_print_queue(smb_request_t * sr)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
smb_post_get_print_queue(smb_request_t * sr)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
smb_com_get_print_queue(smb_request_t * sr)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
smb_pre_write_print_file(smb_request_t * sr)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
smb_post_write_print_file(smb_request_t * sr)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
smb_com_write_print_file(smb_request_t * sr)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", ¶m->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