Merge commit '7d815089a43a963b49eaddf97e514194ec29805b'
[unleashed.git] / usr / src / lib / smbsrv / libmlsvc / common / spoolss_svc.c
blob56a6ea833ff0a1237932705fa92f00c6aa330455
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 * Printing and Spooling RPC service.
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/utsname.h>
32 #include <sys/atomic.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <strings.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <libmlrpc/libmlrpc.h>
39 #include <sys/cfgparam.h>
40 #include <smbsrv/libsmb.h>
41 #include <smbsrv/libmlsvc.h>
42 #include <smbsrv/smb.h>
43 #include <smbsrv/ndl/spoolss.ndl>
44 #include <smbsrv/ndl/winreg.ndl>
45 #include <smb/nterror.h>
46 #include <smbsrv/smbinfo.h>
47 #include <smbsrv/nmpipes.h>
48 #include <mlsvc.h>
50 #ifdef CONFIG_SMB_PRINTING
52 #define SPOOLSS_PRINTER "Postscript"
54 typedef struct smb_spool {
55 list_t sp_list;
56 int sp_cnt;
57 rwlock_t sp_rwl;
58 int sp_initialized;
59 } smb_spool_t;
61 typedef struct smb_spooldoc {
62 uint32_t sd_magic;
63 list_node_t sd_lnd;
64 smb_inaddr_t sd_ipaddr;
65 int sd_spool_num;
66 char sd_username[MAXNAMELEN];
67 char sd_path[MAXPATHLEN];
68 char sd_doc_name[MAXNAMELEN];
69 char sd_printer_name[MAXPATHLEN];
70 int32_t sd_fd;
71 ndr_hdid_t sd_handle;
72 } smb_spooldoc_t;
74 typedef struct {
75 char *name;
76 uint32_t value;
77 } spoolss_winreg_t;
79 typedef struct {
80 uint8_t *sd_buf;
81 uint32_t sd_size;
82 } spoolss_sd_t;
84 static uint32_t spoolss_cnt;
85 static smb_spool_t spoolss_splist;
87 void (*spoolss_copyfile_callback)(smb_inaddr_t *, char *, char *, char *);
89 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result_u);
90 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result);
91 DECL_FIXUP_STRUCT(spoolss_GetPrinter);
93 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA);
94 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA);
95 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO);
96 DECL_FIXUP_STRUCT(spoolss_RFNPCNEX);
98 uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *);
99 static int spoolss_getservername(char *, size_t);
100 static uint32_t spoolss_make_sd(ndr_xa_t *, spoolss_sd_t *);
101 static uint32_t spoolss_format_sd(smb_sd_t *);
102 static int spoolss_find_document(ndr_hdid_t *);
104 static int spoolss_s_OpenPrinter(void *, ndr_xa_t *);
105 static int spoolss_s_ClosePrinter(void *, ndr_xa_t *);
106 static int spoolss_s_AbortPrinter(void *, ndr_xa_t *);
107 static int spoolss_s_ResetPrinter(void *, ndr_xa_t *);
108 static int spoolss_s_GetPrinter(void *, ndr_xa_t *);
109 static int spoolss_s_GetPrinterData(void *, ndr_xa_t *);
110 static int spoolss_s_AddJob(void *, ndr_xa_t *);
111 static int spoolss_s_GetJob(void *, ndr_xa_t *);
112 static int spoolss_s_EnumJobs(void *, ndr_xa_t *);
113 static int spoolss_s_ScheduleJob(void *, ndr_xa_t *);
114 static int spoolss_s_StartDocPrinter(void *, ndr_xa_t *);
115 static int spoolss_s_EndDocPrinter(void *, ndr_xa_t *);
116 static int spoolss_s_StartPagePrinter(void *, ndr_xa_t *);
117 static int spoolss_s_EndPagePrinter(void *, ndr_xa_t *);
118 static int spoolss_s_rfnpcnex(void *, ndr_xa_t *);
119 static int spoolss_s_WritePrinter(void *, ndr_xa_t *);
120 static int spoolss_s_AddForm(void *, ndr_xa_t *);
121 static int spoolss_s_DeleteForm(void *, ndr_xa_t *);
122 static int spoolss_s_EnumForms(void *, ndr_xa_t *);
123 static int spoolss_s_AddMonitor(void *, ndr_xa_t *);
124 static int spoolss_s_DeleteMonitor(void *, ndr_xa_t *);
125 static int spoolss_s_DeletePort(void *, ndr_xa_t *);
126 static int spoolss_s_AddPortEx(void *, ndr_xa_t *);
127 static int spoolss_s_SetPort(void *, ndr_xa_t *);
128 static int spoolss_s_stub(void *, ndr_xa_t *);
130 static ndr_stub_table_t spoolss_stub_table[] = {
131 { spoolss_s_GetJob, SPOOLSS_OPNUM_GetJob },
132 { spoolss_s_EnumJobs, SPOOLSS_OPNUM_EnumJobs },
133 { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinter },
134 { spoolss_s_GetPrinter, SPOOLSS_OPNUM_GetPrinter },
135 { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver },
136 { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterDriver },
137 { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinter },
138 { spoolss_s_StartDocPrinter, SPOOLSS_OPNUM_StartDocPrinter },
139 { spoolss_s_WritePrinter, SPOOLSS_OPNUM_WritePrinter },
140 { spoolss_s_EndDocPrinter, SPOOLSS_OPNUM_EndDocPrinter },
141 { spoolss_s_StartPagePrinter, SPOOLSS_OPNUM_StartPagePrinter },
142 { spoolss_s_EndPagePrinter, SPOOLSS_OPNUM_EndPagePrinter },
143 { spoolss_s_AbortPrinter, SPOOLSS_OPNUM_AbortPrinter },
144 { spoolss_s_ResetPrinter, SPOOLSS_OPNUM_ResetPrinter },
145 { spoolss_s_AddJob, SPOOLSS_OPNUM_AddJob },
146 { spoolss_s_ScheduleJob, SPOOLSS_OPNUM_ScheduleJob },
147 { spoolss_s_GetPrinterData, SPOOLSS_OPNUM_GetPrinterData },
148 { spoolss_s_ClosePrinter, SPOOLSS_OPNUM_ClosePrinter },
149 { spoolss_s_AddForm, SPOOLSS_OPNUM_AddForm },
150 { spoolss_s_DeleteForm, SPOOLSS_OPNUM_DeleteForm },
151 { spoolss_s_EnumForms, SPOOLSS_OPNUM_EnumForms },
152 { spoolss_s_AddMonitor, SPOOLSS_OPNUM_AddMonitor },
153 { spoolss_s_DeleteMonitor, SPOOLSS_OPNUM_DeleteMonitor },
154 { spoolss_s_DeletePort, SPOOLSS_OPNUM_DeletePort },
155 { spoolss_s_AddPortEx, SPOOLSS_OPNUM_AddPortEx },
156 { spoolss_s_SetPort, SPOOLSS_OPNUM_SetPort },
157 { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver2 },
158 { spoolss_s_stub, SPOOLSS_OPNUM_FCPN },
159 { spoolss_s_stub, SPOOLSS_OPNUM_ReplyOpenPrinter },
160 { spoolss_s_stub, SPOOLSS_OPNUM_ReplyClosePrinter },
161 { spoolss_s_stub, SPOOLSS_OPNUM_RFFPCNEX },
162 { spoolss_s_rfnpcnex, SPOOLSS_OPNUM_RFNPCNEX },
163 { spoolss_s_stub, SPOOLSS_OPNUM_RRPCN },
164 { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinterEx },
165 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterData },
166 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterDataEx },
167 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterKey },
171 static ndr_service_t spoolss_service = {
172 "SPOOLSS", /* name */
173 "Print Spool Service", /* desc */
174 "\\spoolss", /* endpoint */
175 PIPE_SPOOLSS, /* sec_addr_port */
176 "12345678-1234-abcd-ef00-0123456789ab", 1, /* abstract */
177 NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */
178 0, /* no bind_instance_size */
179 0, /* no bind_req() */
180 0, /* no unbind_and_close() */
181 0, /* use generic_call_stub() */
182 &TYPEINFO(spoolss_interface), /* interface ti */
183 spoolss_stub_table /* stub_table */
186 void
187 spoolss_initialize(void)
189 if (!spoolss_splist.sp_initialized) {
190 list_create(&spoolss_splist.sp_list,
191 sizeof (smb_spooldoc_t),
192 offsetof(smb_spooldoc_t, sd_lnd));
193 spoolss_splist.sp_initialized = 1;
196 spoolss_copyfile_callback = NULL;
198 (void) ndr_svc_register(&spoolss_service);
201 void
202 spoolss_finalize(void)
204 spoolss_copyfile_callback = NULL;
208 * Register a copyfile callback that the spoolss service can use to
209 * copy files to the spool directory.
211 * Set a null pointer to disable the copying of files to the spool
212 * directory.
214 void
215 spoolss_register_copyfile(spoolss_copyfile_t copyfile)
217 spoolss_copyfile_callback = copyfile;
220 static void
221 spoolss_copyfile(smb_inaddr_t *ipaddr, char *username, char *path,
222 char *docname)
224 if (spoolss_copyfile_callback != NULL)
225 (*spoolss_copyfile_callback)(ipaddr, username, path, docname);
228 static int
229 spoolss_s_OpenPrinter(void *arg, ndr_xa_t *mxa)
231 struct spoolss_OpenPrinter *param = arg;
232 char *name = (char *)param->printer_name;
233 ndr_hdid_t *id;
235 if (name != NULL && *name != '\0') {
236 if (strspn(name, "\\") > 2) {
237 bzero(&param->handle, sizeof (spoolss_handle_t));
238 param->status = ERROR_INVALID_PRINTER_NAME;
239 return (NDR_DRC_OK);
242 smb_tracef("spoolss_s_OpenPrinter: %s", name);
245 if ((id = ndr_hdalloc(mxa, NULL)) == NULL) {
246 bzero(&param->handle, sizeof (spoolss_handle_t));
247 param->status = ERROR_NOT_ENOUGH_MEMORY;
248 return (NDR_DRC_OK);
251 bcopy(id, &param->handle, sizeof (spoolss_handle_t));
252 param->status = 0;
253 return (NDR_DRC_OK);
256 /*ARGSUSED*/
257 static int
258 spoolss_s_StartPagePrinter(void *arg, ndr_xa_t *mxa)
260 struct spoolss_StartPagePrinter *param = arg;
262 param->status = ERROR_SUCCESS;
264 return (NDR_DRC_OK);
267 /*ARGSUSED*/
268 static int
269 spoolss_s_EndPagePrinter(void *arg, ndr_xa_t *mxa)
271 struct spoolss_EndPagePrinter *param = arg;
273 param->status = ERROR_SUCCESS;
275 return (NDR_DRC_OK);
279 * Windows XP and 2000 use this mechanism to write spool files.
280 * Create a spool file fd to be used by spoolss_s_WritePrinter
281 * and add it to the tail of the spool list.
283 static int
284 spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa)
286 struct spoolss_StartDocPrinter *param = arg;
287 ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
288 smb_spooldoc_t *spfile;
289 spoolss_DocInfo_t *docinfo;
290 char g_path[MAXPATHLEN];
291 smb_share_t si;
292 int rc;
293 int fd;
295 if (ndr_hdlookup(mxa, id) == NULL) {
296 smb_tracef("spoolss_s_StartDocPrinter: invalid handle");
297 param->status = ERROR_INVALID_HANDLE;
298 return (NDR_DRC_OK);
301 if ((docinfo = param->dinfo.DocInfoContainer) == NULL) {
302 param->status = ERROR_INVALID_PARAMETER;
303 return (NDR_DRC_OK);
306 if ((rc = smb_shr_get(SMB_SHARE_PRINT, &si)) != NERR_Success) {
307 smb_tracef("spoolss_s_StartDocPrinter: %s error=%d",
308 SMB_SHARE_PRINT, rc);
309 param->status = rc;
310 return (NDR_DRC_OK);
313 if ((spfile = calloc(1, sizeof (smb_spooldoc_t))) == NULL) {
314 param->status = ERROR_NOT_ENOUGH_MEMORY;
315 return (NDR_DRC_OK);
318 if (docinfo->doc_name != NULL)
319 (void) strlcpy(spfile->sd_doc_name,
320 (char *)docinfo->doc_name, MAXNAMELEN);
321 else
322 (void) strlcpy(spfile->sd_doc_name, "document", MAXNAMELEN);
324 if (docinfo->printer_name != NULL)
325 (void) strlcpy(spfile->sd_printer_name,
326 (char *)docinfo->printer_name, MAXPATHLEN);
327 else
328 (void) strlcpy(spfile->sd_printer_name, "printer", MAXPATHLEN);
330 spfile->sd_ipaddr = mxa->pipe->np_user->ui_ipaddr;
331 (void) strlcpy((char *)spfile->sd_username,
332 mxa->pipe->np_user->ui_account, MAXNAMELEN);
333 (void) memcpy(&spfile->sd_handle, &param->handle, sizeof (ndr_hdid_t));
336 * write temporary spool file to print$
338 (void) snprintf(g_path, MAXPATHLEN, "%s/%s%d", si.shr_path,
339 spfile->sd_username, spoolss_cnt);
340 atomic_inc_32(&spoolss_cnt);
342 fd = open(g_path, O_CREAT | O_RDWR, 0600);
343 if (fd == -1) {
344 smb_tracef("spoolss_s_StartDocPrinter: %s: %s",
345 g_path, strerror(errno));
346 param->status = ERROR_OPEN_FAILED;
347 free(spfile);
348 } else {
349 (void) strlcpy((char *)spfile->sd_path, g_path, MAXPATHLEN);
350 spfile->sd_fd = (uint16_t)fd;
353 * Add the document to the spool list.
355 (void) rw_wrlock(&spoolss_splist.sp_rwl);
356 list_insert_tail(&spoolss_splist.sp_list, spfile);
357 spoolss_splist.sp_cnt++;
358 (void) rw_unlock(&spoolss_splist.sp_rwl);
361 * JobId isn't used now, but if printQ management is added
362 * this will have to be incremented per job submitted.
364 param->JobId = 46;
365 param->status = ERROR_SUCCESS;
367 return (NDR_DRC_OK);
371 * Windows XP and 2000 use this mechanism to write spool files
372 * Search the spooldoc list for a matching RPC handle and pass
373 * the spool the file for printing.
375 static int
376 spoolss_s_EndDocPrinter(void *arg, ndr_xa_t *mxa)
378 struct spoolss_EndDocPrinter *param = arg;
379 ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
380 smb_spooldoc_t *sp;
382 if (ndr_hdlookup(mxa, id) == NULL) {
383 smb_tracef("spoolss_s_EndDocPrinter: invalid handle");
384 param->status = ERROR_INVALID_HANDLE;
385 return (NDR_DRC_OK);
388 param->status = ERROR_INVALID_HANDLE;
389 (void) rw_wrlock(&spoolss_splist.sp_rwl);
391 sp = list_head(&spoolss_splist.sp_list);
392 while (sp != NULL) {
393 if (!memcmp(id, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
394 spoolss_copyfile(&sp->sd_ipaddr,
395 sp->sd_username, sp->sd_path, sp->sd_doc_name);
396 (void) close(sp->sd_fd);
397 list_remove(&spoolss_splist.sp_list, sp);
398 free(sp);
399 param->status = ERROR_SUCCESS;
400 break;
403 sp = list_next(&spoolss_splist.sp_list, sp);
406 (void) rw_unlock(&spoolss_splist.sp_rwl);
408 if (param->status != ERROR_SUCCESS)
409 smb_tracef("spoolss_s_EndDocPrinter: document not found");
410 return (NDR_DRC_OK);
413 /*ARGSUSED*/
414 static int
415 spoolss_s_AbortPrinter(void *arg, ndr_xa_t *mxa)
417 struct spoolss_AbortPrinter *param = arg;
419 param->status = ERROR_SUCCESS;
420 return (NDR_DRC_OK);
423 /*ARGSUSED*/
424 static int
425 spoolss_s_ResetPrinter(void *arg, ndr_xa_t *mxa)
427 struct spoolss_AbortPrinter *param = arg;
429 param->status = ERROR_SUCCESS;
430 return (NDR_DRC_OK);
433 static int
434 spoolss_s_ClosePrinter(void *arg, ndr_xa_t *mxa)
436 struct spoolss_ClosePrinter *param = arg;
437 ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
438 ndr_handle_t *hd;
440 if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
441 free(hd->nh_data);
442 hd->nh_data = NULL;
445 ndr_hdfree(mxa, id);
446 bzero(&param->result_handle, sizeof (spoolss_handle_t));
447 param->status = ERROR_SUCCESS;
448 return (NDR_DRC_OK);
451 static int
452 spoolss_s_AddForm(void *arg, ndr_xa_t *mxa)
454 struct spoolss_AddForm *param = arg;
455 ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
457 if (ndr_hdlookup(mxa, id) == NULL) {
458 bzero(param, sizeof (struct spoolss_AddForm));
459 param->status = ERROR_INVALID_HANDLE;
460 return (NDR_DRC_OK);
463 bzero(param, sizeof (struct spoolss_AddForm));
464 param->status = ERROR_SUCCESS;
465 return (NDR_DRC_OK);
468 static int
469 spoolss_s_DeleteForm(void *arg, ndr_xa_t *mxa)
471 struct spoolss_DeleteForm *param = arg;
472 ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
474 if (ndr_hdlookup(mxa, id) == NULL) {
475 bzero(param, sizeof (struct spoolss_DeleteForm));
476 param->status = ERROR_INVALID_HANDLE;
477 return (NDR_DRC_OK);
480 bzero(param, sizeof (struct spoolss_DeleteForm));
481 param->status = ERROR_SUCCESS;
482 return (NDR_DRC_OK);
485 static int
486 spoolss_s_EnumForms(void *arg, ndr_xa_t *mxa)
488 struct spoolss_EnumForms *param = arg;
489 ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
491 if (ndr_hdlookup(mxa, id) == NULL) {
492 bzero(param, sizeof (struct spoolss_EnumForms));
493 param->status = ERROR_INVALID_HANDLE;
494 return (NDR_DRC_OK);
497 bzero(param, sizeof (struct spoolss_EnumForms));
498 param->status = ERROR_SUCCESS;
499 param->needed = 0;
500 return (NDR_DRC_OK);
503 /*ARGSUSED*/
504 static int
505 spoolss_s_AddMonitor(void *arg, ndr_xa_t *mxa)
507 struct spoolss_AddMonitor *param = arg;
509 param->status = ERROR_SUCCESS;
510 return (NDR_DRC_OK);
513 /*ARGSUSED*/
514 static int
515 spoolss_s_DeleteMonitor(void *arg, ndr_xa_t *mxa)
517 struct spoolss_DeleteMonitor *param = arg;
519 param->status = ERROR_SUCCESS;
520 return (NDR_DRC_OK);
523 /*ARGSUSED*/
524 static int
525 spoolss_s_DeletePort(void *arg, ndr_xa_t *mxa)
527 struct spoolss_DeletePort *param = arg;
529 param->status = ERROR_SUCCESS;
530 return (NDR_DRC_OK);
533 /*ARGSUSED*/
534 static int
535 spoolss_s_AddPortEx(void *arg, ndr_xa_t *mxa)
537 struct spoolss_AddPortEx *param = arg;
539 param->status = ERROR_SUCCESS;
540 return (NDR_DRC_OK);
543 /*ARGSUSED*/
544 static int
545 spoolss_s_SetPort(void *arg, ndr_xa_t *mxa)
547 struct spoolss_SetPort *param = arg;
549 param->status = ERROR_SUCCESS;
550 return (NDR_DRC_OK);
553 /*ARGSUSED*/
554 static int
555 spoolss_s_EnumJobs(void *arg, ndr_xa_t *mxa)
557 struct spoolss_EnumJobs *param = arg;
558 DWORD status = ERROR_SUCCESS;
560 switch (param->level) {
561 case 1:
562 case 2:
563 case 3:
564 case 4:
565 default:
566 break;
569 param->status = status;
570 param->needed = 0;
571 param->needed2 = 0;
572 return (NDR_DRC_OK);
576 /*ARGSUSED*/
577 static int
578 spoolss_s_GetJob(void *arg, ndr_xa_t *mxa)
580 struct spoolss_GetJob *param = arg;
581 DWORD status = ERROR_SUCCESS;
583 if (param->BufCount == 0)
584 param->status = ERROR_INSUFFICIENT_BUFFER;
585 else
586 param->status = status;
587 param->needed = 0;
588 return (NDR_DRC_OK);
592 /*ARGSUSED*/
593 static int
594 spoolss_s_ScheduleJob(void *arg, ndr_xa_t *mxa)
596 struct spoolss_ScheduleJob *param = arg;
597 DWORD status = ERROR_SPL_NO_ADDJOB;
599 param->status = status;
600 return (NDR_DRC_OK);
603 /*ARGSUSED*/
604 static int
605 spoolss_s_AddJob(void *arg, ndr_xa_t *mxa)
607 struct spoolss_AddJob *param = arg;
609 param->status = ERROR_SUCCESS;
610 param->needed = 0;
611 return (NDR_DRC_OK);
614 /*ARGSUSED*/
615 static int
616 spoolss_s_rfnpcnex(void *arg, ndr_xa_t *mxa)
618 struct spoolss_RFNPCNEX *param = arg;
620 param->ppinfo = 0;
621 param->status = ERROR_SUCCESS;
622 return (NDR_DRC_OK);
626 * Use the RPC context handle to find the fd and write the document content.
628 static int
629 spoolss_s_WritePrinter(void *arg, ndr_xa_t *mxa)
631 struct spoolss_WritePrinter *param = arg;
632 int written = 0;
633 ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
634 int spfd;
636 if (ndr_hdlookup(mxa, id) == NULL) {
637 param->written = 0;
638 param->status = ERROR_INVALID_HANDLE;
639 smb_tracef("spoolss_s_WritePrinter: invalid handle");
640 return (NDR_DRC_OK);
643 if ((spfd = spoolss_find_document(id)) < 0) {
644 param->written = 0;
645 param->status = ERROR_INVALID_HANDLE;
646 smb_tracef("spoolss_s_WritePrinter: document not found");
647 return (NDR_DRC_OK);
650 written = write(spfd, param->pBuf, param->BufCount);
651 if (written < param->BufCount) {
652 smb_tracef("spoolss_s_WritePrinter: write failed");
653 param->written = 0;
654 param->status = ERROR_CANTWRITE;
655 return (NDR_DRC_OK);
658 param->written = written;
659 param->status = ERROR_SUCCESS;
660 return (NDR_DRC_OK);
664 * Find a document by RPC handle in the spool list and return the fd.
666 static int
667 spoolss_find_document(ndr_hdid_t *handle)
669 smb_spooldoc_t *sp;
671 (void) rw_rdlock(&spoolss_splist.sp_rwl);
673 sp = list_head(&spoolss_splist.sp_list);
674 while (sp != NULL) {
675 if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
676 (void) rw_unlock(&spoolss_splist.sp_rwl);
677 return (sp->sd_fd);
679 sp = list_next(&spoolss_splist.sp_list, sp);
682 (void) rw_unlock(&spoolss_splist.sp_rwl);
683 return (-1);
687 * GetPrinterData is used t obtain values from the registry for a
688 * printer or a print server. See [MS-RPRN] for value descriptions.
689 * The registry returns ERROR_FILE_NOT_FOUND for unknown keys.
691 static int
692 spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa)
694 static spoolss_winreg_t reg[] = {
695 { "ChangeId", 0x0050acf2 },
696 { "W3SvcInstalled", 0x00000000 },
697 { "BeepEnabled", 0x00000000 },
698 { "EventLog", 0x0000001f },
699 { "NetPopup", 0x00000000 },
700 { "NetPopupToComputer", 0x00000000 },
701 { "MajorVersion", 0x00000003 },
702 { "MinorVersion", 0x00000000 },
703 { "DsPresent", 0x00000000 }
706 struct spoolss_GetPrinterData *param = arg;
707 char *name = (char *)param->pValueName;
708 char buf[MAXPATHLEN];
709 static uint8_t reserved_buf[4];
710 spoolss_winreg_t *rp;
711 smb_share_t si;
712 smb_version_t *osversion;
713 struct utsname sysname;
714 smb_wchar_t *wcs;
715 uint32_t value;
716 uint32_t status;
717 int wcslen;
718 int i;
720 if (name == NULL || *name == '\0') {
721 status = ERROR_FILE_NOT_FOUND;
722 goto report_error;
725 for (i = 0; i < sizeof (reg) / sizeof (reg[0]); ++i) {
726 param->pType = WINREG_DWORD;
727 param->Needed = sizeof (uint32_t);
728 rp = &reg[i];
730 if (strcasecmp(name, rp->name) != 0)
731 continue;
733 if (param->Size < sizeof (uint32_t)) {
734 param->Size = 0;
735 goto need_more_data;
738 if ((param->Buf = NDR_NEW(mxa, uint32_t)) == NULL) {
739 status = ERROR_NOT_ENOUGH_MEMORY;
740 goto report_error;
743 value = rp->value;
745 if ((strcasecmp(name, "DsPresent") == 0) &&
746 (smb_config_get_secmode() == SMB_SECMODE_DOMAIN))
747 value = 0x00000001;
749 bcopy(&value, param->Buf, sizeof (uint32_t));
750 param->Size = sizeof (uint32_t);
751 param->status = ERROR_SUCCESS;
752 return (NDR_DRC_OK);
755 if (strcasecmp(name, "OSVersion") == 0) {
756 param->pType = WINREG_BINARY;
757 param->Needed = sizeof (smb_version_t);
759 if (param->Size < sizeof (smb_version_t)) {
760 param->Size = sizeof (smb_version_t);
761 goto need_more_data;
764 if ((osversion = NDR_NEW(mxa, smb_version_t)) == NULL) {
765 status = ERROR_NOT_ENOUGH_MEMORY;
766 goto report_error;
769 smb_config_get_version(osversion);
770 param->Buf = (uint8_t *)osversion;
771 param->status = ERROR_SUCCESS;
772 return (NDR_DRC_OK);
775 if (strcasecmp(name, "DNSMachineName") == 0) {
776 param->pType = WINREG_SZ;
777 buf[0] = '\0';
778 (void) smb_getfqhostname(buf, MAXHOSTNAMELEN);
779 goto encode_string;
782 if (strcasecmp(name, "DefaultSpoolDirectory") == 0) {
783 param->pType = WINREG_SZ;
784 buf[0] = '\0';
786 if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) {
787 status = ERROR_FILE_NOT_FOUND;
788 goto report_error;
791 (void) snprintf(buf, MAXPATHLEN, "C:/%s", si.shr_path);
792 (void) strcanon(buf, "/\\");
793 (void) strsubst(buf, '/', '\\');
794 goto encode_string;
797 if (strcasecmp(name, "Architecture") == 0) {
798 param->pType = WINREG_SZ;
800 if (uname(&sysname) < 0)
801 (void) strlcpy(buf, "Solaris", MAXPATHLEN);
802 else
803 (void) snprintf(buf, MAXPATHLEN, "%s %s",
804 sysname.sysname, sysname.machine);
806 goto encode_string;
809 status = ERROR_FILE_NOT_FOUND;
811 report_error:
812 bzero(param, sizeof (struct spoolss_GetPrinterData));
813 param->Buf = reserved_buf;
814 param->status = status;
815 return (NDR_DRC_OK);
817 encode_string:
818 wcslen = smb_wcequiv_strlen(buf) + sizeof (smb_wchar_t);
819 if (param->Size < wcslen) {
820 param->Needed = wcslen;
821 goto need_more_data;
824 if ((wcs = NDR_MALLOC(mxa, wcslen)) == NULL) {
825 status = ERROR_NOT_ENOUGH_MEMORY;
826 goto report_error;
829 (void) ndr_mbstowcs(NULL, wcs, buf, wcslen);
830 param->Buf = (uint8_t *)wcs;
831 param->Needed = wcslen;
832 param->status = ERROR_SUCCESS;
833 return (NDR_DRC_OK);
835 need_more_data:
836 param->Size = 0;
837 param->Buf = reserved_buf;
838 param->status = ERROR_MORE_DATA;
839 return (NDR_DRC_OK);
842 void
843 smb_rpc_off(char *dst, char *src, uint32_t *offset, uint32_t *outoffset)
845 int nwchars;
846 int bytes;
848 bytes = smb_wcequiv_strlen(src) + 2;
849 nwchars = strlen(src) + 1;
850 *offset -= bytes;
851 *outoffset = *offset;
852 /*LINTED E_BAD_PTR_CAST_ALIGN*/
853 (void) smb_mbstowcs(((smb_wchar_t *)(dst + *offset)), src, nwchars);
857 spoolss_s_GetPrinter(void *arg, ndr_xa_t *mxa)
859 struct spoolss_GetPrinter *param = arg;
860 struct spoolss_GetPrinter0 *pinfo0;
861 struct spoolss_GetPrinter1 *pinfo1;
862 struct spoolss_GetPrinter2 *pinfo2;
863 struct spoolss_DeviceMode *devmode2;
864 ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
865 spoolss_sd_t secdesc;
866 char server[MAXNAMELEN];
867 char printer[MAXNAMELEN];
868 DWORD status = ERROR_SUCCESS;
869 char *wname;
870 uint32_t offset;
871 uint8_t *tmpbuf;
873 if (ndr_hdlookup(mxa, id) == NULL) {
874 status = ERROR_INVALID_HANDLE;
875 goto error_out;
878 if (spoolss_getservername(server, MAXNAMELEN) != 0) {
879 status = ERROR_INTERNAL_ERROR;
880 goto error_out;
883 (void) snprintf(printer, MAXNAMELEN, "%s\\%s", server, SPOOLSS_PRINTER);
885 switch (param->switch_value) {
886 case 0:
887 case 1:
888 param->needed = 460;
889 break;
890 case 2:
891 param->needed = 712;
892 break;
893 default:
894 status = ERROR_INVALID_LEVEL;
895 goto error_out;
898 if (param->BufCount < param->needed) {
899 param->BufCount = 0;
900 param->Buf = NULL;
901 param->status = ERROR_INSUFFICIENT_BUFFER;
902 return (NDR_DRC_OK);
905 if ((param->Buf = NDR_MALLOC(mxa, param->BufCount)) == NULL) {
906 status = ERROR_NOT_ENOUGH_MEMORY;
907 goto error_out;
910 bzero(param->Buf, param->BufCount);
911 wname = (char *)param->Buf;
912 offset = param->needed;
914 switch (param->switch_value) {
915 case 0:
916 /*LINTED E_BAD_PTR_CAST_ALIGN*/
917 pinfo0 = (struct spoolss_GetPrinter0 *)param->Buf;
919 smb_rpc_off(wname, server, &offset, &pinfo0->servername);
920 smb_rpc_off(wname, printer, &offset, &pinfo0->printername);
921 pinfo0->cjobs = 0;
922 pinfo0->total_jobs = 6;
923 pinfo0->total_bytes = 1040771;
924 pinfo0->time0 = 0;
925 pinfo0->time1 = 0;
926 pinfo0->time2 = 3;
927 pinfo0->time3 = 0;
928 pinfo0->global_counter = 2162710;
929 pinfo0->total_pages = 21495865;
930 pinfo0->version = 10;
931 pinfo0->session_counter = 1;
932 pinfo0->job_error = 0x6;
933 pinfo0->change_id = 0x1;
934 pinfo0->status = 0;
935 pinfo0->c_setprinter = 0;
936 break;
937 case 1:
938 /*LINTED E_BAD_PTR_CAST_ALIGN*/
939 pinfo1 = (struct spoolss_GetPrinter1 *)param->Buf;
941 pinfo1->flags = PRINTER_ENUM_ICON8;
942 smb_rpc_off(wname, printer, &offset, &pinfo1->flags);
943 smb_rpc_off(wname, printer, &offset, &pinfo1->description);
944 smb_rpc_off(wname, printer, &offset, &pinfo1->comment);
945 break;
946 case 2:
947 /*LINTED E_BAD_PTR_CAST_ALIGN*/
948 pinfo2 = (struct spoolss_GetPrinter2 *)param->Buf;
950 smb_rpc_off(wname, server, &offset, &pinfo2->servername);
951 smb_rpc_off(wname, printer, &offset, &pinfo2->printername);
952 smb_rpc_off(wname, SPOOLSS_PRINTER, &offset,
953 &pinfo2->sharename);
954 smb_rpc_off(wname, "CIFS Printer Port", &offset,
955 &pinfo2->portname);
956 smb_rpc_off(wname, "", &offset, &pinfo2->drivername);
957 smb_rpc_off(wname, SPOOLSS_PRINTER, &offset,
958 &pinfo2->comment);
959 smb_rpc_off(wname, "farside", &offset, &pinfo2->location);
961 offset -= sizeof (struct spoolss_DeviceMode);
962 pinfo2->devmode = offset;
963 /*LINTED E_BAD_PTR_CAST_ALIGN*/
964 devmode2 = (struct spoolss_DeviceMode *)(param->Buf + offset);
966 smb_rpc_off(wname, "farside", &offset, &pinfo2->sepfile);
967 smb_rpc_off(wname, "winprint", &offset,
968 &pinfo2->printprocessor);
969 smb_rpc_off(wname, "RAW", &offset, &pinfo2->datatype);
970 smb_rpc_off(wname, "", &offset, &pinfo2->parameters);
972 status = spoolss_make_sd(mxa, &secdesc);
973 if (status == ERROR_SUCCESS) {
974 offset -= secdesc.sd_size;
975 pinfo2->secdesc = offset;
976 tmpbuf = (uint8_t *)(param->Buf + offset);
977 bcopy(secdesc.sd_buf, tmpbuf, secdesc.sd_size);
980 pinfo2->attributes = 0x00001048;
981 pinfo2->status = 0x00000000;
982 pinfo2->starttime = 0;
983 pinfo2->untiltime = 0;
984 pinfo2->cjobs = 0;
985 pinfo2->averageppm = 0;
986 pinfo2->defaultpriority = 0;
988 /*LINTED E_BAD_PTR_CAST_ALIGN*/
989 (void) smb_mbstowcs((smb_wchar_t *)devmode2->devicename,
990 printer, 32);
991 devmode2->specversion = 0x0401;
992 devmode2->driverversion = 1024;
993 devmode2->size = 220;
994 devmode2->driverextra_length = 0;
995 devmode2->fields = 0x00014713;
996 devmode2->orientation = 1;
997 devmode2->papersize = 1;
998 devmode2->paperlength = 0;
999 devmode2->paperwidth = 0;
1000 devmode2->scale = 100;
1001 devmode2->copies = 1;
1002 devmode2->defaultsource = 15;
1003 devmode2->printquality = 65532;
1004 devmode2->color = 1;
1005 devmode2->duplex = 1;
1006 devmode2->yresolution = 1;
1007 devmode2->ttoption = 1;
1008 devmode2->collate = 0;
1009 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1010 (void) smb_mbstowcs((smb_wchar_t *)devmode2->formname,
1011 "Letter", 32);
1012 devmode2->logpixels = 0;
1013 devmode2->bitsperpel = 0;
1014 devmode2->pelswidth = 0;
1015 devmode2->pelsheight = 0;
1016 devmode2->displayflags = 0;
1017 devmode2->displayfrequency = 0;
1018 devmode2->icmmethod = 0;
1019 devmode2->icmintent = 0;
1020 devmode2->mediatype = 0;
1021 devmode2->dithertype = 0;
1022 devmode2->reserved1 = 0;
1023 devmode2->reserved2 = 0;
1024 devmode2->panningwidth = 0;
1025 devmode2->panningheight = 0;
1026 break;
1028 default:
1029 break;
1032 param->status = status;
1033 return (NDR_DRC_OK);
1035 error_out:
1036 smb_tracef("spoolss_s_GetPrinter: error %u", status);
1037 bzero(param, sizeof (struct spoolss_GetPrinter));
1038 param->status = status;
1039 return (NDR_DRC_OK);
1042 static int
1043 spoolss_getservername(char *name, size_t namelen)
1045 char hostname[MAXHOSTNAMELEN];
1046 char ipstr[INET6_ADDRSTRLEN];
1047 smb_inaddr_t ipaddr;
1048 struct hostent *h;
1049 const char *p;
1050 int error;
1052 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0) {
1053 smb_tracef("spoolss_s_GetPrinter: gethostname failed");
1054 return (-1);
1057 if ((h = smb_gethostbyname(hostname, &error)) == NULL) {
1058 smb_tracef("spoolss_s_GetPrinter: gethostbyname failed: %d",
1059 error);
1060 return (-1);
1063 bcopy(h->h_addr, &ipaddr, h->h_length);
1064 ipaddr.a_family = h->h_addrtype;
1065 freehostent(h);
1067 p = smb_inet_ntop(&ipaddr, ipstr, SMB_IPSTRLEN(ipaddr.a_family));
1068 if (p == NULL) {
1069 smb_tracef("spoolss_s_GetPrinter: inet_ntop failed");
1070 return (-1);
1073 (void) snprintf(name, namelen, "\\\\%s", ipstr);
1074 return (0);
1077 static uint32_t
1078 spoolss_make_sd(ndr_xa_t *mxa, spoolss_sd_t *secdesc)
1080 smb_sd_t sd;
1081 uint8_t *sd_buf;
1082 uint32_t sd_len;
1083 uint32_t status;
1085 bzero(&sd, sizeof (smb_sd_t));
1087 if ((status = spoolss_format_sd(&sd)) != ERROR_SUCCESS)
1088 return (status);
1090 sd_len = smb_sd_len(&sd, SMB_ALL_SECINFO);
1092 if ((sd_buf = NDR_MALLOC(mxa, sd_len)) == NULL)
1093 return (ERROR_NOT_ENOUGH_MEMORY);
1095 secdesc->sd_buf = sd_buf;
1096 secdesc->sd_size = sd_len;
1098 status = srvsvc_sd_set_relative(&sd, sd_buf);
1099 smb_sd_term(&sd);
1100 return (status);
1103 static uint32_t
1104 spoolss_format_sd(smb_sd_t *sd)
1106 smb_fssd_t fs_sd;
1107 acl_t *acl;
1108 uint32_t status = ERROR_SUCCESS;
1110 if (acl_fromtext("everyone@:full_set::allow", &acl) != 0) {
1111 smb_tracef("spoolss_format_sd: NOT_ENOUGH_MEMORY");
1112 return (ERROR_NOT_ENOUGH_MEMORY);
1114 smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR);
1115 fs_sd.sd_uid = 0;
1116 fs_sd.sd_gid = 0;
1117 fs_sd.sd_zdacl = acl;
1118 fs_sd.sd_zsacl = NULL;
1120 status = smb_sd_fromfs(&fs_sd, sd);
1121 if (status != NT_STATUS_SUCCESS) {
1122 smb_tracef("spoolss_format_sd: %u", status);
1123 status = ERROR_ACCESS_DENIED;
1125 smb_fssd_term(&fs_sd);
1126 return (status);
1129 /*ARGSUSED*/
1130 static int
1131 spoolss_s_stub(void *arg, ndr_xa_t *mxa)
1133 return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
1136 void
1137 fixup_spoolss_RFNPCNEX(struct spoolss_RFNPCNEX *val)
1139 unsigned short size1 = 0;
1140 unsigned short size2 = 0;
1141 unsigned short size3 = 0;
1142 struct spoolss_RPC_V2_NOTIFY_INFO *pinfo;
1144 pinfo = val->ppinfo->pinfo;
1145 switch (pinfo->aData->Reserved) {
1146 case TABLE_STRING:
1147 size1 = sizeof (struct STRING_CONTAINER);
1148 break;
1149 case TABLE_DWORD:
1150 size1 = sizeof (DWORD) * 2;
1151 break;
1152 case TABLE_TIME:
1153 size1 = sizeof (struct SYSTEMTIME_CONTAINER);
1154 break;
1155 case TABLE_DEVMODE:
1156 size1 = sizeof (struct spoolssDevmodeContainer);
1157 break;
1158 case TABLE_SECURITY_DESCRIPTOR:
1159 size1 = sizeof (struct SECURITY_CONTAINER);
1160 break;
1161 default:
1162 return;
1164 size2 = size1 + (2 * sizeof (DWORD));
1165 size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1167 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA, size1);
1168 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA, size2);
1169 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO, size3);
1170 FIXUP_PDU_SIZE(spoolss_RFNPCNEX, size3);
1173 void
1174 fixup_spoolss_GetPrinter(struct spoolss_GetPrinter *val)
1176 unsigned short size1 = 0;
1177 unsigned short size2 = 0;
1178 unsigned short size3 = 0;
1180 switch (val->switch_value) {
1181 CASE_INFO_ENT(spoolss_GetPrinter, 0);
1182 CASE_INFO_ENT(spoolss_GetPrinter, 1);
1183 CASE_INFO_ENT(spoolss_GetPrinter, 2);
1184 CASE_INFO_ENT(spoolss_GetPrinter, 3);
1185 CASE_INFO_ENT(spoolss_GetPrinter, 4);
1186 CASE_INFO_ENT(spoolss_GetPrinter, 5);
1187 CASE_INFO_ENT(spoolss_GetPrinter, 6);
1188 CASE_INFO_ENT(spoolss_GetPrinter, 7);
1189 CASE_INFO_ENT(spoolss_GetPrinter, 8);
1191 default:
1192 return;
1195 size2 = size1 + (2 * sizeof (DWORD));
1196 size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1198 FIXUP_PDU_SIZE(spoolss_GetPrinter_result_u, size1);
1199 FIXUP_PDU_SIZE(spoolss_GetPrinter_result, size2);
1200 FIXUP_PDU_SIZE(spoolss_GetPrinter, size3);
1203 #else /* CONFIG_SMB_PRINTING */
1206 * If not CONFIG_SMB_PRINTING, just provide a few "stubs".
1209 void
1210 spoolss_initialize(void)
1214 void
1215 spoolss_finalize(void)
1219 /*ARGSUSED*/
1220 void
1221 spoolss_register_copyfile(spoolss_copyfile_t copyfile)
1225 #endif /* CONFIG_SMB_PRINTING */