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