r4805: Last planned change to the privileges infrastructure:
[samba.git] / source3 / printing / nt_printing.c
index 14c0417f7765bfdaddb939860135a19b14356b89..d22ec935a39cc737990614784aad31879581487a 100644 (file)
@@ -531,7 +531,7 @@ int get_ntforms(nt_forms_struct **list)
                if (ret != dbuf.dsize) 
                        continue;
 
-               tl = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
+               tl = SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1);
                if (!tl) {
                        DEBUG(0,("get_ntforms: Realloc fail.\n"));
                        return 0;
@@ -593,15 +593,14 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
        
        unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
        for (n=0; n<*count; n++) {
-               if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
-                       DEBUG(103, ("NT workaround, [%s] already exists\n", form_name));
+               if ( strequal((*list)[n].name, form_name) ) {
                        update=True;
                        break;
                }
        }
 
        if (update==False) {
-               if((tl=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL) {
+               if((tl=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) {
                        DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
                        return False;
                }
@@ -618,6 +617,9 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
        (*list)[n].right=form->right;
        (*list)[n].bottom=form->bottom;
 
+       DEBUG(6,("add_a_form: Successfully %s form [%s]\n", 
+               update ? "updated" : "added", form_name));
+
        return True;
 }
 
@@ -710,7 +712,7 @@ int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
                if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
                        continue;
                
-               if((fl = Realloc(*list, sizeof(fstring)*(total+1))) == NULL) {
+               if((fl = SMB_REALLOC_ARRAY(*list, fstring, total+1)) == NULL) {
                        DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
                        return -1;
                }
@@ -766,7 +768,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
        char    *buf = NULL;
        ssize_t byte_count;
 
-       if ((buf=malloc(PE_HEADER_SIZE)) == NULL) {
+       if ((buf=SMB_MALLOC(PE_HEADER_SIZE)) == NULL) {
                DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
                                fname, PE_HEADER_SIZE));
                goto error_exit;
@@ -822,7 +824,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
                        goto error_exit;
 
                SAFE_FREE(buf);
-               if ((buf=malloc(section_table_bytes)) == NULL) {
+               if ((buf=SMB_MALLOC(section_table_bytes)) == NULL) {
                        DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
                                        fname, section_table_bytes));
                        goto error_exit;
@@ -846,7 +848,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
                                        goto error_exit;
 
                                SAFE_FREE(buf);
-                               if ((buf=malloc(section_bytes)) == NULL) {
+                               if ((buf=SMB_MALLOC(section_bytes)) == NULL) {
                                        DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
                                                        fname, section_bytes));
                                        goto error_exit;
@@ -906,7 +908,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
 
                /* Allocate a bit more space to speed up things */
                SAFE_FREE(buf);
-               if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) {
+               if ((buf=SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
                        DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes  = %d\n",
                                        fname, PE_HEADER_SIZE));
                        goto error_exit;
@@ -1728,7 +1730,7 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
        if (len != buflen) {
                char *tb;
 
-               tb = (char *)Realloc(buf, len);
+               tb = (char *)SMB_REALLOC(buf, len);
                if (!tb) {
                        DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
                        ret = -1;
@@ -1793,7 +1795,7 @@ static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **in
        fstrcpy(info.configfile, "");
        fstrcpy(info.helpfile, "");
 
-       if ((info.dependentfiles=(fstring *)malloc(2*sizeof(fstring))) == NULL)
+       if ((info.dependentfiles= SMB_MALLOC_ARRAY(fstring, 2)) == NULL)
                return WERR_NOMEM;
 
        memset(info.dependentfiles, '\0', 2*sizeof(fstring));
@@ -1850,8 +1852,7 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
        while (len < dbuf.dsize) {
                fstring *tddfs;
 
-               tddfs = (fstring *)Realloc(driver.dependentfiles,
-                                                        sizeof(fstring)*(i+2));
+               tddfs = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2);
                if (tddfs == NULL) {
                        DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
                        break;
@@ -2045,17 +2046,32 @@ static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
  handles are not affected.
 ****************************************************************************/
 
-uint32 del_a_printer(char *sharename)
+uint32 del_a_printer(const char *sharename)
 {
        pstring key;
        TDB_DATA kbuf;
+       pstring printdb_path;
 
        slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
-
        kbuf.dptr=key;
        kbuf.dsize=strlen(key)+1;
+       tdb_delete(tdb_printers, kbuf);
 
+       slprintf(key, sizeof(key)-1, "%s%s", SECDESC_PREFIX, sharename);
+       kbuf.dptr=key;
+       kbuf.dsize=strlen(key)+1;
        tdb_delete(tdb_printers, kbuf);
+
+       close_all_print_db();
+
+       if (geteuid() == 0) {
+               pstrcpy(printdb_path, lock_path("printing/"));
+               pstrcat(printdb_path, sharename);
+               pstrcat(printdb_path, ".tdb");
+
+               unlink(printdb_path);
+       }
+
        return 0;
 }
 
@@ -2133,7 +2149,7 @@ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
        if (buflen != len) {
                char *tb;
 
-               tb = (char *)Realloc(buf, len);
+               tb = (char *)SMB_REALLOC(buf, len);
                if (!tb) {
                        DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
                        ret = WERR_NOMEM;
@@ -2175,7 +2191,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
 {
 
        char adevice[MAXDEVICENAME];
-       NT_DEVICEMODE *nt_devmode = (NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE));
+       NT_DEVICEMODE *nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE);
 
        if (nt_devmode == NULL) {
                DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
@@ -2184,7 +2200,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
 
        ZERO_STRUCTP(nt_devmode);
 
-       safe_strcpy(adevice, default_devicename, sizeof(adevice)-1);
+       slprintf(adevice, sizeof(adevice), "%s", default_devicename);
        fstrcpy(nt_devmode->devicename, adevice);       
        
        fstrcpy(nt_devmode->formname, "Letter");
@@ -2395,7 +2411,7 @@ static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
        
        /* allocate another slot in the NT_PRINTER_KEY array */
        
-       d = Realloc( data->keys, sizeof(NT_PRINTER_KEY)*(data->num_keys+1) );
+       d = SMB_REALLOC_ARRAY( data->keys, NT_PRINTER_KEY, data->num_keys+1);
        if ( d )
                data->keys = d;
        
@@ -2404,7 +2420,7 @@ static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
        /* initialze new key */
        
        data->num_keys++;
-       data->keys[key_index].name = strdup( name );
+       data->keys[key_index].name = SMB_STRDUP( name );
        
        ZERO_STRUCTP( &data->keys[key_index].values );
        
@@ -2487,7 +2503,7 @@ uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **su
 
                        /* found a match, so allocate space and copy the name */
                        
-                       if ( !(ptr = Realloc( subkeys_ptr, (num_subkeys+2)*sizeof(fstring))) ) {
+                       if ( !(ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
                                DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n", 
                                        num_subkeys+1));
                                SAFE_FREE( subkeys );
@@ -2550,9 +2566,14 @@ static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
 
        /* a multi-sz has to have a null string terminator, i.e., the last
           string must be followed by two nulls */
-       str_size = (strlen(multi_sz) + 2) * sizeof(smb_ucs2_t);
-       conv_strs = calloc(str_size, 1);
+       str_size = strlen(multi_sz) + 2;
+       conv_strs = SMB_CALLOC_ARRAY(smb_ucs2_t, str_size);
+       if (!conv_strs) {
+               return;
+       }
 
+       /* Change to byte units. */
+       str_size *= sizeof(smb_ucs2_t);
        push_ucs2(NULL, conv_strs, multi_sz, str_size, 
                  STR_TERMINATE | STR_NOALIGN);
 
@@ -2707,9 +2728,12 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
                    printer->info_2->sharename);
 
        /* publish it */
-       ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
-       if (LDAP_ALREADY_EXISTS == ads_rc.err.rc)
-               ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
+       ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
+       if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT)
+               ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
+
+       if (!ADS_ERR_OK(ads_rc))
+               DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc)));
        
        talloc_destroy(ctx);
 
@@ -2831,11 +2855,9 @@ WERROR check_published_printers(void)
 {
        ADS_STATUS ads_rc;
        ADS_STRUCT *ads = NULL;
-       void *res = NULL;
        int snum;
        int n_services = lp_numservices();
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       WERROR win_rc;
 
        ads = ads_init(NULL, NULL, NULL);
        if (!ads) {
@@ -2859,27 +2881,12 @@ WERROR check_published_printers(void)
                if (!(lp_snum_ok(snum) && lp_print_ok(snum)))
                        continue;
 
-               if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2,
-                                                lp_servicename(snum))) ||
-                   !(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
-                       goto next;
-
-               DEBUG(5, ("checking directory for printer %s\n", printer->info_2->printername));
-               ads_rc = ads_find_printer_on_server(ads, &res,
-                               printer->info_2->sharename, global_myname());
-               if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
-                       DEBUG(5, ("printer %s is in directory\n", printer->info_2->printername));
-                       goto next;
-               }
+               if (W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2,
+                                               lp_servicename(snum))) &&
+                   (printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
+                       nt_printer_publish_ads(ads, printer);
 
-               win_rc = nt_printer_publish_ads(ads, printer);
-               if (!W_ERROR_IS_OK(win_rc))
-                       DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, dos_errstr(win_rc)));
-
-       next:
                free_a_printer(&printer, 2);
-               ads_msgfree(ads, res);
-               res = NULL;
        }
 
        ads_destroy(&ads);
@@ -2907,7 +2914,8 @@ BOOL is_printer_published(Printer_entry *print_hnd, int snum,
                return False;
        }
 
-       if (regval_size(guid_val) == sizeof(struct uuid))
+       /* fetching printer guids really ought to be a separate function.. */
+       if (guid && regval_size(guid_val) == sizeof(struct uuid))
                memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid));
 
        free_a_printer(&printer, 2);
@@ -3357,7 +3365,8 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *se
 {
        pstring key;
        NT_PRINTER_INFO_LEVEL_2 info;
-       int             len = 0;
+       int len = 0;
+       int snum = lp_servicenumber(sharename);
        TDB_DATA kbuf, dbuf;
        fstring printername;
        char adevice[MAXDEVICENAME];
@@ -3403,7 +3412,12 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *se
 
        /* Restore the stripped strings. */
        slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", servername);
-       slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info.printername);
+
+       if ( lp_force_printername(snum) )
+               slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, sharename );
+       else 
+               slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info.printername);
+
        fstrcpy(info.printername, printername);
 
        len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
@@ -3416,13 +3430,13 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *se
         * See comments in get_a_printer_2_default()
         */
 
-       if (lp_default_devmode(lp_servicenumber(sharename)) && !info.devmode) {
+       if (lp_default_devmode(snum) && !info.devmode) {
                DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
                        printername));
                info.devmode = construct_nt_devicemode(printername);
        }
 
-       safe_strcpy(adevice, info.printername, sizeof(adevice)-1);
+       slprintf( adevice, sizeof(adevice), "%s", info.printername );
        if (info.devmode) {
                fstrcpy(info.devmode->devicename, adevice);     
        }
@@ -3781,7 +3795,7 @@ static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
        if (buflen < len) {
                char *tb;
 
-               tb = (char *)Realloc(buf, len);
+               tb = (char *)SMB_REALLOC(buf, len);
                if (!tb) {
                        DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
                        ret = -1;
@@ -3905,7 +3919,7 @@ static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, ui
                if ((ctx = talloc_init("save_driver_init_2")) == NULL)
                        return WERR_NOMEM;
 
-               if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
+               if ((nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE)) == NULL) {
                        status = WERR_NOMEM;
                        goto done;
                }
@@ -4022,7 +4036,7 @@ NT_PRINTER_INFO_LEVEL_2* dup_printer_2( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2
        if ( !printer )
                return NULL;
        
-       if ( !(copy = (NT_PRINTER_INFO_LEVEL_2 *)malloc(sizeof(NT_PRINTER_INFO_LEVEL_2))) )
+       if ( !(copy = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL_2)) )
                return NULL;
                
        memcpy( copy, printer, sizeof(NT_PRINTER_INFO_LEVEL_2) );
@@ -4070,7 +4084,7 @@ WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_print
 
        switch (level) {
                case 2:
-                       if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
+                       if ((printer = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL)) == NULL) {
                                DEBUG(0,("get_a_printer: malloc fail.\n"));
                                return WERR_NOMEM;
                        }
@@ -4131,7 +4145,7 @@ WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_print
                                /* save a copy in cache */
                                if ( print_hnd && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)) {
                                        if ( !print_hnd->printer_info )
-                                               print_hnd->printer_info = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL));
+                                               print_hnd->printer_info = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL);
 
                                        if ( print_hnd->printer_info ) {
                                                /* make sure to use the handle's talloc ctx here since 
@@ -5020,6 +5034,11 @@ void map_printer_permissions(SEC_DESC *sd)
        print_job_delete, print_job_pause, print_job_resume,
        print_queue_purge
 
+  Try access control in the following order (for performance reasons):
+    1)  root ans SE_PRINT_OPERATOR can do anything (easy check) 
+    2)  check security descriptor (bit comparisons in memory)
+    3)  "printer admins" (may result in numerous calls to winbind)
+
  ****************************************************************************/
 BOOL print_access_check(struct current_user *user, int snum, int access_type)
 {
@@ -5030,16 +5049,16 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
        const char *pname;
        TALLOC_CTX *mem_ctx = NULL;
        extern struct current_user current_user;
+       SE_PRIV se_printop = SE_PRINT_OPERATOR;
        
        /* If user is NULL then use the current_user structure */
 
        if (!user)
                user = &current_user;
 
-       /* Always allow root or printer admins to do anything */
+       /* Always allow root or SE_PRINT_OPERATROR to do anything */
 
-       if (user->uid == 0 ||
-           user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups)) {
+       if ( user->uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) {
                return True;
        }
 
@@ -5088,6 +5107,13 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
 
        DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
 
+        /* see if we need to try the printer admin list */
+
+        if ( access_granted == 0 ) {
+                if ( user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups) )
+                        return True;
+        }
+
        talloc_destroy(mem_ctx);
        
        if (!result)