2 Trivial tripwire-like system
4 Copyright (C) Andrew Tridgell 2001
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
42 static TDB_CONTEXT *tdb;
48 static struct ignore *ignore_list;
50 static void tsums_dir(const char *dname);
52 static void fatal(const char *format, ...)
58 vasprintf(&ptr, format, ap);
61 if (!ptr || !*ptr) return;
63 fprintf(stderr, "%s", ptr);
70 static void dump_ignored(void)
73 for (ign=ignore_list; ign; ign=ign->next) {
74 printf("Ignoring %s\n", ign->pattern);
78 static void flush_ignored(void)
81 for (ign=ignore_list; ign; ign=ign->next) {
84 asprintf(&keystr, "IGNORE:%s", ign->pattern);
86 key.dsize = strlen(keystr)+1;
93 static void report_difference(const char *fname,
94 struct sum_struct *sum2,
95 struct sum_struct *sum1)
98 printf("(%c%c%c%c%c%c%c%c%c%c%c)\t%s\n",
99 sum1->ctime==sum2->ctime?' ':'c',
100 sum1->mtime==sum2->mtime?' ':'m',
101 sum1->mode==sum2->mode?' ':'p',
102 sum1->uid==sum2->uid?' ':'u',
103 sum1->gid==sum2->gid?' ':'g',
104 sum1->inode==sum2->inode?' ':'i',
105 sum1->device==sum2->device?' ':'d',
106 sum1->rdev==sum2->rdev?' ':'r',
107 sum1->nlink==sum2->nlink?' ':'l',
108 sum1->size==sum2->size?' ':'s',
109 do_quick || memcmp(sum1->sum, sum2->sum, 16)==0?' ':'4',
114 static int link_checksum(const char *fname, char sum[16])
120 n = readlink(fname, lname, sizeof(lname));
121 if (n == -1) return -1;
124 mdfour_update(&md, lname, n);
125 mdfour_result(&md, sum);
130 static int file_checksum(const char *fname, char sum[16])
134 unsigned char buf[64*1024];
136 fd = open(fname,O_RDONLY);
137 if (fd == -1) return -1;
142 int n = read(fd, buf, sizeof(buf));
144 mdfour_update(&md, buf, n);
149 mdfour_result(&md, sum);
153 static void ignore_file(const char *fname)
159 asprintf(&keystr, "IGNORE:%s", fname);
161 key.dsize = strlen(keystr)+1;
162 data.dptr = (void *)&one;
163 data.dsize = sizeof(one);
165 tdb_store(tdb, key, data, TDB_REPLACE);
167 printf("Added %s\n", keystr);
171 static int is_ignored(const char *fname)
174 for (ign=ignore_list; ign; ign=ign->next) {
175 if (fnmatch(ign->pattern, fname, 0) == 0) return 1;
181 static void tsums_file(const char *fname)
184 struct sum_struct sum;
185 struct sum_struct old;
189 if (lstat(fname, &st) != 0) return;
191 if (is_ignored(fname)) goto next;
193 bzero(&sum, sizeof(sum));
194 sum.mtime = st.st_mtime;
195 sum.ctime = st.st_ctime;
196 sum.mode = st.st_mode;
199 sum.device = st.st_dev;
200 sum.inode = st.st_ino;
201 sum.nlink = st.st_nlink;
202 sum.size = st.st_size;
203 if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
204 sum.rdev = st.st_rdev;
207 if (S_ISLNK(st.st_mode)) {
208 link_checksum(fname, &sum.sum[0]);
209 } else if (S_ISREG(st.st_mode) && !do_quick) {
210 file_checksum(fname, &sum.sum[0]);
213 asprintf(&keystr, "FILE:%s", fname);
215 key.dptr = (void *)keystr;
216 key.dsize = strlen(keystr)+1;
217 data = tdb_fetch(tdb, key);
219 if (!data.dptr) goto update;
221 if (data.dsize==sizeof(sum) &&
222 memcmp(&sum, data.dptr, sizeof(sum)) == 0) {
223 /* nothings changed */
227 if (memcmp(&sum, data.dptr, MIN(data.dsize,sizeof(sum))) == 0) {
228 /* data structure extended */
229 if (verbose) printf("old record size (%d/%d) - updating\n",
230 data.dsize, sizeof(sum));
234 bzero(&old, sizeof(old));
235 memcpy(&old, data.dptr, MIN(sizeof(old), data.dsize));
238 old.ctime == sum.ctime &&
239 old.mtime == sum.mtime &&
240 old.uid == sum.uid &&
241 old.gid == sum.gid &&
242 old.mode == sum.mode &&
243 old.device == sum.device &&
244 old.inode == sum.inode &&
245 old.rdev == sum.rdev &&
246 old.nlink == sum.nlink &&
247 old.size == sum.size) {
248 /* quick properties are the same */
252 report_difference(fname, &sum, &old);
259 if (do_quick) file_checksum(fname, &sum.sum[0]);
260 if (data.dptr) free(data.dptr);
261 data.dptr = (void *)∑
262 data.dsize = sizeof(sum);
263 tdb_store(tdb, key, data, TDB_REPLACE);
266 if (keystr) free(keystr);
268 if (recurse && S_ISDIR(st.st_mode)) {
273 static void tsums_dir(const char *dname)
281 for (de=readdir(d); de; de=readdir(d)) {
283 if (strcmp(de->d_name, ".") == 0 ||
284 strcmp(de->d_name, "..") == 0) continue;
285 asprintf(&s, "%s/%s", dname, de->d_name);
293 static int load_ignore(TDB_CONTEXT *db, TDB_DATA key, TDB_DATA data,
296 struct ignore *ignore;
298 if (strncmp(key.dptr, "IGNORE:", 7) != 0) return 0;
300 ignore = (struct ignore *)malloc(sizeof(*ignore));
301 if (!ignore) fatal("out of memory in load_ignore\n");
302 ignore->pattern = strdup(key.dptr+7);
303 ignore->next = ignore_list;
304 ignore_list = ignore;
308 static void process_one(char *fname)
311 printf("%s\n", fname);
320 static int process_fn(TDB_CONTEXT *db, TDB_DATA key, TDB_DATA data,
323 if (strncmp(key.dptr, "FILE:", 5) != 0) return 0;
325 process_one(key.dptr + 5);
329 static void usage(void)
332 tsums maintains signatures of files on a system. Similar to tripwire.
333 Copyright (C) Andrew Tridgell (tridge@samba.org)
335 Usage: tsums [options] <files|dirs...>
338 -a use all existing files
339 -q quick mode (don't checksum)
342 -f <DB> database name
343 -i add listed files to ignore list
344 -d dump the ignored list
345 -F flush the ignored list
350 int main(int argc, char *argv[])
353 char *db_name = "tsums.tdb";
359 int do_flush_ignore=0;
361 while ((c = getopt(argc, argv, "qhuf:idavF")) != -1){
400 tdb = tdb_open(db_name, 1000, 0, O_CREAT|O_RDWR, 0600);
403 fatal("can't open tdb\n");
406 tdb_traverse(tdb, load_ignore, NULL);
413 if (do_flush_ignore) {
420 tdb_traverse(tdb, process_fn, NULL);
424 if (argc == 0) usage();
426 for (i=0;i<argc;i++) {
427 process_one(argv[i]);