fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * CDDL HEADER START
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * The contents of this file are subject to the terms of the
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * Common Development and Distribution License (the "License").
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * You may not use this file except in compliance with the License.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * or http://www.opensolaris.org/os/licensing.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * See the License for the specific language governing permissions
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * and limitations under the License.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * When distributing Covered Code, include this CDDL HEADER in each
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * If applicable, add the following below this CDDL HEADER, with the
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * fields enclosed by brackets "[]" replaced with your own identifying
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * information: Portions Copyright [yyyy] [name of copyright owner]
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * CDDL HEADER END
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
86d7016b0051dd58772baafe5b5bcee51d560b05Gordon Ross * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * CUPS support for the SMB and SPOOLSS print services.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh#define SMBD_CUPS_SPOOL_DIR "//var//spool//cups"
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh const char *(*cupsLangEncoding)(cups_lang_t *);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh ipp_t *(*cupsDoFileRequest)(http_t *, ipp_t *,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh const char *, const char *);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintoshstatic void *smbd_spool_monitor(void *);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintoshstatic void smbd_print_share_comment(smb_share_t *, cups_dest_t *);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintoshstatic void *smbd_share_printers(void *);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintoshstatic void smbd_spool_copyfile(smb_inaddr_t *, char *, char *, char *);
b7301bf5522d8b9141fe432333ded586218327f2Gordon Ross * Start the spool thread.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * Returns 0 on success, an error number if thread creation fails.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh rc = pthread_create(&smbd.s_spool_tid, &attr, smbd_spool_monitor, NULL);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "failed to start print monitor: %s", strerror(errno));
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * A single pthread_kill should be sufficient but we include
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * a couple of retries to avoid implementation idiosyncrasies
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * around signal delivery.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh for (i = 0; i < 3 && smbd.s_spool_tid != 0; ++i) {
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if (pthread_kill(smbd.s_spool_tid, SIGTERM) == ESRCH)
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * This thread blocks waiting for close print file in the kernel.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * It then uses the data returned from the ioctl to copy the spool file
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * into the cups spooler.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * This mechanism is really only used by Windows Vista and Windows 7.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * Other versions of Windows create a zero size file, which is removed
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * by smbd_spool_copyfile.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh spoolss_register_copyfile(smbd_spool_copyfile);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh while (!smbd.s_shutting_down && (error_retry_cnt > 0)) {
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if (smb_kmod_get_spool_doc(&spool_num, username,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * All versions of windows use this function to spool files to a printer
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * via the cups interface
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintoshsmbd_spool_copyfile(smb_inaddr_t *ipaddr, char *username, char *path,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh http_t *http = NULL; /* HTTP connection to server */
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups_lang_t *language = NULL; /* Default language */
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh char uri[HTTP_MAX_URI]; /* printer-uri attribute */
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * Remove zero size files and return; these were inadvertantly
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * created by XP or 2000.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_spool_copyfile: cannot remove %s: %s",
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if ((http = cups->httpConnect("localhost", 631)) == NULL) {
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_spool_copyfile: cupsd not running");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_spool_copyfile: ipp not running");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh request->request.op.operation_id = IPP_PRINT_JOB;
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "attributes-charset", NULL, cups->cupsLangEncoding(language));
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "attributes-natural-language", NULL, language->language);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s",
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) strlcpy(pjob.pj_filename, path, SMBD_PJOBLEN);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) strlcpy(pjob.pj_jobname, doc_name, SMBD_PJOBLEN);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) strlcpy(pjob.pj_username, username, SMBD_PJOBLEN);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) strlcpy(pjob.pj_queuename, SMBD_CUPS_SPOOL_DIR, SMBD_PJOBLEN);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "requesting-user-name", NULL, pjob.pj_username);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_spool_copyfile: %s: unknown client", clientname);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "job-originating-host-name", NULL, clientname);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) snprintf(new_jobname, SMBD_PJOBLEN, "%s%d",
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SMBD_PRINTER);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh response = cups->cupsDoFileRequest(http, request, uri,
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if (response->request.status.status_code >= IPP_OK_CONFLICT) {
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_spool_copyfile: printer %s: %s",
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups->ippErrorString(cups->cupsLastError()));
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_spool_copyfile: unable to print to %s",
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh cups->ippErrorString(cups->cupsLastError()));
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) {
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_cups_init: cannot open libcups");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *))
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh dlsym(smb_cups.cups_hdl, "cupsLangEncoding");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *))
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh dlsym(smb_cups.cups_hdl, "cupsDoFileRequest");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.cupsLastError = (ipp_status_t (*)())
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.cupsLangFree = (void (*)(cups_lang_t *))
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.cupsGetDests = (int (*)(cups_dest_t **))
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *))
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.httpConnect = (http_t *(*)(const char *, int))
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh smb_cups.ippAddString = (ipp_attribute_t *(*)())
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_cups_init: cannot load libcups");
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh rc = pthread_create(&tid, &attr, smbd_share_printers, &tid);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "unable to load printer shares: %s", strerror(errno));
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh * All print shares use the path from print$.
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) {
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_share_printers unable to load %s", SMB_SHARE_PRINT);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh for (i = num_dests, dest = dests; i > 0; i--, dest++) {
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) strlcpy(si.shr_name, dest->name, MAXPATHLEN);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh if (nerr == NERR_Success || nerr == NERR_DuplicateShare)
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh "smbd_share_printers: unable to add share %s: %u",
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintoshsmbd_print_share_comment(smb_share_t *si, cups_dest_t *dest)
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) strlcpy(si->shr_cmnt, comment, SMB_SHARE_CMNT_MAX);
fd9ee8b58485b20072eeef1310a88ff348d5e7fajoyce mcintosh (void) strlcpy(si->shr_cmnt, comment, SMB_SHARE_CMNT_MAX);
86d7016b0051dd58772baafe5b5bcee51d560b05Gordon Ross#else /* HAVE_CUPS */
86d7016b0051dd58772baafe5b5bcee51d560b05Gordon Ross * If not HAVE_CUPS, just provide a few "stubs".
86d7016b0051dd58772baafe5b5bcee51d560b05Gordon Ross#endif /* HAVE_CUPS */