📄 srv_spoolss_nt.c
字号:
*******************************************************************/static DEVICEMODE* dup_devicemode(TALLOC_CTX *ctx, DEVICEMODE *devmode){ DEVICEMODE *d; int len; if (!devmode) return NULL; DEBUG (8,("dup_devmode\n")); /* bulk copy first */ d = TALLOC_MEMDUP(ctx, devmode, sizeof(DEVICEMODE)); if (!d) return NULL; /* dup the pointer members separately */ len = unistrlen(devmode->devicename.buffer); if (len != -1) { d->devicename.buffer = TALLOC_ARRAY(ctx, uint16, len); if (unistrcpy(d->devicename.buffer, devmode->devicename.buffer) != len) return NULL; } len = unistrlen(devmode->formname.buffer); if (len != -1) { d->devicename.buffer = TALLOC_ARRAY(ctx, uint16, len); if (unistrcpy(d->formname.buffer, devmode->formname.buffer) != len) return NULL; } d->dev_private = TALLOC_MEMDUP(ctx, devmode->dev_private, devmode->driverextra); return d;}static void copy_devmode_ctr(TALLOC_CTX *ctx, DEVMODE_CTR *new_ctr, DEVMODE_CTR *ctr){ if (!new_ctr || !ctr) return; DEBUG(8,("copy_devmode_ctr\n")); new_ctr->size = ctr->size; new_ctr->devmode_ptr = ctr->devmode_ptr; if(ctr->devmode_ptr) new_ctr->devmode = dup_devicemode(ctx, ctr->devmode);}static void copy_printer_default(TALLOC_CTX *ctx, PRINTER_DEFAULT *new_def, PRINTER_DEFAULT *def){ if (!new_def || !def) return; DEBUG(8,("copy_printer_defaults\n")); new_def->datatype_ptr = def->datatype_ptr; if (def->datatype_ptr) copy_unistr2(&new_def->datatype, &def->datatype); copy_devmode_ctr(ctx, &new_def->devmode_cont, &def->devmode_cont); new_def->access_required = def->access_required;}/******************************************************************** * Convert a SPOOL_Q_OPEN_PRINTER structure to a * SPOOL_Q_OPEN_PRINTER_EX structure ********************************************************************/static WERROR convert_to_openprinterex(TALLOC_CTX *ctx, SPOOL_Q_OPEN_PRINTER_EX *q_u_ex, SPOOL_Q_OPEN_PRINTER *q_u){ if (!q_u_ex || !q_u) return WERR_OK; DEBUG(8,("convert_to_openprinterex\n")); if ( q_u->printername ) { q_u_ex->printername = TALLOC_ZERO_P( ctx, UNISTR2 ); if (q_u_ex->printername == NULL) return WERR_NOMEM; copy_unistr2(q_u_ex->printername, q_u->printername); } copy_printer_default(ctx, &q_u_ex->printer_default, &q_u->printer_default); return WERR_OK;}/******************************************************************** * spoolss_open_printer * * called from the spoolss dispatcher ********************************************************************/WERROR _spoolss_open_printer(pipes_struct *p, SPOOL_Q_OPEN_PRINTER *q_u, SPOOL_R_OPEN_PRINTER *r_u){ SPOOL_Q_OPEN_PRINTER_EX q_u_ex; SPOOL_R_OPEN_PRINTER_EX r_u_ex; if (!q_u || !r_u) return WERR_NOMEM; ZERO_STRUCT(q_u_ex); ZERO_STRUCT(r_u_ex); /* convert the OpenPrinter() call to OpenPrinterEx() */ r_u_ex.status = convert_to_openprinterex(p->mem_ctx, &q_u_ex, q_u); if (!W_ERROR_IS_OK(r_u_ex.status)) return r_u_ex.status; r_u_ex.status = _spoolss_open_printer_ex(p, &q_u_ex, &r_u_ex); /* convert back to OpenPrinter() */ memcpy(r_u, &r_u_ex, sizeof(*r_u)); return r_u->status;}/******************************************************************** * spoolss_open_printer * * If the openprinterex rpc call contains a devmode, * it's a per-user one. This per-user devmode is derivated * from the global devmode. Openprinterex() contains a per-user * devmode for when you do EMF printing and spooling. * In the EMF case, the NT workstation is only doing half the job * of rendering the page. The other half is done by running the printer * driver on the server. * The EMF file doesn't contain the page description (paper size, orientation, ...). * The EMF file only contains what is to be printed on the page. * So in order for the server to know how to print, the NT client sends * a devicemode attached to the openprinterex call. * But this devicemode is short lived, it's only valid for the current print job. * * If Samba would have supported EMF spooling, this devicemode would * have been attached to the handle, to sent it to the driver to correctly * rasterize the EMF file. * * As Samba only supports RAW spooling, we only receive a ready-to-print file, * we just act as a pass-thru between windows and the printer. * * In order to know that Samba supports only RAW spooling, NT has to call * getprinter() at level 2 (attribute field) or NT has to call startdoc() * and until NT sends a RAW job, we refuse it. * * But to call getprinter() or startdoc(), you first need a valid handle, * and to get an handle you have to call openprintex(). Hence why you have * a devicemode in the openprinterex() call. * * * Differences between NT4 and NT 2000. * NT4: * --- * On NT4, you only have a global devicemode. This global devicemode can be changed * by the administrator (or by a user with enough privs). Everytime a user * wants to print, the devicemode is resetted to the default. In Word, everytime * you print, the printer's characteristics are always reset to the global devicemode. * * NT 2000: * ------- * In W2K, there is the notion of per-user devicemode. The first time you use * a printer, a per-user devicemode is build from the global devicemode. * If you change your per-user devicemode, it is saved in the registry, under the * H_KEY_CURRENT_KEY sub_tree. So that everytime you print, you have your default * printer preferences available. * * To change the per-user devicemode: it's the "Printing Preferences ..." button * on the General Tab of the printer properties windows. * * To change the global devicemode: it's the "Printing Defaults..." button * on the Advanced Tab of the printer properties window. * * JFM. ********************************************************************/WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u){ PRINTER_DEFAULT *printer_default = &q_u->printer_default; POLICY_HND *handle = &r_u->handle; fstring name; int snum; struct current_user user; Printer_entry *Printer=NULL; if ( !q_u->printername ) return WERR_INVALID_PRINTER_NAME; /* some sanity check because you can open a printer or a print server */ /* aka: \\server\printer or \\server */ unistr2_to_ascii(name, q_u->printername, sizeof(name)-1); DEBUGADD(3,("checking name: %s\n",name)); if (!open_printer_hnd(p, handle, name, 0)) return WERR_INVALID_PRINTER_NAME; Printer=find_printer_index_by_hnd(p, handle); if ( !Printer ) { DEBUG(0,(" _spoolss_open_printer_ex: logic error. Can't find printer " "handle we created for printer %s\n", name )); close_printer_handle(p,handle); return WERR_INVALID_PRINTER_NAME; } get_current_user(&user, p); /* * First case: the user is opening the print server: * * Disallow MS AddPrinterWizard if parameter disables it. A Win2k * client 1st tries an OpenPrinterEx with access==0, MUST be allowed. * * Then both Win2k and WinNT clients try an OpenPrinterEx with * SERVER_ALL_ACCESS, which we allow only if the user is root (uid=0) * or if the user is listed in the smb.conf printer admin parameter. * * Then they try OpenPrinterEx with SERVER_READ which we allow. This lets the * client view printer folder, but does not show the MSAPW. * * Note: this test needs code to check access rights here too. Jeremy * could you look at this? * * Second case: the user is opening a printer: * NT doesn't let us connect to a printer if the connecting user * doesn't have print permission. */ if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) { /* Printserver handles use global struct... */ snum = -1; /* Map standard access rights to object specific access rights */ se_map_standard(&printer_default->access_required, &printserver_std_mapping); /* Deny any object specific bits that don't apply to print servers (i.e printer and job specific bits) */ printer_default->access_required &= SPECIFIC_RIGHTS_MASK; if (printer_default->access_required & ~(SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)) { DEBUG(3, ("access DENIED for non-printserver bits\n")); close_printer_handle(p, handle); return WERR_ACCESS_DENIED; } /* Allow admin access */ if ( printer_default->access_required & SERVER_ACCESS_ADMINISTER ) { SE_PRIV se_printop = SE_PRINT_OPERATOR; if (!lp_ms_add_printer_wizard()) { close_printer_handle(p, handle); return WERR_ACCESS_DENIED; } /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, and not a printer admin, then fail */ if ( user.uid != 0 && !user_has_privileges( user.nt_user_token, &se_printop ) && !user_in_list(uidtoname(user.uid), lp_printer_admin(snum), user.groups, user.ngroups) ) { close_printer_handle(p, handle); return WERR_ACCESS_DENIED; } printer_default->access_required = SERVER_ACCESS_ADMINISTER; } else { printer_default->access_required = SERVER_ACCESS_ENUMERATE; } DEBUG(4,("Setting print server access = %s\n", (printer_default->access_required == SERVER_ACCESS_ADMINISTER) ? "SERVER_ACCESS_ADMINISTER" : "SERVER_ACCESS_ENUMERATE" )); /* We fall through to return WERR_OK */ } else { /* NT doesn't let us connect to a printer if the connecting user doesn't have print permission. */ if (!get_printer_snum(p, handle, &snum)) { close_printer_handle(p, handle); return WERR_BADFID; } se_map_standard(&printer_default->access_required, &printer_std_mapping); /* map an empty access mask to the minimum access mask */ if (printer_default->access_required == 0x0) printer_default->access_required = PRINTER_ACCESS_USE; /* * If we are not serving the printer driver for this printer, * map PRINTER_ACCESS_ADMINISTER to PRINTER_ACCESS_USE. This * will keep NT clients happy --jerry */ if (lp_use_client_driver(snum) && (printer_default->access_required & PRINTER_ACCESS_ADMINISTER)) { printer_default->access_required = PRINTER_ACCESS_USE; } /* check smb.conf parameters and the the sec_desc */ if ( !check_access(smbd_server_fd(), lp_hostsallow(snum), lp_hostsdeny(snum)) ) { DEBUG(3, ("access DENIED (hosts allow/deny) for printer open\n")); return WERR_ACCESS_DENIED; } if (!user_ok(uidtoname(user.uid), snum, user.groups, user.ngroups) || !print_access_check(&user, snum, printer_default->access_required)) { DEBUG(3, ("access DENIED for printer open\n")); close_printer_handle(p, handle); return WERR_ACCESS_DENIED; } if ((printer_default->access_required & SPECIFIC_RIGHTS_MASK)& ~(PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE)) { DEBUG(3, ("access DENIED for printer open - unknown bits\n")); close_printer_handle(p, handle); return WERR_ACCESS_DENIED; } if (printer_default->access_required & PRINTER_ACCESS_ADMINISTER) printer_default->access_required = PRINTER_ACCESS_ADMINISTER; else printer_default->access_required = PRINTER_ACCESS_USE; DEBUG(4,("Setting printer access = %s\n", (printer_default->access_required == PRINTER_ACCESS_ADMINISTER) ? "PRINTER_ACCESS_ADMINISTER" : "PRINTER_ACCESS_USE" )); } Printer->access_granted = printer_default->access_required; /* * If the client sent a devmode in the OpenPrinter() call, then * save it here in case we get a job submission on this handle */ if ( (Printer->printer_type != PRINTER_HANDLE_IS_PRINTSERVER) && q_u->printer_default.devmode_cont.devmode_ptr ) { convert_devicemode( Printer->sharename, q_u->printer_default.devmode_cont.devmode, &Printer->nt_devmode ); }#if 0 /* JERRY -- I'm doubtful this is really effective */ /* HACK ALERT!!! Sleep for 1/3 of a second to try trigger a LAN/WAN optimization in Windows 2000 clients --jerry */ if ( (printer_default->access_required == PRINTER_ACCESS_ADMINISTER) && (RA_WIN2K == get_remote_arch()) ) { DEBUG(10,("_spoolss_open_printer_ex: Enabling LAN/WAN hack for Win2k clients.\n")); sys_usleep( 500000 ); }#endif return WERR_OK;}/********************************************************************************************************************************************************/static BOOL convert_printer_info(const SPOOL_PRINTER_INFO_LEVEL *uni, NT_PRINTER_INFO_LEVEL *printer, uint32 level){ BOOL ret; switch (level) { case 2: /* allocate memory if needed. Messy because convert_printer_info is used to update an existing printer or build a new one */ if ( !printer->info_2 ) { printer->info_2 = TALLOC_ZERO_P( printer, NT_PRINTER_INFO_LEVEL_2 ); if ( !printer->info_2 ) { DEBUG(0,("convert_printer_info: talloc() failed!\n")); return False; } } ret = uni_2_asc_printer_info_2(uni->info_2, printer->info_2); printer->info_2->setuptime = time(NULL); return ret; } return False;}static BOOL convert_printer_driver_info(const SPOOL_PRINTER_DRIVER_INFO_LEVEL *uni, NT_PRINTER_DRIVER_INFO_LEVEL *printer, uint32 level){ BOOL result = True; switch (level) { case 3: printer->info_3=NULL; if (!uni_2_asc_printer_driver_3(uni->info_3, &printer->info_3)) result = False; break; case 6: printer->info_6=NULL; if (!uni_2_asc_printer_driver_6(uni->info_6, &printer->info_6)) result = False; break; default: break; } return result;}BOOL convert_devicemode(const char *printername, const DEVICEMODE *devmode, NT_DEVICEMODE **pp_nt_devmode){ NT_DEVICEMODE *nt_devmode = *pp_nt_devmode; /* * Ensure nt_devmode is a valid pointer * as we will be overwriting it. */ if (nt_devmode == NULL) { DEBUG(5, ("convert_devicemode: allocating a generic devmode\n")); if ((nt_devmode = construct_nt_devicemode(printername)) == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -