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