//------------------------------------------------------------------------------
void Scan_registry_user_file(HK_F_OPEN *hks, sqlite3 *db, unsigned int session_id, char *computer_name)
{
  DWORD userRID = 0;
  USERS_INFOS User_infos;
  #ifdef CMD_LINE_ONLY_NO_DB
  printf("\"RegistryUser\";\"source\";\"name\";\"RID\";\"SID\";\"grp\";\"description\";\"last_logon\";\"last_password_change\";"
         "\"nb_connexion\";\"type\";\"state_id\";\"session_id\";\r\n");
  #endif
  //get ref key for hashs
  BYTE b_f[MAX_LINE_SIZE];
  Readnk_Value(hks->buffer, hks->taille_fic, (hks->pos_fhbin)+HBIN_HEADER_SIZE, hks->position, "SAM\\Domains\\Account", NULL,"F", b_f, MAX_LINE_SIZE);

  //enum all users
  //exist or not in the file ?
  HBIN_CELL_NK_HEADER *nk_h = GetRegistryNK(hks->buffer, hks->taille_fic, (hks->pos_fhbin)+HBIN_HEADER_SIZE, hks->position, "SAM\\Domains\\Account\\Users");
  if (nk_h == NULL)return;

  HBIN_CELL_NK_HEADER *nk_h_tmp;
  DWORD valueSize;
  BOOL ok_test;
  char SubKeyName[MAX_PATH];
  char cbuffer[MAX_LINE_SIZE], buffer[MAX_LINE_SIZE];
  DWORD i,nbSubKey = GetSubNK(hks->buffer, hks->taille_fic, nk_h, hks->position, 0, NULL, 0);
  for (i=0;i<nbSubKey;i++)
  {
    ok_test = FALSE;
    //for each subkey
    if(GetSubNK(hks->buffer, hks->taille_fic, nk_h, hks->position, i, SubKeyName, MAX_PATH))
    {
      //get nk of key :)
      nk_h_tmp = GetSubNKtonk(hks->buffer, hks->taille_fic, nk_h, hks->position, i);
      if (nk_h_tmp == NULL)continue;

      //F
      buffer[0]  = 0;
      cbuffer[0] = 0;
      valueSize  = MAX_LINE_SIZE;
      if(ReadBinarynk_Value(hks->buffer, hks->taille_fic, (hks->pos_fhbin)+HBIN_HEADER_SIZE, hks->position, NULL, nk_h_tmp,"F", buffer, &valueSize))
      {
        DataToHexaChar(buffer, valueSize, cbuffer, MAX_LINE_SIZE);
        userRID = TestUserDataFromSAM_F(&User_infos,cbuffer);
        ok_test = TRUE;
      }

      //V
      buffer[0]  = 0;
      cbuffer[0] = 0;
      valueSize  = MAX_LINE_SIZE;
      if(ReadBinarynk_Value(hks->buffer, hks->taille_fic, (hks->pos_fhbin)+HBIN_HEADER_SIZE, hks->position, NULL, nk_h_tmp,"V", buffer, &valueSize))
      {
        DataToHexaChar(buffer, valueSize, cbuffer, MAX_LINE_SIZE);
        if(TestUserDataFromSAM_V(&User_infos,cbuffer,computer_name))
        {
          //test if rid and sid ok
          userRID = HTDF(SubKeyName,8);
          if(User_infos.RID[0] == 0)snprintf(User_infos.RID,MAX_PATH,"%05lu",userRID);
          if(User_infos.SID[0] == 0)snprintf(User_infos.SID,MAX_PATH,"S-1-5-?-?-?-?-%lu",userRID);
        }else
        {
          if(User_infos.RID[0] == 0 && userRID)snprintf(User_infos.RID,MAX_PATH,"%05lu",userRID);
          if(User_infos.SID[0] == 0 && userRID)snprintf(User_infos.SID,MAX_PATH,"S-1-5-?-?-?-?-%lu",userRID);
        }
        ok_test = TRUE;
      }else
      {
        if(User_infos.RID[0] == 0 && userRID)snprintf(User_infos.RID,MAX_PATH,"%05lu",userRID);
        if(User_infos.SID[0] == 0 && userRID)snprintf(User_infos.SID,MAX_PATH,"S-1-5-?-?-?-?-%lu",userRID);
      }

      if (!ok_test)continue;

      //get groups
      if (userRID) GetUserGroupFRF(userRID, User_infos.group, MAX_PATH);

      //get hashs
      if(b_f[0] != 0 && _SYSKEY[0] != 0)
      {
        DecodeSAMHashXP(_SYSKEY,User_infos.pwdump_pwd_raw_format,userRID,User_infos.name,b_f);
      }

      //add user
      convertStringToSQL(User_infos.description, MAX_PATH);
      addRegistryUsertoDB(hks->file,User_infos.name, User_infos.RID, User_infos.SID, User_infos.group,
                          User_infos.description, User_infos.last_logon, User_infos.last_password_change,
                          User_infos.nb_connexion, User_infos.type, User_infos.state_id,session_id, db);

      //add password
      if (TEST_REG_PASSWORD_ENABLE)
        addPasswordtoDB(hks->file, User_infos.name, User_infos.pwdump_pwd_format, User_infos.pwdump_pwd_raw_format, REG_PASSWORD_STRING_LOCAL_USER, session_id, db);
    }
  }
}
//------------------------------------------------------------------------------
void Scan_registry_user_local(sqlite3 *db, unsigned int session_id)
{
  if (registry_users_extract(db,session_id))return;

  //load all users informations
  HMODULE hDLL;
  typedef DWORD (WINAPI *NETAPIBUFFERFREE)(LPVOID Buffer);
  NETAPIBUFFERFREE NetApiBufferFree;
  typedef DWORD (WINAPI *NETUSERENUM)(LPCWSTR servername, DWORD level, DWORD filter, LPBYTE* bufptr, DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries, LPDWORD resume_handle);
  NETUSERENUM NetUserEnum;
  typedef DWORD (WINAPI *NETUSERGETINFO)( LPCWSTR servername, LPCWSTR username, DWORD level, LPBYTE* bufptr);
  NETUSERGETINFO NetUserGetInfo;
  typedef DWORD (WINAPI *NETUSERGETLOCALGROUPS)( LPCWSTR servername, LPCWSTR username, DWORD level, DWORD flags, LPBYTE* bufptr, DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries);
  NETUSERGETLOCALGROUPS NetUserGetLocalGroups;

  typedef struct _USER_INFO_0 {
    LPWSTR usri0_name;
  }*LPUSER_INFO_0;

  typedef struct _USER_INFO_2 {
    LPWSTR usri2_name;
    LPWSTR usri2_password;
    DWORD  usri2_password_age;
    DWORD  usri2_priv;
    LPWSTR usri2_home_dir;
    LPWSTR usri2_comment;
    DWORD  usri2_flags;
    LPWSTR usri2_script_path;
    DWORD  usri2_auth_flags;
    LPWSTR usri2_full_name;
    LPWSTR usri2_usr_comment;
    LPWSTR usri2_parms;
    LPWSTR usri2_workstations;
    DWORD  usri2_last_logon;
    DWORD  usri2_last_logoff;
    DWORD  usri2_acct_expires;
    DWORD  usri2_max_storage;
    DWORD  usri2_units_per_week;
    PBYTE  usri2_logon_hours;
    DWORD  usri2_bad_pw_count;
    DWORD  usri2_num_logons;
    LPWSTR usri2_logon_server;
    DWORD  usri2_country_code;
    DWORD  usri2_code_page;
  } USER_INFO_2, *PUSER_INFO_2, *LPUSER_INFO_2;

  typedef struct _GROUP_USERS_INFO_0 {
    LPWSTR grui0_name;
  } GROUP_USERS_INFO_0, *PGROUP_USERS_INFO_0, *LPGROUP_USERS_INFO_0;

  //load function
  if ((hDLL = LoadLibrary( "NETAPI32.dll"))!=NULL)
  {
    NetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress(hDLL,"NetApiBufferFree");
    NetUserEnum = (NETUSERENUM) GetProcAddress(hDLL,"NetUserEnum");
    NetUserGetInfo = (NETUSERGETINFO) GetProcAddress(hDLL,"NetUserGetInfo");
    NetUserGetLocalGroups = (NETUSERGETLOCALGROUPS) GetProcAddress(hDLL,"NetUserGetLocalGroups");

    if (NetApiBufferFree && NetUserEnum && NetUserGetInfo && NetUserGetLocalGroups)
    {
      //enumerate all accounts
      DWORD nStatus, i, nb, total;
      LPUSER_INFO_0 pBuf, Buffer;
      USER_INFO_2 * pBuf_info;

      char name[MAX_PATH],RID[MAX_PATH],SID[MAX_PATH],group[MAX_PATH],type[MAX_PATH],
      description[MAX_PATH],last_logon[DATE_SIZE_MAX],last_password_change[DATE_SIZE_MAX];
      DWORD nb_connexion,state_id;

      LPGROUP_USERS_INFO_0 LBuffer,pTmpBuf;
      DWORD dwEntriesRead, dwTotalEntries, j, s;

      do
      {
        nStatus = NetUserEnum(0,0,2,(LPBYTE*)&pBuf,-1,&nb,&total,0);
        if (((nStatus == 0) || (nStatus == 234)) && (Buffer = pBuf) != 0)
        {
          for (i = 0; i < nb; i++)
          {
            if (Buffer->usri0_name!=0)
            {
              //init
              name[0]                 = 0;
              RID[0]                  = 0;
              SID[0]                  = 0;
              group[0]                = 0;
              description[0]          = 0;
              last_logon[0]           = 0;
              last_password_change[0] = 0;
              nb_connexion            = 0;
              state_id                = 0;
              type[0]                 = 0;

              if (NetUserGetInfo(0,Buffer->usri0_name,2,(LPBYTE *)&pBuf_info) == 0)
              {
                //name
                snprintf(name,MAX_PATH,"%S",Buffer->usri0_name);

                //get account infos ^^ SID + RID
                GetSIDFromUser(name, RID, SID, MAX_PATH);

                //group
                if (NetUserGetLocalGroups(0,Buffer->usri0_name,0,1,(LPBYTE*)&LBuffer,-1,&dwEntriesRead,&dwTotalEntries) == 0)
                {
                  if ((pTmpBuf = LBuffer) != 0)
                  {
                    for (j = 0; j < dwEntriesRead; j++)
                    {
                      if(pTmpBuf != 0)
                      {
                        s = strlen(group);
                        if (s>=MAX_PATH)break;

                        snprintf(group+s,MAX_PATH-s,"%S,",pTmpBuf->grui0_name);
                      }
                      pTmpBuf++;
                    }
                  }
                }

                //description
                snprintf(description,MAX_PATH,"(%S) %S %S",pBuf_info->usri2_full_name,pBuf_info->usri2_usr_comment,pBuf_info->usri2_comment);

                //state
                if (pBuf_info->usri2_flags&0x2)state_id = 300;//Disable
                else state_id = 301;//Enable
                if (pBuf_info->usri2_flags&0x10)state_id+=2;//Lock

                //last_logon
                if (pBuf_info->usri2_last_logon != 0)
                {
                  timeToString(pBuf_info->usri2_last_logon, last_logon, DATE_SIZE_MAX);
                }

                //last_password_change
                if (pBuf_info->usri2_password_age != 0)
                {
                  snprintf(last_password_change,DATE_SIZE_MAX,"%lu %02lu:%02lu:%02lu",
                           pBuf_info->usri2_password_age/86400,
                           pBuf_info->usri2_password_age%86400/3600,
                           pBuf_info->usri2_password_age%86400%3600/60,
                           pBuf_info->usri2_password_age%86400%3600%60);
                }

                //nb_connexion
                nb_connexion = pBuf_info->usri2_num_logons;

                //type
                switch(pBuf_info->usri2_priv)
                {
                  case 0:snprintf(type,MAX_PATH,"%lu : %s",pBuf_info->usri2_priv,cps[TXT_MSG_GUEST].c);break;
                  case 1:snprintf(type,MAX_PATH,"%lu : %s",pBuf_info->usri2_priv,cps[TXT_MSG_USER].c);break;
                  case 2:snprintf(type,MAX_PATH,"%lu : %s",pBuf_info->usri2_priv,cps[TXT_MSG_ADMIN].c);break;
                  default:snprintf(type,MAX_PATH,"0x%02X : %s",(unsigned int)(pBuf_info->usri2_priv & 0xff),cps[TXT_MSG_UNK].c);break;
                }

                addRegistryUsertoDB("NETAPI32",name, RID, SID, group, description,
                                    last_logon, last_password_change,
                                    nb_connexion, type, state_id, session_id, db);
              }
              Buffer++;
            }else break;
          }
        }
      }while (nStatus == ERROR_MORE_DATA && start_scan);
    }
    FreeLibrary(hDLL);
  }
}
//------------------------------------------------------------------------------
BOOL registry_users_extract(sqlite3 *db, unsigned int session_id)
{
  BOOL ok = FALSE;
  DWORD userRID;
  USERS_INFOS User_infos;

  //import syskey
  char sk[MAX_PATH]="";
  BOOL syskeyok = registry_syskey_local(sk, MAX_PATH);

  //get current computer name
  char computer_name[COMPUTER_NAME_SIZE_MAX]="";
  DWORD taille = COMPUTER_NAME_SIZE_MAX;
  GetComputerName(computer_name,&taille);

  //Set ACL in registry
  int ret = set_sam_tree_access(HKEY_LOCAL_MACHINE,"SECURITY\\SAM\\Domains\\Account\\Users");
  if (ret == 0)
  {
    //get reference key for users hashs
    HKEY CleTmp;
    BOOL ok_test;
    BYTE b_f[MAX_LINE_SIZE];
    if(ReadValue(HKEY_LOCAL_MACHINE, "SAM\\SAM\\Domains\\Account", "F", (char*)b_f, MAX_LINE_SIZE)<= 0x80)b_f[0] = 0;

    //get users
    if (RegOpenKey(HKEY_LOCAL_MACHINE,"SAM\\SAM\\Domains\\Account\\Users\\",&CleTmp)==ERROR_SUCCESS)
    {
      DWORD i, valueSize, SizeSubKeyName, nbSubKey = 0;
      if (RegQueryInfoKey (CleTmp,0,0,0,&nbSubKey,0,0,0,0,0,0,0)==ERROR_SUCCESS)
      {
        char SubKeyName[MAX_PATH], path[MAX_PATH], buffer[MAX_LINE_SIZE], cbuffer[MAX_LINE_SIZE];

        for (i=0;i<nbSubKey;i++)
        {
          ok_test       = FALSE;
          SizeSubKeyName=MAX_PATH;// on reinitialise la taille a chaque fois sinon il ne lit pas la valeur suivant
          SubKeyName[0] = 0;
          if(RegEnumKeyEx (CleTmp,i,SubKeyName,&SizeSubKeyName,0,0,0,0)!=ERROR_SUCCESS)continue;

          //read value
          snprintf(path,MAX_PATH,"SAM\\SAM\\Domains\\Account\\Users\\%s",SubKeyName);

          //F value
          cbuffer[0]= 0;
          buffer[0] = 0;
          userRID   = 0;
          valueSize = ReadValue(HKEY_LOCAL_MACHINE, path, "F", buffer, MAX_LINE_SIZE);
          if (valueSize)
          {
            DataToHexaChar(buffer, valueSize, cbuffer, MAX_LINE_SIZE);
            userRID = TestUserDataFromSAM_F(&User_infos,cbuffer);
            ok_test = TRUE;
         }

          //V value
          cbuffer[0]= 0;
          buffer[0] = 0;
          valueSize = ReadValue(HKEY_LOCAL_MACHINE, path, "V", buffer, MAX_LINE_SIZE);
          if (valueSize)
          {
            //read datas
            DataToHexaChar(buffer, valueSize, cbuffer, MAX_LINE_SIZE);
            if(TestUserDataFromSAM_V(&User_infos,cbuffer,computer_name))
            {
              //test if rid and sid ok
              userRID = HTDF(SubKeyName,8);
              if(User_infos.RID[0] == 0)snprintf(User_infos.RID,MAX_PATH,"%05lu",userRID);
              if(User_infos.SID[0] == 0)snprintf(User_infos.SID,MAX_PATH,"S-1-5-?-?-?-?-%lu",userRID);
           }else
            {
              if((User_infos.RID[0] == 0) && userRID)snprintf(User_infos.RID,MAX_PATH,"%05lu",userRID);
              if((User_infos.SID[0] == 0) && userRID)snprintf(User_infos.SID,MAX_PATH,"S-1-5-?-?-?-?-%lu",userRID);
            }
            ok_test = TRUE;
          }else
          {
            if((User_infos.RID[0] == 0) && userRID)snprintf(User_infos.RID,MAX_PATH,"%05lu",userRID);
            if((User_infos.SID[0] == 0) && userRID)snprintf(User_infos.SID,MAX_PATH,"S-1-5-?-?-?-?-%lu",userRID);
         }

          if (!ok_test)continue;

          //get groups
          if (userRID) GetUserGroup(userRID, User_infos.group, MAX_PATH);

          //get hashs
          if((b_f[0] != 0) && syskeyok)
          {
            DecodeSAMHashXP(sk,User_infos.pwdump_pwd_raw_format,userRID,User_infos.name,b_f);
          }

          //add user
          convertStringToSQL(User_infos.description, MAX_PATH);
          addRegistryUsertoDB("HKEY_LOCAL_MACHINE\\SAM",User_infos.name, User_infos.RID, User_infos.SID, User_infos.group,
                              User_infos.description, User_infos.last_logon, User_infos.last_password_change,
                              User_infos.nb_connexion, User_infos.type, User_infos.state_id,session_id, db);

          //add password
          if (TEST_REG_PASSWORD_ENABLE)
            addPasswordtoDB("HKEY_LOCAL_MACHINE\\SAM", User_infos.name, User_infos.pwdump_pwd_format, User_infos.pwdump_pwd_raw_format, REG_PASSWORD_STRING_LOCAL_USER, session_id, db);
          ok = TRUE;
        }
      }
      RegCloseKey(CleTmp);
    }
  }

  //Restore ACL in registry
  restore_sam_tree_access(HKEY_LOCAL_MACHINE,"SECURITY\\SAM\\Domains\\Account\\Users");

  return ok;
}