r14634: Many bug fixes thanks to train rides and overnight stays in airports
authorGerald Carter <jerry@samba.org>
Wed, 22 Mar 2006 08:04:13 +0000 (08:04 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:15:41 +0000 (11:15 -0500)
* Finally fix parsing idmap uid/gid ranges not to break with spaces
  surrounding the '-'
* Allow local groups to renamed by adding info level 2 to
  _samr_set_aliasinfo()
* Fix parsing bug in _samr_del_dom_alias() reply
* Prevent root from being deleted via Samba
* Prevent builting groups from being renamed or deleted
* Fix bug in pdb_tdb that broke renaming user accounts
* Make sure winbindd is running when trying to create the Administrators
  and Users BUILTIN groups automatically from smbd (and not just check the
  winbind nexted groups parameter value).
* Have the top level rid allocator verify that the RID it is about to
  grant is not already assigned in our own SAM (retries up to 250 times).
  This fixes passdb with existing SIDs assigned to users from the RID algorithm
  but not monotonically allocating the RIDs from passdb.
(This used to be commit db1162241f79c2af8afb7d8c26e8ed1c4a4b476f)

source3/auth/auth_util.c
source3/groupdb/mapping.c
source3/include/rpc_samr.h
source3/param/loadparm.c
source3/passdb/pdb_interface.c
source3/passdb/pdb_tdb.c
source3/rpc_parse/parse_samr.c
source3/rpc_server/srv_samr_nt.c

index 2ece2a61507351418f01caae8dad53886059d2c6..31bc2664b88a660a702fe28aafb95fc255f11014 100644 (file)
@@ -834,7 +834,7 @@ static struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
                /* We can only create a mapping if winbind is running 
                   and the nested group functionality has been enabled */
                   
-               if ( lp_winbind_nested_groups() ) {
+               if ( lp_winbind_nested_groups() && winbind_ping() ) {
                        become_root();
                        status = create_builtin_administrators( );
                        if ( !NT_STATUS_IS_OK(status) ) {
@@ -860,7 +860,7 @@ static struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
                /* We can only create a mapping if winbind is running 
                   and the nested group functionality has been enabled */
                   
-               if ( lp_winbind_nested_groups() ) {
+               if ( lp_winbind_nested_groups() && winbind_ping() ) {
                        become_root();
                        status = create_builtin_users( );
                        if ( !NT_STATUS_IS_OK(status) ) {
index 830584979b5e4708e4f6dc6f723c61b451d985e4..5569dbf4ed5f116930b341c71a2e8bab47345677 100644 (file)
@@ -1164,6 +1164,7 @@ NTSTATUS pdb_default_set_aliasinfo(struct pdb_methods *methods,
        if (!pdb_getgrsid(&map, *sid))
                return NT_STATUS_NO_SUCH_ALIAS;
 
+       fstrcpy(map.nt_name, info->acct_name);
        fstrcpy(map.comment, info->acct_desc);
 
        return pdb_update_group_mapping_entry(&map);
index ccb4fc9e4405d8af232d20e9219376b4711493d4..8a3c4a84208096da9957d4537e5515dedbfb3fdb 100644 (file)
@@ -1203,6 +1203,10 @@ typedef struct {
        uint32 num_member;
 } ALIAS_INFO1;
 
+typedef struct {
+       UNISTR4 name;
+} ALIAS_INFO2;
+
 typedef struct {
        UNISTR4 description;
 } ALIAS_INFO3;
@@ -1216,6 +1220,7 @@ typedef struct {
        uint16 level;
        union {
                ALIAS_INFO1 info1;
+               ALIAS_INFO2 info2;
                ALIAS_INFO3 info3;
        } alias;
 } ALIAS_INFO_CTR;
index 7b831d1e98db7c148a759d6748a5157bd1092cbe..0bde5805b07cbbbb26868f9089cc2acd8b448dc5 100644 (file)
@@ -3212,7 +3212,7 @@ static BOOL handle_idmap_uid(int snum, const char *pszParmValue, char **ptr)
 {
        uint32 low, high;
 
-       if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
+       if (sscanf(pszParmValue, "%u - %u", &low, &high) != 2 || high < low)
                return False;
 
        /* Parse OK */
@@ -3229,7 +3229,7 @@ static BOOL handle_idmap_gid(int snum, const char *pszParmValue, char **ptr)
 {
        uint32 low, high;
 
-       if (sscanf(pszParmValue, "%u-%u", &low, &high) != 2 || high < low)
+       if (sscanf(pszParmValue, "%u - %u", &low, &high) != 2 || high < low)
                return False;
 
        /* Parse OK */
index 7ff0214c72483106073b412135d720ead69b2659..5fdc8ac819ba1040573bc80630c14415b637bdb6 100644 (file)
@@ -426,6 +426,13 @@ static int smb_delete_user(const char *unix_user)
        pstring del_script;
        int ret;
 
+       /* safety check */
+
+       if ( strequal( unix_user, "root" ) ) {
+               DEBUG(0,("smb_delete_user: Refusing to delete local system root account!\n"));
+               return -1;
+       }
+
        pstrcpy(del_script, lp_deluser_script());
        if (! *del_script)
                return -1;
@@ -462,11 +469,22 @@ static NTSTATUS pdb_default_delete_user(struct pdb_methods *methods,
 NTSTATUS pdb_delete_user(TALLOC_CTX *mem_ctx, struct samu *sam_acct)
 {
        struct pdb_methods *pdb = pdb_get_methods();
+       uid_t uid = -1;
 
        if ( !pdb ) {
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       /* sanity check to make sure we don't delete root */
+
+       if ( !sid_to_uid( pdb_get_user_sid(sam_acct), &uid ) ) {
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+       if ( uid == 0 ) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        return pdb->delete_user(pdb, mem_ctx, sam_acct);
 }
 
@@ -516,6 +534,7 @@ NTSTATUS pdb_delete_sam_account(struct samu *sam_acct)
 NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname)
 {
        struct pdb_methods *pdb = pdb_get_methods();
+       uid_t uid;
 
        if ( !pdb ) {
                return NT_STATUS_NOT_IMPLEMENTED;
@@ -526,6 +545,16 @@ NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname)
                csamuser = NULL;
        }
 
+       /* sanity check to make sure we don't rename root */
+
+       if ( !sid_to_uid( pdb_get_user_sid(oldname), &uid ) ) {
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+       if ( uid == 0 ) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        return pdb->rename_sam_account(pdb, oldname, newname);
 }
 
@@ -976,8 +1005,7 @@ BOOL pdb_find_alias(const char *name, DOM_SID *sid)
                return False;
        }
 
-       return NT_STATUS_IS_OK(pdb->find_alias(pdb,
-                                                            name, sid));
+       return NT_STATUS_IS_OK(pdb->find_alias(pdb, name, sid));
 }
 
 NTSTATUS pdb_create_alias(const char *name, uint32 *rid)
@@ -999,8 +1027,7 @@ BOOL pdb_delete_alias(const DOM_SID *sid)
                return False;
        }
 
-       return NT_STATUS_IS_OK(pdb->delete_alias(pdb,
-                                                            sid));
+       return NT_STATUS_IS_OK(pdb->delete_alias(pdb, sid));
                                                            
 }
 
@@ -1012,8 +1039,7 @@ BOOL pdb_get_aliasinfo(const DOM_SID *sid, struct acct_info *info)
                return False;
        }
 
-       return NT_STATUS_IS_OK(pdb->get_aliasinfo(pdb, sid,
-                                                             info));
+       return NT_STATUS_IS_OK(pdb->get_aliasinfo(pdb, sid, info));
 }
 
 BOOL pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info)
@@ -1024,8 +1050,7 @@ BOOL pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info)
                return False;
        }
 
-       return NT_STATUS_IS_OK(pdb->set_aliasinfo(pdb, sid,
-                                                             info));
+       return NT_STATUS_IS_OK(pdb->set_aliasinfo(pdb, sid, info));
 }
 
 NTSTATUS pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member)
@@ -1192,9 +1217,21 @@ BOOL pdb_rid_algorithm(void)
        return pdb->rid_algorithm(pdb);
 }
 
+/********************************************************************
+ Allocate a new RID from the passdb backend.  Verify that it is free
+ by calling lookup_global_sam_rid() to verify that the RID is not
+ in use.  This handles servers that have existing users or groups
+ with add RIDs (assigned from previous algorithmic mappings)
+********************************************************************/
+
 BOOL pdb_new_rid(uint32 *rid)
 {
        struct pdb_methods *pdb = pdb_get_methods();
+       const char *name = NULL;
+       enum SID_NAME_USE type;
+       uint32 allocated_rid = 0;
+       int i;
+       TALLOC_CTX *ctx;
 
        if ( !pdb ) {
                return False;
@@ -1215,7 +1252,38 @@ BOOL pdb_new_rid(uint32 *rid)
                return False;
        }
 
-       return pdb->new_rid(pdb, rid);
+       if ( (ctx = talloc_init("pdb_new_rid")) == NULL ) {
+               DEBUG(0,("pdb_new_rid: Talloc initialization failure\n"));
+               return False;
+       }
+
+       /* Attempt to get an unused RID (max tires is 250...yes that it is 
+          and arbitrary number I pulkled out of my head).   -- jerry */
+
+       for ( i=0; allocated_rid==0 && i<250; i++ ) {
+               /* get a new RID */
+
+               if ( !pdb->new_rid(pdb, &allocated_rid) ) {
+                       return False;
+               }
+
+               /* validate that the RID is not in use */
+
+               if ( lookup_global_sam_rid( ctx, allocated_rid, &name, &type, NULL ) ) {
+                       allocated_rid = 0;
+               }
+       }
+
+       TALLOC_FREE( ctx );
+
+       if ( allocated_rid == 0 ) {
+               DEBUG(0,("pdb_new_rid: Failed to find unused RID\n"));
+               return False;
+       }
+
+       *rid = allocated_rid;
+
+       return True;
 }
 
 /***************************************************************
index b7161ff589dfba1d3ead7e8eccfcfefa5a49f902..94ae32881238cc5c6f4a3fdd1e51b177427b3a8a 100644 (file)
@@ -1382,19 +1382,12 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
        BOOL             interim_account = False;
        int              rename_ret;
 
-       /* make sure we have an open handle to the tdb.  Should have happened 
-          at module  initialization time */
-          
-       if ( !tdbsam ) {
-               DEBUG(0,("tdbsam_getsampwrid: tdbsam not open!\n"));
-               return NT_STATUS_NO_SUCH_USER;
-       }
-       
        /* can't do anything without an external script */
        
        pstrcpy(rename_script, lp_renameuser_script() );
-       if ( ! *rename_script )
+       if ( ! *rename_script ) {
                return NT_STATUS_ACCESS_DENIED;
+       }
 
        /* invalidate the existing TDB iterator if it is open */
        
@@ -1421,8 +1414,7 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
 
        /* add the new account and lock it */
        
-       if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) 
-       {
+       if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
                goto done;
        }
        
@@ -1441,13 +1433,15 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
 
        DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
 
-       if (rename_ret) 
+       if (rename_ret) {
                goto done; 
+       }
 
        /* rewrite the rid->username record */
        
-       if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) )
+       if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
                goto done;
+       }
        interim_account = False;
        tdb_unlock_bystring( tdbsam, newname );
 
index 2f8fe74ed3a3ef2a97aa84e092066886b9108c10..2a9daa0e479135008ce12cd40fe8ddfcf4e38d64 100644 (file)
@@ -3554,6 +3554,28 @@ BOOL samr_io_alias_info3(const char *desc, ALIAS_INFO3 *al3,
 reads or writes a structure.
 ********************************************************************/
 
+BOOL samr_io_alias_info2(const char *desc, ALIAS_INFO2 *al2,
+                        prs_struct *ps, int depth)
+{
+       if (al2 == NULL)
+               return False;
+
+       prs_debug(ps, depth, desc, "samr_io_alias_info2");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;
+
+       if (!prs_unistr4("name", ps, depth, &al2->name))
+               return False;
+
+       return True;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+
 BOOL samr_alias_info_ctr(const char *desc, prs_struct *ps, int depth, ALIAS_INFO_CTR * ctr)
 {
        if ( !ctr )
@@ -3572,6 +3594,10 @@ BOOL samr_alias_info_ctr(const char *desc, prs_struct *ps, int depth, ALIAS_INFO
                if(!samr_io_alias_info1("alias_info1", &ctr->alias.info1, ps, depth))
                        return False;
                break;
+       case 2: 
+               if(!samr_io_alias_info2("alias_info2", &ctr->alias.info2, ps, depth))
+                       return False;
+               break;
        case 3: 
                if(!samr_io_alias_info3("alias_info3", &ctr->alias.info3, ps, depth))
                        return False;
@@ -4474,6 +4500,9 @@ BOOL samr_io_r_delete_dom_alias(const char *desc, SAMR_R_DELETE_DOM_ALIAS * r_u,
        if(!prs_align(ps))
                return False;
 
+       if(!smb_io_pol_hnd("pol", &r_u->pol, ps, depth))
+               return False;
+
        if(!prs_ntstatus("status", ps, depth, &r_u->status))
                return False;
 
index 6a4c9f7133af10214336f491e9eb7f23aada19c3..dc179770411c33096507fea186c366569dc35230 100644 (file)
@@ -3464,9 +3464,14 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_
        if (!get_lsa_policy_samr_sid(p, pol, &sid, &acc_granted, &disp_info))
                return NT_STATUS_INVALID_HANDLE;
 
-       /* observed when joining XP client to Samba domain */
                
+#if 0  /* this really should be applied on a per info level basis   --jerry */
+
+       /* observed when joining XP client to Samba domain */
        acc_required = SA_RIGHT_USER_SET_PASSWORD | SA_RIGHT_USER_SET_ATTRIBUTES | SA_RIGHT_USER_ACCT_FLAGS_EXPIRY;
+#else
+       acc_required = SA_RIGHT_USER_SET_ATTRIBUTES;
+#endif
        
        if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, acc_required, "_samr_set_userinfo2"))) {
                return r_u->status;
@@ -4093,12 +4098,22 @@ NTSTATUS _samr_delete_dom_alias(pipes_struct *p, SAMR_Q_DELETE_DOM_ALIAS *q_u, S
        if (!get_lsa_policy_samr_sid(p, &q_u->alias_pol, &alias_sid, &acc_granted, &disp_info)) 
                return NT_STATUS_INVALID_HANDLE;
        
+       /* copy the handle to the outgoing reply */
+
+       memcpy( &r_u->pol, &q_u->alias_pol, sizeof(r_u->pol) );
+
        if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, STD_RIGHT_DELETE_ACCESS, "_samr_delete_dom_alias"))) {
                return r_u->status;
        }
 
        DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid)));
 
+       /* Don't let Windows delete builtin groups */
+
+       if ( sid_check_is_in_builtin( &alias_sid ) ) {
+               return NT_STATUS_SPECIAL_ACCOUNT;
+       }
+
        if (!sid_check_is_in_our_domain(&alias_sid))
                return NT_STATUS_NO_SUCH_ALIAS;
                
@@ -4453,7 +4468,30 @@ NTSTATUS _samr_set_aliasinfo(pipes_struct *p, SAMR_Q_SET_ALIASINFO *q_u, SAMR_R_
                
        ctr=&q_u->ctr;
 
+       /* get the current group information */
+
+       if ( !pdb_get_aliasinfo( &group_sid, &info ) ) {
+               return NT_STATUS_NO_SUCH_ALIAS;
+       }
+
        switch (ctr->level) {
+               case 2:
+                       /* We currently do not support renaming groups in the
+                          the BUILTIN domain.  Refer to util_builtin.c to understand 
+                          why.  The eventually needs to be fixed to be like Windows
+                          where you can rename builtin groups, just not delete them */
+
+                       if ( sid_check_is_in_builtin( &group_sid ) ) {
+                               return NT_STATUS_SPECIAL_ACCOUNT;
+                       }
+
+                       if ( ctr->alias.info2.name.string ) {
+                               unistr2_to_ascii( info.acct_name, ctr->alias.info2.name.string, 
+                                       sizeof(info.acct_name)-1 );
+                       }
+                       else
+                               fstrcpy( info.acct_name, "" );
+                       break;
                case 3:
                        if ( ctr->alias.info3.description.string ) {
                                unistr2_to_ascii( info.acct_desc,