Changes from APPLIANCE_HEAD:
[ira/wip.git] / source3 / printing / nt_printing.c
index 2ad2e564ecfb131a7c8946f6cbb4320dd5a5e074..2572a98bdea495315df7d9fa91ddaece0b6511a5 100644 (file)
@@ -35,6 +35,15 @@ static TDB_CONTEXT *tdb; /* used for driver files */
 
 #define DATABASE_VERSION 1
 
+/* Map generic permissions to printer object specific permissions */
+
+struct generic_mapping printer_generic_mapping = {
+       PRINTER_READ,
+       PRINTER_WRITE,
+       PRINTER_EXECUTE,
+       PRINTER_ALL_ACCESS
+};
+
 /* We need one default form to support our default printer. Msoft adds the
 forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
 array index). Letter is always first, so (for the current code) additions
@@ -135,6 +144,7 @@ int write_ntforms(nt_forms_struct **list, int number)
                               (*list)[i].bottom);
                if (len > sizeof(buf)) break;
                slprintf(key, sizeof(key), "%s%s", FORMS_PREFIX, (*list)[i].name);
+        dos_to_unix(key, True);            /* Convert key to unix-codepage */
                kbuf.dsize = strlen(key)+1;
                kbuf.dptr = key;
                dbuf.dsize = len;
@@ -226,6 +236,7 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32
        }
 
        slprintf(key, sizeof(key), "%s%s", FORMS_PREFIX, (*list)[n].name);
+       dos_to_unix(key, True);                /* Convert key to unix-codepage */
        kbuf.dsize = strlen(key)+1;
        kbuf.dptr = key;
        if (tdb_delete(tdb, kbuf) != 0) {
@@ -1292,27 +1303,41 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
 
        slprintf(directory, sizeof(directory), "\\print$\\%s\\%d\\", architecture, driver->cversion);
 
-       
-       fstrcpy(temp_name, driver->driverpath);
-       slprintf(driver->driverpath, sizeof(driver->driverpath), "%s%s", directory, temp_name);
+    /* .inf files do not always list a file for each of the four standard files. 
+     * Don't prepend a path to a null filename, or client claims:
+     *   "The server on which the printer resides does not have a suitable 
+     *   <printer driver name> printer driver installed. Click OK if you 
+     *   wish to install the driver on your local machine."
+     */
+       if (strlen(driver->driverpath)) {
+       fstrcpy(temp_name, driver->driverpath);
+       slprintf(driver->driverpath, sizeof(driver->driverpath), "%s%s", directory, temp_name);
+    }
 
-       fstrcpy(temp_name, driver->datafile);
-       slprintf(driver->datafile, sizeof(driver->datafile), "%s%s", directory, temp_name);
+       if (strlen(driver->datafile)) {
+       fstrcpy(temp_name, driver->datafile);
+       slprintf(driver->datafile, sizeof(driver->datafile), "%s%s", directory, temp_name);
+    }
 
-       fstrcpy(temp_name, driver->configfile);
-       slprintf(driver->configfile, sizeof(driver->configfile), "%s%s", directory, temp_name);
+       if (strlen(driver->configfile)) {
+       fstrcpy(temp_name, driver->configfile);
+       slprintf(driver->configfile, sizeof(driver->configfile), "%s%s", directory, temp_name);
+    }
 
-       fstrcpy(temp_name, driver->helpfile);
-       slprintf(driver->helpfile, sizeof(driver->helpfile), "%s%s", directory, temp_name);
+       if (strlen(driver->helpfile)) {
+       fstrcpy(temp_name, driver->helpfile);
+       slprintf(driver->helpfile, sizeof(driver->helpfile), "%s%s", directory, temp_name);
+    }
 
        if (driver->dependentfiles) {
                for (i=0; *driver->dependentfiles[i]; i++) {
-                       fstrcpy(temp_name, driver->dependentfiles[i]);
-                       slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i]), "%s%s", directory, temp_name);
+            fstrcpy(temp_name, driver->dependentfiles[i]);
+            slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i]), "%s%s", directory, temp_name);
                }
        }
 
        slprintf(key, sizeof(key), "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
+       dos_to_unix(key, True);                /* Convert key to unix-codepage */
 
        DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
 
@@ -1676,8 +1701,8 @@ uint32 del_a_printer(char *sharename)
        pstring key;
        TDB_DATA kbuf;
 
-       slprintf(key, sizeof(key), "%s%s",
-                PRINTERS_PREFIX, sharename);
+       slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, sharename);
+       dos_to_unix(key, True);                /* Convert key to unix-codepage */
 
        kbuf.dptr=key;
        kbuf.dsize=strlen(key)+1;
@@ -1759,8 +1784,8 @@ static uint32 update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
        }
        
 
-       slprintf(key, sizeof(key), "%s%s",
-                PRINTERS_PREFIX, info->sharename);
+       slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, info->sharename);
+       dos_to_unix(key, True);                /* Convert key to unix-codepage */
 
        kbuf.dptr = key;
        kbuf.dsize = strlen(key)+1;
@@ -2067,6 +2092,11 @@ static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
                 */
                len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
                devmode.driverextra=(uint16)extra_len;
+               
+               /* check to catch an invalid TDB entry so we don't segfault */
+               if (devmode.driverextra == 0) {
+                       devmode.private = NULL;
+               }
        }
 
        *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
@@ -2182,6 +2212,7 @@ static uint32 get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
        ZERO_STRUCT(info);
 
        slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, sharename);
+       dos_to_unix(key, True);                /* Convert key to unix-codepage */
 
        kbuf.dptr = key;
        kbuf.dsize = strlen(key)+1;
@@ -2748,7 +2779,7 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
 
 static SEC_DESC_BUF *construct_default_printer_sdb(void)
 {
-       SEC_ACE ace[2];
+       SEC_ACE ace[3];
        SEC_ACCESS sa;
        SEC_ACL *psa = NULL;
        SEC_DESC_BUF *sdb = NULL;
@@ -2763,7 +2794,6 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
        init_sec_ace(&ace[0], &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. */
 
@@ -2783,8 +2813,13 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
                }
        }
 
-       init_sec_access(&sa, PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT);
+       init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
        init_sec_ace(&ace[1], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    sa, SEC_ACE_FLAG_OBJECT_INHERIT |
+                    SEC_ACE_FLAG_INHERIT_ONLY);
+
+       init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
+       init_sec_ace(&ace[2], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
                     sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
 
        /* The ACL revision number in rpc_secdesc.h differs from the one
@@ -2794,7 +2829,7 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
 
 #define NT4_ACL_REVISION 0x2
 
-       if ((psa = make_sec_acl(NT4_ACL_REVISION, 2, ace)) != NULL) {
+       if ((psa = make_sec_acl(NT4_ACL_REVISION, 3, ace)) != NULL) {
                psd = make_sec_desc(SEC_DESC_REVISION,
                                    &owner_sid, NULL,
                                    NULL, psa, &sd_size);
@@ -2824,11 +2859,16 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr)
        prs_struct ps;
        TALLOC_CTX *mem_ctx = NULL;
        fstring key;
+       char *temp;
 
        mem_ctx = talloc_init();
        if (mem_ctx == NULL)
                return False;
 
+       if ((temp = strchr(printername + 2, '\\'))) {
+               printername = temp + 1;
+       }
+
        /* Fetch security descriptor from tdb */
 
        slprintf(key, sizeof(key), "SECDESC/%s", printername);
@@ -2901,8 +2941,9 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr)
 
                        sid_to_string(sid_str, &acl->ace[i].sid);
 
-                       DEBUG(10, ("%s 0x%08x\n", sid_str, 
-                                 acl->ace[i].info.mask));
+                       DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
+                                  acl->ace[i].type, acl->ace[i].flags, 
+                                  acl->ace[i].info.mask)); 
                }
        }
 
@@ -2947,6 +2988,20 @@ jfm: I should use this comment for the text file to explain
 
 */
 
+/* Convert generic access rights to printer object specific access rights.
+   It turns out that NT4 security descriptors use generic access rights and
+   NT5 the object specific ones. */
+
+void map_printer_permissions(SEC_DESC *sd)
+{
+       int i;
+
+       for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
+               se_map_generic(&sd->dacl->ace[i].info.mask,
+                              &printer_generic_mapping);
+       }
+}
+
 /****************************************************************************
  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
@@ -2960,7 +3015,7 @@ jfm: I should use this comment for the text file to explain
    PRINTER_ACCESS_USE:
        print_job_start
 
-   JOB_ACCESS_ADMINISTER:
+   PRINTER_ACCESS_ADMINISTER (should really be JOB_ACCESS_ADMINISTER):
        print_job_delete, print_job_pause, print_job_resume,
        print_queue_purge
 
@@ -2968,10 +3023,9 @@ jfm: I should use this comment for the text file to explain
 BOOL print_access_check(struct current_user *user, int snum, int access_type)
 {
        SEC_DESC_BUF *secdesc = NULL;
-       uint32 access_granted, status, required_access = 0;
+       uint32 access_granted, status;
        BOOL result;
        char *pname;
-       int i;
        extern struct current_user current_user;
        
        /* If user is NULL then use the current_user structure */
@@ -3000,93 +3054,14 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
        /* Get printer security descriptor */
 
        nt_printing_getsec(pname, &secdesc);
+       
+       map_printer_permissions(secdesc->sec);
 
-       /* 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;
-               break;
-       default:
-               DEBUG(0, ("invalid value passed to print_access_check()\n"));
-               result = False;
-               goto done;
-       }       
-
-       /* 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
-          values, i.e PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT.
-          This would cause the access check to simply fall out when we
-          check against any subset of these bits.  To get things to work,
-          change every ACE mask of PRINTER_ACE_FULL_CONTROL to
-          PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT before
-          performing the access check.  I'm sure there is a better way to
-          do this! */
-
-       if (secdesc && secdesc->sec && secdesc->sec->dacl &&
-           secdesc->sec->dacl->ace) {
-               for(i = 0; i < secdesc->sec->dacl->num_aces; i++) {
-                       if (secdesc->sec->dacl->ace[i].info.mask ==
-                           PRINTER_ACE_FULL_CONTROL) {
-                               secdesc->sec->dacl->ace[i].info.mask =
-                                       PRINTER_ACE_MANAGE_DOCUMENTS |
-                                       PRINTER_ACE_PRINT;
-                       }
-               }
-       }
-
-       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,
+       result = se_access_check(secdesc->sec, user, access_type,
                                 &access_granted, &status);
 
        /* Check access */
        
- done:
        DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
        
        /* Free mallocated memory */