1/* 2 Unix SMB/Netbios implementation. 3 Version 2.0. 4 SMB backend for the Common UNIX Printing System ("CUPS") 5 Copyright 1999 by Easy Software Products 6 Copyright Andrew Tridgell 1994-1998 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 */ 32extern struct in_addr ipzero; /* Any address */ 33 34 35/* 36 * Local functions... 37 */ 38 39static struct cli_state *smb_connect(char *, char *, char *, char *, 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 char uri[1024], /* URI */ 54 *sep, /* Pointer to separator */ 55 *username, /* Username */ 56 *password, /* Password */ 57 *workgroup, /* Workgroup */ 58 *server, /* Server name */ 59 *printer; /* Printer name */ 60 FILE *fp; /* File to print */ 61 int status; /* Status of LPD job */ 62 struct cli_state *cli; /* SMB interface */ 63 64 /* we expect the URI in argv[0]. Detect the case where it is in argv[1] and cope */ 65 if (argc > 2 && strncmp(argv[0],"smb://", 6) && !strncmp(argv[1],"smb://", 6)) { 66 argv++; 67 argc--; 68 } 69 70 71 if (argc < 6 || argc > 7) 72 { 73 fprintf(stderr, "Usage: %s [DEVICE_URI] job-id user title copies options [file]\n", 74 argv[0]); 75 fputs(" The DEVICE_URI environment variable can also contain the\n", stderr); 76 fputs(" destination printer:\n", stderr); 77 fputs("\n", stderr); 78 fputs(" smb://[username:password@][workgroup/]server/printer\n", stderr); 79 return (1); 80 } 81 82 /* 83 * If we have 7 arguments, print the file named on the command-line. 84 * Otherwise, print data from stdin... 85 */ 86 87 if (argc == 6) 88 { 89 /* 90 * Print from Copy stdin to a temporary file... 91 */ 92 93 fp = stdin; 94 copies = 1; 95 } 96 else if ((fp = fopen(argv[6], "rb")) == NULL) 97 { 98 perror("ERROR: Unable to open print file"); 99 return (1); 100 } 101 else 102 copies = atoi(argv[4]); 103 104 /* 105 * Fine the URI... 106 */ 107 108 if (strncmp(argv[0], "smb://", 6) == 0) 109 strncpy(uri, argv[0], sizeof(uri) - 1); 110 else if (getenv("DEVICE_URI") != NULL) 111 strncpy(uri, getenv("DEVICE_URI"), sizeof(uri) - 1); 112 else 113 { 114 fputs("ERROR: No device URI found in argv[0] or DEVICE_URI environment variable!\n", stderr); 115 return (1); 116 } 117 118 uri[sizeof(uri) - 1] = '\0'; 119 120 /* 121 * Extract the destination from the URI... 122 */ 123 124 if ((sep = strrchr(uri, '@')) != NULL) 125 { 126 username = uri + 6; 127 *sep++ = '\0'; 128 129 server = sep; 130 131 /* 132 * Extract password as needed... 133 */ 134 135 if ((password = strchr(username, ':')) != NULL) 136 *password++ = '\0'; 137 else 138 password = ""; 139 } 140 else 141 { 142 username = ""; 143 password = ""; 144 server = uri + 6; 145 } 146 147 if ((sep = strchr(server, '/')) == NULL) 148 { 149 fputs("ERROR: Bad URI - need printer name!\n", stderr); 150 return (1); 151 } 152 153 *sep++ = '\0'; 154 printer = sep; 155 156 if ((sep = strchr(printer, '/')) != NULL) 157 { 158 /* 159 * Convert to smb://[username:password@]workgroup/server/printer... 160 */ 161 162 *sep++ = '\0'; 163 164 workgroup = server; 165 server = printer; 166 printer = sep; 167 } 168 else 169 workgroup = NULL; 170 171 /* 172 * Setup the SAMBA server state... 173 */ 174 175 setup_logging("smbspool", True); 176 177 TimeInit(); 178 charset_initialise(); 179 180 in_client = True; /* Make sure that we tell lp_load we are */ 181 182 if (!lp_load(CONFIGFILE, True, False, False)) 183 { 184 fprintf(stderr, "ERROR: Can't load %s - run testparm to debug it\n", CONFIGFILE); 185 return (1); 186 } 187 188 if (workgroup == NULL) 189 workgroup = lp_workgroup(); 190 191 codepage_initialise(lp_client_code_page()); 192 193 load_interfaces(); 194 195 if ((cli = smb_connect(workgroup, server, printer, username, password)) == NULL) 196 { 197 perror("ERROR: Unable to connect to SAMBA host"); 198 return (1); 199 } 200 201 /* 202 * Queue the job... 203 */ 204 205 for (i = 0; i < copies; i ++) 206 if ((status = smb_print(cli, argv[3] /* title */, fp)) != 0) 207 break; 208 209 cli_shutdown(cli); 210 211 /* 212 * Return the queue status... 213 */ 214 215 return (status); 216} 217 218 219/* 220 * 'smb_connect()' - Return a connection to a server. 221 */ 222 223static struct cli_state * /* O - SMB connection */ 224smb_connect(char *workgroup, /* I - Workgroup */ 225 char *server, /* I - Server */ 226 char *share, /* I - Printer */ 227 char *username, /* I - Username */ 228 char *password) /* I - Password */ 229{ 230 struct cli_state *c; /* New connection */ 231 struct nmb_name called, /* NMB name of server */ 232 calling; /* NMB name of client */ 233 struct in_addr ip; /* IP address of server */ 234 pstring myname; /* Client name */ 235 236 237 /* 238 * Get the names and addresses of the client and server... 239 */ 240 241 get_myname(myname); 242 243 ip = ipzero; 244 245 make_nmb_name(&calling, myname, 0x0); 246 make_nmb_name(&called, server, 0x20); 247 248 /* 249 * Open a new connection to the SMB server... 250 */ 251 252 if ((c = cli_initialise(NULL)) == NULL) 253 { 254 fputs("ERROR: cli_initialize() failed...\n", stderr); 255 return (NULL); 256 } 257 258 if (!cli_set_port(c, SMB_PORT)) 259 { 260 fputs("ERROR: cli_set_port() failed...\n", stderr); 261 return (NULL); 262 } 263 264 if (!cli_connect(c, server, &ip)) 265 { 266 fputs("ERROR: cli_connect() failed...\n", stderr); 267 return (NULL); 268 } 269 270 if (!cli_session_request(c, &calling, &called)) 271 { 272 fputs("ERROR: cli_session_request() failed...\n", stderr); 273 return (NULL); 274 } 275 276 if (!cli_negprot(c)) 277 { 278 fputs("ERROR: SMB protocol negotiation failed\n", stderr); 279 cli_shutdown(c); 280 return (NULL); 281 } 282 283 /* 284 * Do password stuff... 285 */ 286 287 if (!cli_session_setup(c, username, 288 password, strlen(password), 289 password, strlen(password), 290 workgroup)) 291 { 292 fprintf(stderr, "ERROR: SMB session setup failed: %s\n", cli_errstr(c)); 293 return (NULL); 294 } 295 296 if (!cli_send_tconX(c, share, "?????", 297 password, strlen(password)+1)) 298 { 299 fprintf(stderr, "ERROR: SMB tree connect failed: %s\n", cli_errstr(c)); 300 cli_shutdown(c); 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 326 327 /* 328 * Open the printer device... 329 */ 330 331 if ((fnum = cli_open(cli, title, O_WRONLY | O_CREAT | O_TRUNC, DENY_NONE)) == -1) 332 { 333 fprintf(stderr, "ERROR: %s opening remote file %s\n", 334 cli_errstr(cli), title); 335 return (1); 336 } 337 338 /* 339 * Copy the file to the printer... 340 */ 341 342 if (fp != stdin) 343 rewind(fp); 344 345 tbytes = 0; 346 347 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) 348 { 349 if (cli_write(cli, fnum, 0, buffer, tbytes, nbytes) != nbytes) 350 { 351 fprintf(stderr, "ERROR: Error writing file: %s\n", cli_errstr(cli)); 352 break; 353 } 354 355 tbytes += nbytes; 356 } 357 358 if (!cli_close(cli, fnum)) 359 { 360 fprintf(stderr, "ERROR: %s closing remote file %s\n", 361 cli_errstr(cli), title); 362 return (1); 363 } 364 else 365 return (0); 366} 367