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  * Printing and Spooling RPC service.
27  */
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <pthread.h>
32 #include <synch.h>
33 #include <smbsrv/libsmb.h>
34 #include <smbsrv/libmlrpc.h>
35 #include <smbsrv/libmlsvc.h>
36 #include <smbsrv/ndl/ndrtypes.ndl>
37 #include <smbsrv/ndl/spoolss.ndl>
38 #include <smb/nterror.h>
39 #include <smbsrv/smbinfo.h>
40 #include <smbsrv/nmpipes.h>
41 #include <wchar.h>
42 #include <cups/cups.h>
43 #include <fcntl.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <errno.h>
47 #include <dlfcn.h>
48 #include <mlsvc.h>
49 
50 typedef struct smb_spool {
51 	list_t sp_list;
52 	int sp_cnt;
53 	rwlock_t sp_rwl;
54 	int sp_initialized;
55 } smb_spool_t;
56 
57 static uint32_t spoolss_cnt;
58 static uint32_t spoolss_jobnum = 1;
59 static smb_spool_t spoolss_splist;
60 static smb_cups_ops_t smb_cups;
61 static mutex_t spoolss_cups_mutex;
62 
63 #define	SPOOLSS_PJOBLEN		256
64 #define	SPOOLSS_JOB_NOT_ISSUED	3004
65 #define	SPOOLSS_PRINTER		"Postscript"
66 #define	SPOOLSS_FN_PREFIX	"cifsprintjob-"
67 #define	SPOOLSS_CUPS_SPOOL_DIR	"//var//spool//cups"
68 
69 struct spoolss_printjob {
70 	pid_t pj_pid;
71 	int pj_sysjob;
72 	int pj_fd;
73 	time_t pj_start_time;
74 	int pj_status;
75 	size_t pj_size;
76 	int pj_page_count;
77 	boolean_t pj_isspooled;
78 	boolean_t pj_jobnum;
79 	char pj_filename[SPOOLSS_PJOBLEN];
80 	char pj_jobname[SPOOLSS_PJOBLEN];
81 	char pj_username[SPOOLSS_PJOBLEN];
82 	char pj_queuename[SPOOLSS_PJOBLEN];
83 };
84 
85 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result_u);
86 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result);
87 DECL_FIXUP_STRUCT(spoolss_GetPrinter);
88 
89 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA);
90 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA);
91 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO);
92 DECL_FIXUP_STRUCT(spoolss_RFNPCNEX);
93 
94 uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *);
95 static int spoolss_s_make_sd(uint8_t *);
96 static uint32_t spoolss_sd_format(smb_sd_t *);
97 static int spoolss_find_fd(ndr_hdid_t *);
98 static void spoolss_find_doc_and_print(ndr_hdid_t *);
99 static void spoolss_add_spool_doc(smb_spooldoc_t *);
100 static int spoolss_cups_init(void);
101 static void spoolss_cups_fini(void);
102 
103 static int spoolss_s_OpenPrinter(void *, ndr_xa_t *);
104 static int spoolss_s_ClosePrinter(void *, ndr_xa_t *);
105 static int spoolss_s_AbortPrinter(void *, ndr_xa_t *);
106 static int spoolss_s_ResetPrinter(void *, ndr_xa_t *);
107 static int spoolss_s_GetPrinter(void *, ndr_xa_t *);
108 static int spoolss_s_GetPrinterData(void *, ndr_xa_t *);
109 static int spoolss_s_AddJob(void *, ndr_xa_t *);
110 static int spoolss_s_GetJob(void *, ndr_xa_t *);
111 static int spoolss_s_EnumJobs(void *, ndr_xa_t *);
112 static int spoolss_s_ScheduleJob(void *, ndr_xa_t *);
113 static int spoolss_s_StartDocPrinter(void *, ndr_xa_t *);
114 static int spoolss_s_EndDocPrinter(void *, ndr_xa_t *);
115 static int spoolss_s_StartPagePrinter(void *, ndr_xa_t *);
116 static int spoolss_s_EndPagePrinter(void *, ndr_xa_t *);
117 static int spoolss_s_rfnpcnex(void *, ndr_xa_t *);
118 static int spoolss_s_WritePrinter(void *, ndr_xa_t *);
119 static int spoolss_s_EnumForms(void *, ndr_xa_t *);
120 static int spoolss_s_stub(void *, ndr_xa_t *);
121 
122 static ndr_stub_table_t spoolss_stub_table[] = {
123 	{ spoolss_s_GetJob,		SPOOLSS_OPNUM_GetJob },
124 	{ spoolss_s_EnumJobs,		SPOOLSS_OPNUM_EnumJobs },
125 	{ spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinter },
126 	{ spoolss_s_GetPrinter,		SPOOLSS_OPNUM_GetPrinter },
127 	{ spoolss_s_stub,		SPOOLSS_OPNUM_GetPrinterDriver },
128 	{ spoolss_s_stub,		SPOOLSS_OPNUM_DeletePrinterDriver },
129 	{ spoolss_s_OpenPrinter,	SPOOLSS_OPNUM_OpenPrinter },
130 	{ spoolss_s_StartDocPrinter,	SPOOLSS_OPNUM_StartDocPrinter },
131 	{ spoolss_s_WritePrinter,	SPOOLSS_OPNUM_WritePrinter },
132 	{ spoolss_s_EndDocPrinter,	SPOOLSS_OPNUM_EndDocPrinter },
133 	{ spoolss_s_StartPagePrinter,	SPOOLSS_OPNUM_StartPagePrinter },
134 	{ spoolss_s_EndPagePrinter,	SPOOLSS_OPNUM_EndPagePrinter },
135 	{ spoolss_s_AbortPrinter,	SPOOLSS_OPNUM_AbortPrinter },
136 	{ spoolss_s_ResetPrinter,	SPOOLSS_OPNUM_ResetPrinter },
137 	{ spoolss_s_AddJob,		SPOOLSS_OPNUM_AddJob },
138 	{ spoolss_s_ScheduleJob,    	SPOOLSS_OPNUM_ScheduleJob },
139 	{ spoolss_s_GetPrinterData,	SPOOLSS_OPNUM_GetPrinterData },
140 	{ spoolss_s_ClosePrinter,	SPOOLSS_OPNUM_ClosePrinter },
141 	{ spoolss_s_EnumForms,		SPOOLSS_OPNUM_EnumForms },
142 	{ spoolss_s_stub,		SPOOLSS_OPNUM_GetPrinterDriver2 },
143 	{ spoolss_s_stub,		SPOOLSS_OPNUM_FCPN },
144 	{ spoolss_s_stub,		SPOOLSS_OPNUM_ReplyOpenPrinter },
145 	{ spoolss_s_stub,		SPOOLSS_OPNUM_ReplyClosePrinter },
146 	{ spoolss_s_stub,		SPOOLSS_OPNUM_RFFPCNEX },
147 	{ spoolss_s_rfnpcnex,		SPOOLSS_OPNUM_RFNPCNEX },
148 	{ spoolss_s_stub,		SPOOLSS_OPNUM_RRPCN },
149 	{ spoolss_s_OpenPrinter,	SPOOLSS_OPNUM_OpenPrinterEx },
150 	{ spoolss_s_stub,		SPOOLSS_OPNUM_EnumPrinterData },
151 	{ spoolss_s_stub,		SPOOLSS_OPNUM_EnumPrinterDataEx },
152 	{ spoolss_s_stub,		SPOOLSS_OPNUM_EnumPrinterKey },
153 	{0}
154 };
155 
156 static ndr_service_t spoolss_service = {
157 	"SPOOLSS",			/* name */
158 	"Print Spool Service",		/* desc */
159 	"\\spoolss",			/* endpoint */
160 	PIPE_SPOOLSS,			/* sec_addr_port */
161 	"12345678-1234-abcd-ef00-0123456789ab",	1,	/* abstract */
162 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
163 	0,				/* no bind_instance_size */
164 	0,				/* no bind_req() */
165 	0,				/* no unbind_and_close() */
166 	0,				/* use generic_call_stub() */
167 	&TYPEINFO(spoolss_interface),	/* interface ti */
168 	spoolss_stub_table		/* stub_table */
169 };
170 
171 /*
172  * Defer calling spoolss_cups_init() until something actually
173  * needs access to CUPS due to the libcups dependency on OpenSSL.
174  * OpenSSL is not MT-safe and initializing CUPS here can crash
175  * OpenSSL if it collides with other threads that are in other
176  * libraries that are attempting to use OpenSSL.
177  */
178 void
179 spoolss_initialize(void)
180 {
181 	(void) ndr_svc_register(&spoolss_service);
182 }
183 
184 void
185 spoolss_finalize(void)
186 {
187 	spoolss_cups_fini();
188 }
189 
190 static int
191 spoolss_s_OpenPrinter(void *arg, ndr_xa_t *mxa)
192 {
193 	struct spoolss_OpenPrinter *param = arg;
194 	ndr_hdid_t *id;
195 
196 	if ((id = ndr_hdalloc(mxa, 0)) == NULL) {
197 		bzero(&param->handle, sizeof (spoolss_handle_t));
198 		param->status = ERROR_NOT_ENOUGH_MEMORY;
199 		return (NDR_DRC_OK);
200 	}
201 
202 	bcopy(id, &param->handle, sizeof (spoolss_handle_t));
203 	param->status = 0;
204 
205 	return (NDR_DRC_OK);
206 }
207 
208 /*ARGSUSED*/
209 static int
210 spoolss_s_StartPagePrinter(void *arg, ndr_xa_t *mxa)
211 {
212 	struct spoolss_StartPagePrinter *param = arg;
213 
214 	param->status = ERROR_SUCCESS;
215 
216 	return (NDR_DRC_OK);
217 }
218 
219 /*ARGSUSED*/
220 static int
221 spoolss_s_EndPagePrinter(void *arg, ndr_xa_t *mxa)
222 {
223 	struct spoolss_EndPagePrinter *param = arg;
224 
225 	param->status = ERROR_SUCCESS;
226 
227 	return (NDR_DRC_OK);
228 }
229 
230 /*
231  *
232  * adds new spool doc to the tail.  used by windows
233  * XP and 2000 only
234  *
235  * Return values
236  *      smb_spooldoc_t - NULL if not found
237  */
238 
239 static void
240 spoolss_add_spool_doc(smb_spooldoc_t *sp)
241 {
242 	(void) rw_wrlock(&spoolss_splist.sp_rwl);
243 	if (!spoolss_splist.sp_initialized) {
244 		list_create(&spoolss_splist.sp_list,
245 		    sizeof (smb_spooldoc_t),
246 		    offsetof(smb_spooldoc_t, sd_lnd));
247 		spoolss_splist.sp_initialized = 1;
248 	}
249 	list_insert_tail(&spoolss_splist.sp_list, sp);
250 	spoolss_splist.sp_cnt++;
251 	(void) rw_unlock(&spoolss_splist.sp_rwl);
252 }
253 
254 /*
255  *
256  * finds a completed spool doc using the RPC handle
257  * as the key, then prints the doc
258  *
259  * XP and 2000 only
260  *
261  */
262 
263 static void
264 spoolss_find_doc_and_print(ndr_hdid_t *handle)
265 {
266 	smb_spooldoc_t *sp;
267 
268 	if (!spoolss_splist.sp_initialized) {
269 		syslog(LOG_ERR, "spoolss_find_doc_and_print: not initialized");
270 		return;
271 	}
272 	(void) rw_wrlock(&spoolss_splist.sp_rwl);
273 	sp = list_head(&spoolss_splist.sp_list);
274 	while (sp != NULL) {
275 		/*
276 		 * search the spooldoc list for a matching RPC handle
277 		 * and use the info to pass to cups for printing
278 		 */
279 		if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
280 			spoolss_copy_spool_file(&sp->sd_ipaddr,
281 			    sp->sd_username, sp->sd_path, sp->sd_doc_name);
282 			(void) close(sp->sd_fd);
283 			list_remove(&spoolss_splist.sp_list, sp);
284 			free(sp);
285 			(void) rw_unlock(&spoolss_splist.sp_rwl);
286 			return;
287 		}
288 		sp = list_next(&spoolss_splist.sp_list, sp);
289 	}
290 	syslog(LOG_ERR, "spoolss_find_doc_and_print: handle not found");
291 	(void) rw_unlock(&spoolss_splist.sp_rwl);
292 }
293 
294 static int
295 spoolss_find_fd(ndr_hdid_t *handle)
296 {
297 	smb_spooldoc_t *sp;
298 
299 	if (!spoolss_splist.sp_initialized) {
300 		syslog(LOG_ERR, "spoolss_find_fd: not initialized");
301 		return (-1);
302 	}
303 	(void) rw_rdlock(&spoolss_splist.sp_rwl);
304 	sp = list_head(&spoolss_splist.sp_list);
305 	while (sp != NULL) {
306 		/*
307 		 * check for a matching rpc handle in the
308 		 * spooldoc list
309 		 */
310 		if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
311 			(void) rw_unlock(&spoolss_splist.sp_rwl);
312 			return (sp->sd_fd);
313 		}
314 		sp = list_next(&spoolss_splist.sp_list, sp);
315 	}
316 	syslog(LOG_ERR, "spoolss_find_fd: handle not found");
317 	(void) rw_unlock(&spoolss_splist.sp_rwl);
318 	return (-1);
319 }
320 
321 /*
322  * Windows XP and 2000 use this mechanism to write spool files.
323  * Creates a spool file fd to be used by spoolss_s_WritePrinter.
324  */
325 static int
326 spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa)
327 {
328 	struct spoolss_StartDocPrinter *param = arg;
329 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
330 	smb_spooldoc_t *spfile;
331 	spoolss_DocInfo_t *docinfo;
332 	char g_path[MAXPATHLEN];
333 	smb_share_t si;
334 	int rc;
335 	int fd;
336 
337 	if (ndr_hdlookup(mxa, id) == NULL) {
338 		syslog(LOG_ERR, "spoolss_s_StartDocPrinter: invalid handle");
339 		param->status = ERROR_INVALID_HANDLE;
340 		return (NDR_DRC_OK);
341 	}
342 
343 	if ((docinfo = param->dinfo.DocInfoContainer) == NULL) {
344 		param->status = ERROR_INVALID_PARAMETER;
345 		return (NDR_DRC_OK);
346 	}
347 
348 	if ((rc = smb_shr_get(SMB_SHARE_PRINT, &si)) != NERR_Success) {
349 		syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s error=%d",
350 		    SMB_SHARE_PRINT, rc);
351 		param->status = rc;
352 		return (NDR_DRC_OK);
353 	}
354 
355 	if ((spfile = calloc(1, sizeof (smb_spooldoc_t))) == NULL) {
356 		param->status = ERROR_NOT_ENOUGH_MEMORY;
357 		return (NDR_DRC_OK);
358 	}
359 
360 	if (docinfo->doc_name != NULL)
361 		(void) strlcpy(spfile->sd_doc_name,
362 		    (char *)docinfo->doc_name, MAXNAMELEN);
363 	else
364 		(void) strlcpy(spfile->sd_doc_name, "document", MAXNAMELEN);
365 
366 	if (docinfo->printer_name != NULL)
367 		(void) strlcpy(spfile->sd_printer_name,
368 		    (char *)docinfo->printer_name, MAXPATHLEN);
369 	else
370 		(void) strlcpy(spfile->sd_printer_name, "printer", MAXPATHLEN);
371 
372 	spfile->sd_ipaddr = mxa->pipe->np_user.ui_ipaddr;
373 	(void) strlcpy((char *)spfile->sd_username,
374 	    mxa->pipe->np_user.ui_account, MAXNAMELEN);
375 	(void) memcpy(&spfile->sd_handle, &param->handle,
376 	    sizeof (rpc_handle_t));
377 	/*
378 	 *	write temporary spool file to print$
379 	 */
380 	(void) snprintf(g_path, MAXPATHLEN, "%s/%s%d", si.shr_path,
381 	    spfile->sd_username, spoolss_cnt);
382 	atomic_inc_32(&spoolss_cnt);
383 
384 	fd = open(g_path, O_CREAT | O_RDWR, 0600);
385 	if (fd == -1) {
386 		syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s: %s",
387 		    g_path, strerror(errno));
388 		param->status = ERROR_OPEN_FAILED;
389 		free(spfile);
390 	} else {
391 		(void) strlcpy((char *)spfile->sd_path, g_path, MAXPATHLEN);
392 		spfile->sd_fd = (uint16_t)fd;
393 		spoolss_add_spool_doc(spfile);
394 		/*
395 		 * JobId isn't used now, but if printQ management is added
396 		 * this will have to be incremented per job submitted.
397 		 */
398 		param->JobId = 46;
399 		param->status = ERROR_SUCCESS;
400 	}
401 	return (NDR_DRC_OK);
402 }
403 
404 /*
405  * Windows XP and 2000 use this mechanism to write spool files
406  */
407 
408 /*ARGSUSED*/
409 static int
410 spoolss_s_EndDocPrinter(void *arg, ndr_xa_t *mxa)
411 {
412 	struct spoolss_EndDocPrinter *param = arg;
413 
414 	spoolss_find_doc_and_print((ndr_hdid_t *)&param->handle);
415 	param->status = ERROR_SUCCESS;
416 	return (NDR_DRC_OK);
417 }
418 
419 /*ARGSUSED*/
420 static int
421 spoolss_s_AbortPrinter(void *arg, ndr_xa_t *mxa)
422 {
423 	struct spoolss_AbortPrinter *param = arg;
424 
425 	param->status = ERROR_SUCCESS;
426 	return (NDR_DRC_OK);
427 }
428 
429 /*ARGSUSED*/
430 static int
431 spoolss_s_ResetPrinter(void *arg, ndr_xa_t *mxa)
432 {
433 	struct spoolss_AbortPrinter *param = arg;
434 
435 	param->status = ERROR_SUCCESS;
436 	return (NDR_DRC_OK);
437 }
438 
439 static int
440 spoolss_s_ClosePrinter(void *arg, ndr_xa_t *mxa)
441 {
442 	struct spoolss_ClosePrinter *param = arg;
443 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
444 	ndr_handle_t *hd;
445 
446 	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
447 		free(hd->nh_data);
448 		hd->nh_data = NULL;
449 	}
450 
451 	ndr_hdfree(mxa, id);
452 	bzero(&param->result_handle, sizeof (spoolss_handle_t));
453 	param->status = ERROR_SUCCESS;
454 	return (NDR_DRC_OK);
455 }
456 
457 /*ARGSUSED*/
458 int
459 spoolss_s_EnumForms(void *arg, ndr_xa_t *mxa)
460 {
461 	struct spoolss_EnumForms *param = arg;
462 	DWORD status = ERROR_SUCCESS;
463 
464 	param->status = status;
465 	param->needed = 0;
466 	return (NDR_DRC_OK);
467 }
468 
469 /*ARGSUSED*/
470 int
471 spoolss_s_EnumJobs(void *arg, ndr_xa_t *mxa)
472 {
473 	struct spoolss_EnumJobs *param = arg;
474 	DWORD status = ERROR_SUCCESS;
475 
476 	switch (param->level) {
477 	case 1:
478 	case 2:
479 	case 3:
480 	case 4:
481 	default:
482 		break;
483 	}
484 
485 	param->status = status;
486 	param->needed = 0;
487 	param->needed2 = 0;
488 	return (NDR_DRC_OK);
489 }
490 
491 
492 /*ARGSUSED*/
493 static int
494 spoolss_s_GetJob(void *arg, ndr_xa_t *mxa)
495 {
496 	struct spoolss_GetJob *param = arg;
497 	DWORD status = ERROR_SUCCESS;
498 
499 	if (param->BufCount == 0)
500 		param->status = ERROR_INSUFFICIENT_BUFFER;
501 	else
502 		param->status = status;
503 	param->needed = 0;
504 	return (NDR_DRC_OK);
505 }
506 
507 
508 /*ARGSUSED*/
509 static int
510 spoolss_s_ScheduleJob(void *arg, ndr_xa_t *mxa)
511 {
512 	struct spoolss_ScheduleJob *param = arg;
513 	DWORD status = SPOOLSS_JOB_NOT_ISSUED;
514 
515 	param->status = status;
516 	return (NDR_DRC_OK);
517 }
518 
519 /*ARGSUSED*/
520 static int
521 spoolss_s_AddJob(void *arg, ndr_xa_t *mxa)
522 {
523 	struct spoolss_AddJob *param = arg;
524 
525 	param->status = ERROR_SUCCESS;
526 	param->needed = 0;
527 	return (NDR_DRC_OK);
528 }
529 
530 /*ARGSUSED*/
531 static int
532 spoolss_s_rfnpcnex(void *arg, ndr_xa_t *mxa)
533 {
534 	struct spoolss_RFNPCNEX *param = arg;
535 
536 	param->ppinfo = 0;
537 	param->status = ERROR_SUCCESS;
538 	return (NDR_DRC_OK);
539 }
540 
541 /*
542  * Use the RPC context handle to find the fd and write the document content.
543  */
544 static int
545 spoolss_s_WritePrinter(void *arg, ndr_xa_t *mxa)
546 {
547 	struct spoolss_WritePrinter *param = arg;
548 	int written = 0;
549 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
550 	int spfd;
551 
552 	if (ndr_hdlookup(mxa, id) == NULL) {
553 		param->written = 0;
554 		param->status = ERROR_INVALID_HANDLE;
555 		syslog(LOG_ERR, "spoolss_s_WritePrinter: invalid handle");
556 		return (NDR_DRC_OK);
557 	}
558 
559 	if ((spfd = spoolss_find_fd(id)) < 0) {
560 		param->written = 0;
561 		param->status = ERROR_INVALID_HANDLE;
562 		syslog(LOG_ERR, "spoolss_s_WritePrinter: cannot find fd");
563 		return (NDR_DRC_OK);
564 	}
565 
566 	written = write(spfd, param->pBuf, param->BufCount);
567 	if (written < param->BufCount) {
568 		syslog(LOG_ERR, "spoolss_s_WritePrinter: write failed");
569 		param->written = 0;
570 		param->status = ERROR_CANTWRITE;
571 		return (NDR_DRC_OK);
572 	}
573 
574 	param->written = written;
575 	param->status = ERROR_SUCCESS;
576 	return (NDR_DRC_OK);
577 }
578 
579 /*
580  * All versions of windows use this function to print
581  * spool files via the cups interface
582  */
583 
584 void
585 spoolss_copy_spool_file(smb_inaddr_t *ipaddr, char *username,
586     char *path, char *doc_name)
587 {
588 	smb_cups_ops_t	*cups;
589 	int		ret = 1;		/* Return value */
590 	http_t		*http = NULL;		/* HTTP connection to server */
591 	ipp_t		*request = NULL;	/* IPP Request */
592 	ipp_t		*response = NULL;	/* IPP Response */
593 	cups_lang_t	*language = NULL;	/* Default language */
594 	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
595 	char		new_jobname[SPOOLSS_PJOBLEN];
596 	struct		spoolss_printjob pjob;
597 	char 		clientname[INET6_ADDRSTRLEN];
598 	struct stat 	sbuf;
599 
600 	if (stat(path, &sbuf)) {
601 		syslog(LOG_INFO, "spoolss_copy_spool_file: %s: %s",
602 		    path, strerror(errno));
603 		return;
604 	}
605 
606 	/*
607 	 * Remove zero size files and return; these were inadvertantly
608 	 * created by XP or 2000.
609 	 */
610 	if (sbuf.st_blocks == 0) {
611 		if (remove(path))
612 			syslog(LOG_INFO,
613 			    "spoolss_copy_spool_file: cannot remove %s", path);
614 		return;
615 	}
616 
617 	if ((cups = spoolss_cups_ops()) == NULL)
618 		return;
619 
620 	if ((http = cups->httpConnect("localhost", 631)) == NULL) {
621 		syslog(LOG_INFO, "spoolss_copy_spool_file: cupsd not running");
622 		return;
623 	}
624 
625 	if ((request = cups->ippNew()) == NULL) {
626 		syslog(LOG_INFO, "spoolss_copy_spool_file: ipp not running");
627 		return;
628 	}
629 	request->request.op.operation_id = IPP_PRINT_JOB;
630 	request->request.op.request_id = 1;
631 	language = cups->cupsLangDefault();
632 
633 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
634 	    "attributes-charset", NULL, cups->cupsLangEncoding(language));
635 
636 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
637 	    "attributes-natural-language", NULL, language->language);
638 
639 	(void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s",
640 	    SPOOLSS_PRINTER);
641 	pjob.pj_pid = pthread_self();
642 	pjob.pj_sysjob = 10;
643 	(void) strlcpy(pjob.pj_filename, path, SPOOLSS_PJOBLEN);
644 	pjob.pj_start_time = time(NULL);
645 	pjob.pj_status = 2;
646 	pjob.pj_size = sbuf.st_blocks * 512;
647 	pjob.pj_page_count = 1;
648 	pjob.pj_isspooled = B_TRUE;
649 	pjob.pj_jobnum = spoolss_jobnum;
650 
651 	(void) strlcpy(pjob.pj_jobname, doc_name, SPOOLSS_PJOBLEN);
652 	(void) strlcpy(pjob.pj_username, username, SPOOLSS_PJOBLEN);
653 	(void) strlcpy(pjob.pj_queuename, SPOOLSS_CUPS_SPOOL_DIR,
654 	    SPOOLSS_PJOBLEN);
655 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
656 	    "printer-uri", NULL, uri);
657 
658 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
659 	    "requesting-user-name", NULL, pjob.pj_username);
660 
661 	if (smb_inet_ntop(ipaddr, clientname,
662 	    SMB_IPSTRLEN(ipaddr->a_family)) == NULL) {
663 		syslog(LOG_INFO, "spoolss_copy_spool_file: %s: unknown client",
664 		    clientname);
665 		goto out;
666 	}
667 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
668 	    "job-originating-host-name", NULL, clientname);
669 
670 	(void) snprintf(new_jobname, SPOOLSS_PJOBLEN, "%s%d",
671 	    SPOOLSS_FN_PREFIX, pjob.pj_jobnum);
672 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
673 	    "job-name", NULL, new_jobname);
674 
675 	(void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SPOOLSS_PRINTER);
676 
677 	response = cups->cupsDoFileRequest(http, request, uri,
678 	    pjob.pj_filename);
679 	if (response != NULL) {
680 		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
681 			syslog(LOG_ERR,
682 			    "spoolss_copy_spool_file: file print %s: %s",
683 			    SPOOLSS_PRINTER,
684 			    cups->ippErrorString(cups->cupsLastError()));
685 		} else {
686 			atomic_inc_32(&spoolss_jobnum);
687 			ret = 0;
688 		}
689 	} else {
690 		syslog(LOG_ERR,
691 		    "spoolss_copy_spool_file: unable to print file to %s",
692 		    cups->ippErrorString(cups->cupsLastError()));
693 	}
694 
695 	if (ret == 0)
696 		(void) unlink(pjob.pj_filename);
697 
698 out:
699 	if (response)
700 		cups->ippDelete(response);
701 
702 	if (language)
703 		cups->cupsLangFree(language);
704 
705 	if (http)
706 		cups->httpClose(http);
707 }
708 
709 static int
710 spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa)
711 {
712 	struct spoolss_GetPrinterData *param = arg;
713 	DWORD status = ERROR_SUCCESS;
714 
715 	if (param->Size > 0) {
716 		param->Buf = NDR_NEWN(mxa, char, param->Size);
717 		bzero(param->Buf, param->Size);
718 	} else {
719 		param->Buf = NDR_NEWN(mxa, uint32_t, 1);
720 		param->Buf[0] = 1;
721 		param->Buf[1] = 1;
722 		param->Buf[2] = 2;
723 		param->Buf[3] = 2;
724 	}
725 
726 	/*
727 	 * Increment pType if the Printer Data changes
728 	 * as specified by Microsoft documentation
729 	 */
730 	param->pType = 1;
731 	if (strcasecmp((char *)param->pValueName, "ChangeId") == 0) {
732 		param->pType = 4;
733 		param->Buf[3] = 0x00;
734 		param->Buf[2] = 0x50;
735 		param->Buf[1] = 0xac;
736 		param->Buf[0] = 0xf2;
737 	} else if (strcasecmp((char *)param->pValueName,
738 	    "UISingleJobStatusString") == 0) {
739 		status = ERROR_FILE_NOT_FOUND;
740 	} else if (strcasecmp((char *)param->pValueName,
741 	    "W3SvcInstalled") == 0) {
742 		status = ERROR_FILE_NOT_FOUND;
743 	} else if (strcasecmp((char *)param->pValueName,
744 	    "PrintProcCaps_NT EMF 1.008") == 0) {
745 		status = ERROR_FILE_NOT_FOUND;
746 	} else if (strcasecmp((char *)param->pValueName, "OSVersion") == 0) {
747 		param->Buf = NDR_NEWN(mxa, char, param->Size);
748 		bzero(param->Buf, param->Size);
749 		param->Buf[0] = 0x14;
750 		param->Buf[1] = 0x01;
751 		param->Buf[4] = 0x05;
752 		param->Buf[12] = 0x93;
753 		param->Buf[13] = 0x08;
754 	}
755 	param->status = status;
756 	param->Needed = param->Size;
757 	return (NDR_DRC_OK);
758 }
759 
760 smb_cups_ops_t *
761 spoolss_cups_ops(void)
762 {
763 	if (spoolss_cups_init() != 0)
764 		return (NULL);
765 
766 	return (&smb_cups);
767 }
768 
769 static int
770 spoolss_cups_init(void)
771 {
772 	(void) mutex_lock(&spoolss_cups_mutex);
773 
774 	if (smb_cups.cups_hdl != NULL) {
775 		(void) mutex_unlock(&spoolss_cups_mutex);
776 		return (0);
777 	}
778 
779 	if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) {
780 		(void) mutex_unlock(&spoolss_cups_mutex);
781 		syslog(LOG_DEBUG, "spoolss_cups_init: cannot open libcups");
782 		return (ENOENT);
783 	}
784 
785 	smb_cups.cupsLangDefault =
786 	    (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault");
787 	smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *))
788 	    dlsym(smb_cups.cups_hdl, "cupsLangEncoding");
789 	smb_cups.cupsDoFileRequest =
790 	    (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *))
791 	    dlsym(smb_cups.cups_hdl, "cupsDoFileRequest");
792 	smb_cups.cupsLastError = (ipp_status_t (*)())
793 	    dlsym(smb_cups.cups_hdl, "cupsLastError");
794 	smb_cups.cupsLangFree = (void (*)(cups_lang_t *))
795 	    dlsym(smb_cups.cups_hdl, "cupsLangFree");
796 	smb_cups.cupsGetDests = (int (*)(cups_dest_t **))
797 	    dlsym(smb_cups.cups_hdl, "cupsGetDests");
798 	smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *))
799 	    dlsym(smb_cups.cups_hdl, "cupsFreeDests");
800 
801 	smb_cups.httpClose = (void (*)(http_t *))
802 	    dlsym(smb_cups.cups_hdl, "httpClose");
803 	smb_cups.httpConnect = (http_t *(*)(const char *, int))
804 	    dlsym(smb_cups.cups_hdl, "httpConnect");
805 
806 	smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew");
807 	smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete");
808 	smb_cups.ippErrorString = (char *(*)())
809 	    dlsym(smb_cups.cups_hdl, "ippErrorString");
810 	smb_cups.ippAddString = (ipp_attribute_t *(*)())
811 	    dlsym(smb_cups.cups_hdl, "ippAddString");
812 
813 	if (smb_cups.cupsLangDefault == NULL ||
814 	    smb_cups.cupsLangEncoding == NULL ||
815 	    smb_cups.cupsDoFileRequest == NULL ||
816 	    smb_cups.cupsLastError == NULL ||
817 	    smb_cups.cupsLangFree == NULL ||
818 	    smb_cups.cupsGetDests == NULL ||
819 	    smb_cups.cupsFreeDests == NULL ||
820 	    smb_cups.ippNew == NULL ||
821 	    smb_cups.httpClose == NULL ||
822 	    smb_cups.httpConnect == NULL ||
823 	    smb_cups.ippDelete == NULL ||
824 	    smb_cups.ippErrorString == NULL ||
825 	    smb_cups.ippAddString == NULL) {
826 		smb_dlclose(smb_cups.cups_hdl);
827 		smb_cups.cups_hdl = NULL;
828 		(void) mutex_unlock(&spoolss_cups_mutex);
829 		syslog(LOG_DEBUG, "spoolss_cups_init: cannot load libcups");
830 		return (ENOENT);
831 	}
832 
833 	(void) mutex_unlock(&spoolss_cups_mutex);
834 	return (0);
835 }
836 
837 static void
838 spoolss_cups_fini(void)
839 {
840 	(void) mutex_lock(&spoolss_cups_mutex);
841 
842 	if (smb_cups.cups_hdl != NULL) {
843 		smb_dlclose(smb_cups.cups_hdl);
844 		smb_cups.cups_hdl = NULL;
845 	}
846 
847 	(void) mutex_unlock(&spoolss_cups_mutex);
848 }
849 
850 void
851 smb_rpc_off(char *dst, char *src, uint32_t *offset, uint32_t *outoffset)
852 {
853 	int nwchars;
854 	int bytes;
855 
856 	bytes = smb_wcequiv_strlen(src) + 2;
857 	nwchars = strlen(src) + 1;
858 	*offset -= bytes;
859 	*outoffset = *offset;
860 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
861 	(void) smb_mbstowcs(((smb_wchar_t *)(dst + *offset)), src, nwchars);
862 }
863 
864 int
865 spoolss_s_GetPrinter(void *arg, ndr_xa_t *mxa)
866 {
867 	struct spoolss_GetPrinter *param = arg;
868 	struct spoolss_GetPrinter0 *pinfo0;
869 	struct spoolss_GetPrinter1 *pinfo1;
870 	struct spoolss_GetPrinter2 *pinfo2;
871 	struct spoolss_DeviceMode *devmode2;
872 	DWORD status = ERROR_SUCCESS;
873 	char *wname;
874 	uint32_t offset;
875 	smb_inaddr_t ipaddr;
876 	struct hostent *h;
877 	char hname[MAXHOSTNAMELEN];
878 	char soutbuf[MAXNAMELEN];
879 	char poutbuf[MAXNAMELEN];
880 	char ipstr[INET6_ADDRSTRLEN];
881 	int error;
882 	uint8_t *tmpbuf;
883 
884 	if (param->BufCount == 0) {
885 		status = ERROR_INSUFFICIENT_BUFFER;
886 		goto error_out;
887 	}
888 	param->Buf = NDR_NEWN(mxa, char, param->BufCount);
889 	bzero(param->Buf, param->BufCount);
890 	switch (param->switch_value) {
891 	case 0:
892 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
893 		pinfo0 = (struct spoolss_GetPrinter0 *)param->Buf;
894 		break;
895 	case 1:
896 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
897 		pinfo1 = (struct spoolss_GetPrinter1 *)param->Buf;
898 		break;
899 	case 2:
900 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
901 		pinfo2 = (struct spoolss_GetPrinter2 *)param->Buf;
902 		break;
903 	}
904 	wname = (char *)param->Buf;
905 
906 	status = ERROR_INVALID_PARAMETER;
907 	if (smb_gethostname(hname, MAXHOSTNAMELEN, 0) != 0) {
908 		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: gethostname failed");
909 		goto error_out;
910 	}
911 	if ((h = smb_gethostbyname(hname, &error)) == NULL) {
912 		syslog(LOG_NOTICE,
913 		    "spoolss_s_GetPrinter: gethostbyname failed");
914 		goto error_out;
915 	}
916 	bcopy(h->h_addr, &ipaddr, h->h_length);
917 	ipaddr.a_family = h->h_addrtype;
918 	freehostent(h);
919 	if (smb_inet_ntop(&ipaddr, ipstr, SMB_IPSTRLEN(ipaddr.a_family))
920 	    == NULL) {
921 		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: inet_ntop failed");
922 		goto error_out;
923 	}
924 	status = ERROR_SUCCESS;
925 	(void) snprintf(poutbuf, MAXNAMELEN, "\\\\%s\\%s",
926 	    ipstr, SPOOLSS_PRINTER);
927 	(void) snprintf(soutbuf, MAXNAMELEN, "\\\\%s", ipstr);
928 	param->needed = 0;
929 	switch (param->switch_value) {
930 	case 0:
931 		offset = 460;
932 		smb_rpc_off(wname, "", &offset, &pinfo0->servername);
933 		smb_rpc_off(wname, poutbuf, &offset, &pinfo0->printername);
934 		pinfo0->cjobs = 0;
935 		pinfo0->total_jobs = 6;
936 		pinfo0->total_bytes = 1040771;
937 		pinfo0->time0 = 0;
938 		pinfo0->time1 = 0;
939 		pinfo0->time2 = 3;
940 		pinfo0->time3 = 0;
941 		pinfo0->global_counter = 2162710;
942 		pinfo0->total_pages = 21495865;
943 		pinfo0->version = 10;
944 		pinfo0->session_counter = 1;
945 		pinfo0->job_error = 0x6;
946 		pinfo0->change_id  = 0x1;
947 		pinfo0->status = 0;
948 		pinfo0->c_setprinter = 0;
949 		break;
950 	case 1:
951 		pinfo1->flags = PRINTER_ENUM_ICON8;
952 		offset = 460;
953 		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->flags);
954 		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->description);
955 		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->comment);
956 		break;
957 	case 2:
958 		offset = param->BufCount;
959 		smb_rpc_off(wname, soutbuf, &offset, &pinfo2->servername);
960 		smb_rpc_off(wname, poutbuf, &offset, &pinfo2->printername);
961 		smb_rpc_off(wname, SPOOLSS_PRINTER, &offset,
962 		    &pinfo2->sharename);
963 		smb_rpc_off(wname, "CIFS Printer Port", &offset,
964 		    &pinfo2->portname);
965 		smb_rpc_off(wname, "", &offset, &pinfo2->drivername);
966 		smb_rpc_off(wname, SPOOLSS_PRINTER, &offset,
967 		    &pinfo2->comment);
968 		smb_rpc_off(wname, "farside", &offset, &pinfo2->location);
969 		smb_rpc_off(wname, "farside", &offset, &pinfo2->sepfile);
970 		smb_rpc_off(wname, "winprint", &offset,
971 		    &pinfo2->printprocessor);
972 		smb_rpc_off(wname, "RAW", &offset, &pinfo2->datatype);
973 		smb_rpc_off(wname, "", &offset, &pinfo2->datatype);
974 		pinfo2->attributes = 0x00001048;
975 		pinfo2->status = 0x00000000;
976 		pinfo2->starttime = 0;
977 		pinfo2->untiltime = 0;
978 		pinfo2->cjobs = 0;
979 		pinfo2->averageppm = 0;
980 		pinfo2->defaultpriority = 0;
981 		pinfo2->devmode = 568; // offset
982 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
983 		devmode2 = (struct spoolss_DeviceMode *)(param->Buf
984 		    + pinfo2->devmode);
985 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
986 		(void) smb_mbstowcs(((smb_wchar_t *)
987 		    (devmode2->devicename)), (const char *)poutbuf, 25);
988 		devmode2->specversion = 0x0401;
989 		devmode2->driverversion = 1024;
990 		devmode2->size = 220;
991 		devmode2->driverextra_length = 0;
992 		devmode2->fields = 0x00014713;
993 		devmode2->orientation = 1;
994 		devmode2->papersize = 1;
995 		devmode2->paperlength = 0;
996 		devmode2->paperwidth = 0;
997 		devmode2->scale = 100;
998 		devmode2->copies = 1;
999 		devmode2->defaultsource = 15;
1000 		devmode2->printquality = 65532;
1001 		devmode2->color = 1;
1002 		devmode2->duplex = 1;
1003 		devmode2->yresolution = 1;
1004 		devmode2->ttoption = 1;
1005 		devmode2->collate = 0;
1006 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1007 		(void) smb_mbstowcs(((smb_wchar_t *)
1008 		    (devmode2->formname)), (const char *)"Letter", 6);
1009 		devmode2->logpixels = 0;
1010 		devmode2->bitsperpel = 0;
1011 		devmode2->pelswidth = 0;
1012 		devmode2->pelsheight = 0;
1013 		devmode2->displayflags = 0;
1014 		devmode2->displayfrequency = 0;
1015 		devmode2->icmmethod = 0;
1016 		devmode2->icmintent = 0;
1017 		devmode2->mediatype = 0;
1018 		devmode2->dithertype = 0;
1019 		devmode2->reserved1 = 0;
1020 		devmode2->reserved2 = 0;
1021 		devmode2->panningwidth = 0;
1022 		devmode2->panningheight = 0;
1023 
1024 		pinfo2->secdesc = 84;
1025 		tmpbuf = (uint8_t *)(pinfo2->secdesc + (uint8_t *)param->Buf);
1026 		error = spoolss_s_make_sd(tmpbuf);
1027 		param->needed = 712;
1028 		break;
1029 
1030 	default:
1031 		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: INVALID_LEVEL");
1032 		status = ERROR_INVALID_LEVEL;
1033 		break;
1034 
1035 	}
1036 error_out:
1037 	param->status = status;
1038 	return (NDR_DRC_OK);
1039 }
1040 
1041 int
1042 spoolss_s_make_sd(uint8_t *sd_buf)
1043 {
1044 	smb_sd_t			sd;
1045 	uint32_t			status;
1046 
1047 	bzero(&sd, sizeof (smb_sd_t));
1048 
1049 	if ((status = spoolss_sd_format(&sd)) == ERROR_SUCCESS) {
1050 		status = srvsvc_sd_set_relative(&sd, sd_buf);
1051 		smb_sd_term(&sd);
1052 		return (NDR_DRC_OK);
1053 	}
1054 	syslog(LOG_NOTICE, "spoolss_s_make_sd: error status=%d", status);
1055 	smb_sd_term(&sd);
1056 	return (NDR_DRC_OK);
1057 }
1058 
1059 static uint32_t
1060 spoolss_sd_format(smb_sd_t *sd)
1061 {
1062 	smb_fssd_t	fs_sd;
1063 	acl_t		*acl;
1064 	uint32_t	status = ERROR_SUCCESS;
1065 
1066 	if (acl_fromtext("everyone@:full_set::allow", &acl) != 0) {
1067 		syslog(LOG_ERR, "spoolss_sd_format: NOT_ENOUGH_MEMORY");
1068 		return (ERROR_NOT_ENOUGH_MEMORY);
1069 	}
1070 	smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR);
1071 	fs_sd.sd_uid = 0;
1072 	fs_sd.sd_gid = 0;
1073 	fs_sd.sd_zdacl = acl;
1074 	fs_sd.sd_zsacl = NULL;
1075 
1076 	if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS) {
1077 		syslog(LOG_NOTICE, "spoolss_sd_format: ACCESS_DENIED");
1078 		status = ERROR_ACCESS_DENIED;
1079 	}
1080 	smb_fssd_term(&fs_sd);
1081 	return (status);
1082 }
1083 
1084 /*ARGSUSED*/
1085 static int
1086 spoolss_s_stub(void *arg, ndr_xa_t *mxa)
1087 {
1088 	return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
1089 }
1090 
1091 /*ARGSUSED*/
1092 void
1093 fixup_spoolss_RFNPCNEX(struct spoolss_RFNPCNEX *val)
1094 {
1095 	unsigned short size1 = 0;
1096 	unsigned short size2 = 0;
1097 	unsigned short size3 = 0;
1098 	struct spoolss_RPC_V2_NOTIFY_INFO *pinfo;
1099 
1100 	pinfo = val->ppinfo->pinfo;
1101 	switch (pinfo->aData->Reserved) {
1102 	case TABLE_STRING:
1103 		size1 = sizeof (struct STRING_CONTAINER);
1104 		break;
1105 	case TABLE_DWORD:
1106 		size1 = sizeof (DWORD) * 2;
1107 		break;
1108 	case TABLE_TIME:
1109 		size1 = sizeof (struct SYSTEMTIME_CONTAINER);
1110 		break;
1111 	case TABLE_DEVMODE:
1112 		size1 = sizeof (struct spoolssDevmodeContainer);
1113 		break;
1114 	case TABLE_SECURITY_DESCRIPTOR:
1115 		size1 = sizeof (struct SECURITY_CONTAINER);
1116 		break;
1117 	default:
1118 		return;
1119 	}
1120 	size2 = size1 + (2 * sizeof (DWORD));
1121 	size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1122 
1123 	FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA, size1);
1124 	FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA, size2);
1125 	FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO, size3);
1126 	FIXUP_PDU_SIZE(spoolss_RFNPCNEX, size3);
1127 }
1128 
1129 void
1130 fixup_spoolss_GetPrinter(struct spoolss_GetPrinter *val)
1131 {
1132 	unsigned short size1 = 0;
1133 	unsigned short size2 = 0;
1134 	unsigned short size3 = 0;
1135 
1136 	switch (val->switch_value) {
1137 	CASE_INFO_ENT(spoolss_GetPrinter, 0);
1138 	CASE_INFO_ENT(spoolss_GetPrinter, 1);
1139 	CASE_INFO_ENT(spoolss_GetPrinter, 2);
1140 	CASE_INFO_ENT(spoolss_GetPrinter, 3);
1141 	CASE_INFO_ENT(spoolss_GetPrinter, 4);
1142 	CASE_INFO_ENT(spoolss_GetPrinter, 5);
1143 	CASE_INFO_ENT(spoolss_GetPrinter, 6);
1144 	CASE_INFO_ENT(spoolss_GetPrinter, 7);
1145 	CASE_INFO_ENT(spoolss_GetPrinter, 8);
1146 
1147 	default:
1148 		return;
1149 	};
1150 
1151 	size2 = size1 + (2 * sizeof (DWORD));
1152 	size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1153 
1154 	FIXUP_PDU_SIZE(spoolss_GetPrinter_result_u, size1);
1155 	FIXUP_PDU_SIZE(spoolss_GetPrinter_result, size2);
1156 	FIXUP_PDU_SIZE(spoolss_GetPrinter, size3);
1157 }
1158