From a3a28675fafbbc5a5a378b3a7235253d772ef63e Mon Sep 17 00:00:00 2001 From: David O'Neill Date: Fri, 1 Sep 2000 18:49:26 +0000 Subject: Changes from APPLIANCE_HEAD (per Tim Potter): - make proto - addition of function to convert from errno values to NT status codes (source/lib/error.c) - purge queue done without full access permission will purge only the jobs owned by that user, rather than failing. - unlock job database tdb before sending job to printer - in print_job_start(), ensure that we don't pick a jobid with an existing temporary file that may be owned by another user, as it causes silent failures. - fixes for printer permission checking for NT5 clients (source/include/rpc_spoolss.h, source/printing/nt_printing.c, source/printing/printing.c, source/rpc_server/srv_spoolss_nt.c) - change from uint8 to 'enum SID_NAME_USE' (source/rpc_server/srv_lsa.c) - fixed memory leaks for win95 driver download process (source/smbd/lanman.c) - properly free prs_structs and dacl in testsuite/printing/psec.c (This used to be commit 74af3e2caec7197e5d1ca389e2f78054a4197502) --- source3/printing/nt_printing.c | 103 +++++++++++++++++++++++++++++++++-------- source3/printing/printing.c | 30 ++++++------ 2 files changed, 99 insertions(+), 34 deletions(-) (limited to 'source3/printing') diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 05ab71d178..0ad50a2277 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -2203,30 +2203,47 @@ jfm: I should use this comment for the text file to explain */ /**************************************************************************** - Check a user has permissions to perform the given operation + Check a user has permissions to perform the given operation. We use some + constants defined in include/rpc_spoolss.h that look relevant to check + the various actions we perform when checking printer access. + + PRINTER_ACCESS_ADMINISTER: + print_queue_pause, print_queue_resume, update_printer_sec, + update_printer, spoolss_addprinterex_level_2, + _spoolss_setprinterdata + + PRINTER_ACCESS_USE: + print_job_start + + JOB_ACCESS_ADMINISTER: + print_job_delete, print_job_pause, print_job_resume, + print_queue_purge - if user is NULL then use the current_user structure ****************************************************************************/ -BOOL print_access_check(struct current_user *user, int snum, - uint32 required_access) +BOOL print_access_check(struct current_user *user, int snum, int access_type) { SEC_DESC_BUF *secdesc = NULL; - uint32 access_granted, status; + uint32 access_granted, status, required_access = 0; BOOL result; char *pname; int i; extern struct current_user current_user; + /* If user is NULL then use the current_user structure */ + if (!user) user = ¤t_user; - /* always allow root or printer admins to do anything */ - if (user->uid==0 || + /* Always allow root or printer admins to do anything */ + + if (user->uid == 0 || user_in_list(uidtoname(user->uid), lp_printer_admin(snum))) { return True; } /* Get printer name */ + pname = PRINTERNAME(snum); + if (!pname || !*pname) pname = SERVICE(snum); @@ -2236,8 +2253,34 @@ BOOL print_access_check(struct current_user *user, int snum, } /* Get printer security descriptor */ + nt_printing_getsec(pname, &secdesc); + /* Check against NT4 ACE mask values. From observation these + values are: + + Access Type ACE Mask Constant + ------------------------------------- + Full Control 0x10000000 PRINTER_ACE_FULL_CONTROL + Print 0xe0000000 PRINTER_ACE_PRINT + Manage Documents 0x00020000 PRINTER_ACE_MANAGE_DOCUMENTS + */ + + switch (access_type) { + case PRINTER_ACCESS_USE: + required_access = PRINTER_ACE_PRINT; + break; + case PRINTER_ACCESS_ADMINISTER: + required_access = PRINTER_ACE_MANAGE_DOCUMENTS | + PRINTER_ACE_PRINT; + break; + case JOB_ACCESS_ADMINISTER: + required_access = PRINTER_ACE_MANAGE_DOCUMENTS; + default: + DEBUG(0, ("invalid value passed to print_access_check()\n")); + return False; + } + /* The ACE for Full Control in a printer security descriptor doesn't seem to map properly to the access checking model. For it to work properly it should be the logical OR of all the other @@ -2249,16 +2292,6 @@ BOOL print_access_check(struct current_user *user, int snum, performing the access check. I'm sure there is a better way to do this! */ - /* You forgot to also change the *required access* from PRINTER_ACE_FULL_CONTROL - to PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT before doing the check. - This took me 3 hours to find !!!!! JRA. - */ - - if (required_access & PRINTER_ACE_FULL_CONTROL) { - required_access |= (PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT); - required_access &= ~PRINTER_ACE_FULL_CONTROL; - } - if (secdesc && secdesc->sec && secdesc->sec->dacl && secdesc->sec->dacl->ace) { for(i = 0; i < secdesc->sec->dacl->num_aces; i++) { @@ -2271,14 +2304,46 @@ BOOL print_access_check(struct current_user *user, int snum, } } - /* Check access */ + if ((result = se_access_check(secdesc->sec, user, required_access, + &access_granted, &status))) { + goto done; + } + + /* Check against NT5 ACE mask values. From observation these + values are: + + Access Type ACE Mask Constant + ------------------------------------- + Full Control 0x000f000c PRINTER_ACE_NT5_FULL_CONTROL + Print 0x00020008 PRINTER_ACE_NT5_PRINT + Manage Documents 0x00020000 PRINTER_ACE_NT5_MANAGE_DOCUMENTS + + NT5 likes to rewrite the security descriptor and change the ACE + masks from NT4 format to NT5 format making them unreadable by + NT4 clients. */ + + switch (access_type) { + case PRINTER_ACCESS_USE: + required_access = PRINTER_ACE_NT5_PRINT; + break; + case PRINTER_ACCESS_ADMINISTER: + required_access = PRINTER_ACE_NT5_FULL_CONTROL; + break; + case JOB_ACCESS_ADMINISTER: + required_access = PRINTER_ACE_NT5_MANAGE_DOCUMENTS; + break; + } result = se_access_check(secdesc->sec, user, required_access, &access_granted, &status); + /* Check access */ + + done: DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE")); - + /* Free mallocated memory */ + free_sec_desc_buf(&secdesc); if (!result) diff --git a/source3/printing/printing.c b/source3/printing/printing.c index cf3748ed16..406cbf2c80 100644 --- a/source3/printing/printing.c +++ b/source3/printing/printing.c @@ -507,7 +507,7 @@ BOOL print_job_delete(struct current_user *user, int jobid) owns their job. */ if (!owner && - !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) { + !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { DEBUG(3, ("delete denied by security descriptor\n")); return False; } @@ -542,7 +542,7 @@ BOOL print_job_pause(struct current_user *user, int jobid) owner = is_owner(user->uid, jobid); if (!owner && - !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) { + !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { DEBUG(3, ("pause denied by security descriptor\n")); return False; } @@ -579,7 +579,7 @@ BOOL print_job_resume(struct current_user *user, int jobid) owner = is_owner(user->uid, jobid); if (!is_owner(user->uid, jobid) && - !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) { + !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { DEBUG(3, ("resume denied by security descriptor\n")); return False; } @@ -624,9 +624,9 @@ int print_job_start(struct current_user *user, int snum, char *jobname) errno = 0; - if (!print_access_check(user, snum, PRINTER_ACE_PRINT)) { + if (!print_access_check(user, snum, PRINTER_ACCESS_USE)) { DEBUG(3, ("job start denied by security descriptor\n")); - return False; + return -1; } path = lp_pathname(snum); @@ -665,6 +665,7 @@ int print_job_start(struct current_user *user, int snum, char *jobname) /* lock the database */ tdb_writelock(tdb); + next_jobnum: next_jobid = tdb_fetch_int(tdb, "INFO/nextjob"); if (next_jobid == -1) next_jobid = 1; @@ -684,17 +685,20 @@ int print_job_start(struct current_user *user, int snum, char *jobname) we unlink first to cope with old spool files and also to beat a symlink security hole - it allows us to use O_EXCL + There may be old spool files owned by other users lying around. */ slprintf(pjob.filename, sizeof(pjob.filename), "%s/%s%d", path, PRINT_SPOOL_PREFIX, jobid); if (unlink(pjob.filename) == -1 && errno != ENOENT) { - goto fail; + goto next_jobnum; } pjob.fd = sys_open(pjob.filename,O_WRONLY|O_CREAT|O_EXCL,0600); if (pjob.fd == -1) goto fail; print_job_store(jobid, &pjob); + tdb_writeunlock(tdb); + /* * If the printer is marked as postscript output a leading * file identifier to ensure the file is treated as a raw @@ -706,7 +710,6 @@ int print_job_start(struct current_user *user, int snum, char *jobname) print_job_write(jobid, "%!\n",3); } - tdb_writeunlock(tdb); return jobid; fail: @@ -896,7 +899,7 @@ BOOL print_queue_pause(struct current_user *user, int snum, int *errcode) if (!user) return False; - if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) { + if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) { *errcode = ERROR_ACCESS_DENIED; return False; } @@ -917,7 +920,7 @@ BOOL print_queue_resume(struct current_user *user, int snum, int *errcode) { int ret; - if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) { + if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) { *errcode = ERROR_ACCESS_DENIED; return False; } @@ -940,14 +943,11 @@ BOOL print_queue_purge(struct current_user *user, int snum, int *errcode) print_status_struct status; int njobs, i; - if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) { - *errcode = ERROR_ACCESS_DENIED; - return False; - } - njobs = print_queue_status(snum, &queue, &status); for (i=0;i