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