Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Routine to get probably recycle bin paths from live system #31

Merged
merged 3 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions src/rifiuti-vista.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ main (int argc,
GOptionContext *context;

extern char **fileargs;
extern gboolean live_mode;

rifiuti_init (argv[0]);

Expand All @@ -283,18 +284,38 @@ main (int argc,
if (exit_status != EXIT_SUCCESS)
goto cleanup;

exit_status = check_file_args (fileargs[0], &filelist, RECYCLE_BIN_TYPE_DIR);
if (exit_status != EXIT_SUCCESS)
goto cleanup;
#ifdef G_OS_WIN32
extern gboolean live_mode;

if (live_mode) {
GSList *bindirs = enumerate_drive_bins();
GSList *ptr = bindirs;
while (ptr) {
check_file_args (ptr->data, &filelist, RECYCLE_BIN_TYPE_DIR);
ptr = ptr->next;
}
ptr = NULL;
g_slist_free_full (bindirs, g_free);
}
else
#endif
{
exit_status = check_file_args (fileargs[0], &filelist, RECYCLE_BIN_TYPE_DIR);
if (exit_status != EXIT_SUCCESS)
goto cleanup;
}

g_slist_foreach (filelist, (GFunc) parse_record_cb, &recordlist);

/* Fill in recycle bin metadata */
meta.type = RECYCLE_BIN_TYPE_DIR;
meta.filename = fileargs[0];
meta.keep_deleted_entry = FALSE;
meta.is_empty = (filelist == NULL);
meta.has_unicode_path = TRUE;
if (live_mode)
meta.filename = "(current system)";
else
meta.filename = fileargs[0];

/* NULL filelist at this point means a valid empty $Recycle.bin */
if ( !meta.is_empty && (recordlist == NULL) )
Expand Down
3 changes: 3 additions & 0 deletions src/rifiuti.1
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ rifiuti2 \[em] MS Windows recycle bin analysis tool
.br
.B "\fCrifiuti-vista\/\fP [\-x | [\-n] [\-t \fIdelim\/\fP]] [\-z]"
.B "[\-o \fIoutfile\/\fP] [\-\-] \fIinfo2_or_dir\/\fP"
.br
.B "\fCrifiuti-vista\/\fP --live [\-x | [\-n] [\-t \fIdelim\/\fP]]"
.B "[\-z] [\-o \fIoutfile\/\fP]"
.ad n

.SH DESCRIPTION
Expand Down
94 changes: 94 additions & 0 deletions src/utils-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <windows.h>
#include <aclapi.h>
#include <authz.h>
#include <sddl.h>

#include <glib.h>
#include <glib/gi18n.h>
Expand Down Expand Up @@ -158,6 +159,99 @@ get_user_sid (void)
return NULL;
}

/*
* Probe for logical drives on Windows and return their
* corresponding recycle bin paths for current user
*/
GSList *
enumerate_drive_bins (void)
{
DWORD drive_bitmap;
PSID sid = NULL;
char *errmsg = NULL, *sid_str = NULL;
static char drive_root[4] = "A:\\";
GSList *result = NULL;

if (! (drive_bitmap = GetLogicalDrives())) {
errmsg = g_win32_error_message (GetLastError());
g_critical (_("Failed to enumerate drives in system: %s"), errmsg);
goto enumerate_cleanup;
}

if (NULL == (sid = get_user_sid())) {
g_critical (_("Failed to get SID of current user"));
goto enumerate_cleanup;
}
if (! ConvertSidToStringSidA(sid, &sid_str)) {
errmsg = g_win32_error_message (GetLastError());
g_critical (_("Failed to convert SID to string: %s"), errmsg);
goto enumerate_cleanup;
}

for (int i = 0; i < sizeof(DWORD) * CHAR_BIT; i++) {
if (! (drive_bitmap & (1 << i)))
continue;
drive_root[0] = 'A' + i;
UINT type = GetDriveTypeA(drive_root);
if ( (type == DRIVE_NO_ROOT_DIR)
|| (type == DRIVE_UNKNOWN )
|| (type == DRIVE_REMOTE )
|| (type == DRIVE_CDROM )) {
g_debug ("%s is not a logical drive we want, skipped", drive_root);
continue;
}
char *path = g_strdup_printf ("%s$Recycle.Bin\\%s",
drive_root, sid_str);

result = g_slist_append (result, path);
}

enumerate_cleanup:
// sid_str owned by system
g_free (sid);
g_free (errmsg);
return result;
}

/*
* Get Windows product name via registry
*/
gunichar2 *
windows_product_name (void)
{
LSTATUS status;
DWORD str_size;
gunichar2 *product_name;
gunichar2 *subkey = L"software\\microsoft\\windows nt\\currentversion";
gunichar2 *keyvalue = L"ProductName";

status = RegGetValueW(
HKEY_LOCAL_MACHINE,
subkey,
keyvalue,
RRF_RT_REG_SZ,
NULL,
NULL,
&str_size
);

if ((status != ERROR_SUCCESS) || (str_size > G_MAXSIZE))
return NULL;

product_name = g_malloc ((gsize) str_size);
status = RegGetValueW(
HKEY_LOCAL_MACHINE,
subkey,
keyvalue,
RRF_RT_REG_SZ,
NULL,
product_name,
&str_size
);

return (status == ERROR_SUCCESS) ? product_name : NULL;
}

/*!
* Fetch ACL access mask using Authz API
*/
Expand Down
2 changes: 2 additions & 0 deletions src/utils-win.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

void gui_message (const char *message );
char * get_win_timezone_name (void);
GSList * enumerate_drive_bins (void);
gunichar2 *windows_product_name (void);
gboolean can_list_win32_folder (const char *dir );
gboolean init_wincon_handle (gboolean is_stdout);
void close_wincon_handle (void);
Expand Down
63 changes: 55 additions & 8 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ static char *os_strings[] = {
static int output_mode = OUTPUT_NONE;
static gboolean no_heading = FALSE;
static gboolean use_localtime = FALSE;
gboolean live_mode = FALSE;
char *delim = NULL;
char *legacy_encoding = NULL; /*!< INFO2 only, or upon request */
char *output_loc = NULL;
Expand Down Expand Up @@ -120,6 +121,16 @@ const GOptionEntry rbinfile_options[] = {
{NULL}
};

/* Append to main option group if program is $Recycle.bin reader */
const GOptionEntry live_options[] = {
{
"live", 0, 0,
G_OPTION_ARG_NONE, &live_mode,
N_("Inspect live system"), NULL
},
{NULL}
};

/*
* Option handling related routines
*/
Expand Down Expand Up @@ -368,14 +379,24 @@ _count_fileargs (GOptionContext *context,
gpointer data,
GError **err)
{
if (fileargs && g_strv_length (fileargs) == 1)
return TRUE;

/* FIXME unable to pull user data, so only print generic mesg */
g_set_error (err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
_("Must specify exactly one file or folder argument."));
if (live_mode) {
if (fileargs && g_strv_length (fileargs)) {
g_set_error (err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
_("Live system probation must not be used together "
"with file arguments."));
return FALSE;
}
}
else
{
if (! fileargs || (g_strv_length (fileargs) != 1)) {
g_set_error (err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
_("Must specify exactly one file or folder argument."));
return FALSE;
}
}

return FALSE;
return TRUE;
}


Expand Down Expand Up @@ -699,8 +720,12 @@ rifiuti_setup_opt_ctx (GOptionContext **context,
case RECYCLE_BIN_TYPE_FILE:
g_option_group_add_entries (group, rbinfile_options);
break;
case RECYCLE_BIN_TYPE_DIR:
#ifdef G_OS_WIN32
g_option_group_add_entries (group, live_options);
#endif
break;
default: break;
/* There will be option for recycle bin dir later */
}

g_option_group_set_parse_hooks (group, NULL, _count_fileargs);
Expand Down Expand Up @@ -1072,6 +1097,28 @@ print_header (metarecord meta)
g_print ("\n");
}

#ifdef G_OS_WIN32
if (live_mode)
{
gunichar2 *buf = windows_product_name();
if (buf == NULL)
g_print ("%s", _("OS detection failed"));
else {
GError *err = NULL;
char *product_name = g_utf16_to_utf8(
buf, -1, NULL, NULL, &err);
g_free (buf);
if (err) {
g_clear_error (&err);
g_print ("%s", _("OS detection failed"));
} else {
g_print (_("OS: %s"), product_name);
}
g_free (product_name);
}
}
else
#endif
{
_os_guess g = guess_windows_ver (meta);

Expand Down