📄 srv_spoolss_nt.c
字号:
/* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines * Copyright (C) Andrew Tridgell 1992-2000, * Copyright (C) Luke Kenneth Casson Leighton 1996-2000, * Copyright (C) Jean François Micouleau 1998-2000, * Copyright (C) Jeremy Allison 2001-2002, * Copyright (C) Gerald Carter 2000-2004, * Copyright (C) Tim Potter 2001-2002. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Since the SPOOLSS rpc routines are basically DOS 16-bit calls wrapped up, all the errors returned are DOS errors, not NT status codes. */#include "includes.h"extern userdom_struct current_user_info;#undef DBGC_CLASS#define DBGC_CLASS DBGC_RPC_SRV#ifndef MAX_OPEN_PRINTER_EXS#define MAX_OPEN_PRINTER_EXS 50#endif#define MAGIC_DISPLAY_FREQUENCY 0xfade2bad#define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_"/* Table to map the driver version *//* to OS */static const char * drv_ver_to_os[] = { "WIN9X", /* driver version/cversion 0 */ "", /* unused ? */ "WINNT", /* driver version/cversion 2 */ "WIN2K", /* driver version/cversion 3 */};static const char *get_drv_ver_to_os(int ver){ if (ver < 0 || ver > 3) return ""; return drv_ver_to_os[ver];}struct table_node { const char *long_archi; const char *short_archi; int version;};static Printer_entry *printers_list;typedef struct _counter_printer_0 { struct _counter_printer_0 *next; struct _counter_printer_0 *prev; int snum; uint32 counter;} counter_printer_0;static counter_printer_0 *counter_list;static struct rpc_pipe_client *notify_cli_pipe; /* print notify back-channel pipe handle*/static uint32 smb_connections=0;/* in printing/nt_printing.c */extern STANDARD_MAPPING printer_std_mapping, printserver_std_mapping;#define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())/* translate between internal status numbers and NT status numbers */static int nt_printj_status(int v){ switch (v) { case LPQ_QUEUED: return 0; case LPQ_PAUSED: return JOB_STATUS_PAUSED; case LPQ_SPOOLING: return JOB_STATUS_SPOOLING; case LPQ_PRINTING: return JOB_STATUS_PRINTING; case LPQ_ERROR: return JOB_STATUS_ERROR; case LPQ_DELETING: return JOB_STATUS_DELETING; case LPQ_OFFLINE: return JOB_STATUS_OFFLINE; case LPQ_PAPEROUT: return JOB_STATUS_PAPEROUT; case LPQ_PRINTED: return JOB_STATUS_PRINTED; case LPQ_DELETED: return JOB_STATUS_DELETED; case LPQ_BLOCKED: return JOB_STATUS_BLOCKED; case LPQ_USER_INTERVENTION: return JOB_STATUS_USER_INTERVENTION; } return 0;}static int nt_printq_status(int v){ switch (v) { case LPQ_PAUSED: return PRINTER_STATUS_PAUSED; case LPQ_QUEUED: case LPQ_SPOOLING: case LPQ_PRINTING: return 0; } return 0;}/**************************************************************************** Functions to handle SPOOL_NOTIFY_OPTION struct stored in Printer_entry.****************************************************************************/static void free_spool_notify_option(SPOOL_NOTIFY_OPTION **pp){ if (*pp == NULL) return; SAFE_FREE((*pp)->ctr.type); SAFE_FREE(*pp);}/*************************************************************************** Disconnect from the client****************************************************************************/static void srv_spoolss_replycloseprinter(int snum, POLICY_HND *handle){ WERROR result; /* * Tell the specific printing tdb we no longer want messages for this printer * by deregistering our PID. */ if (!print_notify_deregister_pid(snum)) DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", lp_const_servicename(snum) )); /* weird if the test succeds !!! */ if (smb_connections==0) { DEBUG(0,("srv_spoolss_replycloseprinter:Trying to close non-existant notify backchannel !\n")); return; } result = rpccli_spoolss_reply_close_printer(notify_cli_pipe, notify_cli_pipe->cli->mem_ctx, handle); if (!W_ERROR_IS_OK(result)) DEBUG(0,("srv_spoolss_replycloseprinter: reply_close_printer failed [%s].\n", dos_errstr(result))); /* if it's the last connection, deconnect the IPC$ share */ if (smb_connections==1) { cli_shutdown( notify_cli_pipe->cli ); notify_cli_pipe = NULL; /* The above call shuts downn the pipe also. */ message_deregister(MSG_PRINTER_NOTIFY2); /* Tell the connections db we're no longer interested in * printer notify messages. */ register_message_flags( False, FLAG_MSG_PRINT_NOTIFY ); } smb_connections--;}/**************************************************************************** Functions to free a printer entry datastruct.****************************************************************************/static void free_printer_entry(void *ptr){ Printer_entry *Printer = (Printer_entry *)ptr; if (Printer->notify.client_connected==True) { int snum = -1; if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) { snum = -1; srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd); } else if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTER) { snum = print_queue_snum(Printer->sharename); if (snum != -1) srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd); } } Printer->notify.flags=0; Printer->notify.options=0; Printer->notify.localmachine[0]='\0'; Printer->notify.printerlocal=0; free_spool_notify_option(&Printer->notify.option); Printer->notify.option=NULL; Printer->notify.client_connected=False; free_nt_devicemode( &Printer->nt_devmode ); free_a_printer( &Printer->printer_info, 2 ); talloc_destroy( Printer->ctx ); /* Remove from the internal list. */ DLIST_REMOVE(printers_list, Printer); SAFE_FREE(Printer);}/**************************************************************************** Functions to duplicate a SPOOL_NOTIFY_OPTION struct stored in Printer_entry.****************************************************************************/static SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp){ SPOOL_NOTIFY_OPTION *new_sp = NULL; if (!sp) return NULL; new_sp = SMB_MALLOC_P(SPOOL_NOTIFY_OPTION); if (!new_sp) return NULL; *new_sp = *sp; if (sp->ctr.count) { new_sp->ctr.type = (SPOOL_NOTIFY_OPTION_TYPE *)memdup(sp->ctr.type, sizeof(SPOOL_NOTIFY_OPTION_TYPE) * sp->ctr.count); if (!new_sp->ctr.type) { SAFE_FREE(new_sp); return NULL; } } return new_sp;}/**************************************************************************** find printer index by handle****************************************************************************/static Printer_entry *find_printer_index_by_hnd(pipes_struct *p, POLICY_HND *hnd){ Printer_entry *find_printer = NULL; if(!find_policy_by_hnd(p,hnd,(void **)(void *)&find_printer)) { DEBUG(2,("find_printer_index_by_hnd: Printer handle not found: ")); return NULL; } return find_printer;}/**************************************************************************** Close printer index by handle.****************************************************************************/static BOOL close_printer_handle(pipes_struct *p, POLICY_HND *hnd){ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd); if (!Printer) { DEBUG(2,("close_printer_handle: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd))); return False; } close_policy_hnd(p, hnd); return True;} /**************************************************************************** Delete a printer given a handle.****************************************************************************/WERROR delete_printer_hook( NT_USER_TOKEN *token, const char *sharename ){ char *cmd = lp_deleteprinter_cmd(); pstring command; int ret; SE_PRIV se_printop = SE_PRINT_OPERATOR; BOOL is_print_op = False; /* can't fail if we don't try */ if ( !*cmd ) return WERR_OK; pstr_sprintf(command, "%s \"%s\"", cmd, sharename); if ( token ) is_print_op = user_has_privileges( token, &se_printop ); DEBUG(10,("Running [%s]\n", command)); /********** BEGIN SePrintOperatorPrivlege BLOCK **********/ if ( is_print_op ) become_root(); if ( (ret = smbrun(command, NULL)) == 0 ) { /* Tell everyone we updated smb.conf. */ message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL); } if ( is_print_op ) unbecome_root(); /********** END SePrintOperatorPrivlege BLOCK **********/ DEBUGADD(10,("returned [%d]\n", ret)); if (ret != 0) return WERR_BADFID; /* What to return here? */ /* go ahead and re-read the services immediately */ reload_services( False ); if ( lp_servicenumber( sharename ) < 0 ) return WERR_ACCESS_DENIED; return WERR_OK;}/**************************************************************************** Delete a printer given a handle.****************************************************************************/static WERROR delete_printer_handle(pipes_struct *p, POLICY_HND *hnd){ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd); if (!Printer) { DEBUG(2,("delete_printer_handle: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd))); return WERR_BADFID; } /* * It turns out that Windows allows delete printer on a handle * opened by an admin user, then used on a pipe handle created * by an anonymous user..... but they're working on security.... riiight ! * JRA. */ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { DEBUG(3, ("delete_printer_handle: denied by handle\n")); return WERR_ACCESS_DENIED; } /* this does not need a become root since the access check has been done on the handle already */ if (del_a_printer( Printer->sharename ) != 0) { DEBUG(3,("Error deleting printer %s\n", Printer->sharename)); return WERR_BADFID; } return delete_printer_hook( p->pipe_user.nt_user_token, Printer->sharename );}/**************************************************************************** Return the snum of a printer corresponding to an handle.****************************************************************************/static BOOL get_printer_snum(pipes_struct *p, POLICY_HND *hnd, int *number){ Printer_entry *Printer = find_printer_index_by_hnd(p, hnd); if (!Printer) { DEBUG(2,("get_printer_snum: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd))); return False; } switch (Printer->printer_type) { case PRINTER_HANDLE_IS_PRINTER: DEBUG(4,("short name:%s\n", Printer->sharename)); *number = print_queue_snum(Printer->sharename); return (*number != -1); case PRINTER_HANDLE_IS_PRINTSERVER: return False; default: return False; }}/**************************************************************************** Set printer handle type. Check if it's \\server or \\server\printer****************************************************************************/static BOOL set_printer_hnd_printertype(Printer_entry *Printer, char *handlename){ DEBUG(3,("Setting printer type=%s\n", handlename)); if ( strlen(handlename) < 3 ) { DEBUGADD(4,("A print server must have at least 1 char ! %s\n", handlename)); return False; } /* it's a print server */ if (*handlename=='\\' && *(handlename+1)=='\\' && !strchr_m(handlename+2, '\\')) { DEBUGADD(4,("Printer is a print server\n")); Printer->printer_type = PRINTER_HANDLE_IS_PRINTSERVER; } /* it's a printer */ else { DEBUGADD(4,("Printer is a printer\n")); Printer->printer_type = PRINTER_HANDLE_IS_PRINTER; } return True;}/**************************************************************************** Set printer handle name.****************************************************************************/static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename){ int snum; int n_services=lp_numservices(); char *aprinter, *printername; const char *servername; fstring sname; BOOL found=False; NT_PRINTER_INFO_LEVEL *printer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -