shared/actions.c
ee6702ab
 /*
e1cbc270
  *  Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
  *  Copyright (C) 2009-2013 Sourcefire, Inc.
ee6702ab
  *
  *  Author: aCaB
  *
a5b34b87
  *  These functions are actions that may be taken when a sample alerts.
  *  The user may wish to:
  *  - move file to destination directory.
  *  - copy file to destination directory.
  *  - remove (delete) the file.
  *
ee6702ab
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
  */
 
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
f235c57a
 #if HAVE_UNISTD_H
ee6702ab
 #include <unistd.h>
f235c57a
 #endif
ee6702ab
 #include <fcntl.h>
 #include <errno.h>
 #include <libgen.h>
 
a2a004df
 #include "libclamav/clamav.h"
ee6702ab
 #include "shared/optparser.h"
 #include "shared/output.h"
 #include "shared/misc.h"
c71a0353
 #include "shared/actions.h"
ee6702ab
 
 void (*action)(const char *) = NULL;
 unsigned int notmoved = 0, notremoved = 0;
 
 static char *actarget;
 static int targlen;
 
288057e9
 static int getdest(const char *fullpath, char **newname)
 {
ee6702ab
     char *tmps, *filename;
     int fd, i;
 
     tmps = strdup(fullpath);
288057e9
     if (!tmps) {
         *newname = NULL;
52520dd4
         return -1;
     }
ee6702ab
     filename = basename(tmps);
 
288057e9
     if (!(*newname = (char *)malloc(targlen + strlen(filename) + 6))) {
         free(tmps);
         return -1;
ee6702ab
     }
288057e9
     sprintf(*newname, "%s" PATHSEP "%s", actarget, filename);
     for (i = 1; i < 1000; i++) {
         fd = open(*newname, O_WRONLY | O_CREAT | O_EXCL, 0600);
         if (fd >= 0) {
             free(tmps);
             return fd;
         }
         if (errno != EEXIST) break;
         sprintf(*newname, "%s" PATHSEP "%s.%03u", actarget, filename, i);
ee6702ab
     }
     free(tmps);
     free(*newname);
     *newname = NULL;
     return -1;
 }
 
288057e9
 static void action_move(const char *filename)
 {
ee6702ab
     char *nuname;
52520dd4
     int fd = getdest(filename, &nuname), copied = 0;
ee6702ab
 
a5b34b87
     if (fd < 0 || (rename(filename, nuname) && ((copied = 1)) && filecopy(filename, nuname))) {
288057e9
         logg("!Can't move file %s\n", filename);
         notmoved++;
         if (nuname) unlink(nuname);
ee6702ab
     } else {
288057e9
         if (copied && unlink(filename))
             logg("!Can't unlink '%s': %s\n", filename, strerror(errno));
         else
             logg("~%s: moved to '%s'\n", filename, nuname);
ee6702ab
     }
 
288057e9
     if (fd >= 0) close(fd);
     if (nuname) free(nuname);
ee6702ab
 }
 
288057e9
 static void action_copy(const char *filename)
 {
ee6702ab
     char *nuname;
     int fd = getdest(filename, &nuname);
 
288057e9
     if (fd < 0 || filecopy(filename, nuname)) {
         logg("!Can't copy file '%s'\n", filename);
         notmoved++;
         if (nuname) unlink(nuname);
ee6702ab
     } else
288057e9
         logg("~%s: copied to '%s'\n", filename, nuname);
ee6702ab
 
288057e9
     if (fd >= 0) close(fd);
     if (nuname) free(nuname);
ee6702ab
 }
 
288057e9
 static void action_remove(const char *filename)
 {
     if (unlink(filename)) {
         logg("!Can't remove file '%s'.\n", filename);
         notremoved++;
ee6702ab
     } else {
288057e9
         logg("~%s: Removed.\n", filename);
ee6702ab
     }
 }
 
288057e9
 static int isdir(void)
 {
a2a004df
     STATBUF sb;
288057e9
     if (CLAMSTAT(actarget, &sb) || !S_ISDIR(sb.st_mode)) {
         logg("!'%s' doesn't exist or is not a directory\n", actarget);
         return 0;
ee6702ab
     }
f23454aa
     return 1;
ee6702ab
 }
 
a5b34b87
 /*
  * Call this function at the beginning to configure the user preference.
  * Later, call the "action" callback function to perform the selection action.
  */
288057e9
 int actsetup(const struct optstruct *opts)
 {
ee6702ab
     int move = optget(opts, "move")->enabled;
288057e9
     if (move || optget(opts, "copy")->enabled) {
         actarget = optget(opts, move ? "move" : "copy")->strarg;
         if (!isdir()) return 1;
         action  = move ? action_move : action_copy;
         targlen = strlen(actarget);
     } else if (optget(opts, "remove")->enabled)
         action = action_remove;
ee6702ab
     return 0;
 }