1/* 2 Unix SMB/CIFS implementation. 3 SMB backend for the Common UNIX Printing System ("CUPS") 4 Copyright 1999 by Easy Software Products 5 Copyright Andrew Tridgell 1994-1998 6 Copyright Andrew Bartlett 2002 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23#define NO_SYSLOG 24 25#include "includes.h" 26 27/* 28 * Globals... 29 */ 30 31extern BOOL in_client; /* Boolean for client library */ 32 33 34/* 35 * Local functions... 36 */ 37 38static void list_devices(void); 39static struct cli_state *smb_connect(const char *, const char *, int, const char *, const char *, const char *); 40static int smb_print(struct cli_state *, char *, FILE *); 41 42 43/* 44 * 'main()' - Main entry for SMB backend. 45 */ 46 47 int /* O - Exit status */ 48 main(int argc, /* I - Number of command-line arguments */ 49 char *argv[]) /* I - Command-line arguments */ 50{ 51 int i; /* Looping var */ 52 int copies; /* Number of copies */ 53 int port; /* Port number */ 54 char uri[1024], /* URI */ 55 *sep, /* Pointer to separator */ 56 *password; /* Password */ 57 const char *username, /* Username */ 58 *server, /* Server name */ 59 *printer; /* Printer name */ 60 const char *workgroup; /* Workgroup */ 61 FILE *fp; /* File to print */ 62 int status=0; /* Status of LPD job */ 63 struct cli_state *cli; /* SMB interface */ 64 65 /* we expect the URI in argv[0]. Detect the case where it is in argv[1] and cope */ 66 if (argc > 2 && strncmp(argv[0],"smb://", 6) && !strncmp(argv[1],"smb://", 6)) { 67 argv++; 68 argc--; 69 } 70 71 if (argc == 1) 72 { 73 /* 74 * NEW! In CUPS 1.1 the backends are run with no arguments to list the 75 * available devices. These can be devices served by this backend 76 * or any other backends (i.e. you can have an SNMP backend that 77 * is only used to enumerate the available network printers... :) 78 */ 79 80 list_devices(); 81 return (0); 82 } 83 84 if (argc < 6 || argc > 7) 85 { 86 fprintf(stderr, "Usage: %s [DEVICE_URI] job-id user title copies options [file]\n", 87 argv[0]); 88 fputs(" The DEVICE_URI environment variable can also contain the\n", stderr); 89 fputs(" destination printer:\n", stderr); 90 fputs("\n", stderr); 91 fputs(" smb://[username:password@][workgroup/]server[:port]/printer\n", stderr); 92 return (1); 93 } 94 95 /* 96 * If we have 7 arguments, print the file named on the command-line. 97 * Otherwise, print data from stdin... 98 */ 99 100 if (argc == 6) 101 { 102 /* 103 * Print from Copy stdin to a temporary file... 104 */ 105 106 fp = stdin; 107 copies = 1; 108 } 109 else if ((fp = fopen(argv[6], "rb")) == NULL) 110 { 111 perror("ERROR: Unable to open print file"); 112 return (1); 113 } 114 else 115 copies = atoi(argv[4]); 116 117 /* 118 * Find the URI... 119 */ 120 121 if (getenv("DEVICE_URI") != NULL) 122 strncpy(uri, getenv("DEVICE_URI"), sizeof(uri) - 1); 123 else if (strncmp(argv[0], "smb://", 6) == 0) 124 strncpy(uri, argv[0], sizeof(uri) - 1); 125 else 126 { 127 fputs("ERROR: No device URI found in DEVICE_URI environment variable or argv[0] !\n", stderr); 128 return (1); 129 } 130 131 uri[sizeof(uri) - 1] = '\0'; 132 133 /* 134 * Extract the destination from the URI... 135 */ 136 137 if ((sep = strrchr_m(uri, '@')) != NULL) 138 { 139 username = uri + 6; 140 *sep++ = '\0'; 141 142 server = sep; 143 144 /* 145 * Extract password as needed... 146 */ 147 148 if ((password = strchr_m(username, ':')) != NULL) 149 *password++ = '\0'; 150 else 151 password = ""; 152 } 153 else 154 { 155 username = ""; 156 password = ""; 157 server = uri + 6; 158 } 159 160 if ((sep = strchr_m(server, '/')) == NULL) 161 { 162 fputs("ERROR: Bad URI - need printer name!\n", stderr); 163 return (1); 164 } 165 166 *sep++ = '\0'; 167 printer = sep; 168 169 if ((sep = strchr_m(printer, '/')) != NULL) 170 { 171 /* 172 * Convert to smb://[username:password@]workgroup/server/printer... 173 */ 174 175 *sep++ = '\0'; 176 177 workgroup = server; 178 server = printer; 179 printer = sep; 180 } 181 else 182 workgroup = NULL; 183 184 if ((sep = strrchr_m(server, ':')) != NULL) 185 { 186 *sep++ = '\0'; 187 188 port=atoi(sep); 189 } 190 else 191 port=0; 192 193 194 /* 195 * Setup the SAMBA server state... 196 */ 197 198 setup_logging("smbspool", True); 199 200 in_client = True; /* Make sure that we tell lp_load we are */ 201 202 if (!lp_load(dyn_CONFIGFILE, True, False, False)) 203 { 204 fprintf(stderr, "ERROR: Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE); 205 return (1); 206 } 207 208 if (workgroup == NULL) 209 workgroup = lp_workgroup(); 210 211 load_interfaces(); 212 213 do 214 { 215 if ((cli = smb_connect(workgroup, server, port, printer, username, password)) == NULL) 216 { 217 if (getenv("CLASS") == NULL) 218 { 219 fprintf(stderr, "ERROR: Unable to connect to SAMBA host, will retry in 60 seconds..."); 220 sleep (60); 221 } 222 else 223 { 224 fprintf(stderr, "ERROR: Unable to connect to SAMBA host, trying next printer..."); 225 return (1); 226 } 227 } 228 } 229 while (cli == NULL); 230 231 /* 232 * Now that we are connected to the server, ignore SIGTERM so that we 233 * can finish out any page data the driver sends (e.g. to eject the 234 * current page... Only ignore SIGTERM if we are printing data from 235 * stdin (otherwise you can't cancel raw jobs...) 236 */ 237 238 if (argc < 7) 239 CatchSignal(SIGTERM, SIG_IGN); 240 241 /* 242 * Queue the job... 243 */ 244 245 for (i = 0; i < copies; i ++) 246 if ((status = smb_print(cli, argv[3] /* title */, fp)) != 0) 247 break; 248 249 cli_shutdown(cli); 250 251 /* 252 * Return the queue status... 253 */ 254 255 return (status); 256} 257 258 259/* 260 * 'list_devices()' - List the available printers seen on the network... 261 */ 262 263static void 264list_devices(void) 265{ 266 /* 267 * Eventually, search the local workgroup for available hosts and printers. 268 */ 269 270 puts("network smb \"Unknown\" \"Windows Printer via SAMBA\""); 271} 272 273 274/* 275 * 'smb_connect()' - Return a connection to a server. 276 */ 277 278static struct cli_state * /* O - SMB connection */ 279smb_connect(const char *workgroup, /* I - Workgroup */ 280 const char *server, /* I - Server */ 281 const int port, /* I - Port */ 282 const char *share, /* I - Printer */ 283 const char *username, /* I - Username */ 284 const char *password) /* I - Password */ 285{ 286 struct cli_state *c; /* New connection */ 287 pstring myname; /* Client name */ 288 NTSTATUS nt_status; 289 290 /* 291 * Get the names and addresses of the client and server... 292 */ 293 294 get_myname(myname); 295 296 nt_status = cli_full_connection(&c, myname, server, NULL, port, share, "?????", 297 username, workgroup, password, 0, Undefined, NULL); 298 299 if (!NT_STATUS_IS_OK(nt_status)) { 300 fprintf(stderr, "ERROR: Connection failed with error %s\n", nt_errstr(nt_status)); 301 return NULL; 302 } 303 304 /* 305 * Return the new connection... 306 */ 307 308 return (c); 309} 310 311 312/* 313 * 'smb_print()' - Queue a job for printing using the SMB protocol. 314 */ 315 316static int /* O - 0 = success, non-0 = failure */ 317smb_print(struct cli_state *cli, /* I - SMB connection */ 318 char *title, /* I - Title/job name */ 319 FILE *fp) /* I - File to print */ 320{ 321 int fnum; /* File number */ 322 int nbytes, /* Number of bytes read */ 323 tbytes; /* Total bytes read */ 324 char buffer[8192], /* Buffer for copy */ 325 *ptr; /* Pointer into tile */ 326 327 328 /* 329 * Sanitize the title... 330 */ 331 332 for (ptr = title; *ptr; ptr ++) 333 if (!isalnum((int)*ptr) && !isspace((int)*ptr)) 334 *ptr = '_'; 335 336 /* 337 * Open the printer device... 338 */ 339 340 if ((fnum = cli_open(cli, title, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE)) == -1) 341 { 342 fprintf(stderr, "ERROR: %s opening remote spool %s\n", 343 cli_errstr(cli), title); 344 return (1); 345 } 346 347 /* 348 * Copy the file to the printer... 349 */ 350 351 if (fp != stdin) 352 rewind(fp); 353 354 tbytes = 0; 355 356 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) 357 { 358 if (cli_write(cli, fnum, 0, buffer, tbytes, nbytes) != nbytes) 359 { 360 fprintf(stderr, "ERROR: Error writing spool: %s\n", cli_errstr(cli)); 361 break; 362 } 363 364 tbytes += nbytes; 365 } 366 367 if (!cli_close(cli, fnum)) 368 { 369 fprintf(stderr, "ERROR: %s closing remote spool %s\n", 370 cli_errstr(cli), title); 371 return (1); 372 } 373 else 374 return (0); 375} 376