xref: /titanic_51/usr/src/cmd/smbsrv/smbd/smbd_spool.c (revision b819cea2f73f98c5662230cc9affc8cc84f77fcf)
1fd9ee8b5Sjoyce mcintosh /*
2fd9ee8b5Sjoyce mcintosh  * CDDL HEADER START
3fd9ee8b5Sjoyce mcintosh  *
4fd9ee8b5Sjoyce mcintosh  * The contents of this file are subject to the terms of the
5fd9ee8b5Sjoyce mcintosh  * Common Development and Distribution License (the "License").
6fd9ee8b5Sjoyce mcintosh  * You may not use this file except in compliance with the License.
7fd9ee8b5Sjoyce mcintosh  *
8fd9ee8b5Sjoyce mcintosh  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fd9ee8b5Sjoyce mcintosh  * or http://www.opensolaris.org/os/licensing.
10fd9ee8b5Sjoyce mcintosh  * See the License for the specific language governing permissions
11fd9ee8b5Sjoyce mcintosh  * and limitations under the License.
12fd9ee8b5Sjoyce mcintosh  *
13fd9ee8b5Sjoyce mcintosh  * When distributing Covered Code, include this CDDL HEADER in each
14fd9ee8b5Sjoyce mcintosh  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fd9ee8b5Sjoyce mcintosh  * If applicable, add the following below this CDDL HEADER, with the
16fd9ee8b5Sjoyce mcintosh  * fields enclosed by brackets "[]" replaced with your own identifying
17fd9ee8b5Sjoyce mcintosh  * information: Portions Copyright [yyyy] [name of copyright owner]
18fd9ee8b5Sjoyce mcintosh  *
19fd9ee8b5Sjoyce mcintosh  * CDDL HEADER END
20fd9ee8b5Sjoyce mcintosh  */
21fd9ee8b5Sjoyce mcintosh /*
22fd9ee8b5Sjoyce mcintosh  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2386d7016bSGordon Ross  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
24fd9ee8b5Sjoyce mcintosh  */
25fd9ee8b5Sjoyce mcintosh 
26fd9ee8b5Sjoyce mcintosh /*
27fd9ee8b5Sjoyce mcintosh  * CUPS support for the SMB and SPOOLSS print services.
28fd9ee8b5Sjoyce mcintosh  */
29fd9ee8b5Sjoyce mcintosh 
30fd9ee8b5Sjoyce mcintosh #include <sys/types.h>
31fd9ee8b5Sjoyce mcintosh #include <sys/stat.h>
32*b819cea2SGordon Ross #include <sys/atomic.h>
33fd9ee8b5Sjoyce mcintosh #include <strings.h>
34fd9ee8b5Sjoyce mcintosh #include <syslog.h>
35fd9ee8b5Sjoyce mcintosh #include <signal.h>
36fd9ee8b5Sjoyce mcintosh #include <pthread.h>
37fd9ee8b5Sjoyce mcintosh #include <synch.h>
38fd9ee8b5Sjoyce mcintosh #include <dlfcn.h>
39fd9ee8b5Sjoyce mcintosh #include <errno.h>
40fd9ee8b5Sjoyce mcintosh #include <smbsrv/smb.h>
41fd9ee8b5Sjoyce mcintosh #include <smbsrv/smb_share.h>
42fd9ee8b5Sjoyce mcintosh #include "smbd.h"
43fd9ee8b5Sjoyce mcintosh 
4486d7016bSGordon Ross #ifdef	HAVE_CUPS
4586d7016bSGordon Ross #include <cups/cups.h>
4686d7016bSGordon Ross 
47fd9ee8b5Sjoyce mcintosh #define	SMB_SPOOL_WAIT			2
48fd9ee8b5Sjoyce mcintosh #define	SMBD_PJOBLEN			256
49fd9ee8b5Sjoyce mcintosh #define	SMBD_PRINTER			"Postscript"
50fd9ee8b5Sjoyce mcintosh #define	SMBD_FN_PREFIX			"cifsprintjob-"
51fd9ee8b5Sjoyce mcintosh #define	SMBD_CUPS_SPOOL_DIR		"//var//spool//cups"
52fd9ee8b5Sjoyce mcintosh #define	SMBD_CUPS_DOCNAME		"generic_doc"
53fd9ee8b5Sjoyce mcintosh 
54fd9ee8b5Sjoyce mcintosh typedef struct smbd_printjob {
55fd9ee8b5Sjoyce mcintosh 	pid_t		pj_pid;
56fd9ee8b5Sjoyce mcintosh 	int		pj_sysjob;
57fd9ee8b5Sjoyce mcintosh 	int		pj_fd;
58fd9ee8b5Sjoyce mcintosh 	time_t		pj_start_time;
59fd9ee8b5Sjoyce mcintosh 	int		pj_status;
60fd9ee8b5Sjoyce mcintosh 	size_t		pj_size;
61fd9ee8b5Sjoyce mcintosh 	int		pj_page_count;
62fd9ee8b5Sjoyce mcintosh 	boolean_t	pj_isspooled;
63fd9ee8b5Sjoyce mcintosh 	boolean_t	pj_jobnum;
64fd9ee8b5Sjoyce mcintosh 	char		pj_filename[SMBD_PJOBLEN];
65fd9ee8b5Sjoyce mcintosh 	char		pj_jobname[SMBD_PJOBLEN];
66fd9ee8b5Sjoyce mcintosh 	char		pj_username[SMBD_PJOBLEN];
67fd9ee8b5Sjoyce mcintosh 	char		pj_queuename[SMBD_PJOBLEN];
68fd9ee8b5Sjoyce mcintosh } smbd_printjob_t;
69fd9ee8b5Sjoyce mcintosh 
70fd9ee8b5Sjoyce mcintosh typedef struct smb_cups_ops {
71fd9ee8b5Sjoyce mcintosh 	void		*cups_hdl;
72fd9ee8b5Sjoyce mcintosh 	cups_lang_t	*(*cupsLangDefault)();
73fd9ee8b5Sjoyce mcintosh 	const char	*(*cupsLangEncoding)(cups_lang_t *);
74fd9ee8b5Sjoyce mcintosh 	void		(*cupsLangFree)(cups_lang_t *);
75fd9ee8b5Sjoyce mcintosh 	ipp_status_t	(*cupsLastError)();
76fd9ee8b5Sjoyce mcintosh 	int		(*cupsGetDests)(cups_dest_t **);
77fd9ee8b5Sjoyce mcintosh 	void		(*cupsFreeDests)(int, cups_dest_t *);
78fd9ee8b5Sjoyce mcintosh 	ipp_t		*(*cupsDoFileRequest)(http_t *, ipp_t *,
79fd9ee8b5Sjoyce mcintosh 	    const char *, const char *);
80fd9ee8b5Sjoyce mcintosh 	ipp_t		*(*ippNew)();
81fd9ee8b5Sjoyce mcintosh 	void		(*ippDelete)();
82fd9ee8b5Sjoyce mcintosh 	char		*(*ippErrorString)();
83fd9ee8b5Sjoyce mcintosh 	ipp_attribute_t	*(*ippAddString)();
84fd9ee8b5Sjoyce mcintosh 	void		(*httpClose)(http_t *);
85fd9ee8b5Sjoyce mcintosh 	http_t		*(*httpConnect)(const char *, int);
86fd9ee8b5Sjoyce mcintosh } smb_cups_ops_t;
87fd9ee8b5Sjoyce mcintosh 
88fd9ee8b5Sjoyce mcintosh static uint32_t smbd_cups_jobnum = 1;
89fd9ee8b5Sjoyce mcintosh static smb_cups_ops_t smb_cups;
90fd9ee8b5Sjoyce mcintosh static mutex_t smbd_cups_mutex;
91fd9ee8b5Sjoyce mcintosh 
92fd9ee8b5Sjoyce mcintosh static void *smbd_spool_monitor(void *);
93fd9ee8b5Sjoyce mcintosh static smb_cups_ops_t *smbd_cups_ops(void);
94fd9ee8b5Sjoyce mcintosh static void smbd_print_share_comment(smb_share_t *, cups_dest_t *);
95fd9ee8b5Sjoyce mcintosh static void *smbd_share_printers(void *);
96fd9ee8b5Sjoyce mcintosh static void smbd_spool_copyfile(smb_inaddr_t *, char *, char *, char *);
97fd9ee8b5Sjoyce mcintosh 
98fd9ee8b5Sjoyce mcintosh extern smbd_t smbd;
99fd9ee8b5Sjoyce mcintosh 
100fd9ee8b5Sjoyce mcintosh /*
101b7301bf5SGordon Ross  * Start the spool thread.
102fd9ee8b5Sjoyce mcintosh  * Returns 0 on success, an error number if thread creation fails.
103fd9ee8b5Sjoyce mcintosh  */
104fd9ee8b5Sjoyce mcintosh void
105b7301bf5SGordon Ross smbd_spool_start(void)
106fd9ee8b5Sjoyce mcintosh {
107fd9ee8b5Sjoyce mcintosh 	pthread_attr_t	attr;
108fd9ee8b5Sjoyce mcintosh 	int		rc;
109fd9ee8b5Sjoyce mcintosh 
110b7301bf5SGordon Ross 	if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
111b7301bf5SGordon Ross 		return;
112b7301bf5SGordon Ross 
113fd9ee8b5Sjoyce mcintosh 	(void) pthread_attr_init(&attr);
114fd9ee8b5Sjoyce mcintosh 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
115fd9ee8b5Sjoyce mcintosh 	rc = pthread_create(&smbd.s_spool_tid, &attr, smbd_spool_monitor, NULL);
116fd9ee8b5Sjoyce mcintosh 	(void) pthread_attr_destroy(&attr);
117fd9ee8b5Sjoyce mcintosh 
118fd9ee8b5Sjoyce mcintosh 	if (rc != 0)
119*b819cea2SGordon Ross 		syslog(LOG_NOTICE,
120fd9ee8b5Sjoyce mcintosh 		    "failed to start print monitor: %s", strerror(errno));
121fd9ee8b5Sjoyce mcintosh }
122fd9ee8b5Sjoyce mcintosh 
123fd9ee8b5Sjoyce mcintosh /*
124fd9ee8b5Sjoyce mcintosh  * A single pthread_kill should be sufficient but we include
125fd9ee8b5Sjoyce mcintosh  * a couple of retries to avoid implementation idiosyncrasies
126fd9ee8b5Sjoyce mcintosh  * around signal delivery.
127fd9ee8b5Sjoyce mcintosh  */
128fd9ee8b5Sjoyce mcintosh void
129b7301bf5SGordon Ross smbd_spool_stop(void)
130fd9ee8b5Sjoyce mcintosh {
131fd9ee8b5Sjoyce mcintosh 	int	i;
132fd9ee8b5Sjoyce mcintosh 
133fd9ee8b5Sjoyce mcintosh 	if (pthread_self() == smbd.s_spool_tid)
134fd9ee8b5Sjoyce mcintosh 		return;
135fd9ee8b5Sjoyce mcintosh 
136fd9ee8b5Sjoyce mcintosh 	for (i = 0; i < 3 && smbd.s_spool_tid != 0; ++i) {
137fd9ee8b5Sjoyce mcintosh 		if (pthread_kill(smbd.s_spool_tid, SIGTERM) == ESRCH)
138fd9ee8b5Sjoyce mcintosh 			break;
139fd9ee8b5Sjoyce mcintosh 
140fd9ee8b5Sjoyce mcintosh 		(void) sleep(1);
141fd9ee8b5Sjoyce mcintosh 	}
142fd9ee8b5Sjoyce mcintosh }
143fd9ee8b5Sjoyce mcintosh 
144fd9ee8b5Sjoyce mcintosh /*
145fd9ee8b5Sjoyce mcintosh  * This thread blocks waiting for close print file in the kernel.
146fd9ee8b5Sjoyce mcintosh  * It then uses the data returned from the ioctl to copy the spool file
147fd9ee8b5Sjoyce mcintosh  * into the cups spooler.
148fd9ee8b5Sjoyce mcintosh  *
149fd9ee8b5Sjoyce mcintosh  * This mechanism is really only used by Windows Vista and Windows 7.
150fd9ee8b5Sjoyce mcintosh  * Other versions of Windows create a zero size file, which is removed
151fd9ee8b5Sjoyce mcintosh  * by smbd_spool_copyfile.
152fd9ee8b5Sjoyce mcintosh  */
153fd9ee8b5Sjoyce mcintosh /*ARGSUSED*/
154fd9ee8b5Sjoyce mcintosh static void *
155fd9ee8b5Sjoyce mcintosh smbd_spool_monitor(void *arg)
156fd9ee8b5Sjoyce mcintosh {
157fd9ee8b5Sjoyce mcintosh 	uint32_t	spool_num;
158fd9ee8b5Sjoyce mcintosh 	char		username[MAXNAMELEN];
159fd9ee8b5Sjoyce mcintosh 	char		path[MAXPATHLEN];
160fd9ee8b5Sjoyce mcintosh 	smb_inaddr_t	ipaddr;
161fd9ee8b5Sjoyce mcintosh 	int		error_retry_cnt = 5;
162fd9ee8b5Sjoyce mcintosh 
163fd9ee8b5Sjoyce mcintosh 	smbd_online_wait("smbd_spool_monitor");
164fd9ee8b5Sjoyce mcintosh 
165fd9ee8b5Sjoyce mcintosh 	spoolss_register_copyfile(smbd_spool_copyfile);
166fd9ee8b5Sjoyce mcintosh 
167fd9ee8b5Sjoyce mcintosh 	while (!smbd.s_shutting_down && (error_retry_cnt > 0)) {
168fd9ee8b5Sjoyce mcintosh 		errno = 0;
169fd9ee8b5Sjoyce mcintosh 
170fd9ee8b5Sjoyce mcintosh 		if (smb_kmod_get_spool_doc(&spool_num, username,
171fd9ee8b5Sjoyce mcintosh 		    path, &ipaddr) == 0) {
172fd9ee8b5Sjoyce mcintosh 			smbd_spool_copyfile(&ipaddr,
173fd9ee8b5Sjoyce mcintosh 			    username, path, SMBD_CUPS_DOCNAME);
174fd9ee8b5Sjoyce mcintosh 			error_retry_cnt = 5;
175fd9ee8b5Sjoyce mcintosh 		} else {
176fd9ee8b5Sjoyce mcintosh 			if (errno == ECANCELED)
177fd9ee8b5Sjoyce mcintosh 				break;
17823a9c295SGordon Ross 			if ((errno != EINTR) && (errno != EAGAIN))
179fd9ee8b5Sjoyce mcintosh 				error_retry_cnt--;
18023a9c295SGordon Ross 			(void) sleep(SMB_SPOOL_WAIT);
181fd9ee8b5Sjoyce mcintosh 		}
182fd9ee8b5Sjoyce mcintosh 	}
183fd9ee8b5Sjoyce mcintosh 
184fd9ee8b5Sjoyce mcintosh 	spoolss_register_copyfile(NULL);
185fd9ee8b5Sjoyce mcintosh 	smbd.s_spool_tid = 0;
186fd9ee8b5Sjoyce mcintosh 	return (NULL);
187fd9ee8b5Sjoyce mcintosh }
188fd9ee8b5Sjoyce mcintosh 
189fd9ee8b5Sjoyce mcintosh /*
190fd9ee8b5Sjoyce mcintosh  * All versions of windows use this function to spool files to a printer
191fd9ee8b5Sjoyce mcintosh  * via the cups interface
192fd9ee8b5Sjoyce mcintosh  */
193fd9ee8b5Sjoyce mcintosh static void
194fd9ee8b5Sjoyce mcintosh smbd_spool_copyfile(smb_inaddr_t *ipaddr, char *username, char *path,
195fd9ee8b5Sjoyce mcintosh     char *doc_name)
196fd9ee8b5Sjoyce mcintosh {
197fd9ee8b5Sjoyce mcintosh 	smb_cups_ops_t	*cups;
198fd9ee8b5Sjoyce mcintosh 	http_t		*http = NULL;		/* HTTP connection to server */
199fd9ee8b5Sjoyce mcintosh 	ipp_t		*request = NULL;	/* IPP Request */
200fd9ee8b5Sjoyce mcintosh 	ipp_t		*response = NULL;	/* IPP Response */
201fd9ee8b5Sjoyce mcintosh 	cups_lang_t	*language = NULL;	/* Default language */
202fd9ee8b5Sjoyce mcintosh 	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
203fd9ee8b5Sjoyce mcintosh 	char		new_jobname[SMBD_PJOBLEN];
204fd9ee8b5Sjoyce mcintosh 	smbd_printjob_t	pjob;
205fd9ee8b5Sjoyce mcintosh 	char		clientname[INET6_ADDRSTRLEN];
206fd9ee8b5Sjoyce mcintosh 	struct stat 	sbuf;
207fd9ee8b5Sjoyce mcintosh 	int		rc = 1;
208fd9ee8b5Sjoyce mcintosh 
209fd9ee8b5Sjoyce mcintosh 	if (stat(path, &sbuf)) {
210*b819cea2SGordon Ross 		syslog(LOG_INFO, "smbd_spool_copyfile: %s: %s",
211fd9ee8b5Sjoyce mcintosh 		    path, strerror(errno));
212fd9ee8b5Sjoyce mcintosh 		return;
213fd9ee8b5Sjoyce mcintosh 	}
214fd9ee8b5Sjoyce mcintosh 
215fd9ee8b5Sjoyce mcintosh 	/*
216fd9ee8b5Sjoyce mcintosh 	 * Remove zero size files and return; these were inadvertantly
217fd9ee8b5Sjoyce mcintosh 	 * created by XP or 2000.
218fd9ee8b5Sjoyce mcintosh 	 */
219fd9ee8b5Sjoyce mcintosh 	if (sbuf.st_size == 0) {
220fd9ee8b5Sjoyce mcintosh 		if (remove(path) != 0)
221*b819cea2SGordon Ross 			syslog(LOG_INFO,
222fd9ee8b5Sjoyce mcintosh 			    "smbd_spool_copyfile: cannot remove %s: %s",
223fd9ee8b5Sjoyce mcintosh 			    path, strerror(errno));
224fd9ee8b5Sjoyce mcintosh 		return;
225fd9ee8b5Sjoyce mcintosh 	}
226fd9ee8b5Sjoyce mcintosh 
227fd9ee8b5Sjoyce mcintosh 	if ((cups = smbd_cups_ops()) == NULL)
228fd9ee8b5Sjoyce mcintosh 		return;
229fd9ee8b5Sjoyce mcintosh 
230fd9ee8b5Sjoyce mcintosh 	if ((http = cups->httpConnect("localhost", 631)) == NULL) {
231*b819cea2SGordon Ross 		syslog(LOG_INFO,
232fd9ee8b5Sjoyce mcintosh 		    "smbd_spool_copyfile: cupsd not running");
233fd9ee8b5Sjoyce mcintosh 		return;
234fd9ee8b5Sjoyce mcintosh 	}
235fd9ee8b5Sjoyce mcintosh 
236fd9ee8b5Sjoyce mcintosh 	if ((request = cups->ippNew()) == NULL) {
237*b819cea2SGordon Ross 		syslog(LOG_INFO,
238fd9ee8b5Sjoyce mcintosh 		    "smbd_spool_copyfile: ipp not running");
239fd9ee8b5Sjoyce mcintosh 		return;
240fd9ee8b5Sjoyce mcintosh 	}
241fd9ee8b5Sjoyce mcintosh 
242fd9ee8b5Sjoyce mcintosh 	request->request.op.operation_id = IPP_PRINT_JOB;
243fd9ee8b5Sjoyce mcintosh 	request->request.op.request_id = 1;
244fd9ee8b5Sjoyce mcintosh 	language = cups->cupsLangDefault();
245fd9ee8b5Sjoyce mcintosh 
246fd9ee8b5Sjoyce mcintosh 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
247fd9ee8b5Sjoyce mcintosh 	    "attributes-charset", NULL, cups->cupsLangEncoding(language));
248fd9ee8b5Sjoyce mcintosh 
249fd9ee8b5Sjoyce mcintosh 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
250fd9ee8b5Sjoyce mcintosh 	    "attributes-natural-language", NULL, language->language);
251fd9ee8b5Sjoyce mcintosh 
252fd9ee8b5Sjoyce mcintosh 	(void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s",
253fd9ee8b5Sjoyce mcintosh 	    SMBD_PRINTER);
254fd9ee8b5Sjoyce mcintosh 	pjob.pj_pid = pthread_self();
255fd9ee8b5Sjoyce mcintosh 	pjob.pj_sysjob = 10;
256fd9ee8b5Sjoyce mcintosh 	(void) strlcpy(pjob.pj_filename, path, SMBD_PJOBLEN);
257fd9ee8b5Sjoyce mcintosh 	pjob.pj_start_time = time(NULL);
258fd9ee8b5Sjoyce mcintosh 	pjob.pj_status = 2;
259fd9ee8b5Sjoyce mcintosh 	pjob.pj_size = sbuf.st_blocks * 512;
260fd9ee8b5Sjoyce mcintosh 	pjob.pj_page_count = 1;
261fd9ee8b5Sjoyce mcintosh 	pjob.pj_isspooled = B_TRUE;
262fd9ee8b5Sjoyce mcintosh 	pjob.pj_jobnum = smbd_cups_jobnum;
263fd9ee8b5Sjoyce mcintosh 
264fd9ee8b5Sjoyce mcintosh 	(void) strlcpy(pjob.pj_jobname, doc_name, SMBD_PJOBLEN);
265fd9ee8b5Sjoyce mcintosh 	(void) strlcpy(pjob.pj_username, username, SMBD_PJOBLEN);
266fd9ee8b5Sjoyce mcintosh 	(void) strlcpy(pjob.pj_queuename, SMBD_CUPS_SPOOL_DIR, SMBD_PJOBLEN);
267fd9ee8b5Sjoyce mcintosh 
268fd9ee8b5Sjoyce mcintosh 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
269fd9ee8b5Sjoyce mcintosh 	    "printer-uri", NULL, uri);
270fd9ee8b5Sjoyce mcintosh 
271fd9ee8b5Sjoyce mcintosh 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
272fd9ee8b5Sjoyce mcintosh 	    "requesting-user-name", NULL, pjob.pj_username);
273fd9ee8b5Sjoyce mcintosh 
274fd9ee8b5Sjoyce mcintosh 	if (smb_inet_ntop(ipaddr, clientname,
275fd9ee8b5Sjoyce mcintosh 	    SMB_IPSTRLEN(ipaddr->a_family)) == NULL) {
276*b819cea2SGordon Ross 		syslog(LOG_INFO,
277fd9ee8b5Sjoyce mcintosh 		    "smbd_spool_copyfile: %s: unknown client", clientname);
278fd9ee8b5Sjoyce mcintosh 		goto out;
279fd9ee8b5Sjoyce mcintosh 	}
280fd9ee8b5Sjoyce mcintosh 
281fd9ee8b5Sjoyce mcintosh 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
282fd9ee8b5Sjoyce mcintosh 	    "job-originating-host-name", NULL, clientname);
283fd9ee8b5Sjoyce mcintosh 
284fd9ee8b5Sjoyce mcintosh 	(void) snprintf(new_jobname, SMBD_PJOBLEN, "%s%d",
285fd9ee8b5Sjoyce mcintosh 	    SMBD_FN_PREFIX, pjob.pj_jobnum);
286fd9ee8b5Sjoyce mcintosh 	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
287fd9ee8b5Sjoyce mcintosh 	    "job-name", NULL, new_jobname);
288fd9ee8b5Sjoyce mcintosh 
289fd9ee8b5Sjoyce mcintosh 	(void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SMBD_PRINTER);
290fd9ee8b5Sjoyce mcintosh 
291fd9ee8b5Sjoyce mcintosh 	response = cups->cupsDoFileRequest(http, request, uri,
292fd9ee8b5Sjoyce mcintosh 	    pjob.pj_filename);
293fd9ee8b5Sjoyce mcintosh 	if (response != NULL) {
294fd9ee8b5Sjoyce mcintosh 		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
295*b819cea2SGordon Ross 			syslog(LOG_ERR,
296fd9ee8b5Sjoyce mcintosh 			    "smbd_spool_copyfile: printer %s: %s",
297fd9ee8b5Sjoyce mcintosh 			    SMBD_PRINTER,
298fd9ee8b5Sjoyce mcintosh 			    cups->ippErrorString(cups->cupsLastError()));
299fd9ee8b5Sjoyce mcintosh 		} else {
300fd9ee8b5Sjoyce mcintosh 			atomic_inc_32(&smbd_cups_jobnum);
301fd9ee8b5Sjoyce mcintosh 			rc = 0;
302fd9ee8b5Sjoyce mcintosh 		}
303fd9ee8b5Sjoyce mcintosh 	} else {
304*b819cea2SGordon Ross 		syslog(LOG_ERR,
305fd9ee8b5Sjoyce mcintosh 		    "smbd_spool_copyfile: unable to print to %s",
306fd9ee8b5Sjoyce mcintosh 		    cups->ippErrorString(cups->cupsLastError()));
307fd9ee8b5Sjoyce mcintosh 	}
308fd9ee8b5Sjoyce mcintosh 
309fd9ee8b5Sjoyce mcintosh 	if (rc == 0)
310fd9ee8b5Sjoyce mcintosh 		(void) unlink(pjob.pj_filename);
311fd9ee8b5Sjoyce mcintosh 
312fd9ee8b5Sjoyce mcintosh out:
313fd9ee8b5Sjoyce mcintosh 	if (response)
314fd9ee8b5Sjoyce mcintosh 		cups->ippDelete(response);
315fd9ee8b5Sjoyce mcintosh 
316fd9ee8b5Sjoyce mcintosh 	if (language)
317fd9ee8b5Sjoyce mcintosh 		cups->cupsLangFree(language);
318fd9ee8b5Sjoyce mcintosh 
319fd9ee8b5Sjoyce mcintosh 	if (http)
320fd9ee8b5Sjoyce mcintosh 		cups->httpClose(http);
321fd9ee8b5Sjoyce mcintosh }
322fd9ee8b5Sjoyce mcintosh 
323fd9ee8b5Sjoyce mcintosh int
324fd9ee8b5Sjoyce mcintosh smbd_cups_init(void)
325fd9ee8b5Sjoyce mcintosh {
326fd9ee8b5Sjoyce mcintosh 	(void) mutex_lock(&smbd_cups_mutex);
327fd9ee8b5Sjoyce mcintosh 
328fd9ee8b5Sjoyce mcintosh 	if (smb_cups.cups_hdl != NULL) {
329fd9ee8b5Sjoyce mcintosh 		(void) mutex_unlock(&smbd_cups_mutex);
330fd9ee8b5Sjoyce mcintosh 		return (0);
331fd9ee8b5Sjoyce mcintosh 	}
332fd9ee8b5Sjoyce mcintosh 
333fd9ee8b5Sjoyce mcintosh 	if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) {
334fd9ee8b5Sjoyce mcintosh 		(void) mutex_unlock(&smbd_cups_mutex);
335*b819cea2SGordon Ross 		syslog(LOG_DEBUG,
336fd9ee8b5Sjoyce mcintosh 		    "smbd_cups_init: cannot open libcups");
337fd9ee8b5Sjoyce mcintosh 		return (ENOENT);
338fd9ee8b5Sjoyce mcintosh 	}
339fd9ee8b5Sjoyce mcintosh 
340fd9ee8b5Sjoyce mcintosh 	smb_cups.cupsLangDefault =
341fd9ee8b5Sjoyce mcintosh 	    (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault");
342fd9ee8b5Sjoyce mcintosh 	smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *))
343fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "cupsLangEncoding");
344fd9ee8b5Sjoyce mcintosh 	smb_cups.cupsDoFileRequest =
345fd9ee8b5Sjoyce mcintosh 	    (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *))
346fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "cupsDoFileRequest");
347fd9ee8b5Sjoyce mcintosh 	smb_cups.cupsLastError = (ipp_status_t (*)())
348fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "cupsLastError");
349fd9ee8b5Sjoyce mcintosh 	smb_cups.cupsLangFree = (void (*)(cups_lang_t *))
350fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "cupsLangFree");
351fd9ee8b5Sjoyce mcintosh 	smb_cups.cupsGetDests = (int (*)(cups_dest_t **))
352fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "cupsGetDests");
353fd9ee8b5Sjoyce mcintosh 	smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *))
354fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "cupsFreeDests");
355fd9ee8b5Sjoyce mcintosh 
356fd9ee8b5Sjoyce mcintosh 	smb_cups.httpClose = (void (*)(http_t *))
357fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "httpClose");
358fd9ee8b5Sjoyce mcintosh 	smb_cups.httpConnect = (http_t *(*)(const char *, int))
359fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "httpConnect");
360fd9ee8b5Sjoyce mcintosh 
361fd9ee8b5Sjoyce mcintosh 	smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew");
362fd9ee8b5Sjoyce mcintosh 	smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete");
363fd9ee8b5Sjoyce mcintosh 	smb_cups.ippErrorString = (char *(*)())
364fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "ippErrorString");
365fd9ee8b5Sjoyce mcintosh 	smb_cups.ippAddString = (ipp_attribute_t *(*)())
366fd9ee8b5Sjoyce mcintosh 	    dlsym(smb_cups.cups_hdl, "ippAddString");
367fd9ee8b5Sjoyce mcintosh 
368fd9ee8b5Sjoyce mcintosh 	if (smb_cups.cupsLangDefault == NULL ||
369fd9ee8b5Sjoyce mcintosh 	    smb_cups.cupsLangEncoding == NULL ||
370fd9ee8b5Sjoyce mcintosh 	    smb_cups.cupsDoFileRequest == NULL ||
371fd9ee8b5Sjoyce mcintosh 	    smb_cups.cupsLastError == NULL ||
372fd9ee8b5Sjoyce mcintosh 	    smb_cups.cupsLangFree == NULL ||
373fd9ee8b5Sjoyce mcintosh 	    smb_cups.cupsGetDests == NULL ||
374fd9ee8b5Sjoyce mcintosh 	    smb_cups.cupsFreeDests == NULL ||
375fd9ee8b5Sjoyce mcintosh 	    smb_cups.ippNew == NULL ||
376fd9ee8b5Sjoyce mcintosh 	    smb_cups.httpClose == NULL ||
377fd9ee8b5Sjoyce mcintosh 	    smb_cups.httpConnect == NULL ||
378fd9ee8b5Sjoyce mcintosh 	    smb_cups.ippDelete == NULL ||
379fd9ee8b5Sjoyce mcintosh 	    smb_cups.ippErrorString == NULL ||
380fd9ee8b5Sjoyce mcintosh 	    smb_cups.ippAddString == NULL) {
381fd9ee8b5Sjoyce mcintosh 		(void) dlclose(smb_cups.cups_hdl);
382fd9ee8b5Sjoyce mcintosh 		smb_cups.cups_hdl = NULL;
383fd9ee8b5Sjoyce mcintosh 		(void) mutex_unlock(&smbd_cups_mutex);
384*b819cea2SGordon Ross 		syslog(LOG_DEBUG,
385fd9ee8b5Sjoyce mcintosh 		    "smbd_cups_init: cannot load libcups");
386fd9ee8b5Sjoyce mcintosh 		return (ENOENT);
387fd9ee8b5Sjoyce mcintosh 	}
388fd9ee8b5Sjoyce mcintosh 
389fd9ee8b5Sjoyce mcintosh 	(void) mutex_unlock(&smbd_cups_mutex);
390fd9ee8b5Sjoyce mcintosh 	return (0);
391fd9ee8b5Sjoyce mcintosh }
392fd9ee8b5Sjoyce mcintosh 
393fd9ee8b5Sjoyce mcintosh void
394fd9ee8b5Sjoyce mcintosh smbd_cups_fini(void)
395fd9ee8b5Sjoyce mcintosh {
396fd9ee8b5Sjoyce mcintosh 	(void) mutex_lock(&smbd_cups_mutex);
397fd9ee8b5Sjoyce mcintosh 
398fd9ee8b5Sjoyce mcintosh 	if (smb_cups.cups_hdl != NULL) {
399fd9ee8b5Sjoyce mcintosh 		(void) dlclose(smb_cups.cups_hdl);
400fd9ee8b5Sjoyce mcintosh 		smb_cups.cups_hdl = NULL;
401fd9ee8b5Sjoyce mcintosh 	}
402fd9ee8b5Sjoyce mcintosh 
403fd9ee8b5Sjoyce mcintosh 	(void) mutex_unlock(&smbd_cups_mutex);
404fd9ee8b5Sjoyce mcintosh }
405fd9ee8b5Sjoyce mcintosh 
406fd9ee8b5Sjoyce mcintosh static smb_cups_ops_t *
407fd9ee8b5Sjoyce mcintosh smbd_cups_ops(void)
408fd9ee8b5Sjoyce mcintosh {
409fd9ee8b5Sjoyce mcintosh 	if (smb_cups.cups_hdl == NULL)
410fd9ee8b5Sjoyce mcintosh 		return (NULL);
411fd9ee8b5Sjoyce mcintosh 
412fd9ee8b5Sjoyce mcintosh 	return (&smb_cups);
413fd9ee8b5Sjoyce mcintosh }
414fd9ee8b5Sjoyce mcintosh 
415fd9ee8b5Sjoyce mcintosh void
416fd9ee8b5Sjoyce mcintosh smbd_load_printers(void)
417fd9ee8b5Sjoyce mcintosh {
418fd9ee8b5Sjoyce mcintosh 	pthread_t	tid;
419fd9ee8b5Sjoyce mcintosh 	pthread_attr_t	attr;
420fd9ee8b5Sjoyce mcintosh 	int		rc;
421fd9ee8b5Sjoyce mcintosh 
422fd9ee8b5Sjoyce mcintosh 	if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
423fd9ee8b5Sjoyce mcintosh 		return;
424fd9ee8b5Sjoyce mcintosh 
425fd9ee8b5Sjoyce mcintosh 	(void) pthread_attr_init(&attr);
426fd9ee8b5Sjoyce mcintosh 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
427fd9ee8b5Sjoyce mcintosh 	rc = pthread_create(&tid, &attr, smbd_share_printers, &tid);
428fd9ee8b5Sjoyce mcintosh 	(void) pthread_attr_destroy(&attr);
429fd9ee8b5Sjoyce mcintosh 
430fd9ee8b5Sjoyce mcintosh 	if (rc != 0)
431*b819cea2SGordon Ross 		syslog(LOG_NOTICE,
432fd9ee8b5Sjoyce mcintosh 		    "unable to load printer shares: %s", strerror(errno));
433fd9ee8b5Sjoyce mcintosh }
434fd9ee8b5Sjoyce mcintosh 
435fd9ee8b5Sjoyce mcintosh /*
436fd9ee8b5Sjoyce mcintosh  * All print shares use the path from print$.
437fd9ee8b5Sjoyce mcintosh  */
438fd9ee8b5Sjoyce mcintosh /*ARGSUSED*/
439fd9ee8b5Sjoyce mcintosh static void *
440fd9ee8b5Sjoyce mcintosh smbd_share_printers(void *arg)
441fd9ee8b5Sjoyce mcintosh {
442fd9ee8b5Sjoyce mcintosh 	cups_dest_t	*dests;
443fd9ee8b5Sjoyce mcintosh 	cups_dest_t	*dest;
444fd9ee8b5Sjoyce mcintosh 	smb_cups_ops_t	*cups;
445fd9ee8b5Sjoyce mcintosh 	smb_share_t	si;
446fd9ee8b5Sjoyce mcintosh 	uint32_t	nerr;
447fd9ee8b5Sjoyce mcintosh 	int		num_dests;
448fd9ee8b5Sjoyce mcintosh 	int		i;
449fd9ee8b5Sjoyce mcintosh 
450fd9ee8b5Sjoyce mcintosh 	if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
451fd9ee8b5Sjoyce mcintosh 		return (NULL);
452fd9ee8b5Sjoyce mcintosh 
453fd9ee8b5Sjoyce mcintosh 	if ((cups = smbd_cups_ops()) == NULL)
454fd9ee8b5Sjoyce mcintosh 		return (NULL);
455fd9ee8b5Sjoyce mcintosh 
456fd9ee8b5Sjoyce mcintosh 	if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) {
457*b819cea2SGordon Ross 		syslog(LOG_DEBUG,
458fd9ee8b5Sjoyce mcintosh 		    "smbd_share_printers unable to load %s", SMB_SHARE_PRINT);
459fd9ee8b5Sjoyce mcintosh 		return (NULL);
460fd9ee8b5Sjoyce mcintosh 	}
461fd9ee8b5Sjoyce mcintosh 
462fd9ee8b5Sjoyce mcintosh 	num_dests = cups->cupsGetDests(&dests);
463fd9ee8b5Sjoyce mcintosh 
464fd9ee8b5Sjoyce mcintosh 	for (i = num_dests, dest = dests; i > 0; i--, dest++) {
465fd9ee8b5Sjoyce mcintosh 		if (dest->instance != NULL)
466fd9ee8b5Sjoyce mcintosh 			continue;
467fd9ee8b5Sjoyce mcintosh 
468fd9ee8b5Sjoyce mcintosh 		(void) strlcpy(si.shr_name, dest->name, MAXPATHLEN);
469fd9ee8b5Sjoyce mcintosh 		smbd_print_share_comment(&si, dest);
470fd9ee8b5Sjoyce mcintosh 		si.shr_type = STYPE_PRINTQ;
471fd9ee8b5Sjoyce mcintosh 
472fd9ee8b5Sjoyce mcintosh 		nerr = smb_shr_add(&si);
473fd9ee8b5Sjoyce mcintosh 		if (nerr == NERR_Success || nerr == NERR_DuplicateShare)
474*b819cea2SGordon Ross 			syslog(LOG_DEBUG,
475fd9ee8b5Sjoyce mcintosh 			    "shared printer: %s", si.shr_name);
476fd9ee8b5Sjoyce mcintosh 		else
477*b819cea2SGordon Ross 			syslog(LOG_DEBUG,
478fd9ee8b5Sjoyce mcintosh 			    "smbd_share_printers: unable to add share %s: %u",
479fd9ee8b5Sjoyce mcintosh 			    si.shr_name, nerr);
480fd9ee8b5Sjoyce mcintosh 	}
481fd9ee8b5Sjoyce mcintosh 
482fd9ee8b5Sjoyce mcintosh 	cups->cupsFreeDests(num_dests, dests);
483fd9ee8b5Sjoyce mcintosh 	return (NULL);
484fd9ee8b5Sjoyce mcintosh }
485fd9ee8b5Sjoyce mcintosh 
486fd9ee8b5Sjoyce mcintosh static void
487fd9ee8b5Sjoyce mcintosh smbd_print_share_comment(smb_share_t *si, cups_dest_t *dest)
488fd9ee8b5Sjoyce mcintosh {
489fd9ee8b5Sjoyce mcintosh 	cups_option_t	*options;
490fd9ee8b5Sjoyce mcintosh 	char		*comment;
491fd9ee8b5Sjoyce mcintosh 	char		*name;
492fd9ee8b5Sjoyce mcintosh 	char		*value;
493fd9ee8b5Sjoyce mcintosh 	int		i;
494fd9ee8b5Sjoyce mcintosh 
495fd9ee8b5Sjoyce mcintosh 	comment = "Print Share";
496fd9ee8b5Sjoyce mcintosh 
497fd9ee8b5Sjoyce mcintosh 	if ((options = dest->options) == NULL) {
498fd9ee8b5Sjoyce mcintosh 		(void) strlcpy(si->shr_cmnt, comment, SMB_SHARE_CMNT_MAX);
499fd9ee8b5Sjoyce mcintosh 		return;
500fd9ee8b5Sjoyce mcintosh 	}
501fd9ee8b5Sjoyce mcintosh 
502fd9ee8b5Sjoyce mcintosh 	for (i = 0; i < dest->num_options; ++i) {
503fd9ee8b5Sjoyce mcintosh 		name = options[i].name;
504fd9ee8b5Sjoyce mcintosh 		value = options[i].value;
505fd9ee8b5Sjoyce mcintosh 
506fd9ee8b5Sjoyce mcintosh 		if (name == NULL || value == NULL ||
507fd9ee8b5Sjoyce mcintosh 		    *name == '\0' || *value == '\0')
508fd9ee8b5Sjoyce mcintosh 			continue;
509fd9ee8b5Sjoyce mcintosh 
510fd9ee8b5Sjoyce mcintosh 		if (strcasecmp(name, "printer-info") == 0) {
511fd9ee8b5Sjoyce mcintosh 			comment = value;
512fd9ee8b5Sjoyce mcintosh 			break;
513fd9ee8b5Sjoyce mcintosh 		}
514fd9ee8b5Sjoyce mcintosh 	}
515fd9ee8b5Sjoyce mcintosh 
516fd9ee8b5Sjoyce mcintosh 	(void) strlcpy(si->shr_cmnt, comment, SMB_SHARE_CMNT_MAX);
517fd9ee8b5Sjoyce mcintosh }
51886d7016bSGordon Ross 
51986d7016bSGordon Ross #else	/* HAVE_CUPS */
52086d7016bSGordon Ross 
52186d7016bSGordon Ross /*
52286d7016bSGordon Ross  * If not HAVE_CUPS, just provide a few "stubs".
52386d7016bSGordon Ross  */
52486d7016bSGordon Ross 
52586d7016bSGordon Ross int
52686d7016bSGordon Ross smbd_cups_init(void)
52786d7016bSGordon Ross {
52886d7016bSGordon Ross 	return (ENOENT);
52986d7016bSGordon Ross }
53086d7016bSGordon Ross 
53186d7016bSGordon Ross void
53286d7016bSGordon Ross smbd_cups_fini(void)
53386d7016bSGordon Ross {
53486d7016bSGordon Ross }
53586d7016bSGordon Ross 
53686d7016bSGordon Ross void
53786d7016bSGordon Ross smbd_load_printers(void)
53886d7016bSGordon Ross {
53986d7016bSGordon Ross }
54086d7016bSGordon Ross 
54186d7016bSGordon Ross void
54286d7016bSGordon Ross smbd_spool_init(void)
54386d7016bSGordon Ross {
54486d7016bSGordon Ross }
54586d7016bSGordon Ross 
54686d7016bSGordon Ross void
54786d7016bSGordon Ross smbd_spool_fini(void)
54886d7016bSGordon Ross {
54986d7016bSGordon Ross }
55086d7016bSGordon Ross 
55186d7016bSGordon Ross void
55286d7016bSGordon Ross smbd_spool_start(void)
55386d7016bSGordon Ross {
55486d7016bSGordon Ross }
55586d7016bSGordon Ross 
55686d7016bSGordon Ross void
55786d7016bSGordon Ross smbd_spool_stop(void)
55886d7016bSGordon Ross {
55986d7016bSGordon Ross }
56086d7016bSGordon Ross 
56186d7016bSGordon Ross #endif 	/* HAVE_CUPS */
562