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 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Printing and Spooling RPC service. 28 */ 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <sys/utsname.h> 32 #include <sys/atomic.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <strings.h> 36 #include <fcntl.h> 37 #include <errno.h> 38 #include <smbsrv/libsmb.h> 39 #include <smbsrv/libmlrpc.h> 40 #include <smbsrv/libmlsvc.h> 41 #include <smbsrv/smb.h> 42 #include <smbsrv/ndl/spoolss.ndl> 43 #include <smbsrv/ndl/winreg.ndl> 44 #include <smb/nterror.h> 45 #include <smbsrv/smbinfo.h> 46 #include <smbsrv/nmpipes.h> 47 #include <mlsvc.h> 48 49 #ifdef HAVE_CUPS 50 51 #define SPOOLSS_PRINTER "Postscript" 52 53 typedef struct smb_spool { 54 list_t sp_list; 55 int sp_cnt; 56 rwlock_t sp_rwl; 57 int sp_initialized; 58 } smb_spool_t; 59 60 typedef struct smb_spooldoc { 61 uint32_t sd_magic; 62 list_node_t sd_lnd; 63 smb_inaddr_t sd_ipaddr; 64 int sd_spool_num; 65 char sd_username[MAXNAMELEN]; 66 char sd_path[MAXPATHLEN]; 67 char sd_doc_name[MAXNAMELEN]; 68 char sd_printer_name[MAXPATHLEN]; 69 int32_t sd_fd; 70 ndr_hdid_t sd_handle; 71 } smb_spooldoc_t; 72 73 typedef struct { 74 char *name; 75 uint32_t value; 76 } spoolss_winreg_t; 77 78 typedef struct { 79 uint8_t *sd_buf; 80 uint32_t sd_size; 81 } spoolss_sd_t; 82 83 static uint32_t spoolss_cnt; 84 static smb_spool_t spoolss_splist; 85 86 void (*spoolss_copyfile_callback)(smb_inaddr_t *, char *, char *, char *); 87 88 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result_u); 89 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result); 90 DECL_FIXUP_STRUCT(spoolss_GetPrinter); 91 92 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA); 93 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA); 94 DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO); 95 DECL_FIXUP_STRUCT(spoolss_RFNPCNEX); 96 97 uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *); 98 static int spoolss_getservername(char *, size_t); 99 static uint32_t spoolss_make_sd(ndr_xa_t *, spoolss_sd_t *); 100 static uint32_t spoolss_format_sd(smb_sd_t *); 101 static int spoolss_find_document(ndr_hdid_t *); 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_AddForm(void *, ndr_xa_t *); 120 static int spoolss_s_DeleteForm(void *, ndr_xa_t *); 121 static int spoolss_s_EnumForms(void *, ndr_xa_t *); 122 static int spoolss_s_AddMonitor(void *, ndr_xa_t *); 123 static int spoolss_s_DeleteMonitor(void *, ndr_xa_t *); 124 static int spoolss_s_DeletePort(void *, ndr_xa_t *); 125 static int spoolss_s_AddPortEx(void *, ndr_xa_t *); 126 static int spoolss_s_SetPort(void *, ndr_xa_t *); 127 static int spoolss_s_stub(void *, ndr_xa_t *); 128 129 static ndr_stub_table_t spoolss_stub_table[] = { 130 { spoolss_s_GetJob, SPOOLSS_OPNUM_GetJob }, 131 { spoolss_s_EnumJobs, SPOOLSS_OPNUM_EnumJobs }, 132 { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinter }, 133 { spoolss_s_GetPrinter, SPOOLSS_OPNUM_GetPrinter }, 134 { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver }, 135 { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterDriver }, 136 { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinter }, 137 { spoolss_s_StartDocPrinter, SPOOLSS_OPNUM_StartDocPrinter }, 138 { spoolss_s_WritePrinter, SPOOLSS_OPNUM_WritePrinter }, 139 { spoolss_s_EndDocPrinter, SPOOLSS_OPNUM_EndDocPrinter }, 140 { spoolss_s_StartPagePrinter, SPOOLSS_OPNUM_StartPagePrinter }, 141 { spoolss_s_EndPagePrinter, SPOOLSS_OPNUM_EndPagePrinter }, 142 { spoolss_s_AbortPrinter, SPOOLSS_OPNUM_AbortPrinter }, 143 { spoolss_s_ResetPrinter, SPOOLSS_OPNUM_ResetPrinter }, 144 { spoolss_s_AddJob, SPOOLSS_OPNUM_AddJob }, 145 { spoolss_s_ScheduleJob, SPOOLSS_OPNUM_ScheduleJob }, 146 { spoolss_s_GetPrinterData, SPOOLSS_OPNUM_GetPrinterData }, 147 { spoolss_s_ClosePrinter, SPOOLSS_OPNUM_ClosePrinter }, 148 { spoolss_s_AddForm, SPOOLSS_OPNUM_AddForm }, 149 { spoolss_s_DeleteForm, SPOOLSS_OPNUM_DeleteForm }, 150 { spoolss_s_EnumForms, SPOOLSS_OPNUM_EnumForms }, 151 { spoolss_s_AddMonitor, SPOOLSS_OPNUM_AddMonitor }, 152 { spoolss_s_DeleteMonitor, SPOOLSS_OPNUM_DeleteMonitor }, 153 { spoolss_s_DeletePort, SPOOLSS_OPNUM_DeletePort }, 154 { spoolss_s_AddPortEx, SPOOLSS_OPNUM_AddPortEx }, 155 { spoolss_s_SetPort, SPOOLSS_OPNUM_SetPort }, 156 { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver2 }, 157 { spoolss_s_stub, SPOOLSS_OPNUM_FCPN }, 158 { spoolss_s_stub, SPOOLSS_OPNUM_ReplyOpenPrinter }, 159 { spoolss_s_stub, SPOOLSS_OPNUM_ReplyClosePrinter }, 160 { spoolss_s_stub, SPOOLSS_OPNUM_RFFPCNEX }, 161 { spoolss_s_rfnpcnex, SPOOLSS_OPNUM_RFNPCNEX }, 162 { spoolss_s_stub, SPOOLSS_OPNUM_RRPCN }, 163 { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinterEx }, 164 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterData }, 165 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterDataEx }, 166 { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterKey }, 167 {0} 168 }; 169 170 static ndr_service_t spoolss_service = { 171 "SPOOLSS", /* name */ 172 "Print Spool Service", /* desc */ 173 "\\spoolss", /* endpoint */ 174 PIPE_SPOOLSS, /* sec_addr_port */ 175 "12345678-1234-abcd-ef00-0123456789ab", 1, /* abstract */ 176 NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */ 177 0, /* no bind_instance_size */ 178 0, /* no bind_req() */ 179 0, /* no unbind_and_close() */ 180 0, /* use generic_call_stub() */ 181 &TYPEINFO(spoolss_interface), /* interface ti */ 182 spoolss_stub_table /* stub_table */ 183 }; 184 185 void 186 spoolss_initialize(void) 187 { 188 if (!spoolss_splist.sp_initialized) { 189 list_create(&spoolss_splist.sp_list, 190 sizeof (smb_spooldoc_t), 191 offsetof(smb_spooldoc_t, sd_lnd)); 192 spoolss_splist.sp_initialized = 1; 193 } 194 195 spoolss_copyfile_callback = NULL; 196 197 (void) ndr_svc_register(&spoolss_service); 198 } 199 200 void 201 spoolss_finalize(void) 202 { 203 spoolss_copyfile_callback = NULL; 204 } 205 206 /* 207 * Register a copyfile callback that the spoolss service can use to 208 * copy files to the spool directory. 209 * 210 * Set a null pointer to disable the copying of files to the spool 211 * directory. 212 */ 213 void 214 spoolss_register_copyfile(spoolss_copyfile_t copyfile) 215 { 216 spoolss_copyfile_callback = copyfile; 217 } 218 219 static void 220 spoolss_copyfile(smb_inaddr_t *ipaddr, char *username, char *path, 221 char *docname) 222 { 223 if (spoolss_copyfile_callback != NULL) 224 (*spoolss_copyfile_callback)(ipaddr, username, path, docname); 225 } 226 227 static int 228 spoolss_s_OpenPrinter(void *arg, ndr_xa_t *mxa) 229 { 230 struct spoolss_OpenPrinter *param = arg; 231 char *name = (char *)param->printer_name; 232 ndr_hdid_t *id; 233 234 if (name != NULL && *name != '\0') { 235 if (strspn(name, "\\") > 2) { 236 bzero(¶m->handle, sizeof (spoolss_handle_t)); 237 param->status = ERROR_INVALID_PRINTER_NAME; 238 return (NDR_DRC_OK); 239 } 240 241 smb_tracef("spoolss_s_OpenPrinter: %s", name); 242 } 243 244 if ((id = ndr_hdalloc(mxa, NULL)) == NULL) { 245 bzero(¶m->handle, sizeof (spoolss_handle_t)); 246 param->status = ERROR_NOT_ENOUGH_MEMORY; 247 return (NDR_DRC_OK); 248 } 249 250 bcopy(id, ¶m->handle, sizeof (spoolss_handle_t)); 251 param->status = 0; 252 return (NDR_DRC_OK); 253 } 254 255 /*ARGSUSED*/ 256 static int 257 spoolss_s_StartPagePrinter(void *arg, ndr_xa_t *mxa) 258 { 259 struct spoolss_StartPagePrinter *param = arg; 260 261 param->status = ERROR_SUCCESS; 262 263 return (NDR_DRC_OK); 264 } 265 266 /*ARGSUSED*/ 267 static int 268 spoolss_s_EndPagePrinter(void *arg, ndr_xa_t *mxa) 269 { 270 struct spoolss_EndPagePrinter *param = arg; 271 272 param->status = ERROR_SUCCESS; 273 274 return (NDR_DRC_OK); 275 } 276 277 /* 278 * Windows XP and 2000 use this mechanism to write spool files. 279 * Create a spool file fd to be used by spoolss_s_WritePrinter 280 * and add it to the tail of the spool list. 281 */ 282 static int 283 spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa) 284 { 285 struct spoolss_StartDocPrinter *param = arg; 286 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 287 smb_spooldoc_t *spfile; 288 spoolss_DocInfo_t *docinfo; 289 char g_path[MAXPATHLEN]; 290 smb_share_t si; 291 int rc; 292 int fd; 293 294 if (ndr_hdlookup(mxa, id) == NULL) { 295 smb_tracef("spoolss_s_StartDocPrinter: invalid handle"); 296 param->status = ERROR_INVALID_HANDLE; 297 return (NDR_DRC_OK); 298 } 299 300 if ((docinfo = param->dinfo.DocInfoContainer) == NULL) { 301 param->status = ERROR_INVALID_PARAMETER; 302 return (NDR_DRC_OK); 303 } 304 305 if ((rc = smb_shr_get(SMB_SHARE_PRINT, &si)) != NERR_Success) { 306 smb_tracef("spoolss_s_StartDocPrinter: %s error=%d", 307 SMB_SHARE_PRINT, rc); 308 param->status = rc; 309 return (NDR_DRC_OK); 310 } 311 312 if ((spfile = calloc(1, sizeof (smb_spooldoc_t))) == NULL) { 313 param->status = ERROR_NOT_ENOUGH_MEMORY; 314 return (NDR_DRC_OK); 315 } 316 317 if (docinfo->doc_name != NULL) 318 (void) strlcpy(spfile->sd_doc_name, 319 (char *)docinfo->doc_name, MAXNAMELEN); 320 else 321 (void) strlcpy(spfile->sd_doc_name, "document", MAXNAMELEN); 322 323 if (docinfo->printer_name != NULL) 324 (void) strlcpy(spfile->sd_printer_name, 325 (char *)docinfo->printer_name, MAXPATHLEN); 326 else 327 (void) strlcpy(spfile->sd_printer_name, "printer", MAXPATHLEN); 328 329 spfile->sd_ipaddr = mxa->pipe->np_user->ui_ipaddr; 330 (void) strlcpy((char *)spfile->sd_username, 331 mxa->pipe->np_user->ui_account, MAXNAMELEN); 332 (void) memcpy(&spfile->sd_handle, ¶m->handle, sizeof (ndr_hdid_t)); 333 334 /* 335 * write temporary spool file to print$ 336 */ 337 (void) snprintf(g_path, MAXPATHLEN, "%s/%s%d", si.shr_path, 338 spfile->sd_username, spoolss_cnt); 339 atomic_inc_32(&spoolss_cnt); 340 341 fd = open(g_path, O_CREAT | O_RDWR, 0600); 342 if (fd == -1) { 343 smb_tracef("spoolss_s_StartDocPrinter: %s: %s", 344 g_path, strerror(errno)); 345 param->status = ERROR_OPEN_FAILED; 346 free(spfile); 347 } else { 348 (void) strlcpy((char *)spfile->sd_path, g_path, MAXPATHLEN); 349 spfile->sd_fd = (uint16_t)fd; 350 351 /* 352 * Add the document to the spool list. 353 */ 354 (void) rw_wrlock(&spoolss_splist.sp_rwl); 355 list_insert_tail(&spoolss_splist.sp_list, spfile); 356 spoolss_splist.sp_cnt++; 357 (void) rw_unlock(&spoolss_splist.sp_rwl); 358 359 /* 360 * JobId isn't used now, but if printQ management is added 361 * this will have to be incremented per job submitted. 362 */ 363 param->JobId = 46; 364 param->status = ERROR_SUCCESS; 365 } 366 return (NDR_DRC_OK); 367 } 368 369 /* 370 * Windows XP and 2000 use this mechanism to write spool files 371 * Search the spooldoc list for a matching RPC handle and pass 372 * the spool the file for printing. 373 */ 374 static int 375 spoolss_s_EndDocPrinter(void *arg, ndr_xa_t *mxa) 376 { 377 struct spoolss_EndDocPrinter *param = arg; 378 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 379 smb_spooldoc_t *sp; 380 381 if (ndr_hdlookup(mxa, id) == NULL) { 382 smb_tracef("spoolss_s_EndDocPrinter: invalid handle"); 383 param->status = ERROR_INVALID_HANDLE; 384 return (NDR_DRC_OK); 385 } 386 387 param->status = ERROR_INVALID_HANDLE; 388 (void) rw_wrlock(&spoolss_splist.sp_rwl); 389 390 sp = list_head(&spoolss_splist.sp_list); 391 while (sp != NULL) { 392 if (!memcmp(id, &(sp->sd_handle), sizeof (ndr_hdid_t))) { 393 spoolss_copyfile(&sp->sd_ipaddr, 394 sp->sd_username, sp->sd_path, sp->sd_doc_name); 395 (void) close(sp->sd_fd); 396 list_remove(&spoolss_splist.sp_list, sp); 397 free(sp); 398 param->status = ERROR_SUCCESS; 399 break; 400 } 401 402 sp = list_next(&spoolss_splist.sp_list, sp); 403 } 404 405 (void) rw_unlock(&spoolss_splist.sp_rwl); 406 407 if (param->status != ERROR_SUCCESS) 408 smb_tracef("spoolss_s_EndDocPrinter: document not found"); 409 return (NDR_DRC_OK); 410 } 411 412 /*ARGSUSED*/ 413 static int 414 spoolss_s_AbortPrinter(void *arg, ndr_xa_t *mxa) 415 { 416 struct spoolss_AbortPrinter *param = arg; 417 418 param->status = ERROR_SUCCESS; 419 return (NDR_DRC_OK); 420 } 421 422 /*ARGSUSED*/ 423 static int 424 spoolss_s_ResetPrinter(void *arg, ndr_xa_t *mxa) 425 { 426 struct spoolss_AbortPrinter *param = arg; 427 428 param->status = ERROR_SUCCESS; 429 return (NDR_DRC_OK); 430 } 431 432 static int 433 spoolss_s_ClosePrinter(void *arg, ndr_xa_t *mxa) 434 { 435 struct spoolss_ClosePrinter *param = arg; 436 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 437 ndr_handle_t *hd; 438 439 if ((hd = ndr_hdlookup(mxa, id)) != NULL) { 440 free(hd->nh_data); 441 hd->nh_data = NULL; 442 } 443 444 ndr_hdfree(mxa, id); 445 bzero(¶m->result_handle, sizeof (spoolss_handle_t)); 446 param->status = ERROR_SUCCESS; 447 return (NDR_DRC_OK); 448 } 449 450 static int 451 spoolss_s_AddForm(void *arg, ndr_xa_t *mxa) 452 { 453 struct spoolss_AddForm *param = arg; 454 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 455 456 if (ndr_hdlookup(mxa, id) == NULL) { 457 bzero(param, sizeof (struct spoolss_AddForm)); 458 param->status = ERROR_INVALID_HANDLE; 459 return (NDR_DRC_OK); 460 } 461 462 bzero(param, sizeof (struct spoolss_AddForm)); 463 param->status = ERROR_SUCCESS; 464 return (NDR_DRC_OK); 465 } 466 467 static int 468 spoolss_s_DeleteForm(void *arg, ndr_xa_t *mxa) 469 { 470 struct spoolss_DeleteForm *param = arg; 471 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 472 473 if (ndr_hdlookup(mxa, id) == NULL) { 474 bzero(param, sizeof (struct spoolss_DeleteForm)); 475 param->status = ERROR_INVALID_HANDLE; 476 return (NDR_DRC_OK); 477 } 478 479 bzero(param, sizeof (struct spoolss_DeleteForm)); 480 param->status = ERROR_SUCCESS; 481 return (NDR_DRC_OK); 482 } 483 484 static int 485 spoolss_s_EnumForms(void *arg, ndr_xa_t *mxa) 486 { 487 struct spoolss_EnumForms *param = arg; 488 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 489 490 if (ndr_hdlookup(mxa, id) == NULL) { 491 bzero(param, sizeof (struct spoolss_EnumForms)); 492 param->status = ERROR_INVALID_HANDLE; 493 return (NDR_DRC_OK); 494 } 495 496 bzero(param, sizeof (struct spoolss_EnumForms)); 497 param->status = ERROR_SUCCESS; 498 param->needed = 0; 499 return (NDR_DRC_OK); 500 } 501 502 /*ARGSUSED*/ 503 static int 504 spoolss_s_AddMonitor(void *arg, ndr_xa_t *mxa) 505 { 506 struct spoolss_AddMonitor *param = arg; 507 508 param->status = ERROR_SUCCESS; 509 return (NDR_DRC_OK); 510 } 511 512 /*ARGSUSED*/ 513 static int 514 spoolss_s_DeleteMonitor(void *arg, ndr_xa_t *mxa) 515 { 516 struct spoolss_DeleteMonitor *param = arg; 517 518 param->status = ERROR_SUCCESS; 519 return (NDR_DRC_OK); 520 } 521 522 /*ARGSUSED*/ 523 static int 524 spoolss_s_DeletePort(void *arg, ndr_xa_t *mxa) 525 { 526 struct spoolss_DeletePort *param = arg; 527 528 param->status = ERROR_SUCCESS; 529 return (NDR_DRC_OK); 530 } 531 532 /*ARGSUSED*/ 533 static int 534 spoolss_s_AddPortEx(void *arg, ndr_xa_t *mxa) 535 { 536 struct spoolss_AddPortEx *param = arg; 537 538 param->status = ERROR_SUCCESS; 539 return (NDR_DRC_OK); 540 } 541 542 /*ARGSUSED*/ 543 static int 544 spoolss_s_SetPort(void *arg, ndr_xa_t *mxa) 545 { 546 struct spoolss_SetPort *param = arg; 547 548 param->status = ERROR_SUCCESS; 549 return (NDR_DRC_OK); 550 } 551 552 /*ARGSUSED*/ 553 static int 554 spoolss_s_EnumJobs(void *arg, ndr_xa_t *mxa) 555 { 556 struct spoolss_EnumJobs *param = arg; 557 DWORD status = ERROR_SUCCESS; 558 559 switch (param->level) { 560 case 1: 561 case 2: 562 case 3: 563 case 4: 564 default: 565 break; 566 } 567 568 param->status = status; 569 param->needed = 0; 570 param->needed2 = 0; 571 return (NDR_DRC_OK); 572 } 573 574 575 /*ARGSUSED*/ 576 static int 577 spoolss_s_GetJob(void *arg, ndr_xa_t *mxa) 578 { 579 struct spoolss_GetJob *param = arg; 580 DWORD status = ERROR_SUCCESS; 581 582 if (param->BufCount == 0) 583 param->status = ERROR_INSUFFICIENT_BUFFER; 584 else 585 param->status = status; 586 param->needed = 0; 587 return (NDR_DRC_OK); 588 } 589 590 591 /*ARGSUSED*/ 592 static int 593 spoolss_s_ScheduleJob(void *arg, ndr_xa_t *mxa) 594 { 595 struct spoolss_ScheduleJob *param = arg; 596 DWORD status = ERROR_SPL_NO_ADDJOB; 597 598 param->status = status; 599 return (NDR_DRC_OK); 600 } 601 602 /*ARGSUSED*/ 603 static int 604 spoolss_s_AddJob(void *arg, ndr_xa_t *mxa) 605 { 606 struct spoolss_AddJob *param = arg; 607 608 param->status = ERROR_SUCCESS; 609 param->needed = 0; 610 return (NDR_DRC_OK); 611 } 612 613 /*ARGSUSED*/ 614 static int 615 spoolss_s_rfnpcnex(void *arg, ndr_xa_t *mxa) 616 { 617 struct spoolss_RFNPCNEX *param = arg; 618 619 param->ppinfo = 0; 620 param->status = ERROR_SUCCESS; 621 return (NDR_DRC_OK); 622 } 623 624 /* 625 * Use the RPC context handle to find the fd and write the document content. 626 */ 627 static int 628 spoolss_s_WritePrinter(void *arg, ndr_xa_t *mxa) 629 { 630 struct spoolss_WritePrinter *param = arg; 631 int written = 0; 632 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 633 int spfd; 634 635 if (ndr_hdlookup(mxa, id) == NULL) { 636 param->written = 0; 637 param->status = ERROR_INVALID_HANDLE; 638 smb_tracef("spoolss_s_WritePrinter: invalid handle"); 639 return (NDR_DRC_OK); 640 } 641 642 if ((spfd = spoolss_find_document(id)) < 0) { 643 param->written = 0; 644 param->status = ERROR_INVALID_HANDLE; 645 smb_tracef("spoolss_s_WritePrinter: document not found"); 646 return (NDR_DRC_OK); 647 } 648 649 written = write(spfd, param->pBuf, param->BufCount); 650 if (written < param->BufCount) { 651 smb_tracef("spoolss_s_WritePrinter: write failed"); 652 param->written = 0; 653 param->status = ERROR_CANTWRITE; 654 return (NDR_DRC_OK); 655 } 656 657 param->written = written; 658 param->status = ERROR_SUCCESS; 659 return (NDR_DRC_OK); 660 } 661 662 /* 663 * Find a document by RPC handle in the spool list and return the fd. 664 */ 665 static int 666 spoolss_find_document(ndr_hdid_t *handle) 667 { 668 smb_spooldoc_t *sp; 669 670 (void) rw_rdlock(&spoolss_splist.sp_rwl); 671 672 sp = list_head(&spoolss_splist.sp_list); 673 while (sp != NULL) { 674 if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) { 675 (void) rw_unlock(&spoolss_splist.sp_rwl); 676 return (sp->sd_fd); 677 } 678 sp = list_next(&spoolss_splist.sp_list, sp); 679 } 680 681 (void) rw_unlock(&spoolss_splist.sp_rwl); 682 return (-1); 683 } 684 685 /* 686 * GetPrinterData is used t obtain values from the registry for a 687 * printer or a print server. See [MS-RPRN] for value descriptions. 688 * The registry returns ERROR_FILE_NOT_FOUND for unknown keys. 689 */ 690 static int 691 spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa) 692 { 693 static spoolss_winreg_t reg[] = { 694 { "ChangeId", 0x0050acf2 }, 695 { "W3SvcInstalled", 0x00000000 }, 696 { "BeepEnabled", 0x00000000 }, 697 { "EventLog", 0x0000001f }, 698 { "NetPopup", 0x00000000 }, 699 { "NetPopupToComputer", 0x00000000 }, 700 { "MajorVersion", 0x00000003 }, 701 { "MinorVersion", 0x00000000 }, 702 { "DsPresent", 0x00000000 } 703 }; 704 705 struct spoolss_GetPrinterData *param = arg; 706 char *name = (char *)param->pValueName; 707 char buf[MAXPATHLEN]; 708 static uint8_t reserved_buf[4]; 709 spoolss_winreg_t *rp; 710 smb_share_t si; 711 smb_version_t *osversion; 712 struct utsname sysname; 713 smb_wchar_t *wcs; 714 uint32_t value; 715 uint32_t status; 716 int wcslen; 717 int i; 718 719 if (name == NULL || *name == '\0') { 720 status = ERROR_FILE_NOT_FOUND; 721 goto report_error; 722 } 723 724 for (i = 0; i < sizeof (reg) / sizeof (reg[0]); ++i) { 725 param->pType = WINREG_DWORD; 726 param->Needed = sizeof (uint32_t); 727 rp = ®[i]; 728 729 if (strcasecmp(name, rp->name) != 0) 730 continue; 731 732 if (param->Size < sizeof (uint32_t)) { 733 param->Size = 0; 734 goto need_more_data; 735 } 736 737 if ((param->Buf = NDR_NEW(mxa, uint32_t)) == NULL) { 738 status = ERROR_NOT_ENOUGH_MEMORY; 739 goto report_error; 740 } 741 742 value = rp->value; 743 744 if ((strcasecmp(name, "DsPresent") == 0) && 745 (smb_config_get_secmode() == SMB_SECMODE_DOMAIN)) 746 value = 0x00000001; 747 748 bcopy(&value, param->Buf, sizeof (uint32_t)); 749 param->Size = sizeof (uint32_t); 750 param->status = ERROR_SUCCESS; 751 return (NDR_DRC_OK); 752 } 753 754 if (strcasecmp(name, "OSVersion") == 0) { 755 param->pType = WINREG_BINARY; 756 param->Needed = sizeof (smb_version_t); 757 758 if (param->Size < sizeof (smb_version_t)) { 759 param->Size = sizeof (smb_version_t); 760 goto need_more_data; 761 } 762 763 if ((osversion = NDR_NEW(mxa, smb_version_t)) == NULL) { 764 status = ERROR_NOT_ENOUGH_MEMORY; 765 goto report_error; 766 } 767 768 smb_config_get_version(osversion); 769 param->Buf = (uint8_t *)osversion; 770 param->status = ERROR_SUCCESS; 771 return (NDR_DRC_OK); 772 } 773 774 if (strcasecmp(name, "DNSMachineName") == 0) { 775 param->pType = WINREG_SZ; 776 buf[0] = '\0'; 777 (void) smb_getfqhostname(buf, MAXHOSTNAMELEN); 778 goto encode_string; 779 } 780 781 if (strcasecmp(name, "DefaultSpoolDirectory") == 0) { 782 param->pType = WINREG_SZ; 783 buf[0] = '\0'; 784 785 if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) { 786 status = ERROR_FILE_NOT_FOUND; 787 goto report_error; 788 } 789 790 (void) snprintf(buf, MAXPATHLEN, "C:/%s", si.shr_path); 791 (void) strcanon(buf, "/\\"); 792 (void) strsubst(buf, '/', '\\'); 793 goto encode_string; 794 } 795 796 if (strcasecmp(name, "Architecture") == 0) { 797 param->pType = WINREG_SZ; 798 799 if (uname(&sysname) < 0) 800 (void) strlcpy(buf, "Solaris", MAXPATHLEN); 801 else 802 (void) snprintf(buf, MAXPATHLEN, "%s %s", 803 sysname.sysname, sysname.machine); 804 805 goto encode_string; 806 } 807 808 status = ERROR_FILE_NOT_FOUND; 809 810 report_error: 811 bzero(param, sizeof (struct spoolss_GetPrinterData)); 812 param->Buf = reserved_buf; 813 param->status = status; 814 return (NDR_DRC_OK); 815 816 encode_string: 817 wcslen = smb_wcequiv_strlen(buf) + sizeof (smb_wchar_t); 818 if (param->Size < wcslen) { 819 param->Needed = wcslen; 820 goto need_more_data; 821 } 822 823 if ((wcs = NDR_MALLOC(mxa, wcslen)) == NULL) { 824 status = ERROR_NOT_ENOUGH_MEMORY; 825 goto report_error; 826 } 827 828 (void) ndr_mbstowcs(NULL, wcs, buf, wcslen); 829 param->Buf = (uint8_t *)wcs; 830 param->Needed = wcslen; 831 param->status = ERROR_SUCCESS; 832 return (NDR_DRC_OK); 833 834 need_more_data: 835 param->Size = 0; 836 param->Buf = reserved_buf; 837 param->status = ERROR_MORE_DATA; 838 return (NDR_DRC_OK); 839 } 840 841 void 842 smb_rpc_off(char *dst, char *src, uint32_t *offset, uint32_t *outoffset) 843 { 844 int nwchars; 845 int bytes; 846 847 bytes = smb_wcequiv_strlen(src) + 2; 848 nwchars = strlen(src) + 1; 849 *offset -= bytes; 850 *outoffset = *offset; 851 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 852 (void) smb_mbstowcs(((smb_wchar_t *)(dst + *offset)), src, nwchars); 853 } 854 855 int 856 spoolss_s_GetPrinter(void *arg, ndr_xa_t *mxa) 857 { 858 struct spoolss_GetPrinter *param = arg; 859 struct spoolss_GetPrinter0 *pinfo0; 860 struct spoolss_GetPrinter1 *pinfo1; 861 struct spoolss_GetPrinter2 *pinfo2; 862 struct spoolss_DeviceMode *devmode2; 863 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 864 spoolss_sd_t secdesc; 865 char server[MAXNAMELEN]; 866 char printer[MAXNAMELEN]; 867 DWORD status = ERROR_SUCCESS; 868 char *wname; 869 uint32_t offset; 870 uint8_t *tmpbuf; 871 872 if (ndr_hdlookup(mxa, id) == NULL) { 873 status = ERROR_INVALID_HANDLE; 874 goto error_out; 875 } 876 877 if (spoolss_getservername(server, MAXNAMELEN) != 0) { 878 status = ERROR_INTERNAL_ERROR; 879 goto error_out; 880 } 881 882 (void) snprintf(printer, MAXNAMELEN, "%s\\%s", server, SPOOLSS_PRINTER); 883 884 switch (param->switch_value) { 885 case 0: 886 case 1: 887 param->needed = 460; 888 break; 889 case 2: 890 param->needed = 712; 891 break; 892 default: 893 status = ERROR_INVALID_LEVEL; 894 goto error_out; 895 } 896 897 if (param->BufCount < param->needed) { 898 param->BufCount = 0; 899 param->Buf = NULL; 900 param->status = ERROR_INSUFFICIENT_BUFFER; 901 return (NDR_DRC_OK); 902 } 903 904 if ((param->Buf = NDR_MALLOC(mxa, param->BufCount)) == NULL) { 905 status = ERROR_NOT_ENOUGH_MEMORY; 906 goto error_out; 907 } 908 909 bzero(param->Buf, param->BufCount); 910 wname = (char *)param->Buf; 911 offset = param->needed; 912 913 switch (param->switch_value) { 914 case 0: 915 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 916 pinfo0 = (struct spoolss_GetPrinter0 *)param->Buf; 917 918 smb_rpc_off(wname, server, &offset, &pinfo0->servername); 919 smb_rpc_off(wname, printer, &offset, &pinfo0->printername); 920 pinfo0->cjobs = 0; 921 pinfo0->total_jobs = 6; 922 pinfo0->total_bytes = 1040771; 923 pinfo0->time0 = 0; 924 pinfo0->time1 = 0; 925 pinfo0->time2 = 3; 926 pinfo0->time3 = 0; 927 pinfo0->global_counter = 2162710; 928 pinfo0->total_pages = 21495865; 929 pinfo0->version = 10; 930 pinfo0->session_counter = 1; 931 pinfo0->job_error = 0x6; 932 pinfo0->change_id = 0x1; 933 pinfo0->status = 0; 934 pinfo0->c_setprinter = 0; 935 break; 936 case 1: 937 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 938 pinfo1 = (struct spoolss_GetPrinter1 *)param->Buf; 939 940 pinfo1->flags = PRINTER_ENUM_ICON8; 941 smb_rpc_off(wname, printer, &offset, &pinfo1->flags); 942 smb_rpc_off(wname, printer, &offset, &pinfo1->description); 943 smb_rpc_off(wname, printer, &offset, &pinfo1->comment); 944 break; 945 case 2: 946 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 947 pinfo2 = (struct spoolss_GetPrinter2 *)param->Buf; 948 949 smb_rpc_off(wname, server, &offset, &pinfo2->servername); 950 smb_rpc_off(wname, printer, &offset, &pinfo2->printername); 951 smb_rpc_off(wname, SPOOLSS_PRINTER, &offset, 952 &pinfo2->sharename); 953 smb_rpc_off(wname, "CIFS Printer Port", &offset, 954 &pinfo2->portname); 955 smb_rpc_off(wname, "", &offset, &pinfo2->drivername); 956 smb_rpc_off(wname, SPOOLSS_PRINTER, &offset, 957 &pinfo2->comment); 958 smb_rpc_off(wname, "farside", &offset, &pinfo2->location); 959 960 offset -= sizeof (struct spoolss_DeviceMode); 961 pinfo2->devmode = offset; 962 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 963 devmode2 = (struct spoolss_DeviceMode *)(param->Buf + offset); 964 965 smb_rpc_off(wname, "farside", &offset, &pinfo2->sepfile); 966 smb_rpc_off(wname, "winprint", &offset, 967 &pinfo2->printprocessor); 968 smb_rpc_off(wname, "RAW", &offset, &pinfo2->datatype); 969 smb_rpc_off(wname, "", &offset, &pinfo2->parameters); 970 971 status = spoolss_make_sd(mxa, &secdesc); 972 if (status == ERROR_SUCCESS) { 973 offset -= secdesc.sd_size; 974 pinfo2->secdesc = offset; 975 tmpbuf = (uint8_t *)(param->Buf + offset); 976 bcopy(secdesc.sd_buf, tmpbuf, secdesc.sd_size); 977 } 978 979 pinfo2->attributes = 0x00001048; 980 pinfo2->status = 0x00000000; 981 pinfo2->starttime = 0; 982 pinfo2->untiltime = 0; 983 pinfo2->cjobs = 0; 984 pinfo2->averageppm = 0; 985 pinfo2->defaultpriority = 0; 986 987 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 988 (void) smb_mbstowcs((smb_wchar_t *)devmode2->devicename, 989 printer, 32); 990 devmode2->specversion = 0x0401; 991 devmode2->driverversion = 1024; 992 devmode2->size = 220; 993 devmode2->driverextra_length = 0; 994 devmode2->fields = 0x00014713; 995 devmode2->orientation = 1; 996 devmode2->papersize = 1; 997 devmode2->paperlength = 0; 998 devmode2->paperwidth = 0; 999 devmode2->scale = 100; 1000 devmode2->copies = 1; 1001 devmode2->defaultsource = 15; 1002 devmode2->printquality = 65532; 1003 devmode2->color = 1; 1004 devmode2->duplex = 1; 1005 devmode2->yresolution = 1; 1006 devmode2->ttoption = 1; 1007 devmode2->collate = 0; 1008 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1009 (void) smb_mbstowcs((smb_wchar_t *)devmode2->formname, 1010 "Letter", 32); 1011 devmode2->logpixels = 0; 1012 devmode2->bitsperpel = 0; 1013 devmode2->pelswidth = 0; 1014 devmode2->pelsheight = 0; 1015 devmode2->displayflags = 0; 1016 devmode2->displayfrequency = 0; 1017 devmode2->icmmethod = 0; 1018 devmode2->icmintent = 0; 1019 devmode2->mediatype = 0; 1020 devmode2->dithertype = 0; 1021 devmode2->reserved1 = 0; 1022 devmode2->reserved2 = 0; 1023 devmode2->panningwidth = 0; 1024 devmode2->panningheight = 0; 1025 break; 1026 1027 default: 1028 break; 1029 } 1030 1031 param->status = status; 1032 return (NDR_DRC_OK); 1033 1034 error_out: 1035 smb_tracef("spoolss_s_GetPrinter: error %u", status); 1036 bzero(param, sizeof (struct spoolss_GetPrinter)); 1037 param->status = status; 1038 return (NDR_DRC_OK); 1039 } 1040 1041 static int 1042 spoolss_getservername(char *name, size_t namelen) 1043 { 1044 char hostname[MAXHOSTNAMELEN]; 1045 char ipstr[INET6_ADDRSTRLEN]; 1046 smb_inaddr_t ipaddr; 1047 struct hostent *h; 1048 const char *p; 1049 int error; 1050 1051 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0) { 1052 smb_tracef("spoolss_s_GetPrinter: gethostname failed"); 1053 return (-1); 1054 } 1055 1056 if ((h = smb_gethostbyname(hostname, &error)) == NULL) { 1057 smb_tracef("spoolss_s_GetPrinter: gethostbyname failed: %d", 1058 error); 1059 return (-1); 1060 } 1061 1062 bcopy(h->h_addr, &ipaddr, h->h_length); 1063 ipaddr.a_family = h->h_addrtype; 1064 freehostent(h); 1065 1066 p = smb_inet_ntop(&ipaddr, ipstr, SMB_IPSTRLEN(ipaddr.a_family)); 1067 if (p == NULL) { 1068 smb_tracef("spoolss_s_GetPrinter: inet_ntop failed"); 1069 return (-1); 1070 } 1071 1072 (void) snprintf(name, namelen, "\\\\%s", ipstr); 1073 return (0); 1074 } 1075 1076 static uint32_t 1077 spoolss_make_sd(ndr_xa_t *mxa, spoolss_sd_t *secdesc) 1078 { 1079 smb_sd_t sd; 1080 uint8_t *sd_buf; 1081 uint32_t sd_len; 1082 uint32_t status; 1083 1084 bzero(&sd, sizeof (smb_sd_t)); 1085 1086 if ((status = spoolss_format_sd(&sd)) != ERROR_SUCCESS) 1087 return (status); 1088 1089 sd_len = smb_sd_len(&sd, SMB_ALL_SECINFO); 1090 1091 if ((sd_buf = NDR_MALLOC(mxa, sd_len)) == NULL) 1092 return (ERROR_NOT_ENOUGH_MEMORY); 1093 1094 secdesc->sd_buf = sd_buf; 1095 secdesc->sd_size = sd_len; 1096 1097 status = srvsvc_sd_set_relative(&sd, sd_buf); 1098 smb_sd_term(&sd); 1099 return (status); 1100 } 1101 1102 static uint32_t 1103 spoolss_format_sd(smb_sd_t *sd) 1104 { 1105 smb_fssd_t fs_sd; 1106 acl_t *acl; 1107 uint32_t status = ERROR_SUCCESS; 1108 1109 if (acl_fromtext("everyone@:full_set::allow", &acl) != 0) { 1110 smb_tracef("spoolss_format_sd: NOT_ENOUGH_MEMORY"); 1111 return (ERROR_NOT_ENOUGH_MEMORY); 1112 } 1113 smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); 1114 fs_sd.sd_uid = 0; 1115 fs_sd.sd_gid = 0; 1116 fs_sd.sd_zdacl = acl; 1117 fs_sd.sd_zsacl = NULL; 1118 1119 status = smb_sd_fromfs(&fs_sd, sd); 1120 if (status != NT_STATUS_SUCCESS) { 1121 smb_tracef("spoolss_format_sd: %u", status); 1122 status = ERROR_ACCESS_DENIED; 1123 } 1124 smb_fssd_term(&fs_sd); 1125 return (status); 1126 } 1127 1128 /*ARGSUSED*/ 1129 static int 1130 spoolss_s_stub(void *arg, ndr_xa_t *mxa) 1131 { 1132 return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED); 1133 } 1134 1135 void 1136 fixup_spoolss_RFNPCNEX(struct spoolss_RFNPCNEX *val) 1137 { 1138 unsigned short size1 = 0; 1139 unsigned short size2 = 0; 1140 unsigned short size3 = 0; 1141 struct spoolss_RPC_V2_NOTIFY_INFO *pinfo; 1142 1143 pinfo = val->ppinfo->pinfo; 1144 switch (pinfo->aData->Reserved) { 1145 case TABLE_STRING: 1146 size1 = sizeof (struct STRING_CONTAINER); 1147 break; 1148 case TABLE_DWORD: 1149 size1 = sizeof (DWORD) * 2; 1150 break; 1151 case TABLE_TIME: 1152 size1 = sizeof (struct SYSTEMTIME_CONTAINER); 1153 break; 1154 case TABLE_DEVMODE: 1155 size1 = sizeof (struct spoolssDevmodeContainer); 1156 break; 1157 case TABLE_SECURITY_DESCRIPTOR: 1158 size1 = sizeof (struct SECURITY_CONTAINER); 1159 break; 1160 default: 1161 return; 1162 } 1163 size2 = size1 + (2 * sizeof (DWORD)); 1164 size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD); 1165 1166 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA, size1); 1167 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA, size2); 1168 FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO, size3); 1169 FIXUP_PDU_SIZE(spoolss_RFNPCNEX, size3); 1170 } 1171 1172 void 1173 fixup_spoolss_GetPrinter(struct spoolss_GetPrinter *val) 1174 { 1175 unsigned short size1 = 0; 1176 unsigned short size2 = 0; 1177 unsigned short size3 = 0; 1178 1179 switch (val->switch_value) { 1180 CASE_INFO_ENT(spoolss_GetPrinter, 0); 1181 CASE_INFO_ENT(spoolss_GetPrinter, 1); 1182 CASE_INFO_ENT(spoolss_GetPrinter, 2); 1183 CASE_INFO_ENT(spoolss_GetPrinter, 3); 1184 CASE_INFO_ENT(spoolss_GetPrinter, 4); 1185 CASE_INFO_ENT(spoolss_GetPrinter, 5); 1186 CASE_INFO_ENT(spoolss_GetPrinter, 6); 1187 CASE_INFO_ENT(spoolss_GetPrinter, 7); 1188 CASE_INFO_ENT(spoolss_GetPrinter, 8); 1189 1190 default: 1191 return; 1192 }; 1193 1194 size2 = size1 + (2 * sizeof (DWORD)); 1195 size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD); 1196 1197 FIXUP_PDU_SIZE(spoolss_GetPrinter_result_u, size1); 1198 FIXUP_PDU_SIZE(spoolss_GetPrinter_result, size2); 1199 FIXUP_PDU_SIZE(spoolss_GetPrinter, size3); 1200 } 1201 1202 #else /* HAVE_CUPS */ 1203 1204 /* 1205 * If not HAVE_CUPS, just provide a few "stubs". 1206 */ 1207 1208 void 1209 spoolss_initialize(void) 1210 { 1211 } 1212 1213 void 1214 spoolss_finalize(void) 1215 { 1216 } 1217 1218 /*ARGSUSED*/ 1219 void 1220 spoolss_register_copyfile(spoolss_copyfile_t copyfile) 1221 { 1222 } 1223 1224 #endif /* HAVE_CUPS */