spoolss: clear FormInfo on GetForm error
[obnox/samba/samba-obnox.git] / source3 / rpc_server / spoolss / srv_spoolss_nt.c
index 7482443c74ec59651ee672f9eeb5dd21b5b83d3a..9b898d0ab539a3aafe0481b91e7756c9bd25e3be 100644 (file)
@@ -138,6 +138,7 @@ struct notify_back_channel {
 
        /* print notify back-channel pipe handle*/
        struct rpc_pipe_client *cli_pipe;
+       struct cli_state *cli;
        uint32_t active_connections;
 };
 
@@ -276,7 +277,7 @@ static void srv_spoolss_replycloseprinter(int snum,
        /* if it's the last connection, deconnect the IPC$ share */
        if (prn_hnd->notify.cli_chan->active_connections == 1) {
 
-               cli_shutdown(rpc_pipe_np_smb_conn(prn_hnd->notify.cli_chan->cli_pipe));
+               cli_shutdown(prn_hnd->notify.cli_chan->cli);
                DLIST_REMOVE(back_channels, prn_hnd->notify.cli_chan);
                TALLOC_FREE(prn_hnd->notify.cli_chan);
 
@@ -374,7 +375,7 @@ static WERROR delete_printer_hook(TALLOC_CTX *ctx, struct security_token *token,
                                  const char *sharename,
                                  struct messaging_context *msg_ctx)
 {
-       char *cmd = lp_deleteprinter_cmd(talloc_tos());
+       char *cmd = lp_deleteprinter_command(talloc_tos());
        char *command = NULL;
        int ret;
        bool is_print_op = false;
@@ -630,16 +631,17 @@ static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx,
 
        cache_key = talloc_asprintf(talloc_tos(), "PRINTERNAME/%s",
                                    aprinter);
-       if ((cache_key != NULL) && gencache_get(cache_key, &tmp, NULL)) {
+       if ((cache_key != NULL) &&
+           gencache_get(cache_key, talloc_tos(), &tmp, NULL)) {
 
                found = (strcmp(tmp, printer_not_found) != 0);
                if (!found) {
                        DEBUG(4, ("Printer %s not found\n", aprinter));
-                       SAFE_FREE(tmp);
+                       TALLOC_FREE(tmp);
                        return WERR_INVALID_PRINTER_NAME;
                }
                fstrcpy(sname, tmp);
-               SAFE_FREE(tmp);
+               TALLOC_FREE(tmp);
        }
 
        /* Search all sharenames first as this is easier than pulling
@@ -651,7 +653,7 @@ static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx,
                const char *printer = lp_const_servicename(snum);
 
                /* no point going on if this is not a printer */
-               if (!(lp_snum_ok(snum) && lp_print_ok(snum))) {
+               if (!(lp_snum_ok(snum) && lp_printable(snum))) {
                        continue;
                }
 
@@ -844,14 +846,6 @@ static bool is_monitoring_event(struct printer_handle *p, uint16_t notify_type,
 #define SETUP_SPOOLSS_NOTIFY_DATA_DEVMODE(_data, _devmode) \
        _data->data.devmode.devmode = _devmode;
 
-#define SETUP_SPOOLSS_NOTIFY_DATA_SECDESC(_data, _sd) \
-       _data->data.sd.sd = dup_sec_desc(mem_ctx, _sd); \
-       if (!_data->data.sd.sd) { \
-               _data->data.sd.sd_size = 0; \
-       } \
-       _data->data.sd.sd_size = \
-               ndr_size_security_descriptor(_data->data.sd.sd, 0);
-
 static void init_systemtime_buffer(TALLOC_CTX *mem_ctx,
                                   struct tm *t,
                                   const char **pp,
@@ -1513,6 +1507,7 @@ void srv_spoolss_cleanup(void)
 /**********************************************************************
  callback to receive a MSG_PRINTER_DRVUPGRADE message and interate
  over all printers, upgrading ones as necessary
+ This is now *ONLY* called inside the background lpq updater. JRA.
  **********************************************************************/
 
 void do_drv_upgrade_printer(struct messaging_context *msg,
@@ -1545,7 +1540,7 @@ void do_drv_upgrade_printer(struct messaging_context *msg,
        /* Iterate the printer list */
 
        for (snum = 0; snum < n_services; snum++) {
-               if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
+               if (!lp_snum_ok(snum) || !lp_printable(snum)) {
                        continue;
                }
 
@@ -1725,6 +1720,16 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p,
                return WERR_INVALID_PARAM;
        }
 
+       /*
+        * The printcap printer share inventory is updated on client
+        * enumeration. For clients that do not perform enumeration prior to
+        * access, such as cupssmbadd, we reinitialise the printer share
+        * inventory on open as well.
+        */
+       become_root();
+       delete_and_reload_printers(server_event_context(), p->msg_ctx);
+       unbecome_root();
+
        /* some sanity check because you can open a printer or a print server */
        /* aka: \\server\printer or \\server */
 
@@ -1732,7 +1737,7 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p,
 
        result = open_printer_hnd(p, r->out.handle, r->in.printername, 0);
        if (!W_ERROR_IS_OK(result)) {
-               DEBUG(0,("_spoolss_OpenPrinterEx: Cannot open a printer handle "
+               DEBUG(3,("_spoolss_OpenPrinterEx: Cannot open a printer handle "
                        "for printer %s\n", r->in.printername));
                ZERO_STRUCTP(r->out.handle);
                return result;
@@ -1802,7 +1807,7 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p,
 
                if ( r->in.access_mask & SERVER_ACCESS_ADMINISTER )
                {
-                       if (!lp_ms_add_printer_wizard()) {
+                       if (!lp_show_add_printer_wizard()) {
                                close_printer_handle(p, r->out.handle);
                                ZERO_STRUCTP(r->out.handle);
                                return WERR_ACCESS_DENIED;
@@ -1886,7 +1891,7 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p,
                        rhost = raddr;
                }
 
-               if (!allow_access(lp_hostsdeny(snum), lp_hostsallow(snum),
+               if (!allow_access(lp_hosts_deny(snum), lp_hosts_allow(snum),
                                  rhost, raddr)) {
                        DEBUG(3, ("access DENIED (hosts allow/deny) for printer open\n"));
                        ZERO_STRUCTP(r->out.handle);
@@ -1895,10 +1900,10 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p,
 
                if (!user_ok_token(uidtoname(p->session_info->unix_token->uid), NULL,
                                   p->session_info->security_token, snum) ||
-                   !print_access_check(p->session_info,
-                                       p->msg_ctx,
-                                       snum,
-                                       r->in.access_mask)) {
+                   !W_ERROR_IS_OK(print_access_check(p->session_info,
+                                                     p->msg_ctx,
+                                                     snum,
+                                                     r->in.access_mask))) {
                        DEBUG(3, ("access DENIED for printer open\n"));
                        close_printer_handle(p, r->out.handle);
                        ZERO_STRUCTP(r->out.handle);
@@ -2439,11 +2444,10 @@ WERROR _spoolss_GetPrinterData(struct pipes_struct *p,
  Connect to the client machine.
 **********************************************************/
 
-static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
-                       struct sockaddr_storage *client_ss, const char *remote_machine)
+static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe, struct cli_state **pp_cli,
+                                     struct sockaddr_storage *client_ss, const char *remote_machine)
 {
        NTSTATUS ret;
-       struct cli_state *the_cli;
        struct sockaddr_storage rm_addr;
        char addr[INET6_ADDRSTRLEN];
 
@@ -2469,7 +2473,7 @@ static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
        }
 
        /* setup the connection */
-       ret = cli_full_connection( &the_cli, lp_netbios_name(), remote_machine,
+       ret = cli_full_connection( pp_cli, lp_netbios_name(), remote_machine,
                &rm_addr, 0, "IPC$", "IPC",
                "", /* username */
                "", /* domain */
@@ -2482,9 +2486,9 @@ static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
                return false;
        }
 
-       if ( smbXcli_conn_protocol(the_cli->conn) != PROTOCOL_NT1 ) {
+       if ( smbXcli_conn_protocol((*pp_cli)->conn) != PROTOCOL_NT1 ) {
                DEBUG(0,("spoolss_connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
-               cli_shutdown(the_cli);
+               cli_shutdown(*pp_cli);
                return false;
        }
 
@@ -2493,11 +2497,11 @@ static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
         * Now start the NT Domain stuff :-).
         */
 
-       ret = cli_rpc_pipe_open_noauth(the_cli, &ndr_table_spoolss.syntax_id, pp_pipe);
+       ret = cli_rpc_pipe_open_noauth(*pp_cli, &ndr_table_spoolss, pp_pipe);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(2,("spoolss_connect_to_client: unable to open the spoolss pipe on machine %s. Error was : %s.\n",
                        remote_machine, nt_errstr(ret)));
-               cli_shutdown(the_cli);
+               cli_shutdown(*pp_cli);
                return false;
        }
 
@@ -2543,7 +2547,7 @@ static bool srv_spoolss_replyopenprinter(int snum, const char *printer,
                }
                chan->client_address = *client_ss;
 
-               if (!spoolss_connect_to_client(&chan->cli_pipe, client_ss, unix_printer)) {
+               if (!spoolss_connect_to_client(&chan->cli_pipe, &chan->cli, client_ss, unix_printer)) {
                        TALLOC_FREE(chan);
                        return false;
                }
@@ -2941,7 +2945,14 @@ static void spoolss_notify_security_desc(struct messaging_context *msg_ctx,
                                         struct spoolss_PrinterInfo2 *pinfo2,
                                         TALLOC_CTX *mem_ctx)
 {
-       SETUP_SPOOLSS_NOTIFY_DATA_SECDESC(data, pinfo2->secdesc);
+       if (pinfo2->secdesc == NULL) {
+               data->data.sd.sd = NULL;
+       } else {
+               data->data.sd.sd = security_descriptor_copy(mem_ctx,
+                                                           pinfo2->secdesc);
+       }
+       data->data.sd.sd_size = ndr_size_security_descriptor(data->data.sd.sd,
+                                                            0);
 }
 
 /*******************************************************************
@@ -3542,7 +3553,7 @@ static WERROR printserver_notify_info(struct pipes_struct *p,
                for (snum = 0; snum < n_services; snum++) {
                        if (!lp_browseable(snum) ||
                            !lp_snum_ok(snum) ||
-                           !lp_print_ok(snum)) {
+                           !lp_printable(snum)) {
                                continue; /* skip */
                        }
 
@@ -3611,6 +3622,7 @@ static WERROR printer_notify_info(struct pipes_struct *p,
        print_status_struct status;
        struct spoolss_PrinterInfo2 *pinfo2 = NULL;
        WERROR result;
+       struct tdb_print_db *pdb;
 
        DEBUG(4,("printer_notify_info\n"));
 
@@ -3634,13 +3646,19 @@ static WERROR printer_notify_info(struct pipes_struct *p,
                return WERR_BADFID;
        }
 
+       pdb = get_print_db_byname(Printer->sharename);
+       if (pdb == NULL) {
+               return WERR_BADFID;
+       }
+
        /* Maybe we should use the SYSTEM session_info here... */
        result = winreg_get_printer_internal(mem_ctx,
                                    get_session_info_system(),
                                    p->msg_ctx,
                                    lp_servicename(talloc_tos(), snum), &pinfo2);
        if (!W_ERROR_IS_OK(result)) {
-               return WERR_BADFID;
+               result = WERR_BADFID;
+               goto err_pdb_drop;
        }
 
        /*
@@ -3649,10 +3667,11 @@ static WERROR printer_notify_info(struct pipes_struct *p,
         */
        pinfo2->servername = talloc_strdup(pinfo2, Printer->servername);
        if (pinfo2->servername == NULL) {
-               return WERR_NOMEM;
+               result = WERR_NOMEM;
+               goto err_pdb_drop;
        }
 
-       for (i=0; i<option->count; i++) {
+       for (i = 0; i < option->count; i++) {
                option_type = option->types[i];
 
                switch (option_type.type) {
@@ -3671,12 +3690,21 @@ static WERROR printer_notify_info(struct pipes_struct *p,
                        count = print_queue_status(p->msg_ctx, snum, &queue,
                                                   &status);
 
-                       for (j=0; j<count; j++) {
+                       for (j = 0; j < count; j++) {
+                               uint32_t jobid;
+                               jobid = sysjob_to_jobid_pdb(pdb,
+                                                           queue[j].sysjob);
+                               if (jobid == (uint32_t)-1) {
+                                       DEBUG(2, ("ignoring untracked job %d\n",
+                                                 queue[j].sysjob));
+                                       continue;
+                               }
+                               /* FIXME check return value */
                                construct_notify_jobs_info(p->msg_ctx,
                                                           &queue[j], info,
                                                           pinfo2, snum,
                                                           &option_type,
-                                                          queue[j].sysjob,
+                                                          jobid,
                                                           mem_ctx);
                        }
 
@@ -3701,7 +3729,10 @@ static WERROR printer_notify_info(struct pipes_struct *p,
        */
 
        talloc_free(pinfo2);
-       return WERR_OK;
+       result = WERR_OK;
+err_pdb_drop:
+       release_print_db(pdb);
+       return result;
 }
 
 /****************************************************************
@@ -4055,7 +4086,10 @@ static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx,
                /* don't use talloc_steal() here unless you do a deep steal of all
                   the SEC_DESC members */
 
-               r->secdesc      = dup_sec_desc(mem_ctx, info2->secdesc);
+               r->secdesc = security_descriptor_copy(mem_ctx, info2->secdesc);
+               if (r->secdesc == NULL) {
+                       return WERR_NOMEM;
+               }
        }
 
        return WERR_OK;
@@ -4078,8 +4112,10 @@ static WERROR construct_printer_info3(TALLOC_CTX *mem_ctx,
                /* don't use talloc_steal() here unless you do a deep steal of all
                   the SEC_DESC members */
 
-               r->secdesc = dup_sec_desc(mem_ctx, info2->secdesc);
-               W_ERROR_HAVE_NO_MEMORY(r->secdesc);
+               r->secdesc = security_descriptor_copy(mem_ctx, info2->secdesc);
+               if (r->secdesc == NULL) {
+                       return WERR_NOMEM;
+               }
        }
 
        return WERR_OK;
@@ -4177,21 +4213,47 @@ static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx,
                                      struct spoolss_PrinterInfo7 *r,
                                      int snum)
 {
-       const struct auth_session_info *session_info = get_session_info_system();
-       struct GUID guid;
+       const struct auth_session_info *session_info;
+       char *printer;
+       WERROR werr;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       if (tmp_ctx == NULL) {
+               return WERR_NOMEM;
+       }
 
-       if (is_printer_published(mem_ctx, session_info, msg_ctx,
-                                servername,
-                                lp_servicename(talloc_tos(), snum), &guid, NULL)) {
+       session_info = get_session_info_system();
+       SMB_ASSERT(session_info != NULL);
+
+       printer = lp_servicename(tmp_ctx, snum);
+       if (printer == NULL) {
+               DEBUG(0, ("invalid printer snum %d\n", snum));
+               werr = WERR_INVALID_PARAM;
+               goto out_tmp_free;
+       }
+
+       if (is_printer_published(tmp_ctx, session_info, msg_ctx,
+                                servername, printer, NULL)) {
+               struct GUID guid;
+               werr = nt_printer_guid_get(tmp_ctx, session_info, msg_ctx,
+                                          printer, &guid);
+               if (!W_ERROR_IS_OK(werr)) {
+                       goto out_tmp_free;
+               }
                r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid));
                r->action = DSPRINT_PUBLISH;
        } else {
                r->guid = talloc_strdup(mem_ctx, "");
                r->action = DSPRINT_UNPUBLISH;
        }
-       W_ERROR_HAVE_NO_MEMORY(r->guid);
+       if (r->guid == NULL) {
+               werr = WERR_NOMEM;
+               goto out_tmp_free;
+       }
 
-       return WERR_OK;
+       werr = WERR_OK;
+out_tmp_free:
+       talloc_free(tmp_ctx);
+       return werr;
 }
 
 /********************************************************************
@@ -4237,15 +4299,6 @@ static WERROR construct_printer_info8(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
-
-/********************************************************************
-********************************************************************/
-
-static bool snum_is_shared_printer(int snum)
-{
-       return (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum));
-}
-
 /********************************************************************
  Spoolss_enumprinters.
 ********************************************************************/
@@ -4260,7 +4313,7 @@ static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx,
                                           uint32_t *count_p)
 {
        int snum;
-       int n_services = lp_numservices();
+       int n_services;
        union spoolss_PrinterInfo *info = NULL;
        uint32_t count = 0;
        WERROR result = WERR_OK;
@@ -4272,6 +4325,15 @@ static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx,
                return WERR_NOMEM;
        }
 
+       /*
+        * printer shares are updated on client enumeration. The background
+        * printer process updates printer_list.tdb at regular intervals.
+        */
+       become_root();
+       delete_and_reload_printers(server_event_context(), msg_ctx);
+       unbecome_root();
+
+       n_services = lp_numservices();
        *count_p = 0;
        *info_p = NULL;
 
@@ -4840,7 +4902,8 @@ static WERROR string_array_from_driver_info(TALLOC_CTX *mem_ctx,
                                                  const char *arch,
                                                  int version)
 {
-       int i, num_strings = 0;
+       int i;
+       size_t num_strings = 0;
        const char **array = NULL;
 
        if (string_array == NULL) {
@@ -5623,14 +5686,16 @@ WERROR _spoolss_GetPrinterDriver2(struct pipes_struct *p,
        /* that's an [in out] buffer */
 
        if (!r->in.buffer && (r->in.offered != 0)) {
-               return WERR_INVALID_PARAM;
+               result = WERR_INVALID_PARAM;
+               goto err_info_free;
        }
 
        DEBUG(4,("_spoolss_GetPrinterDriver2\n"));
 
        if (!(printer = find_printer_index_by_hnd(p, r->in.handle))) {
                DEBUG(0,("_spoolss_GetPrinterDriver2: invalid printer handle!\n"));
-               return WERR_INVALID_PRINTER_NAME;
+               result = WERR_INVALID_PRINTER_NAME;
+               goto err_info_free;
        }
 
        *r->out.needed = 0;
@@ -5638,7 +5703,8 @@ WERROR _spoolss_GetPrinterDriver2(struct pipes_struct *p,
        *r->out.server_minor_version = 0;
 
        if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
-               return WERR_BADFID;
+               result = WERR_BADFID;
+               goto err_info_free;
        }
 
        if (r->in.client_major_version == SPOOLSS_DRIVER_VERSION_2012) {
@@ -5655,8 +5721,7 @@ WERROR _spoolss_GetPrinterDriver2(struct pipes_struct *p,
                                                     r->in.architecture,
                                                     version);
        if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(r->out.info);
-               return result;
+               goto err_info_free;
        }
 
        *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_DriverInfo,
@@ -5664,6 +5729,10 @@ WERROR _spoolss_GetPrinterDriver2(struct pipes_struct *p,
        r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
 
        return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+
+err_info_free:
+       TALLOC_FREE(r->out.info);
+       return result;
 }
 
 
@@ -5755,7 +5824,13 @@ WERROR _spoolss_StartDocPrinter(struct pipes_struct *p,
         */
 
        if (info_1->datatype) {
-               if (strcmp(info_1->datatype, "RAW") != 0) {
+               /*
+                * The v4 driver model used in Windows 8 declares print jobs
+                * intended to bypass the XPS processing layer by setting
+                * datatype to "XPS_PASS" instead of "RAW".
+                */
+                if ((strcmp(info_1->datatype, "RAW") != 0)
+                 && (strcmp(info_1->datatype, "XPS_PASS") != 0)) {
                        *r->out.job_id = 0;
                        return WERR_INVALID_DATATYPE;
                }
@@ -6126,7 +6201,7 @@ static bool check_printer_ok(TALLOC_CTX *mem_ctx,
 
 static WERROR add_port_hook(TALLOC_CTX *ctx, struct security_token *token, const char *portname, const char *uri)
 {
-       char *cmd = lp_addport_cmd(talloc_tos());
+       char *cmd = lp_addport_command(talloc_tos());
        char *command = NULL;
        int ret;
        bool is_print_op = false;
@@ -6187,7 +6262,7 @@ static bool add_printer_hook(TALLOC_CTX *ctx, struct security_token *token,
                             const char *remote_machine,
                             struct messaging_context *msg_ctx)
 {
-       char *cmd = lp_addprinter_cmd(talloc_tos());
+       char *cmd = lp_addprinter_command(talloc_tos());
        char **qlines;
        char *command = NULL;
        int numlines;
@@ -6742,7 +6817,7 @@ static WERROR update_printer(struct pipes_struct *p,
        /* Call addprinter hook */
        /* Check changes to see if this is really needed */
 
-       if (*lp_addprinter_cmd(talloc_tos()) &&
+       if (*lp_addprinter_command(talloc_tos()) &&
                        (!strequal(printer->drivername, old_printer->drivername) ||
                         !strequal(printer->comment, old_printer->comment) ||
                         !strequal(printer->portname, old_printer->portname) ||
@@ -6989,6 +7064,7 @@ fill_job_info1
 static WERROR fill_job_info1(TALLOC_CTX *mem_ctx,
                             struct spoolss_JobInfo1 *r,
                             const print_queue_struct *queue,
+                            uint32_t jobid,
                             int position, int snum,
                             struct spoolss_PrinterInfo2 *pinfo2)
 {
@@ -6996,7 +7072,7 @@ static WERROR fill_job_info1(TALLOC_CTX *mem_ctx,
 
        t = gmtime(&queue->time);
 
-       r->job_id               = queue->sysjob;
+       r->job_id               = jobid;
 
        r->printer_name         = lp_servicename(mem_ctx, snum);
        W_ERROR_HAVE_NO_MEMORY(r->printer_name);
@@ -7029,6 +7105,7 @@ fill_job_info2
 static WERROR fill_job_info2(TALLOC_CTX *mem_ctx,
                             struct spoolss_JobInfo2 *r,
                             const print_queue_struct *queue,
+                            uint32_t jobid,
                             int position, int snum,
                             struct spoolss_PrinterInfo2 *pinfo2,
                             struct spoolss_DeviceMode *devmode)
@@ -7037,7 +7114,7 @@ static WERROR fill_job_info2(TALLOC_CTX *mem_ctx,
 
        t = gmtime(&queue->time);
 
-       r->job_id               = queue->sysjob;
+       r->job_id               = jobid;
 
        r->printer_name         = lp_servicename(mem_ctx, snum);
        W_ERROR_HAVE_NO_MEMORY(r->printer_name);
@@ -7079,27 +7156,6 @@ static WERROR fill_job_info2(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
-/****************************************************************************
-fill_job_info3
-****************************************************************************/
-
-static WERROR fill_job_info3(TALLOC_CTX *mem_ctx,
-                            struct spoolss_JobInfo3 *r,
-                            const print_queue_struct *queue,
-                            const print_queue_struct *next_queue,
-                            int position, int snum,
-                            struct spoolss_PrinterInfo2 *pinfo2)
-{
-       r->job_id               = queue->sysjob;
-       r->next_job_id          = 0;
-       if (next_queue) {
-               r->next_job_id  = next_queue->sysjob;
-       }
-       r->reserved             = 0;
-
-       return WERR_OK;
-}
-
 /****************************************************************************
  Enumjobs at level 1.
 ****************************************************************************/
@@ -7114,34 +7170,56 @@ static WERROR enumjobs_level1(TALLOC_CTX *mem_ctx,
        union spoolss_JobInfo *info;
        int i;
        WERROR result = WERR_OK;
+       uint32_t num_filled;
+       struct tdb_print_db *pdb;
 
        info = talloc_array(mem_ctx, union spoolss_JobInfo, num_queues);
-       W_ERROR_HAVE_NO_MEMORY(info);
+       if (info == NULL) {
+               result = WERR_NOMEM;
+               goto err_out;
+       }
+
+       pdb = get_print_db_byname(pinfo2->sharename);
+       if (pdb == NULL) {
+               result = WERR_INVALID_PARAM;
+               goto err_info_free;
+       }
 
-       *count = num_queues;
+       num_filled = 0;
+       for (i = 0; i < num_queues; i++) {
+               uint32_t jobid = sysjob_to_jobid_pdb(pdb, queue[i].sysjob);
+               if (jobid == (uint32_t)-1) {
+                       DEBUG(4, ("skipping sysjob %d\n", queue[i].sysjob));
+                       continue;
+               }
 
-       for (i=0; i<*count; i++) {
                result = fill_job_info1(info,
-                                       &info[i].info1,
+                                       &info[num_filled].info1,
                                        &queue[i],
+                                       jobid,
                                        i,
                                        snum,
                                        pinfo2);
                if (!W_ERROR_IS_OK(result)) {
-                       goto out;
+                       goto err_pdb_drop;
                }
-       }
 
- out:
-       if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(info);
-               *count = 0;
-               return result;
+               num_filled++;
        }
 
+       release_print_db(pdb);
        *info_p = info;
+       *count = num_filled;
 
        return WERR_OK;
+
+err_pdb_drop:
+       release_print_db(pdb);
+err_info_free:
+       TALLOC_FREE(info);
+err_out:
+       *count = 0;
+       return result;
 }
 
 /****************************************************************************
@@ -7158,45 +7236,65 @@ static WERROR enumjobs_level2(TALLOC_CTX *mem_ctx,
        union spoolss_JobInfo *info;
        int i;
        WERROR result = WERR_OK;
+       uint32_t num_filled;
+       struct tdb_print_db *pdb;
 
        info = talloc_array(mem_ctx, union spoolss_JobInfo, num_queues);
-       W_ERROR_HAVE_NO_MEMORY(info);
+       if (info == NULL) {
+               result = WERR_NOMEM;
+               goto err_out;
+       }
 
-       *count = num_queues;
+       pdb = get_print_db_byname(pinfo2->sharename);
+       if (pdb == NULL) {
+               result = WERR_INVALID_PARAM;
+               goto err_info_free;
+       }
 
-       for (i=0; i<*count; i++) {
+       num_filled = 0;
+       for (i = 0; i< num_queues; i++) {
                struct spoolss_DeviceMode *devmode;
+               uint32_t jobid = sysjob_to_jobid_pdb(pdb, queue[i].sysjob);
+               if (jobid == (uint32_t)-1) {
+                       DEBUG(4, ("skipping sysjob %d\n", queue[i].sysjob));
+                       continue;
+               }
 
                result = spoolss_create_default_devmode(info,
                                                        pinfo2->printername,
                                                        &devmode);
                if (!W_ERROR_IS_OK(result)) {
                        DEBUG(3, ("Can't proceed w/o a devmode!"));
-                       goto out;
+                       goto err_pdb_drop;
                }
 
                result = fill_job_info2(info,
-                                       &info[i].info2,
+                                       &info[num_filled].info2,
                                        &queue[i],
+                                       jobid,
                                        i,
                                        snum,
                                        pinfo2,
                                        devmode);
                if (!W_ERROR_IS_OK(result)) {
-                       goto out;
+                       goto err_pdb_drop;
                }
+               num_filled++;
        }
 
- out:
-       if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(info);
-               *count = 0;
-               return result;
-       }
-
+       release_print_db(pdb);
        *info_p = info;
+       *count = num_filled;
 
        return WERR_OK;
+
+err_pdb_drop:
+       release_print_db(pdb);
+err_info_free:
+       TALLOC_FREE(info);
+err_out:
+       *count = 0;
+       return result;
 }
 
 /****************************************************************************
@@ -7213,41 +7311,51 @@ static WERROR enumjobs_level3(TALLOC_CTX *mem_ctx,
        union spoolss_JobInfo *info;
        int i;
        WERROR result = WERR_OK;
+       uint32_t num_filled;
+       struct tdb_print_db *pdb;
 
        info = talloc_array(mem_ctx, union spoolss_JobInfo, num_queues);
-       W_ERROR_HAVE_NO_MEMORY(info);
-
-       *count = num_queues;
+       if (info == NULL) {
+               result = WERR_NOMEM;
+               goto err_out;
+       }
 
-       for (i=0; i<*count; i++) {
-               const print_queue_struct *next_queue = NULL;
+       pdb = get_print_db_byname(pinfo2->sharename);
+       if (pdb == NULL) {
+               result = WERR_INVALID_PARAM;
+               goto err_info_free;
+       }
 
-               if (i+1 < *count) {
-                       next_queue = &queue[i+1];
+       num_filled = 0;
+       for (i = 0; i < num_queues; i++) {
+               uint32_t jobid = sysjob_to_jobid_pdb(pdb, queue[i].sysjob);
+               if (jobid == (uint32_t)-1) {
+                       DEBUG(4, ("skipping sysjob %d\n", queue[i].sysjob));
+                       continue;
                }
 
-               result = fill_job_info3(info,
-                                       &info[i].info3,
-                                       &queue[i],
-                                       next_queue,
-                                       i,
-                                       snum,
-                                       pinfo2);
-               if (!W_ERROR_IS_OK(result)) {
-                       goto out;
-               }
-       }
+               info[num_filled].info3.job_id = jobid;
+               /* next_job_id is overwritten on next iteration */
+               info[num_filled].info3.next_job_id = 0;
+               info[num_filled].info3.reserved = 0;
 
- out:
-       if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(info);
-               *count = 0;
-               return result;
+               if (num_filled > 0) {
+                       info[num_filled - 1].info3.next_job_id = jobid;
+               }
+               num_filled++;
        }
 
+       release_print_db(pdb);
        *info_p = info;
+       *count = num_filled;
 
        return WERR_OK;
+
+err_info_free:
+       TALLOC_FREE(info);
+err_out:
+       *count = 0;
+       return result;
 }
 
 /****************************************************************
@@ -7270,6 +7378,11 @@ WERROR _spoolss_EnumJobs(struct pipes_struct *p,
                return WERR_INVALID_PARAM;
        }
 
+       if ((r->in.level != 1) && (r->in.level != 2) && (r->in.level != 3)) {
+               DEBUG(4, ("EnumJobs level %d not supported\n", r->in.level));
+               return WERR_UNKNOWN_LEVEL;
+       }
+
        DEBUG(4,("_spoolss_EnumJobs\n"));
 
        *r->out.needed = 0;
@@ -7315,7 +7428,7 @@ WERROR _spoolss_EnumJobs(struct pipes_struct *p,
                                         pinfo2, r->out.info, r->out.count);
                break;
        default:
-               result = WERR_UNKNOWN_LEVEL;
+               SMB_ASSERT(false);      /* level checked on entry */
                break;
        }
 
@@ -7740,6 +7853,7 @@ WERROR _spoolss_GetForm(struct pipes_struct *p,
        /* that's an [in out] buffer */
 
        if (!r->in.buffer && (r->in.offered != 0)) {
+               TALLOC_FREE(r->out.info);
                return WERR_INVALID_PARAM;
        }
 
@@ -7816,7 +7930,7 @@ static WERROR fill_port_2(TALLOC_CTX *mem_ctx,
 
 static WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines)
 {
-       char *cmd = lp_enumports_cmd(talloc_tos());
+       char *cmd = lp_enumports_command(talloc_tos());
        char **qlines = NULL;
        char *command = NULL;
        int numlines;
@@ -8080,7 +8194,7 @@ static WERROR spoolss_addprinterex_level_2(struct pipes_struct *p,
        /* FIXME!!!  smbd should check to see if the driver is installed before
           trying to add a printer like this  --jerry */
 
-       if (*lp_addprinter_cmd(talloc_tos()) ) {
+       if (*lp_addprinter_command(talloc_tos()) ) {
                char *raddr;
 
                raddr = tsocket_address_inet_addr_string(p->remote_address,
@@ -8106,10 +8220,10 @@ static WERROR spoolss_addprinterex_level_2(struct pipes_struct *p,
        }
 
        /* you must be a printer admin to add a new printer */
-       if (!print_access_check(p->session_info,
-                               p->msg_ctx,
-                               snum,
-                               PRINTER_ACCESS_ADMINISTER)) {
+       if (!W_ERROR_IS_OK(print_access_check(p->session_info,
+                                             p->msg_ctx,
+                                             snum,
+                                             PRINTER_ACCESS_ADMINISTER))) {
                return WERR_ACCESS_DENIED;
        }
 
@@ -9274,13 +9388,14 @@ static WERROR getjob_level_1(TALLOC_CTX *mem_ctx,
                             int count, int snum,
                             struct spoolss_PrinterInfo2 *pinfo2,
                             uint32_t jobid,
+                            int sysjob,
                             struct spoolss_JobInfo1 *r)
 {
        int i = 0;
        bool found = false;
 
        for (i=0; i<count; i++) {
-               if (queue[i].sysjob == (int)jobid) {
+               if (queue[i].sysjob == sysjob) {
                        found = true;
                        break;
                }
@@ -9294,6 +9409,7 @@ static WERROR getjob_level_1(TALLOC_CTX *mem_ctx,
        return fill_job_info1(mem_ctx,
                              r,
                              &queue[i],
+                             jobid,
                              i,
                              snum,
                              pinfo2);
@@ -9307,6 +9423,7 @@ static WERROR getjob_level_2(TALLOC_CTX *mem_ctx,
                             int count, int snum,
                             struct spoolss_PrinterInfo2 *pinfo2,
                             uint32_t jobid,
+                            int sysjob,
                             struct spoolss_JobInfo2 *r)
 {
        int i = 0;
@@ -9315,7 +9432,7 @@ static WERROR getjob_level_2(TALLOC_CTX *mem_ctx,
        WERROR result;
 
        for (i=0; i<count; i++) {
-               if (queue[i].sysjob == (int)jobid) {
+               if (queue[i].sysjob == sysjob) {
                        found = true;
                        break;
                }
@@ -9347,6 +9464,7 @@ static WERROR getjob_level_2(TALLOC_CTX *mem_ctx,
        return fill_job_info2(mem_ctx,
                              r,
                              &queue[i],
+                             jobid,
                              i,
                              snum,
                              pinfo2,
@@ -9362,15 +9480,19 @@ WERROR _spoolss_GetJob(struct pipes_struct *p,
 {
        WERROR result = WERR_OK;
        struct spoolss_PrinterInfo2 *pinfo2 = NULL;
+       const char *svc_name;
+       int sysjob;
        int snum;
        int count;
+       struct tdb_print_db *pdb;
        print_queue_struct      *queue = NULL;
        print_status_struct prt_status;
 
        /* that's an [in out] buffer */
 
        if (!r->in.buffer && (r->in.offered != 0)) {
-               return WERR_INVALID_PARAM;
+               result = WERR_INVALID_PARAM;
+               goto err_jinfo_free;
        }
 
        DEBUG(5,("_spoolss_GetJob\n"));
@@ -9378,16 +9500,38 @@ WERROR _spoolss_GetJob(struct pipes_struct *p,
        *r->out.needed = 0;
 
        if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
-               return WERR_BADFID;
+               result = WERR_BADFID;
+               goto err_jinfo_free;
+       }
+
+       svc_name = lp_const_servicename(snum);
+       if (svc_name == NULL) {
+               result = WERR_INVALID_PARAM;
+               goto err_jinfo_free;
        }
 
        result = winreg_get_printer_internal(p->mem_ctx,
                                    get_session_info_system(),
                                    p->msg_ctx,
-                                   lp_const_servicename(snum),
+                                   svc_name,
                                    &pinfo2);
        if (!W_ERROR_IS_OK(result)) {
-               return result;
+               goto err_jinfo_free;
+       }
+
+       pdb = get_print_db_byname(svc_name);
+       if (pdb == NULL) {
+               DEBUG(3, ("failed to get print db for svc %s\n", svc_name));
+               result = WERR_INVALID_PARAM;
+               goto err_pinfo_free;
+       }
+
+       sysjob = jobid_to_sysjob_pdb(pdb, r->in.job_id);
+       release_print_db(pdb);
+       if (sysjob == -1) {
+               DEBUG(3, ("no sysjob for spoolss jobid %u\n", r->in.job_id));
+               result = WERR_INVALID_PARAM;
+               goto err_pinfo_free;
        }
 
        count = print_queue_status(p->msg_ctx, snum, &queue, &prt_status);
@@ -9399,12 +9543,14 @@ WERROR _spoolss_GetJob(struct pipes_struct *p,
        case 1:
                result = getjob_level_1(p->mem_ctx,
                                        queue, count, snum, pinfo2,
-                                       r->in.job_id, &r->out.info->info1);
+                                       r->in.job_id, sysjob,
+                                       &r->out.info->info1);
                break;
        case 2:
                result = getjob_level_2(p->mem_ctx,
                                        queue, count, snum, pinfo2,
-                                       r->in.job_id, &r->out.info->info2);
+                                       r->in.job_id, sysjob,
+                                       &r->out.info->info2);
                break;
        default:
                result = WERR_UNKNOWN_LEVEL;
@@ -9415,8 +9561,7 @@ WERROR _spoolss_GetJob(struct pipes_struct *p,
        TALLOC_FREE(pinfo2);
 
        if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(r->out.info);
-               return result;
+               goto err_jinfo_free;
        }
 
        *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_JobInfo, r->out.info,
@@ -9424,6 +9569,12 @@ WERROR _spoolss_GetJob(struct pipes_struct *p,
        r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
 
        return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+
+err_pinfo_free:
+       TALLOC_FREE(pinfo2);
+err_jinfo_free:
+       TALLOC_FREE(r->out.info);
+       return result;
 }
 
 /****************************************************************