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