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