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