lib/util_unistr.o lib/util_file.o \
lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o \
lib/talloc.o lib/hash.o lib/substitute.o lib/fsusage.o \
- lib/ms_fnmatch.o lib/select.o \
+ lib/ms_fnmatch.o lib/select.o lib/error.o \
$(TDB_OBJ)
UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
int dos_ChDir(char *path);
char *dos_GetWd(char *path);
+/*The following definitions come from lib/error.c */
+
+uint32 map_nt_error_from_unix(int unix_error);
+
/*The following definitions come from lib/fault.c */
void fault_setup(void (*fn)(void *));
fstring value, uint8 **data, uint32 *type, uint32 *len);
uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr);
BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr);
-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);
BOOL print_time_access_check(int snum);
#endif
#define PRINTER_STATUS_POWER_SAVE 0x01000000
-/* Printer permissions ACE settings */
+/* Printer permissions ACE settings. NT4 uses generic and standard access
+ rights whereas NT5 converts them all to object specific access rights. */
#define PRINTER_ACE_FULL_CONTROL GENERIC_ALL_ACCESS
#define PRINTER_ACE_MANAGE_DOCUMENTS READ_CONTROL_ACCESS
#define PRINTER_ACE_PRINT \
(GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS)
+#define PRINTER_ACE_NT5_FULL_CONTROL 0x000f000c
+#define PRINTER_ACE_NT5_PRINT 0x00020000
+#define PRINTER_ACE_NT5_MANAGE_DOCUMENTS 0x00020008
+
#define SERVER_ACCESS_ADMINISTER 0x00000001
#define SERVER_ACCESS_ENUMERATE 0x00000002
#define PRINTER_ACCESS_ADMINISTER 0x00000004
--- /dev/null
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9
+ * Unix/DOS/NT error code conversions
+ * Copyright (C) Tim Potter 2000
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/* Mapping between Unix, DOS and NT error numbers */
+
+struct {
+ int unix_error;
+ int dos_error;
+ uint32 nt_error;
+} unix_dos_nt_errmap[] = {
+ { EPERM, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { EACCES, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOENT, ERRbadfile, NT_STATUS_NO_SUCH_FILE },
+ { ENOTDIR, ERRbadpath, NT_STATUS_NOT_A_DIRECTORY },
+ { EIO, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR },
+ { EBADF, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EINVAL, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EEXIST, ERRfilexists, NT_STATUS_ACCESS_DENIED},
+ { ENFILE, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { EMFILE, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { ENOSPC, ERRdiskfull, NT_STATUS_DISK_FULL },
+#ifdef EDQUOT
+ { EDQUOT, ERRdiskfull, NT_STATUS_DISK_FULL },
+#endif
+#ifdef ENOTEMPTY
+ { ENOTEMPTY, ERRnoaccess, NT_STATUS_DIRECTORY_NOT_EMPTY },
+#endif
+#ifdef EXDEV
+ { EXDEV, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE },
+#endif
+ { EROFS, ERRnowrite, NT_STATUS_ACCESS_DENIED },
+
+ { 0, 0, 0 }
+};
+
+/* Map an NT error code from a Unix error code */
+
+uint32 map_nt_error_from_unix(int unix_error)
+{
+ int i = 0;
+
+ /* Look through list */
+
+ while(unix_dos_nt_errmap[i].unix_error != 0) {
+ if (unix_dos_nt_errmap[i].unix_error == unix_error) {
+ return unix_dos_nt_errmap[i].nt_error;
+ }
+
+ i++;
+ }
+
+ /* Default return */
+
+ return NT_STATUS_ACCESS_DENIED;
+}
*/
/****************************************************************************
- 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);
}
/* 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
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++) {
}
}
- /* 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)
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;
}
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;
}
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;
}
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);
/* lock the database */
tdb_writelock(tdb);
+ next_jobnum:
next_jobid = tdb_fetch_int(tdb, "INFO/nextjob");
if (next_jobid == -1) next_jobid = 1;
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
print_job_write(jobid, "%!\n",3);
}
- tdb_writeunlock(tdb);
return jobid;
fail:
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;
}
{
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;
}
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<njobs;i++) {
- print_job_delete1(queue[i].job);
+ if (print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
+ print_job_delete1(queue[i].job);
+ }
}
print_cache_flush(snum);
pstring full_name;
fstring dom_name;
fstring user;
- uint8 sid_name_use = SID_NAME_UNKNOWN;
+ enum SID_NAME_USE sid_name_use = SID_NAME_UNKNOWN;
pstrcpy(full_name, dos_unistr2_to_str(&name[i]));
uint32 rid = 0xffffffff;
int dom_idx = -1;
fstring name, dom_name;
- uint8 sid_name_use = 0;
+ enum SID_NAME_USE sid_name_use = 0;
/* Lookup sid from winbindd */
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
#include "includes.h"
extern int DEBUGLEVEL;
Printer->jobid = print_job_start(&user, snum, jobname);
- /* need to map error codes properly - for now give out of
- memory as I don't know the correct codes (tridge) */
+ /* An error occured in print_job_start() so return an appropriate
+ NT error code. */
+
if (Printer->jobid == -1) {
- return ERROR_NOT_ENOUGH_MEMORY;
+ return map_nt_error_from_unix(errno);
}
Printer->document_started=True;
descriptor. By experimentation with two NT machines, the user
requires Full Access to the printer to change security
information. */
- if (!print_access_check(&user, snum, PRINTER_ACE_FULL_CONTROL)) {
+ if (!print_access_check(&user, snum, PRINTER_ACCESS_ADMINISTER)) {
result = ERROR_ACCESS_DENIED;
goto done;
}
numlines = 0;
qlines = file_lines_load(tmp_file, &numlines);
DEBUGADD(10,("Lines returned = [%d]\n", numlines));
- DEBUGADD(10,("Line[0] = [%s]\n", qlines[0]));
DEBUGADD(10,("Unlinking port file [%s]\n", tmp_file));
unlink(tmp_file);
if(numlines) {
// Set the portname to what the script says the portname should be
strncpy(printer->info_2->portname, qlines[0], sizeof(printer->info_2->portname));
+ DEBUGADD(6,("Line[0] = [%s]\n", qlines[0]));
// Send SIGHUP to process group... is there a better way?
kill(0, SIGHUP);
goto done;
}
- if (!print_access_check(NULL, snum, PRINTER_ACE_FULL_CONTROL)) {
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
DEBUG(3, ("printer property change denied by security "
"descriptor\n"));
result = ERROR_ACCESS_DENIED;
numlines = 0;
qlines = file_lines_load(tmp_file, &numlines);
DEBUGADD(10,("Lines returned = [%d]\n", numlines));
- DEBUGADD(10,("Line[0] = [%s]\n", qlines[0]));
DEBUGADD(10,("Unlinking port file [%s]\n", tmp_file));
unlink(tmp_file);
numlines = 0;
qlines = file_lines_load(tmp_file, &numlines);
DEBUGADD(10,("Lines returned = [%d]\n", numlines));
- DEBUGADD(10,("Line[0] = [%s]\n", qlines[0]));
DEBUGADD(10,("Unlinking port file [%s]\n", tmp_file));
unlink(tmp_file);
}
/* you must be a printer admin to add a new printer */
- if (!print_access_check(NULL, snum, PRINTER_ACE_FULL_CONTROL)) {
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
free_a_printer(&printer,2);
return ERROR_ACCESS_DENIED;
}
if (!get_printer_snum(handle, &snum))
return ERROR_INVALID_HANDLE;
- if (!print_access_check(NULL, snum, PRINTER_ACE_FULL_CONTROL)) {
+ if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
DEBUG(3, ("security descriptor change denied by existing "
"security descriptor\n"));
return ERROR_ACCESS_DENIED;
DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),
strerror(errno)));
desc->errcode=NERR_notsupported;
- return;
+ goto done;
}
/* lookup the long printer driver name in the file description */
SERVICE(snum),count));
desc->errcode=NERR_Success;
- file_lines_free(lines);
- return;
+ goto done;
}
err:
DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
desc->errcode=NERR_notsupported;
+
+ done:
+ safe_free(info);
file_lines_free(lines);
}
/* This function returns the number of files for a given driver */
static int get_printerdrivernumber(int snum)
{
- int i;
+ int i, result = 0;
BOOL ok = False;
pstring tok;
char *p;
if (!lines)
{
DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
- return 0;
+ goto done;
}
/* lookup the long printer driver name in the file description */
while (*p && i) {
if (*p++ == ':') i--;
}
- if (!*p || i)
- goto err;
+ if (!*p || i) {
+ DEBUG(3,("Can't determine number of printer driver files\n"));
+ goto done;
+ }
/* count the number of files */
while (next_token(&p,tok,",",sizeof(tok)))
i++;
- file_lines_free(lines);
- return(i);
+ result = i;
}
- err:
+ done:
- DEBUG(3,("Can't determine number of printer driver files\n"));
+ safe_free(info);
file_lines_free(lines);
- return (0);
+
+ return result;
}
static BOOL api_DosPrintQGetInfo(connection_struct *conn,
prs_struct ps;
int result = 0, i;
+ ZERO_STRUCT(ps);
+
/* Open tdb for reading */
slprintf(tdb_path, sizeof(tdb_path) - 1, "%s/ntdrivers.tdb", LOCKDIR);
if (tdb) tdb_close(tdb);
if (mem_ctx) talloc_destroy(mem_ctx);
if (secdesc_ctr) free_sec_desc_buf(&secdesc_ctr);
+ prs_mem_free(&ps);
return result;
}
{
DOM_SID user_sid, group_sid;
SEC_ACE *ace_list = NULL;
- SEC_ACL *dacl;
+ SEC_ACL *dacl = NULL;
SEC_DESC *sd;
SEC_DESC_BUF *sdb = NULL;
int result = 0, num_aces = 0;
TALLOC_CTX *mem_ctx = NULL;
BOOL has_user_sid = False, has_group_sid = False;
+ ZERO_STRUCT(ps);
+
/* Open tdb for reading */
slprintf(tdb_path, sizeof(tdb_path) - 1, "%s/ntdrivers.tdb", LOCKDIR);
dacl, /* Discretionary ACL */
&size);
+ free_sec_acl(&dacl);
+
sdb = make_sec_desc_buf(size, sd);
free_sec_desc(&sd);
if (tdb) tdb_close(tdb);
if (sdb) free_sec_desc_buf(&sdb);
if (mem_ctx) talloc_destroy(mem_ctx);
+ prs_mem_free(&ps);
return result;
}