Re-instated lanman printing security checks (oops).
authorTim Potter <tpot@samba.org>
Mon, 10 Jul 2000 05:08:21 +0000 (05:08 +0000)
committerTim Potter <tpot@samba.org>
Mon, 10 Jul 2000 05:08:21 +0000 (05:08 +0000)
A user can now pause, resume or delete their own job even if they don't
have the Manage Documents privilege.

Added call to se_access_check() for changing printer properties.  The Full
Access privilege is required for the user to perform this.

Several uninitialised variables and memory leaks plugged.

Modified default ACL created on new printers to be Everyone / Print instead
of Everyone / Full Access.  This required some random stuffing around with
the value of the revision field to correspond with the ACL that NT produces
when setting the same permission on the printer.

Fixed dodgy function call in printing/printfsp.c

source/printing/nt_printing.c
source/printing/printfsp.c
source/printing/printing.c
source/rpc_server/srv_spoolss_nt.c
source/smbd/lanman.c

index e3af34053be7cf95de56f2c94ba0e2b1f1ec606b..83fd18da9b3134297b6ba7cd6d24622dd89f1c79 100644 (file)
@@ -1478,32 +1478,48 @@ BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
 /****************************************************************************
 store a security desc for a printer
 ****************************************************************************/
-uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
+uint32 nt_printing_setsec(char *printername, struct current_user *user,
+                         SEC_DESC_BUF *secdesc_ctr)
 {
        SEC_DESC_BUF *new_secdesc_ctr = NULL;
+       SEC_DESC_BUF *old_secdesc_ctr = NULL;
        prs_struct ps;
        fstring key;
-       uint32 status;
+       uint32 acc_granted, status;
 
-       /* The old owner and group sids of the security descriptor are not
+       /* Get old security descriptor */
+
+       if (!nt_printing_getsec(printername, &old_secdesc_ctr)) {
+               DEBUG(3, ("could not get old security descriptor for "
+                         "printer %s", printername));
+               return ERROR_INVALID_FUNCTION;
+       }
+
+       /* Check the user has permissions to change the security
+          descriptor.  By experimentation with two NT machines, the user
+          requires Full Access to the printer to change security
+          information. */ 
+
+       if (!se_access_check(old_secdesc_ctr->sec, user->uid, user->gid,
+                            user->ngroups, user->groups, 
+                            PRINTER_ACE_FULL_CONTROL, &acc_granted,
+                            &status)) {
+               DEBUG(3, ("security descriptor change denied by existing "
+                         "security descriptor\n"));
+               free_sec_desc_buf(&old_secdesc_ctr);
+               return status;
+       }
+
+        /* The old owner and group sids of the security descriptor are not
           present when new ACEs are added or removed by changing printer
           permissions through NT.  If they are NULL in the new security
           descriptor then copy them over from the old one. */
 
        if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
-               SEC_DESC_BUF *old_secdesc_ctr = NULL;
                DOM_SID *owner_sid, *group_sid;
                SEC_DESC *psd = NULL;
                size_t size;
 
-               /* Get old security descriptor */
-
-               if (!nt_printing_getsec(printername, &old_secdesc_ctr)) {
-                       DEBUG(0, ("could not get old security descriptor for "
-                                 "printer %s", printername));
-                       return ERROR_INVALID_FUNCTION;
-               }
-
                /* Pick out correct owner and group sids */
 
                owner_sid = secdesc_ctr->sec->owner_sid ?
@@ -1528,7 +1544,6 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
                /* Free up memory */
 
                free_sec_desc(&psd);
-               free_sec_desc_buf(&old_secdesc_ctr);
        }
 
        if (!new_secdesc_ctr) {
@@ -1555,7 +1570,11 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
                status = ERROR_INVALID_FUNCTION;
        }
 
+       /* Free mallocated memory */
+
  out:
+       free_sec_desc_buf(&old_secdesc_ctr);
+
        if (new_secdesc_ctr != secdesc_ctr) {
                free_sec_desc_buf(&new_secdesc_ctr);
        }
@@ -1564,6 +1583,31 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
        return status;
 }
 
+/* Call winbindd to convert a name to a sid */
+
+BOOL winbind_lookup_name(char *name, DOM_SID *sid, uint8 *name_type)
+{
+       struct winbindd_request request;
+        struct winbindd_response response;
+       enum nss_status result;
+       
+       if (!sid || !name_type) return False;
+
+        /* Send off request */
+
+        ZERO_STRUCT(request);
+        ZERO_STRUCT(response);
+
+        fstrcpy(request.data.name, name);
+        if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request, 
+                                      &response)) == NSS_STATUS_SUCCESS) {
+               string_to_sid(sid, response.data.sid.sid);
+               *name_type = response.data.sid.type;
+       }
+
+        return result == NSS_STATUS_SUCCESS;
+}
+
 /****************************************************************************
  Construct a default security descriptor buffer for a printer.
 ****************************************************************************/
@@ -1571,22 +1615,43 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
 static SEC_DESC_BUF *construct_default_printer_sdb(void)
 {
        extern DOM_SID global_sid_World; 
-       SEC_ACE ace[2];
+       SEC_ACE ace;
        SEC_ACCESS sa;
        SEC_ACL *psa = NULL;
        SEC_DESC_BUF *sdb = NULL;
        SEC_DESC *psd = NULL;
+       DOM_SID owner_sid;
        size_t sd_size;
+       uint8 name_type;
 
-       init_sec_access(&sa,PRINTER_ACE_FULL_CONTROL);
-       init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
-                                       sa, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
-       init_sec_ace(&ace[1], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
-                                       sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+       /* Create an ACE where Everyone is allowed to print */
+
+       init_sec_access(&sa, PRINTER_ACE_PRINT);
+       init_sec_ace(&ace, &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+       /* Make the security descriptor owned by the Administrators group
+          on the PDC of the domain. */
+
+       if (!winbind_lookup_name("Administrator", &owner_sid, &name_type)) {
+               return NULL;  /* Doh */
+       }
 
-       if ((psa = make_sec_acl( ACL_REVISION, 2, ace)) != NULL) {
-               psd = make_sec_desc(SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
-                                                                       &global_sid_World, &global_sid_World, NULL, psa, &sd_size);
+       
+
+       /* The ACL revision number in rpc_secdesc.h differs from the one
+          created by NT when setting ACE entries in printer
+          descriptors.  NT4 complains about the property being edited by a
+          NT5 machine. */
+
+#define NT4_ACL_REVISION 0x2
+
+       if ((psa = make_sec_acl(NT4_ACL_REVISION, 1, &ace)) != NULL) {
+               psd = make_sec_desc(SEC_DESC_REVISION, 
+                                   SEC_DESC_SELF_RELATIVE | 
+                                   SEC_DESC_DACL_PRESENT,
+                                   &owner_sid, NULL,
+                                   NULL, psa, &sd_size);
                free_sec_acl(&psa);
        }
 
@@ -1597,7 +1662,8 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
 
        sdb = make_sec_desc_buf(sd_size, psd);
 
-       DEBUG(4,("construct_default_printer_sdb: size = %u.\n", (unsigned int)sd_size));
+       DEBUG(4,("construct_default_printer_sdb: size = %u.\n", 
+                (unsigned int)sd_size));
 
        free_sec_desc(&psd);
        return sdb;
@@ -1667,7 +1733,7 @@ jfm: I should use this comment for the text file to explain
 
 /* Check a user has permissions to perform the given operation */
 
-BOOL print_access_check(struct current_user *user, int snum, 
+BOOL print_access_check(struct current_user *user, int snum,
                        uint32 required_access)
 {
        SEC_DESC_BUF *secdesc = NULL;
@@ -1676,14 +1742,6 @@ BOOL print_access_check(struct current_user *user, int snum,
        char *pname;
        int i;
        
-       /* If the user is NULL then we are being called by the lanman
-          printing system.  Let the lower level printing permissions
-          handle this. */
-
-       if (user == NULL) {
-               return True;
-       }
-
        /* Get printer name */
 
        pname = PRINTERNAME(snum);
index 09c61408843b9f1555324262d0bac674f4bb82b2..a1303eb4416e0b370cdae7e22698d48f58cfd21b 100644 (file)
@@ -41,7 +41,7 @@ files_struct *print_fsp_open(connection_struct *conn,char *jobname)
        if(!fsp)
                return NULL;
 
-       jobid = print_job_start(SNUM(conn), conn->vuid, jobname);
+       jobid = print_job_start(&current_user, SNUM(conn), jobname);
        if (jobid == -1) {
                file_free(fsp);
                return NULL;
index 9a2994856d998b9838b693eeeba45e8028f02b16..2f1753b76c8c2d1495312fb57043fb8f9723b1e5 100644 (file)
@@ -477,6 +477,21 @@ static BOOL print_job_delete1(int jobid)
        return True;
 }
 
+/* Return true if the uid owns the print job */
+
+static BOOL is_owner(uid_t uid, int jobid)
+{
+       struct printjob *pjob = print_job_find(jobid);
+       struct passwd *pw;
+
+       if (!pjob || !(pw = sys_getpwuid(uid))) return False;
+
+       DEBUG(0, ("checking owner of jobid %d: %s == %s\n",
+                 jobid, pw->pw_name, pjob->user));
+
+       return (pw && pjob && strequal(pw->pw_name, pjob->user));
+}
+
 /****************************************************************************
 delete a print job
 ****************************************************************************/
@@ -484,7 +499,11 @@ BOOL print_job_delete(struct current_user *user, int jobid)
 {
        int snum = print_job_snum(jobid);
 
-       if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
+       /* Check access against security descriptor or whether the user
+          owns their job. */
+
+       if (!is_owner(user->uid, jobid) &&
+           !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
                DEBUG(3, ("delete denied by security descriptor\n"));
                return False;
        }
@@ -513,7 +532,8 @@ BOOL print_job_pause(struct current_user *user, int jobid)
 
        snum = print_job_snum(jobid);
 
-       if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
+       if (!is_owner(user->uid, jobid) &&
+           !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
                DEBUG(3, ("pause denied by security descriptor\n"));
                return False;
        }
@@ -546,7 +566,8 @@ BOOL print_job_resume(struct current_user *user, int jobid)
 
        snum = print_job_snum(jobid);
 
-       if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
+       if (!is_owner(user->uid, jobid) &&
+           !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
                DEBUG(3, ("resume denied by security descriptor\n"));
                return False;
        }
index 522a266b8c381024fc6131caab6f0300ebf8089a..0be371df11d3028bb6320579570cce5ea8cb89eb 100644 (file)
@@ -3001,8 +3001,10 @@ static uint32 control_printer(const POLICY_HND *handle, uint32 command,
  ********************************************************************/
 static uint32 update_printer_sec(const POLICY_HND *handle, uint32 level,
                                 const SPOOL_PRINTER_INFO_LEVEL *info,
-                                SEC_DESC_BUF *secdesc_ctr)
+                                pipes_struct *p, SEC_DESC_BUF *secdesc_ctr)
 {
+       struct current_user user;
+
        Printer_entry *Printer = find_printer_index_by_hnd(handle);
 
        if (!OPEN_HANDLE(Printer)) {
@@ -3010,7 +3012,15 @@ static uint32 update_printer_sec(const POLICY_HND *handle, uint32 level,
                return ERROR_INVALID_HANDLE;
        }
 
-       return nt_printing_setsec(Printer->dev.printername, secdesc_ctr);
+       if (p->ntlmssp_auth_validated) {
+               memcpy(&user, &p->pipe_user, sizeof(user));
+       } else {
+               extern struct current_user current_user;
+               memcpy(&user, &current_user, sizeof(user));
+       }
+
+       return nt_printing_setsec(Printer->dev.printername, &user, 
+                                 secdesc_ctr);
 }
 
 /********************************************************************
@@ -3025,25 +3035,53 @@ static uint32 update_printer(const POLICY_HND *handle, uint32 level,
        int snum;
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(handle);
-       
+       SEC_DESC_BUF *sd = NULL;
+       uint32 result, acc_granted;
+       extern struct current_user current_user;
+
        DEBUG(8,("update_printer\n"));
        
+       result = NT_STATUS_NO_PROBLEMO;
+
+       /* Check calling user has permission to update printer description */ 
+       
+       if (!nt_printing_getsec(Printer->dev.printername, &sd)) {
+               DEBUG(3, ("Could not get security descriptor for printer %s",
+                         Printer->dev.printername));
+               result = ERROR_INVALID_FUNCTION;
+               goto done;
+       }
+
+       if (!se_access_check(sd->sec, current_user.uid, current_user.gid,
+                            current_user.ngroups, current_user.groups,
+                            PRINTER_ACE_FULL_CONTROL, &acc_granted,
+                            &result)) {
+               DEBUG(3, ("printer property change denied by security "
+                         "descriptor\n"));
+               goto done;
+       }
+
        if (level!=2) {
                DEBUG(0,("Send a mail to samba@samba.org\n"));
                DEBUGADD(0,("with the following message: update_printer: level!=2\n"));
-               return ERROR_INVALID_LEVEL;
+               result = ERROR_INVALID_LEVEL;
+               goto done;
        }
 
        if (!OPEN_HANDLE(Printer)) {
-               DEBUG(0,("update_printer: Invalid handle (%s)\n", OUR_HANDLE(handle)));
-               return ERROR_INVALID_HANDLE;
+               result = ERROR_INVALID_HANDLE;
+               goto done;
        }
 
-       if (!get_printer_snum(handle, &snum) )
-               return ERROR_INVALID_HANDLE;
+       if (!get_printer_snum(handle, &snum)) {
+               result = ERROR_INVALID_HANDLE;
+               goto done;
+       }
        
-       if(get_a_printer(&printer, 2, lp_servicename(snum)) != 0)
-               return ERROR_INVALID_HANDLE;
+       if(get_a_printer(&printer, 2, lp_servicename(snum)) != 0) {
+               result = ERROR_INVALID_HANDLE;
+               goto done;
+       }
 
        DEBUGADD(8,("Converting info_2 struct\n"));
 
@@ -3078,13 +3116,15 @@ static uint32 update_printer(const POLICY_HND *handle, uint32 level,
                        
        if (add_a_printer(*printer, 2)!=0) {
                /* I don't really know what to return here !!! */
-               free_a_printer(&printer, 2);
-               return ERROR_ACCESS_DENIED;
+               result = ERROR_ACCESS_DENIED;
+               goto done;
        }
 
+ done:
        free_a_printer(&printer, 2);
+       free_sec_desc_buf(&sd);
 
-       return NT_STATUS_NO_PROBLEMO;
+       return result;
 }
 
 /****************************************************************************
@@ -3111,7 +3151,8 @@ uint32 _spoolss_setprinter(const POLICY_HND *handle, uint32 level,
                        return update_printer(handle, level, info, devmode_ctr.devmode);
                        break;
                case 3:
-                       return update_printer_sec(handle, level, info, secdesc_ctr);
+                       return update_printer_sec(handle, level, info, p,
+                                                 secdesc_ctr);
                        break;
                default:
                        return ERROR_INVALID_LEVEL;
index 82f0c25fa8629ff8e42e2bfddaa98e66827e9c7f..e5a42d4db460477450120d1cc0e5d4873db6a04c 100644 (file)
@@ -1753,6 +1753,7 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param
        char *str2 = skip_string(str1,1);
        char *p = skip_string(str2,1);
        int jobid, errcode;
+       extern struct current_user current_user;
 
        jobid = SVAL(p,0);
 
@@ -1773,13 +1774,16 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param
        
        switch (function) {
        case 81:                /* delete */ 
-               if (print_job_delete(NULL, jobid)) errcode = NERR_Success;
+               if (print_job_delete(&current_user, jobid)) 
+                       errcode = NERR_Success;
                break;
        case 82:                /* pause */
-               if (print_job_pause(NULL, jobid)) errcode = NERR_Success;
+               if (print_job_pause(&current_user, jobid)) 
+                       errcode = NERR_Success;
                break;
        case 83:                /* resume */
-               if (print_job_resume(NULL, jobid)) errcode = NERR_Success;
+               if (print_job_resume(&current_user, jobid)) 
+                       errcode = NERR_Success;
                break;
        }