Fix bug #5688 LPQ process is orphaned if socket address parameter is invalid
[kai/samba.git] / source3 / printing / printing.c
index aa67f08d821b0a65181917af8876cb14081bbb60..ba88f8ee566fe5f19559bed78f9a115e083bbbee 100644 (file)
@@ -335,7 +335,7 @@ static struct printjob *print_job_find(const char *sharename, uint32 jobid)
        uint32_t tmp;
        TDB_DATA                ret;
        struct tdb_print_db     *pdb = get_print_db_byname(sharename);
-       
+
        DEBUG(10,("print_job_find: looking up job %u for share %s\n",
                        (unsigned int)jobid, sharename ));
 
@@ -350,19 +350,19 @@ static struct printjob *print_job_find(const char *sharename, uint32 jobid)
                DEBUG(10,("print_job_find: failed to find jobid %u.\n", (unsigned int)jobid ));
                return NULL;
        }
-       
+
        if ( pjob.nt_devmode ) {
                free_nt_devicemode( &pjob.nt_devmode );
        }
-               
+
        ZERO_STRUCT( pjob );
-       
+
        if ( unpack_pjob( ret.dptr, ret.dsize, &pjob ) == -1 ) {
                DEBUG(10,("print_job_find: failed to unpack jobid %u.\n", (unsigned int)jobid ));
                SAFE_FREE(ret.dptr);
                return NULL;
        }
-       
+
        SAFE_FREE(ret.dptr);
 
        DEBUG(10,("print_job_find: returning system job %d for jobid %u.\n",
@@ -1394,7 +1394,19 @@ main thread of the background lpq updater
 ****************************************************************************/
 void start_background_queue(void)
 {
+       /* Use local variables for this as we don't
+        * need to save the parent side of this, just
+        * ensure it closes when the process exits.
+        */
+       int pause_pipe[2];
+
        DEBUG(3,("start_background_queue: Starting background LPQ thread\n"));
+
+       if (pipe(pause_pipe) == -1) {
+               DEBUG(5,("start_background_queue: cannot create pipe. %s\n", strerror(errno) ));
+               exit(1);
+       }
+
        background_lpq_updater_pid = sys_fork();
 
        if (background_lpq_updater_pid == -1) {
@@ -1406,6 +1418,9 @@ void start_background_queue(void)
                /* Child. */
                DEBUG(5,("start_background_queue: background LPQ thread started\n"));
 
+               close(pause_pipe[0]);
+               pause_pipe[0] = -1;
+
                if (!reinit_after_fork(smbd_messaging_context(), true)) {
                        DEBUG(0,("reinit_after_fork() failed\n"));
                        smb_panic("reinit_after_fork() failed");
@@ -1420,13 +1435,23 @@ void start_background_queue(void)
 
                messaging_register(smbd_messaging_context(), NULL,
                                   MSG_PRINTER_UPDATE, print_queue_receive);
-               
+
                DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
                while (1) {
-                       pause();
-                       
+                       fd_set pause_fds;
+                       int pause_select;
+
+                       FD_ZERO(&pause_fds);
+                       FD_SET(pause_pipe[1], &pause_fds);
+                       pause_select = sys_select(pause_pipe[1]+1, &pause_fds, NULL, NULL, NULL);
+                       /* If pause_pipe[0] is closed it means the parent smbd
+                        * and children exited or aborted. */
+                       if (pause_select == 1) {
+                                exit_server_cleanly(NULL);
+                       }
+
                        /* check for some essential signals first */
-                       
+
                         if (got_sig_term) {
                                 exit_server_cleanly(NULL);
                         }
@@ -1437,9 +1462,9 @@ void start_background_queue(void)
                                 reload_services(False);
                                 reload_after_sighup = 0;
                         }
-                       
+
                        /* now check for messages */
-                       
+
                        DEBUG(10,("start_background_queue: background LPQ thread got a message\n"));
                        message_dispatch(smbd_messaging_context());
 
@@ -1449,6 +1474,8 @@ void start_background_queue(void)
                                                   0);
                }
        }
+
+       close(pause_pipe[1]);
 }
 
 /****************************************************************************
@@ -1979,28 +2006,24 @@ static bool print_job_delete1(int snum, uint32 jobid)
  Return true if the current user owns the print job.
 ****************************************************************************/
 
-static bool is_owner(struct current_user *user, const char *servicename,
+static bool is_owner(struct auth_serversupplied_info *server_info,
+                    const char *servicename,
                     uint32 jobid)
 {
        struct printjob *pjob = print_job_find(servicename, jobid);
-       user_struct *vuser;
 
-       if (!pjob || !user)
+       if (!pjob || !server_info)
                return False;
 
-       if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
-               return strequal(pjob->user,
-                               vuser->server_info->sanitized_username);
-       } else {
-               return strequal(pjob->user, uidtoname(user->ut.uid));
-       }
+       return strequal(pjob->user, server_info->sanitized_username);
 }
 
 /****************************************************************************
  Delete a print job.
 ****************************************************************************/
 
-bool print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR *errcode)
+bool print_job_delete(struct auth_serversupplied_info *server_info, int snum,
+                     uint32 jobid, WERROR *errcode)
 {
        const char* sharename = lp_const_servicename( snum );
        struct printjob *pjob;
@@ -2009,13 +2032,13 @@ bool print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR
 
        *errcode = WERR_OK;
                
-       owner = is_owner(user, lp_const_servicename(snum), jobid);
+       owner = is_owner(server_info, lp_const_servicename(snum), jobid);
        
        /* Check access against security descriptor or whether the user
           owns their job. */
 
        if (!owner && 
-           !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
+           !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
                DEBUG(3, ("delete denied by security descriptor\n"));
                *errcode = WERR_ACCESS_DENIED;
 
@@ -2023,7 +2046,8 @@ bool print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR
                sys_adminlog( LOG_ERR, 
                              "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
-                             uidtoname(user->ut.uid), PRINTERNAME(snum) );
+                             uidtoname(server_info->utok.uid),
+                             PRINTERNAME(snum) );
                /* END_ADMIN_LOG */
 
                return False;
@@ -2067,7 +2091,8 @@ pause, or resume print job. User name: %s. Printer name: %s.",
  Pause a job.
 ****************************************************************************/
 
-bool print_job_pause(struct current_user *user, int snum, uint32 jobid, WERROR *errcode)
+bool print_job_pause(struct auth_serversupplied_info *server_info, int snum,
+                    uint32 jobid, WERROR *errcode)
 {
        const char* sharename = lp_const_servicename(snum);
        struct printjob *pjob;
@@ -2076,7 +2101,7 @@ bool print_job_pause(struct current_user *user, int snum, uint32 jobid, WERROR *
 
        pjob = print_job_find(sharename, jobid);
        
-       if (!pjob || !user) {
+       if (!pjob || !server_info) {
                DEBUG(10, ("print_job_pause: no pjob or user for jobid %u\n",
                        (unsigned int)jobid ));
                return False;
@@ -2088,15 +2113,16 @@ bool print_job_pause(struct current_user *user, int snum, uint32 jobid, WERROR *
                return False;
        }
 
-       if (!is_owner(user, lp_const_servicename(snum), jobid) &&
-           !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
+       if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
+           !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
                DEBUG(3, ("pause denied by security descriptor\n"));
 
                /* BEGIN_ADMIN_LOG */
                sys_adminlog( LOG_ERR, 
                        "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
-                               uidtoname(user->ut.uid), PRINTERNAME(snum) );
+                             uidtoname(server_info->utok.uid),
+                             PRINTERNAME(snum) );
                /* END_ADMIN_LOG */
 
                *errcode = WERR_ACCESS_DENIED;
@@ -2127,7 +2153,8 @@ pause, or resume print job. User name: %s. Printer name: %s.",
  Resume a job.
 ****************************************************************************/
 
-bool print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR *errcode)
+bool print_job_resume(struct auth_serversupplied_info *server_info, int snum,
+                     uint32 jobid, WERROR *errcode)
 {
        const char *sharename = lp_const_servicename(snum);
        struct printjob *pjob;
@@ -2135,8 +2162,8 @@ bool print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR
        struct printif *current_printif = get_printer_fns( snum );
 
        pjob = print_job_find(sharename, jobid);
-       
-       if (!pjob || !user) {
+
+       if (!pjob || !server_info) {
                DEBUG(10, ("print_job_resume: no pjob or user for jobid %u\n",
                        (unsigned int)jobid ));
                return False;
@@ -2148,8 +2175,8 @@ bool print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR
                return False;
        }
 
-       if (!is_owner(user, lp_const_servicename(snum), jobid) &&
-           !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
+       if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
+           !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
                DEBUG(3, ("resume denied by security descriptor\n"));
                *errcode = WERR_ACCESS_DENIED;
 
@@ -2157,7 +2184,8 @@ bool print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR
                sys_adminlog( LOG_ERR, 
                         "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
-                       uidtoname(user->ut.uid), PRINTERNAME(snum) );
+                             uidtoname(server_info->utok.uid),
+                             PRINTERNAME(snum) );
                /* END_ADMIN_LOG */
                return False;
        }
@@ -2357,12 +2385,12 @@ static bool add_to_jobs_changed(struct tdb_print_db *pdb, uint32 jobid)
  Start spooling a job - return the jobid.
 ***************************************************************************/
 
-uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DEVICEMODE *nt_devmode )
+uint32 print_job_start(struct auth_serversupplied_info *server_info, int snum,
+                      char *jobname, NT_DEVICEMODE *nt_devmode )
 {
        uint32 jobid;
        char *path;
        struct printjob pjob;
-       user_struct *vuser;
        const char *sharename = lp_const_servicename(snum);
        struct tdb_print_db *pdb = get_print_db_byname(sharename);
        int njobs;
@@ -2372,7 +2400,7 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DE
        if (!pdb)
                return (uint32)-1;
 
-       if (!print_access_check(user, snum, PRINTER_ACCESS_USE)) {
+       if (!print_access_check(server_info, snum, PRINTER_ACCESS_USE)) {
                DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
                release_print_db(pdb);
                return (uint32)-1;
@@ -2388,9 +2416,9 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DE
 
        /* see if we have sufficient disk space */
        if (lp_minprintspace(snum)) {
-               SMB_BIG_UINT dspace, dsize;
+               uint64_t dspace, dsize;
                if (sys_fsusage(path, &dspace, &dsize) == 0 &&
-                   dspace < 2*(SMB_BIG_UINT)lp_minprintspace(snum)) {
+                   dspace < 2*(uint64_t)lp_minprintspace(snum)) {
                        DEBUG(3, ("print_job_start: disk space check failed.\n"));
                        release_print_db(pdb);
                        errno = ENOSPC;
@@ -2437,17 +2465,14 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DE
        
        fstrcpy(pjob.jobname, jobname);
 
-       if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
-               fstrcpy(pjob.user, lp_printjob_username(snum));
-               standard_sub_basic(
-                       vuser->server_info->sanitized_username,
-                       pdb_get_domain(vuser->server_info->sam_account),
-                       pjob.user, sizeof(pjob.user)-1);
-               /* ensure NULL termination */ 
-               pjob.user[sizeof(pjob.user)-1] = '\0'; 
-       } else {
-               fstrcpy(pjob.user, uidtoname(user->ut.uid));
-       }
+       fstrcpy(pjob.user, lp_printjob_username(snum));
+       standard_sub_advanced(sharename, server_info->sanitized_username,
+                             path, server_info->utok.gid, 
+                             server_info->sanitized_username,
+                             pdb_get_domain(server_info->sam_account),
+                             pjob.user, sizeof(pjob.user)-1);
+       /* ensure NULL termination */
+       pjob.user[sizeof(pjob.user)-1] = '\0';
 
        fstrcpy(pjob.queuename, lp_const_servicename(snum));
 
@@ -2775,12 +2800,14 @@ int print_queue_status(int snum,
  Pause a queue.
 ****************************************************************************/
 
-bool print_queue_pause(struct current_user *user, int snum, WERROR *errcode)
+bool print_queue_pause(struct auth_serversupplied_info *server_info, int snum,
+                      WERROR *errcode)
 {
        int ret;
        struct printif *current_printif = get_printer_fns( snum );
        
-       if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
+       if (!print_access_check(server_info, snum,
+                               PRINTER_ACCESS_ADMINISTER)) {
                *errcode = WERR_ACCESS_DENIED;
                return False;
        }
@@ -2811,12 +2838,14 @@ bool print_queue_pause(struct current_user *user, int snum, WERROR *errcode)
  Resume a queue.
 ****************************************************************************/
 
-bool print_queue_resume(struct current_user *user, int snum, WERROR *errcode)
+bool print_queue_resume(struct auth_serversupplied_info *server_info, int snum,
+                       WERROR *errcode)
 {
        int ret;
        struct printif *current_printif = get_printer_fns( snum );
 
-       if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
+       if (!print_access_check(server_info, snum,
+                               PRINTER_ACCESS_ADMINISTER)) {
                *errcode = WERR_ACCESS_DENIED;
                return False;
        }
@@ -2847,7 +2876,8 @@ bool print_queue_resume(struct current_user *user, int snum, WERROR *errcode)
  Purge a queue - implemented by deleting all jobs that we can delete.
 ****************************************************************************/
 
-bool print_queue_purge(struct current_user *user, int snum, WERROR *errcode)
+bool print_queue_purge(struct auth_serversupplied_info *server_info, int snum,
+                      WERROR *errcode)
 {
        print_queue_struct *queue;
        print_status_struct status;
@@ -2857,14 +2887,16 @@ bool print_queue_purge(struct current_user *user, int snum, WERROR *errcode)
        /* Force and update so the count is accurate (i.e. not a cached count) */
        print_queue_update(snum, True);
        
-       can_job_admin = print_access_check(user, snum, JOB_ACCESS_ADMINISTER);
+       can_job_admin = print_access_check(server_info, snum,
+                                          JOB_ACCESS_ADMINISTER);
        njobs = print_queue_status(snum, &queue, &status);
        
        if ( can_job_admin )
                become_root();
 
        for (i=0;i<njobs;i++) {
-               bool owner = is_owner(user, lp_const_servicename(snum), queue[i].job);
+               bool owner = is_owner(server_info, lp_const_servicename(snum),
+                                     queue[i].job);
 
                if (owner || can_job_admin) {
                        print_job_delete1(snum, queue[i].job);