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