Skip to content

Commit

Permalink
Secure erase of files.
Browse files Browse the repository at this point in the history
Some customers need for compliance reasons the ability that we use a
secure method for erasing files. This patch adds such ability by
allowing an external program to be invoked to perform the secure erase.

Strict industry standards and government regulations are in place that
force organizations to mitigate the risk of unauthorized exposure of
confidential corporate and government data. Regulations in the United
States include HIPAA (Health Insurance Portability and Accountability
Act); FACTA (The Fair and Accurate Credit Transactions Act of 2003);
GLB (Gramm-Leach Bliley); Sarbanes-Oxley Act (SOx); and Payment Card
Industry Data Security Standards (PCI DSS) and the Data Protection Act
in the United Kingdom. Failure to comply can result in fines and damage
to company reputation, as well as civil and criminal liability.

Data erasure may not work completely on flash based media, such as Solid
State Drives and USB Flash Drives, as these devices can store remnant
data which is inaccessible to the erasure technique, and data can be
retrieved from the individual flash memory chips inside the device.
Data erasure through overwriting only works on hard drives that are
functioning and writing to all sectors. Bad sectors cannot usually be
overwritten, but may contain recoverable information. Bad sectors,
however, may be invisible to the host system and thus to the erasing
software. Disk encryption before use prevents this problem.
Software-driven data erasure could also be compromised by malicious
code.
  • Loading branch information
Marco van Wieringen committed Sep 11, 2015
1 parent aa18ca2 commit a8d8270
Show file tree
Hide file tree
Showing 29 changed files with 296 additions and 134 deletions.
7 changes: 5 additions & 2 deletions src/dird/dird.c
Expand Up @@ -1000,7 +1000,10 @@ static bool check_resources()
UnlockRes();
if (OK) {
close_msg(NULL); /* close temp message handler */
init_msg(NULL, me->messages); /* open daemon message handler */
init_msg(NULL, me->messages); /* open daemon message handler */
if (me->secure_erase_cmdline) {
set_secure_erase_cmdline(me->secure_erase_cmdline);
}
}

bail_out:
Expand Down Expand Up @@ -1278,7 +1281,7 @@ static void cleanup_old_files()
pm_strcpy(cleanup, basename);
pm_strcat(cleanup, result->d_name);
Dmsg1(100, "Unlink: %s\n", cleanup);
unlink(cleanup);
secure_erase(NULL, cleanup);
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/dird/dird_conf.c
Expand Up @@ -145,8 +145,8 @@ static RES_ITEM dir_items[] = {
{ "NdmpLogLevel", CFG_TYPE_PINT32, ITEM(res_dir.ndmp_loglevel), 0, CFG_ITEM_DEFAULT, "4", "13.2.0-", NULL },
{ "AbsoluteJobTimeout", CFG_TYPE_PINT32, ITEM(res_dir.jcr_watchdog_time), 0, 0, NULL, "14.2.0-", NULL },
{ "Auditing", CFG_TYPE_BOOL, ITEM(res_dir.auditing), 0, CFG_ITEM_DEFAULT, "false", "14.2.0-", NULL },
{ "AuditEvents", CFG_TYPE_AUDIT, ITEM(res_dir.audit_events), 0, 0, NULL,
"14.2.0-", NULL },
{ "AuditEvents", CFG_TYPE_AUDIT, ITEM(res_dir.audit_events), 0, 0, NULL, "14.2.0-", NULL },
{ "SecureEraseCommand", CFG_TYPE_STR, ITEM(res_dir.secure_erase_cmdline), 0, 0, NULL, "15.2.1-", NULL },
{ NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
};

Expand Down Expand Up @@ -2386,6 +2386,9 @@ void free_resource(RES *sres, int type)
if (res->res_dir.audit_events) {
delete res->res_dir.audit_events;
}
if (res->res_dir.secure_erase_cmdline) {
free(res->res_dir.secure_erase_cmdline);
}
break;
case R_DEVICE:
case R_COUNTER:
Expand Down
1 change: 1 addition & 0 deletions src/dird/dird_conf.h
Expand Up @@ -145,6 +145,7 @@ class DIRRES: public BRSRES {
uint32_t jcr_watchdog_time; /* Absolute time after which a Job gets terminated regardless of its progress */
uint32_t stats_collect_interval; /* Statistics collect interval in seconds */
char *verid; /* Custom Id to print in version command */
char *secure_erase_cmdline; /* Cmdline to execute to perform secure erase of file */
s_password keyencrkey; /* Key Encryption Key */
};

Expand Down
2 changes: 1 addition & 1 deletion src/dird/msgchan.c
Expand Up @@ -129,7 +129,7 @@ static inline bool send_bootstrap_file_to_sd(JCR *jcr, BSOCK *sd)
sd->signal(BNET_EOD);
fclose(bs);
if (jcr->unlink_bsr) {
unlink(jcr->RestoreBootstrap);
secure_erase(jcr, jcr->RestoreBootstrap);
jcr->unlink_bsr = false;
}
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/dird/ndmp_dma.c
Expand Up @@ -2833,7 +2833,7 @@ void ndmp_restore_cleanup(JCR *jcr, int TermCode)
update_job_end(jcr, TermCode);

if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
unlink(jcr->RestoreBootstrap);
secure_erase(jcr, jcr->RestoreBootstrap);
jcr->unlink_bsr = false;
}

Expand Down
2 changes: 1 addition & 1 deletion src/dird/restore.c
Expand Up @@ -457,7 +457,7 @@ void native_restore_cleanup(JCR *jcr, int TermCode)
update_job_end(jcr, TermCode);

if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
unlink(jcr->RestoreBootstrap);
secure_erase(jcr, jcr->RestoreBootstrap);
jcr->unlink_bsr = false;
}

Expand Down
6 changes: 5 additions & 1 deletion src/dird/ua_status.c
Expand Up @@ -397,7 +397,6 @@ void list_dir_status_header(UAContext *ua)
dbdrivers.strcat(catalog->db_driver);
cnt++;
}

ua->send_msg(_("%s Version: %s (%s) %s %s %s\n"), my_name, VERSION, BDATE,
HOST_OS, DISTNAME, DISTVER);
bstrftime_nc(dt, sizeof(dt), daemon_start_time);
Expand All @@ -409,6 +408,11 @@ void list_dir_status_header(UAContext *ua)
edit_uint64_with_commas(sm_max_bytes, b3),
edit_uint64_with_commas(sm_buffers, b4),
edit_uint64_with_commas(sm_max_buffers, b5));

if (me->secure_erase_cmdline) {
ua->send_msg(_(" secure erase command='%s'\n"), me->secure_erase_cmdline);
}

len = list_dir_plugins(msg);
if (len > 0) {
ua->send_msg("%s\n", msg.c_str());
Expand Down
2 changes: 1 addition & 1 deletion src/dird/verify.c
Expand Up @@ -501,7 +501,7 @@ void verify_cleanup(JCR *jcr, int TermCode)
}

if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
unlink(jcr->RestoreBootstrap);
secure_erase(jcr, jcr->RestoreBootstrap);
jcr->unlink_bsr = false;
}

Expand Down
2 changes: 1 addition & 1 deletion src/filed/accurate_lmdb.c
Expand Up @@ -570,7 +570,7 @@ void B_ACCURATE_LMDB::destroy(JCR *jcr)
}

if (m_lmdb_name) {
unlink(m_lmdb_name);
secure_erase(jcr, m_lmdb_name);
free_pool_memory(m_lmdb_name);
m_lmdb_name = NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion src/filed/dir_cmd.c
Expand Up @@ -1173,7 +1173,7 @@ static bool fileset_cmd(JCR *jcr)
static void free_bootstrap(JCR *jcr)
{
if (jcr->RestoreBootstrap) {
unlink(jcr->RestoreBootstrap);
secure_erase(jcr, jcr->RestoreBootstrap);
free_pool_memory(jcr->RestoreBootstrap);
jcr->RestoreBootstrap = NULL;
}
Expand Down
3 changes: 3 additions & 0 deletions src/filed/filed.c
Expand Up @@ -600,6 +600,9 @@ static bool check_resources()
if (OK) {
close_msg(NULL); /* close temp message handler */
init_msg(NULL, me->messages); /* open user specified message handler */
if (me->secure_erase_cmdline) {
set_secure_erase_cmdline(me->secure_erase_cmdline);
}
}

return OK;
Expand Down
4 changes: 4 additions & 0 deletions src/filed/filed_conf.c
Expand Up @@ -121,6 +121,7 @@ static RES_ITEM cli_items[] = {
{ "AbsoluteJobTimeout", CFG_TYPE_PINT32, ITEM(res_client.jcr_watchdog_time), 0, 0, NULL, NULL, NULL },
{ "AlwaysUseLmdb", CFG_TYPE_BOOL, ITEM(res_client.always_use_lmdb), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
{ "LmdbThreshold", CFG_TYPE_PINT32, ITEM(res_client.lmdb_threshold), 0, 0, NULL, NULL, NULL },
{ "SecureEraseCommand", CFG_TYPE_STR, ITEM(res_client.secure_erase_cmdline), 0, 0, NULL, NULL, NULL },
{ NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
};

Expand Down Expand Up @@ -360,6 +361,9 @@ void free_resource(RES *sres, int type)
if (res->res_client.allowed_job_cmds) {
delete res->res_client.allowed_job_cmds;
}
if (res->res_client.secure_erase_cmdline) {
free(res->res_client.secure_erase_cmdline);
}
break;
case R_MSGS:
if (res->res_msgs.mail_cmd) {
Expand Down
1 change: 1 addition & 0 deletions src/filed/filed_conf.h
Expand Up @@ -116,6 +116,7 @@ class CLIENTRES : public BRSRES {
alist *allowed_job_cmds; /* Only allow the following Job commands to be executed */
TLS_CONTEXT *tls_ctx; /* Shared TLS Context */
char *verid; /* Custom Id to print in version command */
char *secure_erase_cmdline; /* Cmdline to execute to perform secure erase of file */
uint64_t max_bandwidth_per_job; /* Bandwidth limitation (global) */
};

Expand Down
6 changes: 6 additions & 0 deletions src/filed/status.c
Expand Up @@ -150,6 +150,12 @@ static void list_status_header(STATUS_PKT *sp)
"bwlimit=%skB/s\n"), sizeof(boffset_t), sizeof(size_t),
debug_level, get_trace(), edit_uint64_with_commas(me->max_bandwidth_per_job / 1024, b1));
sendit(msg, len, sp);

if (me->secure_erase_cmdline) {
len = Mmsg(msg, _(" secure erase command='%s'\n"), me->secure_erase_cmdline);
sendit(msg, len, sp);
}

len = list_fd_plugins(msg);
if (len > 0) {
sendit(msg, len, sp);
Expand Down
6 changes: 4 additions & 2 deletions src/findlib/create_file.c
Expand Up @@ -157,13 +157,15 @@ int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
if (exists && attr->type != FT_RAW && attr->type != FT_FIFO) {
/* Get rid of old copy */
Dmsg1(400, "unlink %s\n", attr->ofname);
if (unlink(attr->ofname) == -1) {
if (secure_erase(jcr, attr->ofname) == -1) {
berrno be;

Qmsg(jcr, M_ERROR, 0, _("File %s already exists and could not be replaced. ERR=%s.\n"),
attr->ofname, be.bstrerror());
attr->ofname, be.bstrerror());
/* Continue despite error */
}
}

/*
* Here we do some preliminary work for all the above
* types to create the path to the file if it does
Expand Down
4 changes: 0 additions & 4 deletions src/lib/bpipe.c
Expand Up @@ -253,11 +253,7 @@ int close_bpipe(BPIPE *bpipe)
}
Dmsg1(800, "child status=%d\n", status & ~b_errno_exit);
} else if (WIFSIGNALED(chldstatus)) { /* process died */
#ifndef HAVE_WIN32
status = WTERMSIG(chldstatus);
#else
status = 1; /* fake child status */
#endif
Dmsg1(800, "Child died from signal %d\n", status);
status |= b_errno_signal; /* exit signal returned */
}
Expand Down

0 comments on commit a8d8270

Please sign in to comment.