s3-auth Use *unix_token rather than utok in struct auth3_session_info
[kai/samba-autobuild/.git] / source3 / printing / printing.c
index 9e0e4a570b6aca2ea73b7eb14f6dc1e4e0868160..50ef75b8ef51a8ab9121e596b61c43f6b59293b3 100644 (file)
 */
 
 #include "includes.h"
+#include "system/syslog.h"
+#include "system/filesys.h"
 #include "printing.h"
-#include "librpc/gen_ndr/messaging.h"
 #include "../librpc/gen_ndr/ndr_spoolss.h"
 #include "nt_printing.h"
 #include "../librpc/gen_ndr/netlogon.h"
+#include "printing/notify.h"
+#include "printing/pcap.h"
+#include "serverid.h"
+#include "smbd/smbd.h"
+#include "auth.h"
+#include "messages.h"
+#include "util_tdb.h"
+#include "lib/param/loadparm.h"
 
 extern struct current_user current_user;
 extern userdom_struct current_user_info;
@@ -80,7 +89,7 @@ uint16 pjobid_to_rap(const char* sharename, uint32 jobid)
        key.dptr = (uint8 *)&jinfo;
        key.dsize = sizeof(jinfo);
 
-       data = tdb_fetch(rap_tdb, key);
+       data = tdb_fetch_compat(rap_tdb, key);
        if (data.dptr && data.dsize == sizeof(uint16)) {
                rap_jobid = SVAL(data.dptr, 0);
                SAFE_FREE(data.dptr);
@@ -117,7 +126,7 @@ bool rap_to_pjobid(uint16 rap_jobid, fstring sharename, uint32 *pjobid)
        SSVAL(buf,0,rap_jobid);
        key.dptr = buf;
        key.dsize = sizeof(rap_jobid);
-       data = tdb_fetch(rap_tdb, key);
+       data = tdb_fetch_compat(rap_tdb, key);
        if ( data.dptr && data.dsize == sizeof(struct rap_jobid_key) )
        {
                struct rap_jobid_key *jinfo = (struct rap_jobid_key*)data.dptr;
@@ -155,7 +164,7 @@ void rap_jobid_delete(const char* sharename, uint32 jobid)
        key.dptr = (uint8 *)&jinfo;
        key.dsize = sizeof(jinfo);
 
-       data = tdb_fetch(rap_tdb, key);
+       data = tdb_fetch_compat(rap_tdb, key);
        if (!data.dptr || (data.dsize != sizeof(uint16))) {
                DEBUG(10,("rap_jobid_delete: cannot find jobid %u\n",
                        (unsigned int)jobid ));
@@ -200,7 +209,7 @@ bool print_backend_init(struct messaging_context *msg_ctx)
                pdb = get_print_db_byname(lp_const_servicename(snum));
                if (!pdb)
                        continue;
-               if (tdb_lock_bystring(pdb->tdb, sversion) == -1) {
+               if (tdb_lock_bystring(pdb->tdb, sversion) != 0) {
                        DEBUG(0,("print_backend_init: Failed to open printer %s database\n", lp_const_servicename(snum) ));
                        release_print_db(pdb);
                        return False;
@@ -365,7 +374,7 @@ done:
  unpack a pjob from a tdb buffer
 ***********************************************************************/
 
-int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
+static int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
 {
        int     len = 0;
        int     used;
@@ -433,7 +442,7 @@ static struct printjob *print_job_find(const char *sharename, uint32 jobid)
                return NULL;
        }
 
-       ret = tdb_fetch(pdb->tdb, print_key(jobid, &tmp));
+       ret = tdb_fetch_compat(pdb->tdb, print_key(jobid, &tmp));
        release_print_db(pdb);
 
        if (!ret.dptr) {
@@ -525,8 +534,8 @@ uint32 sysjob_to_jobid(int unix_jobid)
 ****************************************************************************/
 
 static const struct {
-       uint32 lpq_status;
-       uint32 spoolss_status;
+       uint32_t lpq_status;
+       uint32_t spoolss_status;
 } lpq_to_spoolss_status_map[] = {
        { LPQ_QUEUED, JOB_STATUS_QUEUED },
        { LPQ_PAUSED, JOB_STATUS_PAUSED },
@@ -539,7 +548,7 @@ static const struct {
        { LPQ_DELETED, JOB_STATUS_DELETED },
        { LPQ_BLOCKED, JOB_STATUS_BLOCKED_DEVQ },
        { LPQ_USER_INTERVENTION, JOB_STATUS_USER_INTERVENTION },
-       { -1, 0 }
+       { (uint32_t)-1, 0 }
 };
 
 /* Convert a lpq status value stored in printing.tdb into the
@@ -558,19 +567,97 @@ static uint32 map_to_spoolss_status(uint32 lpq_status)
        return 0;
 }
 
+/***************************************************************************
+ Append a jobid to the 'jobs changed' list.
+***************************************************************************/
+
+static bool add_to_jobs_changed(struct tdb_print_db *pdb, uint32_t jobid)
+{
+       TDB_DATA data;
+       uint32_t store_jobid;
+
+       SIVAL(&store_jobid, 0, jobid);
+       data.dptr = (uint8 *) &store_jobid;
+       data.dsize = 4;
+
+       DEBUG(10,("add_to_jobs_added: Added jobid %u\n", (unsigned int)jobid ));
+
+       return (tdb_append(pdb->tdb, string_tdb_data("INFO/jobs_changed"),
+                          data) == 0);
+}
+
+/***************************************************************************
+ Remove a jobid from the 'jobs changed' list.
+***************************************************************************/
+
+static bool remove_from_jobs_changed(const char* sharename, uint32_t jobid)
+{
+       struct tdb_print_db *pdb = get_print_db_byname(sharename);
+       TDB_DATA data, key;
+       size_t job_count, i;
+       bool ret = False;
+       bool gotlock = False;
+
+       if (!pdb) {
+               return False;
+       }
+
+       ZERO_STRUCT(data);
+
+       key = string_tdb_data("INFO/jobs_changed");
+
+       if (tdb_chainlock_with_timeout(pdb->tdb, key, 5) != 0)
+               goto out;
+
+       gotlock = True;
+
+       data = tdb_fetch_compat(pdb->tdb, key);
+
+       if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0))
+               goto out;
+
+       job_count = data.dsize / 4;
+       for (i = 0; i < job_count; i++) {
+               uint32 ch_jobid;
+
+               ch_jobid = IVAL(data.dptr, i*4);
+               if (ch_jobid == jobid) {
+                       if (i < job_count -1 )
+                               memmove(data.dptr + (i*4), data.dptr + (i*4) + 4, (job_count - i - 1)*4 );
+                       data.dsize -= 4;
+                       if (tdb_store(pdb->tdb, key, data, TDB_REPLACE) != 0)
+                               goto out;
+                       break;
+               }
+       }
+
+       ret = True;
+  out:
+
+       if (gotlock)
+               tdb_chainunlock(pdb->tdb, key);
+       SAFE_FREE(data.dptr);
+       release_print_db(pdb);
+       if (ret)
+               DEBUG(10,("remove_from_jobs_changed: removed jobid %u\n", (unsigned int)jobid ));
+       else
+               DEBUG(10,("remove_from_jobs_changed: Failed to remove jobid %u\n", (unsigned int)jobid ));
+       return ret;
+}
+
 static void pjob_store_notify(struct tevent_context *ev,
                              struct messaging_context *msg_ctx,
                              const char* sharename, uint32 jobid,
                              struct printjob *old_data,
-                             struct printjob *new_data)
+                             struct printjob *new_data,
+                             bool *pchanged)
 {
-       bool new_job = False;
+       bool new_job = false;
+       bool changed = false;
 
-       if (!old_data)
-               new_job = True;
-
-       /* Job attributes that can't be changed.  We only send
-          notification for these on a new job. */
+       if (old_data == NULL) {
+               new_job = true;
+       }
 
        /* ACHTUNG!  Due to a bug in Samba's spoolss parsing of the
           NOTIFY_INFO_DATA buffer, we *have* to send the job submission
@@ -584,31 +671,40 @@ static void pjob_store_notify(struct tevent_context *ev,
                                     sharename, jobid, new_data->starttime);
                notify_job_username(ev, msg_ctx,
                                    sharename, jobid, new_data->user);
-       }
-
-       if (new_job || !strequal(old_data->jobname, new_data->jobname))
                notify_job_name(ev, msg_ctx,
                                sharename, jobid, new_data->jobname);
-
-       /* Job attributes of a new job or attributes that can be
-          modified. */
-
-       if (new_job || !strequal(old_data->jobname, new_data->jobname))
-               notify_job_name(ev, msg_ctx,
-                               sharename, jobid, new_data->jobname);
-
-       if (new_job || old_data->status != new_data->status)
                notify_job_status(ev, msg_ctx,
-                                 sharename, jobid,
-                                 map_to_spoolss_status(new_data->status));
-
-       if (new_job || old_data->size != new_data->size)
+                                 sharename, jobid, map_to_spoolss_status(new_data->status));
                notify_job_total_bytes(ev, msg_ctx,
                                       sharename, jobid, new_data->size);
-
-       if (new_job || old_data->page_count != new_data->page_count)
                notify_job_total_pages(ev, msg_ctx,
                                       sharename, jobid, new_data->page_count);
+       } else {
+               if (!strequal(old_data->jobname, new_data->jobname)) {
+                       notify_job_name(ev, msg_ctx, sharename,
+                                       jobid, new_data->jobname);
+                       changed = true;
+               }
+
+               if (old_data->status != new_data->status) {
+                       notify_job_status(ev, msg_ctx,
+                                         sharename, jobid,
+                                         map_to_spoolss_status(new_data->status));
+               }
+
+               if (old_data->size != new_data->size) {
+                       notify_job_total_bytes(ev, msg_ctx,
+                                              sharename, jobid, new_data->size);
+               }
+
+               if (old_data->page_count != new_data->page_count) {
+                       notify_job_total_pages(ev, msg_ctx,
+                                              sharename, jobid,
+                                              new_data->page_count);
+               }
+       }
+
+       *pchanged = changed;
 }
 
 /****************************************************************************
@@ -633,7 +729,7 @@ static bool pjob_store(struct tevent_context *ev,
 
        /* Get old data */
 
-       old_data = tdb_fetch(pdb->tdb, print_key(jobid, &tmp));
+       old_data = tdb_fetch_compat(pdb->tdb, print_key(jobid, &tmp));
 
        /* Doh!  Now we have to pack/unpack data since the NT_DEVICEMODE was added */
 
@@ -678,11 +774,10 @@ static bool pjob_store(struct tevent_context *ev,
        ret = (tdb_store(pdb->tdb, print_key(jobid, &tmp), new_data,
                         TDB_REPLACE) == 0);
 
-       release_print_db(pdb);
-
        /* Send notify updates for what has changed */
 
        if ( ret ) {
+               bool changed = false;
                struct printjob old_pjob;
 
                if ( old_data.dsize )
@@ -692,17 +787,25 @@ static bool pjob_store(struct tevent_context *ev,
                                pjob_store_notify(server_event_context(),
                                                  msg_ctx,
                                                  sharename, jobid, &old_pjob,
-                                                 pjob);
+                                                 pjob,
+                                                 &changed);
                                talloc_free(old_pjob.devmode);
+
+                               if (changed) {
+                                       add_to_jobs_changed(pdb, jobid);
+                               }
                        }
+
                }
                else {
                        /* new job */
                        pjob_store_notify(server_event_context(), msg_ctx,
-                                         sharename, jobid, NULL, pjob);
+                                         sharename, jobid, NULL, pjob,
+                                         &changed);
                }
        }
 
+       release_print_db(pdb);
 done:
        SAFE_FREE( old_data.dptr );
        SAFE_FREE( buf );
@@ -976,7 +1079,7 @@ static pid_t get_updating_pid(const char *sharename)
        slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
        key = string_tdb_data(keystr);
 
-       data = tdb_fetch(pdb->tdb, key);
+       data = tdb_fetch_compat(pdb->tdb, key);
        release_print_db(pdb);
        if (!data.dptr || data.dsize != sizeof(pid_t)) {
                SAFE_FREE(data.dptr);
@@ -1123,7 +1226,7 @@ static TDB_DATA get_jobs_added_data(struct tdb_print_db *pdb)
 
        ZERO_STRUCT(data);
 
-       data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_added"));
+       data = tdb_fetch_compat(pdb->tdb, string_tdb_data("INFO/jobs_added"));
        if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0)) {
                SAFE_FREE(data.dptr);
                ZERO_STRUCT(data);
@@ -1212,7 +1315,7 @@ done:
 }
 
 /****************************************************************************
- main work for updating the lpq cahe for a printer queue
+ main work for updating the lpq cache for a printer queue
 ****************************************************************************/
 
 static void print_queue_update_internal( struct tevent_context *ev,
@@ -1414,7 +1517,7 @@ static void print_queue_update_with_lock( struct tevent_context *ev,
 
        slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", sharename);
        /* Only wait 10 seconds for this. */
-       if (tdb_lock_bystring_with_timeout(pdb->tdb, keystr, 10) == -1) {
+       if (tdb_lock_bystring_with_timeout(pdb->tdb, keystr, 10) != 0) {
                DEBUG(0,("print_queue_update_with_lock: Failed to lock printer %s database\n", sharename));
                release_print_db(pdb);
                return;
@@ -1463,7 +1566,7 @@ static void print_queue_update_with_lock( struct tevent_context *ev,
 /****************************************************************************
 this is the receive function of the background lpq updater
 ****************************************************************************/
-static void print_queue_receive(struct messaging_context *msg,
+void print_queue_receive(struct messaging_context *msg,
                                void *private_data,
                                uint32_t msg_type,
                                struct server_id server_id,
@@ -1783,7 +1886,7 @@ bool print_notify_register_pid(int snum)
                tdb = pdb->tdb;
        }
 
-       if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
+       if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) != 0) {
                DEBUG(0,("print_notify_register_pid: Failed to lock printer %s\n",
                                        printername));
                if (pdb)
@@ -1817,7 +1920,7 @@ bool print_notify_register_pid(int snum)
        }
 
        /* Store back the record. */
-       if (tdb_store_bystring(tdb, NOTIFY_PID_LIST_KEY, data, TDB_REPLACE) == -1) {
+       if (tdb_store_bystring(tdb, NOTIFY_PID_LIST_KEY, data, TDB_REPLACE) != 0) {
                DEBUG(0,("print_notify_register_pid: Failed to update pid \
 list for printer %s\n", printername));
                goto done;
@@ -1873,7 +1976,7 @@ bool print_notify_deregister_pid(int snum)
                tdb = pdb->tdb;
        }
 
-       if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
+       if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) != 0) {
                DEBUG(0,("print_notify_register_pid: Failed to lock \
 printer %s database\n", printername));
                if (pdb)
@@ -1907,7 +2010,7 @@ printer %s database\n", printername));
                SAFE_FREE(data.dptr);
 
        /* Store back the record. */
-       if (tdb_store_bystring(tdb, NOTIFY_PID_LIST_KEY, data, TDB_REPLACE) == -1) {
+       if (tdb_store_bystring(tdb, NOTIFY_PID_LIST_KEY, data, TDB_REPLACE) != 0) {
                DEBUG(0,("print_notify_register_pid: Failed to update pid \
 list for printer %s\n", printername));
                goto done;
@@ -2032,12 +2135,12 @@ static bool remove_from_jobs_added(const char* sharename, uint32 jobid)
 
        key = string_tdb_data("INFO/jobs_added");
 
-       if (tdb_chainlock_with_timeout(pdb->tdb, key, 5) == -1)
+       if (tdb_chainlock_with_timeout(pdb->tdb, key, 5) != 0)
                goto out;
 
        gotlock = True;
 
-       data = tdb_fetch(pdb->tdb, key);
+       data = tdb_fetch_compat(pdb->tdb, key);
 
        if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0))
                goto out;
@@ -2051,7 +2154,7 @@ static bool remove_from_jobs_added(const char* sharename, uint32 jobid)
                        if (i < job_count -1 )
                                memmove(data.dptr + (i*4), data.dptr + (i*4) + 4, (job_count - i - 1)*4 );
                        data.dsize -= 4;
-                       if (tdb_store(pdb->tdb, key, data, TDB_REPLACE) == -1)
+                       if (tdb_store(pdb->tdb, key, data, TDB_REPLACE) != 0)
                                goto out;
                        break;
                }
@@ -2140,7 +2243,7 @@ static bool print_job_delete1(struct tevent_context *ev,
  Return true if the current user owns the print job.
 ****************************************************************************/
 
-static bool is_owner(struct auth_serversupplied_info *server_info,
+static bool is_owner(const struct auth3_session_info *server_info,
                     const char *servicename,
                     uint32 jobid)
 {
@@ -2156,7 +2259,7 @@ static bool is_owner(struct auth_serversupplied_info *server_info,
  Delete a print job.
 ****************************************************************************/
 
-WERROR print_job_delete(struct auth_serversupplied_info *server_info,
+WERROR print_job_delete(const struct auth3_session_info *server_info,
                        struct messaging_context *msg_ctx,
                        int snum, uint32_t jobid)
 {
@@ -2179,7 +2282,7 @@ WERROR print_job_delete(struct auth_serversupplied_info *server_info,
                sys_adminlog( LOG_ERR,
                              "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
-                             uidtoname(server_info->utok.uid),
+                             uidtoname(server_info->unix_token->uid),
                              lp_printername(snum) );
                /* END_ADMIN_LOG */
 
@@ -2224,7 +2327,7 @@ pause, or resume print job. User name: %s. Printer name: %s.",
  Pause a job.
 ****************************************************************************/
 
-bool print_job_pause(struct auth_serversupplied_info *server_info,
+bool print_job_pause(const struct auth3_session_info *server_info,
                     struct messaging_context *msg_ctx,
                     int snum, uint32 jobid, WERROR *errcode)
 {
@@ -2256,7 +2359,7 @@ bool print_job_pause(struct auth_serversupplied_info *server_info,
                sys_adminlog( LOG_ERR,
                        "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
-                             uidtoname(server_info->utok.uid),
+                             uidtoname(server_info->unix_token->uid),
                              lp_printername(snum) );
                /* END_ADMIN_LOG */
 
@@ -2289,7 +2392,7 @@ pause, or resume print job. User name: %s. Printer name: %s.",
  Resume a job.
 ****************************************************************************/
 
-bool print_job_resume(struct auth_serversupplied_info *server_info,
+bool print_job_resume(const struct auth3_session_info *server_info,
                      struct messaging_context *msg_ctx,
                      int snum, uint32 jobid, WERROR *errcode)
 {
@@ -2322,7 +2425,7 @@ bool print_job_resume(struct auth_serversupplied_info *server_info,
                sys_adminlog( LOG_ERR,
                         "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
-                             uidtoname(server_info->utok.uid),
+                             uidtoname(server_info->unix_token->uid),
                              lp_printername(snum) );
                /* END_ADMIN_LOG */
                return False;
@@ -2400,7 +2503,7 @@ static int get_queue_status(const char* sharename, print_status_struct *status)
 
        if (status) {
                fstr_sprintf(keystr, "STATUS/%s", sharename);
-               data = tdb_fetch(pdb->tdb, string_tdb_data(keystr));
+               data = tdb_fetch_compat(pdb->tdb, string_tdb_data(keystr));
                if (data.dptr) {
                        if (data.dsize == sizeof(print_status_struct))
                                /* this memcpy is ok since the status struct was
@@ -2459,7 +2562,7 @@ static WERROR allocate_print_jobid(struct tdb_print_db *pdb, int snum,
                /* Lock the database - only wait 20 seconds. */
                ret = tdb_lock_bystring_with_timeout(pdb->tdb,
                                                     "INFO/nextjob", 20);
-               if (ret == -1) {
+               if (ret != 0) {
                        DEBUG(0, ("allocate_print_jobid: "
                                  "Failed to lock printing database %s\n",
                                  sharename));
@@ -2487,7 +2590,7 @@ static WERROR allocate_print_jobid(struct tdb_print_db *pdb, int snum,
                jobid = NEXT_JOBID(jobid);
 
                ret = tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid);
-               if (ret == -1) {
+               if (ret != 0) {
                        terr = tdb_error(pdb->tdb);
                        DEBUG(3, ("allocate_print_jobid: "
                                  "Failed to store INFO/nextjob.\n"));
@@ -2520,7 +2623,7 @@ static WERROR allocate_print_jobid(struct tdb_print_db *pdb, int snum,
                dum.dptr = NULL;
                dum.dsize = 0;
                if (tdb_store(pdb->tdb, print_key(jobid, &tmp), dum,
-                             TDB_INSERT) == -1) {
+                             TDB_INSERT) != 0) {
                        DEBUG(3, ("allocate_print_jobid: "
                                  "jobid (%d) failed to store placeholder.\n",
                                  jobid ));
@@ -2557,7 +2660,7 @@ static bool add_to_jobs_added(struct tdb_print_db *pdb, uint32 jobid)
  Do all checks needed to determine if we can start a job.
 ***************************************************************************/
 
-static WERROR print_job_checks(struct auth_serversupplied_info *server_info,
+static WERROR print_job_checks(const struct auth3_session_info *server_info,
                               struct messaging_context *msg_ctx,
                               int snum, int *njobs)
 {
@@ -2683,7 +2786,7 @@ static WERROR print_job_spool_file(int snum, uint32_t jobid,
  Start spooling a job - return the jobid.
 ***************************************************************************/
 
-WERROR print_job_start(struct auth_serversupplied_info *server_info,
+WERROR print_job_start(const struct auth3_session_info *server_info,
                       struct messaging_context *msg_ctx,
                       const char *clientmachine,
                       int snum, const char *docname, const char *filename,
@@ -2738,7 +2841,7 @@ WERROR print_job_start(struct auth_serversupplied_info *server_info,
 
        fstrcpy(pjob.user, lp_printjob_username(snum));
        standard_sub_advanced(sharename, server_info->sanitized_username,
-                             path, server_info->utok.gid,
+                             path, server_info->unix_token->gid,
                              server_info->sanitized_username,
                              server_info->info3->base.domain.string,
                              pjob.user, sizeof(pjob.user)-1);
@@ -2913,10 +3016,11 @@ static bool get_stored_queue_info(struct messaging_context *msg_ctx,
                                  struct tdb_print_db *pdb, int snum,
                                  int *pcount, print_queue_struct **ppqueue)
 {
-       TDB_DATA data, cgdata;
+       TDB_DATA data, cgdata, jcdata;
        print_queue_struct *queue = NULL;
        uint32 qcount = 0;
        uint32 extra_count = 0;
+       uint32_t changed_count = 0;
        int total_count = 0;
        size_t len = 0;
        uint32 i;
@@ -2935,16 +3039,21 @@ static bool get_stored_queue_info(struct messaging_context *msg_ctx,
        ZERO_STRUCT(cgdata);
 
        /* Get the stored queue data. */
-       data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/linear_queue_array"));
+       data = tdb_fetch_compat(pdb->tdb, string_tdb_data("INFO/linear_queue_array"));
 
        if (data.dptr && data.dsize >= sizeof(qcount))
                len += tdb_unpack(data.dptr + len, data.dsize - len, "d", &qcount);
 
        /* Get the added jobs list. */
-       cgdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_added"));
+       cgdata = tdb_fetch_compat(pdb->tdb, string_tdb_data("INFO/jobs_added"));
        if (cgdata.dptr != NULL && (cgdata.dsize % 4 == 0))
                extra_count = cgdata.dsize/4;
 
+       /* Get the changed jobs list. */
+       jcdata = tdb_fetch_compat(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
+       if (jcdata.dptr != NULL && (jcdata.dsize % 4 == 0))
+               changed_count = jcdata.dsize / 4;
+
        DEBUG(5,("get_stored_queue_info: qcount = %u, extra_count = %u\n", (unsigned int)qcount, (unsigned int)extra_count));
 
        /* Allocate the queue size. */
@@ -3002,6 +3111,50 @@ static bool get_stored_queue_info(struct messaging_context *msg_ctx,
                total_count++;
        }
 
+       /* Update the changed jobids. */
+       for (i = 0; i < changed_count; i++) {
+               uint32_t jobid = IVAL(jcdata.dptr, i * 4);
+               uint32_t j;
+               bool found = false;
+
+               for (j = 0; j < total_count; j++) {
+                       if (queue[j].job == jobid) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (found) {
+                       struct printjob *pjob;
+
+                       DEBUG(5,("get_stored_queue_info: changed job: %u\n",
+                                (unsigned int) jobid));
+
+                       pjob = print_job_find(sharename, jobid);
+                       if (pjob == NULL) {
+                               DEBUG(5,("get_stored_queue_info: failed to find "
+                                        "changed job = %u\n",
+                                        (unsigned int) jobid));
+                               remove_from_jobs_changed(sharename, jobid);
+                               continue;
+                       }
+
+                       queue[j].job = jobid;
+                       queue[j].size = pjob->size;
+                       queue[j].page_count = pjob->page_count;
+                       queue[j].status = pjob->status;
+                       queue[j].priority = 1;
+                       queue[j].time = pjob->starttime;
+                       fstrcpy(queue[j].fs_user, pjob->user);
+                       fstrcpy(queue[j].fs_file, pjob->jobname);
+
+                       DEBUG(5,("get_stored_queue_info: updated queue[%u], jobid: %u, jobname: %s\n",
+                                (unsigned int) j, (unsigned int) jobid, pjob->jobname));
+               }
+
+               remove_from_jobs_changed(sharename, jobid);
+       }
+
        /* Sort the queue by submission time otherwise they are displayed
           in hash order. */
 
@@ -3064,7 +3217,7 @@ int print_queue_status(struct messaging_context *msg_ctx, int snum,
        slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", sharename);
        key = string_tdb_data(keystr);
 
-       data = tdb_fetch(pdb->tdb, key);
+       data = tdb_fetch_compat(pdb->tdb, key);
        if (data.dptr) {
                if (data.dsize == sizeof(*status)) {
                        /* this memcpy is ok since the status struct was
@@ -3092,7 +3245,7 @@ int print_queue_status(struct messaging_context *msg_ctx, int snum,
  Pause a queue.
 ****************************************************************************/
 
-WERROR print_queue_pause(struct auth_serversupplied_info *server_info,
+WERROR print_queue_pause(const struct auth3_session_info *server_info,
                         struct messaging_context *msg_ctx, int snum)
 {
        int ret;
@@ -3129,7 +3282,7 @@ WERROR print_queue_pause(struct auth_serversupplied_info *server_info,
  Resume a queue.
 ****************************************************************************/
 
-WERROR print_queue_resume(struct auth_serversupplied_info *server_info,
+WERROR print_queue_resume(const struct auth3_session_info *server_info,
                          struct messaging_context *msg_ctx, int snum)
 {
        int ret;
@@ -3166,7 +3319,7 @@ WERROR print_queue_resume(struct auth_serversupplied_info *server_info,
  Purge a queue - implemented by deleting all jobs that we can delete.
 ****************************************************************************/
 
-WERROR print_queue_purge(struct auth_serversupplied_info *server_info,
+WERROR print_queue_purge(const struct auth3_session_info *server_info,
                         struct messaging_context *msg_ctx, int snum)
 {
        print_queue_struct *queue;