rpc_server/srv_spoolss_nt.c

説明を見る。
00001 /*
00002  *  Unix SMB/CIFS implementation.
00003  *  RPC Pipe client / server routines
00004  *  Copyright (C) Andrew Tridgell              1992-2000,
00005  *  Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
00006  *  Copyright (C) Jean Fran巽ois Micouleau      1998-2000,
00007  *  Copyright (C) Jeremy Allison               2001-2002,
00008  *  Copyright (C) Gerald Carter                2000-2004,
00009  *  Copyright (C) Tim Potter                   2001-2002.
00010  *
00011  *  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program; if not, write to the Free Software
00023  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024  */
00025 
00026 /* Since the SPOOLSS rpc routines are basically DOS 16-bit calls wrapped
00027    up, all the errors returned are DOS errors, not NT status codes. */
00028 
00029 #include "includes.h"
00030 
00031 extern userdom_struct current_user_info;
00032 
00033 #undef DBGC_CLASS
00034 #define DBGC_CLASS DBGC_RPC_SRV
00035 
00036 #ifndef MAX_OPEN_PRINTER_EXS
00037 #define MAX_OPEN_PRINTER_EXS 50
00038 #endif
00039 
00040 #define MAGIC_DISPLAY_FREQUENCY 0xfade2bad
00041 #define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_"
00042 
00043 struct table_node {
00044         const char    *long_archi;
00045         const char    *short_archi;
00046         int     version;
00047 };
00048 
00049 static Printer_entry *printers_list;
00050 
00051 typedef struct _counter_printer_0 {
00052         struct _counter_printer_0 *next;
00053         struct _counter_printer_0 *prev;
00054         
00055         int snum;
00056         uint32 counter;
00057 } counter_printer_0;
00058 
00059 static counter_printer_0 *counter_list;
00060 
00061 static struct rpc_pipe_client *notify_cli_pipe; /* print notify back-channel pipe handle*/
00062 static uint32 smb_connections=0;
00063 
00064 
00065 /* in printing/nt_printing.c */
00066 
00067 extern STANDARD_MAPPING printer_std_mapping, printserver_std_mapping;
00068 
00069 /* API table for Xcv Monitor functions */
00070 
00071 struct xcv_api_table {
00072         const char *name;
00073         WERROR(*fn) (NT_USER_TOKEN *token, RPC_BUFFER *in, RPC_BUFFER *out, uint32 *needed);
00074 };
00075 
00076 /********************************************************************
00077  * Canonicalize servername.
00078  ********************************************************************/
00079 
00080 static const char *canon_servername(const char *servername)
00081 {
00082         const char *pservername = servername;
00083         while (*pservername == '\\') {
00084                 pservername++;
00085         }
00086         return pservername;
00087 }
00088 
00089 /* translate between internal status numbers and NT status numbers */
00090 static int nt_printj_status(int v)
00091 {
00092         switch (v) {
00093         case LPQ_QUEUED:
00094                 return 0;
00095         case LPQ_PAUSED:
00096                 return JOB_STATUS_PAUSED;
00097         case LPQ_SPOOLING:
00098                 return JOB_STATUS_SPOOLING;
00099         case LPQ_PRINTING:
00100                 return JOB_STATUS_PRINTING;
00101         case LPQ_ERROR:
00102                 return JOB_STATUS_ERROR;
00103         case LPQ_DELETING:
00104                 return JOB_STATUS_DELETING;
00105         case LPQ_OFFLINE:
00106                 return JOB_STATUS_OFFLINE;
00107         case LPQ_PAPEROUT:
00108                 return JOB_STATUS_PAPEROUT;
00109         case LPQ_PRINTED:
00110                 return JOB_STATUS_PRINTED;
00111         case LPQ_DELETED:
00112                 return JOB_STATUS_DELETED;
00113         case LPQ_BLOCKED:
00114                 return JOB_STATUS_BLOCKED;
00115         case LPQ_USER_INTERVENTION:
00116                 return JOB_STATUS_USER_INTERVENTION;
00117         }
00118         return 0;
00119 }
00120 
00121 static int nt_printq_status(int v)
00122 {
00123         switch (v) {
00124         case LPQ_PAUSED:
00125                 return PRINTER_STATUS_PAUSED;
00126         case LPQ_QUEUED:
00127         case LPQ_SPOOLING:
00128         case LPQ_PRINTING:
00129                 return 0;
00130         }
00131         return 0;
00132 }
00133 
00134 /****************************************************************************
00135  Functions to handle SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
00136 ****************************************************************************/
00137 
00138 static void free_spool_notify_option(SPOOL_NOTIFY_OPTION **pp)
00139 {
00140         if (*pp == NULL)
00141                 return;
00142 
00143         SAFE_FREE((*pp)->ctr.type);
00144         SAFE_FREE(*pp);
00145 }
00146 
00147 /***************************************************************************
00148  Disconnect from the client
00149 ****************************************************************************/
00150 
00151 static void srv_spoolss_replycloseprinter(int snum, POLICY_HND *handle)
00152 {
00153         WERROR result;
00154 
00155         /* 
00156          * Tell the specific printing tdb we no longer want messages for this printer
00157          * by deregistering our PID.
00158          */
00159 
00160         if (!print_notify_deregister_pid(snum))
00161                 DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", lp_const_servicename(snum) ));
00162 
00163         /* weird if the test succeds !!! */
00164         if (smb_connections==0) {
00165                 DEBUG(0,("srv_spoolss_replycloseprinter:Trying to close non-existant notify backchannel !\n"));
00166                 return;
00167         }
00168 
00169         result = rpccli_spoolss_reply_close_printer(notify_cli_pipe, notify_cli_pipe->cli->mem_ctx, handle);
00170         
00171         if (!W_ERROR_IS_OK(result))
00172                 DEBUG(0,("srv_spoolss_replycloseprinter: reply_close_printer failed [%s].\n",
00173                         dos_errstr(result)));
00174 
00175         /* if it's the last connection, deconnect the IPC$ share */
00176         if (smb_connections==1) {
00177 
00178                 cli_shutdown( notify_cli_pipe->cli );
00179                 notify_cli_pipe = NULL; /* The above call shuts downn the pipe also. */
00180 
00181                 message_deregister(MSG_PRINTER_NOTIFY2);
00182 
00183                 /* Tell the connections db we're no longer interested in
00184                  * printer notify messages. */
00185 
00186                 register_message_flags( False, FLAG_MSG_PRINT_NOTIFY );
00187         }
00188 
00189         smb_connections--;
00190 }
00191 
00192 /****************************************************************************
00193  Functions to free a printer entry datastruct.
00194 ****************************************************************************/
00195 
00196 static void free_printer_entry(void *ptr)
00197 {
00198         Printer_entry *Printer = (Printer_entry *)ptr;
00199 
00200         if (Printer->notify.client_connected==True) {
00201                 int snum = -1;
00202 
00203                 if ( Printer->printer_type == SPLHND_SERVER) {
00204                         snum = -1;
00205                         srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd);
00206                 } else if (Printer->printer_type == SPLHND_PRINTER) {
00207                         snum = print_queue_snum(Printer->sharename);
00208                         if (snum != -1)
00209                                 srv_spoolss_replycloseprinter(snum,
00210                                                 &Printer->notify.client_hnd);
00211                 }
00212         }
00213 
00214         Printer->notify.flags=0;
00215         Printer->notify.options=0;
00216         Printer->notify.localmachine[0]='\0';
00217         Printer->notify.printerlocal=0;
00218         free_spool_notify_option(&Printer->notify.option);
00219         Printer->notify.option=NULL;
00220         Printer->notify.client_connected=False;
00221         
00222         free_nt_devicemode( &Printer->nt_devmode );
00223         free_a_printer( &Printer->printer_info, 2 );
00224         
00225         talloc_destroy( Printer->ctx );
00226 
00227         /* Remove from the internal list. */
00228         DLIST_REMOVE(printers_list, Printer);
00229 
00230         SAFE_FREE(Printer);
00231 }
00232 
00233 /****************************************************************************
00234  Functions to duplicate a SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
00235 ****************************************************************************/
00236 
00237 static SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
00238 {
00239         SPOOL_NOTIFY_OPTION *new_sp = NULL;
00240 
00241         if (!sp)
00242                 return NULL;
00243 
00244         new_sp = SMB_MALLOC_P(SPOOL_NOTIFY_OPTION);
00245         if (!new_sp)
00246                 return NULL;
00247 
00248         *new_sp = *sp;
00249 
00250         if (sp->ctr.count) {
00251                 new_sp->ctr.type = (SPOOL_NOTIFY_OPTION_TYPE *)memdup(sp->ctr.type, sizeof(SPOOL_NOTIFY_OPTION_TYPE) * sp->ctr.count);
00252 
00253                 if (!new_sp->ctr.type) {
00254                         SAFE_FREE(new_sp);
00255                         return NULL;
00256                 }
00257         }
00258 
00259         return new_sp;
00260 }
00261 
00262 /****************************************************************************
00263   find printer index by handle
00264 ****************************************************************************/
00265 
00266 static Printer_entry *find_printer_index_by_hnd(pipes_struct *p, POLICY_HND *hnd)
00267 {
00268         Printer_entry *find_printer = NULL;
00269 
00270         if(!find_policy_by_hnd(p,hnd,(void **)(void *)&find_printer)) {
00271                 DEBUG(2,("find_printer_index_by_hnd: Printer handle not found: "));
00272                 return NULL;
00273         }
00274 
00275         return find_printer;
00276 }
00277 
00278 /****************************************************************************
00279  Close printer index by handle.
00280 ****************************************************************************/
00281 
00282 static BOOL close_printer_handle(pipes_struct *p, POLICY_HND *hnd)
00283 {
00284         Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
00285 
00286         if (!Printer) {
00287                 DEBUG(2,("close_printer_handle: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
00288                 return False;
00289         }
00290 
00291         close_policy_hnd(p, hnd);
00292 
00293         return True;
00294 }       
00295 
00296 /****************************************************************************
00297  Delete a printer given a handle.
00298 ****************************************************************************/
00299 WERROR delete_printer_hook( NT_USER_TOKEN *token, const char *sharename )
00300 {
00301         char *cmd = lp_deleteprinter_cmd();
00302         pstring command;
00303         int ret;
00304         SE_PRIV se_printop = SE_PRINT_OPERATOR;
00305         BOOL is_print_op = False;
00306                 
00307         /* can't fail if we don't try */
00308         
00309         if ( !*cmd )
00310                 return WERR_OK;
00311                 
00312         pstr_sprintf(command, "%s \"%s\"", cmd, sharename);
00313 
00314         if ( token )
00315                 is_print_op = user_has_privileges( token, &se_printop );
00316         
00317         DEBUG(10,("Running [%s]\n", command));
00318 
00319         /********** BEGIN SePrintOperatorPrivlege BLOCK **********/
00320         
00321         if ( is_print_op )
00322                 become_root();
00323                 
00324         if ( (ret = smbrun(command, NULL)) == 0 ) {
00325                 /* Tell everyone we updated smb.conf. */
00326                 message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
00327         }
00328                 
00329         if ( is_print_op )
00330                 unbecome_root();
00331 
00332         /********** END SePrintOperatorPrivlege BLOCK **********/
00333         
00334         DEBUGADD(10,("returned [%d]\n", ret));
00335 
00336         if (ret != 0) 
00337                 return WERR_BADFID; /* What to return here? */
00338 
00339         /* go ahead and re-read the services immediately */
00340         reload_services( False );
00341         
00342         if ( lp_servicenumber( sharename )  < 0 )
00343                 return WERR_ACCESS_DENIED;
00344                 
00345         return WERR_OK;
00346 }
00347 
00348 /****************************************************************************
00349  Delete a printer given a handle.
00350 ****************************************************************************/
00351 
00352 static WERROR delete_printer_handle(pipes_struct *p, POLICY_HND *hnd)
00353 {
00354         Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
00355 
00356         if (!Printer) {
00357                 DEBUG(2,("delete_printer_handle: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
00358                 return WERR_BADFID;
00359         }
00360 
00361         /* 
00362          * It turns out that Windows allows delete printer on a handle
00363          * opened by an admin user, then used on a pipe handle created
00364          * by an anonymous user..... but they're working on security.... riiight !
00365          * JRA.
00366          */
00367 
00368         if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
00369                 DEBUG(3, ("delete_printer_handle: denied by handle\n"));
00370                 return WERR_ACCESS_DENIED;
00371         }
00372         
00373         /* this does not need a become root since the access check has been 
00374            done on the handle already */
00375            
00376         if (del_a_printer( Printer->sharename ) != 0) {
00377                 DEBUG(3,("Error deleting printer %s\n", Printer->sharename));
00378                 return WERR_BADFID;
00379         }
00380 
00381         return delete_printer_hook( p->pipe_user.nt_user_token, Printer->sharename );
00382 }
00383 
00384 /****************************************************************************
00385  Return the snum of a printer corresponding to an handle.
00386 ****************************************************************************/
00387 
00388 static BOOL get_printer_snum(pipes_struct *p, POLICY_HND *hnd, int *number)
00389 {
00390         Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
00391                 
00392         if (!Printer) {
00393                 DEBUG(2,("get_printer_snum: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
00394                 return False;
00395         }
00396         
00397         switch (Printer->printer_type) {
00398                 case SPLHND_PRINTER:            
00399                         DEBUG(4,("short name:%s\n", Printer->sharename));                       
00400                         *number = print_queue_snum(Printer->sharename);
00401                         return (*number != -1);
00402                 case SPLHND_SERVER:
00403                         return False;
00404                 default:
00405                         return False;
00406         }
00407 }
00408 
00409 /****************************************************************************
00410  Set printer handle type.
00411  Check if it's \\server or \\server\printer
00412 ****************************************************************************/
00413 
00414 static BOOL set_printer_hnd_printertype(Printer_entry *Printer, char *handlename)
00415 {
00416         DEBUG(3,("Setting printer type=%s\n", handlename));
00417 
00418         if ( strlen(handlename) < 3 ) {
00419                 DEBUGADD(4,("A print server must have at least 1 char ! %s\n", handlename));
00420                 return False;
00421         }
00422 
00423         /* it's a print server */
00424         if (*handlename=='\\' && *(handlename+1)=='\\' && !strchr_m(handlename+2, '\\')) {
00425                 DEBUGADD(4,("Printer is a print server\n"));
00426                 Printer->printer_type = SPLHND_SERVER;          
00427         }
00428         /* it's a printer (set_printer_hnd_name() will handle port monitors */
00429         else {
00430                 DEBUGADD(4,("Printer is a printer\n"));
00431                 Printer->printer_type = SPLHND_PRINTER;
00432         }
00433 
00434         return True;
00435 }
00436 
00437 /****************************************************************************
00438  Set printer handle name..  Accept names like \\server, \\server\printer, 
00439  \\server\SHARE, & "\\server\,XcvMonitor Standard TCP/IP Port"    See
00440  the MSDN docs regarding OpenPrinter() for details on the XcvData() and 
00441  XcvDataPort() interface.
00442 ****************************************************************************/
00443 
00444 static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename)
00445 {
00446         int snum;
00447         int n_services=lp_numservices();
00448         char *aprinter, *printername;
00449         const char *servername;
00450         fstring sname;
00451         BOOL found=False;
00452         NT_PRINTER_INFO_LEVEL *printer = NULL;
00453         WERROR result;
00454         
00455         DEBUG(4,("Setting printer name=%s (len=%lu)\n", handlename, (unsigned long)strlen(handlename)));
00456 
00457         aprinter = handlename;
00458         if ( *handlename == '\\' ) {
00459                 servername = canon_servername(handlename);
00460                 if ( (aprinter = strchr_m( servername, '\\' )) != NULL ) {
00461                         *aprinter = '\0';
00462                         aprinter++;
00463                 }
00464         } else {
00465                 servername = "";
00466         }
00467         
00468         /* save the servername to fill in replies on this handle */
00469         
00470         if ( !is_myname_or_ipaddr( servername ) )
00471                 return False;
00472 
00473         fstrcpy( Printer->servername, servername );
00474         
00475         if ( Printer->printer_type == SPLHND_SERVER )
00476                 return True;
00477 
00478         if ( Printer->printer_type != SPLHND_PRINTER )
00479                 return False;
00480 
00481         DEBUGADD(5, ("searching for [%s]\n", aprinter ));
00482         
00483         /* check for the Port Monitor Interface */
00484         
00485         if ( strequal( aprinter, SPL_XCV_MONITOR_TCPMON ) ) {
00486                 Printer->printer_type = SPLHND_PORTMON_TCP;
00487                 fstrcpy(sname, SPL_XCV_MONITOR_TCPMON);
00488                 found = True;
00489         }
00490         else if ( strequal( aprinter, SPL_XCV_MONITOR_LOCALMON ) ) {
00491                 Printer->printer_type = SPLHND_PORTMON_LOCAL;
00492                 fstrcpy(sname, SPL_XCV_MONITOR_LOCALMON);
00493                 found = True;
00494         }
00495 
00496         /* Search all sharenames first as this is easier than pulling 
00497            the printer_info_2 off of disk. Don't use find_service() since
00498            that calls out to map_username() */
00499         
00500         /* do another loop to look for printernames */
00501         
00502         for (snum=0; !found && snum<n_services; snum++) {
00503 
00504                 /* no point going on if this is not a printer */
00505 
00506                 if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
00507                         continue;
00508 
00509                 fstrcpy(sname, lp_servicename(snum));
00510                 if ( strequal( aprinter, sname ) ) {
00511                         found = True;
00512                         break;
00513                 }
00514 
00515                 /* no point looking up the printer object if
00516                    we aren't allowing printername != sharename */
00517                 
00518                 if ( lp_force_printername(snum) )
00519                         continue;
00520 
00521                 fstrcpy(sname, lp_servicename(snum));
00522 
00523                 printer = NULL;
00524 
00525                 /* This call doesn't fill in the location or comment from
00526                  * a CUPS server for efficiency with large numbers of printers.
00527                  * JRA.
00528                  */
00529                 result = get_a_printer_search( NULL, &printer, 2, sname );
00530                 if ( !W_ERROR_IS_OK(result) ) {
00531                         DEBUG(0,("set_printer_hnd_name: failed to lookup printer [%s] -- result [%s]\n",
00532                                 sname, dos_errstr(result)));
00533                         continue;
00534                 }
00535                 
00536                 /* printername is always returned as \\server\printername */
00537                 if ( !(printername = strchr_m(&printer->info_2->printername[2], '\\')) ) {
00538                         DEBUG(0,("set_printer_hnd_name: info2->printername in wrong format! [%s]\n",
00539                                 printer->info_2->printername));
00540                         free_a_printer( &printer, 2);
00541                         continue;
00542                 }
00543                 
00544                 printername++;
00545                 
00546                 if ( strequal(printername, aprinter) ) {
00547                         free_a_printer( &printer, 2);
00548                         found = True;
00549                         break;
00550                 }
00551                 
00552                 DEBUGADD(10, ("printername: %s\n", printername));
00553                 
00554                 free_a_printer( &printer, 2);
00555         }
00556 
00557         free_a_printer( &printer, 2);
00558 
00559         if ( !found ) {
00560                 DEBUGADD(4,("Printer not found\n"));
00561                 return False;
00562         }
00563         
00564         DEBUGADD(4,("set_printer_hnd_name: Printer found: %s -> %s\n", aprinter, sname));
00565 
00566         fstrcpy(Printer->sharename, sname);
00567 
00568         return True;
00569 }
00570 
00571 /****************************************************************************
00572  Find first available printer slot. creates a printer handle for you.
00573  ****************************************************************************/
00574 
00575 static BOOL open_printer_hnd(pipes_struct *p, POLICY_HND *hnd, char *name, uint32 access_granted)
00576 {
00577         Printer_entry *new_printer;
00578 
00579         DEBUG(10,("open_printer_hnd: name [%s]\n", name));
00580 
00581         if((new_printer=SMB_MALLOC_P(Printer_entry)) == NULL)
00582                 return False;
00583 
00584         ZERO_STRUCTP(new_printer);
00585         
00586         if (!create_policy_hnd(p, hnd, free_printer_entry, new_printer)) {
00587                 SAFE_FREE(new_printer);
00588                 return False;
00589         }
00590         
00591         /* Add to the internal list. */
00592         DLIST_ADD(printers_list, new_printer);
00593         
00594         new_printer->notify.option=NULL;
00595                                 
00596         if ( !(new_printer->ctx = talloc_init("Printer Entry [%p]", hnd)) ) {
00597                 DEBUG(0,("open_printer_hnd: talloc_init() failed!\n"));
00598                 close_printer_handle(p, hnd);
00599                 return False;
00600         }
00601         
00602         if (!set_printer_hnd_printertype(new_printer, name)) {
00603                 close_printer_handle(p, hnd);
00604                 return False;
00605         }
00606         
00607         if (!set_printer_hnd_name(new_printer, name)) {
00608                 close_printer_handle(p, hnd);
00609                 return False;
00610         }
00611 
00612         new_printer->access_granted = access_granted;
00613 
00614         DEBUG(5, ("%d printer handles active\n", (int)p->pipe_handles->count ));
00615 
00616         return True;
00617 }
00618 
00619 /***************************************************************************
00620  check to see if the client motify handle is monitoring the notification
00621  given by (notify_type, notify_field).
00622  **************************************************************************/
00623 
00624 static BOOL is_monitoring_event_flags(uint32 flags, uint16 notify_type,
00625                                       uint16 notify_field)
00626 {
00627         return True;
00628 }
00629 
00630 static BOOL is_monitoring_event(Printer_entry *p, uint16 notify_type,
00631                                 uint16 notify_field)
00632 {
00633         SPOOL_NOTIFY_OPTION *option = p->notify.option;
00634         uint32 i, j;
00635 
00636         /* 
00637          * Flags should always be zero when the change notify
00638          * is registered by the client's spooler.  A user Win32 app
00639          * might use the flags though instead of the NOTIFY_OPTION_INFO 
00640          * --jerry
00641          */
00642 
00643         if (!option) {
00644                 return False;
00645         }
00646 
00647         if (p->notify.flags)
00648                 return is_monitoring_event_flags(
00649                         p->notify.flags, notify_type, notify_field);
00650 
00651         for (i = 0; i < option->count; i++) {
00652                 
00653                 /* Check match for notify_type */
00654                 
00655                 if (option->ctr.type[i].type != notify_type)
00656                         continue;
00657 
00658                 /* Check match for field */
00659                 
00660                 for (j = 0; j < option->ctr.type[i].count; j++) {
00661                         if (option->ctr.type[i].fields[j] == notify_field) {
00662                                 return True;
00663                         }
00664                 }
00665         }
00666         
00667         DEBUG(10, ("Open handle for \\\\%s\\%s is not monitoring 0x%02x/0x%02x\n",
00668                    p->servername, p->sharename, notify_type, notify_field));
00669         
00670         return False;
00671 }
00672 
00673 /* Convert a notification message to a SPOOL_NOTIFY_INFO_DATA struct */
00674 
00675 static void notify_one_value(struct spoolss_notify_msg *msg,
00676                              SPOOL_NOTIFY_INFO_DATA *data,
00677                              TALLOC_CTX *mem_ctx)
00678 {
00679         data->notify_data.value[0] = msg->notify.value[0];
00680         data->notify_data.value[1] = 0;
00681 }
00682 
00683 static void notify_string(struct spoolss_notify_msg *msg,
00684                           SPOOL_NOTIFY_INFO_DATA *data,
00685                           TALLOC_CTX *mem_ctx)
00686 {
00687         UNISTR2 unistr;
00688         
00689         /* The length of the message includes the trailing \0 */
00690 
00691         init_unistr2(&unistr, msg->notify.data, UNI_STR_TERMINATE);
00692 
00693         data->notify_data.data.length = msg->len * 2;
00694         data->notify_data.data.string = TALLOC_ARRAY(mem_ctx, uint16, msg->len);
00695 
00696         if (!data->notify_data.data.string) {
00697                 data->notify_data.data.length = 0;
00698                 return;
00699         }
00700         
00701         memcpy(data->notify_data.data.string, unistr.buffer, msg->len * 2);
00702 }
00703 
00704 static void notify_system_time(struct spoolss_notify_msg *msg,
00705                                SPOOL_NOTIFY_INFO_DATA *data,
00706                                TALLOC_CTX *mem_ctx)
00707 {
00708         SYSTEMTIME systime;
00709         prs_struct ps;
00710 
00711         if (msg->len != sizeof(time_t)) {
00712                 DEBUG(5, ("notify_system_time: received wrong sized message (%d)\n",
00713                           msg->len));
00714                 return;
00715         }
00716 
00717         if (!prs_init(&ps, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL)) {
00718                 DEBUG(5, ("notify_system_time: prs_init() failed\n"));
00719                 return;
00720         }
00721 
00722         if (!make_systemtime(&systime, gmtime((time_t *)msg->notify.data))) {
00723                 DEBUG(5, ("notify_system_time: unable to make systemtime\n"));
00724                 prs_mem_free(&ps);
00725                 return;
00726         }
00727 
00728         if (!spoolss_io_system_time("", &ps, 0, &systime)) {
00729                 prs_mem_free(&ps);
00730                 return;
00731         }
00732 
00733         data->notify_data.data.length = prs_offset(&ps);
00734         if (prs_offset(&ps)) {
00735                 data->notify_data.data.string = (uint16 *)
00736                         TALLOC(mem_ctx, prs_offset(&ps));
00737                 if (!data->notify_data.data.string) {
00738                         prs_mem_free(&ps);
00739                         return;
00740                 }
00741                 prs_copy_all_data_out((char *)data->notify_data.data.string, &ps);
00742         } else {
00743                 data->notify_data.data.string = NULL;
00744         }
00745 
00746         prs_mem_free(&ps);
00747 }
00748 
00749 struct notify2_message_table {
00750         const char *name;
00751         void (*fn)(struct spoolss_notify_msg *msg,
00752                    SPOOL_NOTIFY_INFO_DATA *data, TALLOC_CTX *mem_ctx);
00753 };
00754 
00755 static struct notify2_message_table printer_notify_table[] = {
00756         /* 0x00 */ { "PRINTER_NOTIFY_SERVER_NAME", notify_string },
00757         /* 0x01 */ { "PRINTER_NOTIFY_PRINTER_NAME", notify_string },
00758         /* 0x02 */ { "PRINTER_NOTIFY_SHARE_NAME", notify_string },
00759         /* 0x03 */ { "PRINTER_NOTIFY_PORT_NAME", notify_string },
00760         /* 0x04 */ { "PRINTER_NOTIFY_DRIVER_NAME", notify_string },
00761         /* 0x05 */ { "PRINTER_NOTIFY_COMMENT", notify_string },
00762         /* 0x06 */ { "PRINTER_NOTIFY_LOCATION", notify_string },
00763         /* 0x07 */ { "PRINTER_NOTIFY_DEVMODE", NULL },
00764         /* 0x08 */ { "PRINTER_NOTIFY_SEPFILE", notify_string },
00765         /* 0x09 */ { "PRINTER_NOTIFY_PRINT_PROCESSOR", notify_string },
00766         /* 0x0a */ { "PRINTER_NOTIFY_PARAMETERS", NULL },
00767         /* 0x0b */ { "PRINTER_NOTIFY_DATATYPE", notify_string },
00768         /* 0x0c */ { "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", NULL },
00769         /* 0x0d */ { "PRINTER_NOTIFY_ATTRIBUTES", notify_one_value },
00770         /* 0x0e */ { "PRINTER_NOTIFY_PRIORITY", notify_one_value },
00771         /* 0x0f */ { "PRINTER_NOTIFY_DEFAULT_PRIORITY", NULL },
00772         /* 0x10 */ { "PRINTER_NOTIFY_START_TIME", NULL },
00773         /* 0x11 */ { "PRINTER_NOTIFY_UNTIL_TIME", NULL },
00774         /* 0x12 */ { "PRINTER_NOTIFY_STATUS", notify_one_value },
00775 };
00776 
00777 static struct notify2_message_table job_notify_table[] = {
00778         /* 0x00 */ { "JOB_NOTIFY_PRINTER_NAME", NULL },
00779         /* 0x01 */ { "JOB_NOTIFY_MACHINE_NAME", NULL },
00780         /* 0x02 */ { "JOB_NOTIFY_PORT_NAME", NULL },
00781         /* 0x03 */ { "JOB_NOTIFY_USER_NAME", notify_string },
00782         /* 0x04 */ { "JOB_NOTIFY_NOTIFY_NAME", NULL },
00783         /* 0x05 */ { "JOB_NOTIFY_DATATYPE", NULL },
00784         /* 0x06 */ { "JOB_NOTIFY_PRINT_PROCESSOR", NULL },
00785         /* 0x07 */ { "JOB_NOTIFY_PARAMETERS", NULL },
00786         /* 0x08 */ { "JOB_NOTIFY_DRIVER_NAME", NULL },
00787         /* 0x09 */ { "JOB_NOTIFY_DEVMODE", NULL },
00788         /* 0x0a */ { "JOB_NOTIFY_STATUS", notify_one_value },
00789         /* 0x0b */ { "JOB_NOTIFY_STATUS_STRING", NULL },
00790         /* 0x0c */ { "JOB_NOTIFY_SECURITY_DESCRIPTOR", NULL },
00791         /* 0x0d */ { "JOB_NOTIFY_DOCUMENT", notify_string },
00792         /* 0x0e */ { "JOB_NOTIFY_PRIORITY", NULL },
00793         /* 0x0f */ { "JOB_NOTIFY_POSITION", NULL },
00794         /* 0x10 */ { "JOB_NOTIFY_SUBMITTED", notify_system_time },
00795         /* 0x11 */ { "JOB_NOTIFY_START_TIME", NULL },
00796         /* 0x12 */ { "JOB_NOTIFY_UNTIL_TIME", NULL },
00797         /* 0x13 */ { "JOB_NOTIFY_TIME", NULL },
00798         /* 0x14 */ { "JOB_NOTIFY_TOTAL_PAGES", notify_one_value },
00799         /* 0x15 */ { "JOB_NOTIFY_PAGES_PRINTED", NULL },
00800         /* 0x16 */ { "JOB_NOTIFY_TOTAL_BYTES", notify_one_value },
00801         /* 0x17 */ { "JOB_NOTIFY_BYTES_PRINTED", NULL },
00802 };
00803 
00804 
00805 /***********************************************************************
00806  Allocate talloc context for container object
00807  **********************************************************************/
00808  
00809 static void notify_msg_ctr_init( SPOOLSS_NOTIFY_MSG_CTR *ctr )
00810 {
00811         if ( !ctr )
00812                 return;
00813 
00814         ctr->ctx = talloc_init("notify_msg_ctr_init %p", ctr);
00815                 
00816         return;
00817 }
00818 
00819 /***********************************************************************
00820  release all allocated memory and zero out structure
00821  **********************************************************************/
00822  
00823 static void notify_msg_ctr_destroy( SPOOLSS_NOTIFY_MSG_CTR *ctr )
00824 {
00825         if ( !ctr )
00826                 return;
00827 
00828         if ( ctr->ctx )
00829                 talloc_destroy(ctr->ctx);
00830                 
00831         ZERO_STRUCTP(ctr);
00832                 
00833         return;
00834 }
00835 
00836 /***********************************************************************
00837  **********************************************************************/
00838  
00839 static TALLOC_CTX* notify_ctr_getctx( SPOOLSS_NOTIFY_MSG_CTR *ctr )
00840 {
00841         if ( !ctr )
00842                 return NULL;
00843                 
00844         return ctr->ctx;
00845 }
00846 
00847 /***********************************************************************
00848  **********************************************************************/
00849  
00850 static SPOOLSS_NOTIFY_MSG_GROUP* notify_ctr_getgroup( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
00851 {
00852         if ( !ctr || !ctr->msg_groups )
00853                 return NULL;
00854         
00855         if ( idx >= ctr->num_groups )
00856                 return NULL;
00857                 
00858         return &ctr->msg_groups[idx];
00859 
00860 }
00861 
00862 /***********************************************************************
00863  How many groups of change messages do we have ?
00864  **********************************************************************/
00865  
00866 static int notify_msg_ctr_numgroups( SPOOLSS_NOTIFY_MSG_CTR *ctr )
00867 {
00868         if ( !ctr )
00869                 return 0;
00870                 
00871         return ctr->num_groups;
00872 }
00873 
00874 /***********************************************************************
00875  Add a SPOOLSS_NOTIFY_MSG_CTR to the correct group
00876  **********************************************************************/
00877  
00878 static int notify_msg_ctr_addmsg( SPOOLSS_NOTIFY_MSG_CTR *ctr, SPOOLSS_NOTIFY_MSG *msg )
00879 {
00880         SPOOLSS_NOTIFY_MSG_GROUP        *groups = NULL;
00881         SPOOLSS_NOTIFY_MSG_GROUP        *msg_grp = NULL;
00882         SPOOLSS_NOTIFY_MSG              *msg_list = NULL;
00883         int                             i, new_slot;
00884         
00885         if ( !ctr || !msg )
00886                 return 0;
00887         
00888         /* loop over all groups looking for a matching printer name */
00889         
00890         for ( i=0; i<ctr->num_groups; i++ ) {
00891                 if ( strcmp(ctr->msg_groups[i].printername, msg->printer) == 0 )
00892                         break;
00893         }
00894         
00895         /* add a new group? */
00896         
00897         if ( i == ctr->num_groups ) {
00898                 ctr->num_groups++;
00899 
00900                 if ( !(groups = TALLOC_REALLOC_ARRAY( ctr->ctx, ctr->msg_groups, SPOOLSS_NOTIFY_MSG_GROUP, ctr->num_groups)) ) {
00901                         DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed!\n"));
00902                         return 0;
00903                 }
00904                 ctr->msg_groups = groups;
00905 
00906                 /* clear the new entry and set the printer name */
00907                 
00908                 ZERO_STRUCT( ctr->msg_groups[ctr->num_groups-1] );
00909                 fstrcpy( ctr->msg_groups[ctr->num_groups-1].printername, msg->printer );
00910         }
00911         
00912         /* add the change messages; 'i' is the correct index now regardless */
00913         
00914         msg_grp = &ctr->msg_groups[i];
00915         
00916         msg_grp->num_msgs++;
00917         
00918         if ( !(msg_list = TALLOC_REALLOC_ARRAY( ctr->ctx, msg_grp->msgs, SPOOLSS_NOTIFY_MSG, msg_grp->num_msgs )) ) {
00919                 DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed for new message [%d]!\n", msg_grp->num_msgs));
00920                 return 0;
00921         }
00922         msg_grp->msgs = msg_list;
00923         
00924         new_slot = msg_grp->num_msgs-1;
00925         memcpy( &msg_grp->msgs[new_slot], msg, sizeof(SPOOLSS_NOTIFY_MSG) );
00926         
00927         /* need to allocate own copy of data */
00928         
00929         if ( msg->len != 0 ) 
00930                 msg_grp->msgs[new_slot].notify.data = (char *)
00931                         TALLOC_MEMDUP( ctr->ctx, msg->notify.data, msg->len );
00932         
00933         return ctr->num_groups;
00934 }
00935 
00936 /***********************************************************************
00937  Send a change notication message on all handles which have a call 
00938  back registered
00939  **********************************************************************/
00940 
00941 static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx )
00942 {
00943         Printer_entry            *p;
00944         TALLOC_CTX               *mem_ctx = notify_ctr_getctx( ctr );
00945         SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, idx );
00946         SPOOLSS_NOTIFY_MSG       *messages;
00947         int                      sending_msg_count;
00948         
00949         if ( !msg_group ) {
00950                 DEBUG(5,("send_notify2_changes() called with no msg group!\n"));
00951                 return;
00952         }
00953         
00954         messages = msg_group->msgs;
00955         
00956         if ( !messages ) {
00957                 DEBUG(5,("send_notify2_changes() called with no messages!\n"));
00958                 return;
00959         }
00960         
00961         DEBUG(8,("send_notify2_changes: Enter...[%s]\n", msg_group->printername));
00962         
00963         /* loop over all printers */
00964         
00965         for (p = printers_list; p; p = p->next) {
00966                 SPOOL_NOTIFY_INFO_DATA *data;
00967                 uint32  data_len = 0;
00968                 uint32  id;
00969                 int     i;
00970 
00971                 /* Is there notification on this handle? */
00972 
00973                 if ( !p->notify.client_connected )
00974                         continue;
00975 
00976                 DEBUG(10,("Client connected! [\\\\%s\\%s]\n", p->servername, p->sharename));
00977 
00978                 /* For this printer?  Print servers always receive 
00979                    notifications. */
00980 
00981                 if ( ( p->printer_type == SPLHND_PRINTER )  &&
00982                     ( !strequal(msg_group->printername, p->sharename) ) )
00983                         continue;
00984 
00985                 DEBUG(10,("Our printer\n"));
00986                 
00987                 /* allocate the max entries possible */
00988                 
00989                 data = TALLOC_ARRAY( mem_ctx, SPOOL_NOTIFY_INFO_DATA, msg_group->num_msgs);
00990                 if (!data) {
00991                         return;
00992                 }
00993 
00994                 ZERO_STRUCTP(data);
00995                 
00996                 /* build the array of change notifications */
00997                 
00998                 sending_msg_count = 0;
00999                 
01000                 for ( i=0; i<msg_group->num_msgs; i++ ) {
01001                         SPOOLSS_NOTIFY_MSG      *msg = &messages[i];
01002                         
01003                         /* Are we monitoring this event? */
01004 
01005                         if (!is_monitoring_event(p, msg->type, msg->field))
01006                                 continue;
01007 
01008                         sending_msg_count++;
01009                         
01010                         
01011                         DEBUG(10,("process_notify2_message: Sending message type [0x%x] field [0x%2x] for printer [%s]\n",
01012                                 msg->type, msg->field, p->sharename));
01013 
01014                         /* 
01015                          * if the is a printer notification handle and not a job notification 
01016                          * type, then set the id to 0.  Other wise just use what was specified
01017                          * in the message.  
01018                          *
01019                          * When registering change notification on a print server handle 
01020                          * we always need to send back the id (snum) matching the printer
01021                          * for which the change took place.  For change notify registered
01022                          * on a printer handle, this does not matter and the id should be 0.
01023                          *
01024                          * --jerry
01025                          */
01026 
01027                         if ( ( p->printer_type == SPLHND_PRINTER ) && ( msg->type == PRINTER_NOTIFY_TYPE ) )
01028                                 id = 0;
01029                         else
01030                                 id = msg->id;
01031 
01032 
01033                         /* Convert unix jobid to smb jobid */
01034 
01035                         if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) {
01036                                 id = sysjob_to_jobid(msg->id);
01037 
01038                                 if (id == -1) {
01039                                         DEBUG(3, ("no such unix jobid %d\n", msg->id));
01040                                         goto done;
01041                                 }
01042                         }
01043 
01044                         construct_info_data( &data[data_len], msg->type, msg->field, id );
01045 
01046                         switch(msg->type) {
01047                         case PRINTER_NOTIFY_TYPE:
01048                                 if ( printer_notify_table[msg->field].fn )
01049                                         printer_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
01050                                 break;
01051                         
01052                         case JOB_NOTIFY_TYPE:
01053                                 if ( job_notify_table[msg->field].fn )
01054                                         job_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
01055                                 break;
01056 
01057                         default:
01058                                 DEBUG(5, ("Unknown notification type %d\n", msg->type));
01059                                 goto done;
01060                         }
01061 
01062                         data_len++;
01063                 }
01064 
01065                 if ( sending_msg_count ) {
01066                         rpccli_spoolss_rrpcn( notify_cli_pipe, mem_ctx, &p->notify.client_hnd, 
01067                                         data_len, data, p->notify.change, 0 );
01068                 }
01069         }
01070         
01071 done:
01072         DEBUG(8,("send_notify2_changes: Exit...\n"));
01073         return;
01074 }
01075 
01076 /***********************************************************************
01077  **********************************************************************/
01078 
01079 static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, void *buf, size_t len )
01080 {
01081 
01082         uint32 tv_sec, tv_usec;
01083         size_t offset = 0;
01084 
01085         /* Unpack message */
01086 
01087         offset += tdb_unpack((char *)buf + offset, len - offset, "f",
01088                              msg->printer);
01089         
01090         offset += tdb_unpack((char *)buf + offset, len - offset, "ddddddd",
01091                                 &tv_sec, &tv_usec,
01092                                 &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags);
01093 
01094         if (msg->len == 0)
01095                 tdb_unpack((char *)buf + offset, len - offset, "dd",
01096                            &msg->notify.value[0], &msg->notify.value[1]);
01097         else
01098                 tdb_unpack((char *)buf + offset, len - offset, "B", 
01099                            &msg->len, &msg->notify.data);
01100 
01101         DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message for printer %s, jobid %u type %d, field 0x%02x, flags 0x%04x\n",
01102                   msg->printer, (unsigned int)msg->id, msg->type, msg->field, msg->flags));
01103 
01104         tv->tv_sec = tv_sec;
01105         tv->tv_usec = tv_usec;
01106 
01107         if (msg->len == 0)
01108                 DEBUG(3, ("notify2_unpack_msg: value1 = %d, value2 = %d\n", msg->notify.value[0],
01109                           msg->notify.value[1]));
01110         else
01111                 dump_data(3, msg->notify.data, msg->len);
01112 
01113         return True;
01114 }
01115 
01116 /********************************************************************
01117  Receive a notify2 message list
01118  ********************************************************************/
01119 
01120 static void receive_notify2_message_list(int msg_type, struct process_id src,
01121                                          void *msg, size_t len,
01122                                          void *private_data)
01123 {
01124         size_t                  msg_count, i;
01125         char                    *buf = (char *)msg;
01126         char                    *msg_ptr;
01127         size_t                  msg_len;
01128         SPOOLSS_NOTIFY_MSG      notify;
01129         SPOOLSS_NOTIFY_MSG_CTR  messages;
01130         int                     num_groups;
01131 
01132         if (len < 4) {
01133                 DEBUG(0,("receive_notify2_message_list: bad message format (len < 4)!\n"));
01134                 return;
01135         }
01136         
01137         msg_count = IVAL(buf, 0);
01138         msg_ptr = buf + 4;
01139 
01140         DEBUG(5, ("receive_notify2_message_list: got %lu messages in list\n", (unsigned long)msg_count));
01141 
01142         if (msg_count == 0) {
01143                 DEBUG(0,("receive_notify2_message_list: bad message format (msg_count == 0) !\n"));
01144                 return;
01145         }
01146 
01147         /* initialize the container */
01148         
01149         ZERO_STRUCT( messages );
01150         notify_msg_ctr_init( &messages );
01151         
01152         /* 
01153          * build message groups for each printer identified
01154          * in a change_notify msg.  Remember that a PCN message
01155          * includes the handle returned for the srv_spoolss_replyopenprinter()
01156          * call.  Therefore messages are grouped according to printer handle.
01157          */
01158          
01159         for ( i=0; i<msg_count; i++ ) {
01160                 struct timeval msg_tv;
01161 
01162                 if (msg_ptr + 4 - buf > len) {
01163                         DEBUG(0,("receive_notify2_message_list: bad message format (len > buf_size) !\n"));
01164                         return;
01165                 }
01166 
01167                 msg_len = IVAL(msg_ptr,0);
01168                 msg_ptr += 4;
01169 
01170                 if (msg_ptr + msg_len - buf > len) {
01171                         DEBUG(0,("receive_notify2_message_list: bad message format (bad len) !\n"));
01172                         return;
01173                 }
01174                 
01175                 /* unpack messages */
01176                 
01177                 ZERO_STRUCT( notify );
01178                 notify2_unpack_msg( &notify, &msg_tv, msg_ptr, msg_len );
01179                 msg_ptr += msg_len;
01180 
01181                 /* add to correct list in container */
01182                 
01183                 notify_msg_ctr_addmsg( &messages, &notify );
01184                 
01185                 /* free memory that might have been allocated by notify2_unpack_msg() */
01186                 
01187                 if ( notify.len != 0 )
01188                         SAFE_FREE( notify.notify.data );
01189         }
01190         
01191         /* process each group of messages */
01192         
01193         num_groups = notify_msg_ctr_numgroups( &messages );
01194         for ( i=0; i<num_groups; i++ )
01195                 send_notify2_changes( &messages, i );
01196         
01197         
01198         /* cleanup */
01199                 
01200         DEBUG(10,("receive_notify2_message_list: processed %u messages\n", (uint32)msg_count ));
01201                 
01202         notify_msg_ctr_destroy( &messages );
01203         
01204         return;
01205 }
01206 
01207 /********************************************************************
01208  Send a message to ourself about new driver being installed
01209  so we can upgrade the information for each printer bound to this
01210  driver
01211  ********************************************************************/
01212  
01213 static BOOL srv_spoolss_drv_upgrade_printer(char* drivername)
01214 {
01215         int len = strlen(drivername);
01216         
01217         if (!len)
01218                 return False;
01219 
01220         DEBUG(10,("srv_spoolss_drv_upgrade_printer: Sending message about driver upgrade [%s]\n",
01221                 drivername));
01222                 
01223         message_send_pid(pid_to_procid(sys_getpid()),
01224                          MSG_PRINTER_DRVUPGRADE, drivername, len+1, False);
01225 
01226         return True;
01227 }
01228 
01229 /**********************************************************************
01230  callback to receive a MSG_PRINTER_DRVUPGRADE message and interate
01231  over all printers, upgrading ones as necessary 
01232  **********************************************************************/
01233  
01234 void do_drv_upgrade_printer(int msg_type, struct process_id src,
01235                             void *buf, size_t len, void *private_data)
01236 {
01237         fstring drivername;
01238         int snum;
01239         int n_services = lp_numservices();
01240         
01241         len = MIN(len,sizeof(drivername)-1);
01242         strncpy(drivername, (const char *)buf, len);
01243         
01244         DEBUG(10,("do_drv_upgrade_printer: Got message for new driver [%s]\n", drivername ));
01245 
01246         /* Iterate the printer list */
01247         
01248         for (snum=0; snum<n_services; snum++)
01249         {
01250                 if (lp_snum_ok(snum) && lp_print_ok(snum) ) 
01251                 {
01252                         WERROR result;
01253                         NT_PRINTER_INFO_LEVEL *printer = NULL;
01254                         
01255                         result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
01256                         if (!W_ERROR_IS_OK(result))
01257                                 continue;
01258                                 
01259                         if (printer && printer->info_2 && !strcmp(drivername, printer->info_2->drivername)) 
01260                         {
01261                                 DEBUG(6,("Updating printer [%s]\n", printer->info_2->printername));
01262                                 
01263                                 /* all we care about currently is the change_id */
01264                                 
01265                                 result = mod_a_printer(printer, 2);
01266                                 if (!W_ERROR_IS_OK(result)) {
01267                                         DEBUG(3,("do_drv_upgrade_printer: mod_a_printer() failed with status [%s]\n", 
01268                                                 dos_errstr(result)));
01269                                 }
01270                         }
01271                         
01272                         free_a_printer(&printer, 2);                    
01273                 }
01274         }
01275         
01276         /* all done */  
01277 }
01278 
01279 /********************************************************************
01280  Update the cache for all printq's with a registered client 
01281  connection
01282  ********************************************************************/
01283 
01284 void update_monitored_printq_cache( void )
01285 {
01286         Printer_entry *printer = printers_list;
01287         int snum;
01288         
01289         /* loop through all printers and update the cache where 
01290            client_connected == True */
01291         while ( printer ) 
01292         {
01293                 if ( (printer->printer_type == SPLHND_PRINTER) 
01294                         && printer->notify.client_connected ) 
01295                 {
01296                         snum = print_queue_snum(printer->sharename);
01297                         print_queue_status( snum, NULL, NULL );
01298                 }
01299                 
01300                 printer = printer->next;
01301         }
01302         
01303         return;
01304 }
01305 /********************************************************************
01306  Send a message to ourself about new driver being installed
01307  so we can upgrade the information for each printer bound to this
01308  driver
01309  ********************************************************************/
01310  
01311 static BOOL srv_spoolss_reset_printerdata(char* drivername)
01312 {
01313         int len = strlen(drivername);
01314         
01315         if (!len)
01316                 return False;
01317 
01318         DEBUG(10,("srv_spoolss_reset_printerdata: Sending message about resetting printerdata [%s]\n",
01319                 drivername));
01320                 
01321         message_send_pid(pid_to_procid(sys_getpid()),
01322                          MSG_PRINTERDATA_INIT_RESET, drivername, len+1, False);
01323 
01324         return True;
01325 }
01326 
01327 /**********************************************************************
01328  callback to receive a MSG_PRINTERDATA_INIT_RESET message and interate
01329  over all printers, resetting printer data as neessary 
01330  **********************************************************************/
01331  
01332 void reset_all_printerdata(int msg_type, struct process_id src,
01333                            void *buf, size_t len, void *private_data)
01334 {
01335         fstring drivername;
01336         int snum;
01337         int n_services = lp_numservices();
01338         
01339         len = MIN( len, sizeof(drivername)-1 );
01340         strncpy( drivername, (const char *)buf, len );
01341         
01342         DEBUG(10,("reset_all_printerdata: Got message for new driver [%s]\n", drivername ));
01343 
01344         /* Iterate the printer list */
01345         
01346         for ( snum=0; snum<n_services; snum++ )
01347         {
01348                 if ( lp_snum_ok(snum) && lp_print_ok(snum) ) 
01349                 {
01350                         WERROR result;
01351                         NT_PRINTER_INFO_LEVEL *printer = NULL;
01352                         
01353                         result = get_a_printer( NULL, &printer, 2, lp_const_servicename(snum) );
01354                         if ( !W_ERROR_IS_OK(result) )
01355                                 continue;
01356                                 
01357                         /* 
01358                          * if the printer is bound to the driver, 
01359                          * then reset to the new driver initdata 
01360                          */
01361                         
01362                         if ( printer && printer->info_2 && !strcmp(drivername, printer->info_2->drivername) ) 
01363                         {
01364                                 DEBUG(6,("reset_all_printerdata: Updating printer [%s]\n", printer->info_2->printername));
01365                                 
01366                                 if ( !set_driver_init(printer, 2) ) {
01367                                         DEBUG(5,("reset_all_printerdata: Error resetting printer data for printer [%s], driver [%s]!\n",
01368                                                 printer->info_2->printername, printer->info_2->drivername));
01369                                 }       
01370                                 
01371                                 result = mod_a_printer( printer, 2 );
01372                                 if ( !W_ERROR_IS_OK(result) ) {
01373                                         DEBUG(3,("reset_all_printerdata: mod_a_printer() failed!  (%s)\n", 
01374                                                 get_dos_error_msg(result)));
01375                                 }
01376                         }
01377                         
01378                         free_a_printer( &printer, 2 );
01379                 }
01380         }
01381         
01382         /* all done */  
01383         
01384         return;
01385 }
01386 
01387 /********************************************************************
01388  Copy routines used by convert_to_openprinterex()
01389  *******************************************************************/
01390 
01391 static DEVICEMODE* dup_devicemode(TALLOC_CTX *ctx, DEVICEMODE *devmode)
01392 {
01393         DEVICEMODE *d;
01394         int len;
01395 
01396         if (!devmode)
01397                 return NULL;
01398                 
01399         DEBUG (8,("dup_devmode\n"));
01400         
01401         /* bulk copy first */
01402         
01403         d = (DEVICEMODE *)TALLOC_MEMDUP(ctx, devmode, sizeof(DEVICEMODE));
01404         if (!d)
01405                 return NULL;
01406                 
01407         /* dup the pointer members separately */
01408         
01409         len = unistrlen(devmode->devicename.buffer);
01410         if (len != -1) {
01411                 d->devicename.buffer = TALLOC_ARRAY(ctx, uint16, len);
01412                 if (!d->devicename.buffer) {
01413                         return NULL;
01414                 }
01415                 if (unistrcpy(d->devicename.buffer, devmode->devicename.buffer) != len)
01416                         return NULL;
01417         }
01418                 
01419 
01420         len = unistrlen(devmode->formname.buffer);
01421         if (len != -1) {
01422                 d->formname.buffer = TALLOC_ARRAY(ctx, uint16, len);
01423                 if (!d->formname.buffer) {
01424                         return NULL;
01425                 }
01426                 if (unistrcpy(d->formname.buffer, devmode->formname.buffer) != len)
01427                         return NULL;
01428         }
01429 
01430         if (devmode->driverextra) {
01431                 d->dev_private = (uint8 *)TALLOC_MEMDUP(ctx, devmode->dev_private,
01432                                                 devmode->driverextra);
01433                 if (!d->dev_private) {
01434                         return NULL;
01435                 }       
01436         } else {
01437                 d->dev_private = NULL;
01438         }
01439         return d;
01440 }
01441 
01442 static void copy_devmode_ctr(TALLOC_CTX *ctx, DEVMODE_CTR *new_ctr, DEVMODE_CTR *ctr)
01443 {
01444         if (!new_ctr || !ctr)
01445                 return;
01446                 
01447         DEBUG(8,("copy_devmode_ctr\n"));
01448         
01449         new_ctr->size = ctr->size;
01450         new_ctr->devmode_ptr = ctr->devmode_ptr;
01451         
01452         if(ctr->devmode_ptr)
01453                 new_ctr->devmode = dup_devicemode(ctx, ctr->devmode);
01454 }
01455 
01456 static void copy_printer_default(TALLOC_CTX *ctx, PRINTER_DEFAULT *new_def, PRINTER_DEFAULT *def)
01457 {
01458         if (!new_def || !def)
01459                 return;
01460         
01461         DEBUG(8,("copy_printer_defaults\n"));
01462         
01463         new_def->datatype_ptr = def->datatype_ptr;
01464         
01465         if (def->datatype_ptr)
01466                 copy_unistr2(&new_def->datatype, &def->datatype);
01467         
01468         copy_devmode_ctr(ctx, &new_def->devmode_cont, &def->devmode_cont);
01469         
01470         new_def->access_required = def->access_required;
01471 }
01472 
01473 /********************************************************************
01474  * Convert a SPOOL_Q_OPEN_PRINTER structure to a 
01475  * SPOOL_Q_OPEN_PRINTER_EX structure
01476  ********************************************************************/
01477 
01478 static WERROR convert_to_openprinterex(TALLOC_CTX *ctx, SPOOL_Q_OPEN_PRINTER_EX *q_u_ex, SPOOL_Q_OPEN_PRINTER *q_u)
01479 {
01480         if (!q_u_ex || !q_u)
01481                 return WERR_OK;
01482 
01483         DEBUG(8,("convert_to_openprinterex\n"));
01484                                 
01485         if ( q_u->printername ) {
01486                 q_u_ex->printername = TALLOC_ZERO_P( ctx, UNISTR2 );
01487                 if (q_u_ex->printername == NULL)
01488                         return WERR_NOMEM;
01489                 copy_unistr2(q_u_ex->printername, q_u->printername);
01490         }
01491         
01492         copy_printer_default(ctx, &q_u_ex->printer_default, &q_u->printer_default);
01493 
01494         return WERR_OK;
01495 }
01496 
01497 /********************************************************************
01498  * spoolss_open_printer
01499  *
01500  * called from the spoolss dispatcher
01501  ********************************************************************/
01502 
01503 WERROR _spoolss_open_printer(pipes_struct *p, SPOOL_Q_OPEN_PRINTER *q_u, SPOOL_R_OPEN_PRINTER *r_u)
01504 {
01505         SPOOL_Q_OPEN_PRINTER_EX q_u_ex;
01506         SPOOL_R_OPEN_PRINTER_EX r_u_ex;
01507         
01508         if (!q_u || !r_u)
01509                 return WERR_NOMEM;
01510         
01511         ZERO_STRUCT(q_u_ex);
01512         ZERO_STRUCT(r_u_ex);
01513         
01514         /* convert the OpenPrinter() call to OpenPrinterEx() */
01515         
01516         r_u_ex.status = convert_to_openprinterex(p->mem_ctx, &q_u_ex, q_u);
01517         if (!W_ERROR_IS_OK(r_u_ex.status))
01518                 return r_u_ex.status;
01519         
01520         r_u_ex.status = _spoolss_open_printer_ex(p, &q_u_ex, &r_u_ex);
01521         
01522         /* convert back to OpenPrinter() */
01523         
01524         memcpy(r_u, &r_u_ex, sizeof(*r_u));
01525         
01526         return r_u->status;
01527 }
01528 
01529 /********************************************************************
01530  ********************************************************************/
01531 
01532 WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u)
01533 {
01534         PRINTER_DEFAULT         *printer_default = &q_u->printer_default;
01535         POLICY_HND              *handle = &r_u->handle;
01536 
01537         fstring name;
01538         int snum;
01539         struct current_user user;
01540         Printer_entry *Printer=NULL;
01541 
01542         if ( !q_u->printername )
01543                 return WERR_INVALID_PRINTER_NAME;
01544 
01545         /* some sanity check because you can open a printer or a print server */
01546         /* aka: \\server\printer or \\server */
01547 
01548         unistr2_to_ascii(name, q_u->printername, sizeof(name)-1);
01549 
01550         DEBUGADD(3,("checking name: %s\n",name));
01551 
01552         if (!open_printer_hnd(p, handle, name, 0))
01553                 return WERR_INVALID_PRINTER_NAME;
01554         
01555         Printer=find_printer_index_by_hnd(p, handle);
01556         if ( !Printer ) {
01557                 DEBUG(0,(" _spoolss_open_printer_ex: logic error.  Can't find printer "
01558                         "handle we created for printer %s\n", name ));
01559                 close_printer_handle(p,handle);
01560                 return WERR_INVALID_PRINTER_NAME;
01561         }
01562 
01563         get_current_user(&user, p);
01564 
01565         /*
01566          * First case: the user is opening the print server:
01567          *
01568          * Disallow MS AddPrinterWizard if parameter disables it. A Win2k
01569          * client 1st tries an OpenPrinterEx with access==0, MUST be allowed.
01570          *
01571          * Then both Win2k and WinNT clients try an OpenPrinterEx with
01572          * SERVER_ALL_ACCESS, which we allow only if the user is root (uid=0)
01573          * or if the user is listed in the smb.conf printer admin parameter.
01574          *
01575          * Then they try OpenPrinterEx with SERVER_READ which we allow. This lets the
01576          * client view printer folder, but does not show the MSAPW.
01577          *
01578          * Note: this test needs code to check access rights here too. Jeremy
01579          * could you look at this?
01580          * 
01581          * Second case: the user is opening a printer:
01582          * NT doesn't let us connect to a printer if the connecting user
01583          * doesn't have print permission.
01584          * 
01585          * Third case: user is opening a Port Monitor
01586          * access checks same as opening a handle to the print server.
01587          */
01588 
01589         switch (Printer->printer_type ) 
01590         {
01591         case SPLHND_SERVER:
01592         case SPLHND_PORTMON_TCP:
01593         case SPLHND_PORTMON_LOCAL:
01594                 /* Printserver handles use global struct... */
01595 
01596                 snum = -1;
01597 
01598                 /* Map standard access rights to object specific access rights */
01599                 
01600                 se_map_standard(&printer_default->access_required, 
01601                                 &printserver_std_mapping);
01602         
01603                 /* Deny any object specific bits that don't apply to print
01604                    servers (i.e printer and job specific bits) */
01605 
01606                 printer_default->access_required &= SPECIFIC_RIGHTS_MASK;
01607 
01608                 if (printer_default->access_required &
01609                     ~(SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)) {
01610                         DEBUG(3, ("access DENIED for non-printserver bits\n"));
01611                         close_printer_handle(p, handle);
01612                         return WERR_ACCESS_DENIED;
01613                 }
01614 
01615                 /* Allow admin access */
01616 
01617                 if ( printer_default->access_required & SERVER_ACCESS_ADMINISTER ) 
01618                 {
01619                         SE_PRIV se_printop = SE_PRINT_OPERATOR;
01620 
01621                         if (!lp_ms_add_printer_wizard()) {
01622                                 close_printer_handle(p, handle);
01623                                 return WERR_ACCESS_DENIED;
01624                         }
01625 
01626                         /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
01627                            and not a printer admin, then fail */
01628                         
01629                         if ((user.ut.uid != 0) &&
01630                             !user_has_privileges(user.nt_user_token,
01631                                                  &se_printop ) &&
01632                             !token_contains_name_in_list(
01633                                     uidtoname(user.ut.uid), NULL,
01634                                     user.nt_user_token,
01635                                     lp_printer_admin(snum))) {
01636                                 close_printer_handle(p, handle);
01637                                 return WERR_ACCESS_DENIED;
01638                         }
01639                         
01640                         printer_default->access_required = SERVER_ACCESS_ADMINISTER;
01641                 }
01642                 else
01643                 {
01644                         printer_default->access_required = SERVER_ACCESS_ENUMERATE;
01645                 }
01646 
01647                 DEBUG(4,("Setting print server access = %s\n", (printer_default->access_required == SERVER_ACCESS_ADMINISTER) 
01648                         ? "SERVER_ACCESS_ADMINISTER" : "SERVER_ACCESS_ENUMERATE" ));
01649                         
01650                 /* We fall through to return WERR_OK */
01651                 break;
01652 
01653         case SPLHND_PRINTER:
01654                 /* NT doesn't let us connect to a printer if the connecting user
01655                    doesn't have print permission.  */
01656 
01657                 if (!get_printer_snum(p, handle, &snum)) {
01658                         close_printer_handle(p, handle);
01659                         return WERR_BADFID;
01660                 }
01661 
01662                 se_map_standard(&printer_default->access_required, &printer_std_mapping);
01663                 
01664                 /* map an empty access mask to the minimum access mask */
01665                 if (printer_default->access_required == 0x0)
01666                         printer_default->access_required = PRINTER_ACCESS_USE;
01667 
01668                 /*
01669                  * If we are not serving the printer driver for this printer,
01670                  * map PRINTER_ACCESS_ADMINISTER to PRINTER_ACCESS_USE.  This
01671                  * will keep NT clients happy  --jerry  
01672                  */
01673                  
01674                 if (lp_use_client_driver(snum) 
01675                         && (printer_default->access_required & PRINTER_ACCESS_ADMINISTER))
01676                 {
01677                         printer_default->access_required = PRINTER_ACCESS_USE;
01678                 }
01679 
01680                 /* check smb.conf parameters and the the sec_desc */
01681                 
01682                 if ( !check_access(smbd_server_fd(), lp_hostsallow(snum), lp_hostsdeny(snum)) ) {    
01683                         DEBUG(3, ("access DENIED (hosts allow/deny) for printer open\n"));
01684                         return WERR_ACCESS_DENIED;
01685                 }
01686 
01687                 if (!user_ok_token(uidtoname(user.ut.uid), user.nt_user_token,
01688                                    snum) ||
01689                     !print_access_check(&user, snum,
01690                                         printer_default->access_required)) {
01691                         DEBUG(3, ("access DENIED for printer open\n"));
01692                         close_printer_handle(p, handle);
01693                         return WERR_ACCESS_DENIED;
01694                 }
01695 
01696                 if ((printer_default->access_required & SPECIFIC_RIGHTS_MASK)& ~(PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE)) {
01697                         DEBUG(3, ("access DENIED for printer open - unknown bits\n"));
01698                         close_printer_handle(p, handle);
01699                         return WERR_ACCESS_DENIED;
01700                 }
01701 
01702                 if (printer_default->access_required & PRINTER_ACCESS_ADMINISTER)
01703                         printer_default->access_required = PRINTER_ACCESS_ADMINISTER;
01704                 else
01705                         printer_default->access_required = PRINTER_ACCESS_USE;
01706 
01707                 DEBUG(4,("Setting printer access = %s\n", (printer_default->access_required == PRINTER_ACCESS_ADMINISTER) 
01708                         ? "PRINTER_ACCESS_ADMINISTER" : "PRINTER_ACCESS_USE" ));
01709 
01710                 break;
01711 
01712         default:
01713                 /* sanity check to prevent programmer error */
01714                 return WERR_BADFID;
01715         }
01716         
01717         Printer->access_granted = printer_default->access_required;
01718         
01719         /* 
01720          * If the client sent a devmode in the OpenPrinter() call, then
01721          * save it here in case we get a job submission on this handle
01722          */
01723         
01724          if ( (Printer->printer_type != SPLHND_SERVER)
01725                 && q_u->printer_default.devmode_cont.devmode_ptr )
01726          { 
01727                 convert_devicemode( Printer->sharename, q_u->printer_default.devmode_cont.devmode,
01728                         &Printer->nt_devmode );
01729          }
01730 
01731 #if 0   /* JERRY -- I'm doubtful this is really effective */
01732         /* HACK ALERT!!! Sleep for 1/3 of a second to try trigger a LAN/WAN 
01733            optimization in Windows 2000 clients  --jerry */
01734 
01735         if ( (printer_default->access_required == PRINTER_ACCESS_ADMINISTER) 
01736                 && (RA_WIN2K == get_remote_arch()) )
01737         {
01738                 DEBUG(10,("_spoolss_open_printer_ex: Enabling LAN/WAN hack for Win2k clients.\n"));
01739                 sys_usleep( 500000 );
01740         }
01741 #endif
01742 
01743         return WERR_OK;
01744 }
01745 
01746 /****************************************************************************
01747 ****************************************************************************/
01748 
01749 static BOOL convert_printer_info(const SPOOL_PRINTER_INFO_LEVEL *uni,
01750                                 NT_PRINTER_INFO_LEVEL *printer, uint32 level)
01751 {
01752         BOOL ret;
01753 
01754         switch (level) {
01755                 case 2:
01756                         /* allocate memory if needed.  Messy because 
01757                            convert_printer_info is used to update an existing 
01758                            printer or build a new one */
01759 
01760                         if ( !printer->info_2 ) {
01761                                 printer->info_2 = TALLOC_ZERO_P( printer, NT_PRINTER_INFO_LEVEL_2 );
01762                                 if ( !printer->info_2 ) {
01763                                         DEBUG(0,("convert_printer_info: talloc() failed!\n"));
01764                                         return False;
01765                                 }
01766                         }
01767 
01768                         ret = uni_2_asc_printer_info_2(uni->info_2, printer->info_2);
01769                         printer->info_2->setuptime = time(NULL);
01770 
01771                         return ret;
01772         }
01773 
01774         return False;
01775 }
01776 
01777 static BOOL convert_printer_driver_info(const SPOOL_PRINTER_DRIVER_INFO_LEVEL *uni,
01778                                         NT_PRINTER_DRIVER_INFO_LEVEL *printer, uint32 level)
01779 {
01780         BOOL result = True;
01781 
01782         switch (level) {
01783                 case 3:
01784                         printer->info_3=NULL;
01785                         if (!uni_2_asc_printer_driver_3(uni->info_3, &printer->info_3))
01786                                 result = False;
01787                         break;
01788                 case 6:
01789                         printer->info_6=NULL;
01790                         if (!uni_2_asc_printer_driver_6(uni->info_6, &printer->info_6))
01791                                 result = False;
01792                         break;
01793                 default:
01794                         break;
01795         }
01796 
01797         return result;
01798 }
01799 
01800 BOOL convert_devicemode(const char *printername, const DEVICEMODE *devmode,
01801                                 NT_DEVICEMODE **pp_nt_devmode)
01802 {
01803         NT_DEVICEMODE *nt_devmode = *pp_nt_devmode;
01804 
01805         /*
01806          * Ensure nt_devmode is a valid pointer
01807          * as we will be overwriting it.
01808          */
01809                 
01810         if (nt_devmode == NULL) {
01811                 DEBUG(5, ("convert_devicemode: allocating a generic devmode\n"));
01812                 if ((nt_devmode = construct_nt_devicemode(printername)) == NULL)
01813                         return False;
01814         }
01815 
01816         rpcstr_pull(nt_devmode->devicename,devmode->devicename.buffer, 31, -1, 0);
01817         rpcstr_pull(nt_devmode->formname,devmode->formname.buffer, 31, -1, 0);
01818 
01819         nt_devmode->specversion=devmode->specversion;
01820         nt_devmode->driverversion=devmode->driverversion;
01821         nt_devmode->size=devmode->size;
01822         nt_devmode->fields=devmode->fields;
01823         nt_devmode->orientation=devmode->orientation;
01824         nt_devmode->papersize=devmode->papersize;
01825         nt_devmode->paperlength=devmode->paperlength;
01826         nt_devmode->paperwidth=devmode->paperwidth;
01827         nt_devmode->scale=devmode->scale;
01828         nt_devmode->copies=devmode->copies;
01829         nt_devmode->defaultsource=devmode->defaultsource;
01830         nt_devmode->printquality=devmode->printquality;
01831         nt_devmode->color=devmode->color;
01832         nt_devmode->duplex=devmode->duplex;
01833         nt_devmode->yresolution=devmode->yresolution;
01834         nt_devmode->ttoption=devmode->ttoption;
01835         nt_devmode->collate=devmode->collate;
01836 
01837         nt_devmode->logpixels=devmode->logpixels;
01838         nt_devmode->bitsperpel=devmode->bitsperpel;
01839         nt_devmode->pelswidth=devmode->pelswidth;
01840         nt_devmode->pelsheight=devmode->pelsheight;
01841         nt_devmode->displayflags=devmode->displayflags;
01842         nt_devmode->displayfrequency=devmode->displayfrequency;
01843         nt_devmode->icmmethod=devmode->icmmethod;
01844         nt_devmode->icmintent=devmode->icmintent;
01845         nt_devmode->mediatype=devmode->mediatype;
01846         nt_devmode->dithertype=devmode->dithertype;
01847         nt_devmode->reserved1=devmode->reserved1;
01848         nt_devmode->reserved2=devmode->reserved2;
01849         nt_devmode->panningwidth=devmode->panningwidth;
01850         nt_devmode->panningheight=devmode->panningheight;
01851 
01852         /*
01853          * Only change private and driverextra if the incoming devmode
01854          * has a new one. JRA.
01855          */
01856 
01857         if ((devmode->driverextra != 0) && (devmode->dev_private != NULL)) {
01858                 SAFE_FREE(nt_devmode->nt_dev_private);
01859                 nt_devmode->driverextra=devmode->driverextra;
01860                 if((nt_devmode->nt_dev_private=SMB_MALLOC_ARRAY(uint8, nt_devmode->driverextra)) == NULL)
01861                         return False;
01862                 memcpy(nt_devmode->nt_dev_private, devmode->dev_private, nt_devmode->driverextra);
01863         }
01864 
01865         *pp_nt_devmode = nt_devmode;
01866 
01867         return True;
01868 }
01869 
01870 /********************************************************************
01871  * _spoolss_enddocprinter_internal.
01872  ********************************************************************/
01873 
01874 static WERROR _spoolss_enddocprinter_internal(pipes_struct *p, POLICY_HND *handle)
01875 {
01876         Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
01877         int snum;
01878 
01879         if (!Printer) {
01880                 DEBUG(2,("_spoolss_enddocprinter_internal: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
01881                 return WERR_BADFID;
01882         }
01883         
01884         if (!get_printer_snum(p, handle, &snum))
01885                 return WERR_BADFID;
01886 
01887         Printer->document_started=False;
01888         print_job_end(snum, Printer->jobid,NORMAL_CLOSE);
01889         /* error codes unhandled so far ... */
01890 
01891         return WERR_OK;
01892 }
01893 
01894 /********************************************************************
01895  * api_spoolss_closeprinter
01896  ********************************************************************/
01897 
01898 WERROR _spoolss_closeprinter(pipes_struct *p, SPOOL_Q_CLOSEPRINTER *q_u, SPOOL_R_CLOSEPRINTER *r_u)
01899 {
01900         POLICY_HND *handle = &q_u->handle;
01901 
01902         Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
01903 
01904         if (Printer && Printer->document_started)
01905                 _spoolss_enddocprinter_internal(p, handle);          /* print job was not closed */
01906 
01907         if (!close_printer_handle(p, handle))
01908                 return WERR_BADFID;     
01909                 
01910         /* clear the returned printer handle.  Observed behavior 
01911            from Win2k server.  Don't think this really matters.
01912            Previous code just copied the value of the closed
01913            handle.    --jerry */
01914 
01915         memset(&r_u->handle, '\0', sizeof(r_u->handle));
01916 
01917         return WERR_OK;
01918 }
01919 
01920 /********************************************************************
01921  * api_spoolss_deleteprinter
01922 
01923  ********************************************************************/
01924 
01925 WERROR _spoolss_deleteprinter(pipes_struct *p, SPOOL_Q_DELETEPRINTER *q_u, SPOOL_R_DELETEPRINTER *r_u)
01926 {
01927         POLICY_HND *handle = &q_u->handle;
01928         Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
01929         WERROR result;
01930 
01931         if (Printer && Printer->document_started)
01932                 _spoolss_enddocprinter_internal(p, handle);  /* print job was not closed */
01933 
01934         memcpy(&r_u->handle, &q_u->handle, sizeof(r_u->handle));
01935 
01936         result = delete_printer_handle(p, handle);
01937 
01938         update_c_setprinter(False);
01939 
01940         return result;
01941 }
01942 
01943 /*******************************************************************
01944  * static function to lookup the version id corresponding to an
01945  * long architecture string
01946  ******************************************************************/
01947 
01948 static int get_version_id (char * arch)
01949 {
01950         int i;
01951         struct table_node archi_table[]= {
01952  
01953                 {"Windows 4.0",          "WIN40",       0 },
01954                 {"Windows NT x86",       "W32X86",      2 },
01955                 {"Windows NT R4000",     "W32MIPS",     2 },    
01956                 {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
01957                 {"Windows NT PowerPC",   "W32PPC",      2 },
01958                 {"Windows IA64",         "IA64",        3 },
01959                 {"Windows x64",          "x64",         3 },
01960                 {NULL,                   "",            -1 }
01961         };
01962  
01963         for (i=0; archi_table[i].long_archi != NULL; i++)
01964         {
01965                 if (strcmp(arch, archi_table[i].long_archi) == 0)
01966                         return (archi_table[i].version);
01967         }
01968         
01969         return -1;
01970 }
01971 
01972 /********************************************************************
01973  * _spoolss_deleteprinterdriver
01974  ********************************************************************/
01975 
01976 WERROR _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER *q_u, SPOOL_R_DELETEPRINTERDRIVER *r_u)
01977 {
01978         fstring                         driver;
01979         fstring                         arch;
01980         NT_PRINTER_DRIVER_INFO_LEVEL    info;
01981         NT_PRINTER_DRIVER_INFO_LEVEL    info_win2k;
01982         int                             version;
01983         struct current_user             user;
01984         WERROR                          status;
01985         WERROR                          status_win2k = WERR_ACCESS_DENIED;
01986         SE_PRIV                         se_printop = SE_PRINT_OPERATOR; 
01987         
01988         get_current_user(&user, p);
01989          
01990         /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
01991            and not a printer admin, then fail */
01992                         
01993         if ( (user.ut.uid != 0) 
01994                 && !user_has_privileges(user.nt_user_token, &se_printop ) 
01995                 && !token_contains_name_in_list( uidtoname(user.ut.uid), 
01996                     NULL, user.nt_user_token, lp_printer_admin(-1)) ) 
01997         {
01998                 return WERR_ACCESS_DENIED;
01999         }
02000 
02001         unistr2_to_ascii(driver, &q_u->driver, sizeof(driver)-1 );
02002         unistr2_to_ascii(arch,   &q_u->arch,   sizeof(arch)-1   );
02003         
02004         /* check that we have a valid driver name first */
02005         
02006         if ((version=get_version_id(arch)) == -1) 
02007                 return WERR_INVALID_ENVIRONMENT;
02008                                 
02009         ZERO_STRUCT(info);
02010         ZERO_STRUCT(info_win2k);
02011         
02012         if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) 
02013         {
02014                 /* try for Win2k driver if "Windows NT x86" */
02015                 
02016                 if ( version == 2 ) {
02017                         version = 3;
02018                         if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) {
02019                                 status = WERR_UNKNOWN_PRINTER_DRIVER;
02020                                 goto done;
02021                         }
02022                 }
02023                 /* otherwise it was a failure */
02024                 else {
02025                         status = WERR_UNKNOWN_PRINTER_DRIVER;
02026                         goto done;
02027                 }
02028                 
02029         }
02030         
02031         if (printer_driver_in_use(info.info_3)) {
02032                 status = WERR_PRINTER_DRIVER_IN_USE;
02033                 goto done;
02034         }
02035         
02036         if ( version == 2 )
02037         {               
02038                 if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3, driver, arch, 3)))
02039                 {
02040                         /* if we get to here, we now have 2 driver info structures to remove */
02041                         /* remove the Win2k driver first*/
02042                 
02043                         status_win2k = delete_printer_driver(info_win2k.info_3, &user, 3, False );
02044                         free_a_printer_driver( info_win2k, 3 );
02045                 
02046                         /* this should not have failed---if it did, report to client */
02047                         if ( !W_ERROR_IS_OK(status_win2k) )
02048                         {
02049                                 status = status_win2k;
02050                                 goto done;
02051                         }
02052                 }
02053         }
02054         
02055         status = delete_printer_driver(info.info_3, &user, version, False);
02056         
02057         /* if at least one of the deletes succeeded return OK */
02058         
02059         if ( W_ERROR_IS_OK(status) || W_ERROR_IS_OK(status_win2k) )
02060                 status = WERR_OK;
02061         
02062 done:
02063         free_a_printer_driver( info, 3 );
02064 
02065         return status;
02066 }
02067 
02068 /********************************************************************
02069  * spoolss_deleteprinterdriverex
02070  ********************************************************************/
02071 
02072 WERROR _spoolss_deleteprinterdriverex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVEREX *q_u, SPOOL_R_DELETEPRINTERDRIVEREX *r_u)
02073 {
02074         fstring                         driver;
02075         fstring                         arch;
02076         NT_PRINTER_DRIVER_INFO_LEVEL    info;
02077         NT_PRINTER_DRIVER_INFO_LEVEL    info_win2k;
02078         int                             version;
02079         uint32                          flags = q_u->delete_flags;
02080         BOOL                            delete_files;
02081         struct current_user             user;
02082         WERROR                          status;
02083         WERROR                          status_win2k = WERR_ACCESS_DENIED;
02084         SE_PRIV                         se_printop = SE_PRINT_OPERATOR; 
02085         
02086         get_current_user(&user, p);
02087         
02088         /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
02089            and not a printer admin, then fail */
02090                         
02091         if ( (user.ut.uid != 0) 
02092                 && !user_has_privileges(user.nt_user_token, &se_printop ) 
02093                 && !token_contains_name_in_list( uidtoname(user.ut.uid), 
02094                     NULL, user.nt_user_token, lp_printer_admin(-1)) ) 
02095         {
02096                 return WERR_ACCESS_DENIED;
02097         }
02098         
02099         unistr2_to_ascii(driver, &q_u->driver, sizeof(driver)-1 );
02100         unistr2_to_ascii(arch,   &q_u->arch,   sizeof(arch)-1   );
02101 
02102         /* check that we have a valid driver name first */
02103         if ((version=get_version_id(arch)) == -1) {
02104                 /* this is what NT returns */
02105                 return WERR_INVALID_ENVIRONMENT;
02106         }
02107         
02108         if ( flags & DPD_DELETE_SPECIFIC_VERSION )
02109                 version = q_u->version;
02110                 
02111         ZERO_STRUCT(info);
02112         ZERO_STRUCT(info_win2k);
02113                 
02114         status = get_a_printer_driver(&info, 3, driver, arch, version);
02115         
02116         if ( !W_ERROR_IS_OK(status) ) 
02117         {
02118                 /* 
02119                  * if the client asked for a specific version, 
02120                  * or this is something other than Windows NT x86,
02121                  * then we've failed 
02122                  */
02123                 
02124                 if ( (flags&DPD_DELETE_SPECIFIC_VERSION) || (version !=2) )
02125                         goto done;
02126                         
02127                 /* try for Win2k driver if "Windows NT x86" */
02128                 
02129                 version = 3;
02130                 if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) {
02131                         status = WERR_UNKNOWN_PRINTER_DRIVER;
02132                         goto done;
02133                 }
02134         }
02135                 
02136         if ( printer_driver_in_use(info.info_3) ) {
02137                 status = WERR_PRINTER_DRIVER_IN_USE;
02138                 goto done;
02139         }
02140         
02141         /* 
02142          * we have a couple of cases to consider. 
02143          * (1) Are any files in use?  If so and DPD_DELTE_ALL_FILE is set,
02144          *     then the delete should fail if **any** files overlap with 
02145          *     other drivers 
02146          * (2) If DPD_DELTE_UNUSED_FILES is sert, then delete all
02147          *     non-overlapping files 
02148          * (3) If neither DPD_DELTE_ALL_FILE nor DPD_DELTE_ALL_FILES
02149          *     is set, the do not delete any files
02150          * Refer to MSDN docs on DeletePrinterDriverEx() for details.
02151          */
02152         
02153         delete_files = flags & (DPD_DELETE_ALL_FILES|DPD_DELETE_UNUSED_FILES);
02154         
02155         /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */
02156                 
02157         if ( delete_files && printer_driver_files_in_use(info.info_3) & (flags&DPD_DELETE_ALL_FILES) ) {
02158                 /* no idea of the correct error here */
02159                 status = WERR_ACCESS_DENIED;    
02160                 goto done;
02161         }
02162 
02163                         
02164         /* also check for W32X86/3 if necessary; maybe we already have? */
02165                 
02166         if ( (version == 2) && ((flags&DPD_DELETE_SPECIFIC_VERSION) != DPD_DELETE_SPECIFIC_VERSION)  ) {
02167                 if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3, driver, arch, 3))) 
02168                 {
02169                         
02170                         if ( delete_files && printer_driver_files_in_use(info_win2k.info_3) & (flags&DPD_DELETE_ALL_FILES) ) {
02171                                 /* no idea of the correct error here */
02172                                 free_a_printer_driver( info_win2k, 3 );
02173                                 status = WERR_ACCESS_DENIED;    
02174                                 goto done;
02175                         }
02176                 
02177                         /* if we get to here, we now have 2 driver info structures to remove */
02178                         /* remove the Win2k driver first*/
02179                 
02180                         status_win2k = delete_printer_driver(info_win2k.info_3, &user, 3, delete_files);
02181                         free_a_printer_driver( info_win2k, 3 );
02182                                 
02183                         /* this should not have failed---if it did, report to client */
02184                                 
02185                         if ( !W_ERROR_IS_OK(status_win2k) )
02186                                 goto done;
02187                 }
02188         }
02189 
02190         status = delete_printer_driver(info.info_3, &user, version, delete_files);
02191 
02192         if ( W_ERROR_IS_OK(status) || W_ERROR_IS_OK(status_win2k) )
02193                 status = WERR_OK;
02194 done:
02195         free_a_printer_driver( info, 3 );
02196         
02197         return status;
02198 }
02199 
02200 
02201 /****************************************************************************
02202  Internal routine for retreiving printerdata
02203  ***************************************************************************/
02204 
02205 static WERROR get_printer_dataex( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printer, 
02206                                   const char *key, const char *value, uint32 *type, uint8 **data, 
02207                                   uint32 *needed, uint32 in_size  )
02208 {
02209         REGISTRY_VALUE          *val;
02210         uint32                  size;
02211         int                     data_len;
02212         
02213         if ( !(val = get_printer_data( printer->info_2, key, value)) )
02214                 return WERR_BADFILE;
02215         
02216         *type = regval_type( val );
02217 
02218         DEBUG(5,("get_printer_dataex: allocating %d\n", in_size));
02219 
02220         size = regval_size( val );
02221         
02222         /* copy the min(in_size, len) */
02223         
02224         if ( in_size ) {
02225                 data_len = (size > in_size) ? in_size : size*sizeof(uint8);
02226                 
02227                 /* special case for 0 length values */
02228                 if ( data_len ) {
02229                         if ( (*data  = (uint8 *)TALLOC_MEMDUP(ctx, regval_data_p(val), data_len)) == NULL )
02230                                 return WERR_NOMEM;
02231                 }
02232                 else {
02233                         if ( (*data  = (uint8 *)TALLOC_ZERO(ctx, in_size)) == NULL )
02234                                 return WERR_NOMEM;
02235                 }
02236         }
02237         else
02238                 *data = NULL;
02239 
02240         *needed = size;
02241         
02242         DEBUG(5,("get_printer_dataex: copy done\n"));
02243 
02244         return WERR_OK;
02245 }
02246 
02247 /****************************************************************************
02248  Internal routine for removing printerdata
02249  ***************************************************************************/
02250 
02251 static WERROR delete_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value )
02252 {
02253         return delete_printer_data( printer->info_2, key, value );
02254 }
02255 
02256 /****************************************************************************
02257  Internal routine for storing printerdata
02258  ***************************************************************************/
02259 
02260 WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, const char *value, 
02261                                   uint32 type, uint8 *data, int real_len  )
02262 {
02263         /* the registry objects enforce uniqueness based on value name */
02264 
02265         return add_printer_data( printer->info_2, key, value, type, data, real_len );
02266 }
02267 
02268 /********************************************************************
02269  GetPrinterData on a printer server Handle.
02270 ********************************************************************/
02271 
02272 static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint32 *type, uint8 **data, uint32 *needed, uint32 in_size)
02273 {               
02274         int i;
02275         
02276         DEBUG(8,("getprinterdata_printer_server:%s\n", value));
02277                 
02278         if (!StrCaseCmp(value, "W3SvcInstalled")) {
02279                 *type = REG_DWORD;
02280                 if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
02281                         return WERR_NOMEM;
02282                 SIVAL(*data, 0, 0x00);
02283                 *needed = 0x4;
02284                 return WERR_OK;
02285         }
02286 
02287         if (!StrCaseCmp(value, "BeepEnabled")) {
02288                 *type = REG_DWORD;
02289                 if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
02290                         return WERR_NOMEM;
02291                 SIVAL(*data, 0, 0x00);
02292                 *needed = 0x4;                  
02293                 return WERR_OK;
02294         }
02295 
02296         if (!StrCaseCmp(value, "EventLog")) {
02297                 *type = REG_DWORD;
02298                 if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
02299                         return WERR_NOMEM;
02300                 /* formally was 0x1b */
02301                 SIVAL(*data, 0, 0x0);
02302                 *needed = 0x4;                  
02303                 return WERR_OK;
02304         }
02305 
02306         if (!StrCaseCmp(value, "NetPopup")) {
02307                 *type = REG_DWORD;
02308                 if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
02309                         return WERR_NOMEM;
02310                 SIVAL(*data, 0, 0x00);
02311                 *needed = 0x4;
02312                 return WERR_OK;
02313         }
02314 
02315         if (!StrCaseCmp(value, "MajorVersion")) {
02316                 *type = REG_DWORD;
02317                 if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
02318                         return WERR_NOMEM;
02319 
02320                 /* Windows NT 4.0 seems to not allow uploading of drivers
02321                    to a server that reports 0x3 as the MajorVersion.
02322                    need to investigate more how Win2k gets around this .
02323                    -- jerry */
02324 
02325                 if ( RA_WINNT == get_remote_arch() )
02326                         SIVAL(*data, 0, 2);
02327                 else
02328                         SIVAL(*data, 0, 3);
02329                 
02330                 *needed = 0x4;
02331                 return WERR_OK;
02332         }
02333 
02334         if (!StrCaseCmp(value, "MinorVersion")) {
02335                 *type = REG_DWORD;
02336                 if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
02337                         return WERR_NOMEM;
02338                 SIVAL(*data, 0, 0);
02339                 *needed = 0x4;
02340                 return WERR_OK;
02341         }
02342 
02343         /* REG_BINARY
02344          *  uint32 size          = 0x114
02345          *  uint32 major         = 5
02346          *  uint32 minor         = [0|1]
02347          *  uint32 build         = [2195|2600]
02348          *  extra unicode string = e.g. "Service Pack 3"
02349          */
02350         if (!StrCaseCmp(value, "OSVersion")) {
02351                 *type = REG_BINARY;
02352                 *needed = 0x114;
02353 
02354                 if ( !(*data = TALLOC_ZERO_ARRAY(ctx, uint8, (*needed > in_size) ? *needed:in_size )) )
02355                         return WERR_NOMEM;
02356 
02357                 SIVAL(*data, 0, *needed);       /* size */
02358                 SIVAL(*data, 4, 5);             /* Windows 2000 == 5.0 */
02359                 SIVAL(*data, 8, 0);
02360                 SIVAL(*data, 12, 2195);         /* build */
02361                 
02362                 /* leave extra string empty */
02363                 
02364                 return WERR_OK;
02365         }
02366 
02367 
02368         if (!StrCaseCmp(value, "DefaultSpoolDirectory")) {
02369                 const char *string="C:\\PRINTERS";
02370                 *type = REG_SZ;
02371                 *needed = 2*(strlen(string)+1);         
02372                 if((*data  = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
02373                         return WERR_NOMEM;
02374                 memset(*data, 0, (*needed > in_size) ? *needed:in_size);
02375                 
02376                 /* it's done by hand ready to go on the wire */
02377                 for (i=0; i<strlen(string); i++) {
02378                         (*data)[2*i]=string[i];
02379                         (*data)[2*i+1]='\0';
02380                 }                       
02381                 return WERR_OK;
02382         }
02383 
02384         if (!StrCaseCmp(value, "Architecture")) {                       
02385                 const char *string="Windows NT x86";
02386                 *type = REG_SZ;
02387                 *needed = 2*(strlen(string)+1); 
02388                 if((*data  = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
02389                         return WERR_NOMEM;
02390                 memset(*data, 0, (*needed > in_size) ? *needed:in_size);
02391                 for (i=0; i<strlen(string); i++) {
02392                         (*data)[2*i]=string[i];
02393                         (*data)[2*i+1]='\0';
02394                 }                       
02395                 return WERR_OK;
02396         }
02397 
02398         if (!StrCaseCmp(value, "DsPresent")) {
02399                 *type = REG_DWORD;
02400                 if ( !(*data = TALLOC_ARRAY(ctx, uint8, sizeof(uint32) )) )
02401                         return WERR_NOMEM;
02402 
02403                 /* only show the publish check box if we are a 
02404                    memeber of a AD domain */
02405 
02406                 if ( lp_security() == SEC_ADS )
02407                         SIVAL(*data, 0, 0x01);
02408                 else
02409                         SIVAL(*data, 0, 0x00);
02410 
02411                 *needed = 0x4;
02412                 return WERR_OK;
02413         }
02414 
02415         if (!StrCaseCmp(value, "DNSMachineName")) {                     
02416                 pstring hostname;
02417                 
02418                 if (!get_mydnsfullname(hostname))
02419                         return WERR_BADFILE;
02420                 *type = REG_SZ;
02421                 *needed = 2*(strlen(hostname)+1);       
02422                 if((*data  = (uint8 *)TALLOC(ctx, (*needed > in_size) ? *needed:in_size )) == NULL)
02423                         return WERR_NOMEM;
02424                 memset(*data, 0, (*needed > in_size) ? *needed:in_size);
02425                 for (i=0; i<strlen(hostname); i++) {
02426                         (*data)[2*i]=hostname[i];
02427                         (*data)[2*i+1]='\0';
02428                 }                       
02429                 return WERR_OK;
02430         }
02431 
02432 
02433         return WERR_BADFILE;
02434 }
02435 
02436 /********************************************************************
02437  * spoolss_getprinterdata
02438  ********************************************************************/
02439 
02440 WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPOOL_R_GETPRINTERDATA *r_u)
02441 {
02442         POLICY_HND      *handle = &q_u->handle;
02443         UNISTR2         *valuename = &q_u->valuename;
02444         uint32          in_size = q_u->size;
02445         uint32          *type = &r_u->type;
02446         uint32          *out_size = &r_u->size;
02447         uint8           **data = &r_u->data;
02448         uint32          *needed = &r_u->needed;
02449         WERROR          status;
02450         fstring         value;
02451         Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
02452         NT_PRINTER_INFO_LEVEL   *printer = NULL;
02453         int             snum = 0;
02454         
02455         /*
02456          * Reminder: when it's a string, the length is in BYTES
02457          * even if UNICODE is negociated.
02458          *
02459          * JFM, 4/19/1999
02460          */
02461 
02462         *out_size = in_size;
02463 
02464         /* in case of problem, return some default values */
02465         
02466         *needed = 0;
02467         *type   = 0;
02468         
02469         DEBUG(4,("_spoolss_getprinterdata\n"));
02470         
02471         if ( !Printer ) {
02472                 DEBUG(2,("_spoolss_getprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
02473                 status = WERR_BADFID;
02474                 goto done;
02475         }
02476         
02477         unistr2_to_ascii(value, valuename, sizeof(value)-1);
02478         
02479         if ( Printer->printer_type == SPLHND_SERVER )
02480                 status = getprinterdata_printer_server( p->mem_ctx, value, type, data, needed, *out_size );
02481         else
02482         {
02483                 if ( !get_printer_snum(p,handle, &snum) ) {
02484                         status = WERR_BADFID;
02485                         goto done;
02486                 }
02487 
02488                 status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
02489                 if ( !W_ERROR_IS_OK(status) )
02490                         goto done;
02491 
02492                 /* XP sends this and wants to change id value from the PRINTER_INFO_0 */
02493 
02494                 if ( strequal(value, "ChangeId") ) {
02495                         *type = REG_DWORD;
02496                         *needed = sizeof(uint32);
02497                         if ( (*data = (uint8*)TALLOC(p->mem_ctx, sizeof(uint32))) == NULL) {
02498                                 status = WERR_NOMEM;
02499                                 goto done;
02500                         }
02501                         SIVAL( *data, 0, printer->info_2->changeid );
02502                         status = WERR_OK;
02503                 }
02504                 else
02505                         status = get_printer_dataex( p->mem_ctx, printer, SPOOL_PRINTERDATA_KEY, value, type, data, needed, *out_size );
02506         }
02507 
02508         if (*needed > *out_size)
02509                 status = WERR_MORE_DATA;
02510         
02511 done:
02512         if ( !W_ERROR_IS_OK(status) ) 
02513         {
02514                 DEBUG(5, ("error %d: allocating %d\n", W_ERROR_V(status),*out_size));
02515                 
02516                 /* reply this param doesn't exist */
02517                 
02518                 if ( *out_size ) {
02519                         if((*data=(uint8 *)TALLOC_ZERO_ARRAY(p->mem_ctx, uint8, *out_size)) == NULL) {
02520                                 if ( printer ) 
02521                                         free_a_printer( &printer, 2 );
02522                                 return WERR_NOMEM;
02523                         } 
02524                 } else {
02525                         *data = NULL;
02526                 }
02527         }
02528         
02529         /* cleanup & exit */
02530 
02531         if ( printer )
02532                 free_a_printer( &printer, 2 );
02533         
02534         return status;
02535 }
02536 
02537 /*********************************************************
02538  Connect to the client machine.
02539 **********************************************************/
02540 
02541 static BOOL spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
02542                         struct in_addr *client_ip, const char *remote_machine)
02543 {
02544         NTSTATUS ret;
02545         struct cli_state *the_cli;
02546         struct in_addr rm_addr;
02547 
02548         if ( is_zero_ip(*client_ip) ) {
02549                 if ( !resolve_name( remote_machine, &rm_addr, 0x20) ) {
02550                         DEBUG(2,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine));
02551                         return False;
02552                 }
02553 
02554                 if ( ismyip( rm_addr )) {
02555                         DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
02556                         return False;
02557                 }
02558         } else {
02559                 rm_addr.s_addr = client_ip->s_addr;
02560                 DEBUG(5,("spoolss_connect_to_client: Using address %s (no name resolution necessary)\n",
02561                         inet_ntoa(*client_ip) ));
02562         }
02563 
02564         /* setup the connection */
02565 
02566         ret = cli_full_connection( &the_cli, global_myname(), remote_machine, 
02567                 &rm_addr, 0, "IPC$", "IPC",
02568                 "", /* username */
02569                 "", /* domain */
02570                 "", /* password */
02571                 0, lp_client_signing(), NULL );
02572 
02573         if ( !NT_STATUS_IS_OK( ret ) ) {
02574                 DEBUG(2,("spoolss_connect_to_client: connection to [%s] failed!\n", 
02575                         remote_machine ));
02576                 return False;
02577         }       
02578                 
02579         if ( the_cli->protocol != PROTOCOL_NT1 ) {
02580                 DEBUG(0,("spoolss_connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
02581                 cli_shutdown(the_cli);
02582                 return False;
02583         }
02584     
02585         /*
02586          * Ok - we have an anonymous connection to the IPC$ share.
02587          * Now start the NT Domain stuff :-).
02588          */
02589 
02590         if ( !(*pp_pipe = cli_rpc_pipe_open_noauth(the_cli, PI_SPOOLSS, &ret)) ) {
02591                 DEBUG(2,("spoolss_connect_to_client: unable to open the spoolss pipe on machine %s. Error was : %s.\n",
02592                         remote_machine, nt_errstr(ret)));
02593                 cli_shutdown(the_cli);
02594                 return False;
02595         } 
02596 
02597         /* make sure to save the cli_state pointer.  Keep its own talloc_ctx */
02598 
02599         (*pp_pipe)->cli = the_cli;
02600 
02601         return True;
02602 }
02603 
02604 /***************************************************************************
02605  Connect to the client.
02606 ****************************************************************************/
02607 
02608 static BOOL srv_spoolss_replyopenprinter(int snum, const char *printer, 
02609                                         uint32 localprinter, uint32 type, 
02610                                         POLICY_HND *handle, struct in_addr *client_ip)
02611 {
02612         WERROR result;
02613 
02614         /*
02615          * If it's the first connection, contact the client
02616          * and connect to the IPC$ share anonymously
02617          */
02618         if (smb_connections==0) {
02619                 fstring unix_printer;
02620 
02621                 fstrcpy(unix_printer, printer+2); /* the +2 is to strip the leading 2 backslashs */
02622 
02623                 if ( !spoolss_connect_to_client( &notify_cli_pipe, client_ip, unix_printer ))
02624                         return False;
02625                         
02626                 message_register(MSG_PRINTER_NOTIFY2,
02627                                  receive_notify2_message_list, NULL);
02628                 /* Tell the connections db we're now interested in printer
02629                  * notify messages. */
02630                 register_message_flags( True, FLAG_MSG_PRINT_NOTIFY );
02631         }
02632 
02633         /* 
02634          * Tell the specific printing tdb we want messages for this printer
02635          * by registering our PID.
02636          */
02637 
02638         if (!print_notify_register_pid(snum))
02639                 DEBUG(0,("print_notify_register_pid: Failed to register our pid for printer %s\n", printer ));
02640 
02641         smb_connections++;
02642 
02643         result = rpccli_spoolss_reply_open_printer(notify_cli_pipe, notify_cli_pipe->cli->mem_ctx, printer, localprinter, 
02644                         type, handle);
02645                         
02646         if (!W_ERROR_IS_OK(result))
02647                 DEBUG(5,("srv_spoolss_reply_open_printer: Client RPC returned [%s]\n",
02648                         dos_errstr(result)));
02649 
02650         return (W_ERROR_IS_OK(result)); 
02651 }
02652 
02653 /********************************************************************
02654  * _spoolss_rffpcnex
02655  * ReplyFindFirstPrinterChangeNotifyEx
02656  *
02657  * before replying OK: status=0 a rpc call is made to the workstation
02658  * asking ReplyOpenPrinter 
02659  *
02660  * in fact ReplyOpenPrinter is the changenotify equivalent on the spoolss pipe
02661  * called from api_spoolss_rffpcnex
02662  ********************************************************************/
02663 
02664 WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNEX *r_u)
02665 {
02666         POLICY_HND *handle = &q_u->handle;
02667         uint32 flags = q_u->flags;
02668         uint32 options = q_u->options;
02669         UNISTR2 *localmachine = &q_u->localmachine;
02670         uint32 printerlocal = q_u->printerlocal;
02671         int snum = -1;
02672         SPOOL_NOTIFY_OPTION *option = q_u->option;
02673         struct in_addr client_ip;
02674 
02675         /* store the notify value in the printer struct */
02676 
02677         Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
02678 
02679         if (!Printer) {
02680                 DEBUG(2,("_spoolss_rffpcnex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
02681                 return WERR_BADFID;
02682         }
02683 
02684         Printer->notify.flags=flags;
02685         Printer->notify.options=options;
02686         Printer->notify.printerlocal=printerlocal;
02687 
02688         if (Printer->notify.option)
02689                 free_spool_notify_option(&Printer->notify.option);
02690 
02691         Printer->notify.option=dup_spool_notify_option(option);
02692 
02693         unistr2_to_ascii(Printer->notify.localmachine, localmachine, 
02694                        sizeof(Printer->notify.localmachine)-1);
02695 
02696         /* Connect to the client machine and send a ReplyOpenPrinter */
02697 
02698         if ( Printer->printer_type == SPLHND_SERVER)
02699                 snum = -1;
02700         else if ( (Printer->printer_type == SPLHND_PRINTER) &&
02701                         !get_printer_snum(p, handle, &snum) )
02702                 return WERR_BADFID;
02703                 
02704         client_ip.s_addr = inet_addr(p->conn->client_address);
02705 
02706         if(!srv_spoolss_replyopenprinter(snum, Printer->notify.localmachine,
02707                                         Printer->notify.printerlocal, 1,
02708                                         &Printer->notify.client_hnd, &client_ip))
02709                 return WERR_SERVER_UNAVAILABLE;
02710 
02711         Printer->notify.client_connected=True;
02712 
02713         return WERR_OK;
02714 }
02715 
02716 /*******************************************************************
02717  * fill a notify_info_data with the servername
02718  ********************************************************************/
02719 
02720 void spoolss_notify_server_name(int snum, 
02721                                        SPOOL_NOTIFY_INFO_DATA *data, 
02722                                        print_queue_struct *queue,
02723                                        NT_PRINTER_INFO_LEVEL *printer,
02724                                        TALLOC_CTX *mem_ctx) 
02725 {
02726         pstring temp;
02727         uint32 len;
02728 
02729         len = rpcstr_push(temp, printer->info_2->servername, sizeof(temp)-2, STR_TERMINATE);
02730 
02731         data->notify_data.data.length = len;
02732         if (len) {
02733                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
02734                 if (!data->notify_data.data.string) {
02735                         data->notify_data.data.length = 0;
02736                         return;
02737                 }
02738         
02739                 memcpy(data->notify_data.data.string, temp, len);
02740         } else {
02741                 data->notify_data.data.string = NULL;
02742         }
02743 }
02744 
02745 /*******************************************************************
02746  * fill a notify_info_data with the printername (not including the servername).
02747  ********************************************************************/
02748 
02749 void spoolss_notify_printer_name(int snum, 
02750                                         SPOOL_NOTIFY_INFO_DATA *data, 
02751                                         print_queue_struct *queue,
02752                                         NT_PRINTER_INFO_LEVEL *printer,
02753                                         TALLOC_CTX *mem_ctx)
02754 {
02755         pstring temp;
02756         uint32 len;
02757                 
02758         /* the notify name should not contain the \\server\ part */
02759         char *p = strrchr(printer->info_2->printername, '\\');
02760 
02761         if (!p) {
02762                 p = printer->info_2->printername;
02763         } else {
02764                 p++;
02765         }
02766 
02767         len = rpcstr_push(temp, p, sizeof(temp)-2, STR_TERMINATE);
02768 
02769         data->notify_data.data.length = len;
02770         if (len) {
02771                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
02772                 if (!data->notify_data.data.string) {
02773                         data->notify_data.data.length = 0;
02774                         return;
02775                 }
02776                 memcpy(data->notify_data.data.string, temp, len);
02777         } else {
02778                 data->notify_data.data.string = NULL;
02779         }
02780 }
02781 
02782 /*******************************************************************
02783  * fill a notify_info_data with the servicename
02784  ********************************************************************/
02785 
02786 void spoolss_notify_share_name(int snum, 
02787                                       SPOOL_NOTIFY_INFO_DATA *data, 
02788                                       print_queue_struct *queue,
02789                                       NT_PRINTER_INFO_LEVEL *printer,
02790                                       TALLOC_CTX *mem_ctx)
02791 {
02792         pstring temp;
02793         uint32 len;
02794 
02795         len = rpcstr_push(temp, lp_servicename(snum), sizeof(temp)-2, STR_TERMINATE);
02796 
02797         data->notify_data.data.length = len;
02798         if (len) {
02799                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
02800                 if (!data->notify_data.data.string) {
02801                         data->notify_data.data.length = 0;
02802                         return;
02803                 }
02804                 memcpy(data->notify_data.data.string, temp, len);
02805         } else {
02806                 data->notify_data.data.string = NULL;
02807         }
02808         
02809 }
02810 
02811 /*******************************************************************
02812  * fill a notify_info_data with the port name
02813  ********************************************************************/
02814 
02815 void spoolss_notify_port_name(int snum, 
02816                                      SPOOL_NOTIFY_INFO_DATA *data, 
02817                                      print_queue_struct *queue,
02818                                      NT_PRINTER_INFO_LEVEL *printer,
02819                                      TALLOC_CTX *mem_ctx)
02820 {
02821         pstring temp;
02822         uint32 len;
02823 
02824         /* even if it's strange, that's consistant in all the code */
02825 
02826         len = rpcstr_push(temp, printer->info_2->portname, sizeof(temp)-2, STR_TERMINATE);
02827 
02828         data->notify_data.data.length = len;
02829         if (len) {
02830                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
02831         
02832                 if (!data->notify_data.data.string) {
02833                         data->notify_data.data.length = 0;
02834                         return;
02835                 }
02836         
02837                 memcpy(data->notify_data.data.string, temp, len);
02838         } else {
02839                 data->notify_data.data.string = NULL;
02840         }
02841 }
02842 
02843 /*******************************************************************
02844  * fill a notify_info_data with the printername
02845  * but it doesn't exist, have to see what to do
02846  ********************************************************************/
02847 
02848 void spoolss_notify_driver_name(int snum, 
02849                                        SPOOL_NOTIFY_INFO_DATA *data,
02850                                        print_queue_struct *queue,
02851                                        NT_PRINTER_INFO_LEVEL *printer,
02852                                        TALLOC_CTX *mem_ctx)
02853 {
02854         pstring temp;
02855         uint32 len;
02856 
02857         len = rpcstr_push(temp, printer->info_2->drivername, sizeof(temp)-2, STR_TERMINATE);
02858 
02859         data->notify_data.data.length = len;
02860         if (len) {
02861                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
02862         
02863                 if (!data->notify_data.data.string) {
02864                         data->notify_data.data.length = 0;
02865                         return;
02866                 }
02867         
02868                 memcpy(data->notify_data.data.string, temp, len);
02869         } else {
02870                 data->notify_data.data.string = NULL;
02871         }
02872 }
02873 
02874 /*******************************************************************
02875  * fill a notify_info_data with the comment
02876  ********************************************************************/
02877 
02878 void spoolss_notify_comment(int snum, 
02879                                    SPOOL_NOTIFY_INFO_DATA *data,
02880                                    print_queue_struct *queue,
02881                                    NT_PRINTER_INFO_LEVEL *printer,
02882                                    TALLOC_CTX *mem_ctx)
02883 {
02884         pstring temp;
02885         uint32 len;
02886 
02887         if (*printer->info_2->comment == '\0')
02888                 len = rpcstr_push(temp, lp_comment(snum), sizeof(temp)-2, STR_TERMINATE);
02889         else
02890                 len = rpcstr_push(temp, printer->info_2->comment, sizeof(temp)-2, STR_TERMINATE);
02891 
02892         data->notify_data.data.length = len;
02893         if (len) {
02894                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
02895         
02896                 if (!data->notify_data.data.string) {
02897                         data->notify_data.data.length = 0;
02898                         return;
02899                 }
02900         
02901                 memcpy(data->notify_data.data.string, temp, len);
02902         } else {
02903                 data->notify_data.data.string = NULL;
02904         }
02905 }
02906 
02907 /*******************************************************************
02908  * fill a notify_info_data with the comment
02909  * location = "Room 1, floor 2, building 3"
02910  ********************************************************************/
02911 
02912 void spoolss_notify_location(int snum, 
02913                                     SPOOL_NOTIFY_INFO_DATA *data,
02914                                     print_queue_struct *queue,
02915                                     NT_PRINTER_INFO_LEVEL *printer,
02916                                     TALLOC_CTX *mem_ctx)
02917 {
02918         pstring temp;
02919         uint32 len;
02920 
02921         len = rpcstr_push(temp, printer->info_2->location,sizeof(temp)-2, STR_TERMINATE);
02922 
02923         data->notify_data.data.length = len;
02924         if (len) {
02925                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
02926         
02927                 if (!data->notify_data.data.string) {
02928                         data->notify_data.data.length = 0;
02929                         return;
02930                 }
02931         
02932                 memcpy(data->notify_data.data.string, temp, len);
02933         } else {
02934                 data->notify_data.data.string = NULL;
02935         }
02936 }
02937 
02938 /*******************************************************************
02939  * fill a notify_info_data with the device mode
02940  * jfm:xxxx don't to it for know but that's a real problem !!!
02941  ********************************************************************/
02942 
02943 static void spoolss_notify_devmode(int snum, 
02944                                    SPOOL_NOTIFY_INFO_DATA *data,
02945                                    print_queue_struct *queue,
02946                                    NT_PRINTER_INFO_LEVEL *printer,
02947                                    TALLOC_CTX *mem_ctx)
02948 {
02949         /* for a dummy implementation we have to zero the fields */
02950         data->notify_data.data.length = 0;
02951         data->notify_data.data.string = NULL;
02952 }
02953 
02954 /*******************************************************************
02955  * fill a notify_info_data with the separator file name
02956  ********************************************************************/
02957 
02958 void spoolss_notify_sepfile(int snum, 
02959                                    SPOOL_NOTIFY_INFO_DATA *data, 
02960                                    print_queue_struct *queue,
02961                                    NT_PRINTER_INFO_LEVEL *printer,
02962                                    TALLOC_CTX *mem_ctx)
02963 {
02964         pstring temp;
02965         uint32 len;
02966 
02967         len = rpcstr_push(temp, printer->info_2->sepfile, sizeof(temp)-2, STR_TERMINATE);
02968 
02969         data->notify_data.data.length = len;
02970         if (len) {
02971                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
02972         
02973                 if (!data->notify_data.data.string) {
02974                         data->notify_data.data.length = 0;
02975                         return;
02976                 }
02977         
02978                 memcpy(data->notify_data.data.string, temp, len);
02979         } else {
02980                 data->notify_data.data.string = NULL;
02981         }
02982 }
02983 
02984 /*******************************************************************
02985  * fill a notify_info_data with the print processor
02986  * jfm:xxxx return always winprint to indicate we don't do anything to it
02987  ********************************************************************/
02988 
02989 void spoolss_notify_print_processor(int snum, 
02990                                            SPOOL_NOTIFY_INFO_DATA *data,
02991                                            print_queue_struct *queue,
02992                                            NT_PRINTER_INFO_LEVEL *printer,
02993                                            TALLOC_CTX *mem_ctx)
02994 {
02995         pstring temp;
02996         uint32 len;
02997 
02998         len = rpcstr_push(temp,  printer->info_2->printprocessor, sizeof(temp)-2, STR_TERMINATE);
02999 
03000         data->notify_data.data.length = len;
03001         if (len) {
03002                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
03003         
03004                 if (!data->notify_data.data.string) {
03005                         data->notify_data.data.length = 0;
03006                         return;
03007                 }
03008         
03009                 memcpy(data->notify_data.data.string, temp, len);
03010         } else {
03011                 data->notify_data.data.string = NULL;
03012         }
03013 }
03014 
03015 /*******************************************************************
03016  * fill a notify_info_data with the print processor options
03017  * jfm:xxxx send an empty string
03018  ********************************************************************/
03019 
03020 void spoolss_notify_parameters(int snum, 
03021                                       SPOOL_NOTIFY_INFO_DATA *data,
03022                                       print_queue_struct *queue,
03023                                       NT_PRINTER_INFO_LEVEL *printer,
03024                                       TALLOC_CTX *mem_ctx)
03025 {
03026         pstring temp;
03027         uint32 len;
03028 
03029         len = rpcstr_push(temp,  printer->info_2->parameters, sizeof(temp)-2, STR_TERMINATE);
03030 
03031         data->notify_data.data.length = len;
03032         if (len) {
03033                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
03034         
03035                 if (!data->notify_data.data.string) {
03036                         data->notify_data.data.length = 0;
03037                         return;
03038                 }
03039         
03040                 memcpy(data->notify_data.data.string, temp, len);
03041         } else {
03042                 data->notify_data.data.string = NULL;
03043         }
03044 }
03045 
03046 /*******************************************************************
03047  * fill a notify_info_data with the data type
03048  * jfm:xxxx always send RAW as data type
03049  ********************************************************************/
03050 
03051 void spoolss_notify_datatype(int snum, 
03052                                     SPOOL_NOTIFY_INFO_DATA *data,
03053                                     print_queue_struct *queue,
03054                                     NT_PRINTER_INFO_LEVEL *printer,
03055                                     TALLOC_CTX *mem_ctx)
03056 {
03057         pstring temp;
03058         uint32 len;
03059 
03060         len = rpcstr_push(temp, printer->info_2->datatype, sizeof(pstring)-2, STR_TERMINATE);
03061 
03062         data->notify_data.data.length = len;
03063         if (len) {
03064                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
03065         
03066                 if (!data->notify_data.data.string) {
03067                         data->notify_data.data.length = 0;
03068                         return;
03069                 }
03070         
03071                 memcpy(data->notify_data.data.string, temp, len);
03072         } else {
03073                 data->notify_data.data.string = NULL;
03074         }
03075 }
03076 
03077 /*******************************************************************
03078  * fill a notify_info_data with the security descriptor
03079  * jfm:xxxx send an null pointer to say no security desc
03080  * have to implement security before !
03081  ********************************************************************/
03082 
03083 static void spoolss_notify_security_desc(int snum, 
03084                                          SPOOL_NOTIFY_INFO_DATA *data,
03085                                          print_queue_struct *queue,
03086                                          NT_PRINTER_INFO_LEVEL *printer,
03087                                          TALLOC_CTX *mem_ctx)
03088 {
03089         data->notify_data.sd.size = printer->info_2->secdesc_buf->len;
03090         data->notify_data.sd.desc = dup_sec_desc( mem_ctx, printer->info_2->secdesc_buf->sec ) ;
03091 }
03092 
03093 /*******************************************************************
03094  * fill a notify_info_data with the attributes
03095  * jfm:xxxx a samba printer is always shared
03096  ********************************************************************/
03097 
03098 void spoolss_notify_attributes(int snum, 
03099                                       SPOOL_NOTIFY_INFO_DATA *data,
03100                                       print_queue_struct *queue,
03101                                       NT_PRINTER_INFO_LEVEL *printer,
03102                                       TALLOC_CTX *mem_ctx)
03103 {
03104         data->notify_data.value[0] = printer->info_2->attributes;
03105         data->notify_data.value[1] = 0;
03106 }
03107 
03108 /*******************************************************************
03109  * fill a notify_info_data with the priority
03110  ********************************************************************/
03111 
03112 static void spoolss_notify_priority(int snum, 
03113                                     SPOOL_NOTIFY_INFO_DATA *data,
03114                                     print_queue_struct *queue,
03115                                     NT_PRINTER_INFO_LEVEL *printer,
03116                                     TALLOC_CTX *mem_ctx)
03117 {
03118         data->notify_data.value[0] = printer->info_2->priority;
03119         data->notify_data.value[1] = 0;
03120 }
03121 
03122 /*******************************************************************
03123  * fill a notify_info_data with the default priority
03124  ********************************************************************/
03125 
03126 static void spoolss_notify_default_priority(int snum, 
03127                                             SPOOL_NOTIFY_INFO_DATA *data,
03128                                             print_queue_struct *queue,
03129                                             NT_PRINTER_INFO_LEVEL *printer,
03130                                             TALLOC_CTX *mem_ctx)
03131 {
03132         data->notify_data.value[0] = printer->info_2->default_priority;
03133         data->notify_data.value[1] = 0;
03134 }
03135 
03136 /*******************************************************************
03137  * fill a notify_info_data with the start time
03138  ********************************************************************/
03139 
03140 static void spoolss_notify_start_time(int snum, 
03141                                       SPOOL_NOTIFY_INFO_DATA *data,
03142                                       print_queue_struct *queue,
03143                                       NT_PRINTER_INFO_LEVEL *printer,
03144                                       TALLOC_CTX *mem_ctx)
03145 {
03146         data->notify_data.value[0] = printer->info_2->starttime;
03147         data->notify_data.value[1] = 0;
03148 }
03149 
03150 /*******************************************************************
03151  * fill a notify_info_data with the until time
03152  ********************************************************************/
03153 
03154 static void spoolss_notify_until_time(int snum, 
03155                                       SPOOL_NOTIFY_INFO_DATA *data,
03156                                       print_queue_struct *queue,
03157                                       NT_PRINTER_INFO_LEVEL *printer,
03158                                       TALLOC_CTX *mem_ctx)
03159 {
03160         data->notify_data.value[0] = printer->info_2->untiltime;
03161         data->notify_data.value[1] = 0;
03162 }
03163 
03164 /*******************************************************************
03165  * fill a notify_info_data with the status
03166  ********************************************************************/
03167 
03168 static void spoolss_notify_status(int snum, 
03169                                   SPOOL_NOTIFY_INFO_DATA *data,
03170                                   print_queue_struct *queue,
03171                                   NT_PRINTER_INFO_LEVEL *printer,
03172                                   TALLOC_CTX *mem_ctx)
03173 {
03174         print_status_struct status;
03175 
03176         print_queue_length(snum, &status);
03177         data->notify_data.value[0]=(uint32) status.status;
03178         data->notify_data.value[1] = 0;
03179 }
03180 
03181 /*******************************************************************
03182  * fill a notify_info_data with the number of jobs queued
03183  ********************************************************************/
03184 
03185 void spoolss_notify_cjobs(int snum, 
03186                                  SPOOL_NOTIFY_INFO_DATA *data,
03187                                  print_queue_struct *queue,
03188                                  NT_PRINTER_INFO_LEVEL *printer, 
03189                                  TALLOC_CTX *mem_ctx)
03190 {
03191         data->notify_data.value[0] = print_queue_length(snum, NULL);
03192         data->notify_data.value[1] = 0;
03193 }
03194 
03195 /*******************************************************************
03196  * fill a notify_info_data with the average ppm
03197  ********************************************************************/
03198 
03199 static void spoolss_notify_average_ppm(int snum, 
03200                                        SPOOL_NOTIFY_INFO_DATA *data,
03201                                        print_queue_struct *queue,
03202                                        NT_PRINTER_INFO_LEVEL *printer,
03203                                        TALLOC_CTX *mem_ctx)
03204 {
03205         /* always respond 8 pages per minutes */
03206         /* a little hard ! */
03207         data->notify_data.value[0] = printer->info_2->averageppm;
03208         data->notify_data.value[1] = 0;
03209 }
03210 
03211 /*******************************************************************
03212  * fill a notify_info_data with username
03213  ********************************************************************/
03214 
03215 static void spoolss_notify_username(int snum, 
03216                                     SPOOL_NOTIFY_INFO_DATA *data,
03217                                     print_queue_struct *queue,
03218                                     NT_PRINTER_INFO_LEVEL *printer,
03219                                     TALLOC_CTX *mem_ctx)
03220 {
03221         pstring temp;
03222         uint32 len;
03223 
03224         len = rpcstr_push(temp, queue->fs_user, sizeof(temp)-2, STR_TERMINATE);
03225 
03226         data->notify_data.data.length = len;
03227         if (len) {
03228                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
03229         
03230                 if (!data->notify_data.data.string) {
03231                         data->notify_data.data.length = 0;
03232                         return;
03233                 }
03234         
03235                 memcpy(data->notify_data.data.string, temp, len);
03236         } else {
03237                 data->notify_data.data.string = NULL;
03238         }
03239 }
03240 
03241 /*******************************************************************
03242  * fill a notify_info_data with job status
03243  ********************************************************************/
03244 
03245 static void spoolss_notify_job_status(int snum, 
03246                                       SPOOL_NOTIFY_INFO_DATA *data,
03247                                       print_queue_struct *queue,
03248                                       NT_PRINTER_INFO_LEVEL *printer,
03249                                       TALLOC_CTX *mem_ctx)
03250 {
03251         data->notify_data.value[0]=nt_printj_status(queue->status);
03252         data->notify_data.value[1] = 0;
03253 }
03254 
03255 /*******************************************************************
03256  * fill a notify_info_data with job name
03257  ********************************************************************/
03258 
03259 static void spoolss_notify_job_name(int snum, 
03260                                     SPOOL_NOTIFY_INFO_DATA *data,
03261                                     print_queue_struct *queue,
03262                                     NT_PRINTER_INFO_LEVEL *printer,
03263                                     TALLOC_CTX *mem_ctx)
03264 {
03265         pstring temp;
03266         uint32 len;
03267 
03268         len = rpcstr_push(temp, queue->fs_file, sizeof(temp)-2, STR_TERMINATE);
03269 
03270         data->notify_data.data.length = len;
03271         if (len) {
03272                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
03273         
03274                 if (!data->notify_data.data.string) {
03275                         data->notify_data.data.length = 0;
03276                         return;
03277                 }
03278         
03279                 memcpy(data->notify_data.data.string, temp, len);
03280         } else {
03281                 data->notify_data.data.string = NULL;
03282         }
03283 }
03284 
03285 /*******************************************************************
03286  * fill a notify_info_data with job status
03287  ********************************************************************/
03288 
03289 static void spoolss_notify_job_status_string(int snum, 
03290                                              SPOOL_NOTIFY_INFO_DATA *data,
03291                                              print_queue_struct *queue,
03292                                              NT_PRINTER_INFO_LEVEL *printer, 
03293                                              TALLOC_CTX *mem_ctx)
03294 {
03295         /*
03296          * Now we're returning job status codes we just return a "" here. JRA.
03297          */
03298 
03299         const char *p = "";
03300         pstring temp;
03301         uint32 len;
03302 
03303 #if 0 /* NO LONGER NEEDED - JRA. 02/22/2001 */
03304         p = "unknown";
03305 
03306         switch (queue->status) {
03307         case LPQ_QUEUED:
03308                 p = "Queued";
03309                 break;
03310         case LPQ_PAUSED:
03311                 p = "";    /* NT provides the paused string */
03312                 break;
03313         case LPQ_SPOOLING:
03314                 p = "Spooling";
03315                 break;
03316         case LPQ_PRINTING:
03317                 p = "Printing";
03318                 break;
03319         }
03320 #endif /* NO LONGER NEEDED. */
03321 
03322         len = rpcstr_push(temp, p, sizeof(temp) - 2, STR_TERMINATE);
03323 
03324         data->notify_data.data.length = len;
03325         if (len) {
03326                 data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
03327         
03328                 if (!data->notify_data.data.string) {
03329                         data->notify_data.data.length = 0;
03330                         return;
03331                 }
03332         
03333                 memcpy(data->notify_data.data.string, temp, len);
03334         } else {
03335                 data->notify_data.data.string = NULL;
03336         }
03337 }
03338 
03339 /*******************************************************************
03340  * fill a notify_info_data with job time
03341  ********************************************************************/
03342 
03343 static void spoolss_notify_job_time(int snum, 
03344                                     SPOOL_NOTIFY_INFO_DATA *data,
03345                                     print_queue_struct *queue,
03346                                     NT_PRINTER_INFO_LEVEL *printer,
03347                                     TALLOC_CTX *mem_ctx)
03348 {
03349         data->notify_data.value[0]=0x0;
03350         data->notify_data.value[1]=0;
03351 }
03352 
03353 /*******************************************************************
03354  * fill a notify_info_data with job size
03355  ********************************************************************/
03356 
03357 static void spoolss_notify_job_size(int snum, 
03358                                     SPOOL_NOTIFY_INFO_DATA *data,
03359                                     print_queue_struct *queue,
03360                                     NT_PRINTER_INFO_LEVEL *printer,
03361                                     TALLOC_CTX *mem_ctx)
03362 {
03363         data->notify_data.value[0]=queue->size;
03364         data->notify_data.value[1]=0;
03365 }
03366 
03367 /*******************************************************************
03368  * fill a notify_info_data with page info
03369  ********************************************************************/
03370 static void spoolss_notify_total_pages(int snum,
03371                                 SPOOL_NOTIFY_INFO_DATA *data,
03372                                 print_queue_struct *queue,
03373                                 NT_PRINTER_INFO_LEVEL *printer,
03374                                 TALLOC_CTX *mem_ctx)
03375 {
03376         data->notify_data.value[0]=queue->page_count;
03377         data->notify_data.value[1]=0;
03378 }
03379 
03380 /*******************************************************************
03381  * fill a notify_info_data with pages printed info.
03382  ********************************************************************/
03383 static void spoolss_notify_pages_printed(int snum,
03384                                 SPOOL_NOTIFY_INFO_DATA *data,
03385                                 print_queue_struct *queue,
03386                                 NT_PRINTER_INFO_LEVEL *printer,
03387                                 TALLOC_CTX *mem_ctx)
03388 {
03389         data->notify_data.value[0]=0;  /* Add code when back-end tracks this */
03390         data->notify_data.value[1]=0;
03391 }
03392 
03393 /*******************************************************************
03394  Fill a notify_info_data with job position.
03395  ********************************************************************/
03396 
03397 static void spoolss_notify_job_position(int snum, 
03398                                         SPOOL_NOTIFY_INFO_DATA *data,
03399                                         print_queue_struct *queue,
03400                                         NT_PRINTER_INFO_LEVEL *printer,
03401                                         TALLOC_CTX *mem_ctx)
03402 {
03403         data->notify_data.value[0]=queue->job;
03404         data->notify_data.value[1]=0;
03405 }
03406 
03407 /*******************************************************************
03408  Fill a notify_info_data with submitted time.
03409  ********************************************************************/
03410 
03411 static void spoolss_notify_submitted_time(int snum, 
03412                                           SPOOL_NOTIFY_INFO_DATA *data,
03413                                           print_queue_struct *queue,
03414                                           NT_PRINTER_INFO_LEVEL *printer,
03415                                           TALLOC_CTX *mem_ctx)
03416 {
03417         struct tm *t;
03418         uint32 len;
03419         SYSTEMTIME st;
03420         char *p;
03421 
03422         t=gmtime(&queue->time);
03423 
03424         len = sizeof(SYSTEMTIME);
03425 
03426         data->notify_data.data.length = len;
03427         data->notify_data.data.string = (uint16 *)TALLOC(mem_ctx, len);
03428 
03429         if (!data->notify_data.data.string) {
03430                 data->notify_data.data.length = 0;
03431                 return;
03432         }
03433         
03434         make_systemtime(&st, t);
03435 
03436         /*
03437          * Systemtime must be linearized as a set of UINT16's. 
03438          * Fix from Benjamin (Bj) Kuit bj@it.uts.edu.au
03439          */
03440 
03441         p = (char *)data->notify_data.data.string;
03442         SSVAL(p, 0, st.year);
03443         SSVAL(p, 2, st.month);
03444         SSVAL(p, 4, st.dayofweek);
03445         SSVAL(p, 6, st.day);
03446         SSVAL(p, 8, st.hour);
03447         SSVAL(p, 10, st.minute);
03448         SSVAL(p, 12, st.second);
03449         SSVAL(p, 14, st.milliseconds);
03450 }
03451 
03452 struct s_notify_info_data_table
03453 {
03454         uint16 type;
03455         uint16 field;
03456         const char *name;
03457         uint32 size;
03458         void (*fn) (int snum, SPOOL_NOTIFY_INFO_DATA *data,
03459                     print_queue_struct *queue,
03460                     NT_PRINTER_INFO_LEVEL *printer, TALLOC_CTX *mem_ctx);
03461 };
03462 
03463 /* A table describing the various print notification constants and
03464    whether the notification data is a pointer to a variable sized
03465    buffer, a one value uint32 or a two value uint32. */
03466 
03467 static const struct s_notify_info_data_table notify_info_data_table[] =
03468 {
03469 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME,         "PRINTER_NOTIFY_SERVER_NAME",         NOTIFY_STRING,   spoolss_notify_server_name },
03470 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME,        "PRINTER_NOTIFY_PRINTER_NAME",        NOTIFY_STRING,   spoolss_notify_printer_name },
03471 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME,          "PRINTER_NOTIFY_SHARE_NAME",          NOTIFY_STRING,   spoolss_notify_share_name },
03472 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME,           "PRINTER_NOTIFY_PORT_NAME",           NOTIFY_STRING,   spoolss_notify_port_name },
03473 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME,         "PRINTER_NOTIFY_DRIVER_NAME",         NOTIFY_STRING,   spoolss_notify_driver_name },
03474 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT,             "PRINTER_NOTIFY_COMMENT",             NOTIFY_STRING,   spoolss_notify_comment },
03475 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION,            "PRINTER_NOTIFY_LOCATION",            NOTIFY_STRING,   spoolss_notify_location },
03476 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEVMODE,             "PRINTER_NOTIFY_DEVMODE",             NOTIFY_POINTER,   spoolss_notify_devmode },
03477 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SEPFILE,             "PRINTER_NOTIFY_SEPFILE",             NOTIFY_STRING,   spoolss_notify_sepfile },
03478 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINT_PROCESSOR,     "PRINTER_NOTIFY_PRINT_PROCESSOR",     NOTIFY_STRING,   spoolss_notify_print_processor },
03479 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PARAMETERS,          "PRINTER_NOTIFY_PARAMETERS",          NOTIFY_STRING,   spoolss_notify_parameters },
03480 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DATATYPE,            "PRINTER_NOTIFY_DATATYPE",            NOTIFY_STRING,   spoolss_notify_datatype },
03481 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SECURITY_DESCRIPTOR, "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", NOTIFY_SECDESC,   spoolss_notify_security_desc },
03482 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_ATTRIBUTES,          "PRINTER_NOTIFY_ATTRIBUTES",          NOTIFY_ONE_VALUE, spoolss_notify_attributes },
03483 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRIORITY,            "PRINTER_NOTIFY_PRIORITY",            NOTIFY_ONE_VALUE, spoolss_notify_priority },
03484 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEFAULT_PRIORITY,    "PRINTER_NOTIFY_DEFAULT_PRIORITY",    NOTIFY_ONE_VALUE, spoolss_notify_default_priority },
03485 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_START_TIME,          "PRINTER_NOTIFY_START_TIME",          NOTIFY_ONE_VALUE, spoolss_notify_start_time },
03486 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_UNTIL_TIME,          "PRINTER_NOTIFY_UNTIL_TIME",          NOTIFY_ONE_VALUE, spoolss_notify_until_time },
03487 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS,              "PRINTER_NOTIFY_STATUS",              NOTIFY_ONE_VALUE, spoolss_notify_status },
03488 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_STATUS_STRING,       "PRINTER_NOTIFY_STATUS_STRING",       NOTIFY_POINTER,   NULL },
03489 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_CJOBS,               "PRINTER_NOTIFY_CJOBS",               NOTIFY_ONE_VALUE, spoolss_notify_cjobs },
03490 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_AVERAGE_PPM,         "PRINTER_NOTIFY_AVERAGE_PPM",         NOTIFY_ONE_VALUE, spoolss_notify_average_ppm },
03491 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_PAGES,         "PRINTER_NOTIFY_TOTAL_PAGES",         NOTIFY_POINTER,   NULL },
03492 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PAGES_PRINTED,       "PRINTER_NOTIFY_PAGES_PRINTED",       NOTIFY_POINTER,   NULL },
03493 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_BYTES,         "PRINTER_NOTIFY_TOTAL_BYTES",         NOTIFY_POINTER,   NULL },
03494 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_BYTES_PRINTED,       "PRINTER_NOTIFY_BYTES_PRINTED",       NOTIFY_POINTER,   NULL },
03495 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINTER_NAME,            "JOB_NOTIFY_PRINTER_NAME",            NOTIFY_STRING,   spoolss_notify_printer_name },
03496 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_MACHINE_NAME,            "JOB_NOTIFY_MACHINE_NAME",            NOTIFY_STRING,   spoolss_notify_server_name },
03497 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PORT_NAME,               "JOB_NOTIFY_PORT_NAME",               NOTIFY_STRING,   spoolss_notify_port_name },
03498 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_USER_NAME,               "JOB_NOTIFY_USER_NAME",               NOTIFY_STRING,   spoolss_notify_username },
03499 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_NOTIFY_NAME,             "JOB_NOTIFY_NOTIFY_NAME",             NOTIFY_STRING,   spoolss_notify_username },
03500 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_DATATYPE,                "JOB_NOTIFY_DATATYPE",                NOTIFY_STRING,   spoolss_notify_datatype },
03501 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINT_PROCESSOR,         "JOB_NOTIFY_PRINT_PROCESSOR",         NOTIFY_STRING,   spoolss_notify_print_processor },
03502 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PARAMETERS,              "JOB_NOTIFY_PARAMETERS",              NOTIFY_STRING,   spoolss_notify_parameters },
03503 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_DRIVER_NAME,             "JOB_NOTIFY_DRIVER_NAME",             NOTIFY_STRING,   spoolss_notify_driver_name },
03504 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_DEVMODE,                 "JOB_NOTIFY_DEVMODE",                 NOTIFY_POINTER,   spoolss_notify_devmode },
03505 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS,                  "JOB_NOTIFY_STATUS",                  NOTIFY_ONE_VALUE, spoolss_notify_job_status },
03506 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS_STRING,           "JOB_NOTIFY_STATUS_STRING",           NOTIFY_STRING,   spoolss_notify_job_status_string },
03507 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_SECURITY_DESCRIPTOR,     "JOB_NOTIFY_SECURITY_DESCRIPTOR",     NOTIFY_POINTER,   NULL },
03508 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_DOCUMENT,                "JOB_NOTIFY_DOCUMENT",                NOTIFY_STRING,   spoolss_notify_job_name },
03509 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRIORITY,                "JOB_NOTIFY_PRIORITY",                NOTIFY_ONE_VALUE, spoolss_notify_priority },
03510 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_POSITION,                "JOB_NOTIFY_POSITION",                NOTIFY_ONE_VALUE, spoolss_notify_job_position },
03511 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_SUBMITTED,               "JOB_NOTIFY_SUBMITTED",               NOTIFY_POINTER,   spoolss_notify_submitted_time },
03512 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_START_TIME,              "JOB_NOTIFY_START_TIME",              NOTIFY_ONE_VALUE, spoolss_notify_start_time },
03513 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_UNTIL_TIME,              "JOB_NOTIFY_UNTIL_TIME",              NOTIFY_ONE_VALUE, spoolss_notify_until_time },
03514 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_TIME,                    "JOB_NOTIFY_TIME",                    NOTIFY_ONE_VALUE, spoolss_notify_job_time },
03515 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_PAGES,             "JOB_NOTIFY_TOTAL_PAGES",             NOTIFY_ONE_VALUE, spoolss_notify_total_pages },
03516 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PAGES_PRINTED,           "JOB_NOTIFY_PAGES_PRINTED",           NOTIFY_ONE_VALUE, spoolss_notify_pages_printed },
03517 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_BYTES,             "JOB_NOTIFY_TOTAL_BYTES",             NOTIFY_ONE_VALUE, spoolss_notify_job_size },
03518 { PRINT_TABLE_END, 0x0, NULL, 0x0, NULL },
03519 };
03520 
03521 /*******************************************************************
03522  Return the size of info_data structure.
03523 ********************************************************************/
03524 
03525 static uint32 size_of_notify_info_data(uint16 type, uint16 field)
03526 {
03527         int i=0;
03528 
03529         for (i = 0; i < (sizeof(notify_info_data_table)/sizeof(struct s_notify_info_data_table)); i++) {
03530                 if ( (notify_info_data_table[i].type == type)
03531                         && (notify_info_data_table[i].field == field) ) {
03532                         switch(notify_info_data_table[i].size) {
03533                                 case NOTIFY_ONE_VALUE:
03534                                 case NOTIFY_TWO_VALUE:
03535                                         return 1;
03536                                 case NOTIFY_STRING:
03537                                         return 2;
03538 
03539                                 /* The only pointer notify data I have seen on
03540                                    the wire is the submitted time and this has
03541                                    the notify size set to 4. -tpot */
03542 
03543                                 case NOTIFY_POINTER:
03544                                         return 4;
03545                                         
03546                                 case NOTIFY_SECDESC:
03547                                         return 5;
03548                         }
03549                 }
03550         }
03551 
03552         DEBUG(5, ("invalid notify data type %d/%d\n", type, field));
03553 
03554         return 0;
03555 }
03556 
03557 /*******************************************************************
03558  Return the type of notify_info_data.
03559 ********************************************************************/
03560 
03561 static uint32 type_of_notify_info_data(uint16 type, uint16 field)
03562 {
03563         uint32 i=0;
03564 
03565         for (i = 0; i < (sizeof(notify_info_data_table)/sizeof(struct s_notify_info_data_table)); i++) {
03566                 if (notify_info_data_table[i].type == type &&
03567                     notify_info_data_table[i].field == field)
03568                         return notify_info_data_table[i].size;
03569         }
03570 
03571         return 0;
03572 }
03573 
03574 /****************************************************************************
03575 ****************************************************************************/
03576 
03577 static BOOL search_notify(uint16 type, uint16 field, int *value)
03578 {       
03579         int i;
03580 
03581         for (i = 0; notify_info_data_table[i].type != PRINT_TABLE_END; i++) {
03582                 if (notify_info_data_table[i].type == type &&
03583                     notify_info_data_table[i].field == field &&
03584                     notify_info_data_table[i].fn != NULL) {
03585                         *value = i;
03586                         return True;
03587                 }
03588         }
03589         
03590         return False;   
03591 }
03592 
03593 /****************************************************************************
03594 ****************************************************************************/
03595 
03596 void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16 field, int id)
03597 {
03598         info_data->type     = type;
03599         info_data->field    = field;
03600         info_data->reserved = 0;
03601 
03602         info_data->size     = size_of_notify_info_data(type, field);
03603         info_data->enc_type = type_of_notify_info_data(type, field);
03604 
03605         info_data->id = id;
03606 }
03607 
03608 /*******************************************************************
03609  *
03610  * fill a notify_info struct with info asked
03611  *
03612  ********************************************************************/
03613 
03614 static BOOL construct_notify_printer_info(Printer_entry *print_hnd, SPOOL_NOTIFY_INFO *info, int
03615                                           snum, SPOOL_NOTIFY_OPTION_TYPE
03616                                           *option_type, uint32 id,
03617                                           TALLOC_CTX *mem_ctx) 
03618 {
03619         int field_num,j;
03620         uint16 type;
03621         uint16 field;
03622 
03623         SPOOL_NOTIFY_INFO_DATA *current_data;
03624         NT_PRINTER_INFO_LEVEL *printer = NULL;
03625         print_queue_struct *queue=NULL;
03626 
03627         type=option_type->type;
03628 
03629         DEBUG(4,("construct_notify_printer_info: Notify type: [%s], number of notify info: [%d] on printer: [%s]\n",
03630                 (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
03631                 option_type->count, lp_servicename(snum)));
03632         
03633         if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &printer, 2, lp_const_servicename(snum))))
03634                 return False;
03635 
03636         for(field_num=0; field_num<option_type->count; field_num++) {
03637                 field = option_type->fields[field_num];
03638                 
03639                 DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field));
03640 
03641                 if (!search_notify(type, field, &j) )
03642                         continue;
03643 
03644                 if((info->data=SMB_REALLOC_ARRAY(info->data, SPOOL_NOTIFY_INFO_DATA, info->count+1)) == NULL) {
03645                         DEBUG(2,("construct_notify_printer_info: failed to enlarge buffer info->data!\n"));
03646                         free_a_printer(&printer, 2);
03647                         return False;
03648                 }
03649 
03650                 current_data = &info->data[info->count];
03651 
03652                 construct_info_data(current_data, type, field, id);
03653 
03654                 DEBUG(10,("construct_notify_printer_info: calling [%s]  snum=%d  printername=[%s])\n",
03655                                 notify_info_data_table[j].name, snum, printer->info_2->printername ));
03656 
03657                 notify_info_data_table[j].fn(snum, current_data, queue,
03658                                              printer, mem_ctx);
03659 
03660                 info->count++;
03661         }
03662 
03663         free_a_printer(&printer, 2);
03664         return True;
03665 }
03666 
03667 /*******************************************************************
03668  *
03669  * fill a notify_info struct with info asked
03670  *
03671  ********************************************************************/
03672 
03673 static BOOL construct_notify_jobs_info(print_queue_struct *queue,
03674                                        SPOOL_NOTIFY_INFO *info,
03675                                        NT_PRINTER_INFO_LEVEL *printer,
03676                                        int snum, SPOOL_NOTIFY_OPTION_TYPE
03677                                        *option_type, uint32 id,
03678                                        TALLOC_CTX *mem_ctx) 
03679 {
03680         int field_num,j;
03681         uint16 type;
03682         uint16 field;
03683 
03684         SPOOL_NOTIFY_INFO_DATA *current_data;
03685         
03686         DEBUG(4,("construct_notify_jobs_info\n"));
03687         
03688         type = option_type->type;
03689 
03690         DEBUGADD(4,("Notify type: [%s], number of notify info: [%d]\n",
03691                 (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
03692                 option_type->count));
03693 
03694         for(field_num=0; field_num<option_type->count; field_num++) {
03695                 field = option_type->fields[field_num];
03696 
03697                 if (!search_notify(type, field, &j) )
03698                         continue;
03699 
03700                 if((info->data=SMB_REALLOC_ARRAY(info->data, SPOOL_NOTIFY_INFO_DATA, info->count+1)) == NULL) {
03701                         DEBUG(2,("construct_notify_jobs_info: failed to enlarg buffer info->data!\n"));
03702                         return False;
03703                 }
03704 
03705                 current_data=&(info->data[info->count]);
03706 
03707                 construct_info_data(current_data, type, field, id);
03708                 notify_info_data_table[j].fn(snum, current_data, queue,
03709                                              printer, mem_ctx);
03710                 info->count++;
03711         }
03712 
03713         return True;
03714 }
03715 
03716 /*
03717  * JFM: The enumeration is not that simple, it's even non obvious.
03718  *
03719  * let's take an example: I want to monitor the PRINTER SERVER for
03720  * the printer's name and the number of jobs currently queued.
03721  * So in the NOTIFY_OPTION, I have one NOTIFY_OPTION_TYPE structure.
03722  * Its type is PRINTER_NOTIFY_TYPE and it has 2 fields NAME and CJOBS.
03723  *
03724  * I have 3 printers on the back of my server.
03725  *
03726  * Now the response is a NOTIFY_INFO structure, with 6 NOTIFY_INFO_DATA
03727  * structures.
03728  *   Number     Data                    Id
03729  *      1       printer 1 name          1
03730  *      2       printer 1 cjob          1
03731  *      3       printer 2 name          2
03732  *      4       printer 2 cjob          2
03733  *      5       printer 3 name          3
03734  *      6       printer 3 name          3
03735  *
03736  * that's the print server case, the printer case is even worse.
03737  */
03738 
03739 /*******************************************************************
03740  *
03741  * enumerate all printers on the printserver
03742  * fill a notify_info struct with info asked
03743  *
03744  ********************************************************************/
03745 
03746 static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd, 
03747                                       SPOOL_NOTIFY_INFO *info,
03748                                       TALLOC_CTX *mem_ctx)
03749 {
03750         int snum;
03751         Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
03752         int n_services=lp_numservices();
03753         int i;
03754         SPOOL_NOTIFY_OPTION *option;
03755         SPOOL_NOTIFY_OPTION_TYPE *option_type;
03756 
03757         DEBUG(4,("printserver_notify_info\n"));
03758         
03759         if (!Printer)
03760                 return WERR_BADFID;
03761 
03762         option=Printer->notify.option;
03763         info->version=2;
03764         info->data=NULL;
03765         info->count=0;
03766 
03767         /* a bug in xp sp2 rc2 causes it to send a fnpcn request without 
03768            sending a ffpcn() request first */
03769 
03770         if ( !option )
03771                 return WERR_BADFID;
03772 
03773         for (i=0; i<option->count; i++) {
03774                 option_type=&(option->ctr.type[i]);
03775                 
03776                 if (option_type->type!=PRINTER_NOTIFY_TYPE)
03777                         continue;
03778                 
03779                 for (snum=0; snum<n_services; snum++)
03780                 {
03781                         if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
03782                                 construct_notify_printer_info ( Printer, info, snum, option_type, snum, mem_ctx );
03783                 }
03784         }
03785                         
03786 #if 0                   
03787         /*
03788          * Debugging information, don't delete.
03789          */
03790 
03791         DEBUG(1,("dumping the NOTIFY_INFO\n"));
03792         DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count));
03793         DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n"));
03794         
03795         for (i=0; i<info->count; i++) {
03796                 DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n",
03797                 i, info->data[i].type, info->data[i].field, info->data[i].reserved,
03798                 info->data[i].id, info->data[i].size, info->data[i].enc_type));
03799         }
03800 #endif
03801         
03802         return WERR_OK;
03803 }
03804 
03805 /*******************************************************************
03806  *
03807  * fill a notify_info struct with info asked
03808  *
03809  ********************************************************************/
03810 
03811 static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY_INFO *info,
03812                                   TALLOC_CTX *mem_ctx)
03813 {
03814         int snum;
03815         Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
03816         int i;
03817         uint32 id;
03818         SPOOL_NOTIFY_OPTION *option;
03819         SPOOL_NOTIFY_OPTION_TYPE *option_type;
03820         int count,j;
03821         print_queue_struct *queue=NULL;
03822         print_status_struct status;
03823         
03824         DEBUG(4,("printer_notify_info\n"));
03825 
03826         if (!Printer)
03827                 return WERR_BADFID;
03828 
03829         option=Printer->notify.option;
03830         id = 0x0;
03831         info->version=2;
03832         info->data=NULL;
03833         info->count=0;
03834 
03835         /* a bug in xp sp2 rc2 causes it to send a fnpcn request without 
03836            sending a ffpcn() request first */
03837 
03838         if ( !option )
03839                 return WERR_BADFID;
03840 
03841         get_printer_snum(p, hnd, &snum);
03842 
03843         for (i=0; i<option->count; i++) {
03844                 option_type=&option->ctr.type[i];
03845                 
03846                 switch ( option_type->type ) {
03847                 case PRINTER_NOTIFY_TYPE:
03848                         if(construct_notify_printer_info(Printer, info, snum, 
03849                                                          option_type, id,
03850                                                          mem_ctx))  
03851                                 id--;
03852                         break;
03853                         
03854                 case JOB_NOTIFY_TYPE: {
03855                         NT_PRINTER_INFO_LEVEL *printer = NULL;
03856 
03857                         count = print_queue_status(snum, &queue, &status);
03858 
03859                         if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum))))
03860                                 goto done;
03861 
03862                         for (j=0; j<count; j++) {
03863                                 construct_notify_jobs_info(&queue[j], info,
03864                                                            printer, snum,
03865                                                            option_type,
03866                                                            queue[j].job,
03867                                                            mem_ctx); 
03868                         }
03869 
03870                         free_a_printer(&printer, 2);
03871                         
03872                 done:
03873                         SAFE_FREE(queue);
03874                         break;
03875                 }
03876                 }
03877         }
03878         
03879         /*
03880          * Debugging information, don't delete.
03881          */
03882         /*
03883         DEBUG(1,("dumping the NOTIFY_INFO\n"));
03884         DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count));
03885         DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n"));
03886         
03887         for (i=0; i<info->count; i++) {
03888                 DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n",
03889                 i, info->data[i].type, info->data[i].field, info->data[i].reserved,
03890                 info->data[i].id, info->data[i].size, info->data[i].enc_type));
03891         }
03892         */
03893         return WERR_OK;
03894 }
03895 
03896 /********************************************************************
03897  * spoolss_rfnpcnex
03898  ********************************************************************/
03899 
03900 WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCNEX *r_u)
03901 {
03902         POLICY_HND *handle = &q_u->handle;
03903         SPOOL_NOTIFY_INFO *info = &r_u->info;
03904 
03905         Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
03906         WERROR result = WERR_BADFID;
03907 
03908         /* we always have a NOTIFY_INFO struct */
03909         r_u->info_ptr=0x1;
03910 
03911         if (!Printer) {
03912                 DEBUG(2,("_spoolss_rfnpcnex: Invalid handle (%s:%u:%u).\n",
03913                          OUR_HANDLE(handle)));
03914                 goto done;
03915         }
03916 
03917         DEBUG(4,("Printer type %x\n",Printer->printer_type));
03918 
03919         /*
03920          *      We are now using the change value, and 
03921          *      I should check for PRINTER_NOTIFY_OPTIONS_REFRESH but as
03922          *      I don't have a global notification system, I'm sending back all the
03923          *      informations even when _NOTHING_ has changed.
03924          */
03925 
03926         /* We need to keep track of the change value to send back in 
03927            RRPCN replies otherwise our updates are ignored. */
03928 
03929         Printer->notify.fnpcn = True;
03930 
03931         if (Printer->notify.client_connected) {
03932                 DEBUG(10,("_spoolss_rfnpcnex: Saving change value in request [%x]\n", q_u->change));
03933                 Printer->notify.change = q_u->change;
03934         }
03935 
03936         /* just ignore the SPOOL_NOTIFY_OPTION */
03937         
03938         switch (Printer->printer_type) {
03939                 case SPLHND_SERVER:
03940                         result = printserver_notify_info(p, handle, info, p->mem_ctx);
03941                         break;
03942                         
03943                 case SPLHND_PRINTER:
03944                         result = printer_notify_info(p, handle, info, p->mem_ctx);
03945                         break;
03946         }
03947         
03948         Printer->notify.fnpcn = False;
03949         
03950 done:
03951         return result;
03952 }
03953 
03954 /********************************************************************
03955  * construct_printer_info_0
03956  * fill a printer_info_0 struct
03957  ********************************************************************/
03958 
03959 static BOOL construct_printer_info_0(Printer_entry *print_hnd, PRINTER_INFO_0 *printer, int snum)
03960 {
03961         pstring chaine;
03962         int count;
03963         NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
03964         counter_printer_0 *session_counter;
03965         uint32 global_counter;
03966         struct tm *t;
03967         time_t setuptime;
03968         print_status_struct status;
03969         
03970         if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
03971                 return False;
03972 
03973         count = print_queue_length(snum, &status);
03974 
03975         /* check if we already have a counter for this printer */       
03976         for(session_counter = counter_list; session_counter; session_counter = session_counter->next) {
03977                 if (session_counter->snum == snum)
03978                         break;
03979         }
03980 
03981         /* it's the first time, add it to the list */
03982         if (session_counter==NULL) {
03983                 if((session_counter=SMB_MALLOC_P(counter_printer_0)) == NULL) {
03984                         free_a_printer(&ntprinter, 2);
03985                         return False;
03986                 }
03987                 ZERO_STRUCTP(session_counter);
03988                 session_counter->snum=snum;
03989                 session_counter->counter=0;
03990                 DLIST_ADD(counter_list, session_counter);
03991         }
03992         
03993         /* increment it */
03994         session_counter->counter++;
03995         
03996         /* JFM:
03997          * the global_counter should be stored in a TDB as it's common to all the clients
03998          * and should be zeroed on samba startup
03999          */
04000         global_counter=session_counter->counter;
04001         
04002         pstrcpy(chaine,ntprinter->info_2->printername);
04003 
04004         init_unistr(&printer->printername, chaine);
04005         
04006         slprintf(chaine,sizeof(chaine)-1,"\\\\%s", get_server_name(print_hnd));
04007         init_unistr(&printer->servername, chaine);
04008         
04009         printer->cjobs = count;
04010         printer->total_jobs = 0;
04011         printer->total_bytes = 0;
04012 
04013         setuptime = (time_t)ntprinter->info_2->setuptime;
04014         t=gmtime(&setuptime);
04015 
04016         printer->year = t->tm_year+1900;
04017         printer->month = t->tm_mon+1;
04018         printer->dayofweek = t->tm_wday;
04019         printer->day = t->tm_mday;
04020         printer->hour = t->tm_hour;
04021         printer->minute = t->tm_min;
04022         printer->second = t->tm_sec;
04023         printer->milliseconds = 0;
04024 
04025         printer->global_counter = global_counter;
04026         printer->total_pages = 0;
04027         
04028         /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */
04029         printer->major_version = 0x0005;        /* NT 5 */
04030         printer->build_version = 0x0893;        /* build 2195 */
04031         
04032         printer->unknown7 = 0x1;
04033         printer->unknown8 = 0x0;
04034         printer->unknown9 = 0x0;
04035         printer->session_counter = session_counter->counter;
04036         printer->unknown11 = 0x0;
04037         printer->printer_errors = 0x0;          /* number of print failure */
04038         printer->unknown13 = 0x0;
04039         printer->unknown14 = 0x1;
04040         printer->unknown15 = 0x024a;            /* 586 Pentium ? */
04041         printer->unknown16 =  0x0;
04042         printer->change_id = ntprinter->info_2->changeid; /* ChangeID in milliseconds*/
04043         printer->unknown18 =  0x0;
04044         printer->status = nt_printq_status(status.status);
04045         printer->unknown20 =  0x0;
04046         printer->c_setprinter = get_c_setprinter(); /* monotonically increasing sum of delta printer counts */
04047         printer->unknown22 = 0x0;
04048         printer->unknown23 = 0x6;               /* 6  ???*/
04049         printer->unknown24 = 0;                 /* unknown 24 to 26 are always 0 */
04050         printer->unknown25 = 0;
04051         printer->unknown26 = 0;
04052         printer->unknown27 = 0;
04053         printer->unknown28 = 0;
04054         printer->unknown29 = 0;
04055         
04056         free_a_printer(&ntprinter,2);
04057         return (True);  
04058 }
04059 
04060 /********************************************************************
04061  * construct_printer_info_1
04062  * fill a printer_info_1 struct
04063  ********************************************************************/
04064 static BOOL construct_printer_info_1(Printer_entry *print_hnd, uint32 flags, PRINTER_INFO_1 *printer, int snum)
04065 {
04066         pstring chaine;
04067         pstring chaine2;
04068         NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
04069 
04070         if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
04071                 return False;
04072 
04073         printer->flags=flags;
04074 
04075         if (*ntprinter->info_2->comment == '\0') {
04076                 init_unistr(&printer->comment, lp_comment(snum));
04077                 slprintf(chaine,sizeof(chaine)-1,"%s,%s,%s", ntprinter->info_2->printername,
04078                         ntprinter->info_2->drivername, lp_comment(snum));
04079         }
04080         else {
04081                 init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
04082                 slprintf(chaine,sizeof(chaine)-1,"%s,%s,%s", ntprinter->info_2->printername,
04083                         ntprinter->info_2->drivername, ntprinter->info_2->comment);
04084         }
04085                 
04086         slprintf(chaine2,sizeof(chaine)-1,"%s", ntprinter->info_2->printername);
04087 
04088         init_unistr(&printer->description, chaine);
04089         init_unistr(&printer->name, chaine2);   
04090         
04091         free_a_printer(&ntprinter,2);
04092 
04093         return True;
04094 }
04095 
04096 /****************************************************************************
04097  Free a DEVMODE struct.
04098 ****************************************************************************/
04099 
04100 static void free_dev_mode(DEVICEMODE *dev)
04101 {
04102         if (dev == NULL)
04103                 return;
04104 
04105         SAFE_FREE(dev->dev_private);
04106         SAFE_FREE(dev); 
04107 }
04108 
04109 
04110 /****************************************************************************
04111  Convert an NT_DEVICEMODE to a DEVICEMODE structure.  Both pointers 
04112  should be valid upon entry
04113 ****************************************************************************/
04114 
04115 static BOOL convert_nt_devicemode( DEVICEMODE *devmode, NT_DEVICEMODE *ntdevmode )
04116 {
04117         if ( !devmode || !ntdevmode )
04118                 return False;
04119                 
04120         init_unistr(&devmode->devicename, ntdevmode->devicename);
04121 
04122         init_unistr(&devmode->formname, ntdevmode->formname);
04123 
04124         devmode->specversion      = ntdevmode->specversion;
04125         devmode->driverversion    = ntdevmode->driverversion;
04126         devmode->size             = ntdevmode->size;
04127         devmode->driverextra      = ntdevmode->driverextra;
04128         devmode->fields           = ntdevmode->fields;
04129                                 
04130         devmode->orientation      = ntdevmode->orientation;     
04131         devmode->papersize        = ntdevmode->papersize;
04132         devmode->paperlength      = ntdevmode->paperlength;
04133         devmode->paperwidth       = ntdevmode->paperwidth;
04134         devmode->scale            = ntdevmode->scale;
04135         devmode->copies           = ntdevmode->copies;
04136         devmode->defaultsource    = ntdevmode->defaultsource;
04137         devmode->printquality     = ntdevmode->printquality;
04138         devmode->color            = ntdevmode->color;
04139         devmode->duplex           = ntdevmode->duplex;
04140         devmode->yresolution      = ntdevmode->yresolution;
04141         devmode->ttoption         = ntdevmode->ttoption;
04142         devmode->collate          = ntdevmode->collate;
04143         devmode->icmmethod        = ntdevmode->icmmethod;
04144         devmode->icmintent        = ntdevmode->icmintent;
04145         devmode->mediatype        = ntdevmode->mediatype;
04146         devmode->dithertype       = ntdevmode->dithertype;
04147 
04148         if (ntdevmode->nt_dev_private != NULL) {
04149                 if ((devmode->dev_private=(uint8 *)memdup(ntdevmode->nt_dev_private, ntdevmode->driverextra)) == NULL)
04150                         return False;
04151         }
04152         
04153         return True;
04154 }
04155 
04156 /****************************************************************************
04157  Create a DEVMODE struct. Returns malloced memory.
04158 ****************************************************************************/
04159 
04160 DEVICEMODE *construct_dev_mode(const char *servicename)
04161 {
04162         NT_PRINTER_INFO_LEVEL   *printer = NULL;
04163         DEVICEMODE              *devmode = NULL;
04164         
04165         DEBUG(7,("construct_dev_mode\n"));
04166         
04167         DEBUGADD(8,("getting printer characteristics\n"));
04168 
04169         if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename))) 
04170                 return NULL;
04171 
04172         if ( !printer->info_2->devmode ) {
04173                 DEBUG(5, ("BONG! There was no device mode!\n"));
04174                 goto done;
04175         }
04176 
04177         if ((devmode = SMB_MALLOC_P(DEVICEMODE)) == NULL) {
04178                 DEBUG(2,("construct_dev_mode: malloc fail.\n"));
04179                 goto done;
04180         }
04181 
04182         ZERO_STRUCTP(devmode);  
04183         
04184         DEBUGADD(8,("loading DEVICEMODE\n"));
04185 
04186         if ( !convert_nt_devicemode( devmode, printer->info_2->devmode ) ) {
04187                 free_dev_mode( devmode );
04188                 devmode = NULL;
04189         }
04190 
04191 done:
04192         free_a_printer(&printer,2);
04193 
04194         return devmode;
04195 }
04196 
04197 /********************************************************************
04198  * construct_printer_info_2
04199  * fill a printer_info_2 struct
04200  ********************************************************************/
04201 
04202 static BOOL construct_printer_info_2(Printer_entry *print_hnd, PRINTER_INFO_2 *printer, int snum)
04203 {
04204         int count;
04205         NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
04206 
04207         print_status_struct status;
04208 
04209         if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
04210                 return False;
04211                 
04212         count = print_queue_length(snum, &status);
04213 
04214         init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
04215         init_unistr(&printer->printername, ntprinter->info_2->printername);                             /* printername*/
04216         init_unistr(&printer->sharename, lp_servicename(snum));                 /* sharename */
04217         init_unistr(&printer->portname, ntprinter->info_2->portname);                   /* port */      
04218         init_unistr(&printer->drivername, ntprinter->info_2->drivername);       /* drivername */
04219 
04220         if (*ntprinter->info_2->comment == '\0')
04221                 init_unistr(&printer->comment, lp_comment(snum));                       /* comment */   
04222         else
04223                 init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
04224 
04225         init_unistr(&printer->location, ntprinter->info_2->location);           /* location */  
04226         init_unistr(&printer->sepfile, ntprinter->info_2->sepfile);             /* separator file */
04227         init_unistr(&printer->printprocessor, ntprinter->info_2->printprocessor);/* print processor */
04228         init_unistr(&printer->datatype, ntprinter->info_2->datatype);           /* datatype */  
04229         init_unistr(&printer->parameters, ntprinter->info_2->parameters);       /* parameters (of print processor) */   
04230 
04231         printer->attributes = ntprinter->info_2->attributes;
04232 
04233         printer->priority = ntprinter->info_2->priority;                                /* priority */  
04234         printer->defaultpriority = ntprinter->info_2->default_priority;         /* default priority */
04235         printer->starttime = ntprinter->info_2->starttime;                      /* starttime */
04236         printer->untiltime = ntprinter->info_2->untiltime;                      /* untiltime */
04237         printer->status = nt_printq_status(status.status);                      /* status */
04238         printer->cjobs = count;                                                 /* jobs */
04239         printer->averageppm = ntprinter->info_2->averageppm;                    /* average pages per minute */
04240                         
04241         if ( !(printer->devmode = construct_dev_mode(
04242                        lp_const_servicename(snum))) )
04243                 DEBUG(8, ("Returning NULL Devicemode!\n"));
04244 
04245         printer->secdesc = NULL;
04246 
04247         if ( ntprinter->info_2->secdesc_buf 
04248                 && ntprinter->info_2->secdesc_buf->len != 0 ) 
04249         {
04250                 /* don't use talloc_steal() here unless you do a deep steal of all 
04251                    the SEC_DESC members */
04252 
04253                 printer->secdesc = dup_sec_desc( get_talloc_ctx(), 
04254                         ntprinter->info_2->secdesc_buf->sec );
04255         }
04256 
04257         free_a_printer(&ntprinter, 2);
04258 
04259         return True;
04260 }
04261 
04262 /********************************************************************
04263  * construct_printer_info_3
04264  * fill a printer_info_3 struct
04265  ********************************************************************/
04266 
04267 static BOOL construct_printer_info_3(Printer_entry *print_hnd, PRINTER_INFO_3 **pp_printer, int snum)
04268 {
04269         NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
04270         PRINTER_INFO_3 *printer = NULL;
04271 
04272         if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
04273                 return False;
04274 
04275         *pp_printer = NULL;
04276         if ((printer = SMB_MALLOC_P(PRINTER_INFO_3)) == NULL) {
04277                 DEBUG(2,("construct_printer_info_3: malloc fail.\n"));
04278                 free_a_printer(&ntprinter, 2);
04279                 return False;
04280         }
04281 
04282         ZERO_STRUCTP(printer);
04283         
04284         /* These are the components of the SD we are returning. */
04285 
04286         if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->len != 0) {
04287                 /* don't use talloc_steal() here unless you do a deep steal of all 
04288                    the SEC_DESC members */
04289 
04290                 printer->secdesc = dup_sec_desc( get_talloc_ctx(), 
04291                         ntprinter->info_2->secdesc_buf->sec );
04292         }
04293 
04294         free_a_printer(&ntprinter, 2);
04295 
04296         *pp_printer = printer;
04297         return True;
04298 }
04299 
04300 /********************************************************************
04301  * construct_printer_info_4
04302  * fill a printer_info_4 struct
04303  ********************************************************************/
04304 
04305 static BOOL construct_printer_info_4(Printer_entry *print_hnd, PRINTER_INFO_4 *printer, int snum)
04306 {
04307         NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
04308 
04309         if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
04310                 return False;
04311                 
04312         init_unistr(&printer->printername, ntprinter->info_2->printername);                             /* printername*/
04313         init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
04314         printer->attributes = ntprinter->info_2->attributes;
04315 
04316         free_a_printer(&ntprinter, 2);
04317         return True;
04318 }
04319 
04320 /********************************************************************
04321  * construct_printer_info_5
04322  * fill a printer_info_5 struct
04323  ********************************************************************/
04324 
04325 static BOOL construct_printer_info_5(Printer_entry *print_hnd, PRINTER_INFO_5 *printer, int snum)
04326 {
04327         NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
04328 
04329         if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
04330                 return False;
04331                 
04332         init_unistr(&printer->printername, ntprinter->info_2->printername);
04333         init_unistr(&printer->portname, ntprinter->info_2->portname); 
04334         printer->attributes = ntprinter->info_2->attributes;
04335 
04336         /* these two are not used by NT+ according to MSDN */
04337 
04338         printer->device_not_selected_timeout = 0x0;  /* have seen 0x3a98 */
04339         printer->transmission_retry_timeout  = 0x0;  /* have seen 0xafc8 */
04340 
04341         free_a_printer(&ntprinter, 2);
04342 
04343         return True;
04344 }
04345 
04346 /********************************************************************
04347  * construct_printer_info_7
04348  * fill a printer_info_7 struct
04349  ********************************************************************/
04350 
04351 static BOOL construct_printer_info_7(Printer_entry *print_hnd, PRINTER_INFO_7 *printer, int snum)
04352 {
04353         char *guid_str = NULL;
04354         struct GUID guid; 
04355         
04356         if (is_printer_published(print_hnd, snum, &guid)) {
04357                 asprintf(&guid_str, "{%s}", smb_uuid_string_static(guid));
04358                 strupper_m(guid_str);
04359                 init_unistr(&printer->guid, guid_str);
04360                 printer->action = SPOOL_DS_PUBLISH;
04361         } else {
04362                 init_unistr(&printer->guid, "");
04363                 printer->action = SPOOL_DS_UNPUBLISH;
04364         }
04365 
04366         return True;
04367 }
04368 
04369 /********************************************************************
04370  Spoolss_enumprinters.
04371 ********************************************************************/
04372 
04373 static WERROR enum_all_printers_info_1(uint32 flags, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
04374 {
04375         int snum;
04376         int i;
04377         int n_services=lp_numservices();
04378         PRINTER_INFO_1 *printers=NULL;
04379         PRINTER_INFO_1 current_prt;
04380         WERROR result = WERR_OK;
04381         
04382         DEBUG(4,("enum_all_printers_info_1\n"));        
04383 
04384         for (snum=0; snum<n_services; snum++) {
04385                 if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
04386                         DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
04387 
04388                         if (construct_printer_info_1(NULL, flags, &current_prt, snum)) {
04389                                 if((printers=SMB_REALLOC_ARRAY(printers, PRINTER_INFO_1, *returned +1)) == NULL) {
04390                                         DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
04391                                         *returned=0;
04392                                         return WERR_NOMEM;
04393                                 }
04394                                 DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *returned));             
04395 
04396                                 memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_1));
04397                                 (*returned)++;
04398                         }
04399                 }
04400         }
04401                 
04402         /* check the required size. */  
04403         for (i=0; i<*returned; i++)
04404                 (*needed) += spoolss_size_printer_info_1(&printers[i]);
04405 
04406         if (*needed > offered) {
04407                 result = WERR_INSUFFICIENT_BUFFER;
04408                 goto out;
04409         }
04410 
04411         if (!rpcbuf_alloc_size(buffer, *needed)) {
04412                 result = WERR_NOMEM;
04413                 goto out;
04414         }
04415 
04416         /* fill the buffer with the structures */
04417         for (i=0; i<*returned; i++)
04418                 smb_io_printer_info_1("", buffer, &printers[i], 0);     
04419 
04420 out:
04421         /* clear memory */
04422 
04423         SAFE_FREE(printers);
04424 
04425         if ( !W_ERROR_IS_OK(result) )
04426                 *returned = 0;
04427 
04428         return result;
04429 }
04430 
04431 /********************************************************************
04432  enum_all_printers_info_1_local.
04433 *********************************************************************/
04434 
04435 static WERROR enum_all_printers_info_1_local(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
04436 {
04437         DEBUG(4,("enum_all_printers_info_1_local\n"));  
04438         
04439         return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
04440 }
04441 
04442 /********************************************************************
04443  enum_all_printers_info_1_name.
04444 *********************************************************************/
04445 
04446 static WERROR enum_all_printers_info_1_name(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
04447 {
04448         char *s = name;
04449         
04450         DEBUG(4,("enum_all_printers_info_1_name\n"));   
04451         
04452         if ((name[0] == '\\') && (name[1] == '\\'))
04453                 s = name + 2;
04454                 
04455         if (is_myname_or_ipaddr(s)) {
04456                 return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
04457         }
04458         else
04459                 return WERR_INVALID_NAME;
04460 }
04461 
04462 #if 0   /* JERRY -- disabled for now.  Don't think this is used, tested, or correct */
04463 /********************************************************************
04464  enum_all_printers_info_1_remote.
04465 *********************************************************************/
04466 
04467 static WERROR enum_all_printers_info_1_remote(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
04468 {
04469         PRINTER_INFO_1 *printer;
04470         fstring printername;
04471         fstring desc;
04472         fstring comment;
04473         DEBUG(4,("enum_all_printers_info_1_remote\n")); 
04474         WERROR result = WERR_OK;
04475 
04476         /* JFM: currently it's more a place holder than anything else.
04477          * In the spooler world there is a notion of server registration.
04478          * the print servers are registered on the PDC (in the same domain)
04479          *
04480          * We should have a TDB here. The registration is done thru an 
04481          * undocumented RPC call.
04482          */
04483         
04484         if((printer=SMB_MALLOC_P(PRINTER_INFO_1)) == NULL)
04485                 return WERR_NOMEM;
04486 
04487         *returned=1;
04488         
04489         slprintf(printername, sizeof(printername)-1,"Windows NT Remote Printers!!\\\\%s", name);                
04490         slprintf(desc, sizeof(desc)-1,"%s", name);
04491         slprintf(comment, sizeof(comment)-1, "Logged on Domain");
04492 
04493         init_unistr(&printer->description, desc);
04494         init_unistr(&printer->name, printername);       
04495         init_unistr(&printer->comment, comment);
04496         printer->flags=PRINTER_ENUM_ICON3|PRINTER_ENUM_CONTAINER;
04497                 
04498         /* check the required size. */  
04499         *needed += spoolss_size_printer_info_1(printer);
04500 
04501         if (*needed > offered) {
04502                 result = WERR_INSUFFICIENT_BUFFER;
04503                 goto out;
04504         }
04505 
04506         if (!rpcbuf_alloc_size(buffer, *needed)) {
04507                 result = WERR_NOMEM;
04508                 goto out;
04509         }
04510 
04511         /* fill the buffer with the structures */
04512         smb_io_printer_info_1("", buffer, printer, 0);  
04513 
04514 out:
04515         /* clear memory */
04516         SAFE_FREE(printer);
04517 
04518         if ( !W_ERROR_IS_OK(result) )
04519                 *returned = 0;
04520 
04521         return result;
04522 }
04523 
04524 #endif
04525 
04526 /********************************************************************
04527  enum_all_printers_info_1_network.
04528 *********************************************************************/
04529 
04530 static WERROR enum_all_printers_info_1_network(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
04531 {
04532         char *s = name;
04533 
04534         DEBUG(4,("enum_all_printers_info_1_network\n"));        
04535         
04536         /* If we respond to a enum_printers level 1 on our name with flags
04537            set to PRINTER_ENUM_REMOTE with a list of printers then these
04538            printers incorrectly appear in the APW browse list.
04539            Specifically the printers for the server appear at the workgroup
04540            level where all the other servers in the domain are
04541            listed. Windows responds to this call with a
04542            WERR_CAN_NOT_COMPLETE so we should do the same. */ 
04543 
04544         if (name[0] == '\\' && name[1] == '\\')
04545                  s = name + 2;
04546 
04547         if (is_myname_or_ipaddr(s))
04548                  return WERR_CAN_NOT_COMPLETE;
04549 
04550         return enum_all_printers_info_1(PRINTER_ENUM_UNKNOWN_8, buffer, offered, needed, returned);
04551 }
04552 
04553 /********************************************************************
04554  * api_spoolss_enumprinters
04555  *
04556  * called from api_spoolss_enumprinters (see this to understand)
04557  ********************************************************************/
04558 
04559 static WERROR enum_all_printers_info_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
04560 {
04561         int snum;
04562         int i;
04563         int n_services=lp_numservices();
04564         PRINTER_INFO_2 *printers=NULL;
04565         PRINTER_INFO_2 current_prt;
04566         WERROR result = WERR_OK;
04567 
04568         *returned = 0;
04569 
04570         for (snum=0; snum<n_services; snum++) {
04571                 if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
04572                         DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
04573                                 
04574                         if (construct_printer_info_2(NULL, &current_prt, snum)) {
04575                                 if ( !(printers=SMB_REALLOC_ARRAY(printers, PRINTER_INFO_2, *returned +1)) ) {
04576                                         DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
04577                                         *returned = 0;
04578                                         return WERR_NOMEM;
04579                                 }
04580 
04581                                 DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *returned + 1));         
04582 
04583                                 memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_2));
04584 
04585                                 (*returned)++;
04586                         }
04587                 }
04588         }
04589         
04590         /* check the required size. */  
04591         for (i=0; i<*returned; i++) 
04592                 (*needed) += spoolss_size_printer_info_2(&printers[i]);
04593         
04594         if (*needed > offered) {
04595                 result = WERR_INSUFFICIENT_BUFFER;
04596                 goto out;
04597         }
04598 
04599         if (!rpcbuf_alloc_size(buffer, *needed)) {
04600                 result = WERR_NOMEM;
04601                 goto out;
04602         }
04603 
04604         /* fill the buffer with the structures */
04605         for (i=0; i<*returned; i++)
04606                 smb_io_printer_info_2("", buffer, &(printers[i]), 0);   
04607         
04608 out:
04609         /* clear memory */
04610 
04611         for (i=0; i<*returned; i++) 
04612                 free_devmode(printers[i].devmode);
04613 
04614         SAFE_FREE(printers);
04615 
04616         if ( !W_ERROR_IS_OK(result) )
04617                 *returned = 0;
04618 
04619         return result;
04620 }
04621 
04622 /********************************************************************
04623  * handle enumeration of printers at level 1
04624  ********************************************************************/
04625 
04626 static WERROR enumprinters_level1( uint32 flags, fstring name,
04627                                  RPC_BUFFER *buffer, uint32 offered,
04628                                  uint32 *needed, uint32 *returned)
04629 {
04630         /* Not all the flags are equals */
04631 
04632         if (flags & PRINTER_ENUM_LOCAL)
04633                 return enum_all_printers_info_1_local(buffer, offered, needed, returned);
04634 
04635         if (flags & PRINTER_ENUM_NAME)
04636                 return enum_all_printers_info_1_name(name, buffer, offered, needed, returned);
04637 
04638 #if 0   /* JERRY - disabled for now */
04639         if (flags & PRINTER_ENUM_REMOTE)
04640                 return enum_all_printers_info_1_remote(name, buffer, offered, needed, returned);
04641 #endif
04642 
04643         if (flags & PRINTER_ENUM_NETWORK)
04644                 return enum_all_printers_info_1_network(name, buffer, offered, needed, returned);
04645 
04646         return WERR_OK; /* NT4sp5 does that */
04647 }
04648 
04649 /********************************************************************
04650  * handle enumeration of printers at level 2
04651  ********************************************************************/
04652 
04653 static WERROR enumprinters_level2( uint32 flags, const char *servername,
04654                                  RPC_BUFFER *buffer, uint32 offered,
04655                                  uint32 *needed, uint32 *returned)
04656 {
04657         if (flags & PRINTER_ENUM_LOCAL) {
04658                         return enum_all_printers_info_2(buffer, offered, needed, returned);
04659         }
04660 
04661         if (flags & PRINTER_ENUM_NAME) {
04662                 if (is_myname_or_ipaddr(canon_servername(servername)))
04663                         return enum_all_printers_info_2(buffer, offered, needed, returned);
04664                 else
04665                         return WERR_INVALID_NAME;
04666         }
04667 
04668         if (flags & PRINTER_ENUM_REMOTE)
04669                 return WERR_UNKNOWN_LEVEL;
04670 
04671         return WERR_OK;
04672 }
04673 
04674 /********************************************************************
04675  * handle enumeration of printers at level 5
04676  ********************************************************************/
04677 
04678 static WERROR enumprinters_level5( uint32 flags, const char *servername,
04679                                  RPC_BUFFER *buffer, uint32 offered,
04680                                  uint32 *needed, uint32 *returned)
04681 {
04682 /*      return enum_all_printers_info_5(buffer, offered, needed, returned);*/
04683         return WERR_OK;
04684 }
04685 
04686 /********************************************************************
04687  * api_spoolss_enumprinters
04688  *
04689  * called from api_spoolss_enumprinters (see this to understand)
04690  ********************************************************************/
04691 
04692 WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_R_ENUMPRINTERS *r_u)
04693 {
04694         uint32 flags = q_u->flags;
04695         UNISTR2 *servername = &q_u->servername;
04696         uint32 level = q_u->level;
04697         RPC_BUFFER *buffer = NULL;
04698         uint32 offered = q_u->offered;
04699         uint32 *needed = &r_u->needed;
04700         uint32 *returned = &r_u->returned;
04701 
04702         fstring name;
04703         
04704         /* that's an [in out] buffer */
04705 
04706         if (!q_u->buffer && (offered!=0)) {
04707                 return WERR_INVALID_PARAM;
04708         }
04709 
04710         rpcbuf_move(q_u->buffer, &r_u->buffer);
04711         buffer = r_u->buffer;
04712 
04713         DEBUG(4,("_spoolss_enumprinters\n"));
04714 
04715         *needed=0;
04716         *returned=0;
04717         
04718         /*
04719          * Level 1:
04720          *          flags==PRINTER_ENUM_NAME
04721          *           if name=="" then enumerates all printers
04722          *           if name!="" then enumerate the printer
04723          *          flags==PRINTER_ENUM_REMOTE
04724          *          name is NULL, enumerate printers
04725          * Level 2: name!="" enumerates printers, name can't be NULL
04726          * Level 3: doesn't exist
04727          * Level 4: does a local registry lookup
04728          * Level 5: same as Level 2
04729          */
04730 
04731         unistr2_to_ascii(name, servername, sizeof(name)-1);
04732         strupper_m(name);
04733 
04734         switch (level) {
04735         case 1:
04736                 return enumprinters_level1(flags, name, buffer, offered, needed, returned);
04737         case 2:
04738                 return enumprinters_level2(flags, name, buffer, offered, needed, returned);
04739         case 5:
04740                 return enumprinters_level5(flags, name, buffer, offered, needed, returned);
04741         case 3:
04742         case 4:
04743                 break;
04744         }
04745         return WERR_UNKNOWN_LEVEL;
04746 }
04747 
04748 /****************************************************************************
04749 ****************************************************************************/
04750 
04751 static WERROR getprinter_level_0(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
04752 {
04753         PRINTER_INFO_0 *printer=NULL;
04754         WERROR result = WERR_OK;
04755 
04756         if((printer=SMB_MALLOC_P(PRINTER_INFO_0)) == NULL)
04757                 return WERR_NOMEM;
04758 
04759         construct_printer_info_0(print_hnd, printer, snum);
04760         
04761         /* check the required size. */  
04762         *needed += spoolss_size_printer_info_0(printer);
04763 
04764         if (*needed > offered) {
04765                 result = WERR_INSUFFICIENT_BUFFER;
04766                 goto out;
04767         }
04768 
04769         if (!rpcbuf_alloc_size(buffer, *needed)) {
04770                 result = WERR_NOMEM;
04771                 goto out;
04772         }
04773 
04774         /* fill the buffer with the structures */
04775         smb_io_printer_info_0("", buffer, printer, 0);  
04776         
04777 out:
04778         /* clear memory */
04779 
04780         SAFE_FREE(printer);
04781 
04782         return result;
04783 }
04784 
04785 /****************************************************************************
04786 ****************************************************************************/
04787 
04788 static WERROR getprinter_level_1(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
04789 {
04790         PRINTER_INFO_1 *printer=NULL;
04791         WERROR result = WERR_OK;
04792 
04793         if((printer=SMB_MALLOC_P(PRINTER_INFO_1)) == NULL)
04794                 return WERR_NOMEM;
04795 
04796         construct_printer_info_1(print_hnd, PRINTER_ENUM_ICON8, printer, snum);
04797         
04798         /* check the required size. */  
04799         *needed += spoolss_size_printer_info_1(printer);
04800 
04801         if (*needed > offered) {
04802                 result = WERR_INSUFFICIENT_BUFFER;
04803                 goto out;
04804         }
04805 
04806         if (!rpcbuf_alloc_size(buffer, *needed)) {
04807                 result = WERR_NOMEM;
04808                 goto out;
04809         }
04810 
04811         /* fill the buffer with the structures */
04812         smb_io_printer_info_1("", buffer, printer, 0);  
04813         
04814 out:
04815         /* clear memory */
04816         SAFE_FREE(printer);
04817 
04818         return result;  
04819 }
04820 
04821 /****************************************************************************
04822 ****************************************************************************/
04823 
04824 static WERROR getprinter_level_2(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
04825 {
04826         PRINTER_INFO_2 *printer=NULL;
04827         WERROR result = WERR_OK;
04828 
04829         if((printer=SMB_MALLOC_P(PRINTER_INFO_2))==NULL)
04830                 return WERR_NOMEM;
04831         
04832         construct_printer_info_2(print_hnd, printer, snum);
04833         
04834         /* check the required size. */  
04835         *needed += spoolss_size_printer_info_2(printer);
04836         
04837         if (*needed > offered) {
04838                 result = WERR_INSUFFICIENT_BUFFER;
04839                 goto out;
04840         }
04841 
04842         if (!rpcbuf_alloc_size(buffer, *needed)) {
04843                 result = WERR_NOMEM;
04844                 goto out;
04845         }
04846 
04847         /* fill the buffer with the structures */
04848         if (!smb_io_printer_info_2("", buffer, printer, 0)) 
04849                 result = WERR_NOMEM;
04850         
04851 out:
04852         /* clear memory */
04853         free_printer_info_2(printer);
04854 
04855         return result;  
04856 }
04857 
04858 /****************************************************************************
04859 ****************************************************************************/
04860 
04861 static WERROR getprinter_level_3(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
04862 {
04863         PRINTER_INFO_3 *printer=NULL;
04864         WERROR result = WERR_OK;
04865 
04866         if (!construct_printer_info_3(print_hnd, &printer, snum))
04867                 return WERR_NOMEM;
04868         
04869         /* check the required size. */  
04870         *needed += spoolss_size_printer_info_3(printer);
04871 
04872         if (*needed > offered) {
04873                 result = WERR_INSUFFICIENT_BUFFER;
04874                 goto out;
04875         }
04876 
04877         if (!rpcbuf_alloc_size(buffer, *needed)) {
04878                 result = WERR_NOMEM;
04879                 goto out;
04880         }
04881 
04882         /* fill the buffer with the structures */
04883         smb_io_printer_info_3("", buffer, printer, 0);  
04884         
04885 out:
04886         /* clear memory */
04887         free_printer_info_3(printer);
04888         
04889         return result;  
04890 }
04891 
04892 /****************************************************************************
04893 ****************************************************************************/
04894 
04895 static WERROR getprinter_level_4(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
04896 {
04897         PRINTER_INFO_4 *printer=NULL;
04898         WERROR result = WERR_OK;
04899 
04900         if((printer=SMB_MALLOC_P(PRINTER_INFO_4))==NULL)
04901                 return WERR_NOMEM;
04902 
04903         if (!construct_printer_info_4(print_hnd, printer, snum)) {
04904                 SAFE_FREE(printer);
04905                 return WERR_NOMEM;
04906         }
04907         
04908         /* check the required size. */  
04909         *needed += spoolss_size_printer_info_4(printer);
04910 
04911         if (*needed > offered) {
04912                 result = WERR_INSUFFICIENT_BUFFER;
04913                 goto out;
04914         }
04915 
04916         if (!rpcbuf_alloc_size(buffer, *needed)) {
04917                 result = WERR_NOMEM;
04918                 goto out;
04919         }
04920 
04921         /* fill the buffer with the structures */
04922         smb_io_printer_info_4("", buffer, printer, 0);  
04923         
04924 out:
04925         /* clear memory */
04926         free_printer_info_4(printer);
04927         
04928         return result;  
04929 }
04930 
04931 /****************************************************************************
04932 ****************************************************************************/
04933 
04934 static WERROR getprinter_level_5(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
04935 {
04936         PRINTER_INFO_5 *printer=NULL;
04937         WERROR result = WERR_OK;
04938 
04939         if((printer=SMB_MALLOC_P(PRINTER_INFO_5))==NULL)
04940                 return WERR_NOMEM;
04941 
04942         if (!construct_printer_info_5(print_hnd, printer, snum)) {
04943                 free_printer_info_5(printer);
04944                 return WERR_NOMEM;
04945         }
04946         
04947         /* check the required size. */  
04948         *needed += spoolss_size_printer_info_5(printer);
04949 
04950         if (*needed > offered) {
04951                 result = WERR_INSUFFICIENT_BUFFER;
04952                 goto out;
04953         }
04954 
04955         if (!rpcbuf_alloc_size(buffer, *needed)) {
04956                 result = WERR_NOMEM;
04957                 goto out;
04958         }
04959 
04960         /* fill the buffer with the structures */
04961         smb_io_printer_info_5("", buffer, printer, 0);  
04962         
04963 out:
04964         /* clear memory */
04965         free_printer_info_5(printer);
04966         
04967         return result;  
04968 }
04969 
04970 static WERROR getprinter_level_7(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
04971 {
04972         PRINTER_INFO_7 *printer=NULL;
04973         WERROR result = WERR_OK;
04974 
04975         if((printer=SMB_MALLOC_P(PRINTER_INFO_7))==NULL)
04976                 return WERR_NOMEM;
04977 
04978         if (!construct_printer_info_7(print_hnd, printer, snum))
04979                 return WERR_NOMEM;
04980         
04981         /* check the required size. */  
04982         *needed += spoolss_size_printer_info_7(printer);
04983 
04984         if (*needed > offered) {
04985                 result = WERR_INSUFFICIENT_BUFFER;
04986                 goto out;
04987         }
04988 
04989         if (!rpcbuf_alloc_size(buffer, *needed)) {
04990                 result = WERR_NOMEM;
04991                 goto out;
04992 
04993         }
04994 
04995         /* fill the buffer with the structures */
04996         smb_io_printer_info_7("", buffer, printer, 0);  
04997         
04998 out:
04999         /* clear memory */
05000         free_printer_info_7(printer);
05001         
05002         return result;  
05003 }
05004 
05005 /****************************************************************************
05006 ****************************************************************************/
05007 
05008 WERROR _spoolss_getprinter(pipes_struct *p, SPOOL_Q_GETPRINTER *q_u, SPOOL_R_GETPRINTER *r_u)
05009 {
05010         POLICY_HND *handle = &q_u->handle;
05011         uint32 level = q_u->level;
05012         RPC_BUFFER *buffer = NULL;
05013         uint32 offered = q_u->offered;
05014         uint32 *needed = &r_u->needed;
05015         Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
05016 
05017         int snum;
05018 
05019         /* that's an [in out] buffer */
05020 
05021         if (!q_u->buffer && (offered!=0)) {
05022                 return WERR_INVALID_PARAM;
05023         }
05024 
05025         rpcbuf_move(q_u->buffer, &r_u->buffer);
05026         buffer = r_u->buffer;
05027 
05028         *needed=0;
05029 
05030         if (!get_printer_snum(p, handle, &snum))
05031                 return WERR_BADFID;
05032 
05033         switch (level) {
05034         case 0:
05035                 return getprinter_level_0(Printer, snum, buffer, offered, needed);
05036         case 1:
05037                 return getprinter_level_1(Printer, snum, buffer, offered, needed);
05038         case 2:         
05039                 return getprinter_level_2(Printer, snum, buffer, offered, needed);
05040         case 3:         
05041                 return getprinter_level_3(Printer, snum, buffer, offered, needed);
05042         case 4:         
05043                 return getprinter_level_4(Printer, snum, buffer, offered, needed);
05044         case 5:         
05045                 return getprinter_level_5(Printer, snum, buffer, offered, needed);
05046         case 7:
05047                 return getprinter_level_7(Printer, snum, buffer, offered, needed);
05048         }
05049         return WERR_UNKNOWN_LEVEL;
05050 }       
05051                 
05052 /********************************************************************
05053  * fill a DRIVER_INFO_1 struct
05054  ********************************************************************/
05055 
05056 static void fill_printer_driver_info_1(DRIVER_INFO_1 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername, fstring architecture)
05057 {
05058         init_unistr( &info->name, driver.info_3->name);
05059 }
05060 
05061 /********************************************************************
05062  * construct_printer_driver_info_1
05063  ********************************************************************/
05064 
05065 static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, const char *servername, fstring architecture, uint32 version)
05066 {       
05067         NT_PRINTER_INFO_LEVEL *printer = NULL;
05068         NT_PRINTER_DRIVER_INFO_LEVEL driver;
05069 
05070         ZERO_STRUCT(driver);
05071 
05072         if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
05073                 return WERR_INVALID_PRINTER_NAME;
05074 
05075         if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
05076                 free_a_printer(&printer, 2);
05077                 return WERR_UNKNOWN_PRINTER_DRIVER;
05078         }
05079 
05080         fill_printer_driver_info_1(info, driver, servername, architecture);
05081 
05082         free_a_printer(&printer,2);
05083 
05084         return WERR_OK;
05085 }
05086 
05087 /********************************************************************
05088  * construct_printer_driver_info_2
05089  * fill a printer_info_2 struct
05090  ********************************************************************/
05091 
05092 static void fill_printer_driver_info_2(DRIVER_INFO_2 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
05093 {
05094         pstring temp;
05095         const char *cservername = canon_servername(servername);
05096 
05097         info->version=driver.info_3->cversion;
05098 
05099         init_unistr( &info->name, driver.info_3->name );
05100         init_unistr( &info->architecture, driver.info_3->environment );
05101 
05102 
05103     if (strlen(driver.info_3->driverpath)) {
05104                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->driverpath);
05105                 init_unistr( &info->driverpath, temp );
05106     } else
05107         init_unistr( &info->driverpath, "" );
05108 
05109         if (strlen(driver.info_3->datafile)) {
05110                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->datafile);
05111                 init_unistr( &info->datafile, temp );
05112         } else
05113                 init_unistr( &info->datafile, "" );
05114         
05115         if (strlen(driver.info_3->configfile)) {
05116                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->configfile);
05117                 init_unistr( &info->configfile, temp ); 
05118         } else
05119                 init_unistr( &info->configfile, "" );
05120 }
05121 
05122 /********************************************************************
05123  * construct_printer_driver_info_2
05124  * fill a printer_info_2 struct
05125  ********************************************************************/
05126 
05127 static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, const char *servername, fstring architecture, uint32 version)
05128 {
05129         NT_PRINTER_INFO_LEVEL *printer = NULL;
05130         NT_PRINTER_DRIVER_INFO_LEVEL driver;
05131 
05132         ZERO_STRUCT(printer);
05133         ZERO_STRUCT(driver);
05134 
05135         if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
05136                 return WERR_INVALID_PRINTER_NAME;
05137 
05138         if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
05139                 free_a_printer(&printer, 2);
05140                 return WERR_UNKNOWN_PRINTER_DRIVER;
05141         }
05142 
05143         fill_printer_driver_info_2(info, driver, servername);
05144 
05145         free_a_printer(&printer,2);
05146 
05147         return WERR_OK;
05148 }
05149 
05150 /********************************************************************
05151  * copy a strings array and convert to UNICODE
05152  *
05153  * convert an array of ascii string to a UNICODE string
05154  ********************************************************************/
05155 
05156 static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, const char *servername)
05157 {
05158         int i=0;
05159         int j=0;
05160         const char *v;
05161         pstring line;
05162 
05163         DEBUG(6,("init_unistr_array\n"));
05164         *uni_array=NULL;
05165 
05166         while (True) 
05167         {
05168                 if ( !char_array )
05169                         v = "";
05170                 else 
05171                 {
05172                         v = char_array[i];
05173                         if (!v) 
05174                                 v = ""; /* hack to handle null lists */
05175                 }
05176                 
05177                 /* hack to allow this to be used in places other than when generating 
05178                    the list of dependent files */
05179                    
05180                 if ( servername )
05181                         slprintf( line, sizeof(line)-1, "\\\\%s%s", canon_servername(servername), v );
05182                 else
05183                         pstrcpy( line, v );
05184                         
05185                 DEBUGADD(6,("%d:%s:%lu\n", i, line, (unsigned long)strlen(line)));
05186 
05187                 /* add one extra unit16 for the second terminating NULL */
05188                 
05189                 if ( (*uni_array=SMB_REALLOC_ARRAY(*uni_array, uint16, j+1+strlen(line)+2)) == NULL ) {
05190                         DEBUG(2,("init_unistr_array: Realloc error\n" ));
05191                         return 0;
05192                 }
05193 
05194                 if ( !strlen(v) ) 
05195                         break;
05196                 
05197                 j += (rpcstr_push((*uni_array+j), line, sizeof(uint16)*strlen(line)+2, STR_TERMINATE) / sizeof(uint16));
05198                 i++;
05199         }
05200         
05201         if (*uni_array) {
05202                 /* special case for ""; we need to add both NULL's here */
05203                 if (!j)
05204                         (*uni_array)[j++]=0x0000;       
05205                 (*uni_array)[j]=0x0000;
05206         }
05207         
05208         DEBUGADD(6,("last one:done\n"));
05209 
05210         /* return size of array in uint16's */
05211                 
05212         return j+1;
05213 }
05214 
05215 /********************************************************************
05216  * construct_printer_info_3
05217  * fill a printer_info_3 struct
05218  ********************************************************************/
05219 
05220 static void fill_printer_driver_info_3(DRIVER_INFO_3 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
05221 {
05222         pstring temp;
05223         const char *cservername = canon_servername(servername);
05224 
05225         ZERO_STRUCTP(info);
05226 
05227         info->version=driver.info_3->cversion;
05228 
05229         init_unistr( &info->name, driver.info_3->name );        
05230         init_unistr( &info->architecture, driver.info_3->environment );
05231 
05232         if (strlen(driver.info_3->driverpath)) {
05233                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->driverpath);             
05234                 init_unistr( &info->driverpath, temp );
05235         } else
05236                 init_unistr( &info->driverpath, "" );
05237     
05238         if (strlen(driver.info_3->datafile)) {
05239                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->datafile);
05240                 init_unistr( &info->datafile, temp );
05241         } else
05242                 init_unistr( &info->datafile, "" );
05243 
05244         if (strlen(driver.info_3->configfile)) {
05245                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->configfile);
05246                 init_unistr( &info->configfile, temp ); 
05247         } else
05248                 init_unistr( &info->configfile, "" );
05249 
05250         if (strlen(driver.info_3->helpfile)) {
05251                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->helpfile);
05252                 init_unistr( &info->helpfile, temp );
05253         } else
05254                 init_unistr( &info->helpfile, "" );
05255 
05256         init_unistr( &info->monitorname, driver.info_3->monitorname );
05257         init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
05258 
05259         info->dependentfiles=NULL;
05260         init_unistr_array(&info->dependentfiles, driver.info_3->dependentfiles, cservername);
05261 }
05262 
05263 /********************************************************************
05264  * construct_printer_info_3
05265  * fill a printer_info_3 struct
05266  ********************************************************************/
05267 
05268 static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, const char *servername, fstring architecture, uint32 version)
05269 {       
05270         NT_PRINTER_INFO_LEVEL *printer = NULL;
05271         NT_PRINTER_DRIVER_INFO_LEVEL driver;
05272         WERROR status;
05273         ZERO_STRUCT(driver);
05274 
05275         status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
05276         DEBUG(8,("construct_printer_driver_info_3: status: %s\n", dos_errstr(status)));
05277         if (!W_ERROR_IS_OK(status))
05278                 return WERR_INVALID_PRINTER_NAME;
05279 
05280         status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);    
05281         DEBUG(8,("construct_printer_driver_info_3: status: %s\n", dos_errstr(status)));
05282 
05283 #if 0   /* JERRY */
05284 
05285         /* 
05286          * I put this code in during testing.  Helpful when commenting out the 
05287          * support for DRIVER_INFO_6 in regards to win2k.  Not needed in general
05288          * as win2k always queries the driver using an infor level of 6.
05289          * I've left it in (but ifdef'd out) because I'll probably
05290          * use it in experimentation again in the future.   --jerry 22/01/2002
05291          */
05292 
05293         if (!W_ERROR_IS_OK(status)) {
05294                 /*
05295                  * Is this a W2k client ?
05296                  */
05297                 if (version == 3) {
05298                         /* Yes - try again with a WinNT driver. */
05299                         version = 2;
05300                         status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);    
05301                         DEBUG(8,("construct_printer_driver_info_3: status: %s\n", dos_errstr(status)));
05302                 }
05303 #endif
05304 
05305                 if (!W_ERROR_IS_OK(status)) {
05306                         free_a_printer(&printer,2);
05307                         return WERR_UNKNOWN_PRINTER_DRIVER;
05308                 }
05309                 
05310 #if 0   /* JERRY */
05311         }
05312 #endif
05313         
05314 
05315         fill_printer_driver_info_3(info, driver, servername);
05316 
05317         free_a_printer(&printer,2);
05318 
05319         return WERR_OK;
05320 }
05321 
05322 /********************************************************************
05323  * construct_printer_info_6
05324  * fill a printer_info_6 struct - we know that driver is really level 3. This sucks. JRA.
05325  ********************************************************************/
05326 
05327 static void fill_printer_driver_info_6(DRIVER_INFO_6 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
05328 {
05329         pstring temp;
05330         fstring nullstr;
05331         const char *cservername = canon_servername(servername);
05332 
05333         ZERO_STRUCTP(info);
05334         memset(&nullstr, '\0', sizeof(fstring));
05335 
05336         info->version=driver.info_3->cversion;
05337 
05338         init_unistr( &info->name, driver.info_3->name );        
05339         init_unistr( &info->architecture, driver.info_3->environment );
05340 
05341         if (strlen(driver.info_3->driverpath)) {
05342                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->driverpath);             
05343                 init_unistr( &info->driverpath, temp );
05344         } else
05345                 init_unistr( &info->driverpath, "" );
05346 
05347         if (strlen(driver.info_3->datafile)) {
05348                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->datafile);
05349                 init_unistr( &info->datafile, temp );
05350         } else
05351                 init_unistr( &info->datafile, "" );
05352 
05353         if (strlen(driver.info_3->configfile)) {
05354                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->configfile);
05355                 init_unistr( &info->configfile, temp ); 
05356         } else
05357                 init_unistr( &info->configfile, "" );
05358 
05359         if (strlen(driver.info_3->helpfile)) {
05360                 slprintf(temp, sizeof(temp)-1, "\\\\%s%s", cservername, driver.info_3->helpfile);
05361                 init_unistr( &info->helpfile, temp );
05362         } else
05363                 init_unistr( &info->helpfile, "" );
05364         
05365         init_unistr( &info->monitorname, driver.info_3->monitorname );
05366         init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
05367 
05368         info->dependentfiles = NULL;
05369         init_unistr_array( &info->dependentfiles, driver.info_3->dependentfiles, servername );
05370 
05371         info->previousdrivernames=NULL;
05372         init_unistr_array(&info->previousdrivernames, &nullstr, servername);
05373 
05374         info->driver_date=0;
05375 
05376         info->padding=0;
05377         info->driver_version_low=0;
05378         info->driver_version_high=0;
05379 
05380         init_unistr( &info->mfgname, "");
05381         init_unistr( &info->oem_url, "");
05382         init_unistr( &info->hardware_id, "");
05383         init_unistr( &info->provider, "");
05384 }
05385 
05386 /********************************************************************
05387  * construct_printer_info_6
05388  * fill a printer_info_6 struct
05389  ********************************************************************/
05390 
05391 static WERROR construct_printer_driver_info_6(DRIVER_INFO_6 *info, int snum, 
05392               const char *servername, fstring architecture, uint32 version)
05393 {       
05394         NT_PRINTER_INFO_LEVEL           *printer = NULL;
05395         NT_PRINTER_DRIVER_INFO_LEVEL    driver;
05396         WERROR                          status;
05397         
05398         ZERO_STRUCT(driver);
05399 
05400         status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
05401         
05402         DEBUG(8,("construct_printer_driver_info_6: status: %s\n", dos_errstr(status)));
05403         
05404         if (!W_ERROR_IS_OK(status))
05405                 return WERR_INVALID_PRINTER_NAME;
05406 
05407         status = get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
05408                 
05409         DEBUG(8,("construct_printer_driver_info_6: status: %s\n", dos_errstr(status)));
05410         
05411         if (!W_ERROR_IS_OK(status)) 
05412         {
05413                 /*
05414                  * Is this a W2k client ?
05415                  */
05416 
05417                 if (version < 3) {
05418                         free_a_printer(&printer,2);
05419                         return WERR_UNKNOWN_PRINTER_DRIVER;
05420                 }
05421 
05422                 /* Yes - try again with a WinNT driver. */
05423                 version = 2;
05424                 status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);    
05425                 DEBUG(8,("construct_printer_driver_info_6: status: %s\n", dos_errstr(status)));
05426                 if (!W_ERROR_IS_OK(status)) {
05427                         free_a_printer(&printer,2);
05428                         return WERR_UNKNOWN_PRINTER_DRIVER;
05429                 }
05430         }
05431 
05432         fill_printer_driver_info_6(info, driver, servername);
05433 
05434         free_a_printer(&printer,2);
05435         free_a_printer_driver(driver, 3);
05436 
05437         return WERR_OK;
05438 }
05439 
05440 /****************************************************************************
05441 ****************************************************************************/
05442 
05443 static void free_printer_driver_info_3(DRIVER_INFO_3 *info)
05444 {
05445         SAFE_FREE(info->dependentfiles);
05446 }
05447 
05448 /****************************************************************************
05449 ****************************************************************************/
05450 
05451 static void free_printer_driver_info_6(DRIVER_INFO_6 *info)
05452 {
05453         SAFE_FREE(info->dependentfiles);
05454 }
05455 
05456 /****************************************************************************
05457 ****************************************************************************/
05458 
05459 static WERROR getprinterdriver2_level1(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
05460 {
05461         DRIVER_INFO_1 *info=NULL;
05462         WERROR result;
05463         
05464         if((info=SMB_MALLOC_P(DRIVER_INFO_1)) == NULL)
05465                 return WERR_NOMEM;
05466         
05467         result = construct_printer_driver_info_1(info, snum, servername, architecture, version);
05468         if (!W_ERROR_IS_OK(result)) 
05469                 goto out;
05470 
05471         /* check the required size. */  
05472         *needed += spoolss_size_printer_driver_info_1(info);
05473 
05474         if (*needed > offered) {
05475                 result = WERR_INSUFFICIENT_BUFFER;
05476                 goto out;
05477         }
05478 
05479         if (!rpcbuf_alloc_size(buffer, *needed)) {
05480                 result = WERR_NOMEM;
05481                 goto out;
05482         }
05483 
05484         /* fill the buffer with the structures */
05485         smb_io_printer_driver_info_1("", buffer, info, 0);      
05486 
05487 out:
05488         /* clear memory */
05489         SAFE_FREE(info);
05490 
05491         return result;
05492 }
05493 
05494 /****************************************************************************
05495 ****************************************************************************/
05496 
05497 static WERROR getprinterdriver2_level2(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
05498 {
05499         DRIVER_INFO_2 *info=NULL;
05500         WERROR result;
05501         
05502         if((info=SMB_MALLOC_P(DRIVER_INFO_2)) == NULL)
05503                 return WERR_NOMEM;
05504         
05505         result = construct_printer_driver_info_2(info, snum, servername, architecture, version);
05506         if (!W_ERROR_IS_OK(result)) 
05507                 goto out;
05508 
05509         /* check the required size. */  
05510         *needed += spoolss_size_printer_driver_info_2(info);
05511 
05512         if (*needed > offered) {
05513                 result = WERR_INSUFFICIENT_BUFFER;
05514                 goto out;
05515         }
05516         
05517         if (!rpcbuf_alloc_size(buffer, *needed)) {
05518                 result = WERR_NOMEM;
05519                 goto out;
05520         }
05521 
05522         /* fill the buffer with the structures */
05523         smb_io_printer_driver_info_2("", buffer, info, 0);      
05524 
05525 out:
05526         /* clear memory */
05527         SAFE_FREE(info);
05528 
05529         return result;
05530 }
05531 
05532 /****************************************************************************
05533 ****************************************************************************/
05534 
05535 static WERROR getprinterdriver2_level3(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
05536 {
05537         DRIVER_INFO_3 info;
05538         WERROR result;
05539 
05540         ZERO_STRUCT(info);
05541 
05542         result = construct_printer_driver_info_3(&info, snum, servername, architecture, version);
05543         if (!W_ERROR_IS_OK(result))
05544                 goto out;
05545 
05546         /* check the required size. */  
05547         *needed += spoolss_size_printer_driver_info_3(&info);
05548 
05549         if (*needed > offered) {
05550                 result = WERR_INSUFFICIENT_BUFFER;
05551                 goto out;
05552         }
05553 
05554         if (!rpcbuf_alloc_size(buffer, *needed)) {
05555                 result = WERR_NOMEM;
05556                 goto out;
05557         }
05558 
05559         /* fill the buffer with the structures */
05560         smb_io_printer_driver_info_3("", buffer, &info, 0);
05561 
05562 out:
05563         free_printer_driver_info_3(&info);
05564 
05565         return result;
05566 }
05567 
05568 /****************************************************************************
05569 ****************************************************************************/
05570 
05571 static WERROR getprinterdriver2_level6(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
05572 {
05573         DRIVER_INFO_6 info;
05574         WERROR result;
05575 
05576         ZERO_STRUCT(info);
05577 
05578         result = construct_printer_driver_info_6(&info, snum, servername, architecture, version);
05579         if (!W_ERROR_IS_OK(result)) 
05580                 goto out;
05581 
05582         /* check the required size. */  
05583         *needed += spoolss_size_printer_driver_info_6(&info);
05584 
05585         if (*needed > offered) {
05586                 result = WERR_INSUFFICIENT_BUFFER;
05587                 goto out;
05588         }
05589         
05590         if (!rpcbuf_alloc_size(buffer, *needed)) {
05591                 result = WERR_NOMEM;
05592                 goto out;
05593         }
05594 
05595         /* fill the buffer with the structures */
05596         smb_io_printer_driver_info_6("", buffer, &info, 0);
05597 
05598 out:
05599         free_printer_driver_info_6(&info);
05600 
05601         return result;
05602 }
05603 
05604 /****************************************************************************
05605 ****************************************************************************/
05606 
05607 WERROR _spoolss_getprinterdriver2(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVER2 *q_u, SPOOL_R_GETPRINTERDRIVER2 *r_u)
05608 {
05609         POLICY_HND *handle = &q_u->handle;
05610         UNISTR2 *uni_arch = &q_u->architecture;
05611         uint32 level = q_u->level;
05612         uint32 clientmajorversion = q_u->clientmajorversion;
05613         RPC_BUFFER *buffer = NULL;
05614         uint32 offered = q_u->offered;
05615         uint32 *needed = &r_u->needed;
05616         uint32 *servermajorversion = &r_u->servermajorversion;
05617         uint32 *serverminorversion = &r_u->serverminorversion;
05618         Printer_entry *printer;
05619 
05620         fstring servername;
05621         fstring architecture;
05622         int snum;
05623 
05624         /* that's an [in out] buffer */
05625 
05626         if (!q_u->buffer && (offered!=0)) {
05627                 return WERR_INVALID_PARAM;
05628         }
05629 
05630         rpcbuf_move(q_u->buffer, &r_u->buffer);
05631         buffer = r_u->buffer;
05632 
05633         DEBUG(4,("_spoolss_getprinterdriver2\n"));
05634 
05635         if ( !(printer = find_printer_index_by_hnd( p, handle )) ) {
05636                 DEBUG(0,("_spoolss_getprinterdriver2: invalid printer handle!\n"));
05637                 return WERR_INVALID_PRINTER_NAME;
05638         }
05639 
05640         *needed = 0;
05641         *servermajorversion = 0;
05642         *serverminorversion = 0;
05643 
05644         fstrcpy(servername, get_server_name( printer ));
05645         unistr2_to_ascii(architecture, uni_arch, sizeof(architecture)-1);
05646 
05647         if (!get_printer_snum(p, handle, &snum))
05648                 return WERR_BADFID;
05649 
05650         switch (level) {
05651         case 1:
05652                 return getprinterdriver2_level1(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
05653         case 2:
05654                 return getprinterdriver2_level2(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
05655         case 3:
05656                 return getprinterdriver2_level3(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
05657         case 6:
05658                 return getprinterdriver2_level6(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
05659 #if 0   /* JERRY */
05660         case 101: 
05661                 /* apparently this call is the equivalent of 
05662                    EnumPrinterDataEx() for the DsDriver key */
05663                 break;
05664 #endif
05665         }
05666 
05667         return WERR_UNKNOWN_LEVEL;
05668 }
05669 
05670 /****************************************************************************
05671 ****************************************************************************/
05672 
05673 WERROR _spoolss_startpageprinter(pipes_struct *p, SPOOL_Q_STARTPAGEPRINTER *q_u, SPOOL_R_STARTPAGEPRINTER *r_u)
05674 {
05675         POLICY_HND *handle = &q_u->handle;
05676 
05677         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
05678 
05679         if (!Printer) {
05680                 DEBUG(3,("Error in startpageprinter printer handle\n"));
05681                 return WERR_BADFID;
05682         }
05683 
05684         Printer->page_started=True;
05685         return WERR_OK;
05686 }
05687 
05688 /****************************************************************************
05689 ****************************************************************************/
05690 
05691 WERROR _spoolss_endpageprinter(pipes_struct *p, SPOOL_Q_ENDPAGEPRINTER *q_u, SPOOL_R_ENDPAGEPRINTER *r_u)
05692 {
05693         POLICY_HND *handle = &q_u->handle;
05694         int snum;
05695 
05696         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
05697 
05698         if (!Printer) {
05699                 DEBUG(2,("_spoolss_endpageprinter: Invalid handle (%s:%u:%u).\n",OUR_HANDLE(handle)));
05700                 return WERR_BADFID;
05701         }
05702         
05703         if (!get_printer_snum(p, handle, &snum))
05704                 return WERR_BADFID;
05705 
05706         Printer->page_started=False;
05707         print_job_endpage(snum, Printer->jobid);
05708 
05709         return WERR_OK;
05710 }
05711 
05712 /********************************************************************
05713  * api_spoolss_getprinter
05714  * called from the spoolss dispatcher
05715  *
05716  ********************************************************************/
05717 
05718 WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, SPOOL_R_STARTDOCPRINTER *r_u)
05719 {
05720         POLICY_HND *handle = &q_u->handle;
05721         DOC_INFO *docinfo = &q_u->doc_info_container.docinfo;
05722         uint32 *jobid = &r_u->jobid;
05723 
05724         DOC_INFO_1 *info_1 = &docinfo->doc_info_1;
05725         int snum;
05726         pstring jobname;
05727         fstring datatype;
05728         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
05729         struct current_user user;
05730 
05731         if (!Printer) {
05732                 DEBUG(2,("_spoolss_startdocprinter: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
05733                 return WERR_BADFID;
05734         }
05735 
05736         get_current_user(&user, p);
05737 
05738         /*
05739          * a nice thing with NT is it doesn't listen to what you tell it.
05740          * when asked to send _only_ RAW datas, it tries to send datas
05741          * in EMF format.
05742          *
05743          * So I add checks like in NT Server ...
05744          */
05745         
05746         if (info_1->p_datatype != 0) {
05747                 unistr2_to_ascii(datatype, &info_1->datatype, sizeof(datatype));
05748                 if (strcmp(datatype, "RAW") != 0) {
05749                         (*jobid)=0;
05750                         return WERR_INVALID_DATATYPE;
05751                 }               
05752         }               
05753         
05754         /* get the share number of the printer */
05755         if (!get_printer_snum(p, handle, &snum)) {
05756                 return WERR_BADFID;
05757         }
05758 
05759         unistr2_to_ascii(jobname, &info_1->docname, sizeof(jobname));
05760         
05761         Printer->jobid = print_job_start(&user, snum, jobname, Printer->nt_devmode);
05762 
05763         /* An error occured in print_job_start() so return an appropriate
05764            NT error code. */
05765 
05766         if (Printer->jobid == -1) {
05767                 return map_werror_from_unix(errno);
05768         }
05769         
05770         Printer->document_started=True;
05771         (*jobid) = Printer->jobid;
05772 
05773         return WERR_OK;
05774 }
05775 
05776 /********************************************************************
05777  * api_spoolss_getprinter
05778  * called from the spoolss dispatcher
05779  *
05780  ********************************************************************/
05781 
05782 WERROR _spoolss_enddocprinter(pipes_struct *p, SPOOL_Q_ENDDOCPRINTER *q_u, SPOOL_R_ENDDOCPRINTER *r_u)
05783 {
05784         POLICY_HND *handle = &q_u->handle;
05785 
05786         return _spoolss_enddocprinter_internal(p, handle);
05787 }
05788 
05789 /****************************************************************************
05790 ****************************************************************************/
05791 
05792 WERROR _spoolss_writeprinter(pipes_struct *p, SPOOL_Q_WRITEPRINTER *q_u, SPOOL_R_WRITEPRINTER *r_u)
05793 {
05794         POLICY_HND *handle = &q_u->handle;
05795         uint32 buffer_size = q_u->buffer_size;
05796         uint8 *buffer = q_u->buffer;
05797         uint32 *buffer_written = &q_u->buffer_size2;
05798         int snum;
05799         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
05800         
05801         if (!Printer) {
05802                 DEBUG(2,("_spoolss_writeprinter: Invalid handle (%s:%u:%u)\n",OUR_HANDLE(handle)));
05803                 r_u->buffer_written = q_u->buffer_size2;
05804                 return WERR_BADFID;
05805         }
05806 
05807         if (!get_printer_snum(p, handle, &snum))
05808                 return WERR_BADFID;
05809 
05810         (*buffer_written) = (uint32)print_job_write(snum, Printer->jobid, (const char *)buffer,
05811                                         (SMB_OFF_T)-1, (size_t)buffer_size);
05812         if (*buffer_written == (uint32)-1) {
05813                 r_u->buffer_written = 0;
05814                 if (errno == ENOSPC)
05815                         return WERR_NO_SPOOL_SPACE;
05816                 else
05817                         return WERR_ACCESS_DENIED;
05818         }
05819 
05820         r_u->buffer_written = q_u->buffer_size2;
05821 
05822         return WERR_OK;
05823 }
05824 
05825 /********************************************************************
05826  * api_spoolss_getprinter
05827  * called from the spoolss dispatcher
05828  *
05829  ********************************************************************/
05830 
05831 static WERROR control_printer(POLICY_HND *handle, uint32 command,
05832                               pipes_struct *p)
05833 {
05834         struct current_user user;
05835         int snum;
05836         WERROR errcode = WERR_BADFUNC;
05837         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
05838 
05839         get_current_user(&user, p);
05840 
05841         if (!Printer) {
05842                 DEBUG(2,("control_printer: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
05843                 return WERR_BADFID;
05844         }
05845 
05846         if (!get_printer_snum(p, handle, &snum))
05847                 return WERR_BADFID;
05848 
05849         switch (command) {
05850         case PRINTER_CONTROL_PAUSE:
05851                 if (print_queue_pause(&user, snum, &errcode)) {
05852                         errcode = WERR_OK;
05853                 }
05854                 break;
05855         case PRINTER_CONTROL_RESUME:
05856         case PRINTER_CONTROL_UNPAUSE:
05857                 if (print_queue_resume(&user, snum, &errcode)) {
05858                         errcode = WERR_OK;
05859                 }
05860                 break;
05861         case PRINTER_CONTROL_PURGE:
05862                 if (print_queue_purge(&user, snum, &errcode)) {
05863                         errcode = WERR_OK;
05864                 }
05865                 break;
05866         default:
05867                 return WERR_UNKNOWN_LEVEL;
05868         }
05869 
05870         return errcode;
05871 }
05872 
05873 /********************************************************************
05874  * api_spoolss_abortprinter
05875  * From MSDN: "Deletes printer's spool file if printer is configured
05876  * for spooling"
05877  ********************************************************************/
05878 
05879 WERROR _spoolss_abortprinter(pipes_struct *p, SPOOL_Q_ABORTPRINTER *q_u, SPOOL_R_ABORTPRINTER *r_u)
05880 {
05881         POLICY_HND      *handle = &q_u->handle;
05882         Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
05883         int             snum;
05884         struct          current_user user;
05885         WERROR          errcode = WERR_OK;
05886         
05887         if (!Printer) {
05888                 DEBUG(2,("_spoolss_abortprinter: Invalid handle (%s:%u:%u)\n",OUR_HANDLE(handle)));
05889                 return WERR_BADFID;
05890         }
05891         
05892         if (!get_printer_snum(p, handle, &snum))
05893                 return WERR_BADFID;
05894         
05895         get_current_user( &user, p );   
05896         
05897         print_job_delete( &user, snum, Printer->jobid, &errcode );      
05898         
05899         return errcode;
05900 }
05901 
05902 /********************************************************************
05903  * called by spoolss_api_setprinter
05904  * when updating a printer description
05905  ********************************************************************/
05906 
05907 static WERROR update_printer_sec(POLICY_HND *handle, uint32 level,
05908                                  const SPOOL_PRINTER_INFO_LEVEL *info,
05909                                  pipes_struct *p, SEC_DESC_BUF *secdesc_ctr)
05910 {
05911         SEC_DESC_BUF *new_secdesc_ctr = NULL, *old_secdesc_ctr = NULL;
05912         WERROR result;
05913         int snum;
05914 
05915         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
05916 
05917         if (!Printer || !get_printer_snum(p, handle, &snum)) {
05918                 DEBUG(2,("update_printer_sec: Invalid handle (%s:%u:%u)\n",
05919                          OUR_HANDLE(handle)));
05920 
05921                 result = WERR_BADFID;
05922                 goto done;
05923         }
05924         
05925         if (!secdesc_ctr) {
05926                 DEBUG(10,("update_printer_sec: secdesc_ctr is NULL !\n"));
05927                 result = WERR_INVALID_PARAM;
05928                 goto done;
05929         }
05930 
05931         /* Check the user has permissions to change the security
05932            descriptor.  By experimentation with two NT machines, the user
05933            requires Full Access to the printer to change security
05934            information. */
05935 
05936         if ( Printer->access_granted != PRINTER_ACCESS_ADMINISTER ) {
05937                 DEBUG(4,("update_printer_sec: updated denied by printer permissions\n"));
05938                 result = WERR_ACCESS_DENIED;
05939                 goto done;
05940         }
05941 
05942         /* NT seems to like setting the security descriptor even though
05943            nothing may have actually changed. */
05944 
05945         nt_printing_getsec(p->mem_ctx, Printer->sharename, &old_secdesc_ctr);
05946 
05947         if (DEBUGLEVEL >= 10) {
05948                 SEC_ACL *the_acl;
05949                 int i;
05950 
05951                 the_acl = old_secdesc_ctr->sec->dacl;
05952                 DEBUG(10, ("old_secdesc_ctr for %s has %d aces:\n", 
05953                            PRINTERNAME(snum), the_acl->num_aces));
05954 
05955                 for (i = 0; i < the_acl->num_aces; i++) {
05956                         fstring sid_str;
05957 
05958                         sid_to_string(sid_str, &the_acl->aces[i].trustee);
05959 
05960                         DEBUG(10, ("%s 0x%08x\n", sid_str, 
05961                                   the_acl->aces[i].access_mask));
05962                 }
05963 
05964                 the_acl = secdesc_ctr->sec->dacl;
05965 
05966                 if (the_acl) {
05967                         DEBUG(10, ("secdesc_ctr for %s has %d aces:\n", 
05968                                    PRINTERNAME(snum), the_acl->num_aces));
05969 
05970                         for (i = 0; i < the_acl->num_aces; i++) {
05971                                 fstring sid_str;
05972                                 
05973                                 sid_to_string(sid_str, &the_acl->aces[i].trustee);
05974                                 
05975                                 DEBUG(10, ("%s 0x%08x\n", sid_str, 
05976                                            the_acl->aces[i].access_mask));
05977                         }
05978                 } else {
05979                         DEBUG(10, ("dacl for secdesc_ctr is NULL\n"));
05980                 }
05981         }
05982 
05983         new_secdesc_ctr = sec_desc_merge(p->mem_ctx, secdesc_ctr, old_secdesc_ctr);
05984         if (!new_secdesc_ctr) {
05985                 result = WERR_NOMEM;
05986                 goto done;
05987         }
05988 
05989         if (sec_desc_equal(new_secdesc_ctr->sec, old_secdesc_ctr->sec)) {
05990                 result = WERR_OK;
05991                 goto done;
05992         }
05993 
05994         result = nt_printing_setsec(Printer->sharename, new_secdesc_ctr);
05995 
05996  done:
05997 
05998         return result;
05999 }
06000 
06001 /********************************************************************
06002  Canonicalize printer info from a client
06003 
06004  ATTN: It does not matter what we set the servername to hear 
06005  since we do the necessary work in get_a_printer() to set it to 
06006  the correct value based on what the client sent in the 
06007  _spoolss_open_printer_ex().
06008  ********************************************************************/
06009 
06010 static BOOL check_printer_ok(NT_PRINTER_INFO_LEVEL_2 *info, int snum)
06011 {
06012         fstring printername;
06013         const char *p;
06014         
06015         DEBUG(5,("check_printer_ok: servername=%s printername=%s sharename=%s "
06016                 "portname=%s drivername=%s comment=%s location=%s\n",
06017                 info->servername, info->printername, info->sharename, 
06018                 info->portname, info->drivername, info->comment, info->location));
06019 
06020         /* we force some elements to "correct" values */
06021         slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", global_myname());
06022         fstrcpy(info->sharename, lp_servicename(snum));
06023         
06024         /* check to see if we allow printername != sharename */
06025 
06026         if ( lp_force_printername(snum) ) {
06027                 slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
06028                         global_myname(), info->sharename );
06029         } else {
06030 
06031                 /* make sure printername is in \\server\printername format */
06032         
06033                 fstrcpy( printername, info->printername );
06034                 p = printername;
06035                 if ( printername[0] == '\\' && printername[1] == '\\' ) {
06036                         if ( (p = strchr_m( &printername[2], '\\' )) != NULL )
06037                                 p++;
06038                 }
06039                 
06040                 slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
06041                          global_myname(), p );
06042         }
06043 
06044         info->attributes |= PRINTER_ATTRIBUTE_SAMBA;
06045         info->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA;
06046         
06047         
06048         
06049         return True;
06050 }
06051 
06052 /****************************************************************************
06053 ****************************************************************************/
06054 
06055 WERROR add_port_hook(NT_USER_TOKEN *token, const char *portname, const char *uri )
06056 {
06057         char *cmd = lp_addport_cmd();
06058         pstring command;
06059         int ret;
06060         int fd;
06061         SE_PRIV se_printop = SE_PRINT_OPERATOR;
06062         BOOL is_print_op = False;
06063 
06064         if ( !*cmd ) {
06065                 return WERR_ACCESS_DENIED;
06066         }
06067                 
06068         slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\"", cmd, portname, uri );
06069 
06070         if ( token )
06071                 is_print_op = user_has_privileges( token, &se_printop );
06072 
06073         DEBUG(10,("Running [%s]\n", command));
06074 
06075         /********* BEGIN SePrintOperatorPrivilege **********/
06076 
06077         if ( is_print_op )
06078                 become_root();
06079         
06080         ret = smbrun(command, &fd);
06081 
06082         if ( is_print_op )
06083                 unbecome_root();
06084 
06085         /********* END SePrintOperatorPrivilege **********/
06086 
06087         DEBUGADD(10,("returned [%d]\n", ret));
06088 
06089         if ( ret != 0 ) {
06090                 if (fd != -1)
06091                         close(fd);
06092                 return WERR_ACCESS_DENIED;
06093         }
06094         
06095         return WERR_OK;
06096 }
06097 
06098 /****************************************************************************
06099 ****************************************************************************/
06100 
06101 BOOL add_printer_hook(NT_USER_TOKEN *token, NT_PRINTER_INFO_LEVEL *printer)
06102 {
06103         char *cmd = lp_addprinter_cmd();
06104         char **qlines;
06105         pstring command;
06106         int numlines;
06107         int ret;
06108         int fd;
06109         fstring remote_machine = "%m";
06110         SE_PRIV se_printop = SE_PRINT_OPERATOR;
06111         BOOL is_print_op = False;
06112 
06113         standard_sub_basic(current_user_info.smb_name,
06114                            current_user_info.domain,
06115                            remote_machine,sizeof(remote_machine));
06116         
06117         slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
06118                         cmd, printer->info_2->printername, printer->info_2->sharename,
06119                         printer->info_2->portname, printer->info_2->drivername,
06120                         printer->info_2->location, printer->info_2->comment, remote_machine);
06121 
06122         if ( token )
06123                 is_print_op = user_has_privileges( token, &se_printop );
06124 
06125         DEBUG(10,("Running [%s]\n", command));
06126 
06127         /********* BEGIN SePrintOperatorPrivilege **********/
06128 
06129         if ( is_print_op )
06130                 become_root();
06131         
06132         if ( (ret = smbrun(command, &fd)) == 0 ) {
06133                 /* Tell everyone we updated smb.conf. */
06134                 message_send_all(conn_tdb_ctx(), MSG_SMB_CONF_UPDATED, NULL, 0, False, NULL);
06135         }
06136 
06137         if ( is_print_op )
06138                 unbecome_root();
06139 
06140         /********* END SePrintOperatorPrivilege **********/
06141 
06142         DEBUGADD(10,("returned [%d]\n", ret));
06143 
06144         if ( ret != 0 ) {
06145                 if (fd != -1)
06146                         close(fd);
06147                 return False;
06148         }
06149 
06150         /* reload our services immediately */
06151         reload_services( False );
06152 
06153         numlines = 0;
06154         /* Get lines and convert them back to dos-codepage */
06155         qlines = fd_lines_load(fd, &numlines, 0);
06156         DEBUGADD(10,("Lines returned = [%d]\n", numlines));
06157         close(fd);
06158 
06159         /* Set the portname to what the script says the portname should be. */
06160         /* but don't require anything to be return from the script exit a good error code */
06161 
06162         if (numlines) {
06163                 /* Set the portname to what the script says the portname should be. */
06164                 strncpy(printer->info_2->portname, qlines[0], sizeof(printer->info_2->portname));
06165                 DEBUGADD(6,("Line[0] = [%s]\n", qlines[0]));
06166         }
06167 
06168         file_lines_free(qlines);
06169         return True;
06170 }
06171 
06172 
06173 /********************************************************************
06174  * Called by spoolss_api_setprinter
06175  * when updating a printer description.
06176  ********************************************************************/
06177 
06178 static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
06179                            const SPOOL_PRINTER_INFO_LEVEL *info,
06180                            DEVICEMODE *devmode)
06181 {
06182         int snum;
06183         NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
06184         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
06185         WERROR result;
06186         UNISTR2 buffer;
06187         fstring asc_buffer;
06188 
06189         DEBUG(8,("update_printer\n"));
06190 
06191         result = WERR_OK;
06192 
06193         if (!Printer) {
06194                 result = WERR_BADFID;
06195                 goto done;
06196         }
06197 
06198         if (!get_printer_snum(p, handle, &snum)) {
06199                 result = WERR_BADFID;
06200                 goto done;
06201         }
06202 
06203         if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum))) ||
06204             (!W_ERROR_IS_OK(get_a_printer(Printer, &old_printer, 2, lp_const_servicename(snum))))) {
06205                 result = WERR_BADFID;
06206                 goto done;
06207         }
06208 
06209         DEBUGADD(8,("Converting info_2 struct\n"));
06210 
06211         /*
06212          * convert_printer_info converts the incoming
06213          * info from the client and overwrites the info
06214          * just read from the tdb in the pointer 'printer'.
06215          */
06216 
06217         if (!convert_printer_info(info, printer, level)) {
06218                 result =  WERR_NOMEM;
06219                 goto done;
06220         }
06221 
06222         if (devmode) {
06223                 /* we have a valid devmode
06224                    convert it and link it*/
06225 
06226                 DEBUGADD(8,("update_printer: Converting the devicemode struct\n"));
06227                 if (!convert_devicemode(printer->info_2->printername, devmode,
06228                                 &printer->info_2->devmode)) {
06229                         result =  WERR_NOMEM;
06230                         goto done;
06231                 }
06232         }
06233 
06234         /* Do sanity check on the requested changes for Samba */
06235 
06236         if (!check_printer_ok(printer->info_2, snum)) {
06237                 result = WERR_INVALID_PARAM;
06238                 goto done;
06239         }
06240 
06241         /* FIXME!!! If the driver has changed we really should verify that 
06242            it is installed before doing much else   --jerry */
06243 
06244         /* Check calling user has permission to update printer description */
06245 
06246         if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
06247                 DEBUG(3, ("update_printer: printer property change denied by handle\n"));
06248                 result = WERR_ACCESS_DENIED;
06249                 goto done;
06250         }
06251 
06252         /* Call addprinter hook */
06253         /* Check changes to see if this is really needed */
06254         
06255         if ( *lp_addprinter_cmd() 
06256                 && (!strequal(printer->info_2->drivername, old_printer->info_2->drivername)
06257                         || !strequal(printer->info_2->comment, old_printer->info_2->comment)
06258                         || !strequal(printer->info_2->portname, old_printer->info_2->portname)
06259                         || !strequal(printer->info_2->location, old_printer->info_2->location)) )
06260         {
06261                 /* add_printer_hook() will call reload_services() */
06262 
06263                 if ( !add_printer_hook(p->pipe_user.nt_user_token, printer) ) {
06264                         result = WERR_ACCESS_DENIED;
06265                         goto done;
06266                 }
06267         }
06268         
06269         /*
06270          * When a *new* driver is bound to a printer, the drivername is used to
06271          * lookup previously saved driver initialization info, which is then
06272          * bound to the printer, simulating what happens in the Windows arch.
06273          */
06274         if (!strequal(printer->info_2->drivername, old_printer->info_2->drivername))
06275         {
06276                 if (!set_driver_init(printer, 2)) 
06277                 {
06278                         DEBUG(5,("update_printer: Error restoring driver initialization data for driver [%s]!\n",
06279                                 printer->info_2->drivername));
06280                 }
06281                 
06282                 DEBUG(10,("update_printer: changing driver [%s]!  Sending event!\n",
06283                         printer->info_2->drivername));
06284                         
06285                 notify_printer_driver(snum, printer->info_2->drivername);
06286         }
06287 
06288         /* 
06289          * flag which changes actually occured.  This is a small subset of 
06290          * all the possible changes.  We also have to update things in the 
06291          * DsSpooler key.
06292          */
06293 
06294         if (!strequal(printer->info_2->comment, old_printer->info_2->comment)) {
06295                 init_unistr2( &buffer, printer->info_2->comment, UNI_STR_TERMINATE);
06296                 set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "description",
06297                         REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
06298 
06299                 notify_printer_comment(snum, printer->info_2->comment);
06300         }
06301 
06302         if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename)) {
06303                 init_unistr2( &buffer, printer->info_2->sharename, UNI_STR_TERMINATE);
06304                 set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shareName",
06305                         REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
06306 
06307                 notify_printer_sharename(snum, printer->info_2->sharename);
06308         }
06309 
06310         if (!strequal(printer->info_2->printername, old_printer->info_2->printername)) {
06311                 char *pname;
06312                 
06313                 if ( (pname = strchr_m( printer->info_2->printername+2, '\\' )) != NULL )
06314                         pname++;
06315                 else
06316                         pname = printer->info_2->printername;
06317                         
06318 
06319                 init_unistr2( &buffer, pname, UNI_STR_TERMINATE);
06320                 set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "printerName",
06321                         REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
06322 
06323                 notify_printer_printername( snum, pname );
06324         }
06325         
06326         if (!strequal(printer->info_2->portname, old_printer->info_2->portname)) {
06327                 init_unistr2( &buffer, printer->info_2->portname, UNI_STR_TERMINATE);
06328                 set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "portName",
06329                         REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
06330 
06331                 notify_printer_port(snum, printer->info_2->portname);
06332         }
06333 
06334         if (!strequal(printer->info_2->location, old_printer->info_2->location)) {
06335                 init_unistr2( &buffer, printer->info_2->location, UNI_STR_TERMINATE);
06336                 set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "location",
06337                         REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
06338 
06339                 notify_printer_location(snum, printer->info_2->location);
06340         }
06341         
06342         /* here we need to update some more DsSpooler keys */
06343         /* uNCName, serverName, shortServerName */
06344         
06345         init_unistr2( &buffer, global_myname(), UNI_STR_TERMINATE);
06346         set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "serverName",
06347                 REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
06348         set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shortServerName",
06349                 REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
06350 
06351         slprintf( asc_buffer, sizeof(asc_buffer)-1, "\\\\%s\\%s",
06352                  global_myname(), printer->info_2->sharename );
06353         init_unistr2( &buffer, asc_buffer, UNI_STR_TERMINATE);
06354         set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "uNCName",
06355                 REG_SZ, (uint8*)buffer.buffer, buffer.uni_str_len*2 );
06356 
06357         /* Update printer info */
06358         result = mod_a_printer(printer, 2);
06359 
06360 done:
06361         free_a_printer(&printer, 2);
06362         free_a_printer(&old_printer, 2);
06363 
06364 
06365         return result;
06366 }
06367 
06368 /****************************************************************************
06369 ****************************************************************************/
06370 static WERROR publish_or_unpublish_printer(pipes_struct *p, POLICY_HND *handle,
06371                                    const SPOOL_PRINTER_INFO_LEVEL *info)
06372 {
06373 #ifdef HAVE_ADS
06374         SPOOL_PRINTER_INFO_LEVEL_7 *info7 = info->info_7;
06375         int snum;
06376         Printer_entry *Printer;
06377 
06378         if ( lp_security() != SEC_ADS ) {
06379                 return WERR_UNKNOWN_LEVEL;
06380         }
06381 
06382         Printer = find_printer_index_by_hnd(p, handle);
06383 
06384         DEBUG(5,("publish_or_unpublish_printer, action = %d\n",info7->action));
06385 
06386         if (!Printer)
06387                 return WERR_BADFID;
06388 
06389         if (!get_printer_snum(p, handle, &snum))
06390                 return WERR_BADFID;
06391         
06392         nt_printer_publish(Printer, snum, info7->action);
06393         
06394         return WERR_OK;
06395 #else
06396         return WERR_UNKNOWN_LEVEL;
06397 #endif
06398 }
06399 /****************************************************************************
06400 ****************************************************************************/
06401 
06402 WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SETPRINTER *r_u)
06403 {
06404         POLICY_HND *handle = &q_u->handle;
06405         uint32 level = q_u->level;
06406         SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info;
06407         DEVMODE_CTR devmode_ctr = q_u->devmode_ctr;
06408         SEC_DESC_BUF *secdesc_ctr = q_u->secdesc_ctr;
06409         uint32 command = q_u->command;
06410         WERROR result;
06411 
06412         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
06413         
06414         if (!Printer) {
06415                 DEBUG(2,("_spoolss_setprinter: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
06416                 return WERR_BADFID;
06417         }
06418 
06419         /* check the level */   
06420         switch (level) {
06421                 case 0:
06422                         return control_printer(handle, command, p);
06423                 case 2:
06424                         result = update_printer(p, handle, level, info, devmode_ctr.devmode);
06425                         if (!W_ERROR_IS_OK(result)) 
06426                                 return result;
06427                         if (secdesc_ctr)
06428                                 result = update_printer_sec(handle, level, info, p, secdesc_ctr);
06429                         return result;
06430                 case 3:
06431                         return update_printer_sec(handle, level, info, p,
06432                                                   secdesc_ctr);
06433                 case 7:
06434                         return publish_or_unpublish_printer(p, handle, info);
06435                 default:
06436                         return WERR_UNKNOWN_LEVEL;
06437         }
06438 }
06439 
06440 /****************************************************************************
06441 ****************************************************************************/
06442 
06443 WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u)
06444 {
06445         POLICY_HND *handle = &q_u->handle;
06446         Printer_entry *Printer= find_printer_index_by_hnd(p, handle);
06447         
06448         if (!Printer) {
06449                 DEBUG(2,("_spoolss_fcpn: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
06450                 return WERR_BADFID;
06451         }
06452 
06453         if (Printer->notify.client_connected==True) {
06454                 int snum = -1;
06455 
06456                 if ( Printer->printer_type == SPLHND_SERVER)
06457                         snum = -1;
06458                 else if ( (Printer->printer_type == SPLHND_PRINTER) &&
06459                                 !get_printer_snum(p, handle, &snum) )
06460                         return WERR_BADFID;
06461 
06462                 srv_spoolss_replycloseprinter(snum, &Printer->notify.client_hnd);
06463         }
06464 
06465         Printer->notify.flags=0;
06466         Printer->notify.options=0;
06467         Printer->notify.localmachine[0]='\0';
06468         Printer->notify.printerlocal=0;
06469         if (Printer->notify.option)
06470                 free_spool_notify_option(&Printer->notify.option);
06471         Printer->notify.client_connected=False;
06472 
06473         return WERR_OK;
06474 }
06475 
06476 /****************************************************************************
06477 ****************************************************************************/
06478 
06479 WERROR _spoolss_addjob(pipes_struct *p, SPOOL_Q_ADDJOB *q_u, SPOOL_R_ADDJOB *r_u)
06480 {
06481         /* that's an [in out] buffer */
06482 
06483         if (!q_u->buffer && (q_u->offered!=0)) {
06484                 return WERR_INVALID_PARAM;
06485         }
06486 
06487         rpcbuf_move(q_u->buffer, &r_u->buffer);
06488 
06489         r_u->needed = 0;
06490         return WERR_INVALID_PARAM; /* this is what a NT server
06491                                            returns for AddJob. AddJob
06492                                            must fail on non-local
06493                                            printers */
06494 }
06495 
06496 /****************************************************************************
06497 ****************************************************************************/
06498 
06499 static void fill_job_info_1(JOB_INFO_1 *job_info, const print_queue_struct *queue,
06500                             int position, int snum, 
06501                             const NT_PRINTER_INFO_LEVEL *ntprinter)
06502 {
06503         struct tm *t;
06504         
06505         t=gmtime(&queue->time);
06506 
06507         job_info->jobid=queue->job;     
06508         init_unistr(&job_info->printername, lp_servicename(snum));
06509         init_unistr(&job_info->machinename, ntprinter->info_2->servername);
06510         init_unistr(&job_info->username, queue->fs_user);
06511         init_unistr(&job_info->document, queue->fs_file);
06512         init_unistr(&job_info->datatype, "RAW");
06513         init_unistr(&job_info->text_status, "");
06514         job_info->status=nt_printj_status(queue->status);
06515         job_info->priority=queue->priority;
06516         job_info->position=position;
06517         job_info->totalpages=queue->page_count;
06518         job_info->pagesprinted=0;
06519 
06520         make_systemtime(&job_info->submitted, t);
06521 }
06522 
06523 /****************************************************************************
06524 ****************************************************************************/
06525 
06526 static BOOL fill_job_info_2(JOB_INFO_2 *job_info, const print_queue_struct *queue,
06527                             int position, int snum, 
06528                             const NT_PRINTER_INFO_LEVEL *ntprinter,
06529                             DEVICEMODE *devmode)
06530 {
06531         struct tm *t;
06532 
06533         t=gmtime(&queue->time);
06534 
06535         job_info->jobid=queue->job;
06536         
06537         init_unistr(&job_info->printername, ntprinter->info_2->printername);
06538         
06539         init_unistr(&job_info->machinename, ntprinter->info_2->servername);
06540         init_unistr(&job_info->username, queue->fs_user);
06541         init_unistr(&job_info->document, queue->fs_file);
06542         init_unistr(&job_info->notifyname, queue->fs_user);
06543         init_unistr(&job_info->datatype, "RAW");
06544         init_unistr(&job_info->printprocessor, "winprint");
06545         init_unistr(&job_info->parameters, "");
06546         init_unistr(&job_info->drivername, ntprinter->info_2->drivername);
06547         init_unistr(&job_info->text_status, "");
06548         
06549 /* and here the security descriptor */
06550 
06551         job_info->status=nt_printj_status(queue->status);
06552         job_info->priority=queue->priority;
06553         job_info->position=position;
06554         job_info->starttime=0;
06555         job_info->untiltime=0;
06556         job_info->totalpages=queue->page_count;
06557         job_info->size=queue->size;
06558         make_systemtime(&(job_info->submitted), t);
06559         job_info->timeelapsed=0;
06560         job_info->pagesprinted=0;
06561 
06562         job_info->devmode = devmode;
06563 
06564         return (True);
06565 }
06566 
06567 /****************************************************************************
06568  Enumjobs at level 1.
06569 ****************************************************************************/
06570 
06571 static WERROR enumjobs_level1(const print_queue_struct *queue, int snum,
06572                               const NT_PRINTER_INFO_LEVEL *ntprinter,
06573                               RPC_BUFFER *buffer, uint32 offered,
06574                               uint32 *needed, uint32 *returned)
06575 {
06576         JOB_INFO_1 *info;
06577         int i;
06578         WERROR result = WERR_OK;
06579         
06580         info=SMB_MALLOC_ARRAY(JOB_INFO_1,*returned);
06581         if (info==NULL) {
06582                 *returned=0;
06583                 return WERR_NOMEM;
06584         }
06585         
06586         for (i=0; i<*returned; i++)
06587                 fill_job_info_1( &info[i], &queue[i], i, snum, ntprinter );
06588 
06589         /* check the required size. */  
06590         for (i=0; i<*returned; i++)
06591                 (*needed) += spoolss_size_job_info_1(&info[i]);
06592 
06593         if (*needed > offered) {
06594                 result = WERR_INSUFFICIENT_BUFFER;
06595                 goto out;
06596         }
06597 
06598         if (!rpcbuf_alloc_size(buffer, *needed)) {
06599                 result = WERR_NOMEM;
06600                 goto out;
06601         }
06602 
06603         /* fill the buffer with the structures */
06604         for (i=0; i<*returned; i++)
06605                 smb_io_job_info_1("", buffer, &info[i], 0);     
06606 
06607 out:
06608         /* clear memory */
06609         SAFE_FREE(info);
06610 
06611         if ( !W_ERROR_IS_OK(result) )
06612                 *returned = 0;
06613 
06614         return result;
06615 }
06616 
06617 /****************************************************************************
06618  Enumjobs at level 2.
06619 ****************************************************************************/
06620 
06621 static WERROR enumjobs_level2(const print_queue_struct *queue, int snum,
06622                               const NT_PRINTER_INFO_LEVEL *ntprinter,
06623                               RPC_BUFFER *buffer, uint32 offered,
06624                               uint32 *needed, uint32 *returned)
06625 {
06626         JOB_INFO_2 *info = NULL;
06627         int i;
06628         WERROR result = WERR_OK;
06629         DEVICEMODE *devmode = NULL;
06630         
06631         if ( !(info = SMB_MALLOC_ARRAY(JOB_INFO_2,*returned)) ) {
06632                 *returned=0;
06633                 return WERR_NOMEM;
06634         }
06635                 
06636         /* this should not be a failure condition if the devmode is NULL */
06637         
06638         devmode = construct_dev_mode(lp_const_servicename(snum));
06639 
06640         for (i=0; i<*returned; i++)
06641                 fill_job_info_2(&(info[i]), &queue[i], i, snum, ntprinter, devmode);
06642 
06643         /* check the required size. */  
06644         for (i=0; i<*returned; i++)
06645                 (*needed) += spoolss_size_job_info_2(&info[i]);
06646 
06647         if (*needed > offered) {
06648                 result = WERR_INSUFFICIENT_BUFFER;
06649                 goto out;
06650         }
06651 
06652         if (!rpcbuf_alloc_size(buffer, *needed)) {
06653                 result = WERR_NOMEM;
06654                 goto out;
06655         }
06656 
06657         /* fill the buffer with the structures */
06658         for (i=0; i<*returned; i++)
06659                 smb_io_job_info_2("", buffer, &info[i], 0);     
06660 
06661 out:
06662         free_devmode(devmode);
06663         SAFE_FREE(info);
06664 
06665         if ( !W_ERROR_IS_OK(result) )
06666                 *returned = 0;
06667 
06668         return result;
06669 
06670 }
06671 
06672 /****************************************************************************
06673  Enumjobs.
06674 ****************************************************************************/
06675 
06676 WERROR _spoolss_enumjobs( pipes_struct *p, SPOOL_Q_ENUMJOBS *q_u, SPOOL_R_ENUMJOBS *r_u)
06677 {       
06678         POLICY_HND *handle = &q_u->handle;
06679         uint32 level = q_u->level;
06680         RPC_BUFFER *buffer = NULL;
06681         uint32 offered = q_u->offered;
06682         uint32 *needed = &r_u->needed;
06683         uint32 *returned = &r_u->returned;
06684         WERROR wret;
06685         NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
06686         int snum;
06687         print_status_struct prt_status;
06688         print_queue_struct *queue=NULL;
06689 
06690         /* that's an [in out] buffer */
06691 
06692         if (!q_u->buffer && (offered!=0)) {
06693                 return WERR_INVALID_PARAM;
06694         }
06695 
06696         rpcbuf_move(q_u->buffer, &r_u->buffer);
06697         buffer = r_u->buffer;
06698 
06699         DEBUG(4,("_spoolss_enumjobs\n"));
06700 
06701         *needed=0;
06702         *returned=0;
06703 
06704         /* lookup the printer snum and tdb entry */
06705         
06706         if (!get_printer_snum(p, handle, &snum))
06707                 return WERR_BADFID;
06708 
06709         wret = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
06710         if ( !W_ERROR_IS_OK(wret) )
06711                 return wret;
06712         
06713         *returned = print_queue_status(snum, &queue, &prt_status);
06714         DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", *returned, prt_status.status, prt_status.message));
06715 
06716         if (*returned == 0) {
06717                 SAFE_FREE(queue);
06718                 free_a_printer(&ntprinter, 2);
06719                 return WERR_OK;
06720         }
06721 
06722         switch (level) {
06723         case 1:
06724                 wret = enumjobs_level1(queue, snum, ntprinter, buffer, offered, needed, returned);
06725                 break;
06726         case 2:
06727                 wret = enumjobs_level2(queue, snum, ntprinter, buffer, offered, needed, returned);
06728                 break;
06729         default:
06730                 *returned=0;
06731                 wret = WERR_UNKNOWN_LEVEL;
06732                 break;
06733         }
06734         
06735         SAFE_FREE(queue);
06736         free_a_printer( &ntprinter, 2 );
06737         return wret;
06738 }
06739 
06740 /****************************************************************************
06741 ****************************************************************************/
06742 
06743 WERROR _spoolss_schedulejob( pipes_struct *p, SPOOL_Q_SCHEDULEJOB *q_u, SPOOL_R_SCHEDULEJOB *r_u)
06744 {
06745         return WERR_OK;
06746 }
06747 
06748 /****************************************************************************
06749 ****************************************************************************/
06750 
06751 WERROR _spoolss_setjob(pipes_struct *p, SPOOL_Q_SETJOB *q_u, SPOOL_R_SETJOB *r_u)
06752 {
06753         POLICY_HND *handle = &q_u->handle;
06754         uint32 jobid = q_u->jobid;
06755         uint32 command = q_u->command;
06756 
06757         struct current_user user;
06758         int snum;
06759         WERROR errcode = WERR_BADFUNC;
06760                 
06761         if (!get_printer_snum(p, handle, &snum)) {
06762                 return WERR_BADFID;
06763         }
06764 
06765         if (!print_job_exists(lp_const_servicename(snum), jobid)) {
06766                 return WERR_INVALID_PRINTER_NAME;
06767         }
06768 
06769         get_current_user(&user, p);     
06770 
06771         switch (command) {
06772         case JOB_CONTROL_CANCEL:
06773         case JOB_CONTROL_DELETE:
06774                 if (print_job_delete(&user, snum, jobid, &errcode)) {
06775                         errcode = WERR_OK;
06776                 }
06777                 break;
06778         case JOB_CONTROL_PAUSE:
06779                 if (print_job_pause(&user, snum, jobid, &errcode)) {
06780                         errcode = WERR_OK;
06781                 }               
06782                 break;
06783         case JOB_CONTROL_RESTART:
06784         case JOB_CONTROL_RESUME:
06785                 if (print_job_resume(&user, snum, jobid, &errcode)) {
06786                         errcode = WERR_OK;
06787                 }
06788                 break;
06789         default:
06790                 return WERR_UNKNOWN_LEVEL;
06791         }
06792 
06793         return errcode;
06794 }
06795 
06796 /****************************************************************************
06797  Enumerates all printer drivers at level 1.
06798 ****************************************************************************/
06799 
06800 static WERROR enumprinterdrivers_level1(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
06801 {
06802         int i;
06803         int ndrivers;
06804         uint32 version;
06805         fstring *list = NULL;
06806         NT_PRINTER_DRIVER_INFO_LEVEL driver;
06807         DRIVER_INFO_1 *driver_info_1=NULL;
06808         WERROR result = WERR_OK;
06809 
06810         *returned=0;
06811 
06812         for (version=0; version<DRIVER_MAX_VERSION; version++) {
06813                 list=NULL;
06814                 ndrivers=get_ntdrivers(&list, architecture, version);
06815                 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
06816 
06817                 if(ndrivers == -1) {
06818                         SAFE_FREE(driver_info_1);
06819                         return WERR_NOMEM;
06820                 }
06821 
06822                 if(ndrivers != 0) {
06823                         if((driver_info_1=SMB_REALLOC_ARRAY(driver_info_1, DRIVER_INFO_1, *returned+ndrivers )) == NULL) {
06824                                 DEBUG(0,("enumprinterdrivers_level1: failed to enlarge driver info buffer!\n"));
06825                                 SAFE_FREE(list);
06826                                 return WERR_NOMEM;
06827                         }
06828                 }
06829 
06830                 for (i=0; i<ndrivers; i++) {
06831                         WERROR status;
06832                         DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
06833                         ZERO_STRUCT(driver);
06834                         status = get_a_printer_driver(&driver, 3, list[i], 
06835                                                       architecture, version);
06836                         if (!W_ERROR_IS_OK(status)) {
06837                                 SAFE_FREE(list);
06838                                 SAFE_FREE(driver_info_1);
06839                                 return status;
06840                         }
06841                         fill_printer_driver_info_1(&driver_info_1[*returned+i], driver, servername, architecture );             
06842                         free_a_printer_driver(driver, 3);
06843                 }       
06844 
06845                 *returned+=ndrivers;
06846                 SAFE_FREE(list);
06847         }
06848         
06849         /* check the required size. */
06850         for (i=0; i<*returned; i++) {
06851                 DEBUGADD(6,("adding driver [%d]'s size\n",i));
06852                 *needed += spoolss_size_printer_driver_info_1(&driver_info_1[i]);
06853         }
06854 
06855         if (*needed > offered) {
06856                 result = WERR_INSUFFICIENT_BUFFER;
06857                 goto out;
06858         }
06859 
06860         if (!rpcbuf_alloc_size(buffer, *needed)) {
06861                 result = WERR_NOMEM;    
06862                 goto out;
06863         }
06864 
06865         /* fill the buffer with the driver structures */
06866         for (i=0; i<*returned; i++) {
06867                 DEBUGADD(6,("adding driver [%d] to buffer\n",i));
06868                 smb_io_printer_driver_info_1("", buffer, &driver_info_1[i], 0);
06869         }
06870 
06871 out:
06872         SAFE_FREE(driver_info_1);
06873 
06874         if ( !W_ERROR_IS_OK(result) )
06875                 *returned = 0;
06876 
06877         return result;
06878 }
06879 
06880 /****************************************************************************
06881  Enumerates all printer drivers at level 2.
06882 ****************************************************************************/
06883 
06884 static WERROR enumprinterdrivers_level2(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
06885 {
06886         int i;
06887         int ndrivers;
06888         uint32 version;
06889         fstring *list = NULL;
06890         NT_PRINTER_DRIVER_INFO_LEVEL driver;
06891         DRIVER_INFO_2 *driver_info_2=NULL;
06892         WERROR result = WERR_OK;
06893 
06894         *returned=0;
06895 
06896         for (version=0; version<DRIVER_MAX_VERSION; version++) {
06897                 list=NULL;
06898                 ndrivers=get_ntdrivers(&list, architecture, version);
06899                 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
06900 
06901                 if(ndrivers == -1) {
06902                         SAFE_FREE(driver_info_2);
06903                         return WERR_NOMEM;
06904                 }
06905 
06906                 if(ndrivers != 0) {
06907                         if((driver_info_2=SMB_REALLOC_ARRAY(driver_info_2, DRIVER_INFO_2, *returned+ndrivers )) == NULL) {
06908                                 DEBUG(0,("enumprinterdrivers_level2: failed to enlarge driver info buffer!\n"));
06909                                 SAFE_FREE(list);
06910                                 return WERR_NOMEM;
06911                         }
06912                 }
06913                 
06914                 for (i=0; i<ndrivers; i++) {
06915                         WERROR status;
06916 
06917                         DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
06918                         ZERO_STRUCT(driver);
06919                         status = get_a_printer_driver(&driver, 3, list[i], 
06920                                                       architecture, version);
06921                         if (!W_ERROR_IS_OK(status)) {
06922                                 SAFE_FREE(list);
06923                                 SAFE_FREE(driver_info_2);
06924                                 return status;
06925                         }
06926                         fill_printer_driver_info_2(&driver_info_2[*returned+i], driver, servername);            
06927                         free_a_printer_driver(driver, 3);
06928                 }       
06929 
06930                 *returned+=ndrivers;
06931                 SAFE_FREE(list);
06932         }
06933         
06934         /* check the required size. */
06935         for (i=0; i<*returned; i++) {
06936                 DEBUGADD(6,("adding driver [%d]'s size\n",i));
06937                 *needed += spoolss_size_printer_driver_info_2(&(driver_info_2[i]));
06938         }
06939 
06940         if (*needed > offered) {
06941                 result = WERR_INSUFFICIENT_BUFFER;
06942                 goto out;
06943         }
06944 
06945         if (!rpcbuf_alloc_size(buffer, *needed)) {
06946                 result = WERR_NOMEM;    
06947                 goto out;
06948         }
06949 
06950         /* fill the buffer with the form structures */
06951         for (i=0; i<*returned; i++) {
06952                 DEBUGADD(6,("adding driver [%d] to buffer\n",i));
06953                 smb_io_printer_driver_info_2("", buffer, &(driver_info_2[i]), 0);
06954         }
06955 
06956 out:
06957         SAFE_FREE(driver_info_2);
06958 
06959         if ( !W_ERROR_IS_OK(result) )
06960                 *returned = 0;
06961 
06962         return result;
06963 }
06964 
06965 /****************************************************************************
06966  Enumerates all printer drivers at level 3.
06967 ****************************************************************************/
06968 
06969 static WERROR enumprinterdrivers_level3(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
06970 {
06971         int i;
06972         int ndrivers;
06973         uint32 version;
06974         fstring *list = NULL;
06975         DRIVER_INFO_3 *driver_info_3=NULL;
06976         NT_PRINTER_DRIVER_INFO_LEVEL driver;
06977         WERROR result = WERR_OK;
06978 
06979         *returned=0;
06980 
06981         for (version=0; version<DRIVER_MAX_VERSION; version++) {
06982                 list=NULL;
06983                 ndrivers=get_ntdrivers(&list, architecture, version);
06984                 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", ndrivers, architecture, version));
06985 
06986                 if(ndrivers == -1) {
06987                         SAFE_FREE(driver_info_3);
06988                         return WERR_NOMEM;
06989                 }
06990 
06991                 if(ndrivers != 0) {
06992                         if((driver_info_3=SMB_REALLOC_ARRAY(driver_info_3, DRIVER_INFO_3, *returned+ndrivers )) == NULL) {
06993                                 DEBUG(0,("enumprinterdrivers_level3: failed to enlarge driver info buffer!\n"));
06994                                 SAFE_FREE(list);
06995                                 return WERR_NOMEM;
06996                         }
06997                 }
06998 
06999                 for (i=0; i<ndrivers; i++) {
07000                         WERROR status;
07001 
07002                         DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
07003                         ZERO_STRUCT(driver);
07004                         status = get_a_printer_driver(&driver, 3, list[i], 
07005                                                       architecture, version);
07006                         if (!W_ERROR_IS_OK(status)) {
07007                                 SAFE_FREE(list);
07008                                 SAFE_FREE(driver_info_3);
07009                                 return status;
07010                         }
07011                         fill_printer_driver_info_3(&driver_info_3[*returned+i], driver, servername);            
07012                         free_a_printer_driver(driver, 3);
07013                 }       
07014 
07015                 *returned+=ndrivers;
07016                 SAFE_FREE(list);
07017         }
07018 
07019         /* check the required size. */
07020         for (i=0; i<*returned; i++) {
07021                 DEBUGADD(6,("adding driver [%d]'s size\n",i));
07022                 *needed += spoolss_size_printer_driver_info_3(&driver_info_3[i]);
07023         }
07024 
07025         if (*needed > offered) {
07026                 result = WERR_INSUFFICIENT_BUFFER;
07027                 goto out;
07028         }
07029 
07030         if (!rpcbuf_alloc_size(buffer, *needed)) {
07031                 result = WERR_NOMEM;    
07032                 goto out;
07033         }
07034 
07035         /* fill the buffer with the driver structures */
07036         for (i=0; i<*returned; i++) {
07037                 DEBUGADD(6,("adding driver [%d] to buffer\n",i));
07038                 smb_io_printer_driver_info_3("", buffer, &driver_info_3[i], 0);
07039         }
07040 
07041 out:
07042         for (i=0; i<*returned; i++) {
07043                 SAFE_FREE(driver_info_3[i].dependentfiles);
07044         }
07045 
07046         SAFE_FREE(driver_info_3);
07047         
07048         if ( !W_ERROR_IS_OK(result) )
07049                 *returned = 0;
07050 
07051         return result;
07052 }
07053 
07054 /****************************************************************************
07055  Enumerates all printer drivers.
07056 ****************************************************************************/
07057 
07058 WERROR _spoolss_enumprinterdrivers( pipes_struct *p, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, SPOOL_R_ENUMPRINTERDRIVERS *r_u)
07059 {
07060         uint32 level = q_u->level;
07061         RPC_BUFFER *buffer = NULL;
07062         uint32 offered = q_u->offered;
07063         uint32 *needed = &r_u->needed;
07064         uint32 *returned = &r_u->returned;
07065         const char *cservername;
07066         fstring servername;
07067         fstring architecture;
07068 
07069         /* that's an [in out] buffer */
07070 
07071         if (!q_u->buffer && (offered!=0)) {
07072                 return WERR_INVALID_PARAM;
07073         }
07074 
07075         rpcbuf_move(q_u->buffer, &r_u->buffer);
07076         buffer = r_u->buffer;
07077 
07078         DEBUG(4,("_spoolss_enumprinterdrivers\n"));
07079         
07080         *needed   = 0;
07081         *returned = 0;
07082 
07083         unistr2_to_ascii(architecture, &q_u->environment, sizeof(architecture)-1);
07084         unistr2_to_ascii(servername, &q_u->name, sizeof(servername)-1);
07085 
07086         cservername = canon_servername(servername);
07087 
07088         if (!is_myname_or_ipaddr(cservername))
07089                 return WERR_UNKNOWN_PRINTER_DRIVER;
07090 
07091         switch (level) {
07092         case 1:
07093                 return enumprinterdrivers_level1(cservername, architecture, buffer, offered, needed, returned);
07094         case 2:
07095                 return enumprinterdrivers_level2(cservername, architecture, buffer, offered, needed, returned);
07096         case 3:
07097                 return enumprinterdrivers_level3(cservername, architecture, buffer, offered, needed, returned);
07098         default:
07099                 return WERR_UNKNOWN_LEVEL;
07100         }
07101 }
07102 
07103 /****************************************************************************
07104 ****************************************************************************/
07105 
07106 static void fill_form_1(FORM_1 *form, nt_forms_struct *list)
07107 {
07108         form->flag=list->flag;
07109         init_unistr(&form->name, list->name);
07110         form->width=list->width;
07111         form->length=list->length;
07112         form->left=list->left;
07113         form->top=list->top;
07114         form->right=list->right;
07115         form->bottom=list->bottom;      
07116 }
07117         
07118 /****************************************************************************
07119 ****************************************************************************/
07120 
07121 WERROR _spoolss_enumforms(pipes_struct *p, SPOOL_Q_ENUMFORMS *q_u, SPOOL_R_ENUMFORMS *r_u)
07122 {
07123         uint32 level = q_u->level;
07124         RPC_BUFFER *buffer = NULL;
07125         uint32 offered = q_u->offered;
07126         uint32 *needed = &r_u->needed;
07127         uint32 *numofforms = &r_u->numofforms;
07128         uint32 numbuiltinforms;
07129 
07130         nt_forms_struct *list=NULL;
07131         nt_forms_struct *builtinlist=NULL;
07132         FORM_1 *forms_1;
07133         int buffer_size=0;
07134         int i;
07135 
07136         /* that's an [in out] buffer */
07137 
07138         if (!q_u->buffer && (offered!=0) ) {
07139                 return WERR_INVALID_PARAM;
07140         }
07141 
07142         rpcbuf_move(q_u->buffer, &r_u->buffer);
07143         buffer = r_u->buffer;
07144 
07145         DEBUG(4,("_spoolss_enumforms\n"));
07146         DEBUGADD(5,("Offered buffer size [%d]\n", offered));
07147         DEBUGADD(5,("Info level [%d]\n",          level));
07148 
07149         numbuiltinforms = get_builtin_ntforms(&builtinlist);
07150         DEBUGADD(5,("Number of builtin forms [%d]\n",     numbuiltinforms));
07151         *numofforms = get_ntforms(&list);
07152         DEBUGADD(5,("Number of user forms [%d]\n",     *numofforms));
07153         *numofforms += numbuiltinforms;
07154 
07155         if (*numofforms == 0) {
07156                 SAFE_FREE(builtinlist);
07157                 SAFE_FREE(list);
07158                 return WERR_NO_MORE_ITEMS;
07159         }
07160 
07161         switch (level) {
07162         case 1:
07163                 if ((forms_1=SMB_MALLOC_ARRAY(FORM_1, *numofforms)) == NULL) {
07164                         SAFE_FREE(builtinlist);
07165                         SAFE_FREE(list);
07166                         *numofforms=0;
07167                         return WERR_NOMEM;
07168                 }
07169 
07170                 /* construct the list of form structures */
07171                 for (i=0; i<numbuiltinforms; i++) {
07172                         DEBUGADD(6,("Filling form number [%d]\n",i));
07173                         fill_form_1(&forms_1[i], &builtinlist[i]);
07174                 }
07175                 
07176                 SAFE_FREE(builtinlist);
07177 
07178                 for (; i<*numofforms; i++) {
07179                         DEBUGADD(6,("Filling form number [%d]\n",i));
07180                         fill_form_1(&forms_1[i], &list[i-numbuiltinforms]);
07181                 }
07182                 
07183                 SAFE_FREE(list);
07184 
07185                 /* check the required size. */
07186                 for (i=0; i<numbuiltinforms; i++) {
07187                         DEBUGADD(6,("adding form [%d]'s size\n",i));
07188                         buffer_size += spoolss_size_form_1(&forms_1[i]);
07189                 }
07190                 for (; i<*numofforms; i++) {
07191                         DEBUGADD(6,("adding form [%d]'s size\n",i));
07192                         buffer_size += spoolss_size_form_1(&forms_1[i]);
07193                 }
07194 
07195                 *needed=buffer_size;            
07196                 
07197                 if (*needed > offered) {
07198                         SAFE_FREE(forms_1);
07199                         *numofforms=0;
07200                         return WERR_INSUFFICIENT_BUFFER;
07201                 }
07202         
07203                 if (!rpcbuf_alloc_size(buffer, buffer_size)){
07204                         SAFE_FREE(forms_1);
07205                         *numofforms=0;
07206                         return WERR_NOMEM;
07207                 }
07208 
07209                 /* fill the buffer with the form structures */
07210                 for (i=0; i<numbuiltinforms; i++) {
07211                         DEBUGADD(6,("adding form [%d] to buffer\n",i));
07212                         smb_io_form_1("", buffer, &forms_1[i], 0);
07213                 }
07214                 for (; i<*numofforms; i++) {
07215                         DEBUGADD(6,("adding form [%d] to buffer\n",i));
07216                         smb_io_form_1("", buffer, &forms_1[i], 0);
07217                 }
07218 
07219                 SAFE_FREE(forms_1);
07220 
07221                 return WERR_OK;
07222                         
07223         default:
07224                 SAFE_FREE(list);
07225                 SAFE_FREE(builtinlist);
07226                 return WERR_UNKNOWN_LEVEL;
07227         }
07228 }
07229 
07230 /****************************************************************************
07231 ****************************************************************************/
07232 
07233 WERROR _spoolss_getform(pipes_struct *p, SPOOL_Q_GETFORM *q_u, SPOOL_R_GETFORM *r_u)
07234 {
07235         uint32 level = q_u->level;
07236         UNISTR2 *uni_formname = &q_u->formname;
07237         RPC_BUFFER *buffer = NULL;
07238         uint32 offered = q_u->offered;
07239         uint32 *needed = &r_u->needed;
07240 
07241         nt_forms_struct *list=NULL;
07242         nt_forms_struct builtin_form;
07243         BOOL foundBuiltin;
07244         FORM_1 form_1;
07245         fstring form_name;
07246         int buffer_size=0;
07247         int numofforms=0, i=0;
07248 
07249         /* that's an [in out] buffer */
07250 
07251         if (!q_u->buffer && (offered!=0)) {
07252                 return WERR_INVALID_PARAM;
07253         }
07254 
07255         rpcbuf_move(q_u->buffer, &r_u->buffer);
07256         buffer = r_u->buffer;
07257 
07258         unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
07259 
07260         DEBUG(4,("_spoolss_getform\n"));
07261         DEBUGADD(5,("Offered buffer size [%d]\n", offered));
07262         DEBUGADD(5,("Info level [%d]\n",          level));
07263 
07264         foundBuiltin = get_a_builtin_ntform(uni_formname,&builtin_form);
07265         if (!foundBuiltin) {
07266                 numofforms = get_ntforms(&list);
07267                 DEBUGADD(5,("Number of forms [%d]\n",     numofforms));
07268 
07269                 if (numofforms == 0)
07270                         return WERR_BADFID;
07271         }
07272 
07273         switch (level) {
07274         case 1:
07275                 if (foundBuiltin) {
07276                         fill_form_1(&form_1, &builtin_form);
07277                 } else {
07278 
07279                         /* Check if the requested name is in the list of form structures */
07280                         for (i=0; i<numofforms; i++) {
07281 
07282                                 DEBUG(4,("_spoolss_getform: checking form %s (want %s)\n", list[i].name, form_name));
07283 
07284                                 if (strequal(form_name, list[i].name)) {
07285                                         DEBUGADD(6,("Found form %s number [%d]\n", form_name, i));
07286                                         fill_form_1(&form_1, &list[i]);
07287                                         break;
07288                                 }
07289                         }
07290                         
07291                         SAFE_FREE(list);
07292                         if (i == numofforms) {
07293                                 return WERR_BADFID;
07294                         }
07295                 }
07296                 /* check the required size. */
07297 
07298                 *needed=spoolss_size_form_1(&form_1);
07299                 
07300                 if (*needed > offered) 
07301                         return WERR_INSUFFICIENT_BUFFER;
07302 
07303                 if (!rpcbuf_alloc_size(buffer, buffer_size))
07304                         return WERR_NOMEM;
07305 
07306                 /* fill the buffer with the form structures */
07307                 DEBUGADD(6,("adding form %s [%d] to buffer\n", form_name, i));
07308                 smb_io_form_1("", buffer, &form_1, 0);
07309 
07310                 return WERR_OK;
07311                         
07312         default:
07313                 SAFE_FREE(list);
07314                 return WERR_UNKNOWN_LEVEL;
07315         }
07316 }
07317 
07318 /****************************************************************************
07319 ****************************************************************************/
07320 
07321 static void fill_port_1(PORT_INFO_1 *port, const char *name)
07322 {
07323         init_unistr(&port->port_name, name);
07324 }
07325 
07326 /****************************************************************************
07327  TODO: This probably needs distinguish between TCP/IP and Local ports 
07328  somehow.
07329 ****************************************************************************/
07330 
07331 static void fill_port_2(PORT_INFO_2 *port, const char *name)
07332 {
07333         init_unistr(&port->port_name, name);
07334         init_unistr(&port->monitor_name, "Local Monitor");
07335         init_unistr(&port->description, SPL_LOCAL_PORT );
07336         port->port_type=PORT_TYPE_WRITE;
07337         port->reserved=0x0;     
07338 }
07339 
07340 
07341 /****************************************************************************
07342  wrapper around the enumer ports command
07343 ****************************************************************************/
07344 
07345 WERROR enumports_hook( int *count, char ***lines )
07346 {
07347         char *cmd = lp_enumports_cmd();
07348         char **qlines;
07349         pstring command;
07350         int numlines;
07351         int ret;
07352         int fd;
07353 
07354         *count = 0;
07355         *lines = NULL;
07356 
07357         /* if no hook then just fill in the default port */
07358         
07359         if ( !*cmd ) {
07360                 qlines = SMB_MALLOC_ARRAY( char*, 2 );
07361                 qlines[0] = SMB_STRDUP( SAMBA_PRINTER_PORT_NAME );
07362                 qlines[1] = NULL;
07363                 numlines = 1;
07364         }
07365         else {
07366                 /* we have a valid enumport command */
07367                 
07368                 slprintf(command, sizeof(command)-1, "%s \"%d\"", cmd, 1);
07369 
07370                 DEBUG(10,("Running [%s]\n", command));
07371                 ret = smbrun(command, &fd);
07372                 DEBUG(10,("Returned [%d]\n", ret));
07373                 if (ret != 0) {
07374                         if (fd != -1) {
07375                                 close(fd);
07376                         }
07377                         return WERR_ACCESS_DENIED;
07378                 }
07379 
07380                 numlines = 0;
07381                 qlines = fd_lines_load(fd, &numlines, 0);
07382                 DEBUGADD(10,("Lines returned = [%d]\n", numlines));
07383                 close(fd);
07384         }
07385         
07386         *count = numlines;
07387         *lines = qlines;
07388 
07389         return WERR_OK;
07390 }
07391 
07392 /****************************************************************************
07393  enumports level 1.
07394 ****************************************************************************/
07395 
07396 static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
07397 {
07398         PORT_INFO_1 *ports=NULL;
07399         int i=0;
07400         WERROR result = WERR_OK;
07401         char **qlines = NULL;
07402         int numlines = 0;
07403 
07404         result = enumports_hook( &numlines, &qlines );
07405         if (!W_ERROR_IS_OK(result)) {
07406                 file_lines_free(qlines);
07407                 return result;
07408         }
07409         
07410         if(numlines) {
07411                 if((ports=SMB_MALLOC_ARRAY( PORT_INFO_1, numlines )) == NULL) {
07412                         DEBUG(10,("Returning WERR_NOMEM [%s]\n", 
07413                                   dos_errstr(WERR_NOMEM)));
07414                         file_lines_free(qlines);
07415                         return WERR_NOMEM;
07416                 }
07417 
07418                 for (i=0; i<numlines; i++) {
07419                         DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
07420                         fill_port_1(&ports[i], qlines[i]);
07421                 }
07422         }
07423         file_lines_free(qlines);
07424 
07425         *returned = numlines;
07426 
07427         /* check the required size. */
07428         for (i=0; i<*returned; i++) {
07429                 DEBUGADD(6,("adding port [%d]'s size\n", i));
07430                 *needed += spoolss_size_port_info_1(&ports[i]);
07431         }
07432                 
07433         if (*needed > offered) {
07434                 result = WERR_INSUFFICIENT_BUFFER;
07435                 goto out;
07436         }
07437 
07438         if (!rpcbuf_alloc_size(buffer, *needed)) {
07439                 result = WERR_NOMEM;
07440                 goto out;
07441         }
07442 
07443         /* fill the buffer with the ports structures */
07444         for (i=0; i<*returned; i++) {
07445                 DEBUGADD(6,("adding port [%d] to buffer\n", i));
07446                 smb_io_port_1("", buffer, &ports[i], 0);
07447         }
07448 
07449 out:
07450         SAFE_FREE(ports);
07451 
07452         if ( !W_ERROR_IS_OK(result) )
07453                 *returned = 0;
07454 
07455         return result;
07456 }
07457 
07458 /****************************************************************************
07459  enumports level 2.
07460 ****************************************************************************/
07461 
07462 static WERROR enumports_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
07463 {
07464         PORT_INFO_2 *ports=NULL;
07465         int i=0;
07466         WERROR result = WERR_OK;
07467         char **qlines = NULL;
07468         int numlines = 0;
07469 
07470         result = enumports_hook( &numlines, &qlines );
07471         if ( !W_ERROR_IS_OK(result)) {
07472                 file_lines_free(qlines);
07473                 return result;
07474         }
07475         
07476         if(numlines) {
07477                 if((ports=SMB_MALLOC_ARRAY( PORT_INFO_2, numlines)) == NULL) {
07478                         file_lines_free(qlines);
07479                         return WERR_NOMEM;
07480                 }
07481 
07482                 for (i=0; i<numlines; i++) {
07483                         DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
07484                         fill_port_2(&(ports[i]), qlines[i]);
07485                 }
07486         }
07487 
07488         file_lines_free(qlines);
07489 
07490         *returned = numlines;
07491 
07492         /* check the required size. */
07493         for (i=0; i<*returned; i++) {
07494                 DEBUGADD(6,("adding port [%d]'s size\n", i));
07495                 *needed += spoolss_size_port_info_2(&ports[i]);
07496         }
07497                 
07498         if (*needed > offered) {
07499                 result = WERR_INSUFFICIENT_BUFFER;
07500                 goto out;
07501         }
07502 
07503         if (!rpcbuf_alloc_size(buffer, *needed)) {
07504                 result = WERR_NOMEM;
07505                 goto out;
07506         }
07507 
07508         /* fill the buffer with the ports structures */
07509         for (i=0; i<*returned; i++) {
07510                 DEBUGADD(6,("adding port [%d] to buffer\n", i));
07511                 smb_io_port_2("", buffer, &ports[i], 0);
07512         }
07513 
07514 out:
07515         SAFE_FREE(ports);
07516 
07517         if ( !W_ERROR_IS_OK(result) )
07518                 *returned = 0;
07519 
07520         return result;
07521 }
07522 
07523 /****************************************************************************
07524  enumports.
07525 ****************************************************************************/
07526 
07527 WERROR _spoolss_enumports( pipes_struct *p, SPOOL_Q_ENUMPORTS *q_u, SPOOL_R_ENUMPORTS *r_u)
07528 {
07529         uint32 level = q_u->level;
07530         RPC_BUFFER *buffer = NULL;
07531         uint32 offered = q_u->offered;
07532         uint32 *needed = &r_u->needed;
07533         uint32 *returned = &r_u->returned;
07534 
07535         /* that's an [in out] buffer */
07536 
07537         if (!q_u->buffer && (offered!=0)) {
07538                 return WERR_INVALID_PARAM;
07539         }
07540 
07541         rpcbuf_move(q_u->buffer, &r_u->buffer);
07542         buffer = r_u->buffer;
07543 
07544         DEBUG(4,("_spoolss_enumports\n"));
07545         
07546         *returned=0;
07547         *needed=0;
07548         
07549         switch (level) {
07550         case 1:
07551                 return enumports_level_1(buffer, offered, needed, returned);
07552         case 2:
07553                 return enumports_level_2(buffer, offered, needed, returned);
07554         default:
07555                 return WERR_UNKNOWN_LEVEL;
07556         }
07557 }
07558 
07559 /****************************************************************************
07560 ****************************************************************************/
07561 
07562 static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_srv_name,
07563                                 const SPOOL_PRINTER_INFO_LEVEL *info,
07564                                 DEVICEMODE *devmode, SEC_DESC_BUF *sec_desc_buf,
07565                                 uint32 user_switch, const SPOOL_USER_CTR *user,
07566                                 POLICY_HND *handle)
07567 {
07568         NT_PRINTER_INFO_LEVEL *printer = NULL;
07569         fstring name;
07570         int     snum;
07571         WERROR err = WERR_OK;
07572 
07573         if ( !(printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) {
07574                 DEBUG(0,("spoolss_addprinterex_level_2: malloc fail.\n"));
07575                 return WERR_NOMEM;
07576         }
07577 
07578         /* convert from UNICODE to ASCII - this allocates the info_2 struct inside *printer.*/
07579         if (!convert_printer_info(info, printer, 2)) {
07580                 free_a_printer(&printer, 2);
07581                 return WERR_NOMEM;
07582         }
07583 
07584         /* check to see if the printer already exists */
07585 
07586         if ((snum = print_queue_snum(printer->info_2->sharename)) != -1) {
07587                 DEBUG(5, ("spoolss_addprinterex_level_2: Attempted to add a printer named [%s] when one already existed!\n", 
07588                         printer->info_2->sharename));
07589                 free_a_printer(&printer, 2);
07590                 return WERR_PRINTER_ALREADY_EXISTS;
07591         }
07592         
07593         /* FIXME!!!  smbd should check to see if the driver is installed before
07594            trying to add a printer like this  --jerry */
07595 
07596         if (*lp_addprinter_cmd() ) {
07597                 if ( !add_printer_hook(p->pipe_user.nt_user_token, printer) ) {
07598                         free_a_printer(&printer,2);
07599                         return WERR_ACCESS_DENIED;
07600                 }
07601         } else {
07602                 DEBUG(0,("spoolss_addprinterex_level_2: add printer for printer %s called and no"
07603                         "smb.conf parameter \"addprinter command\" is defined. This"
07604                         "parameter must exist for this call to succeed\n",
07605                         printer->info_2->sharename ));
07606         }
07607 
07608         /* use our primary netbios name since get_a_printer() will convert 
07609            it to what the client expects on a case by case basis */
07610 
07611         slprintf(name, sizeof(name)-1, "\\\\%s\\%s", global_myname(),
07612              printer->info_2->sharename);
07613 
07614         
07615         if ((snum = print_queue_snum(printer->info_2->sharename)) == -1) {
07616                 free_a_printer(&printer,2);
07617                 return WERR_ACCESS_DENIED;
07618         }
07619 
07620         /* you must be a printer admin to add a new printer */
07621         if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
07622                 free_a_printer(&printer,2);
07623                 return WERR_ACCESS_DENIED;              
07624         }
07625         
07626         /*
07627          * Do sanity check on the requested changes for Samba.
07628          */
07629 
07630         if (!check_printer_ok(printer->info_2, snum)) {
07631                 free_a_printer(&printer,2);
07632                 return WERR_INVALID_PARAM;
07633         }
07634 
07635         /*
07636          * When a printer is created, the drivername bound to the printer is used
07637          * to lookup previously saved driver initialization info, which is then 
07638          * bound to the new printer, simulating what happens in the Windows arch.
07639          */
07640 
07641         if (!devmode)
07642         {
07643                 set_driver_init(printer, 2);
07644         }
07645         else 
07646         {
07647                 /* A valid devmode was included, convert and link it
07648                 */
07649                 DEBUGADD(10, ("spoolss_addprinterex_level_2: devmode included, converting\n"));
07650 
07651                 if (!convert_devicemode(printer->info_2->printername, devmode,
07652                                 &printer->info_2->devmode))
07653                         return  WERR_NOMEM;
07654         }
07655 
07656         /* write the ASCII on disk */
07657         err = mod_a_printer(printer, 2);
07658         if (!W_ERROR_IS_OK(err)) {
07659                 free_a_printer(&printer,2);
07660                 return err;
07661         }
07662 
07663         if (!open_printer_hnd(p, handle, name, PRINTER_ACCESS_ADMINISTER)) {
07664                 /* Handle open failed - remove addition. */
07665                 del_a_printer(printer->info_2->sharename);
07666                 free_a_printer(&printer,2);
07667                 return WERR_ACCESS_DENIED;
07668         }
07669 
07670         update_c_setprinter(False);
07671         free_a_printer(&printer,2);
07672 
07673         return WERR_OK;
07674 }
07675 
07676 /****************************************************************************
07677 ****************************************************************************/
07678 
07679 WERROR _spoolss_addprinterex( pipes_struct *p, SPOOL_Q_ADDPRINTEREX *q_u, SPOOL_R_ADDPRINTEREX *r_u)
07680 {
07681         UNISTR2 *uni_srv_name = q_u->server_name;
07682         uint32 level = q_u->level;
07683         SPOOL_PRINTER_INFO_LEVEL *info = &q_u->info;
07684         DEVICEMODE *devmode = q_u->devmode_ctr.devmode;
07685         SEC_DESC_BUF *sdb = q_u->secdesc_ctr;
07686         uint32 user_switch = q_u->user_switch;
07687         SPOOL_USER_CTR *user = &q_u->user_ctr;
07688         POLICY_HND *handle = &r_u->handle;
07689 
07690         switch (level) {
07691                 case 1:
07692                         /* we don't handle yet */
07693                         /* but I know what to do ... */
07694                         return WERR_UNKNOWN_LEVEL;
07695                 case 2:
07696                         return spoolss_addprinterex_level_2(p, uni_srv_name, info,
07697                                                             devmode, sdb,
07698                                                             user_switch, user, handle);
07699                 default:
07700                         return WERR_UNKNOWN_LEVEL;
07701         }
07702 }
07703 
07704 /****************************************************************************
07705 ****************************************************************************/
07706 
07707 WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u, SPOOL_R_ADDPRINTERDRIVER *r_u)
07708 {
07709         uint32 level = q_u->level;
07710         SPOOL_PRINTER_DRIVER_INFO_LEVEL *info = &q_u->info;
07711         WERROR err = WERR_OK;
07712         NT_PRINTER_DRIVER_INFO_LEVEL driver;
07713         struct current_user user;
07714         fstring driver_name;
07715         uint32 version;
07716 
07717         ZERO_STRUCT(driver);
07718 
07719         get_current_user(&user, p);
07720         
07721         if (!convert_printer_driver_info(info, &driver, level)) {
07722                 err = WERR_NOMEM;
07723                 goto done;
07724         }
07725 
07726         DEBUG(5,("Cleaning driver's information\n"));
07727         err = clean_up_driver_struct(driver, level, &user);
07728         if (!W_ERROR_IS_OK(err))
07729                 goto done;
07730 
07731         DEBUG(5,("Moving driver to final destination\n"));
07732         if( !W_ERROR_IS_OK(err = move_driver_to_download_area(driver, level, &user, &err)) ) {
07733                 goto done;
07734         }
07735 
07736         if (add_a_printer_driver(driver, level)!=0) {
07737                 err = WERR_ACCESS_DENIED;
07738                 goto done;
07739         }
07740 
07741         /* 
07742          * I think this is where he DrvUpgradePrinter() hook would be
07743          * be called in a driver's interface DLL on a Windows NT 4.0/2k
07744          * server.  Right now, we just need to send ourselves a message
07745          * to update each printer bound to this driver.   --jerry       
07746          */
07747          
07748         if (!srv_spoolss_drv_upgrade_printer(driver_name)) {
07749                 DEBUG(0,("_spoolss_addprinterdriver: Failed to send message about upgrading driver [%s]!\n",
07750                         driver_name));
07751         }
07752 
07753         /*
07754          * Based on the version (e.g. driver destination dir: 0=9x,2=Nt/2k,3=2k/Xp),
07755          * decide if the driver init data should be deleted. The rules are:
07756          *  1) never delete init data if it is a 9x driver, they don't use it anyway
07757          *  2) delete init data only if there is no 2k/Xp driver
07758          *  3) always delete init data
07759          * The generalized rule is always use init data from the highest order driver.
07760          * It is necessary to follow the driver install by an initialization step to
07761          * finish off this process.
07762         */
07763         if (level == 3)
07764                 version = driver.info_3->cversion;
07765         else if (level == 6)
07766                 version = driver.info_6->version;
07767         else
07768                 version = -1;
07769         switch (version) {
07770                 /*
07771                  * 9x printer driver - never delete init data
07772                 */
07773                 case 0: 
07774                         DEBUG(10,("_spoolss_addprinterdriver: init data not deleted for 9x driver [%s]\n",
07775                                         driver_name));
07776                         break;
07777                 
07778                 /*
07779                  * Nt or 2k (compatiblity mode) printer driver - only delete init data if
07780                  * there is no 2k/Xp driver init data for this driver name.
07781                 */
07782                 case 2:
07783                 {
07784                         NT_PRINTER_DRIVER_INFO_LEVEL driver1;
07785 
07786                         if (!W_ERROR_IS_OK(get_a_printer_driver(&driver1, 3, driver_name, "Windows NT x86", 3))) {
07787                                 /*
07788                                  * No 2k/Xp driver found, delete init data (if any) for the new Nt driver.
07789                                 */
07790                                 if (!del_driver_init(driver_name))
07791                                         DEBUG(6,("_spoolss_addprinterdriver: del_driver_init(%s) Nt failed!\n", driver_name));
07792                         } else {
07793                                 /*
07794                                  * a 2k/Xp driver was found, don't delete init data because Nt driver will use it.
07795                                 */
07796                                 free_a_printer_driver(driver1,3);
07797                                 DEBUG(10,("_spoolss_addprinterdriver: init data not deleted for Nt driver [%s]\n", 
07798                                                 driver_name));
07799                         }
07800                 }
07801                 break;
07802 
07803                 /*
07804                  * 2k or Xp printer driver - always delete init data
07805                 */
07806                 case 3: 
07807                         if (!del_driver_init(driver_name))
07808                                 DEBUG(6,("_spoolss_addprinterdriver: del_driver_init(%s) 2k/Xp failed!\n", driver_name));
07809                         break;
07810 
07811                 default:
07812                         DEBUG(0,("_spoolss_addprinterdriver: invalid level=%d\n", level));
07813                         break;
07814         }
07815 
07816         
07817 done:
07818         free_a_printer_driver(driver, level);
07819         return err;
07820 }
07821 
07822 /********************************************************************
07823  * spoolss_addprinterdriverex
07824  ********************************************************************/
07825 
07826 WERROR _spoolss_addprinterdriverex(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVEREX *q_u, SPOOL_R_ADDPRINTERDRIVEREX *r_u)
07827 {
07828         SPOOL_Q_ADDPRINTERDRIVER q_u_local;
07829         SPOOL_R_ADDPRINTERDRIVER r_u_local;
07830         
07831         /* 
07832          * we only support the semantics of AddPrinterDriver()
07833          * i.e. only copy files that are newer than existing ones
07834          */
07835         
07836         if ( q_u->copy_flags != APD_COPY_NEW_FILES )
07837                 return WERR_ACCESS_DENIED;
07838         
07839         ZERO_STRUCT(q_u_local);
07840         ZERO_STRUCT(r_u_local);
07841 
07842         /* just pass the information off to _spoolss_addprinterdriver() */
07843         q_u_local.server_name_ptr = q_u->server_name_ptr;
07844         copy_unistr2(&q_u_local.server_name, &q_u->server_name);
07845         q_u_local.level = q_u->level;
07846         memcpy( &q_u_local.info, &q_u->info, sizeof(SPOOL_PRINTER_DRIVER_INFO_LEVEL) );
07847         
07848         return _spoolss_addprinterdriver( p, &q_u_local, &r_u_local );
07849 }
07850 
07851 /****************************************************************************
07852 ****************************************************************************/
07853 
07854 static void fill_driverdir_1(DRIVER_DIRECTORY_1 *info, char *name)
07855 {
07856         init_unistr(&info->name, name);
07857 }
07858 
07859 /****************************************************************************
07860 ****************************************************************************/
07861 
07862 static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environment, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
07863 {
07864         pstring path;
07865         pstring long_archi;
07866         fstring servername;
07867         const char *pservername; 
07868         const char *short_archi;
07869         DRIVER_DIRECTORY_1 *info=NULL;
07870         WERROR result = WERR_OK;
07871 
07872         unistr2_to_ascii(servername, name, sizeof(servername)-1);
07873         unistr2_to_ascii(long_archi, uni_environment, sizeof(long_archi)-1);
07874 
07875         pservername = canon_servername(servername);
07876         
07877         if ( !is_myname_or_ipaddr( pservername ) )
07878                 return WERR_INVALID_PARAM;
07879 
07880         if (!(short_archi = get_short_archi(long_archi)))
07881                 return WERR_INVALID_ENVIRONMENT;
07882 
07883         if((info=SMB_MALLOC_P(DRIVER_DIRECTORY_1)) == NULL)
07884                 return WERR_NOMEM;
07885 
07886         slprintf(path, sizeof(path)-1, "\\\\%s\\print$\\%s", pservername, short_archi);
07887 
07888         DEBUG(4,("printer driver directory: [%s]\n", path));
07889 
07890         fill_driverdir_1(info, path);
07891         
07892         *needed += spoolss_size_driverdir_info_1(info);
07893 
07894         if (*needed > offered) {
07895                 result = WERR_INSUFFICIENT_BUFFER;
07896                 goto out;
07897         }
07898 
07899         if (!rpcbuf_alloc_size(buffer, *needed)) {
07900                 result = WERR_NOMEM;
07901                 goto out;
07902         }
07903 
07904         smb_io_driverdir_1("", buffer, info, 0);
07905 
07906 out:
07907         SAFE_FREE(info);
07908         
07909         return result;
07910 }
07911 
07912 /****************************************************************************
07913 ****************************************************************************/
07914 
07915 WERROR _spoolss_getprinterdriverdirectory(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVERDIR *q_u, SPOOL_R_GETPRINTERDRIVERDIR *r_u)
07916 {
07917         UNISTR2 *name = &q_u->name;
07918         UNISTR2 *uni_environment = &q_u->environment;
07919         uint32 level = q_u->level;
07920         RPC_BUFFER *buffer = NULL;
07921         uint32 offered = q_u->offered;
07922         uint32 *needed = &r_u->needed;
07923 
07924         /* that's an [in out] buffer */
07925 
07926         if (!q_u->buffer && (offered!=0)) {
07927                 return WERR_INVALID_PARAM;
07928         }
07929 
07930         rpcbuf_move(q_u->buffer, &r_u->buffer);
07931         buffer = r_u->buffer;
07932 
07933         DEBUG(4,("_spoolss_getprinterdriverdirectory\n"));
07934 
07935         *needed=0;
07936 
07937         switch(level) {
07938         case 1:
07939                 return getprinterdriverdir_level_1(name, uni_environment, buffer, offered, needed);
07940         default:
07941                 return WERR_UNKNOWN_LEVEL;
07942         }
07943 }
07944         
07945 /****************************************************************************
07946 ****************************************************************************/
07947 
07948 WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, SPOOL_R_ENUMPRINTERDATA *r_u)
07949 {
07950         POLICY_HND *handle = &q_u->handle;
07951         uint32 idx               = q_u->index;
07952         uint32 in_value_len      = q_u->valuesize;
07953         uint32 in_data_len       = q_u->datasize;
07954         uint32 *out_max_value_len = &r_u->valuesize;
07955         uint16 **out_value       = &r_u->value;
07956         uint32 *out_value_len    = &r_u->realvaluesize;
07957         uint32 *out_type         = &r_u->type;
07958         uint32 *out_max_data_len = &r_u->datasize;
07959         uint8  **data_out        = &r_u->data;
07960         uint32 *out_data_len     = &r_u->realdatasize;
07961 
07962         NT_PRINTER_INFO_LEVEL *printer = NULL;
07963         
07964         uint32          biggest_valuesize;
07965         uint32          biggest_datasize;
07966         uint32          data_len;
07967         Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
07968         int             snum;
07969         WERROR          result;
07970         REGISTRY_VALUE  *val = NULL;
07971         NT_PRINTER_DATA *p_data;
07972         int             i, key_index, num_values;
07973         int             name_length;
07974         
07975         *out_type = 0;
07976 
07977         *out_max_data_len = 0;
07978         *data_out         = NULL;
07979         *out_data_len     = 0;
07980 
07981         DEBUG(5,("spoolss_enumprinterdata\n"));
07982 
07983         if (!Printer) {
07984                 DEBUG(2,("_spoolss_enumprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
07985                 return WERR_BADFID;
07986         }
07987 
07988         if (!get_printer_snum(p,handle, &snum))
07989                 return WERR_BADFID;
07990         
07991         result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
07992         if (!W_ERROR_IS_OK(result))
07993                 return result;
07994                 
07995         p_data = printer->info_2->data; 
07996         key_index = lookup_printerkey( p_data, SPOOL_PRINTERDATA_KEY );
07997 
07998         result = WERR_OK;
07999 
08000         /*
08001          * The NT machine wants to know the biggest size of value and data
08002          *
08003          * cf: MSDN EnumPrinterData remark section
08004          */
08005          
08006         if ( !in_value_len && !in_data_len && (key_index != -1) ) 
08007         {
08008                 DEBUGADD(6,("Activating NT mega-hack to find sizes\n"));
08009 
08010                 biggest_valuesize = 0;
08011                 biggest_datasize  = 0;
08012                                 
08013                 num_values = regval_ctr_numvals( p_data->keys[key_index].values );
08014         
08015                 for ( i=0; i<num_values; i++ )
08016                 {
08017                         val = regval_ctr_specific_value( p_data->keys[key_index].values, i );
08018                         
08019                         name_length = strlen(val->valuename);
08020                         if ( strlen(val->valuename) > biggest_valuesize ) 
08021                                 biggest_valuesize = name_length;
08022                                 
08023                         if ( val->size > biggest_datasize )
08024                                 biggest_datasize = val->size;
08025                                 
08026                         DEBUG(6,("current values: [%d], [%d]\n", biggest_valuesize, 
08027                                 biggest_datasize));
08028                 }
08029 
08030                 /* the value is an UNICODE string but real_value_size is the length 
08031                    in bytes including the trailing 0 */
08032                    
08033                 *out_value_len = 2 * (1+biggest_valuesize);
08034                 *out_data_len  = biggest_datasize;
08035 
08036                 DEBUG(6,("final values: [%d], [%d]\n", *out_value_len, *out_data_len));
08037 
08038                 goto done;
08039         }
08040         
08041         /*
08042          * the value len is wrong in NT sp3
08043          * that's the number of bytes not the number of unicode chars
08044          */
08045         
08046         if ( key_index != -1 )
08047                 val = regval_ctr_specific_value( p_data->keys[key_index].values, idx );
08048 
08049         if ( !val ) 
08050         {
08051 
08052                 /* out_value should default to "" or else NT4 has
08053                    problems unmarshalling the response */
08054 
08055                 *out_max_value_len=(in_value_len/sizeof(uint16));
08056                 
08057                 if (in_value_len) {
08058                         if((*out_value=(uint16 *)TALLOC_ZERO(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL)
08059                         {
08060                                 result = WERR_NOMEM;
08061                                 goto done;
08062                         }
08063                         *out_value_len = (uint32)rpcstr_push((char *)*out_value, "", in_value_len, 0);
08064                 } else {
08065                         *out_value=NULL;
08066                         *out_value_len = 0;
08067                 }
08068 
08069                 /* the data is counted in bytes */
08070                 
08071                 *out_max_data_len = in_data_len;
08072                 *out_data_len     = in_data_len;
08073                 
08074                 /* only allocate when given a non-zero data_len */
08075                 
08076                 if ( in_data_len && ((*data_out=(uint8 *)TALLOC_ZERO(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL) )
08077                 {
08078                         result = WERR_NOMEM;
08079                         goto done;
08080                 }
08081 
08082                 result = WERR_NO_MORE_ITEMS;
08083         }
08084         else 
08085         {
08086                 /*
08087                  * the value is:
08088                  * - counted in bytes in the request
08089                  * - counted in UNICODE chars in the max reply
08090                  * - counted in bytes in the real size
08091                  *
08092                  * take a pause *before* coding not *during* coding
08093                  */
08094         
08095                 /* name */
08096                 *out_max_value_len=(in_value_len/sizeof(uint16));
08097                 if (in_value_len) {
08098                         if ( (*out_value = (uint16 *)TALLOC_ZERO(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL ) 
08099                         {
08100                                 result = WERR_NOMEM;
08101                                 goto done;
08102                         }
08103         
08104                         *out_value_len = (uint32)rpcstr_push((char *)*out_value, regval_name(val), (size_t)in_value_len, 0);
08105                 } else {
08106                         *out_value = NULL;
08107                         *out_value_len = 0;
08108                 }
08109 
08110                 /* type */
08111                 
08112                 *out_type = regval_type( val );
08113 
08114                 /* data - counted in bytes */
08115 
08116                 *out_max_data_len = in_data_len;
08117                 if ( in_data_len && (*data_out = (uint8 *)TALLOC_ZERO(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL) 
08118                 {
08119                         result = WERR_NOMEM;
08120                         goto done;
08121                 }
08122                 data_len = regval_size(val);
08123                 if ( *data_out && data_len )
08124                         memcpy( *data_out, regval_data_p(val), data_len );
08125                 *out_data_len = data_len;
08126         }
08127 
08128 done:
08129         free_a_printer(&printer, 2);
08130         return result;
08131 }
08132 
08133 /****************************************************************************
08134 ****************************************************************************/
08135 
08136 WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SPOOL_R_SETPRINTERDATA *r_u)
08137 {
08138         POLICY_HND              *handle = &q_u->handle;
08139         UNISTR2                 *value = &q_u->value;
08140         uint32                  type = q_u->type;
08141         uint8                   *data = q_u->data;
08142         uint32                  real_len = q_u->real_len;
08143 
08144         NT_PRINTER_INFO_LEVEL   *printer = NULL;
08145         int                     snum=0;
08146         WERROR                  status = WERR_OK;
08147         Printer_entry           *Printer=find_printer_index_by_hnd(p, handle);
08148         fstring                 valuename;
08149         
08150         DEBUG(5,("spoolss_setprinterdata\n"));
08151 
08152         if (!Printer) {
08153                 DEBUG(2,("_spoolss_setprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
08154                 return WERR_BADFID;
08155         }
08156 
08157         if ( Printer->printer_type == SPLHND_SERVER ) {
08158                 DEBUG(10,("_spoolss_setprinterdata: Not implemented for server handles yet\n"));
08159                 return WERR_INVALID_PARAM;
08160         }
08161 
08162         if (!get_printer_snum(p,handle, &snum))
08163                 return WERR_BADFID;
08164 
08165         /* 
08166          * Access check : NT returns "access denied" if you make a 
08167          * SetPrinterData call without the necessary privildge.
08168          * we were originally returning OK if nothing changed
08169          * which made Win2k issue **a lot** of SetPrinterData
08170          * when connecting to a printer  --jerry
08171          */
08172 
08173         if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) 
08174         {
08175                 DEBUG(3, ("_spoolss_setprinterdata: change denied by handle access permissions\n"));
08176                 status = WERR_ACCESS_DENIED;
08177                 goto done;
08178         }
08179 
08180         status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
08181         if (!W_ERROR_IS_OK(status))
08182                 return status;
08183 
08184         unistr2_to_ascii( valuename, value, sizeof(valuename)-1 );
08185         
08186         /*
08187          * When client side code sets a magic printer data key, detect it and save
08188          * the current printer data and the magic key's data (its the DEVMODE) for
08189          * future printer/driver initializations.
08190          */
08191         if ( (type == REG_BINARY) && strequal( valuename, PHANTOM_DEVMODE_KEY)) 
08192         {
08193                 /* Set devmode and printer initialization info */
08194                 status = save_driver_init( printer, 2, data, real_len );
08195         
08196                 srv_spoolss_reset_printerdata( printer->info_2->drivername );
08197         }
08198         else 
08199         {
08200         status = set_printer_dataex( printer, SPOOL_PRINTERDATA_KEY, valuename, 
08201                                         type, data, real_len );
08202                 if ( W_ERROR_IS_OK(status) )
08203                         status = mod_a_printer(printer, 2);
08204         }
08205 
08206 done:
08207         free_a_printer(&printer, 2);
08208 
08209         return status;
08210 }
08211 
08212 /****************************************************************************
08213 ****************************************************************************/
08214 
08215 WERROR _spoolss_resetprinter(pipes_struct *p, SPOOL_Q_RESETPRINTER *q_u, SPOOL_R_RESETPRINTER *r_u)
08216 {
08217         POLICY_HND      *handle = &q_u->handle;
08218         Printer_entry   *Printer=find_printer_index_by_hnd(p, handle);
08219         int             snum;
08220         
08221         DEBUG(5,("_spoolss_resetprinter\n"));
08222 
08223         /*
08224          * All we do is to check to see if the handle and queue is valid.
08225          * This call really doesn't mean anything to us because we only
08226          * support RAW printing.   --jerry
08227          */
08228          
08229         if (!Printer) {
08230                 DEBUG(2,("_spoolss_resetprinter: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
08231                 return WERR_BADFID;
08232         }
08233 
08234         if (!get_printer_snum(p,handle, &snum))
08235                 return WERR_BADFID;
08236 
08237 
08238         /* blindly return success */    
08239         return WERR_OK;
08240 }
08241 
08242 
08243 /****************************************************************************
08244 ****************************************************************************/
08245 
08246 WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_u, SPOOL_R_DELETEPRINTERDATA *r_u)
08247 {
08248         POLICY_HND      *handle = &q_u->handle;
08249         UNISTR2         *value = &q_u->valuename;
08250 
08251         NT_PRINTER_INFO_LEVEL   *printer = NULL;
08252         int             snum=0;
08253         WERROR          status = WERR_OK;
08254         Printer_entry   *Printer=find_printer_index_by_hnd(p, handle);
08255         pstring         valuename;
08256         
08257         DEBUG(5,("spoolss_deleteprinterdata\n"));
08258         
08259         if (!Printer) {
08260                 DEBUG(2,("_spoolss_deleteprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
08261                 return WERR_BADFID;
08262         }
08263 
08264         if (!get_printer_snum(p, handle, &snum))
08265                 return WERR_BADFID;
08266 
08267         if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
08268                 DEBUG(3, ("_spoolss_deleteprinterdata: printer properties change denied by handle\n"));
08269                 return WERR_ACCESS_DENIED;
08270         }
08271 
08272         status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
08273         if (!W_ERROR_IS_OK(status))
08274                 return status;
08275 
08276         unistr2_to_ascii( valuename, value, sizeof(valuename)-1 );
08277 
08278         status = delete_printer_dataex( printer, SPOOL_PRINTERDATA_KEY, valuename );
08279         
08280         if ( W_ERROR_IS_OK(status) )
08281                 mod_a_printer( printer, 2 );
08282 
08283         free_a_printer(&printer, 2);
08284 
08285         return status;
08286 }
08287 
08288 /****************************************************************************
08289 ****************************************************************************/
08290 
08291 WERROR _spoolss_addform( pipes_struct *p, SPOOL_Q_ADDFORM *q_u, SPOOL_R_ADDFORM *r_u)
08292 {
08293         POLICY_HND *handle = &q_u->handle;
08294         FORM *form = &q_u->form;
08295         nt_forms_struct tmpForm;
08296         int snum;
08297         WERROR status = WERR_OK;
08298         NT_PRINTER_INFO_LEVEL *printer = NULL;
08299 
08300         int count=0;
08301         nt_forms_struct *list=NULL;
08302         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
08303 
08304         DEBUG(5,("spoolss_addform\n"));
08305 
08306         if (!Printer) {
08307                 DEBUG(2,("_spoolss_addform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
08308                 return WERR_BADFID;
08309         }
08310         
08311         
08312         /* forms can be added on printer of on the print server handle */
08313         
08314         if ( Printer->printer_type == SPLHND_PRINTER )
08315         {
08316                 if (!get_printer_snum(p,handle, &snum))
08317                         return WERR_BADFID;
08318          
08319                 status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
08320                 if (!W_ERROR_IS_OK(status))
08321                         goto done;
08322         }
08323 
08324         if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
08325                 DEBUG(2,("_spoolss_addform: denied by handle permissions.\n"));
08326                 status = WERR_ACCESS_DENIED;
08327                 goto done;
08328         }
08329         
08330         /* can't add if builtin */
08331         
08332         if (get_a_builtin_ntform(&form->name,&tmpForm)) {
08333                 status = WERR_ALREADY_EXISTS;
08334                 goto done;
08335         }
08336 
08337         count = get_ntforms(&list);
08338         
08339         if(!add_a_form(&list, form, &count)) {
08340                 status =  WERR_NOMEM;
08341                 goto done;
08342         }
08343         
08344         write_ntforms(&list, count);
08345         
08346         /*
08347          * ChangeID must always be set if this is a printer
08348          */
08349          
08350         if ( Printer->printer_type == SPLHND_PRINTER )
08351                 status = mod_a_printer(printer, 2);
08352         
08353 done:
08354         if ( printer )
08355                 free_a_printer(&printer, 2);
08356         SAFE_FREE(list);
08357 
08358         return status;
08359 }
08360 
08361 /****************************************************************************
08362 ****************************************************************************/
08363 
08364 WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DELETEFORM *r_u)
08365 {
08366         POLICY_HND *handle = &q_u->handle;
08367         UNISTR2 *form_name = &q_u->name;
08368         nt_forms_struct tmpForm;
08369         int count=0;
08370         nt_forms_struct *list=NULL;
08371         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
08372         int snum;
08373         WERROR status = WERR_OK;
08374         NT_PRINTER_INFO_LEVEL *printer = NULL;
08375 
08376         DEBUG(5,("spoolss_deleteform\n"));
08377 
08378         if (!Printer) {
08379                 DEBUG(2,("_spoolss_deleteform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
08380                 return WERR_BADFID;
08381         }
08382 
08383         /* forms can be deleted on printer of on the print server handle */
08384         
08385         if ( Printer->printer_type == SPLHND_PRINTER )
08386         {
08387                 if (!get_printer_snum(p,handle, &snum))
08388                         return WERR_BADFID;
08389          
08390                 status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
08391                 if (!W_ERROR_IS_OK(status))
08392                         goto done;
08393         }
08394 
08395         if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
08396                 DEBUG(2,("_spoolss_deleteform: denied by handle permissions.\n"));
08397                 status = WERR_ACCESS_DENIED;
08398                 goto done;
08399         }
08400 
08401         /* can't delete if builtin */
08402         
08403         if (get_a_builtin_ntform(form_name,&tmpForm)) {
08404                 status = WERR_INVALID_PARAM;
08405                 goto done;
08406         }
08407 
08408         count = get_ntforms(&list);
08409         
08410         if ( !delete_a_form(&list, form_name, &count, &status ))
08411                 goto done;
08412 
08413         /*
08414          * ChangeID must always be set if this is a printer
08415          */
08416          
08417         if ( Printer->printer_type == SPLHND_PRINTER )
08418                 status = mod_a_printer(printer, 2);
08419         
08420 done:
08421         if ( printer )
08422                 free_a_printer(&printer, 2);
08423         SAFE_FREE(list);
08424 
08425         return status;
08426 }
08427 
08428 /****************************************************************************
08429 ****************************************************************************/
08430 
08431 WERROR _spoolss_setform(pipes_struct *p, SPOOL_Q_SETFORM *q_u, SPOOL_R_SETFORM *r_u)
08432 {
08433         POLICY_HND *handle = &q_u->handle;
08434         FORM *form = &q_u->form;
08435         nt_forms_struct tmpForm;
08436         int snum;
08437         WERROR status = WERR_OK;
08438         NT_PRINTER_INFO_LEVEL *printer = NULL;
08439 
08440         int count=0;
08441         nt_forms_struct *list=NULL;
08442         Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
08443 
08444         DEBUG(5,("spoolss_setform\n"));
08445 
08446         if (!Printer) {
08447                 DEBUG(2,("_spoolss_setform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
08448                 return WERR_BADFID;
08449         }
08450 
08451         /* forms can be modified on printer of on the print server handle */
08452         
08453         if ( Printer->printer_type == SPLHND_PRINTER )
08454         {
08455                 if (!get_printer_snum(p,handle, &snum))
08456                         return WERR_BADFID;
08457          
08458                 status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
08459                 if (!W_ERROR_IS_OK(status))
08460                         goto done;
08461         }
08462 
08463         if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
08464                 DEBUG(2,("_spoolss_setform: denied by handle permissions\n"));
08465                 status = WERR_ACCESS_DENIED;
08466                 goto done;
08467         }
08468 
08469         /* can't set if builtin */
08470         if (get_a_builtin_ntform(&form->name,&tmpForm)) {
08471                 status = WERR_INVALID_PARAM;
08472                 goto done;
08473         }
08474 
08475         count = get_ntforms(&list);
08476         update_a_form(&list, form, count);
08477         write_ntforms(&list, count);
08478 
08479         /*
08480          * ChangeID must always be set if this is a printer
08481          */
08482          
08483         if ( Printer->printer_type == SPLHND_PRINTER )
08484                 status = mod_a_printer(printer, 2);
08485         
08486         
08487 done:
08488         if ( printer )
08489                 free_a_printer(&printer, 2);
08490         SAFE_FREE(list);
08491 
08492         return status;
08493 }
08494 
08495 /****************************************************************************
08496  enumprintprocessors level 1.
08497 ****************************************************************************/
08498 
08499 static WERROR enumprintprocessors_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
08500 {
08501         PRINTPROCESSOR_1 *info_1=NULL;
08502         WERROR result = WERR_OK;
08503         
08504         if((info_1 = SMB_MALLOC_P(PRINTPROCESSOR_1)) == NULL)
08505                 return WERR_NOMEM;
08506 
08507         (*returned) = 0x1;
08508         
08509         init_unistr(&info_1->name, "winprint");
08510 
08511         *needed += spoolss_size_printprocessor_info_1(info_1);
08512 
08513         if (*needed > offered) {
08514                 result = WERR_INSUFFICIENT_BUFFER;
08515                 goto out;
08516         }
08517 
08518         if (!rpcbuf_alloc_size(buffer, *needed)) {
08519                 result = WERR_NOMEM;
08520                 goto out;
08521         }
08522 
08523         smb_io_printprocessor_info_1("", buffer, info_1, 0);
08524 
08525 out:
08526         SAFE_FREE(info_1);
08527 
08528         if ( !W_ERROR_IS_OK(result) )
08529                 *returned = 0;
08530 
08531         return result;
08532 }
08533 
08534 /****************************************************************************
08535 ****************************************************************************/
08536 
08537 WERROR _spoolss_enumprintprocessors(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, SPOOL_R_ENUMPRINTPROCESSORS *r_u)
08538 {
08539         uint32 level = q_u->level;
08540         RPC_BUFFER *buffer = NULL;
08541         uint32 offered = q_u->offered;
08542         uint32 *needed = &r_u->needed;
08543         uint32 *returned = &r_u->returned;
08544 
08545         /* that's an [in out] buffer */
08546 
08547         if (!q_u->buffer && (offered!=0)) {
08548                 return WERR_INVALID_PARAM;
08549         }
08550 
08551         rpcbuf_move(q_u->buffer, &r_u->buffer);
08552         buffer = r_u->buffer;
08553 
08554         DEBUG(5,("spoolss_enumprintprocessors\n"));
08555 
08556         /*
08557          * Enumerate the print processors ...
08558          *
08559          * Just reply with "winprint", to keep NT happy
08560          * and I can use my nice printer checker.
08561          */
08562         
08563         *returned=0;
08564         *needed=0;
08565         
08566         switch (level) {
08567         case 1:
08568                 return enumprintprocessors_level_1(buffer, offered, needed, returned);
08569         default:
08570                 return WERR_UNKNOWN_LEVEL;
08571         }
08572 }
08573 
08574 /****************************************************************************
08575  enumprintprocdatatypes level 1.
08576 ****************************************************************************/
08577 
08578 static WERROR enumprintprocdatatypes_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
08579 {
08580         PRINTPROCDATATYPE_1 *info_1=NULL;
08581         WERROR result = WERR_OK;
08582         
08583         if((info_1 = SMB_MALLOC_P(PRINTPROCDATATYPE_1)) == NULL)
08584                 return WERR_NOMEM;
08585 
08586         (*returned) = 0x1;
08587         
08588         init_unistr(&info_1->name, "RAW");
08589 
08590         *needed += spoolss_size_printprocdatatype_info_1(info_1);
08591 
08592         if (*needed > offered) {
08593                 result = WERR_INSUFFICIENT_BUFFER;
08594                 goto out;
08595         }
08596 
08597         if (!rpcbuf_alloc_size(buffer, *needed)) {
08598                 result = WERR_NOMEM;
08599                 goto out;
08600         }
08601 
08602         smb_io_printprocdatatype_info_1("", buffer, info_1, 0);
08603 
08604 out:
08605         SAFE_FREE(info_1);
08606 
08607         if ( !W_ERROR_IS_OK(result) )
08608                 *returned = 0;
08609 
08610         return result;
08611 }
08612 
08613 /****************************************************************************
08614 ****************************************************************************/
08615 
08616 WERROR _spoolss_enumprintprocdatatypes(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u)
08617 {
08618         uint32 level = q_u->level;
08619         RPC_BUFFER *buffer = NULL;
08620         uint32 offered = q_u->offered;
08621         uint32 *needed = &r_u->needed;
08622         uint32 *returned = &r_u->returned;
08623 
08624         /* that's an [in out] buffer */
08625 
08626         if (!q_u->buffer && (offered!=0)) {
08627                 return WERR_INVALID_PARAM;
08628         }
08629 
08630         rpcbuf_move(q_u->buffer, &r_u->buffer);
08631         buffer = r_u->buffer;
08632 
08633         DEBUG(5,("_spoolss_enumprintprocdatatypes\n"));
08634         
08635         *returned=0;
08636         *needed=0;
08637         
08638         switch (level) {
08639         case 1:
08640                 return enumprintprocdatatypes_level_1(buffer, offered, needed, returned);
08641         default:
08642                 return WERR_UNKNOWN_LEVEL;
08643         }
08644 }
08645 
08646 /****************************************************************************
08647  enumprintmonitors level 1.
08648 ****************************************************************************/
08649 
08650 static WERROR enumprintmonitors_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
08651 {
08652         PRINTMONITOR_1 *info_1;
08653         WERROR result = WERR_OK;
08654         int i;
08655         
08656         if((info_1 = SMB_MALLOC_ARRAY(PRINTMONITOR_1, 2)) == NULL)
08657                 return WERR_NOMEM;
08658 
08659         *returned = 2;
08660         
08661         init_unistr(&(info_1[0].name), SPL_LOCAL_PORT ); 
08662         init_unistr(&(info_1[1].name), SPL_TCPIP_PORT );
08663 
08664         for ( i=0; i<*returned; i++ ) {
08665                 *needed += spoolss_size_printmonitor_info_1(&info_1[i]);
08666         }
08667         
08668         if (*needed > offered) {
08669                 result = WERR_INSUFFICIENT_BUFFER;
08670                 goto out;
08671         }
08672 
08673         if (!rpcbuf_alloc_size(buffer, *needed)) {
08674                 result = WERR_NOMEM;
08675                 goto out;
08676         }
08677 
08678         for ( i=0; i<*returned; i++ ) {
08679                 smb_io_printmonitor_info_1("", buffer, &info_1[i], 0);
08680         }
08681 
08682 out:
08683         SAFE_FREE(info_1);
08684 
08685         if ( !W_ERROR_IS_OK(result) )
08686                 *returned = 0;
08687 
08688         return result;
08689 }
08690 
08691 /****************************************************************************
08692  enumprintmonitors level 2.
08693 ****************************************************************************/
08694 
08695 static WERROR enumprintmonitors_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
08696 {
08697         PRINTMONITOR_2 *info_2;
08698         WERROR result = WERR_OK;
08699         int i;
08700         
08701         if((info_2 = SMB_MALLOC_ARRAY(PRINTMONITOR_2, 2)) == NULL)
08702                 return WERR_NOMEM;
08703 
08704         *returned = 2;
08705         
08706         init_unistr( &(info_2[0].name), SPL_LOCAL_PORT );
08707         init_unistr( &(info_2[0].environment), "Windows NT X86" );
08708         init_unistr( &(info_2[0].dll_name), "localmon.dll" );
08709         
08710         init_unistr( &(info_2[1].name), SPL_TCPIP_PORT );
08711         init_unistr( &(info_2[1].environment), "Windows NT X86" );
08712         init_unistr( &(info_2[1].dll_name), "tcpmon.dll" );
08713 
08714         for ( i=0; i<*returned; i++ ) {
08715                 *needed += spoolss_size_printmonitor_info_2(&info_2[i]);
08716         }
08717         
08718         if (*needed > offered) {
08719                 result = WERR_INSUFFICIENT_BUFFER;
08720                 goto out;
08721         }
08722 
08723         if (!rpcbuf_alloc_size(buffer, *needed)) {
08724                 result = WERR_NOMEM;
08725                 goto out;
08726         }
08727 
08728         for ( i=0; i<*returned; i++ ) {
08729                 smb_io_printmonitor_info_2("", buffer, &info_2[i], 0);
08730         }
08731 
08732 out:
08733         SAFE_FREE(info_2);
08734 
08735         if ( !W_ERROR_IS_OK(result) )
08736                 *returned = 0;
08737         
08738         return result;
08739 }
08740 
08741 /****************************************************************************
08742 ****************************************************************************/
08743 
08744 WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_u, SPOOL_R_ENUMPRINTMONITORS *r_u)
08745 {
08746         uint32 level = q_u->level;
08747         RPC_BUFFER *buffer = NULL;
08748         uint32 offered = q_u->offered;
08749         uint32 *needed = &r_u->needed;
08750         uint32 *returned = &r_u->returned;
08751 
08752         /* that's an [in out] buffer */
08753 
08754         if (!q_u->buffer && (offered!=0)) {
08755                 return WERR_INVALID_PARAM;
08756         }
08757 
08758         rpcbuf_move(q_u->buffer, &r_u->buffer);
08759         buffer = r_u->buffer;
08760 
08761         DEBUG(5,("spoolss_enumprintmonitors\n"));
08762 
08763         /*
08764          * Enumerate the print monitors ...
08765          *
08766          * Just reply with "Local Port", to keep NT happy
08767          * and I can use my nice printer checker.
08768          */
08769         
08770         *returned=0;
08771         *needed=0;
08772         
08773         switch (level) {
08774         case 1:
08775                 return enumprintmonitors_level_1(buffer, offered, needed, returned);
08776         case 2:
08777                 return enumprintmonitors_level_2(buffer, offered, needed, returned);
08778         default:
08779                 return WERR_UNKNOWN_LEVEL;
08780         }
08781 }
08782 
08783 /****************************************************************************
08784 ****************************************************************************/
08785 
08786 static WERROR getjob_level_1(print_queue_struct **queue, int count, int snum,
08787                              NT_PRINTER_INFO_LEVEL *ntprinter,
08788                              uint32 jobid, RPC_BUFFER *buffer, uint32 offered, 
08789                              uint32 *needed)
08790 {
08791         int i=0;
08792         BOOL found=False;
08793         JOB_INFO_1 *info_1=NULL;
08794         WERROR result = WERR_OK;
08795 
08796         info_1=SMB_MALLOC_P(JOB_INFO_1);
08797 
08798         if (info_1 == NULL) {
08799                 return WERR_NOMEM;
08800         }
08801                 
08802         for (i=0; i<count && found==False; i++) { 
08803                 if ((*queue)[i].job==(int)jobid)
08804                         found=True;
08805         }
08806         
08807         if (found==False) {
08808                 SAFE_FREE(info_1);
08809                 /* NT treats not found as bad param... yet another bad choice */
08810                 return WERR_INVALID_PARAM;
08811         }
08812         
08813         fill_job_info_1( info_1, &((*queue)[i-1]), i, snum, ntprinter );
08814         
08815         *needed += spoolss_size_job_info_1(info_1);
08816 
08817         if (*needed > offered) {
08818                 result = WERR_INSUFFICIENT_BUFFER;
08819                 goto out;
08820         }
08821 
08822         if (!rpcbuf_alloc_size(buffer, *needed)) {
08823                 result = WERR_NOMEM;
08824                 goto out;
08825         }
08826 
08827         smb_io_job_info_1("", buffer, info_1, 0);
08828 
08829 out:
08830         SAFE_FREE(info_1);
08831 
08832         return result;
08833 }
08834 
08835 /****************************************************************************
08836 ****************************************************************************/
08837 
08838 static WERROR getjob_level_2(print_queue_struct **queue, int count, int snum, 
08839                              NT_PRINTER_INFO_LEVEL *ntprinter,
08840                              uint32 jobid, RPC_BUFFER *buffer, uint32 offered, 
08841                              uint32 *needed)
08842 {
08843         int             i = 0;
08844         BOOL            found = False;
08845         JOB_INFO_2      *info_2;
08846         WERROR          result;
08847         DEVICEMODE      *devmode = NULL;
08848         NT_DEVICEMODE   *nt_devmode = NULL;
08849 
08850         if ( !(info_2=SMB_MALLOC_P(JOB_INFO_2)) )
08851                 return WERR_NOMEM;
08852 
08853         ZERO_STRUCTP(info_2);
08854 
08855         for ( i=0; i<count && found==False; i++ ) 
08856         {
08857                 if ((*queue)[i].job == (int)jobid)
08858                         found = True;
08859         }
08860         
08861         if ( !found ) {
08862                 /* NT treats not found as bad param... yet another bad
08863                    choice */
08864                 result = WERR_INVALID_PARAM;
08865                 goto done;
08866         }
08867         
08868         /* 
08869          * if the print job does not have a DEVMODE associated with it, 
08870          * just use the one for the printer. A NULL devicemode is not
08871          *  a failure condition
08872          */
08873          
08874         if ( !(nt_devmode=print_job_devmode( lp_const_servicename(snum), jobid )) )
08875                 devmode = construct_dev_mode(lp_const_servicename(snum));
08876         else {
08877                 if ((devmode = SMB_MALLOC_P(DEVICEMODE)) != NULL) {
08878                         ZERO_STRUCTP( devmode );
08879                         convert_nt_devicemode( devmode, nt_devmode );
08880                 }
08881         }
08882         
08883         fill_job_info_2(info_2, &((*queue)[i-1]), i, snum, ntprinter, devmode);
08884         
08885         *needed += spoolss_size_job_info_2(info_2);
08886 
08887         if (*needed > offered) {
08888                 result = WERR_INSUFFICIENT_BUFFER;
08889                 goto done;
08890         }
08891 
08892         if (!rpcbuf_alloc_size(buffer, *needed)) {
08893                 result = WERR_NOMEM;
08894                 goto done;
08895         }
08896 
08897         smb_io_job_info_2("", buffer, info_2, 0);
08898 
08899         result = WERR_OK;
08900         
08901  done:
08902         /* Cleanup allocated memory */
08903 
08904         free_job_info_2(info_2);        /* Also frees devmode */
08905         SAFE_FREE(info_2);
08906 
08907         return result;
08908 }
08909 
08910 /****************************************************************************
08911 ****************************************************************************/
08912 
08913 WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_u)
08914 {
08915         POLICY_HND *handle = &q_u->handle;
08916         uint32 jobid = q_u->jobid;
08917         uint32 level = q_u->level;
08918         RPC_BUFFER *buffer = NULL;
08919         uint32 offered = q_u->offered;
08920         uint32 *needed = &r_u->needed;
08921         WERROR          wstatus = WERR_OK;
08922         NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
08923         int snum;
08924         int count;
08925         print_queue_struct      *queue = NULL;
08926         print_status_struct prt_status;
08927 
08928         /* that's an [in out] buffer */
08929 
08930         if (!q_u->buffer && (offered!=0)) {
08931                 return WERR_INVALID_PARAM;
08932         }
08933 
08934         rpcbuf_move(q_u->buffer, &r_u->buffer);
08935         buffer = r_u->buffer;
08936 
08937         DEBUG(5,("spoolss_getjob\n"));
08938         
08939         *needed = 0;
08940         
08941         if (!get_printer_snum(p, handle, &snum))
08942                 return WERR_BADFID;
08943         
08944         wstatus = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
08945         if ( !W_ERROR_IS_OK(wstatus) )
08946                 return wstatus;
08947                 
08948         count = print_queue_status(snum, &queue, &prt_status);
08949         
08950         DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n",
08951                      count, prt_status.status, prt_status.message));
08952                 
08953         switch ( level ) {
08954         case 1:
08955                         wstatus = getjob_level_1(&queue, count, snum, ntprinter, jobid, 
08956                                 buffer, offered, needed);
08957                         break;
08958         case 2:
08959                         wstatus = getjob_level_2(&queue, count, snum, ntprinter, jobid, 
08960                                 buffer, offered, needed);
08961                         break;
08962         default:
08963                         wstatus = WERR_UNKNOWN_LEVEL;
08964                         break;
08965         }
08966         
08967         SAFE_FREE(queue);
08968         free_a_printer( &ntprinter, 2 );
08969         
08970         return wstatus;
08971 }
08972 
08973 /********************************************************************
08974  spoolss_getprinterdataex
08975  
08976  From MSDN documentation of GetPrinterDataEx: pass request
08977  to GetPrinterData if key is "PrinterDriverData".
08978  ********************************************************************/
08979 
08980 WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u, SPOOL_R_GETPRINTERDATAEX *r_u)
08981 {
08982         POLICY_HND      *handle = &q_u->handle;
08983         uint32          in_size = q_u->size;
08984         uint32          *type = &r_u->type;
08985         uint32          *out_size = &r_u->size;
08986         uint8           **data = &r_u->data;
08987         uint32          *needed = &r_u->needed;
08988         fstring         keyname, valuename;
08989         
08990         Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
08991         
08992         NT_PRINTER_INFO_LEVEL   *printer = NULL;
08993         int                     snum = 0;
08994         WERROR                  status = WERR_OK;
08995 
08996         DEBUG(4,("_spoolss_getprinterdataex\n"));
08997 
08998         unistr2_to_ascii(keyname, &q_u->keyname, sizeof(keyname) - 1);
08999         unistr2_to_ascii(valuename, &q_u->valuename, sizeof(valuename) - 1);
09000         
09001         DEBUG(10, ("_spoolss_getprinterdataex: key => [%s], value => [%s]\n", 
09002                 keyname, valuename));
09003 
09004         /* in case of problem, return some default values */
09005         
09006         *needed   = 0;
09007         *type     = 0;
09008         *out_size = in_size;
09009 
09010         if (!Printer) {
09011                 DEBUG(2,("_spoolss_getprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
09012                 status = WERR_BADFID;
09013                 goto done;
09014         }
09015 
09016         /* Is the handle to a printer or to the server? */
09017 
09018         if (Printer->printer_type == SPLHND_SERVER) {
09019                 DEBUG(10,("_spoolss_getprinterdataex: Not implemented for server handles yet\n"));
09020                 status = WERR_INVALID_PARAM;
09021                 goto done;
09022         }
09023         
09024         if ( !get_printer_snum(p,handle, &snum) )
09025                 return WERR_BADFID;
09026 
09027         status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
09028         if ( !W_ERROR_IS_OK(status) )
09029                 goto done;
09030 
09031         /* check to see if the keyname is valid */
09032         if ( !strlen(keyname) ) {
09033                 status = WERR_INVALID_PARAM;
09034                 goto done;
09035         }
09036         
09037         if ( lookup_printerkey( printer->info_2->data, keyname ) == -1 ) {
09038                 DEBUG(4,("_spoolss_getprinterdataex: Invalid keyname [%s]\n", keyname ));
09039                 free_a_printer( &printer, 2 );
09040                 status = WERR_BADFILE;
09041                 goto done;
09042         }
09043         
09044         /* When given a new keyname, we should just create it */
09045 
09046         status = get_printer_dataex( p->mem_ctx, printer, keyname, valuename, type, data, needed, in_size );
09047         
09048         if (*needed > *out_size)
09049                 status = WERR_MORE_DATA;
09050 
09051 done:
09052         if ( !W_ERROR_IS_OK(status) ) 
09053         {
09054                 DEBUG(5, ("error: allocating %d\n", *out_size));
09055                 
09056                 /* reply this param doesn't exist */
09057                 
09058                 if ( *out_size ) 
09059                 {
09060                         if( (*data=(uint8 *)TALLOC_ZERO(p->mem_ctx, *out_size*sizeof(uint8))) == NULL ) {
09061                                 status = WERR_NOMEM;
09062                                 goto done;
09063                         }
09064                 } else {
09065                         *data = NULL;
09066                 }
09067         }
09068         
09069         if ( printer )
09070         free_a_printer( &printer, 2 );
09071         
09072         return status;
09073 }
09074 
09075 /********************************************************************
09076  * spoolss_setprinterdataex
09077  ********************************************************************/
09078 
09079 WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u, SPOOL_R_SETPRINTERDATAEX *r_u)
09080 {
09081         POLICY_HND              *handle = &q_u->handle; 
09082         uint32                  type = q_u->type;
09083         uint8                   *data = q_u->data;
09084         uint32                  real_len = q_u->real_len;
09085 
09086         NT_PRINTER_INFO_LEVEL   *printer = NULL;
09087         int                     snum = 0;
09088         WERROR                  status = WERR_OK;
09089         Printer_entry           *Printer = find_printer_index_by_hnd(p, handle);
09090         fstring                 valuename;
09091         fstring                 keyname;
09092         char                    *oid_string;
09093         
09094         DEBUG(4,("_spoolss_setprinterdataex\n"));
09095 
09096         /* From MSDN documentation of SetPrinterDataEx: pass request to
09097            SetPrinterData if key is "PrinterDriverData" */
09098 
09099         if (!Printer) {
09100                 DEBUG(2,("_spoolss_setprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
09101                 return WERR_BADFID;
09102         }
09103 
09104         if ( Printer->printer_type == SPLHND_SERVER ) {
09105                 DEBUG(10,("_spoolss_setprinterdataex: Not implemented for server handles yet\n"));
09106                 return WERR_INVALID_PARAM;
09107         }
09108 
09109         if ( !get_printer_snum(p,handle, &snum) )
09110                 return WERR_BADFID;
09111 
09112         /* 
09113          * Access check : NT returns "access denied" if you make a 
09114          * SetPrinterData call without the necessary privildge.
09115          * we were originally returning OK if nothing changed
09116          * which made Win2k issue **a lot** of SetPrinterData
09117          * when connecting to a printer  --jerry
09118          */
09119 
09120         if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) 
09121         {
09122                 DEBUG(3, ("_spoolss_setprinterdataex: change denied by handle access permissions\n"));
09123                 return WERR_ACCESS_DENIED;
09124         }
09125 
09126         status = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
09127         if (!W_ERROR_IS_OK(status))
09128                 return status;
09129 
09130         unistr2_to_ascii( valuename, &q_u->value, sizeof(valuename) - 1);
09131         unistr2_to_ascii( keyname, &q_u->key, sizeof(keyname) - 1);
09132         
09133         /* check for OID in valuename */
09134         
09135         if ( (oid_string = strchr( valuename, ',' )) != NULL )
09136         {
09137                 *oid_string = '\0';
09138                 oid_string++;
09139         }
09140 
09141         /* save the registry data */
09142         
09143         status = set_printer_dataex( printer, keyname, valuename, type, data, real_len ); 
09144         
09145         if ( W_ERROR_IS_OK(status) )
09146         {
09147                 /* save the OID if one was specified */
09148                 if ( oid_string ) {
09149                         fstrcat( keyname, "\\" );
09150                         fstrcat( keyname, SPOOL_OID_KEY );
09151                 
09152                         /* 
09153                          * I'm not checking the status here on purpose.  Don't know 
09154                          * if this is right, but I'm returning the status from the 
09155                          * previous set_printer_dataex() call.  I have no idea if 
09156                          * this is right.    --jerry
09157                          */
09158                  
09159                         set_printer_dataex( printer, keyname, valuename, 
09160                                             REG_SZ, (void*)oid_string, strlen(oid_string)+1 );          
09161                 }
09162         
09163                 status = mod_a_printer(printer, 2);
09164         }
09165                 
09166         free_a_printer(&printer, 2);
09167 
09168         return status;
09169 }
09170 
09171 
09172 /********************************************************************
09173  * spoolss_deleteprinterdataex
09174  ********************************************************************/
09175 
09176 WERROR _spoolss_deleteprinterdataex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATAEX *q_u, SPOOL_R_DELETEPRINTERDATAEX *r_u)
09177 {
09178         POLICY_HND      *handle = &q_u->handle;
09179         UNISTR2         *value = &q_u->valuename;
09180         UNISTR2         *key = &q_u->keyname;
09181 
09182         NT_PRINTER_INFO_LEVEL   *printer = NULL;
09183         int             snum=0;
09184         WERROR          status = WERR_OK;
09185         Printer_entry   *Printer=find_printer_index_by_hnd(p, handle);
09186         pstring         valuename, keyname;
09187         
09188         DEBUG(5,("spoolss_deleteprinterdataex\n"));
09189         
09190         if (!Printer) {
09191                 DEBUG(2,("_spoolss_deleteprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
09192                 return WERR_BADFID;
09193         }
09194 
09195         if (!get_printer_snum(p, handle, &snum))
09196                 return WERR_BADFID;
09197 
09198         if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
09199                 DEBUG(3, ("_spoolss_deleteprinterdataex: printer properties change denied by handle\n"));
09200                 return WERR_ACCESS_DENIED;
09201         }
09202 
09203         status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
09204         if (!W_ERROR_IS_OK(status))
09205                 return status;
09206 
09207         unistr2_to_ascii( valuename, value, sizeof(valuename)-1 );
09208         unistr2_to_ascii( keyname, key, sizeof(keyname)-1 );
09209 
09210         status = delete_printer_dataex( printer, keyname, valuename );
09211 
09212         if ( W_ERROR_IS_OK(status) )
09213                 mod_a_printer( printer, 2 );
09214                 
09215         free_a_printer(&printer, 2);
09216 
09217         return status;
09218 }
09219 
09220 /********************************************************************
09221  * spoolss_enumprinterkey
09222  ********************************************************************/
09223 
09224 
09225 WERROR _spoolss_enumprinterkey(pipes_struct *p, SPOOL_Q_ENUMPRINTERKEY *q_u, SPOOL_R_ENUMPRINTERKEY *r_u)
09226 {
09227         fstring         key;
09228         fstring         *keynames = NULL;
09229         uint16          *enumkeys = NULL;
09230         int             num_keys;
09231         int             printerkey_len;
09232         POLICY_HND      *handle = &q_u->handle;
09233         Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
09234         NT_PRINTER_DATA *data;
09235         NT_PRINTER_INFO_LEVEL   *printer = NULL;
09236         int             snum = 0;
09237         WERROR          status = WERR_BADFILE;
09238         
09239         
09240         DEBUG(4,("_spoolss_enumprinterkey\n"));
09241 
09242         if (!Printer) {
09243                 DEBUG(2,("_spoolss_enumprinterkey: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
09244                 return WERR_BADFID;
09245         }
09246 
09247         if ( !get_printer_snum(p,handle, &snum) )
09248                 return WERR_BADFID;
09249 
09250         status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
09251         if (!W_ERROR_IS_OK(status))
09252                 return status;
09253                 
09254         /* get the list of subkey names */
09255         
09256         unistr2_to_ascii( key, &q_u->key, sizeof(key)-1 );
09257         data = printer->info_2->data;
09258 
09259         num_keys = get_printer_subkeys( data, key, &keynames );
09260 
09261         if ( num_keys == -1 ) {
09262                 status = WERR_BADFILE;
09263                 goto done;
09264         }
09265 
09266         printerkey_len = init_unistr_array( &enumkeys,  keynames, NULL );
09267 
09268         r_u->needed = printerkey_len*2;
09269 
09270         if ( q_u->size < r_u->needed ) {
09271                 status = WERR_MORE_DATA;
09272                 goto done;
09273         }
09274 
09275         if (!make_spoolss_buffer5(p->mem_ctx, &r_u->keys, printerkey_len, enumkeys)) {
09276                 status = WERR_NOMEM;
09277                 goto done;
09278         }
09279                         
09280         status = WERR_OK;
09281 
09282         if ( q_u->size < r_u->needed ) 
09283                 status = WERR_MORE_DATA;
09284 
09285 done:
09286         free_a_printer( &printer, 2 );
09287         SAFE_FREE( keynames );
09288         
09289         return status;
09290 }
09291 
09292 /********************************************************************
09293  * spoolss_deleteprinterkey
09294  ********************************************************************/
09295 
09296 WERROR _spoolss_deleteprinterkey(pipes_struct *p, SPOOL_Q_DELETEPRINTERKEY *q_u, SPOOL_R_DELETEPRINTERKEY *r_u)
09297 {
09298         POLICY_HND              *handle = &q_u->handle;
09299         Printer_entry           *Printer = find_printer_index_by_hnd(p, &q_u->handle);
09300         fstring                 key;
09301         NT_PRINTER_INFO_LEVEL   *printer = NULL;
09302         int                     snum=0;
09303         WERROR                  status;
09304         
09305         DEBUG(5,("spoolss_deleteprinterkey\n"));
09306         
09307         if (!Printer) {
09308                 DEBUG(2,("_spoolss_deleteprinterkey: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
09309                 return WERR_BADFID;
09310         }
09311 
09312         /* if keyname == NULL, return error */
09313         
09314         if ( !q_u->keyname.buffer )
09315                 return WERR_INVALID_PARAM;
09316                 
09317         if (!get_printer_snum(p, handle, &snum))
09318                 return WERR_BADFID;
09319 
09320         if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
09321                 DEBUG(3, ("_spoolss_deleteprinterkey: printer properties change denied by handle\n"));
09322                 return WERR_ACCESS_DENIED;
09323         }
09324 
09325         status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
09326         if (!W_ERROR_IS_OK(status))
09327                 return status;
09328         
09329         /* delete the key and all subneys */
09330         
09331         unistr2_to_ascii(key, &q_u->keyname, sizeof(key) - 1);
09332  
09333         status = delete_all_printer_data( printer->info_2, key );       
09334 
09335         if ( W_ERROR_IS_OK(status) )
09336                 status = mod_a_printer(printer, 2);
09337         
09338         free_a_printer( &printer, 2 );
09339         
09340         return status;
09341 }
09342 
09343 
09344 /********************************************************************
09345  * spoolss_enumprinterdataex
09346  ********************************************************************/
09347 
09348 WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_u, SPOOL_R_ENUMPRINTERDATAEX *r_u)
09349 {
09350         POLICY_HND      *handle = &q_u->handle; 
09351         uint32          in_size = q_u->size;
09352         uint32          num_entries, 
09353                         needed;
09354         NT_PRINTER_INFO_LEVEL   *printer = NULL;
09355         PRINTER_ENUM_VALUES     *enum_values = NULL;
09356         NT_PRINTER_DATA         *p_data;
09357         fstring         key;
09358         Printer_entry   *Printer = find_printer_index_by_hnd(p, handle);
09359         int             snum;
09360         WERROR          result;
09361         int             key_index;
09362         int             i;
09363         REGISTRY_VALUE  *val;
09364         char            *value_name;
09365         uint32          data_len;
09366         
09367 
09368         DEBUG(4,("_spoolss_enumprinterdataex\n"));
09369 
09370         if (!Printer) {
09371                 DEBUG(2,("_spoolss_enumprinterdataex: Invalid handle (%s:%u:%u1<).\n", OUR_HANDLE(handle)));
09372                 return WERR_BADFID;
09373         }
09374 
09375         /* 
09376          * first check for a keyname of NULL or "".  Win2k seems to send 
09377          * this a lot and we should send back WERR_INVALID_PARAM
09378          * no need to spend time looking up the printer in this case.
09379          * --jerry
09380          */
09381          
09382         unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
09383         if ( !strlen(key) ) {
09384                 result = WERR_INVALID_PARAM;
09385                 goto done;
09386         }
09387 
09388         /* get the printer off of disk */
09389         
09390         if (!get_printer_snum(p,handle, &snum))
09391                 return WERR_BADFID;
09392         
09393         ZERO_STRUCT(printer);
09394         result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
09395         if (!W_ERROR_IS_OK(result))
09396                 return result;
09397         
09398         /* now look for a match on the key name */
09399         
09400         p_data = printer->info_2->data;
09401         
09402         unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1);
09403         if ( (key_index = lookup_printerkey( p_data, key)) == -1  )
09404         {
09405                 DEBUG(10,("_spoolss_enumprinterdataex: Unknown keyname [%s]\n", key));
09406                 result = WERR_INVALID_PARAM;
09407                 goto done;
09408         }
09409         
09410         result = WERR_OK;
09411         needed = 0;
09412         
09413         /* allocate the memory for the array of pointers -- if necessary */
09414         
09415         num_entries = regval_ctr_numvals( p_data->keys[key_index].values );
09416         if ( num_entries )
09417         {
09418                 if ( (enum_values=TALLOC_ARRAY(p->mem_ctx, PRINTER_ENUM_VALUES, num_entries)) == NULL )
09419                 {
09420                         DEBUG(0,("_spoolss_enumprinterdataex: talloc() failed to allocate memory for [%lu] bytes!\n",
09421                                 (unsigned long)num_entries*sizeof(PRINTER_ENUM_VALUES)));
09422                         result = WERR_NOMEM;
09423                         goto done;
09424                 }
09425 
09426                 memset( enum_values, 0x0, num_entries*sizeof(PRINTER_ENUM_VALUES) );
09427         }
09428                 
09429         /* 
09430          * loop through all params and build the array to pass 
09431          * back to the  client 
09432          */
09433          
09434         for ( i=0; i<num_entries; i++ )
09435         {
09436                 /* lookup the registry value */
09437                 
09438                 val = regval_ctr_specific_value( p_data->keys[key_index].values, i );
09439                 DEBUG(10,("retrieved value number [%d] [%s]\n", i, regval_name(val) ));
09440 
09441                 /* copy the data */
09442                 
09443                 value_name = regval_name( val );
09444                 init_unistr( &enum_values[i].valuename, value_name );
09445                 enum_values[i].value_len = (strlen(value_name)+1) * 2;
09446                 enum_values[i].type      = regval_type( val );
09447                 
09448                 data_len = regval_size( val );
09449                 if ( data_len ) {
09450                         if ( !(enum_values[i].data = TALLOC_MEMDUP(p->mem_ctx, regval_data_p(val), data_len)) ) 
09451                         {
09452                                 DEBUG(0,("TALLOC_MEMDUP failed to allocate memory [data_len=%d] for data!\n", 
09453                                         data_len ));
09454                                 result = WERR_NOMEM;
09455                                 goto done;
09456                         }
09457                 }
09458                 enum_values[i].data_len = data_len;
09459 
09460                 /* keep track of the size of the array in bytes */
09461                 
09462                 needed += spoolss_size_printer_enum_values(&enum_values[i]);
09463         }
09464         
09465         /* housekeeping information in the reply */
09466         
09467         /* Fix from Martin Zielinski <mz@seh.de> - ensure
09468          * the hand marshalled container size is a multiple
09469          * of 4 bytes for RPC alignment.
09470          */
09471 
09472         if (needed % 4) {
09473                 needed += 4-(needed % 4);
09474         }
09475 
09476         r_u->needed     = needed;
09477         r_u->returned   = num_entries;
09478 
09479         if (needed > in_size) {
09480                 result = WERR_MORE_DATA;
09481                 goto done;
09482         }
09483                 
09484         /* copy data into the reply */
09485 
09486         /* mz: Vista x64 returns 0x6f7 (The stub received bad data), if the
09487            response buffer size is != the offered buffer size
09488 
09489                 r_u->ctr.size           = r_u->needed;
09490         */
09491         r_u->ctr.size           = in_size;
09492 
09493         r_u->ctr.size_of_array  = r_u->returned;
09494         r_u->ctr.values         = enum_values;
09495         
09496         
09497                 
09498 done:   
09499         if ( printer )
09500         free_a_printer(&printer, 2);
09501 
09502         return result;
09503 }
09504 
09505 /****************************************************************************
09506 ****************************************************************************/
09507 
09508 static void fill_printprocessordirectory_1(PRINTPROCESSOR_DIRECTORY_1 *info, char *name)
09509 {
09510         init_unistr(&info->name, name);
09511 }
09512 
09513 static WERROR getprintprocessordirectory_level_1(UNISTR2 *name, 
09514                                                  UNISTR2 *environment, 
09515                                                  RPC_BUFFER *buffer, 
09516                                                  uint32 offered, 
09517                                                  uint32 *needed)
09518 {
09519         pstring path;
09520         pstring long_archi;
09521         PRINTPROCESSOR_DIRECTORY_1 *info=NULL;
09522         WERROR result = WERR_OK;
09523 
09524         unistr2_to_ascii(long_archi, environment, sizeof(long_archi)-1);
09525 
09526         if (!get_short_archi(long_archi))
09527                 return WERR_INVALID_ENVIRONMENT;
09528 
09529         if((info=SMB_MALLOC_P(PRINTPROCESSOR_DIRECTORY_1)) == NULL)
09530                 return WERR_NOMEM;
09531 
09532         pstrcpy(path, "C:\\WINNT\\System32\\spool\\PRTPROCS\\W32X86");
09533 
09534         fill_printprocessordirectory_1(info, path);
09535         
09536         *needed += spoolss_size_printprocessordirectory_info_1(info);
09537 
09538         if (*needed > offered) {
09539                 result = WERR_INSUFFICIENT_BUFFER;
09540                 goto out;
09541         }
09542 
09543         if (!rpcbuf_alloc_size(buffer, *needed)) {
09544                 result = WERR_INSUFFICIENT_BUFFER;
09545                 goto out;
09546         }
09547 
09548         smb_io_printprocessordirectory_1("", buffer, info, 0);
09549 
09550 out:
09551         SAFE_FREE(info);
09552         
09553         return result;
09554 }
09555 
09556 WERROR _spoolss_getprintprocessordirectory(pipes_struct *p, SPOOL_Q_GETPRINTPROCESSORDIRECTORY *q_u, SPOOL_R_GETPRINTPROCESSORDIRECTORY *r_u)
09557 {
09558         uint32 level = q_u->level;
09559         RPC_BUFFER *buffer = NULL;
09560         uint32 offered = q_u->offered;
09561         uint32 *needed = &r_u->needed;
09562         WERROR result;
09563 
09564         /* that's an [in out] buffer */
09565 
09566         if (!q_u->buffer && (offered!=0)) {
09567                 return WERR_INVALID_PARAM;
09568         }
09569 
09570         rpcbuf_move(q_u->buffer, &r_u->buffer);
09571         buffer = r_u->buffer;
09572 
09573         DEBUG(5,("_spoolss_getprintprocessordirectory\n"));
09574         
09575         *needed=0;
09576 
09577         switch(level) {
09578         case 1:
09579                 result = getprintprocessordirectory_level_1
09580                   (&q_u->name, &q_u->environment, buffer, offered, needed);
09581                 break;
09582         default:
09583                 result = WERR_UNKNOWN_LEVEL;
09584         }
09585 
09586         return result;
09587 }
09588 
09589 /*******************************************************************
09590  Streams the monitor UI DLL name in UNICODE
09591 *******************************************************************/
09592 
09593 static WERROR xcvtcp_monitorui( NT_USER_TOKEN *token, RPC_BUFFER *in, 
09594                                 RPC_BUFFER *out, uint32 *needed )
09595 {
09596         const char *dllname = "tcpmonui.dll";
09597         
09598         *needed = (strlen(dllname)+1) * 2;
09599         
09600         if ( rpcbuf_get_size(out) < *needed ) {
09601                 return WERR_INSUFFICIENT_BUFFER;                
09602         }
09603         
09604         if ( !make_monitorui_buf( out, dllname ) ) {
09605                 return WERR_NOMEM;
09606         }
09607         
09608         return WERR_OK;
09609 }
09610 
09611 /*******************************************************************
09612  Create a new TCP/IP port
09613 *******************************************************************/
09614 
09615 static WERROR xcvtcp_addport( NT_USER_TOKEN *token, RPC_BUFFER *in, 
09616                               RPC_BUFFER *out, uint32 *needed )
09617 {
09618         NT_PORT_DATA_1 port1;
09619         pstring device_uri;
09620 
09621         ZERO_STRUCT( port1 );
09622 
09623         /* convert to our internal port data structure */
09624 
09625         if ( !convert_port_data_1( &port1, in ) ) {
09626                 return WERR_NOMEM;
09627         }
09628 
09629         /* create the device URI and call the add_port_hook() */
09630 
09631         switch ( port1.protocol ) {
09632         case PORT_PROTOCOL_DIRECT:
09633                 pstr_sprintf( device_uri, "socket://%s:%d/", port1.hostaddr, port1.port );
09634                 break;
09635 
09636         case PORT_PROTOCOL_LPR:
09637                 pstr_sprintf( device_uri, "lpr://%s/%s", port1.hostaddr, port1.queue );
09638                 break;
09639         
09640         default:
09641                 return WERR_UNKNOWN_PORT;
09642         }
09643 
09644         return add_port_hook( token, port1.name, device_uri );
09645 }
09646 
09647 /*******************************************************************
09648 *******************************************************************/
09649 
09650 struct xcv_api_table xcvtcp_cmds[] = {
09651         { "MonitorUI",  xcvtcp_monitorui },
09652         { "AddPort",    xcvtcp_addport},
09653         { NULL,         NULL }
09654 };
09655 
09656 static WERROR process_xcvtcp_command( NT_USER_TOKEN *token, const char *command, 
09657                                       RPC_BUFFER *inbuf, RPC_BUFFER *outbuf, 
09658                                       uint32 *needed )
09659 {
09660         int i;
09661         
09662         DEBUG(10,("process_xcvtcp_command: Received command \"%s\"\n", command));
09663         
09664         for ( i=0; xcvtcp_cmds[i].name; i++ ) {
09665                 if ( strcmp( command, xcvtcp_cmds[i].name ) == 0 )
09666                         return xcvtcp_cmds[i].fn( token, inbuf, outbuf, needed );
09667         }
09668         
09669         return WERR_BADFUNC;
09670 }
09671 
09672 /*******************************************************************
09673 *******************************************************************/
09674 #if 0   /* don't support management using the "Local Port" monitor */
09675 
09676 static WERROR xcvlocal_monitorui( NT_USER_TOKEN *token, RPC_BUFFER *in, 
09677                                   RPC_BUFFER *out, uint32 *needed )
09678 {
09679         const char *dllname = "localui.dll";
09680         
09681         *needed = (strlen(dllname)+1) * 2;
09682         
09683         if ( rpcbuf_get_size(out) < *needed ) {
09684                 return WERR_INSUFFICIENT_BUFFER;                
09685         }
09686         
09687         if ( !make_monitorui_buf( out, dllname )) {
09688                 return WERR_NOMEM;
09689         }
09690         
09691         return WERR_OK;
09692 }
09693 
09694 /*******************************************************************
09695 *******************************************************************/
09696 
09697 struct xcv_api_table xcvlocal_cmds[] = {
09698         { "MonitorUI",  xcvlocal_monitorui },
09699         { NULL,         NULL }
09700 };
09701 #else
09702 struct xcv_api_table xcvlocal_cmds[] = {
09703         { NULL,         NULL }
09704 };
09705 #endif
09706 
09707 
09708 
09709 /*******************************************************************
09710 *******************************************************************/
09711 
09712 static WERROR process_xcvlocal_command( NT_USER_TOKEN *token, const char *command, 
09713                                         RPC_BUFFER *inbuf, RPC_BUFFER *outbuf, 
09714                                         uint32 *needed )
09715 {
09716         int i;
09717         
09718         DEBUG(10,("process_xcvlocal_command: Received command \"%s\"\n", command));
09719 
09720         for ( i=0; xcvlocal_cmds[i].name; i++ ) {
09721                 if ( strcmp( command, xcvlocal_cmds[i].name ) == 0 )
09722                         return xcvlocal_cmds[i].fn( token, inbuf, outbuf , needed );
09723         }
09724         return WERR_BADFUNC;
09725 }
09726 
09727 /*******************************************************************
09728 *******************************************************************/
09729 
09730 WERROR _spoolss_xcvdataport(pipes_struct *p, SPOOL_Q_XCVDATAPORT *q_u, SPOOL_R_XCVDATAPORT *r_u)
09731 {       
09732         Printer_entry *Printer = find_printer_index_by_hnd(p, &q_u->handle);
09733         fstring command;
09734 
09735         if (!Printer) {
09736                 DEBUG(2,("_spoolss_xcvdataport: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(&q_u->handle)));
09737                 return WERR_BADFID;
09738         }
09739 
09740         /* Has to be a handle to the TCP/IP port monitor */
09741         
09742         if ( !(Printer->printer_type & (SPLHND_PORTMON_LOCAL|SPLHND_PORTMON_TCP)) ) {
09743                 DEBUG(2,("_spoolss_xcvdataport: Call only valid for Port Monitors\n"));
09744                 return WERR_BADFID;
09745         }
09746         
09747         /* requires administrative access to the server */
09748         
09749         if ( !(Printer->access_granted & SERVER_ACCESS_ADMINISTER) ) {
09750                 DEBUG(2,("_spoolss_xcvdataport: denied by handle permissions.\n"));
09751                 return WERR_ACCESS_DENIED;
09752         }
09753 
09754         /* Get the command name.  There's numerous commands supported by the 
09755            TCPMON interface. */
09756         
09757         rpcstr_pull(command, q_u->dataname.buffer, sizeof(command), 
09758                 q_u->dataname.uni_str_len*2, 0);
09759                 
09760         /* Allocate the outgoing buffer */
09761         
09762         rpcbuf_init( &r_u->outdata, q_u->offered, p->mem_ctx );
09763         
09764         switch ( Printer->printer_type ) {
09765         case SPLHND_PORTMON_TCP:
09766                 return process_xcvtcp_command( p->pipe_user.nt_user_token, command, 
09767                         &q_u->indata, &r_u->outdata, &r_u->needed );
09768         case SPLHND_PORTMON_LOCAL:
09769                 return process_xcvlocal_command( p->pipe_user.nt_user_token, command, 
09770                         &q_u->indata, &r_u->outdata, &r_u->needed );
09771         }
09772 
09773         return WERR_INVALID_PRINT_MONITOR;
09774 }
09775 
09776 

Sambaに対してSat Aug 29 21:23:22 2009に生成されました。  doxygen 1.4.7