1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Printing and Spooling RPC service. 27 */ 28 #include <unistd.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <pthread.h> 32 #include <synch.h> 33 #include <smbsrv/libsmb.h> 34 #include <smbsrv/libmlrpc.h> 35 #include <smbsrv/libmlsvc.h> 36 #include <smbsrv/ndl/ndrtypes.ndl> 37 #include <smbsrv/ndl/spoolss.ndl> 38 #include <smb/nterror.h> 39 #include <smbsrv/smbinfo.h> 40 #include <smbsrv/nmpipes.h> 41 #include <wchar.h> 42 #include <cups/cups.h> 43 #include <fcntl.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 #include <errno.h> 47 #include <dlfcn.h> 48 #include <mlsvc.h> 49 50 typedef struct smb_spool { 51 list_t sp_list; 52 int sp_cnt; 53 rwlock_t sp_rwl; 54 int sp_initialized; 55 } smb_spool_t; 56 57 static uint32_t spoolss_cnt; 58 static uint32_t spoolss_jobnum = 1; 59 static smb_spool_t spoolss_splist; 60 static smb_cups_ops_t smb_cups; 61 static mutex_t spoolss_cups_mutex; 62 63 #define SPOOLSS_PJOBLEN 256 64 #define SPOOLSS_JOB_NOT_ISSUED 3004 65 #define SPOOLSS_PRINTER "Postscript" 66 #define SPOOLSS_FN_PREFIX "cifsprintjob-" 67 #define SPOOLSS_CUPS_SPOOL_DIR "//var//spool//cups" 68 69 struct spoolss_printjob { 70 pid_t pj_pid; 71 int pj_sysjob; 72 int pj_fd; 73 time_t pj_start_time; 74 int pj_status; 75 size_t pj_size; 76 int pj_page_count; 77 boolean_t pj_isspooled; 78 boolean_t pj_jobnum; 79 char pj_filename[SPOOLSS_PJOBLEN]; 80 char pj_jobname[SPOOLSS_PJOBLEN]; 81 char pj_username[SPOOLSS_PJOBLEN]; 82 char pj_queuename[SPOOLSS_PJOBLEN]; 83 }; 84 85 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result_u); 86 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result); 87 DECL_FIXUP_STRUCT(spoolss_GetPrinter); 88 89 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA); 90 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA); 91 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO); 92 DECL_FIXUP_STRUCT(spoolss_RFNPCNEX); 93 94 uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *); 95 static int spoolss_s_make_sd(uint8_t *); 96 static uint32_t spoolss_sd_format(smb_sd_t *); 97 static int spoolss_find_fd(ndr_hdid_t *); 98 static void spoolss_find_doc_and_print(ndr_hdid_t *); 99 static void spoolss_add_spool_doc(smb_spooldoc_t *); 100 static int spoolss_cups_init(void); 101 static void spoolss_cups_fini(void); 102 103 static int spoolss_s_OpenPrinter(void *, ndr_xa_t *); 104 static int spoolss_s_ClosePrinter(void *, ndr_xa_t *); 105 static int spoolss_s_AbortPrinter(void *, ndr_xa_t *); 106 static int spoolss_s_ResetPrinter(void *, ndr_xa_t *); 107 static int spoolss_s_GetPrinter(void *, ndr_xa_t *); 108 static int spoolss_s_GetPrinterData(void *, ndr_xa_t *); 109 static int spoolss_s_AddJob(void *, ndr_xa_t *); 110 static int spoolss_s_GetJob(void *, ndr_xa_t *); 111 static int spoolss_s_EnumJobs(void *, ndr_xa_t *); 112 static int spoolss_s_ScheduleJob(void *, ndr_xa_t *); 113 static int spoolss_s_StartDocPrinter(void *, ndr_xa_t *); 114 static int spoolss_s_EndDocPrinter(void *, ndr_xa_t *); 115 static int spoolss_s_StartPagePrinter(void *, ndr_xa_t *); 116 static int spoolss_s_EndPagePrinter(void *, ndr_xa_t *); 117 static int spoolss_s_rfnpcnex(void *, ndr_xa_t *); 118 static int spoolss_s_WritePrinter(void *, ndr_xa_t *); 119 static int spoolss_s_EnumForms(void *, ndr_xa_t *); 120 static int spoolss_s_stub(void *, ndr_xa_t *); 121 122 static ndr_stub_table_t spoolss_stub_table[] = { 123 { spoolss_s_GetJob, SPOOLSS_OPNUM_GetJob }, 124 { spoolss_s_EnumJobs, SPOOLSS_OPNUM_EnumJobs }, 125 { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinter }, 126 { spoolss_s_GetPrinter, SPOOLSS_OPNUM_GetPrinter }, 127 { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver }, 128 { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterDriver }, 129 { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinter }, 130 { spoolss_s_StartDocPrinter, SPOOLSS_OPNUM_StartDocPrinter }, 131 { spoolss_s_WritePrinter, SPOOLSS_OPNUM_WritePrinter }, 132 { spoolss_s_EndDocPrinter, SPOOLSS_OPNUM_EndDocPrinter }, 133 { spoolss_s_StartPagePrinter, SPOOLSS_OPNUM_StartPagePrinter }, 134 { spoolss_s_EndPagePrinter, SPOOLSS_OPNUM_EndPagePrinter }, 135 { spoolss_s_AbortPrinter, SPOOLSS_OPNUM_AbortPrinter }, 136 { spoolss_s_ResetPrinter, SPOOLSS_OPNUM_ResetPrinter }, 137 { spoolss_s_AddJob, SPOOLSS_OPNUM_AddJob }, 138 { spoolss_s_ScheduleJob, SPOOLSS_OPNUM_ScheduleJob }, 139 { spoolss_s_GetPrinterData, SPOOLSS_OPNUM_GetPrinterData }, 140 { spoolss_s_ClosePrinter, SPOOLSS_OPNUM_ClosePrinter }, 141 { spoolss_s_EnumForms, SPOOLSS_OPNUM_EnumForms }, 142 { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver2 }, 143 { spoolss_s_stub, SPOOLSS_OPNUM_FCPN }, 144 { spoolss_s_stub, SPOOLSS_OPNUM_ReplyOpenPrinter }, 145 { spoolss_s_stub, SPOOLSS_OPNUM_ReplyClosePrinter }, 146 { spoolss_s_stub, SPOOLSS_OPNUM_RFFPCNEX }, 147 { spoolss_s_rfnpcnex, SPOOLSS_OPNUM_RFNPCNEX }, 148 { spoolss_s_stub, SPOOLSS_OPNUM_RRPCN }, 149 { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinterEx }, 150 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterData }, 151 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterDataEx }, 152 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterKey }, 153 {0} 154 }; 155 156 static ndr_service_t spoolss_service = { 157 "SPOOLSS", /* name */ 158 "Print Spool Service", /* desc */ 159 "\\spoolss", /* endpoint */ 160 PIPE_SPOOLSS, /* sec_addr_port */ 161 "12345678-1234-abcd-ef00-0123456789ab", 1, /* abstract */ 162 NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */ 163 0, /* no bind_instance_size */ 164 0, /* no bind_req() */ 165 0, /* no unbind_and_close() */ 166 0, /* use generic_call_stub() */ 167 &TYPEINFO(spoolss_interface), /* interface ti */ 168 spoolss_stub_table /* stub_table */ 169 }; 170 171 /* 172 * Defer calling spoolss_cups_init() until something actually 173 * needs access to CUPS due to the libcups dependency on OpenSSL. 174 * OpenSSL is not MT-safe and initializing CUPS here can crash 175 * OpenSSL if it collides with other threads that are in other 176 * libraries that are attempting to use OpenSSL. 177 */ 178 void 179 spoolss_initialize(void) 180 { 181 (void) ndr_svc_register(&spoolss_service); 182 } 183 184 void 185 spoolss_finalize(void) 186 { 187 spoolss_cups_fini(); 188 } 189 190 static int 191 spoolss_s_OpenPrinter(void *arg, ndr_xa_t *mxa) 192 { 193 struct spoolss_OpenPrinter *param = arg; 194 ndr_hdid_t *id; 195 196 if ((id = ndr_hdalloc(mxa, 0)) == NULL) { 197 bzero(¶m->handle, sizeof (spoolss_handle_t)); 198 param->status = ERROR_NOT_ENOUGH_MEMORY; 199 return (NDR_DRC_OK); 200 } 201 202 bcopy(id, ¶m->handle, sizeof (spoolss_handle_t)); 203 param->status = 0; 204 205 return (NDR_DRC_OK); 206 } 207 208 /*ARGSUSED*/ 209 static int 210 spoolss_s_StartPagePrinter(void *arg, ndr_xa_t *mxa) 211 { 212 struct spoolss_StartPagePrinter *param = arg; 213 214 param->status = ERROR_SUCCESS; 215 216 return (NDR_DRC_OK); 217 } 218 219 /*ARGSUSED*/ 220 static int 221 spoolss_s_EndPagePrinter(void *arg, ndr_xa_t *mxa) 222 { 223 struct spoolss_EndPagePrinter *param = arg; 224 225 param->status = ERROR_SUCCESS; 226 227 return (NDR_DRC_OK); 228 } 229 230 /* 231 * 232 * adds new spool doc to the tail. used by windows 233 * XP and 2000 only 234 * 235 * Return values 236 * smb_spooldoc_t - NULL if not found 237 */ 238 239 static void 240 spoolss_add_spool_doc(smb_spooldoc_t *sp) 241 { 242 (void) rw_wrlock(&spoolss_splist.sp_rwl); 243 if (!spoolss_splist.sp_initialized) { 244 list_create(&spoolss_splist.sp_list, 245 sizeof (smb_spooldoc_t), 246 offsetof(smb_spooldoc_t, sd_lnd)); 247 spoolss_splist.sp_initialized = 1; 248 } 249 list_insert_tail(&spoolss_splist.sp_list, sp); 250 spoolss_splist.sp_cnt++; 251 (void) rw_unlock(&spoolss_splist.sp_rwl); 252 } 253 254 /* 255 * 256 * finds a completed spool doc using the RPC handle 257 * as the key, then prints the doc 258 * 259 * XP and 2000 only 260 * 261 */ 262 263 static void 264 spoolss_find_doc_and_print(ndr_hdid_t *handle) 265 { 266 smb_spooldoc_t *sp; 267 268 if (!spoolss_splist.sp_initialized) { 269 syslog(LOG_ERR, "spoolss_find_doc_and_print: not initialized"); 270 return; 271 } 272 (void) rw_wrlock(&spoolss_splist.sp_rwl); 273 sp = list_head(&spoolss_splist.sp_list); 274 while (sp != NULL) { 275 /* 276 * search the spooldoc list for a matching RPC handle 277 * and use the info to pass to cups for printing 278 */ 279 if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) { 280 spoolss_copy_spool_file(&sp->sd_ipaddr, 281 sp->sd_username, sp->sd_path, sp->sd_doc_name); 282 (void) close(sp->sd_fd); 283 list_remove(&spoolss_splist.sp_list, sp); 284 free(sp); 285 (void) rw_unlock(&spoolss_splist.sp_rwl); 286 return; 287 } 288 sp = list_next(&spoolss_splist.sp_list, sp); 289 } 290 syslog(LOG_ERR, "spoolss_find_doc_and_print: handle not found"); 291 (void) rw_unlock(&spoolss_splist.sp_rwl); 292 } 293 294 static int 295 spoolss_find_fd(ndr_hdid_t *handle) 296 { 297 smb_spooldoc_t *sp; 298 299 if (!spoolss_splist.sp_initialized) { 300 syslog(LOG_ERR, "spoolss_find_fd: not initialized"); 301 return (-1); 302 } 303 (void) rw_rdlock(&spoolss_splist.sp_rwl); 304 sp = list_head(&spoolss_splist.sp_list); 305 while (sp != NULL) { 306 /* 307 * check for a matching rpc handle in the 308 * spooldoc list 309 */ 310 if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) { 311 (void) rw_unlock(&spoolss_splist.sp_rwl); 312 return (sp->sd_fd); 313 } 314 sp = list_next(&spoolss_splist.sp_list, sp); 315 } 316 syslog(LOG_ERR, "spoolss_find_fd: handle not found"); 317 (void) rw_unlock(&spoolss_splist.sp_rwl); 318 return (-1); 319 } 320 321 /* 322 * Windows XP and 2000 use this mechanism to write spool files. 323 * Creates a spool file fd to be used by spoolss_s_WritePrinter. 324 */ 325 static int 326 spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa) 327 { 328 struct spoolss_StartDocPrinter *param = arg; 329 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 330 smb_spooldoc_t *spfile; 331 spoolss_DocInfo_t *docinfo; 332 char g_path[MAXPATHLEN]; 333 smb_share_t si; 334 int rc; 335 int fd; 336 337 if (ndr_hdlookup(mxa, id) == NULL) { 338 syslog(LOG_ERR, "spoolss_s_StartDocPrinter: invalid handle"); 339 param->status = ERROR_INVALID_HANDLE; 340 return (NDR_DRC_OK); 341 } 342 343 if ((docinfo = param->dinfo.DocInfoContainer) == NULL) { 344 param->status = ERROR_INVALID_PARAMETER; 345 return (NDR_DRC_OK); 346 } 347 348 if ((rc = smb_shr_get(SMB_SHARE_PRINT, &si)) != NERR_Success) { 349 syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s error=%d", 350 SMB_SHARE_PRINT, rc); 351 param->status = rc; 352 return (NDR_DRC_OK); 353 } 354 355 if ((spfile = calloc(1, sizeof (smb_spooldoc_t))) == NULL) { 356 param->status = ERROR_NOT_ENOUGH_MEMORY; 357 return (NDR_DRC_OK); 358 } 359 360 if (docinfo->doc_name != NULL) 361 (void) strlcpy(spfile->sd_doc_name, 362 (char *)docinfo->doc_name, MAXNAMELEN); 363 else 364 (void) strlcpy(spfile->sd_doc_name, "document", MAXNAMELEN); 365 366 if (docinfo->printer_name != NULL) 367 (void) strlcpy(spfile->sd_printer_name, 368 (char *)docinfo->printer_name, MAXPATHLEN); 369 else 370 (void) strlcpy(spfile->sd_printer_name, "printer", MAXPATHLEN); 371 372 spfile->sd_ipaddr = mxa->pipe->np_user.ui_ipaddr; 373 (void) strlcpy((char *)spfile->sd_username, 374 mxa->pipe->np_user.ui_account, MAXNAMELEN); 375 (void) memcpy(&spfile->sd_handle, ¶m->handle, 376 sizeof (rpc_handle_t)); 377 /* 378 * write temporary spool file to print$ 379 */ 380 (void) snprintf(g_path, MAXPATHLEN, "%s/%s%d", si.shr_path, 381 spfile->sd_username, spoolss_cnt); 382 atomic_inc_32(&spoolss_cnt); 383 384 fd = open(g_path, O_CREAT | O_RDWR, 0600); 385 if (fd == -1) { 386 syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s: %s", 387 g_path, strerror(errno)); 388 param->status = ERROR_OPEN_FAILED; 389 free(spfile); 390 } else { 391 (void) strlcpy((char *)spfile->sd_path, g_path, MAXPATHLEN); 392 spfile->sd_fd = (uint16_t)fd; 393 spoolss_add_spool_doc(spfile); 394 /* 395 * JobId isn't used now, but if printQ management is added 396 * this will have to be incremented per job submitted. 397 */ 398 param->JobId = 46; 399 param->status = ERROR_SUCCESS; 400 } 401 return (NDR_DRC_OK); 402 } 403 404 /* 405 * Windows XP and 2000 use this mechanism to write spool files 406 */ 407 408 /*ARGSUSED*/ 409 static int 410 spoolss_s_EndDocPrinter(void *arg, ndr_xa_t *mxa) 411 { 412 struct spoolss_EndDocPrinter *param = arg; 413 414 spoolss_find_doc_and_print((ndr_hdid_t *)¶m->handle); 415 param->status = ERROR_SUCCESS; 416 return (NDR_DRC_OK); 417 } 418 419 /*ARGSUSED*/ 420 static int 421 spoolss_s_AbortPrinter(void *arg, ndr_xa_t *mxa) 422 { 423 struct spoolss_AbortPrinter *param = arg; 424 425 param->status = ERROR_SUCCESS; 426 return (NDR_DRC_OK); 427 } 428 429 /*ARGSUSED*/ 430 static int 431 spoolss_s_ResetPrinter(void *arg, ndr_xa_t *mxa) 432 { 433 struct spoolss_AbortPrinter *param = arg; 434 435 param->status = ERROR_SUCCESS; 436 return (NDR_DRC_OK); 437 } 438 439 static int 440 spoolss_s_ClosePrinter(void *arg, ndr_xa_t *mxa) 441 { 442 struct spoolss_ClosePrinter *param = arg; 443 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 444 ndr_handle_t *hd; 445 446 if ((hd = ndr_hdlookup(mxa, id)) != NULL) { 447 free(hd->nh_data); 448 hd->nh_data = NULL; 449 } 450 451 ndr_hdfree(mxa, id); 452 bzero(¶m->result_handle, sizeof (spoolss_handle_t)); 453 param->status = ERROR_SUCCESS; 454 return (NDR_DRC_OK); 455 } 456 457 /*ARGSUSED*/ 458 int 459 spoolss_s_EnumForms(void *arg, ndr_xa_t *mxa) 460 { 461 struct spoolss_EnumForms *param = arg; 462 DWORD status = ERROR_SUCCESS; 463 464 param->status = status; 465 param->needed = 0; 466 return (NDR_DRC_OK); 467 } 468 469 /*ARGSUSED*/ 470 int 471 spoolss_s_EnumJobs(void *arg, ndr_xa_t *mxa) 472 { 473 struct spoolss_EnumJobs *param = arg; 474 DWORD status = ERROR_SUCCESS; 475 476 switch (param->level) { 477 case 1: 478 case 2: 479 case 3: 480 case 4: 481 default: 482 break; 483 } 484 485 param->status = status; 486 param->needed = 0; 487 param->needed2 = 0; 488 return (NDR_DRC_OK); 489 } 490 491 492 /*ARGSUSED*/ 493 static int 494 spoolss_s_GetJob(void *arg, ndr_xa_t *mxa) 495 { 496 struct spoolss_GetJob *param = arg; 497 DWORD status = ERROR_SUCCESS; 498 499 if (param->BufCount == 0) 500 param->status = ERROR_INSUFFICIENT_BUFFER; 501 else 502 param->status = status; 503 param->needed = 0; 504 return (NDR_DRC_OK); 505 } 506 507 508 /*ARGSUSED*/ 509 static int 510 spoolss_s_ScheduleJob(void *arg, ndr_xa_t *mxa) 511 { 512 struct spoolss_ScheduleJob *param = arg; 513 DWORD status = SPOOLSS_JOB_NOT_ISSUED; 514 515 param->status = status; 516 return (NDR_DRC_OK); 517 } 518 519 /*ARGSUSED*/ 520 static int 521 spoolss_s_AddJob(void *arg, ndr_xa_t *mxa) 522 { 523 struct spoolss_AddJob *param = arg; 524 525 param->status = ERROR_SUCCESS; 526 param->needed = 0; 527 return (NDR_DRC_OK); 528 } 529 530 /*ARGSUSED*/ 531 static int 532 spoolss_s_rfnpcnex(void *arg, ndr_xa_t *mxa) 533 { 534 struct spoolss_RFNPCNEX *param = arg; 535 536 param->ppinfo = 0; 537 param->status = ERROR_SUCCESS; 538 return (NDR_DRC_OK); 539 } 540 541 /* 542 * Use the RPC context handle to find the fd and write the document content. 543 */ 544 static int 545 spoolss_s_WritePrinter(void *arg, ndr_xa_t *mxa) 546 { 547 struct spoolss_WritePrinter *param = arg; 548 int written = 0; 549 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 550 int spfd; 551 552 if (ndr_hdlookup(mxa, id) == NULL) { 553 param->written = 0; 554 param->status = ERROR_INVALID_HANDLE; 555 syslog(LOG_ERR, "spoolss_s_WritePrinter: invalid handle"); 556 return (NDR_DRC_OK); 557 } 558 559 if ((spfd = spoolss_find_fd(id)) < 0) { 560 param->written = 0; 561 param->status = ERROR_INVALID_HANDLE; 562 syslog(LOG_ERR, "spoolss_s_WritePrinter: cannot find fd"); 563 return (NDR_DRC_OK); 564 } 565 566 written = write(spfd, param->pBuf, param->BufCount); 567 if (written < param->BufCount) { 568 syslog(LOG_ERR, "spoolss_s_WritePrinter: write failed"); 569 param->written = 0; 570 param->status = ERROR_CANTWRITE; 571 return (NDR_DRC_OK); 572 } 573 574 param->written = written; 575 param->status = ERROR_SUCCESS; 576 return (NDR_DRC_OK); 577 } 578 579 /* 580 * All versions of windows use this function to print 581 * spool files via the cups interface 582 */ 583 584 void 585 spoolss_copy_spool_file(smb_inaddr_t *ipaddr, char *username, 586 char *path, char *doc_name) 587 { 588 smb_cups_ops_t *cups; 589 int ret = 1; /* Return value */ 590 http_t *http = NULL; /* HTTP connection to server */ 591 ipp_t *request = NULL; /* IPP Request */ 592 ipp_t *response = NULL; /* IPP Response */ 593 cups_lang_t *language = NULL; /* Default language */ 594 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 595 char new_jobname[SPOOLSS_PJOBLEN]; 596 struct spoolss_printjob pjob; 597 char clientname[INET6_ADDRSTRLEN]; 598 struct stat sbuf; 599 600 if (stat(path, &sbuf)) { 601 syslog(LOG_INFO, "spoolss_copy_spool_file: %s: %s", 602 path, strerror(errno)); 603 return; 604 } 605 606 /* 607 * Remove zero size files and return; these were inadvertantly 608 * created by XP or 2000. 609 */ 610 if (sbuf.st_blocks == 0) { 611 if (remove(path)) 612 syslog(LOG_INFO, 613 "spoolss_copy_spool_file: cannot remove %s", path); 614 return; 615 } 616 617 if ((cups = spoolss_cups_ops()) == NULL) 618 return; 619 620 if ((http = cups->httpConnect("localhost", 631)) == NULL) { 621 syslog(LOG_INFO, "spoolss_copy_spool_file: cupsd not running"); 622 return; 623 } 624 625 if ((request = cups->ippNew()) == NULL) { 626 syslog(LOG_INFO, "spoolss_copy_spool_file: ipp not running"); 627 return; 628 } 629 request->request.op.operation_id = IPP_PRINT_JOB; 630 request->request.op.request_id = 1; 631 language = cups->cupsLangDefault(); 632 633 cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 634 "attributes-charset", NULL, cups->cupsLangEncoding(language)); 635 636 cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 637 "attributes-natural-language", NULL, language->language); 638 639 (void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s", 640 SPOOLSS_PRINTER); 641 pjob.pj_pid = pthread_self(); 642 pjob.pj_sysjob = 10; 643 (void) strlcpy(pjob.pj_filename, path, SPOOLSS_PJOBLEN); 644 pjob.pj_start_time = time(NULL); 645 pjob.pj_status = 2; 646 pjob.pj_size = sbuf.st_blocks * 512; 647 pjob.pj_page_count = 1; 648 pjob.pj_isspooled = B_TRUE; 649 pjob.pj_jobnum = spoolss_jobnum; 650 651 (void) strlcpy(pjob.pj_jobname, doc_name, SPOOLSS_PJOBLEN); 652 (void) strlcpy(pjob.pj_username, username, SPOOLSS_PJOBLEN); 653 (void) strlcpy(pjob.pj_queuename, SPOOLSS_CUPS_SPOOL_DIR, 654 SPOOLSS_PJOBLEN); 655 cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 656 "printer-uri", NULL, uri); 657 658 cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 659 "requesting-user-name", NULL, pjob.pj_username); 660 661 if (smb_inet_ntop(ipaddr, clientname, 662 SMB_IPSTRLEN(ipaddr->a_family)) == NULL) { 663 syslog(LOG_INFO, "spoolss_copy_spool_file: %s: unknown client", 664 clientname); 665 goto out; 666 } 667 cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 668 "job-originating-host-name", NULL, clientname); 669 670 (void) snprintf(new_jobname, SPOOLSS_PJOBLEN, "%s%d", 671 SPOOLSS_FN_PREFIX, pjob.pj_jobnum); 672 cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 673 "job-name", NULL, new_jobname); 674 675 (void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SPOOLSS_PRINTER); 676 677 response = cups->cupsDoFileRequest(http, request, uri, 678 pjob.pj_filename); 679 if (response != NULL) { 680 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 681 syslog(LOG_ERR, 682 "spoolss_copy_spool_file: file print %s: %s", 683 SPOOLSS_PRINTER, 684 cups->ippErrorString(cups->cupsLastError())); 685 } else { 686 atomic_inc_32(&spoolss_jobnum); 687 ret = 0; 688 } 689 } else { 690 syslog(LOG_ERR, 691 "spoolss_copy_spool_file: unable to print file to %s", 692 cups->ippErrorString(cups->cupsLastError())); 693 } 694 695 if (ret == 0) 696 (void) unlink(pjob.pj_filename); 697 698 out: 699 if (response) 700 cups->ippDelete(response); 701 702 if (language) 703 cups->cupsLangFree(language); 704 705 if (http) 706 cups->httpClose(http); 707 } 708 709 static int 710 spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa) 711 { 712 struct spoolss_GetPrinterData *param = arg; 713 DWORD status = ERROR_SUCCESS; 714 715 if (param->Size > 0) { 716 param->Buf = NDR_NEWN(mxa, char, param->Size); 717 bzero(param->Buf, param->Size); 718 } else { 719 param->Buf = NDR_NEWN(mxa, uint32_t, 1); 720 param->Buf[0] = 1; 721 param->Buf[1] = 1; 722 param->Buf[2] = 2; 723 param->Buf[3] = 2; 724 } 725 726 /* 727 * Increment pType if the Printer Data changes 728 * as specified by Microsoft documentation 729 */ 730 param->pType = 1; 731 if (strcasecmp((char *)param->pValueName, "ChangeId") == 0) { 732 param->pType = 4; 733 param->Buf[3] = 0x00; 734 param->Buf[2] = 0x50; 735 param->Buf[1] = 0xac; 736 param->Buf[0] = 0xf2; 737 } else if (strcasecmp((char *)param->pValueName, 738 "UISingleJobStatusString") == 0) { 739 status = ERROR_FILE_NOT_FOUND; 740 } else if (strcasecmp((char *)param->pValueName, 741 "W3SvcInstalled") == 0) { 742 status = ERROR_FILE_NOT_FOUND; 743 } else if (strcasecmp((char *)param->pValueName, 744 "PrintProcCaps_NT EMF 1.008") == 0) { 745 status = ERROR_FILE_NOT_FOUND; 746 } else if (strcasecmp((char *)param->pValueName, "OSVersion") == 0) { 747 param->Buf = NDR_NEWN(mxa, char, param->Size); 748 bzero(param->Buf, param->Size); 749 param->Buf[0] = 0x14; 750 param->Buf[1] = 0x01; 751 param->Buf[4] = 0x05; 752 param->Buf[12] = 0x93; 753 param->Buf[13] = 0x08; 754 } 755 param->status = status; 756 param->Needed = param->Size; 757 return (NDR_DRC_OK); 758 } 759 760 smb_cups_ops_t * 761 spoolss_cups_ops(void) 762 { 763 if (spoolss_cups_init() != 0) 764 return (NULL); 765 766 return (&smb_cups); 767 } 768 769 static int 770 spoolss_cups_init(void) 771 { 772 (void) mutex_lock(&spoolss_cups_mutex); 773 774 if (smb_cups.cups_hdl != NULL) { 775 (void) mutex_unlock(&spoolss_cups_mutex); 776 return (0); 777 } 778 779 if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) { 780 (void) mutex_unlock(&spoolss_cups_mutex); 781 syslog(LOG_DEBUG, "spoolss_cups_init: cannot open libcups"); 782 return (ENOENT); 783 } 784 785 smb_cups.cupsLangDefault = 786 (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault"); 787 smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *)) 788 dlsym(smb_cups.cups_hdl, "cupsLangEncoding"); 789 smb_cups.cupsDoFileRequest = 790 (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *)) 791 dlsym(smb_cups.cups_hdl, "cupsDoFileRequest"); 792 smb_cups.cupsLastError = (ipp_status_t (*)()) 793 dlsym(smb_cups.cups_hdl, "cupsLastError"); 794 smb_cups.cupsLangFree = (void (*)(cups_lang_t *)) 795 dlsym(smb_cups.cups_hdl, "cupsLangFree"); 796 smb_cups.cupsGetDests = (int (*)(cups_dest_t **)) 797 dlsym(smb_cups.cups_hdl, "cupsGetDests"); 798 smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *)) 799 dlsym(smb_cups.cups_hdl, "cupsFreeDests"); 800 801 smb_cups.httpClose = (void (*)(http_t *)) 802 dlsym(smb_cups.cups_hdl, "httpClose"); 803 smb_cups.httpConnect = (http_t *(*)(const char *, int)) 804 dlsym(smb_cups.cups_hdl, "httpConnect"); 805 806 smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew"); 807 smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete"); 808 smb_cups.ippErrorString = (char *(*)()) 809 dlsym(smb_cups.cups_hdl, "ippErrorString"); 810 smb_cups.ippAddString = (ipp_attribute_t *(*)()) 811 dlsym(smb_cups.cups_hdl, "ippAddString"); 812 813 if (smb_cups.cupsLangDefault == NULL || 814 smb_cups.cupsLangEncoding == NULL || 815 smb_cups.cupsDoFileRequest == NULL || 816 smb_cups.cupsLastError == NULL || 817 smb_cups.cupsLangFree == NULL || 818 smb_cups.cupsGetDests == NULL || 819 smb_cups.cupsFreeDests == NULL || 820 smb_cups.ippNew == NULL || 821 smb_cups.httpClose == NULL || 822 smb_cups.httpConnect == NULL || 823 smb_cups.ippDelete == NULL || 824 smb_cups.ippErrorString == NULL || 825 smb_cups.ippAddString == NULL) { 826 smb_dlclose(smb_cups.cups_hdl); 827 smb_cups.cups_hdl = NULL; 828 (void) mutex_unlock(&spoolss_cups_mutex); 829 syslog(LOG_DEBUG, "spoolss_cups_init: cannot load libcups"); 830 return (ENOENT); 831 } 832 833 (void) mutex_unlock(&spoolss_cups_mutex); 834 return (0); 835 } 836 837 static void 838 spoolss_cups_fini(void) 839 { 840 (void) mutex_lock(&spoolss_cups_mutex); 841 842 if (smb_cups.cups_hdl != NULL) { 843 smb_dlclose(smb_cups.cups_hdl); 844 smb_cups.cups_hdl = NULL; 845 } 846 847 (void) mutex_unlock(&spoolss_cups_mutex); 848 } 849 850 void 851 smb_rpc_off(char *dst, char *src, uint32_t *offset, uint32_t *outoffset) 852 { 853 int nwchars; 854 int bytes; 855 856 bytes = smb_wcequiv_strlen(src) + 2; 857 nwchars = strlen(src) + 1; 858 *offset -= bytes; 859 *outoffset = *offset; 860 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 861 (void) smb_mbstowcs(((smb_wchar_t *)(dst + *offset)), src, nwchars); 862 } 863 864 int 865 spoolss_s_GetPrinter(void *arg, ndr_xa_t *mxa) 866 { 867 struct spoolss_GetPrinter *param = arg; 868 struct spoolss_GetPrinter0 *pinfo0; 869 struct spoolss_GetPrinter1 *pinfo1; 870 struct spoolss_GetPrinter2 *pinfo2; 871 struct spoolss_DeviceMode *devmode2; 872 DWORD status = ERROR_SUCCESS; 873 char *wname; 874 uint32_t offset; 875 smb_inaddr_t ipaddr; 876 struct hostent *h; 877 char hname[MAXHOSTNAMELEN]; 878 char soutbuf[MAXNAMELEN]; 879 char poutbuf[MAXNAMELEN]; 880 char ipstr[INET6_ADDRSTRLEN]; 881 int error; 882 uint8_t *tmpbuf; 883 884 if (param->BufCount == 0) { 885 status = ERROR_INSUFFICIENT_BUFFER; 886 goto error_out; 887 } 888 param->Buf = NDR_NEWN(mxa, char, param->BufCount); 889 bzero(param->Buf, param->BufCount); 890 switch (param->switch_value) { 891 case 0: 892 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 893 pinfo0 = (struct spoolss_GetPrinter0 *)param->Buf; 894 break; 895 case 1: 896 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 897 pinfo1 = (struct spoolss_GetPrinter1 *)param->Buf; 898 break; 899 case 2: 900 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 901 pinfo2 = (struct spoolss_GetPrinter2 *)param->Buf; 902 break; 903 } 904 wname = (char *)param->Buf; 905 906 status = ERROR_INVALID_PARAMETER; 907 if (smb_gethostname(hname, MAXHOSTNAMELEN, 0) != 0) { 908 syslog(LOG_NOTICE, "spoolss_s_GetPrinter: gethostname failed"); 909 goto error_out; 910 } 911 if ((h = smb_gethostbyname(hname, &error)) == NULL) { 912 syslog(LOG_NOTICE, 913 "spoolss_s_GetPrinter: gethostbyname failed"); 914 goto error_out; 915 } 916 bcopy(h->h_addr, &ipaddr, h->h_length); 917 ipaddr.a_family = h->h_addrtype; 918 freehostent(h); 919 if (smb_inet_ntop(&ipaddr, ipstr, SMB_IPSTRLEN(ipaddr.a_family)) 920 == NULL) { 921 syslog(LOG_NOTICE, "spoolss_s_GetPrinter: inet_ntop failed"); 922 goto error_out; 923 } 924 status = ERROR_SUCCESS; 925 (void) snprintf(poutbuf, MAXNAMELEN, "\\\\%s\\%s", 926 ipstr, SPOOLSS_PRINTER); 927 (void) snprintf(soutbuf, MAXNAMELEN, "\\\\%s", ipstr); 928 param->needed = 0; 929 switch (param->switch_value) { 930 case 0: 931 offset = 460; 932 smb_rpc_off(wname, "", &offset, &pinfo0->servername); 933 smb_rpc_off(wname, poutbuf, &offset, &pinfo0->printername); 934 pinfo0->cjobs = 0; 935 pinfo0->total_jobs = 6; 936 pinfo0->total_bytes = 1040771; 937 pinfo0->time0 = 0; 938 pinfo0->time1 = 0; 939 pinfo0->time2 = 3; 940 pinfo0->time3 = 0; 941 pinfo0->global_counter = 2162710; 942 pinfo0->total_pages = 21495865; 943 pinfo0->version = 10; 944 pinfo0->session_counter = 1; 945 pinfo0->job_error = 0x6; 946 pinfo0->change_id = 0x1; 947 pinfo0->status = 0; 948 pinfo0->c_setprinter = 0; 949 break; 950 case 1: 951 pinfo1->flags = PRINTER_ENUM_ICON8; 952 offset = 460; 953 smb_rpc_off(wname, poutbuf, &offset, &pinfo1->flags); 954 smb_rpc_off(wname, poutbuf, &offset, &pinfo1->description); 955 smb_rpc_off(wname, poutbuf, &offset, &pinfo1->comment); 956 break; 957 case 2: 958 offset = param->BufCount; 959 smb_rpc_off(wname, soutbuf, &offset, &pinfo2->servername); 960 smb_rpc_off(wname, poutbuf, &offset, &pinfo2->printername); 961 smb_rpc_off(wname, SPOOLSS_PRINTER, &offset, 962 &pinfo2->sharename); 963 smb_rpc_off(wname, "CIFS Printer Port", &offset, 964 &pinfo2->portname); 965 smb_rpc_off(wname, "", &offset, &pinfo2->drivername); 966 smb_rpc_off(wname, SPOOLSS_PRINTER, &offset, 967 &pinfo2->comment); 968 smb_rpc_off(wname, "farside", &offset, &pinfo2->location); 969 smb_rpc_off(wname, "farside", &offset, &pinfo2->sepfile); 970 smb_rpc_off(wname, "winprint", &offset, 971 &pinfo2->printprocessor); 972 smb_rpc_off(wname, "RAW", &offset, &pinfo2->datatype); 973 smb_rpc_off(wname, "", &offset, &pinfo2->datatype); 974 pinfo2->attributes = 0x00001048; 975 pinfo2->status = 0x00000000; 976 pinfo2->starttime = 0; 977 pinfo2->untiltime = 0; 978 pinfo2->cjobs = 0; 979 pinfo2->averageppm = 0; 980 pinfo2->defaultpriority = 0; 981 pinfo2->devmode = 568; // offset 982 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 983 devmode2 = (struct spoolss_DeviceMode *)(param->Buf 984 + pinfo2->devmode); 985 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 986 (void) smb_mbstowcs(((smb_wchar_t *) 987 (devmode2->devicename)), (const char *)poutbuf, 25); 988 devmode2->specversion = 0x0401; 989 devmode2->driverversion = 1024; 990 devmode2->size = 220; 991 devmode2->driverextra_length = 0; 992 devmode2->fields = 0x00014713; 993 devmode2->orientation = 1; 994 devmode2->papersize = 1; 995 devmode2->paperlength = 0; 996 devmode2->paperwidth = 0; 997 devmode2->scale = 100; 998 devmode2->copies = 1; 999 devmode2->defaultsource = 15; 1000 devmode2->printquality = 65532; 1001 devmode2->color = 1; 1002 devmode2->duplex = 1; 1003 devmode2->yresolution = 1; 1004 devmode2->ttoption = 1; 1005 devmode2->collate = 0; 1006 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1007 (void) smb_mbstowcs(((smb_wchar_t *) 1008 (devmode2->formname)), (const char *)"Letter", 6); 1009 devmode2->logpixels = 0; 1010 devmode2->bitsperpel = 0; 1011 devmode2->pelswidth = 0; 1012 devmode2->pelsheight = 0; 1013 devmode2->displayflags = 0; 1014 devmode2->displayfrequency = 0; 1015 devmode2->icmmethod = 0; 1016 devmode2->icmintent = 0; 1017 devmode2->mediatype = 0; 1018 devmode2->dithertype = 0; 1019 devmode2->reserved1 = 0; 1020 devmode2->reserved2 = 0; 1021 devmode2->panningwidth = 0; 1022 devmode2->panningheight = 0; 1023 1024 pinfo2->secdesc = 84; 1025 tmpbuf = (uint8_t *)(pinfo2->secdesc + (uint8_t *)param->Buf); 1026 error = spoolss_s_make_sd(tmpbuf); 1027 param->needed = 712; 1028 break; 1029 1030 default: 1031 syslog(LOG_NOTICE, "spoolss_s_GetPrinter: INVALID_LEVEL"); 1032 status = ERROR_INVALID_LEVEL; 1033 break; 1034 1035 } 1036 error_out: 1037 param->status = status; 1038 return (NDR_DRC_OK); 1039 } 1040 1041 int 1042 spoolss_s_make_sd(uint8_t *sd_buf) 1043 { 1044 smb_sd_t sd; 1045 uint32_t status; 1046 1047 bzero(&sd, sizeof (smb_sd_t)); 1048 1049 if ((status = spoolss_sd_format(&sd)) == ERROR_SUCCESS) { 1050 status = srvsvc_sd_set_relative(&sd, sd_buf); 1051 smb_sd_term(&sd); 1052 return (NDR_DRC_OK); 1053 } 1054 syslog(LOG_NOTICE, "spoolss_s_make_sd: error status=%d", status); 1055 smb_sd_term(&sd); 1056 return (NDR_DRC_OK); 1057 } 1058 1059 static uint32_t 1060 spoolss_sd_format(smb_sd_t *sd) 1061 { 1062 smb_fssd_t fs_sd; 1063 acl_t *acl; 1064 uint32_t status = ERROR_SUCCESS; 1065 1066 if (acl_fromtext("everyone@:full_set::allow", &acl) != 0) { 1067 syslog(LOG_ERR, "spoolss_sd_format: NOT_ENOUGH_MEMORY"); 1068 return (ERROR_NOT_ENOUGH_MEMORY); 1069 } 1070 smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); 1071 fs_sd.sd_uid = 0; 1072 fs_sd.sd_gid = 0; 1073 fs_sd.sd_zdacl = acl; 1074 fs_sd.sd_zsacl = NULL; 1075 1076 if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS) { 1077 syslog(LOG_NOTICE, "spoolss_sd_format: ACCESS_DENIED"); 1078 status = ERROR_ACCESS_DENIED; 1079 } 1080 smb_fssd_term(&fs_sd); 1081 return (status); 1082 } 1083 1084 /*ARGSUSED*/ 1085 static int 1086 spoolss_s_stub(void *arg, ndr_xa_t *mxa) 1087 { 1088 return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED); 1089 } 1090 1091 /*ARGSUSED*/ 1092 void 1093 fixup_spoolss_RFNPCNEX(struct spoolss_RFNPCNEX *val) 1094 { 1095 unsigned short size1 = 0; 1096 unsigned short size2 = 0; 1097 unsigned short size3 = 0; 1098 struct spoolss_RPC_V2_NOTIFY_INFO *pinfo; 1099 1100 pinfo = val->ppinfo->pinfo; 1101 switch (pinfo->aData->Reserved) { 1102 case TABLE_STRING: 1103 size1 = sizeof (struct STRING_CONTAINER); 1104 break; 1105 case TABLE_DWORD: 1106 size1 = sizeof (DWORD) * 2; 1107 break; 1108 case TABLE_TIME: 1109 size1 = sizeof (struct SYSTEMTIME_CONTAINER); 1110 break; 1111 case TABLE_DEVMODE: 1112 size1 = sizeof (struct spoolssDevmodeContainer); 1113 break; 1114 case TABLE_SECURITY_DESCRIPTOR: 1115 size1 = sizeof (struct SECURITY_CONTAINER); 1116 break; 1117 default: 1118 return; 1119 } 1120 size2 = size1 + (2 * sizeof (DWORD)); 1121 size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD); 1122 1123 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA, size1); 1124 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA, size2); 1125 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO, size3); 1126 FIXUP_PDU_SIZE(spoolss_RFNPCNEX, size3); 1127 } 1128 1129 void 1130 fixup_spoolss_GetPrinter(struct spoolss_GetPrinter *val) 1131 { 1132 unsigned short size1 = 0; 1133 unsigned short size2 = 0; 1134 unsigned short size3 = 0; 1135 1136 switch (val->switch_value) { 1137 CASE_INFO_ENT(spoolss_GetPrinter, 0); 1138 CASE_INFO_ENT(spoolss_GetPrinter, 1); 1139 CASE_INFO_ENT(spoolss_GetPrinter, 2); 1140 CASE_INFO_ENT(spoolss_GetPrinter, 3); 1141 CASE_INFO_ENT(spoolss_GetPrinter, 4); 1142 CASE_INFO_ENT(spoolss_GetPrinter, 5); 1143 CASE_INFO_ENT(spoolss_GetPrinter, 6); 1144 CASE_INFO_ENT(spoolss_GetPrinter, 7); 1145 CASE_INFO_ENT(spoolss_GetPrinter, 8); 1146 1147 default: 1148 return; 1149 }; 1150 1151 size2 = size1 + (2 * sizeof (DWORD)); 1152 size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD); 1153 1154 FIXUP_PDU_SIZE(spoolss_GetPrinter_result_u, size1); 1155 FIXUP_PDU_SIZE(spoolss_GetPrinter_result, size2); 1156 FIXUP_PDU_SIZE(spoolss_GetPrinter, size3); 1157 } 1158