- blocksize recognition code.
For 1.30 release:
+- Add Signature type to File DB record.
+
- CD into subdirectory when open()ing files for backup to
speed up things. Test with testfind().
- Add prefixlinks to where or not where absolute links to FD.
#define STREAM_SPARSE_GZIP_DATA 7
#define STREAM_PROGRAM_NAMES 8 /* program names for program data */
#define STREAM_PROGRAM_DATA 9 /* Data needing program */
+#define STREAM_SHA1_SIGNATURE 10 /* SHA1 signature for the file */
+
+/*
+ * Internal code for Signature types
+ */
+#define NO_SIG 0
+#define MD5_SIG 1
+#define SHA1_SIG 2
/* Size of File Address stored in STREAM_SPARSE_DATA. Do NOT change! */
#define SPARSE_FADDR_SIZE (sizeof(uint64_t))
Dmsg0(200, "Done db_open_database()\n");
mdb->cfd = -1;
V(mutex);
+ Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is for TESTING ONLY!\n"));
+ Jmsg(jcr, M_WARNING, 0, _("You should use either SQLite or MySQL\n"));
+
return mdb;
}
return stat;
}
-int db_add_MD5_to_file_record(void *jcr, B_DB *mdb, FileId_t FileId, char *MD5)
+int db_add_SIG_to_file_record(void *jcr, B_DB *mdb, FileId_t FileId, char *SIG, int type)
{
return 1;
}
JobId_t MarkId;
char LStat[256];
/* int Status; */
- char MD5[50];
+ char SIG[50];
+ int SigType; /* NO_SIG/MD5_SIG/SHA1_SIG */
} FILE_DBR;
/* Pool record -- same format as database */
int db_update_job_end_record(void *jcr, B_DB *db, JOB_DBR *jr);
int db_update_pool_record(void *jcr, B_DB *db, POOL_DBR *pr);
int db_update_media_record(void *jcr, B_DB *db, MEDIA_DBR *mr);
-int db_add_MD5_to_file_record(void *jcr, B_DB *mdb, FileId_t FileId, char *MD5);
+int db_add_SIG_to_file_record(void *jcr, B_DB *mdb, FileId_t FileId, char *SIG, int type);
int db_mark_file_record(void *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId);
#endif /* __SQL_PROTOS_H */
} else {
fdbr->FileId = (FileId_t)str_to_int64(row[0]);
bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
- bstrncpy(fdbr->MD5, row[2], sizeof(fdbr->MD5));
+ bstrncpy(fdbr->SIG, row[2], sizeof(fdbr->SIG));
stat = 1;
}
} else {
*/
/* Update the attributes record by adding the MD5 signature */
int
-db_add_MD5_to_file_record(void *jcr, B_DB *mdb, FileId_t FileId, char *MD5)
+db_add_SIG_to_file_record(void *jcr, B_DB *mdb, FileId_t FileId, char *SIG,
+ int type)
{
int stat;
db_lock(mdb);
- Mmsg(&mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%u", MD5, FileId);
+ Mmsg(&mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%u", SIG, FileId);
stat = UPDATE_DB(jcr, mdb, mdb->cmd);
db_unlock(mdb);
return stat;
if (!db_create_file_attributes_record(jcr, jcr->db, &ar)) {
Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
}
- /* Save values for MD5 update */
+ /* Save values for SIG update */
jcr->FileId = ar.FileId;
jcr->FileIndex = FileIndex;
- } else if (Stream == STREAM_MD5_SIGNATURE) {
+ } else if (Stream == STREAM_MD5_SIGNATURE || Stream == STREAM_SHA1_SIGNATURE) {
fname = p;
if (jcr->FileIndex != FileIndex) {
- Jmsg(jcr, M_WARNING, 0, "Got MD5 but not same File as attributes\n");
+ Jmsg(jcr, M_WARNING, 0, "Got MD5/SHA1 but not same File as attributes\n");
} else {
- /* Update MD5 signature in catalog */
- char MD5buf[50]; /* 24 bytes should be enough */
- bin_to_base64(MD5buf, fname, 16);
- Dmsg2(190, "MD5len=%d MD5=%s\n", strlen(MD5buf), MD5buf);
- if (!db_add_MD5_to_file_record(jcr, jcr->db, jcr->FileId, MD5buf)) {
- Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5. %s"),
+ /* Update signature in catalog */
+ char SIGbuf[50]; /* 24 bytes should be enough */
+ int len, type;
+ if (Stream == STREAM_MD5_SIGNATURE) {
+ len = 16;
+ type = MD5_SIG;
+ } else {
+ len = 20;
+ type = SHA1_SIG;
+ }
+ bin_to_base64(SIGbuf, fname, len);
+ Dmsg3(190, "SIGlen=%d SIG=%s type=%d\n", strlen(SIGbuf), SIGbuf, Stream);
+ if (!db_add_SIG_to_file_record(jcr, jcr->db, jcr->FileId, SIGbuf, type)) {
+ Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5/SHA1. %s"),
db_strerror(jcr->db));
}
}
{NULL, NULL, NULL, 0, 0, 0}
};
+/* FileOptions resource
+ *
+ * name handler value code flags default_value
+ */
+static struct res_items fo_items[] = {
+ {"name", store_name, ITEM(res_fo.hdr.name), 0, ITEM_REQUIRED, 0},
+ {"description", store_str, ITEM(res_fo.hdr.desc), 0, 0, 0},
+ {"replace", store_replace, ITEM(res_fo.replace), REPLACE_ALWAYS, ITEM_DEFAULT, 0},
+ {NULL, NULL, NULL, 0, 0, 0}
+};
+
+
/* FileSet resource
*
* name handler value code flags default_value
{"storage", store_items, R_STORAGE, NULL},
{"catalog", cat_items, R_CATALOG, NULL},
{"schedule", sch_items, R_SCHEDULE, NULL},
+ {"fileoptions", fo_items, R_FILEOPTIONS, NULL},
{"fileset", fs_items, R_FILESET, NULL},
{"group", group_items, R_GROUP, NULL},
{"pool", pool_items, R_POOL, NULL},
/* Options permitted for each keyword and resulting value */
static struct s_fs_opt FS_options[] = {
{"md5", INC_KW_SIGNATURE, "M"},
+ {"sha1", INC_KW_SIGNATURE, "S"},
{"gzip", INC_KW_COMPRESSION, "Z6"},
{"gzip1", INC_KW_COMPRESSION, "Z1"},
{"gzip2", INC_KW_COMPRESSION, "Z2"},
case T_IDENTIFIER:
case T_UNQUOTED_STRING:
case T_QUOTED_STRING:
- fname = (char *) malloc(lc->str_len + inc_opts_len + 1);
+ fname = (char *)malloc(lc->str_len + inc_opts_len + 1);
strcpy(fname, inc_opts);
strcat(fname, lc->str);
if (res_all.res_fs.have_MD5) {
if (res_all.res_fs.num_excludes == res_all.res_fs.exclude_size) {
res_all.res_fs.exclude_size += 10;
if (res_all.res_fs.exclude_array == NULL) {
- res_all.res_fs.exclude_array = (char **) malloc(sizeof(char *) * res_all.res_fs.exclude_size);
+ res_all.res_fs.exclude_array = (char **)malloc(sizeof(char *) * res_all.res_fs.exclude_size);
} else {
- res_all.res_fs.exclude_array = (char **) realloc(res_all.res_fs.exclude_array,
+ res_all.res_fs.exclude_array = (char **)realloc(res_all.res_fs.exclude_array,
sizeof(char *) * res_all.res_fs.exclude_size);
}
}
* Version $Id$
*/
/*
- Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+ Copyright (C) 2000-2003 2002 Kern Sibbald and John Walker
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
};
typedef struct s_res_job JOB;
+/*
+ * File Options Resource (options for Includes)
+ */
+struct s_res_fo {
+ RES hdr;
+
+ char opts[20]; /* Options string */
+ int replace; /* How (overwrite, ...) */
+ struct s_applyto *applyto; /* applyto strings */
+};
+typedef struct s_res_fo FILEOPTIONS;
+
+struct s_incexc_item {
+ char opts[20]; /* options string */
+ struct s_res_fo *fileopts; /* file options */
+ char name[1]; /* include/exclude name */
+};
+
/*
* FileSet Resource
*
struct s_res_fs {
RES hdr;
+ /* ***FIXME*** each include must have chain of FileOptions */
char **include_array;
int num_includes;
int include_size;
int exclude_size;
int have_MD5; /* set if MD5 initialized */
struct MD5Context md5c; /* MD5 of include/exclude */
- char MD5[50]; /* base 64 representation of MD5 */
+ char MD5[30]; /* base 64 representation of MD5 */
};
typedef struct s_res_fs FILESET;
-/*
- * FileOptions Resource (options for Includes)
- */
-struct s_res_fo {
- RES hdr;
-
- char opts[50]; /* Options string */
- struct s_applyto *applyto; /* applyto strings */
-};
-typedef struct s_res_fo FILEOPTIONS;
-
/*
* Schedule Resource
*
long file_index;
int stream, len;
char *attr, *p, *fn;
- char Opts_MD5[MAXSTRING]; /* either Verify opts or MD5 signature */
- char MD5[MAXSTRING];
+ char Opts_SIG[MAXSTRING]; /* either Verify opts or MD5/SHA1 signature */
+ char SIG[MAXSTRING];
jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
- if ((len = sscanf(fd->msg, "%ld %d %s", &file_index, &stream, Opts_MD5)) != 3) {
+ if ((len = sscanf(fd->msg, "%ld %d %s", &file_index, &stream, Opts_SIG)) != 3) {
Jmsg(jcr, M_FATAL, 0, _("<filed: bad attributes, expected 3 fields got %d\n\
msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
set_jcr_job_status(jcr, JS_ErrorTerminated);
skip_spaces(&p);
skip_nonspaces(&p); /* skip Stream */
skip_spaces(&p);
- skip_nonspaces(&p); /* skip Opts_MD5 */
+ skip_nonspaces(&p); /* skip Opts_SHA1 */
p++; /* skip space */
fn = jcr->fname;
while (*p != 0) {
continue;
}
jcr->FileId = ar.FileId;
- } else if (stream == STREAM_MD5_SIGNATURE) {
+ } else if (stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE) {
if (jcr->FileIndex != (uint32_t)file_index) {
- Jmsg2(jcr, M_ERROR, 0, _("MD5 index %d not same as attributes %d\n"),
+ Jmsg2(jcr, M_ERROR, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
file_index, jcr->FileIndex);
set_jcr_job_status(jcr, JS_Error);
continue;
}
- db_escape_string(MD5, Opts_MD5, strlen(Opts_MD5));
- Dmsg2(120, "MD5len=%d MD5=%s\n", strlen(MD5), MD5);
- if (!db_add_MD5_to_file_record(jcr, jcr->db, jcr->FileId, MD5)) {
+ db_escape_string(SIG, Opts_SIG, strlen(Opts_SIG));
+ Dmsg2(120, "SIGlen=%d SIG=%s\n", strlen(SIG), SIG);
+ if (!db_add_SIG_to_file_record(jcr, jcr->db, jcr->FileId, SIG,
+ stream==STREAM_MD5_SIGNATURE?MD5_SIG:SHA1_SIG)) {
Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
set_jcr_job_status(jcr, JS_Error);
}
int stat = JS_Terminated;
char buf[MAXSTRING];
POOLMEM *fname = get_pool_memory(PM_MESSAGE);
- int do_MD5 = FALSE;
+ int do_SIG = NO_SIG;
long file_index = 0;
memset(&fdbr, 0, sizeof(FILE_DBR));
Dmsg0(20, "bdird: waiting to receive file attributes\n");
/*
- * Get Attributes and MD5 Signature from File daemon
+ * Get Attributes and Signature from File daemon
* We expect:
* FileIndex
* Stream
- * Options or MD5
+ * Options or SIG (MD5/SHA1)
* Filename
* Attributes
* Link name ???
while ((n=bget_msg(fd, 0)) >= 0 && !job_cancelled(jcr)) {
int stream;
char *attr, *p, *fn;
- char Opts_MD5[MAXSTRING]; /* Verify Opts or MD5 signature */
+ char Opts_SIG[MAXSTRING]; /* Verify Opts or MD5/SHA1 signature */
fname = check_pool_memory_size(fname, fd->msglen);
jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
- Dmsg1(400, "Atts+MD5=%s\n", fd->msg);
+ Dmsg1(400, "Atts+SIG=%s\n", fd->msg);
if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &stream,
- Opts_MD5)) != 3) {
+ fname)) != 3) {
Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n\
mslen=%d msg=%s\n"), len, fd->msglen, fd->msg);
goto bail_out;
}
+ /*
+ * We read the Options or Signature into fname
+ * to prevent overrun, now copy it to proper location.
+ */
+ bstrncpy(Opts_SIG, fname, sizeof(Opts_SIG));
p = fd->msg;
skip_nonspaces(&p); /* skip FileIndex */
skip_spaces(&p);
skip_nonspaces(&p); /* skip Stream */
skip_spaces(&p);
- skip_nonspaces(&p); /* skip Opts_MD5 */
+ skip_nonspaces(&p); /* skip Opts_SIG */
p++; /* skip space */
fn = fname;
while (*p != 0) {
jcr->JobFiles++;
jcr->FileIndex = file_index; /* remember attribute file_index */
decode_stat(attr, &statf); /* decode file stat packet */
- do_MD5 = FALSE;
+ do_SIG = NO_SIG;
jcr->fn_printed = FALSE;
strcpy(jcr->fname, fname); /* move filename into JCR */
}
Dmsg3(400, "Found %s in catalog. inx=%d Opts=%s\n", jcr->fname,
- file_index, Opts_MD5);
+ file_index, Opts_SIG);
decode_stat(fdbr.LStat, &statc); /* decode catalog stat */
/*
* Loop over options supplied by user and verify the
* fields he requests.
*/
- for (p=Opts_MD5; *p; p++) {
+ for (p=Opts_SIG; *p; p++) {
char ed1[30], ed2[30];
switch (*p) {
case 'i': /* compare INODEs */
break;
case '5': /* compare MD5 */
Dmsg1(500, "set Do_MD5 for %s\n", jcr->fname);
- do_MD5 = TRUE;
+ do_SIG = MD5_SIG;
+ break;
+ case '1': /* compare SHA1 */
+ do_SIG = SHA1_SIG;
break;
case ':':
case 'V':
}
}
/*
- * Got MD5 Signature from Storage daemon
- * It came across in the Opts_MD5 field.
+ * Got SIG Signature from Storage daemon
+ * It came across in the Opts_SIG field.
*/
- } else if (stream == STREAM_MD5_SIGNATURE) {
- Dmsg2(400, "stream=MD5 inx=%d MD5=%s\n", file_index, Opts_MD5);
+ } else if (stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE) {
+ Dmsg2(400, "stream=SIG inx=%d SIG=%s\n", file_index, Opts_SIG);
/*
- * When ever we get an MD5 signature is MUST have been
+ * When ever we get a signature is MUST have been
* preceded by an attributes record, which sets attr_file_index
*/
if (jcr->FileIndex != (uint32_t)file_index) {
- Jmsg2(jcr, M_FATAL, 0, _("MD5 index %d not same as attributes %d\n"),
+ Jmsg2(jcr, M_FATAL, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
file_index, jcr->FileIndex);
goto bail_out;
}
- if (do_MD5) {
- db_escape_string(buf, Opts_MD5, strlen(Opts_MD5));
- if (strcmp(buf, fdbr.MD5) != 0) {
+ if (do_SIG) {
+ db_escape_string(buf, Opts_SIG, strlen(Opts_SIG));
+ if (strcmp(buf, fdbr.SIG) != 0) {
prt_fname(jcr);
if (debug_level >= 10) {
- Jmsg(jcr, M_INFO, 0, _(" MD5 not same. File=%s Cat=%s\n"), buf, fdbr.MD5);
+ Jmsg(jcr, M_INFO, 0, _(" %s not same. File=%s Cat=%s\n"),
+ stream==STREAM_MD5_SIGNATURE?"MD5":"SHA1", buf, fdbr.SIG);
} else {
- Jmsg(jcr, M_INFO, 0, _(" MD5 differs.\n"));
+ Jmsg(jcr, M_INFO, 0, _(" %s differs.\n"),
+ stream==STREAM_MD5_SIGNATURE?"MD5":"SHA1");
}
stat = JS_Differences;
}
- do_MD5 = FALSE;
+ do_SIG = FALSE;
}
}
jcr->JobFiles = file_index;
char attribsEx[MAXSTRING];
int stat, stream;
struct MD5Context md5c;
+ struct SHA1Context sha1c;
int gotMD5 = 0;
- unsigned char signature[16];
+ int gotSHA1 = 0;
+ unsigned char signature[25]; /* large enough for either signature */
BSOCK *sd;
JCR *jcr = (JCR *)ijcr;
POOLMEM *msgsave;
if (ff_pkt->flags & FO_MD5) {
MD5Init(&md5c);
+ } else if (ff_pkt->flags & FO_SHA1) {
+ SHA1Init(&sha1c);
}
/*
if (ff_pkt->flags & FO_MD5) {
MD5Update(&md5c, (unsigned char *)rbuf, sd->msglen);
gotMD5 = 1;
+ } else if (ff_pkt->flags & FO_SHA1) {
+ SHA1Update(&sha1c, (unsigned char *)rbuf, sd->msglen);
+ gotSHA1 = 1;
}
#ifdef HAVE_LIBZ
sd->msglen = 16;
bnet_send(sd);
bnet_sig(sd, BNET_EOD); /* end of MD5 */
+#endif
+ gotMD5 = 0;
+ } else if (gotSHA1 && ff_pkt->flags & FO_SHA1) {
+ /* Terminate any SHA1 signature and send it to Storage daemon and the Director */
+ SHA1Final(&sha1c, signature);
+#ifndef NO_FD_SEND_TEST
+ bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_SHA1_SIGNATURE);
+ Dmsg1(100, "bfiled>stored:header %s\n", sd->msg);
+ memcpy(sd->msg, signature, 20);
+ sd->msglen = 20;
+ bnet_send(sd);
+ bnet_sig(sd, BNET_EOD); /* end of SHA1 */
#endif
gotMD5 = 0;
}
* 2. Stream data
* a. Attributes (Unix or Win32)
* or b. File data for the file
- * or c. Possibly MD5 record
+ * or c. Possibly MD5 or SHA1 record
* 3. Repeat step 1
*/
while (bnet_recv(sd) >= 0 && !job_cancelled(jcr)) {
set_attributes(jcr, fname, ofile, lname, type, stream,
&statp, attribsEx, &ofd);
extract = FALSE;
- } else if (stream != STREAM_MD5_SIGNATURE) {
+ } else if (!(stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE)) {
Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
}
}
/*
* Called here by find() for each file.
*
- * Find the file, compute the MD5 and send it back to the Director
+ * Find the file, compute the MD5 or SHA1 and send it back to the Director
*/
static int verify_file(FF_PKT *ff_pkt, void *pkt)
{
int32_t n;
int fid, stat;
struct MD5Context md5c;
- unsigned char signature[20];
+ struct SHA1Context sha1c;
+ unsigned char signature[25]; /* large enough for either */
BSOCK *dir;
JCR *jcr = (JCR *)pkt;
/* If file opened, compute MD5 */
if (fid >= 0 && ff_pkt->flags & FO_MD5) {
- char MD5buf[50]; /* 24 should do */
-
+ char MD5buf[40]; /* 24 should do */
MD5Init(&md5c);
-
while ((n=read(fid, jcr->big_buf, jcr->buf_size)) > 0) {
MD5Update(&md5c, ((unsigned char *) jcr->big_buf), n);
jcr->JobBytes += n;
Jmsg(jcr, M_WARNING, -1, _("Error reading file %s: ERR=%s\n"),
ff_pkt->fname, strerror(errno));
}
-
MD5Final(signature, &md5c);
bin_to_base64(MD5buf, (char *)signature, 16); /* encode 16 bytes */
bnet_fsend(dir, "%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_SIGNATURE, MD5buf,
jcr->JobFiles);
Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg);
+ } else if (fid >= 0 && ff_pkt->flags & FO_SHA1) {
+ char SHA1buf[40]; /* 24 should do */
+ SHA1Init(&sha1c);
+ while ((n=read(fid, jcr->big_buf, jcr->buf_size)) > 0) {
+ SHA1Update(&sha1c, ((unsigned char *) jcr->big_buf), n);
+ jcr->JobBytes += n;
+ }
+ if (n < 0) {
+ Jmsg(jcr, M_WARNING, -1, _("Error reading file %s: ERR=%s\n"),
+ ff_pkt->fname, strerror(errno));
+ }
+ SHA1Final(&sha1c, signature);
+
+ bin_to_base64(SHA1buf, (char *)signature, 20); /* encode 20 bytes */
+ Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, SHA1buf);
+ bnet_fsend(dir, "%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_SIGNATURE,
+ SHA1buf, jcr->JobFiles);
+ Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg);
}
if (fid >= 0) {
close(fid);
jcr->JobFiles);
Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg);
- } else if (stream != STREAM_MD5_SIGNATURE) {
+ /* If SHA1 stream */
+ } else if (stream == STREAM_SHA1_SIGNATURE) {
+ char SHA1buf[30];
+ bin_to_base64(SHA1buf, (char *)sd->msg, 20); /* encode 20 bytes */
+ Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, SHA1buf);
+ bnet_fsend(dir, "%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_SIGNATURE,
+ SHA1buf, jcr->JobFiles);
+ Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg);
+ } else {
Pmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
}
}
#define FO_IF_NEWER 0x020 /* replace if newer */
#define FO_NOREPLACE 0x040 /* never replace */
#define FO_READFIFO 0x080 /* read data from fifo */
+#define FO_SHA1 0x100 /* Do SHA1 checksum */
/*
* Options saved in "options" of include list
#define OPT_replace_if_newer 0x20 /* replace file if newer */
#define OPT_never_replace 0x40 /* never replace */
#define OPT_read_fifo 0x80 /* read data from fifo (named pipe) */
+#define OPT_compute_SHA1 0x100 /* compute SHA1 of file's data */
struct s_included_file {
case 'M': /* MD5 */
inc->options |= OPT_compute_MD5;
break;
+ case 'S':
+ inc->options |= OPT_compute_SHA1;
+ break;
case 'n':
inc->options |= OPT_never_replace;
break;
cram-md5.c crc32.c daemon.c edit.c fnmatch.c \
hmac.c idcache.c jcr.c lex.c \
md5.c message.c mem_pool.c parse_conf.c \
- queue.c rwlock.c serial.c \
+ queue.c rwlock.c serial.c sha1.c \
signal.c smartall.c tree.c util.c watchdog.c workq.c
# immortal.c filesys.c
cram-md5.o crc32.o daemon.o edit.o fnmatch.o \
hmac.o idcache.o jcr.o lex.o \
md5.o message.o mem_pool.o parse_conf.o \
- queue.o rwlock.o serial.o \
+ queue.o rwlock.o serial.o sha1.o \
signal.o smartall.o tree.o util.o watchdog.o workq.o
# immortal.o filesys.o
clean:
$(RMF) *.a core a.out *.o *.bak *.tex *.pdf *~ *.intpro *.extpro 1 2 3
- $(RMF) rwlock_test
+ $(RMF) rwlock_test md5 sha1
realclean: clean
$(RMF) tags
*/
/*
- Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+ Copyright (C) 2000-2003 Kern Sibbald and John Walker
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
#include "fnmatch.h"
#endif
#include "md5.h"
+#include "sha1.h"
#include "tree.h"
#include "watchdog.h"
#include "bpipe.h"
buf[2] += c;
buf[3] += d;
}
+
+#ifdef MD5_SUM
+/*
+ * Reads a single ASCII file and prints the HEX md5 sum.
+ */
+#include <stdio.h>
+int main(int argc, char *argv[])
+{
+ FILE *fd;
+ MD5Context ctx;
+ char buf[5000];
+ char signature[20];
+
+ if (argc < 1) {
+ printf("Must have filename\n");
+ exit(1);
+ }
+ fd = fopen(argv[1], "r");
+ if (!fd) {
+ printf("Could not open %s: ERR=%s\n", argv[1], strerror(errno));
+ exit(1);
+ }
+ MD5Init(&ctx);
+ while (fgets(buf, sizeof(buf), fd)) {
+ MD5Update(&ctx, (unsigned char *)buf, strlen(buf));
+ }
+ MD5Final((unsigned char *)signature, &ctx);
+ for (int i=0; i < 16; i++) {
+ printf("%02x", signature[i]& 0xFF);
+ }
+ printf(" %s\n", argv[1]);
+}
+#endif
(((word) << (bits)) | ((word) >> (32-(bits))))
/* Local Function Prototyptes */
-void SHA1PadMessage(SHA1Context *);
-void SHA1ProcessMessageBlock(SHA1Context *);
+static void SHA1PadMessage(SHA1Context *);
+static void SHA1ProcessMessageBlock(SHA1Context *);
/*
- * SHA1Reset
+ * SHA1Init
*
* Description:
* This function will initialize the SHA1Context in preparation
* sha Error Code.
*
*/
-int SHA1Reset(SHA1Context *context)
+int SHA1Init(SHA1Context *context)
{
if (!context)
{
}
/*
- * SHA1Result
+ * SHA1Final
*
* Description:
* This function will return the 160-bit message digest into the
* sha Error Code.
*
*/
-int SHA1Result( SHA1Context *context,
- uint8_t Message_Digest[SHA1HashSize])
+int SHA1Final(SHA1Context *context,
+ uint8_t Message_Digest[SHA1HashSize])
{
int i;
- if (!context || !Message_Digest)
- {
+ if (!context || !Message_Digest) {
return shaNull;
}
- if (context->Corrupted)
- {
+ if (context->Corrupted) {
return context->Corrupted;
}
- if (!context->Computed)
- {
+ if (!context->Computed) {
SHA1PadMessage(context);
- for(i=0; i<64; ++i)
- {
+ for(i=0; i<64; ++i) {
/* message may be sensitive, clear it out */
context->Message_Block[i] = 0;
}
}
- for(i = 0; i < SHA1HashSize; ++i)
- {
+ for(i = 0; i < SHA1HashSize; ++i) {
Message_Digest[i] = context->Intermediate_Hash[i>>2]
- >> 8 * ( 3 - ( i & 0x03 ) );
+ >> 8 * ( 3 - ( i & 0x03 ) );
}
return shaSuccess;
}
/*
- * SHA1Input
+ * SHA1Update
*
* Description:
* This function accepts an array of octets as the next portion
* sha Error Code.
*
*/
-int SHA1Input( SHA1Context *context,
- const uint8_t *message_array,
- unsigned length)
+int SHA1Update(SHA1Context *context,
+ const uint8_t *message_array,
+ unsigned length)
{
- if (!length)
- {
+ if (!length) {
return shaSuccess;
}
- if (!context || !message_array)
- {
+ if (!context || !message_array) {
return shaNull;
}
- if (context->Computed)
- {
+ if (context->Computed) {
context->Corrupted = shaStateError;
return shaStateError;
}
- if (context->Corrupted)
- {
+ if (context->Corrupted) {
return context->Corrupted;
}
- while(length-- && !context->Corrupted)
- {
- context->Message_Block[context->Message_Block_Index++] =
- (*message_array & 0xFF);
-
- context->Length_Low += 8;
- if (context->Length_Low == 0)
- {
- context->Length_High++;
- if (context->Length_High == 0)
- {
- /* Message is too long */
- context->Corrupted = 1;
- }
- }
-
- if (context->Message_Block_Index == 64)
- {
- SHA1ProcessMessageBlock(context);
- }
-
- message_array++;
+ while(length-- && !context->Corrupted) {
+ context->Message_Block[context->Message_Block_Index++] =
+ (*message_array & 0xFF);
+
+ context->Length_Low += 8;
+ if (context->Length_Low == 0) {
+ context->Length_High++;
+ if (context->Length_High == 0) {
+ /* Message is too long */
+ context->Corrupted = 1;
+ }
+ }
+
+ if (context->Message_Block_Index == 64) {
+ SHA1ProcessMessageBlock(context);
+ }
+
+ message_array++;
}
return shaSuccess;
*
*
*/
-void SHA1ProcessMessageBlock(SHA1Context *context)
+static void SHA1ProcessMessageBlock(SHA1Context *context)
{
const uint32_t K[] = { /* Constants defined in SHA-1 */
0x5A827999,
/*
* Initialize the first 16 words in the array W
*/
- for(t = 0; t < 16; t++)
- {
+ for(t = 0; t < 16; t++) {
W[t] = context->Message_Block[t * 4] << 24;
W[t] |= context->Message_Block[t * 4 + 1] << 16;
W[t] |= context->Message_Block[t * 4 + 2] << 8;
W[t] |= context->Message_Block[t * 4 + 3];
}
- for(t = 16; t < 80; t++)
- {
+ for(t = 16; t < 80; t++) {
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
D = context->Intermediate_Hash[3];
E = context->Intermediate_Hash[4];
- for(t = 0; t < 20; t++)
- {
+ for(t = 0; t < 20; t++) {
temp = SHA1CircularShift(5,A) +
- ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ ((B & C) | ((~B) & D)) + E + W[t] + K[0];
E = D;
D = C;
C = SHA1CircularShift(30,B);
A = temp;
}
- for(t = 20; t < 40; t++)
- {
+ for(t = 20; t < 40; t++) {
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
E = D;
D = C;
A = temp;
}
- for(t = 40; t < 60; t++)
- {
+ for(t = 40; t < 60; t++) {
temp = SHA1CircularShift(5,A) +
- ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
E = D;
D = C;
C = SHA1CircularShift(30,B);
A = temp;
}
- for(t = 60; t < 80; t++)
- {
+ for(t = 60; t < 80; t++) {
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
E = D;
D = C;
*
*/
-void SHA1PadMessage(SHA1Context *context)
+static void SHA1PadMessage(SHA1Context *context)
{
/*
* Check to see if the current message block is too small to hold
* block, process it, and then continue padding into a second
* block.
*/
- if (context->Message_Block_Index > 55)
- {
+ if (context->Message_Block_Index > 55) {
context->Message_Block[context->Message_Block_Index++] = 0x80;
- while(context->Message_Block_Index < 64)
- {
+ while(context->Message_Block_Index < 64) {
context->Message_Block[context->Message_Block_Index++] = 0;
}
SHA1ProcessMessageBlock(context);
- while(context->Message_Block_Index < 56)
- {
+ while(context->Message_Block_Index < 56) {
context->Message_Block[context->Message_Block_Index++] = 0;
}
- }
- else
- {
+ } else {
context->Message_Block[context->Message_Block_Index++] = 0x80;
- while(context->Message_Block_Index < 56)
- {
+ while(context->Message_Block_Index < 56) {
context->Message_Block[context->Message_Block_Index++] = 0;
}
/*
* Perform SHA-1 tests
*/
- for(j = 0; j < 4; ++j)
- {
+ for(j = 0; j < 4; ++j) {
printf( "\nTest %d: %d, '%s'\n",
j+1,
repeatcount[j],
testarray[j]);
- err = SHA1Reset(&sha);
- if (err)
- {
+ err = SHA1Init(&sha);
+ if (err) {
fprintf(stderr, "SHA1Reset Error %d.\n", err );
break; /* out of for j loop */
}
- for(i = 0; i < repeatcount[j]; ++i)
- {
+ for(i = 0; i < repeatcount[j]; ++i) {
- err = SHA1Input(&sha,
+ err = SHA1Input(&sha,
(const unsigned char *) testarray[j],
strlen(testarray[j]));
- if (err)
- {
+ if (err) {
fprintf(stderr, "SHA1Input Error %d.\n", err );
break; /* out of for i loop */
}
}
- err = SHA1Result(&sha, Message_Digest);
- if (err)
- {
+ err = SHA1Final(&sha, Message_Digest);
+ if (err) {
fprintf(stderr,
"SHA1Result Error %d, could not compute message digest.\n",
err );
else
{
printf("\t");
- for(i = 0; i < 20 ; ++i)
- {
+ for(i = 0; i < 20 ; ++i) {
printf("%02X ", Message_Digest[i]);
}
printf("\n");
}
/* Test some error returns */
- err = SHA1Input(&sha,(const unsigned char *) testarray[1], 1);
+ err = SHA1Input(&sha,(const unsigned char *) testarray[1], 1);
printf ("\nError %d. Should be %d.\n", err, shaStateError );
- err = SHA1Reset(0);
+ err = SHA1Init(0);
printf ("\nError %d. Should be %d.\n", err, shaNull );
return 0;
}
#endif /* TEST_DRIVER */
+
+#ifdef SHA1_SUM
+/*
+ * Reads a single ASCII file and prints the HEX sha1 sum.
+ */
+#include <stdio.h>
+int main(int argc, char *argv[])
+{
+ FILE *fd;
+ SHA1Context ctx;
+ char buf[5000];
+ char signature[25];
+
+ if (argc < 1) {
+ printf("Must have filename\n");
+ exit(1);
+ }
+ fd = fopen(argv[1], "r");
+ if (!fd) {
+ printf("Could not open %s: ERR=%s\n", argv[1], strerror(errno));
+ exit(1);
+ }
+ SHA1Init(&ctx);
+ while (fgets(buf, sizeof(buf), fd)) {
+ SHA1Update(&ctx, (unsigned char *)buf, strlen(buf));
+ }
+ SHA1Final(&ctx, (unsigned char *)signature);
+ for (int i=0; i < 20; i++) {
+ printf("%02x", signature[i]& 0xFF);
+ }
+ printf(" %s\n", argv[1]);
+}
+#endif
* sha1.h
*
* Description:
- * This is the header file for code which implements the Secure
- * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
- * April 17, 1995.
+ * This is the header file for code which implements the Secure
+ * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ * April 17, 1995.
*
- * Many of the variable names in this code, especially the
- * single character names, were used because those were the names
- * used in the publication.
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the names
+ * used in the publication.
*
- * Please read the file sha1.c for more information.
+ * Please read the file sha1.c for more information.
*
* Full Copyright Statement
*
/*
* If you do not have the ISO standard stdint.h header file, then you
* must typdef the following:
- * name meaning
- * uint32_t unsigned 32 bit integer
- * uint8_t unsigned 8 bit integer (i.e., unsigned char)
+ * name meaning
+ * uint32_t unsigned 32 bit integer
+ * uint8_t unsigned 8 bit integer (i.e., unsigned char)
* int_least16_t integer of >= 16 bits
*
*/
enum
{
shaSuccess = 0,
- shaNull, /* Null pointer parameter */
- shaInputTooLong, /* input data too long */
- shaStateError /* called Input after Result */
+ shaNull, /* Null pointer parameter */
+ shaInputTooLong, /* input data too long */
+ shaStateError /* called Input after Result */
};
#endif
#define SHA1HashSize 20
{
uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
- uint32_t Length_Low; /* Message length in bits */
- uint32_t Length_High; /* Message length in bits */
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
- /* Index into message block array */
+ /* Index into message block array */
int_least16_t Message_Block_Index;
- uint8_t Message_Block[64]; /* 512-bit message blocks */
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
- int Computed; /* Is the digest computed? */
- int Corrupted; /* Is the message digest corrupted? */
+ int Computed; /* Is the digest computed? */
+ int Corrupted; /* Is the message digest corrupted? */
} SHA1Context;
/*
* Function Prototypes
*/
-int SHA1Reset( SHA1Context *);
-int SHA1Input( SHA1Context *,
- const uint8_t *,
- unsigned int);
-int SHA1Result( SHA1Context *,
- uint8_t Message_Digest[SHA1HashSize]);
+int SHA1Init(SHA1Context *);
+int SHA1Update(SHA1Context *,
+ const uint8_t *,
+ unsigned int);
+int SHA1Final(SHA1Context *,
+ uint8_t Message_Digest[SHA1HashSize]);
#endif
/* Send attributes and MD5 to Director for Catalog */
if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_MD5_SIGNATURE ||
- stream == STREAM_WIN32_ATTRIBUTES) {
+ stream == STREAM_WIN32_ATTRIBUTES || stream == STREAM_SHA1_SIGNATURE) {
if (!jcr->no_attributes) {
if (jcr->spool_attributes && jcr->dir_bsock->spool_fd) {
jcr->dir_bsock->spool = 1;
Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n");
prog_name_msg = 1;
}
- } else if (rec->Stream != STREAM_MD5_SIGNATURE) {
+ } else if (!(rec->Stream == STREAM_MD5_SIGNATURE ||
+ rec->Stream == STREAM_SHA1_SIGNATURE)) {
Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec->Stream, rec->data);
}
}
static int create_fileset_record(B_DB *db, FILESET_DBR *fsr);
static int create_jobmedia_record(B_DB *db, JCR *jcr);
static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId);
-static int update_MD5_record(B_DB *db, char *MD5buf, DEV_RECORD *rec);
+static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type);
/* Global variables */
} else if (rec->Stream == STREAM_MD5_SIGNATURE) {
- char MD5buf[30];
+ char MD5buf[50];
bin_to_base64(MD5buf, (char *)rec->data, 16); /* encode 16 bytes */
if (verbose > 1) {
Pmsg1(000, _("Got MD5 record: %s\n"), MD5buf);
}
- update_MD5_record(db, MD5buf, rec);
+ update_SIG_record(db, MD5buf, rec, MD5_SIG);
+
+ } else if (rec->Stream == STREAM_SHA1_SIGNATURE) {
+ char SIGbuf[50];
+ bin_to_base64(SIGbuf, (char *)rec->data, 20); /* encode 20 bytes */
+ if (verbose > 1) {
+ Pmsg1(000, _("Got SHA1 record: %s\n"), SIGbuf);
+ }
+ update_SIG_record(db, SIGbuf, rec, SHA1_SIG);
+
} else if (rec->Stream == STREAM_PROGRAM_NAMES) {
if (verbose) {
}
/*
- * Simulate the database call that updates the MD5 record
+ * Simulate the database call that updates the MD5/SHA1 record
*/
-static int update_MD5_record(B_DB *db, char *MD5buf, DEV_RECORD *rec)
+static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type)
{
JCR *mjcr;
mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
if (!mjcr) {
if (mr.VolJobs > 0) {
- Pmsg2(000, _("Could not find SessId=%d SessTime=%d for MD5 record.\n"),
+ Pmsg2(000, _("Could not find SessId=%d SessTime=%d for MD5/SHA1 record.\n"),
rec->VolSessionId, rec->VolSessionTime);
} else {
ignored_msgs++;
return 1;
}
- if (!db_add_MD5_to_file_record(bjcr, db, mjcr->FileId, MD5buf)) {
- Pmsg1(0, _("Could not add MD5 to File record. ERR=%s\n"), db_strerror(db));
+ if (!db_add_SIG_to_file_record(bjcr, db, mjcr->FileId, SIGbuf, type)) {
+ Pmsg1(0, _("Could not add MD5/SHA1 to File record. ERR=%s\n"), db_strerror(db));
free_jcr(mjcr);
return 0;
}
if (verbose > 1) {
- Pmsg0(000, _("Updated MD5 record\n"));
+ Pmsg0(000, _("Updated MD5/SHA1 record\n"));
}
free_jcr(mjcr);
return 1;
changer = edit_device_codes(jcr, changer,
jcr->device->changer_command, "load");
status = run_program(changer, timeout, NULL);
+ if (status == 0) {
+ Jmsg(jcr, M_INFO, 0, _("Autochanger \"load slot\" status is OK.\n"));
+ } else {
+ Jmsg(jcr, M_INFO, 0, _("Bad autochanger \"load slot\" status = %d.\n"),
+ status);
+ }
Dmsg2(100, "load slot %d status=%d\n", slot, status);
}
free_pool_memory(changer);
return "DATA";
case STREAM_MD5_SIGNATURE:
return "MD5";
+ case STREAM_SHA1_SIGNATURE:
+ return "SHA1";
case STREAM_GZIP_DATA:
return "GZIP";
case STREAM_WIN32_ATTRIBUTES:
return "contDATA";
case -STREAM_MD5_SIGNATURE:
return "contMD5";
+ case -STREAM_SHA1_SIGNATURE:
+ return "contSHA1";
case -STREAM_GZIP_DATA:
return "contGZIP";
case -STREAM_WIN32_ATTRIBUTES: