first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[kai/samba.git] / source3 / passdb / passdb.c
index a4bb657e80ede1bb3ceead9642573d7cb545e004..c0a20f34204c3bc7b3814bd5fa1acc2fe445f89c 100644 (file)
@@ -27,10 +27,13 @@ extern int DEBUGLEVEL;
 
 /*
  * This is set on startup - it defines the SID for this
- * machine.
+ * machine, and therefore the SAM database for which it is
+ * responsible.
  */
 
-DOM_SID global_machine_sid;
+extern DOM_SID global_sam_sid;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
 
 /*
  * NOTE. All these functions are abstracted into a structure
@@ -84,6 +87,15 @@ BOOL initialize_password_db(void)
  * Functions that return/manipulate a struct smb_passwd.
  */
 
+/************************************************************************
+ Utility function to search smb passwd by rid.  
+*************************************************************************/
+
+struct smb_passwd *iterate_getsmbpwrid(uint32 user_rid)
+{
+       return iterate_getsmbpwuid(pdb_user_rid_to_uid(user_rid));
+}
+
 /************************************************************************
  Utility function to search smb passwd by uid.  use this if your database
  does not have search facilities.
@@ -222,6 +234,15 @@ struct smb_passwd *getsmbpwnam(char *name)
        return pdb_ops->getsmbpwnam(name);
 }
 
+/************************************************************************
+ Routine to search smb passwd by user rid.
+*************************************************************************/
+
+struct smb_passwd *getsmbpwrid(uint32 user_rid)
+{
+       return pdb_ops->getsmbpwrid(user_rid);
+}
+
 /************************************************************************
  Routine to search smb passwd by uid.
 *************************************************************************/
@@ -399,7 +420,7 @@ struct sam_passwd *getsam21pwrid(uint32 rid)
 static void pdb_init_dispinfo(struct sam_disp_info *user)
 {
        if (user == NULL) return;
-       bzero(user, sizeof(*user));
+       memset((char *)user, '\0', sizeof(*user));
 }
 
 /*************************************************************
@@ -409,7 +430,7 @@ static void pdb_init_dispinfo(struct sam_disp_info *user)
 void pdb_init_smb(struct smb_passwd *user)
 {
        if (user == NULL) return;
-       bzero(user, sizeof(*user));
+       memset((char *)user, '\0', sizeof(*user));
        user->pass_last_set_time    = (time_t)-1;
 }
 
@@ -419,7 +440,7 @@ void pdb_init_smb(struct smb_passwd *user)
 void pdb_init_sam(struct sam_passwd *user)
 {
        if (user == NULL) return;
-       bzero(user, sizeof(*user));
+       memset((char *)user, '\0', sizeof(*user));
        user->logon_time            = (time_t)-1;
        user->logoff_time           = (time_t)-1;
        user->kickoff_time          = (time_t)-1;
@@ -534,7 +555,7 @@ char *pdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
  15 lines, which is more important.
  **********************************************************/
 
-uint16 pdb_decode_acct_ctrl(char *p)
+uint16 pdb_decode_acct_ctrl(const char *p)
 {
        uint16 acct_ctrl = 0;
        BOOL finished = False;
@@ -577,7 +598,7 @@ uint16 pdb_decode_acct_ctrl(char *p)
  gets password-database-format time from a string.
  ********************************************************************/
 
-static time_t get_time_from_string(char *p)
+static time_t get_time_from_string(const char *p)
 {
        int i;
 
@@ -593,7 +614,7 @@ static time_t get_time_from_string(char *p)
                 * read into a time_t as the seconds since
                 * 1970 that the password was last changed.
                 */
-               return (time_t)strtol((char *)p, NULL, 16);
+               return (time_t)strtol(p, NULL, 16);
        }
        return (time_t)-1;
 }
@@ -602,9 +623,9 @@ static time_t get_time_from_string(char *p)
  gets password last set time
  ********************************************************************/
 
-time_t pdb_get_last_set_time(char *p)
+time_t pdb_get_last_set_time(const char *p)
 {
-       if (*p && StrnCaseCmp((char *)p, "LCT-", 4))
+       if (*p && StrnCaseCmp(p, "LCT-", 4))
        {
                return get_time_from_string(p + 4);
        }
@@ -672,14 +693,14 @@ void pdb_set_last_set_time(char *p, int max_len, time_t t)
 /*************************************************************
  Routine to set 32 hex password characters from a 16 byte array.
 **************************************************************/
-void pdb_sethexpwd(char *p, char *pwd, uint16 acct_ctrl)
+void pdb_sethexpwd(char *p, unsigned char *pwd, uint16 acct_ctrl)
 {
        if (pwd != NULL)
        {
                int i;
                for (i = 0; i < 16; i++)
                {
-                       slprintf(&p[i*2], 33, "%02X", pwd[i]);
+                       slprintf(&p[i*2], 3, "%02X", pwd[i]);
                }
        }
        else
@@ -698,7 +719,7 @@ void pdb_sethexpwd(char *p, char *pwd, uint16 acct_ctrl)
  Routine to get the 32 hex characters and turn them
  into a 16 byte array.
 **************************************************************/
-BOOL pdb_gethexpwd(char *p, char *pwd)
+BOOL pdb_gethexpwd(char *p, unsigned char *pwd)
 {
        int i;
        unsigned char   lonybble, hinybble;
@@ -787,7 +808,7 @@ static BOOL read_sid_from_file(int fd, char *sid_file)
    */
 
   fline[sizeof(fline)-1] = '\0';
-  if(!string_to_sid( &global_machine_sid, fline)) {
+  if(!string_to_sid( &global_sam_sid, fline)) {
     DEBUG(0,("unable to generate machine SID.\n"));
     return False;
   }
@@ -799,14 +820,16 @@ static BOOL read_sid_from_file(int fd, char *sid_file)
  Generate the global machine sid. Look for the MACHINE.SID file first, if
  not found then look in smb.conf and use it to create the MACHINE.SID file.
 ****************************************************************************/
-BOOL pdb_generate_machine_sid(void)
+BOOL pdb_generate_sam_sid(void)
 {
        int fd;
        char *p;
        pstring sid_file;
        fstring sid_string;
        SMB_STRUCT_STAT st;
-       uchar raw_sid_data[12];
+       BOOL overwrite_bad_sid = False;
+
+       generate_wellknown_sids();
 
        pstrcpy(sid_file, lp_smb_passwd_file());
        p = strrchr(sid_file, '/');
@@ -815,7 +838,7 @@ BOOL pdb_generate_machine_sid(void)
        }
 
        if (!directory_exist(sid_file, NULL)) {
-               if (dos_mkdir(sid_file, 0700) != 0) {
+               if (mkdir(sid_file, 0700) != 0) {
                        DEBUG(0,("can't create private directory %s : %s\n",
                                 sid_file, strerror(errno)));
                        return False;
@@ -824,7 +847,7 @@ BOOL pdb_generate_machine_sid(void)
 
        pstrcat(sid_file, "MACHINE.SID");
     
-       if((fd = open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
+       if((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) {
                DEBUG(0,("unable to open or create file %s. Error was %s\n",
                         sid_file, strerror(errno) ));
                return False;
@@ -851,30 +874,54 @@ BOOL pdb_generate_machine_sid(void)
                        close(fd);
                        return False;
                }
-               close(fd);
-               return True;
-       } 
-  
-       /*
-        * The file contains no data - we may need to generate our
-        * own sid. Try the lp_domain_sid() first.
-        */
-       
-       if(*lp_domain_sid())
-               fstrcpy( sid_string, lp_domain_sid());
-       else {
+
                /*
+                * JRA. Reversed the sense of this test now that I have
+                * actually done this test *personally*. One more reason
+                * to never trust third party information you have not
+                * independently verified.... sigh. JRA.
+                */
+
+               if(global_sam_sid.num_auths > 0 && global_sam_sid.sub_auths[0] == 0x21) {
+                       /*
+                        * Fix and re-write...
+                        */
+                       overwrite_bad_sid = True;
+                       global_sam_sid.sub_auths[0] = 21;
+                       DEBUG(5,("pdb_generate_sam_sid: Old (incorrect) sid id_auth of hex 21 \
+detected - re-writing to be decimal 21 instead.\n" ));
+                       sid_to_string(sid_string, &global_sam_sid);
+                       if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) {
+                               DEBUG(0,("unable to seek file file %s. Error was %s\n",
+                                        sid_file, strerror(errno) ));
+                               close(fd);
+                               return False;
+                       }
+               } else {
+                       close(fd);
+                       return True;
+               }
+       } else {
+               /*
+                * The file contains no data - we need to generate our
+                * own sid.
                 * Generate the new sid data & turn it into a string.
                 */
                int i;
+               uchar raw_sid_data[12];
+               DOM_SID mysid;
+
+               memset((char *)&mysid, '\0', sizeof(DOM_SID));
+               mysid.sid_rev_num = 1;
+               mysid.id_auth[5] = 5;
+               mysid.num_auths = 0;
+               mysid.sub_auths[mysid.num_auths++] = 21;
+
                generate_random_buffer( raw_sid_data, 12, True);
-               
-               fstrcpy( sid_string, "S-1-5-21");
-               for( i = 0; i < 3; i++) {
-                       fstring tmp_string;
-                       slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
-                       fstrcat( sid_string, tmp_string);
-               }
+               for( i = 0; i < 3; i++)
+                       mysid.sub_auths[mysid.num_auths++] = IVAL(raw_sid_data, i*4);
+
+               sid_to_string(sid_string, &mysid);
        } 
        
        fstrcat(sid_string, "\n");
@@ -883,7 +930,7 @@ BOOL pdb_generate_machine_sid(void)
         * Ensure our new SID is valid.
         */
        
-       if(!string_to_sid( &global_machine_sid, sid_string)) {
+       if(!string_to_sid( &global_sam_sid, sid_string)) {
                DEBUG(0,("unable to generate machine SID.\n"));
                return False;
        } 
@@ -898,50 +945,59 @@ BOOL pdb_generate_machine_sid(void)
                close(fd);
                return False;
        } 
-  
-       /*
-        * At this point we have a blocking lock on the SID
-        * file - check if in the meantime someone else wrote
-        * SID data into the file. If so - they were here first,
-        * use their data.
-        */
-       
-       if(sys_fstat( fd, &st) < 0) {
-               DEBUG(0,("unable to stat file %s. Error was %s\n",
-                        sid_file, strerror(errno) ));
-               close(fd);
-               return False;
-       } 
-  
-       if(st.st_size > 0) {
+       if(!overwrite_bad_sid) {
                /*
-                * Unlock as soon as possible to reduce
-                * contention on the exclusive lock.
-                */ 
-               do_file_lock( fd, 60, F_UNLCK);
-               
-               /*
-                * We have a valid SID - read it.
+                * At this point we have a blocking lock on the SID
+                * file - check if in the meantime someone else wrote
+                * SID data into the file. If so - they were here first,
+                * use their data.
                 */
-               
-               if(!read_sid_from_file( fd, sid_file)) {
-                       DEBUG(0,("unable to read file %s. Error was %s\n",
+       
+               if(sys_fstat( fd, &st) < 0) {
+                       DEBUG(0,("unable to stat file %s. Error was %s\n",
                                 sid_file, strerror(errno) ));
                        close(fd);
                        return False;
-               }
-               close(fd);
-               return True;
-       } 
+               } 
+  
+               if(st.st_size > 0) {
+                       /*
+                        * Unlock as soon as possible to reduce
+                        * contention on the exclusive lock.
+                        */ 
+                       do_file_lock( fd, 60, F_UNLCK);
+               
+                       /*
+                        * We have a valid SID - read it.
+                        */
+               
+                       if(!read_sid_from_file( fd, sid_file)) {
+                               DEBUG(0,("unable to read file %s. Error was %s\n",
+                                        sid_file, strerror(errno) ));
+                               close(fd);
+                               return False;
+                       }
+                       close(fd);
+                       return True;
+               } 
+       }
        
        /*
-        * The file is still empty and we have an exlusive lock on it.
+        * The file is still empty and we have an exlusive lock on it,
+        * or we're fixing an earlier mistake.
         * Write out out SID data into the file.
         */
-       
-       if(fchmod(fd, 0644) < 0) {
+
+       /*
+        * Use chmod here as some (strange) UNIX's don't
+        * have fchmod. JRA.
+        */     
+
+       if(chmod(sid_file, 0644) < 0) {
                DEBUG(0,("unable to set correct permissions on file %s. \
 Error was %s\n", sid_file, strerror(errno) ));
+               do_file_lock( fd, 60, F_UNLCK);
                close(fd);
                return False;
        } 
@@ -949,6 +1005,7 @@ Error was %s\n", sid_file, strerror(errno) ));
        if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
                DEBUG(0,("unable to write file %s. Error was %s\n",
                         sid_file, strerror(errno) ));
+               do_file_lock( fd, 60, F_UNLCK);
                close(fd);
                return False;
        } 
@@ -962,6 +1019,24 @@ Error was %s\n", sid_file, strerror(errno) ));
        return True;
 }   
 
+/*******************************************************************
+ Converts NT user RID to a UNIX uid.
+ ********************************************************************/
+
+uid_t pdb_user_rid_to_uid(uint32 user_rid)
+{
+       return (uid_t)(((user_rid & (~USER_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
+/*******************************************************************
+ Converts NT user RID to a UNIX gid.
+ ********************************************************************/
+
+gid_t pdb_user_rid_to_gid(uint32 user_rid)
+{
+       return (uid_t)(((user_rid & (~GROUP_RID_TYPE))- 1000)/RID_MULTIPLIER);
+}
+
 /*******************************************************************
  converts UNIX uid to an NT User RID.
  ********************************************************************/
@@ -1011,3 +1086,121 @@ BOOL pdb_rid_is_user(uint32 rid)
    }
    return False;
 }
+
+/*******************************************************************
+ Convert a rid into a name. Used in the lookup SID rpc.
+ ********************************************************************/
+
+BOOL lookup_local_rid(uint32 rid, char *name, uint8 *psid_name_use)
+{
+
+       BOOL is_user = pdb_rid_is_user(rid);
+
+       DEBUG(5,("lookup_local_rid: looking up %s RID %u.\n", is_user ? "user" :
+                       "group", (unsigned int)rid));
+
+       if(is_user) {
+               if(rid == DOMAIN_USER_RID_ADMIN) {
+                       pstring admin_users;
+                       char *p = admin_users;
+                       pstrcpy( admin_users, lp_domain_admin_users());
+                       if(!next_token(&p, name, NULL, sizeof(fstring)))
+                               fstrcpy(name, "Administrator");
+               } else if (rid == DOMAIN_USER_RID_GUEST) {
+                       pstring guest_users;
+                       char *p = guest_users;
+                       pstrcpy( guest_users, lp_domain_guest_users());
+                       if(!next_token(&p, name, NULL, sizeof(fstring)))
+                               fstrcpy(name, "Guest");
+               } else {
+                       uid_t uid = pdb_user_rid_to_uid(rid);
+                       struct passwd *pass = sys_getpwuid(uid);
+
+                       *psid_name_use = SID_NAME_USER;
+
+                       DEBUG(5,("lookup_local_rid: looking up uid %u %s\n", (unsigned int)uid,
+                               pass ? "succeeded" : "failed" ));
+
+                       if(!pass) {
+                               slprintf(name, sizeof(fstring)-1, "unix_user.%u", (unsigned int)uid);
+                               return True;
+                       }
+
+                       fstrcpy(name, pass->pw_name);
+
+                       DEBUG(5,("lookup_local_rid: found user %s for rid %u\n", name,
+                               (unsigned int)rid ));
+               }
+
+       } else {
+               gid_t gid = pdb_user_rid_to_gid(rid);
+               struct group *gr = getgrgid(gid);
+
+               *psid_name_use = SID_NAME_ALIAS;
+
+               DEBUG(5,("lookup_local_rid: looking up gid %u %s\n", (unsigned int)gid,
+                       gr ? "succeeded" : "failed" ));
+
+               if(!gr) {
+                       slprintf(name, sizeof(fstring)-1, "unix_group.%u", (unsigned int)gid);
+                       return True;
+               }
+
+               fstrcpy( name, gr->gr_name);
+
+               DEBUG(5,("lookup_local_rid: found group %s for rid %u\n", name,
+                       (unsigned int)rid ));
+       }
+
+       return True;
+}
+
+/*******************************************************************
+ Convert a name into a SID. Used in the lookup name rpc.
+ ********************************************************************/
+
+BOOL lookup_local_name(char *domain, char *user, DOM_SID *psid, uint8 *psid_name_use)
+{
+       extern DOM_SID global_sid_World_Domain;
+       struct passwd *pass = NULL;
+       DOM_SID local_sid;
+
+       sid_copy(&local_sid, &global_sam_sid);
+
+       if(!strequal(global_myname, domain) && !strequal(global_myworkgroup, domain))
+               return False;
+
+       /*
+        * Special case for MACHINE\Everyone. Map to the world_sid.
+        */
+
+       if(strequal(user, "Everyone")) {
+               sid_copy( psid, &global_sid_World_Domain);
+               sid_append_rid(psid, 0);
+               *psid_name_use = SID_NAME_ALIAS;
+               return True;
+       }
+
+       (void)map_username(user);
+
+       if(!(pass = Get_Pwnam(user, False))) {
+               /*
+                * Maybe it was a group ?
+                */
+               struct group *grp = getgrnam(user);
+
+               if(!grp)
+                       return False;
+
+               sid_append_rid( &local_sid, pdb_gid_to_group_rid(grp->gr_gid));
+               *psid_name_use = SID_NAME_ALIAS;
+       } else {
+
+               sid_append_rid( &local_sid, pdb_uid_to_user_rid(pass->pw_uid));
+               *psid_name_use = SID_NAME_USER;
+       }
+
+       sid_copy( psid, &local_sid);
+
+       return True;
+}