/****************************************************************************
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 ?
/* Free up memory */
free_sec_desc(&psd);
- free_sec_desc_buf(&old_secdesc_ctr);
}
if (!new_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);
}
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.
****************************************************************************/
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);
}
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;
/* 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;
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);
if(!fsp)
return NULL;
- jobid = print_job_start(SNUM(conn), conn->vuid, jobname);
+ jobid = print_job_start(¤t_user, SNUM(conn), jobname);
if (jobid == -1) {
file_free(fsp);
return NULL;
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
****************************************************************************/
{
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;
}
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;
}
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;
}
********************************************************************/
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)) {
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, ¤t_user, sizeof(user));
+ }
+
+ return nt_printing_setsec(Printer->dev.printername, &user,
+ secdesc_ctr);
}
/********************************************************************
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"));
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;
}
/****************************************************************************
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;
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);
switch (function) {
case 81: /* delete */
- if (print_job_delete(NULL, jobid)) errcode = NERR_Success;
+ if (print_job_delete(¤t_user, jobid))
+ errcode = NERR_Success;
break;
case 82: /* pause */
- if (print_job_pause(NULL, jobid)) errcode = NERR_Success;
+ if (print_job_pause(¤t_user, jobid))
+ errcode = NERR_Success;
break;
case 83: /* resume */
- if (print_job_resume(NULL, jobid)) errcode = NERR_Success;
+ if (print_job_resume(¤t_user, jobid))
+ errcode = NERR_Success;
break;
}