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