static int mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) { mrb_value tmp; mrb_value io_klass, str_klass; io_klass = mrb_obj_value(mrb_class_get(mrb, "IO")); str_klass = mrb_obj_value(mrb_class_get(mrb, "String")); tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass); if (mrb_test(tmp)) { struct mrb_io *fptr; fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); if (fptr && fptr->fd >= 0) { return fstat(fptr->fd, st); } mrb_raise(mrb, E_IO_ERROR, "closed stream"); return -1; } tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); if (mrb_test(tmp)) { if (do_lstat) { return LSTAT(mrb_str_to_cstr(mrb, obj), st); } else { return stat(mrb_str_to_cstr(mrb, obj), st); } } return -1; }
static void change_attributes (const char * name) { unsigned long flags; STRUCT_STAT st; if (LSTAT (name, &st) == -1) { com_err (program_name, errno, _("while trying to stat %s"), name); return; } if (S_ISLNK(st.st_mode) && recursive) return; /* Don't try to open device files, fifos etc. We probably ought to display an error if the file was explicitly given on the command line (whether or not recursive was requested). */ if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode)) return; if (set) { if (verbose) { printf (_("Flags of %s set as "), name); print_flags (stdout, sf, 0); printf ("\n"); } if (fsetflags (name, sf) == -1) perror (name); } else { if (fgetflags (name, &flags) == -1) com_err (program_name, errno, _("while reading flags on %s"), name); else { if (rem) flags &= ~rf; if (add) flags |= af; if (verbose) { printf (_("Flags of %s set as "), name); print_flags (stdout, flags, 0); printf ("\n"); } if (!S_ISDIR(st.st_mode)) flags &= ~EXT2_DIRSYNC_FL; if (fsetflags (name, flags) == -1) com_err (program_name, errno, _("while setting flags on %s"), name); } } if (set_version) { if (verbose) printf (_("Version of %s set as %lu\n"), name, version); if (fsetversion (name, version) == -1) com_err (program_name, errno, _("while setting version on %s"), name); } if (S_ISDIR(st.st_mode) && recursive) iterate_on_dir (name, chattr_dir_proc, NULL); }
static int checkopaque(register char* path, struct stat* st) { register char* basesp; int oerrno = errno; struct stat statb; char savebuf[sizeof(state.opaque)]; register int r = 0; if (st->st_nlink <= 1) return 0; if (st->st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) return 0; /* * change the basename to state.opaque */ if (basesp = strrchr(path, '/')) basesp++; else basesp = path; memcpy(savebuf, basesp, sizeof(state.opaque)); strcpy(basesp, state.opaque); if (LSTAT(path, &statb)) { /* * for backward compatability */ basesp[3] = 0; if (LSTAT(path, &statb)) goto not_opaque; } if (statb.st_ino == st->st_ino && statb.st_dev == st->st_dev) { errno = ENOENT; r = statb.st_ino; } else errno = oerrno; not_opaque: memcpy(basesp, savebuf, sizeof(state.opaque)); return r; }
static void lsattr_args (const char * name) { STRUCT_STAT st; if (LSTAT (name, &st) == -1) com_err (program_name, errno, _("while trying to stat %s"), name); else { if (S_ISDIR(st.st_mode) && !dirs_opt) iterate_on_dir (name, lsattr_dir_proc, NULL); else list_attributes (name); } }
static int lsattr_args (const char * name) { STRUCT_STAT st; int retval = 0; if (LSTAT (name, &st) == -1) { com_err (program_name, errno, _("while trying to stat %s"), name); retval = -1; } else { if (S_ISDIR(st.st_mode) && !dirs_opt) retval = iterate_on_dir (name, lsattr_dir_proc, NULL); else retval = list_attributes (name); } return retval; }
int unlink3d(register const char* path) { register char* sp; register int r; #if FS Mount_t* mp; if (!fscall(NiL, MSG_remove, 0, path)) return state.ret; mp = monitored(); #endif if (!(sp = pathreal(path, P_PATHONLY|P_SAFE, NiL))) return -1; if (state.path.level) return 0; if (!(r = LSTAT(sp, &state.path.st))) { if (S_ISLNK(state.path.st.st_mode) && !checklink(sp, &state.path.st, P_PATHONLY|P_LSTAT) && state.path.linksize > 0) { /* * remove instance if not default */ r = strlen(sp) - (sizeof(state.vdefault) - 1); if (r > 3 && streq(sp + r, state.vdefault)) return 0; } r = UNLINK(sp); } if (!r) { #if FS if (mp) fscall(mp, MSG_remove, 0, path); for (mp = state.global; mp; mp = mp->global) if (fssys(mp, MSG_remove)) fscall(mp, MSG_remove, 0, path); #endif } else if (errno == ENOENT && pathreal(path, 0, NiL)) r = 0; return r; }
static u_short internal_function fts_stat (FTSOBJ *sp, FTSENTRY *p, int follow) { FTSENTRY *t; dev_t dev; INO_T ino; struct STAT *sbp, sb; int saved_errno; /* If user needs stat info, stat buffer already allocated. */ sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; #if defined FTS_WHITEOUT && 0 /* check for whiteout */ if (p->fts_flags & FTS_ISW) { if (sbp != &sb) { memset(sbp, '\0', sizeof (*sbp)); sbp->st_mode = S_IFWHT; } return (FTS_W); } #endif /* * If doing a logical walk, or application requested FTS_FOLLOW, do * a stat(2). If that fails, check for a non-existent symlink. If * fail, set the errno from the stat call. */ if (ISSET(FTS_LOGICAL) || follow) { if (STAT(p->fts_accpath, sbp)) { saved_errno = errno; if (!LSTAT(p->fts_accpath, sbp)) { __set_errno (0); return (FTS_SLNONE); } p->fts_errno = saved_errno; goto err; } } else if (LSTAT(p->fts_accpath, sbp)) { p->fts_errno = errno; err: memset(sbp, 0, sizeof(struct STAT)); return (FTS_NS); } if (S_ISDIR(sbp->st_mode)) { /* * Set the device/inode. Used to find cycles and check for * crossing mount points. Also remember the link count, used * in fts_build to limit the number of stat calls. It is * understood that these fields are only referenced if fts_info * is set to FTS_D. */ dev = p->fts_dev = sbp->st_dev; ino = p->fts_ino = sbp->st_ino; p->fts_nlink = sbp->st_nlink; if (ISDOT(p->fts_name)) return (FTS_DOT); /* * Cycle detection is done by brute force when the directory * is first encountered. If the tree gets deep enough or the * number of symbolic links to directories is high enough, * something faster might be worthwhile. */ for (t = p->fts_parent; t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) if (ino == t->fts_ino && dev == t->fts_dev) { p->fts_cycle = t; return (FTS_DC); } return (FTS_D); } if (S_ISLNK(sbp->st_mode)) return (FTS_SL); if (S_ISREG(sbp->st_mode)) return (FTS_F); return (FTS_DEFAULT); }
int remove_tree (const char *root, bool remove_root) { char *new_name = NULL; int err = 0; struct DIRECT *ent; struct stat sb; DIR *dir; /* * Open the source directory and read each entry. Every file * entry in the directory is copied with the UID and GID set * to the provided values. As an added security feature only * regular files (and directories ...) are copied, and no file * is made set-ID. */ dir = opendir (root); if (NULL == dir) { return -1; } while ((ent = readdir (dir))) { size_t new_len = strlen (root) + strlen (ent->d_name) + 2; /* * Skip the "." and ".." entries */ if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) { continue; } /* * Make the filename for the current entry. */ free (new_name); new_name = (char *) malloc (new_len); if (NULL == new_name) { err = -1; break; } (void) snprintf (new_name, new_len, "%s/%s", root, ent->d_name); if (LSTAT (new_name, &sb) == -1) { continue; } if (S_ISDIR (sb.st_mode)) { /* * Recursively delete this directory. */ if (remove_tree (new_name, true) != 0) { err = -1; break; } } else { /* * Delete the file. */ if (unlink (new_name) != 0) { err = -1; break; } } } if (NULL != new_name) { free (new_name); } (void) closedir (dir); if (remove_root && (0 == err)) { if (rmdir (root) != 0) { err = -1; } } return err; }
static #endif char* pathreal(const char* apath, register int type, struct stat* st) { char* path = (char*)apath; register char* sp; register char* cp; register char* ip; Table_t* safe; int oerrno = errno; int opaqued = 0; int len; int vir; int safesize; int safe_dir; long visits; char buf[PATH_MAX + 1]; static struct stat stbuf; static struct stat tsbuf; state.path.level = state.path.synthesize = state.path.nlinks = 0; if (!path) { errno = EFAULT; return 0; } initialize(); if (state.in_2d) { if (!st || (!state.level || *path == '/') && !LSTAT(path, st)) return path; if (state.level && streq(path, ".") && !CHDIR(state.pwd)) { state.level = 0; return path; } return 0; } #if FS if (mounted() && (sp = fsreal(state.path.monitor, MSG_stat, state.path.mount))) apath = (char*)(path = sp); #endif /* * handle null path, . and / separately */ if (safe = state.safe ? &state.vsafe : (Table_t*)0) { type |= P_ABSOLUTE; if (!(safesize = state.safe->servicesize)) safesize = strlen(state.safe->service); } else type &= ~P_SAFE; again: if (!*path) { errno = ENOENT; return 0; } cp = sp = path; state.path.synthesize = state.path.linksize = 0; if (!st) st = &stbuf; /* * check if virtual dir has been created by another process * only P_PATHONLY|P_TOP calls (usually create or modify link) and * references to "." are checked for performance */ if (state.level > 0 && state.pwd && ((type & (P_PATHONLY|P_TOP)) && *sp != '/' || *sp == '.' && sp[1] == 0)) { if (!CHDIR(state.pwd)) state.level = 0; else if (!(type & (P_PATHONLY|P_TOP))) { len = 0; state.path.level += (state.path.synthesize = state.level); sp = strcpy(state.path.name, state.pwd); goto skip; } } if (!state.pwd || sp[1] == 0 && (*sp == '.' || *sp == '/' && !safe)) { if (st != &stbuf && LSTAT(sp, st)) return 0; if (*sp == '/' || !state.pwd && (type & P_PATHONLY)) strncpy(state.path.name, sp, PATH_MAX); else if (!state.pwd) { /* * treat the current directory as if were empty */ errno = ENOENT; return 0; } else strncpy(state.path.name, state.pwd, PATH_MAX); errno = oerrno; return state.path.name; } /* * put absolute pathname into state.path */ safe_dir = 0; if (*path != '/') { strcpy(state.path.name, state.pwd); sp = state.path.name + state.pwdsize; *sp++ = '/'; if (safe && state.pwdsize >= safesize && !strncmp(state.pwd, state.safe->service, safesize) && (!state.pwd[safesize] || state.pwd[safesize] == '/')) safe_dir = safesize; } else sp = state.path.name; ip = state.path.name + elementsof(state.path.name); while (sp < ip && (*sp = *cp++)) sp++; if (type & P_DOTDOT) strcpy(sp, "/.."); sp = state.path.name; if (!(ip = pathcanon(sp + safe_dir, sizeof(state.path.name) - safe_dir, 0))) { errno = ENOENT; return 0; } if (type & (P_DOTDOT|P_NOSLASH)) { /* * remove trailing slashes */ while (*--ip == '/'); *++ip = 0; } else if ((type & P_SLASH) && *(ip - 1) != '/') *ip++ = '/'; if (*(ip - 1) == '/' && ip - sp > 1) { /* * trailing slash is equivalent to trailing slash-dot * this forces the common-sense interpretation */ #if DEBUG if (!(state.test & 010)) #endif *ip++ = '.'; *ip = 0; } len = ip - sp; /* * try to use relative path */ if (!(type & (P_LSTAT|P_READLINK))) { for (ip = state.pwd; *ip && *ip == *sp++; ip++); if (*ip != 0 || *sp && *sp != '/' || state.level < 0) sp = state.path.name; else { state.path.level += (state.path.synthesize = state.level); if (state.level && !(type & P_PATHONLY) && st == &stbuf) { sp = state.path.name; len -= state.pwdsize; } else if (type & P_ABSOLUTE) sp = state.path.name; else if (*sp == '/') sp++; } if (*sp == 0) sp = state.dot; } skip: if ((type & P_NOOPAQUE) && !LSTAT(sp, st) && checkopaque(sp, st)) { message((-1, "%s: remove opaque", sp)); UNLINK(sp); opaqued = 1; } if (safe && *sp == '/') { state.path.table = safe; cp = pathnext(sp, NiL, NiL); state.path.table = safe = 0; if (cp) { state.path.level = 0; path = strcpy(buf, sp); message((-5, "pathreal: == safe map %s", path)); type &= ~(P_DOTDOT|P_SAFE); goto again; } if (!*(sp + 1)) { strncpy(sp, state.safe->service, safesize); sp[safesize] = 0; } else if (strncmp(sp, state.safe->service, safesize) || sp[safesize] && sp[safesize] != '/') { if (*path != '/' && safe_dir) { errno = EPERM; return 0; } if (sp[1]) strcpy(buf, sp); else *buf = 0; len = sfsprintf(sp, sizeof(state.path.name), "%-*s%s", safesize, state.safe->service, buf); message((-5, "pathreal: == safe next %s", sp)); if (!pathnext(sp, NiL, NiL)) { errno = EPERM; return 0; } } else type &= ~P_SAFE; } if ((type & P_SAFE) && state.path.level) { errno = EPERM; return 0; } if (type & P_PATHONLY) { errno = oerrno; return sp; } visits = 0; vir = 1; while (LSTAT(sp, st)) { if (vir) { if (apath[0] == '.' && apath[1] == '.' && apath[2] == '.' && !apath[3]) { if (state.level > 0) { message((-1, "pathreal: %s => %s", apath, sp)); LSTAT(".", st); return sp; } errno = ENOENT; return 0; } vir = 0; } if (errno == ENOTDIR) { /* * check for version instance */ cp = ip = sp + strlen(sp); while (ip > sp && *--ip != '/'); if (ip < sp) return 0; while (ip > sp && *--ip == '/'); if (ip < sp) return 0; while (ip > sp && *--ip != '/'); if (*ip == '/') ip++; while (cp >= ip) { cp[4] = *cp; cp--; } memcpy(ip, state.opaque, 4); if (!LSTAT(sp, st)) break; errno = ENOTDIR; return 0; } if (errno != ENOENT || opaqued) return 0; #if FS /* * check user mount */ if (visits) { Mount_t* mp; const char* up; if ((mp = getmount(sp, &up)) && (mp->fs->flags & FS_NAME) && (sp = fsreal(mp, MSG_open, (char*)up)) && !LSTAT(sp, st)) break; } #endif /* * search down the viewpath */ if (type & P_SAFE) { errno = EPERM; return 0; } if (!pathnext(state.path.name, NiL, &visits)) return 0; sp = state.path.name; if (!(type & P_ABSOLUTE)) { /* * try to use relative path */ for (ip = state.pwd; *ip && *ip == *sp++; ip++); if (*ip == 0 && *sp == '/') sp++; else sp = state.path.name; } if (*sp == 0) sp = state.dot; } if (st->st_nlink > 1 && checkopaque(sp, st)) return 0; if ((type & P_TOP) && state.path.level) { int rfd; int wfd; if ((rfd = OPEN(sp, O_RDONLY, 0)) < 0) sp = 0; else { tsbuf = *st; wfd = open(apath, O_WRONLY|O_CREAT|O_TRUNC|O_cloexec, st->st_mode & S_IPERM); *st = tsbuf; if (wfd < 0) sp = 0; else { if (fs3d_copy(rfd, wfd, st)) sp = 0; CLOSE(wfd); } CLOSE(rfd); } if (!sp) { errno = EROFS; return 0; } if (st == &stbuf) st = 0; return pathreal(apath, P_PATHONLY, st); } IVIEW(st, state.path.level); if (state.path.synthesize) { if (state.path.level < state.level) { if (len) { ip = state.path.name + strlen(state.path.name) - len; len = *ip; *ip = 0; } if (!CHDIR(state.path.name)) state.level = state.path.level; message((-1, "chdir=%s level=%d", state.path.name, state.level)); *ip = len; } else if (S_ISDIR(st->st_mode)) { int mask; static int uid = -1; static int gid; umask(mask = umask(0)); st->st_mode = (st->st_mode | (S_IRWXU|S_IRWXG|S_IRWXO)) & ~(mask & (S_IRWXU|S_IRWXG|S_IRWXO)); if (uid == -1) { uid = geteuid(); gid = getegid(); } st->st_uid = uid; st->st_gid = gid; } } ip = sp; /* * symbolic links handled specially * get filename from pathname */ if (S_ISLNK(st->st_mode) && (len = checklink(sp, st, type)) > 1 && !(type & (P_LSTAT|P_READLINK)) && state.path.nlinks++ < MAXSYMLINKS) { path = strcpy(buf, state.path.name); message((-1, "pathreal: == again %s", path)); if (*path != '/') state.path.level = 0; type &= ~(P_DOTDOT|P_SAFE); goto again; } #if VCS && defined(VCS_REAL) VCS_REAL(state.path.name, st); #endif errno = oerrno; return sp; }
static int sigtool_scandir (const char *dirname, int hex_output) { DIR *dd; struct dirent *dent; STATBUF statbuf; char *fname; const char *tmpdir; char *dir; int ret = CL_CLEAN, desc; cli_ctx *ctx; fname = NULL; if ((dd = opendir (dirname)) != NULL) { while ((dent = readdir (dd))) { if (dent->d_ino) { if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) { /* build the full name */ fname = (char *) cli_calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char)); if(!fname){ closedir(dd); return -1; } sprintf (fname, "%s"PATHSEP"%s", dirname, dent->d_name); /* stat the file */ if (LSTAT (fname, &statbuf) != -1) { if (S_ISDIR (statbuf.st_mode) && !S_ISLNK (statbuf.st_mode)) { if (sigtool_scandir (fname, hex_output)) { free (fname); closedir (dd); return CL_VIRUS; } } else { if (S_ISREG (statbuf.st_mode)) { struct uniq *vba = NULL; tmpdir = cli_gettmpdir(); /* generate the temporary directory */ dir = cli_gentemp (tmpdir); if(!dir) { printf("cli_gentemp() failed\n"); free(fname); closedir (dd); return -1; } if (mkdir (dir, 0700)) { printf ("Can't create temporary directory %s\n", dir); free(fname); closedir (dd); free(dir); return CL_ETMPDIR; } if ((desc = open (fname, O_RDONLY|O_BINARY)) == -1) { printf ("Can't open file %s\n", fname); free(fname); closedir (dd); free(dir); return 1; } if(!(ctx = convenience_ctx(desc))) { free(fname); close(desc); closedir(dd); free(dir); return 1; } if ((ret = cli_ole2_extract (dir, ctx, &vba))) { printf ("ERROR %s\n", cl_strerror (ret)); destroy_ctx(desc, ctx); cli_rmdirs (dir); free (dir); closedir (dd); free(fname); return ret; } if(vba) sigtool_vba_scandir (dir, hex_output, vba); destroy_ctx(desc, ctx); cli_rmdirs (dir); free (dir); } } } free (fname); } } } } else { logg("!Can't open directory %s.\n", dirname); return CL_EOPEN; } closedir (dd); return 0; }
int sigtool_vba_scandir (const char *dirname, int hex_output, struct uniq *U) { int ret = CL_CLEAN, i, j, fd, data_len; vba_project_t *vba_project; DIR *dd; struct dirent *dent; STATBUF statbuf; char *fullname, vbaname[1024], *hash; unsigned char *data; uint32_t hashcnt; hashcnt = uniq_get(U, "_vba_project", 12, NULL); while(hashcnt--) { if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue; for(i = 0; i < vba_project->count; i++) { for(j = 0; j < vba_project->colls[i]; j++) { snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", vba_project->dir, vba_project->name[i], j); vbaname[sizeof(vbaname)-1] = '\0'; fd = open(vbaname, O_RDONLY|O_BINARY); if(fd == -1) continue; data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len); close(fd); if(data) { data = (unsigned char *) realloc (data, data_len + 1); data[data_len]='\0'; printf ("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data); free(data); } } } free(vba_project->name); free(vba_project->colls); free(vba_project->dir); free(vba_project->offset); free(vba_project); } if((hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) { while(hashcnt--) { snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt); vbaname[sizeof(vbaname)-1] = '\0'; fd = open(vbaname, O_RDONLY|O_BINARY); if (fd == -1) continue; if ((fullname = cli_ppt_vba_read(fd, NULL))) { sigtool_scandir(fullname, hex_output); cli_rmdirs(fullname); free(fullname); } close(fd); } } if ((hashcnt = uniq_get(U, "worddocument", 12, &hash))) { while(hashcnt--) { snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt); vbaname[sizeof(vbaname)-1] = '\0'; fd = open(vbaname, O_RDONLY|O_BINARY); if (fd == -1) continue; if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) { close(fd); continue; } for (i = 0; i < vba_project->count; i++) { data_len = vba_project->length[i]; data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], data_len , vba_project->key[i]); if(data) { data = (unsigned char *) realloc (data, data_len + 1); data[data_len]='\0'; printf ("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data); free(data); } } close(fd); free(vba_project->name); free(vba_project->colls); free(vba_project->dir); free(vba_project->offset); free(vba_project->key); free(vba_project->length); free(vba_project); } } if ((dd = opendir (dirname)) != NULL) { while ((dent = readdir (dd))) { if (dent->d_ino) { if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) { /* build the full name */ fullname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char)); sprintf (fullname, "%s"PATHSEP"%s", dirname, dent->d_name); /* stat the file */ if (LSTAT (fullname, &statbuf) != -1) { if (S_ISDIR (statbuf.st_mode) && !S_ISLNK (statbuf.st_mode)) sigtool_vba_scandir (fullname, hex_output, U); } free (fullname); } } } } else { logg("!ScanDir -> Can't open directory %s.\n", dirname); return CL_EOPEN; } closedir (dd); return ret; }
static int change_attributes(const char * name) { unsigned long flags; STRUCT_STAT st; if (LSTAT (name, &st) == -1) { if (!silent) com_err (program_name, errno, _("while trying to stat %s"), name); return -1; } if (set) { if (verbose) { printf (_("Flags of %s set as "), name); print_flags (stdout, sf, 0); printf ("\n"); } if (fsetflags (name, sf) == -1) perror (name); } else { if (fgetflags (name, &flags) == -1) { if (!silent) com_err (program_name, errno, _("while reading flags on %s"), name); return -1; } else { if (rem) flags &= ~rf; if (add) flags |= af; if (verbose) { printf (_("Flags of %s set as "), name); print_flags (stdout, flags, 0); printf ("\n"); } if (!S_ISDIR(st.st_mode)) flags &= ~EXT2_DIRSYNC_FL; if (fsetflags (name, flags) == -1) { if (!silent) com_err(program_name, errno, _("while setting flags on %s"), name); return -1; } } } if (set_version) { if (verbose) printf (_("Version of %s set as %lu\n"), name, version); if (fsetversion (name, version) == -1) { if (!silent) com_err (program_name, errno, _("while setting version on %s"), name); return -1; } } if (S_ISDIR(st.st_mode) && recursive) return iterate_on_dir (name, chattr_dir_proc, NULL); return 0; }
/* * copy_tree - copy files in a directory tree * * copy_tree() walks a directory tree and copies ordinary files * as it goes. * * When reset_selinux is enabled, extended attributes (and thus * SELinux attributes) are not copied. * * old_uid and new_uid are used to set the ownership of the copied * files. Unless old_uid is set to -1, only the files owned by * old_uid have their ownership changed to new_uid. In addition, if * new_uid is set to -1, no ownership will be changed. * * The same logic applies for the group-ownership and * old_gid/new_gid. */ int copy_tree (const char *src_root, const char *dst_root, bool copy_root, bool reset_selinux, uid_t old_uid, uid_t new_uid, gid_t old_gid, gid_t new_gid) { int err = 0; bool set_orig = false; struct DIRECT *ent; DIR *dir; if (copy_root) { struct stat sb; if (access (dst_root, F_OK) == 0) { return -1; } if (LSTAT (src_root, &sb) == -1) { return -1; } if (!S_ISDIR (sb.st_mode)) { fprintf (stderr, "%s: %s is not a directory", Prog, src_root); return -1; } return copy_entry (src_root, dst_root, reset_selinux, old_uid, new_uid, old_gid, new_gid); } /* * Make certain both directories exist. This routine is called * after the home directory is created, or recursively after the * target is created. It assumes the target directory exists. */ if ( (access (src_root, F_OK) != 0) || (access (dst_root, F_OK) != 0)) { return -1; } /* * Open the source directory and read each entry. Every file * entry in the directory is copied with the UID and GID set * to the provided values. As an added security feature only * regular files (and directories ...) are copied, and no file * is made set-ID. */ dir = opendir (src_root); if (NULL == dir) { return -1; } if (src_orig == NULL) { src_orig = src_root; dst_orig = dst_root; set_orig = true; } while ((0 == err) && (ent = readdir (dir)) != NULL) { /* * Skip the "." and ".." entries */ if ((strcmp (ent->d_name, ".") != 0) && (strcmp (ent->d_name, "..") != 0)) { char *src_name; char *dst_name; size_t src_len = strlen (ent->d_name) + 2; size_t dst_len = strlen (ent->d_name) + 2; src_len += strlen (src_root); dst_len += strlen (dst_root); src_name = (char *) malloc (src_len); dst_name = (char *) malloc (dst_len); if ((NULL == src_name) || (NULL == dst_name)) { err = -1; } else { /* * Build the filename for both the source and * the destination files. */ (void) snprintf (src_name, src_len, "%s/%s", src_root, ent->d_name); (void) snprintf (dst_name, dst_len, "%s/%s", dst_root, ent->d_name); err = copy_entry (src_name, dst_name, reset_selinux, old_uid, new_uid, old_gid, new_gid); } if (NULL != src_name) { free (src_name); } if (NULL != dst_name) { free (dst_name); } } } (void) closedir (dir); if (set_orig) { src_orig = NULL; dst_orig = NULL; /* FIXME: clean links * Since there can be hardlinks elsewhere on the device, * we cannot check that all the hardlinks were found: assert (NULL == links); */ } #ifdef WITH_SELINUX /* Reset SELinux to create files with default contexts. * Note that the context is only reset on exit of copy_tree (it is * assumed that the program would quit without needing a restored * context if copy_tree failed previously), and that copy_tree can * be called recursively (hence the context is set on the * sub-functions of copy_entry). */ if (reset_selinux_file_context () != 0) { err = -1; } #endif /* WITH_SELINUX */ return err; }
/* * copy_entry - copy the entry of a directory * * Copy the entry src to dst. * Depending on the type of entry, this function will forward the * request to copy_dir(), copy_symlink(), copy_hardlink(), * copy_special(), or copy_file(). * * The access and modification time will not be modified. * * The permissions will be set to new_uid/new_gid. * * If new_uid (resp. new_gid) is equal to -1, the user (resp. group) will * not be modified. * * Only the files owned (resp. group-owned) by old_uid (resp. * old_gid) will be modified, unless old_uid (resp. old_gid) is set * to -1. */ static int copy_entry (const char *src, const char *dst, bool reset_selinux, uid_t old_uid, uid_t new_uid, gid_t old_gid, gid_t new_gid) { int err = 0; struct stat sb; struct link_name *lp; struct timeval mt[2]; if (LSTAT (src, &sb) == -1) { /* If we cannot stat the file, do not care. */ } else { #ifdef HAVE_STRUCT_STAT_ST_ATIM mt[0].tv_sec = sb.st_atim.tv_sec; mt[0].tv_usec = sb.st_atim.tv_nsec / 1000; #else /* !HAVE_STRUCT_STAT_ST_ATIM */ mt[0].tv_sec = sb.st_atime; # ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC mt[0].tv_usec = sb.st_atimensec / 1000; # else /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */ mt[0].tv_usec = 0; # endif /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */ #endif /* !HAVE_STRUCT_STAT_ST_ATIM */ #ifdef HAVE_STRUCT_STAT_ST_MTIM mt[1].tv_sec = sb.st_mtim.tv_sec; mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000; #else /* !HAVE_STRUCT_STAT_ST_MTIM */ mt[1].tv_sec = sb.st_mtime; # ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC mt[1].tv_usec = sb.st_mtimensec / 1000; # else /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */ mt[1].tv_usec = 0; # endif /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */ #endif /* !HAVE_STRUCT_STAT_ST_MTIM */ if (S_ISDIR (sb.st_mode)) { err = copy_dir (src, dst, reset_selinux, &sb, mt, old_uid, new_uid, old_gid, new_gid); } #ifdef S_IFLNK /* * Copy any symbolic links */ else if (S_ISLNK (sb.st_mode)) { err = copy_symlink (src, dst, reset_selinux, &sb, mt, old_uid, new_uid, old_gid, new_gid); } #endif /* S_IFLNK */ /* * See if this is a previously copied link */ else if ((lp = check_link (src, &sb)) != NULL) { err = copy_hardlink (dst, reset_selinux, lp); } /* * Deal with FIFOs and special files. The user really * shouldn't have any of these, but it seems like it * would be nice to copy everything ... */ else if (!S_ISREG (sb.st_mode)) { err = copy_special (src, dst, reset_selinux, &sb, mt, old_uid, new_uid, old_gid, new_gid); } /* * Create the new file and copy the contents. The new * file will be owned by the provided UID and GID values. */ else { err = copy_file (src, dst, reset_selinux, &sb, mt, old_uid, new_uid, old_gid, new_gid); } } return err; }
/* * chown_tree - change ownership of files in a directory tree * * chown_dir() walks a directory tree and changes the ownership * of all files owned by the provided user ID. */ int chown_tree (const char *root, uid_t old_uid, uid_t new_uid, gid_t old_gid, gid_t new_gid) { char new_name[1024]; int rc = 0; struct DIRECT *ent; struct stat sb; DIR *dir; /* * Make certain the directory exists. This routine is called * directory by the invoker, or recursively. */ if (access (root, F_OK) != 0) return -1; /* * Open the directory and read each entry. Every entry is tested * to see if it is a directory, and if so this routine is called * recursively. If not, it is checked to see if it is owned by * old user ID. */ if (!(dir = opendir (root))) return -1; while ((ent = readdir (dir))) { /* * Skip the "." and ".." entries */ if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) continue; /* * Make the filename for both the source and the * destination files. */ if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) break; snprintf (new_name, sizeof new_name, "%s/%s", root, ent->d_name); /* Don't follow symbolic links! */ if (LSTAT (new_name, &sb) == -1) continue; if (S_ISDIR (sb.st_mode) && !S_ISLNK (sb.st_mode)) { /* * Do the entire subdirectory. */ rc = chown_tree (new_name, old_uid, new_uid, old_gid, new_gid); if (0 != rc) { break; } } #ifndef HAVE_LCHOWN /* don't use chown (follows symbolic links!) */ if (S_ISLNK (sb.st_mode)) continue; #endif if (sb.st_uid == old_uid) LCHOWN (new_name, new_uid, sb.st_gid == old_gid ? new_gid : sb.st_gid); } (void) closedir (dir); /* * Now do the root of the tree */ if (stat (root, &sb) == 0) { if (sb.st_uid == old_uid) { LCHOWN (root, new_uid, sb.st_gid == old_gid ? new_gid : sb.st_gid); } } return rc; }
Errors Device_getDeviceInfo(DeviceInfo *deviceInfo, const String deviceName ) { FileStat fileStat; int handle; #if defined(HAVE_IOCTL) && defined(HAVE_BLKSSZGET) int i; #endif #if defined(HAVE_IOCTL) && defined(HAVE_BLKGETSIZE) long l; #endif FILE *mtab; struct mntent mountEntry; char buffer[4096]; assert(deviceName != NULL); assert(deviceInfo != NULL); // initialize variables deviceInfo->type = DEVICE_TYPE_UNKNOWN; deviceInfo->size = -1LL; deviceInfo->blockSize = 0L; // deviceInfo->freeBlocks = 0LL; // deviceInfo->totalBlocks = 0LL; deviceInfo->mountedFlag = FALSE; // get device meta data if (LSTAT(String_cString(deviceName),&fileStat) == 0) { deviceInfo->timeLastAccess = fileStat.st_atime; deviceInfo->timeModified = fileStat.st_mtime; deviceInfo->timeLastChanged = fileStat.st_ctime; deviceInfo->userId = fileStat.st_uid; deviceInfo->groupId = fileStat.st_gid; deviceInfo->permission = (DevicePermission)fileStat.st_mode; #ifdef HAVE_MAJOR deviceInfo->major = major(fileStat.st_rdev); #else deviceInfo->major = 0; #endif #ifdef HAVE_MINOR deviceInfo->minor = minor(fileStat.st_rdev); #else deviceInfo->minor = 0; #endif deviceInfo->id = (uint64)fileStat.st_ino; if (S_ISCHR(fileStat.st_mode)) deviceInfo->type = DEVICE_TYPE_CHARACTER; else if (S_ISBLK(fileStat.st_mode)) deviceInfo->type = DEVICE_TYPE_BLOCK; } if (deviceInfo->type == DEVICE_TYPE_BLOCK) { // try to get block size, total size handle = open(String_cString(deviceName),O_RDONLY); if (handle != -1) { #if defined(HAVE_IOCTL) && defined(HAVE_BLKSSZGET) if (ioctl(handle,BLKSSZGET, &i) == 0) deviceInfo->blockSize = (ulong)i; #endif #if defined(HAVE_IOCTL) && defined(HAVE_BLKGETSIZE) if (ioctl(handle,BLKGETSIZE,&l) == 0) deviceInfo->size = (int64)l*512; #endif close(handle); } } // check if mounted mtab = setmntent("/etc/mtab","r"); if (mtab != NULL) { while (getmntent_r(mtab,&mountEntry,buffer,sizeof(buffer)) != NULL) { if (String_equalsCString(deviceName,mountEntry.mnt_fsname)) { deviceInfo->mountedFlag = TRUE; break; } } endmntent(mtab); } return ERROR_NONE; }
static void do_FEF( Fchar *fn, void (*proc)(const Fchar *, const char *, const struct stat *), int dev, struct ino_link *inop, Fchar separator, int max_depth ) { struct stat fs; Dir_t *dir; if (proc == 0) return; /* just make sure */ if (LSTAT(fn, &fs) < 0) { (*proc)(fn, strerror(errno), &fs); return; } /* report on file fn */ (*proc)(fn, (char*)0, &fs); if (max_depth == 0) return; if ((fs.st_mode & S_IFMT) != S_IFDIR) return; #ifdef S_IFLNK /* don't follow links */ if ((fs.st_mode & S_IFMT) == S_IFLNK) return; #endif /* treat directory */ if (dev < 0) { /* no device known yet */ dev = fs.st_dev; } if (fs.st_dev != dev) { return; } dir = Opendir(fn); if (dir == 0) { (*proc)(fn, "directory not readable", &fs); } else { /* scan new directory */ int fnl = Fnamelen(fn); Dirent_t *dent; struct ino_link ino; /* worry about loops in the file system */ if (in_ino_list(inop, &fs)) { (*proc)(fn, "loop in file system", &fs); Closedir(dir); return; } link_ino_list(inop, &ino, &fs); /* shape up the directory name */ if (fn[fnl-1] != separator) { /* append separator */ fn[fnl++] = separator; fn[fnl] = '\0'; } /* descend */ while ((dent = Readdir(dir)) != (Dirent_t *)0) { if ( Fnamecmp(dent->d_name, str2Fname(".")) == 0 || Fnamecmp(dent->d_name, str2Fname("..")) == 0 ) continue; if (Fnamecmp(dent->d_name, str2Fname("")) == 0) { (*proc)(fn, "directory contains empty file name", &fs ); continue; } /* append name */ Fnamecat(fn, dent->d_name); do_FEF(fn, proc, dev, &ino, separator, max_depth-1); /* remove name again*/ fn[fnl] = '\0'; } Closedir(dir); } }
int scanmanager(const struct optstruct *opts) { int ret = 0, i; unsigned int options = 0, dboptions = 0, dirlnk = 1, filelnk = 1; struct cl_engine *engine; STATBUF sb; char *file, cwd[1024], *pua_cats = NULL; const char *filename; const struct optstruct *opt; #ifndef _WIN32 struct rlimit rlim; #endif dirlnk = optget(opts, "follow-dir-symlinks")->numarg; if(dirlnk > 2) { logg("!--follow-dir-symlinks: Invalid argument\n"); return 2; } filelnk = optget(opts, "follow-file-symlinks")->numarg; if(filelnk > 2) { logg("!--follow-file-symlinks: Invalid argument\n"); return 2; } if(optget(opts, "yara-rules")->enabled) { char *p = optget(opts, "yara-rules")->strarg; if(strcmp(p, "yes")) { if(!strcmp(p, "only")) dboptions |= CL_DB_YARA_ONLY; else if (!strcmp(p, "no")) dboptions |= CL_DB_YARA_EXCLUDE; } } if(optget(opts, "phishing-sigs")->enabled) dboptions |= CL_DB_PHISHING; if(optget(opts, "official-db-only")->enabled) dboptions |= CL_DB_OFFICIAL_ONLY; if(optget(opts,"phishing-scan-urls")->enabled) dboptions |= CL_DB_PHISHING_URLS; if(optget(opts,"bytecode")->enabled) dboptions |= CL_DB_BYTECODE; if((ret = cl_init(CL_INIT_DEFAULT))) { logg("!Can't initialize libclamav: %s\n", cl_strerror(ret)); return 2; } if(!(engine = cl_engine_new())) { logg("!Can't initialize antivirus engine\n"); return 2; } cl_engine_set_clcb_virus_found(engine, clamscan_virus_found_cb); if (optget(opts, "disable-cache")->enabled) cl_engine_set_num(engine, CL_ENGINE_DISABLE_CACHE, 1); if (optget(opts, "disable-pe-stats")->enabled) { cl_engine_set_num(engine, CL_ENGINE_DISABLE_PE_STATS, 1); } if (optget(opts, "enable-stats")->enabled) { cl_engine_stats_enable(engine); } if (optget(opts, "stats-timeout")->enabled) { cl_engine_set_num(engine, CL_ENGINE_STATS_TIMEOUT, optget(opts, "StatsTimeout")->numarg); } if (optget(opts, "stats-host-id")->enabled) { char *p = optget(opts, "stats-host-id")->strarg; if (strcmp(p, "default")) { if (!strcmp(p, "none")) { cl_engine_set_clcb_stats_get_hostid(engine, NULL); } else if (!strcmp(p, "anonymous")) { strcpy(hostid, STATS_ANON_UUID); } else { if (strlen(p) > 36) { logg("!Invalid HostID\n"); cl_engine_set_clcb_stats_submit(engine, NULL); cl_engine_free(engine); return 2; } strcpy(hostid, p); } cl_engine_set_clcb_stats_get_hostid(engine, get_hostid); } } if(optget(opts, "detect-pua")->enabled) { dboptions |= CL_DB_PUA; if((opt = optget(opts, "exclude-pua"))->enabled) { dboptions |= CL_DB_PUA_EXCLUDE; i = 0; while(opt) { if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) { logg("!Can't allocate memory for pua_cats\n"); cl_engine_free(engine); return 2; } sprintf(pua_cats + i, ".%s", opt->strarg); i += strlen(opt->strarg) + 1; pua_cats[i] = 0; opt = opt->nextarg; } pua_cats[i] = '.'; pua_cats[i + 1] = 0; } if((opt = optget(opts, "include-pua"))->enabled) { if(pua_cats) { logg("!--exclude-pua and --include-pua cannot be used at the same time\n"); cl_engine_free(engine); free(pua_cats); return 2; } dboptions |= CL_DB_PUA_INCLUDE; i = 0; while(opt) { if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) { logg("!Can't allocate memory for pua_cats\n"); cl_engine_free(engine); return 2; } sprintf(pua_cats + i, ".%s", opt->strarg); i += strlen(opt->strarg) + 1; pua_cats[i] = 0; opt = opt->nextarg; } pua_cats[i] = '.'; pua_cats[i + 1] = 0; } if(pua_cats) { if((ret = cl_engine_set_str(engine, CL_ENGINE_PUA_CATEGORIES, pua_cats))) { logg("!cli_engine_set_str(CL_ENGINE_PUA_CATEGORIES) failed: %s\n", cl_strerror(ret)); free(pua_cats); cl_engine_free(engine); return 2; } free(pua_cats); } } if(optget(opts, "dev-ac-only")->enabled) cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1); if(optget(opts, "dev-ac-depth")->enabled) cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, optget(opts, "dev-ac-depth")->numarg); if(optget(opts, "leave-temps")->enabled) cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1); if(optget(opts, "force-to-disk")->enabled) cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1); if(optget(opts, "bytecode-unsigned")->enabled) dboptions |= CL_DB_BYTECODE_UNSIGNED; if((opt = optget(opts,"bytecode-timeout"))->enabled) cl_engine_set_num(engine, CL_ENGINE_BYTECODE_TIMEOUT, opt->numarg); if (optget(opts, "nocerts")->enabled) cl_engine_set_num(engine, CL_ENGINE_DISABLE_PE_CERTS, 1); if (optget(opts, "dumpcerts")->enabled) cl_engine_set_num(engine, CL_ENGINE_PE_DUMPCERTS, 1); if((opt = optget(opts,"bytecode-mode"))->enabled) { enum bytecode_mode mode; if (!strcmp(opt->strarg, "ForceJIT")) mode = CL_BYTECODE_MODE_JIT; else if(!strcmp(opt->strarg, "ForceInterpreter")) mode = CL_BYTECODE_MODE_INTERPRETER; else if(!strcmp(opt->strarg, "Test")) mode = CL_BYTECODE_MODE_TEST; else mode = CL_BYTECODE_MODE_AUTO; cl_engine_set_num(engine, CL_ENGINE_BYTECODE_MODE, mode); } if((opt = optget(opts, "statistics"))->enabled) { while(opt) { if (!strcasecmp(opt->strarg, "bytecode")) { dboptions |= CL_DB_BYTECODE_STATS; } else if (!strcasecmp(opt->strarg, "pcre")) { dboptions |= CL_DB_PCRE_STATS; } opt = opt->nextarg; } } if((opt = optget(opts, "tempdir"))->enabled) { if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) { logg("!cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "database"))->active) { while(opt) { if((ret = cl_load(opt->strarg, engine, &info.sigs, dboptions))) { logg("!%s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } opt = opt->nextarg; } } else { char *dbdir = freshdbdir(); if((ret = cl_load(dbdir, engine, &info.sigs, dboptions))) { logg("!%s\n", cl_strerror(ret)); free(dbdir); cl_engine_free(engine); return 2; } free(dbdir); } /* pcre engine limits - required for cl_engine_compile */ if ((opt = optget(opts, "pcre-match-limit"))->active) { if ((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_MATCH_LIMIT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_PCRE_MATCH_LIMIT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if ((opt = optget(opts, "pcre-recmatch-limit"))->active) { if ((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_RECMATCH_LIMIT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_PCRE_RECMATCH_LIMIT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((ret = cl_engine_compile(engine)) != 0) { logg("!Database initialization error: %s\n", cl_strerror(ret));; cl_engine_free(engine); return 2; } if(optget(opts, "archive-verbose")->enabled) { cl_engine_set_clcb_meta(engine, meta); cl_engine_set_clcb_pre_cache(engine, pre); cl_engine_set_clcb_post_scan(engine, post); } /* set limits */ if((opt = optget(opts, "max-scansize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_SCANSIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-filesize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } #ifndef _WIN32 if(getrlimit(RLIMIT_FSIZE, &rlim) == 0) { if(rlim.rlim_cur < (rlim_t) cl_engine_get_num(engine, CL_ENGINE_MAX_FILESIZE, NULL)) logg("^System limit for file size is lower than engine->maxfilesize\n"); if(rlim.rlim_cur < (rlim_t) cl_engine_get_num(engine, CL_ENGINE_MAX_SCANSIZE, NULL)) logg("^System limit for file size is lower than engine->maxscansize\n"); } else { logg("^Cannot obtain resource limits for file size\n"); } #endif if((opt = optget(opts, "max-files"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILES, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_FILES) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-recursion"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_RECURSION, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_RECURSION) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } /* Engine max sizes */ if((opt = optget(opts, "max-embeddedpe"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_EMBEDDEDPE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_EMBEDDEDPE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-htmlnormalize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_HTMLNORMALIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_HTMLNORMALIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-htmlnotags"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_HTMLNOTAGS, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_HTMLNOTAGS) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-scriptnormalize"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCRIPTNORMALIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_SCRIPTNORMALIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-ziptypercg"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_ZIPTYPERCG, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_ZIPTYPERCG) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-partitions"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_PARTITIONS, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_PARTITIONS) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-iconspe"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_ICONSPE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_ICONSPE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "max-rechwp3"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_RECHWP3, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MAX_RECHWP3) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if ((opt = optget(opts, "timelimit"))->active) { if ((ret = cl_engine_set_num(engine, CL_ENGINE_TIME_LIMIT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_TIME_LIMIT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if ((opt = optget(opts, "pcre-max-filesize"))->active) { if ((ret = cl_engine_set_num(engine, CL_ENGINE_PCRE_MAX_FILESIZE, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_PCRE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } /* set scan options */ if(optget(opts, "allmatch")->enabled) { options |= CL_SCAN_ALLMATCHES; } if(optget(opts,"phishing-ssl")->enabled) options |= CL_SCAN_PHISHING_BLOCKSSL; if(optget(opts,"phishing-cloak")->enabled) options |= CL_SCAN_PHISHING_BLOCKCLOAK; if(optget(opts,"partition-intersection")->enabled) options |= CL_SCAN_PARTITION_INTXN; if(optget(opts,"heuristic-scan-precedence")->enabled) options |= CL_SCAN_HEURISTIC_PRECEDENCE; if(optget(opts, "scan-archive")->enabled) options |= CL_SCAN_ARCHIVE; if(optget(opts, "detect-broken")->enabled) options |= CL_SCAN_BLOCKBROKEN; if(optget(opts, "block-encrypted")->enabled) options |= CL_SCAN_BLOCKENCRYPTED; if(optget(opts, "block-macros")->enabled) options |= CL_SCAN_BLOCKMACROS; if(optget(opts, "scan-pe")->enabled) options |= CL_SCAN_PE; if(optget(opts, "scan-elf")->enabled) options |= CL_SCAN_ELF; if(optget(opts, "scan-ole2")->enabled) options |= CL_SCAN_OLE2; if(optget(opts, "scan-pdf")->enabled) options |= CL_SCAN_PDF; if(optget(opts, "scan-swf")->enabled) options |= CL_SCAN_SWF; if(optget(opts, "scan-html")->enabled && optget(opts, "normalize")->enabled) options |= CL_SCAN_HTML; if(optget(opts, "scan-mail")->enabled) options |= CL_SCAN_MAIL; if(optget(opts, "scan-xmldocs")->enabled) options |= CL_SCAN_XMLDOCS; if(optget(opts, "scan-hwp3")->enabled) options |= CL_SCAN_HWP3; if(optget(opts, "algorithmic-detection")->enabled) options |= CL_SCAN_ALGORITHMIC; if(optget(opts, "block-max")->enabled) { options |= CL_SCAN_BLOCKMAX; } #ifdef HAVE__INTERNAL__SHA_COLLECT if(optget(opts, "dev-collect-hashes")->enabled) options |= CL_SCAN_INTERNAL_COLLECT_SHA; #endif if(optget(opts, "dev-performance")->enabled) options |= CL_SCAN_PERFORMANCE_INFO; if(optget(opts, "detect-structured")->enabled) { options |= CL_SCAN_STRUCTURED; if((opt = optget(opts, "structured-ssn-format"))->enabled) { switch(opt->numarg) { case 0: options |= CL_SCAN_STRUCTURED_SSN_NORMAL; break; case 1: options |= CL_SCAN_STRUCTURED_SSN_STRIPPED; break; case 2: options |= (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED); break; default: logg("!Invalid argument for --structured-ssn-format\n"); return 2; } } else { options |= CL_SCAN_STRUCTURED_SSN_NORMAL; } if((opt = optget(opts, "structured-ssn-count"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_SSN_COUNT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MIN_SSN_COUNT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } if((opt = optget(opts, "structured-cc-count"))->active) { if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_CC_COUNT, opt->numarg))) { logg("!cli_engine_set_num(CL_ENGINE_MIN_CC_COUNT) failed: %s\n", cl_strerror(ret)); cl_engine_free(engine); return 2; } } } else { options &= ~CL_SCAN_STRUCTURED; } #ifdef C_LINUX procdev = (dev_t) 0; if(CLAMSTAT("/proc", &sb) != -1 && !sb.st_size) procdev = sb.st_dev; #endif #if HAVE_JSON if (optget(opts, "gen-json")->enabled) options |= CL_SCAN_FILE_PROPERTIES; #endif /* check filetype */ if(!opts->filename && !optget(opts, "file-list")->enabled) { /* we need full path for some reasons (eg. archive handling) */ if(!getcwd(cwd, sizeof(cwd))) { logg("!Can't get absolute pathname of current working directory\n"); ret = 2; } else { CLAMSTAT(cwd, &sb); scandirs(cwd, engine, opts, options, 1, sb.st_dev); } } else if(opts->filename && !optget(opts, "file-list")->enabled && !strcmp(opts->filename[0], "-")) { /* read data from stdin */ ret = scanstdin(engine, opts, options); } else { if(opts->filename && optget(opts, "file-list")->enabled) logg("^Only scanning files from --file-list (files passed at cmdline are ignored)\n"); while((filename = filelist(opts, &ret)) && (file = strdup(filename))) { if(LSTAT(file, &sb) == -1) { perror(file); logg("^%s: Can't access file\n", file); ret = 2; } else { for(i = strlen(file) - 1; i > 0; i--) { if(file[i] == *PATHSEP) file[i] = 0; else break; } if(S_ISLNK(sb.st_mode)) { if(dirlnk == 0 && filelnk == 0) { if(!printinfected) logg("%s: Symbolic link\n", file); } else if(CLAMSTAT(file, &sb) != -1) { if(S_ISREG(sb.st_mode) && filelnk) { scanfile(file, engine, opts, options); } else if(S_ISDIR(sb.st_mode) && dirlnk) { scandirs(file, engine, opts, options, 1, sb.st_dev); } else { if(!printinfected) logg("%s: Symbolic link\n", file); } } } else if(S_ISREG(sb.st_mode)) { scanfile(file, engine, opts, options); } else if(S_ISDIR(sb.st_mode)) { scandirs(file, engine, opts, options, 1, sb.st_dev); } else { logg("^%s: Not supported file type\n", file); ret = 2; } } free(file); } } if((opt = optget(opts, "statistics"))->enabled) { while(opt) { if (!strcasecmp(opt->strarg, "bytecode")) { cli_sigperf_print(); cli_sigperf_events_destroy(); } #if HAVE_PCRE else if (!strcasecmp(opt->strarg, "pcre")) { cli_pcre_perf_print(); cli_pcre_perf_events_destroy(); } #endif opt = opt->nextarg; } } /* free the engine */ cl_engine_free(engine); /* overwrite return code - infection takes priority */ if(info.ifiles) ret = 1; else if(info.errors) ret = 2; return ret; }
static void scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, unsigned int options, unsigned int depth, dev_t dev) { DIR *dd; struct dirent *dent; STATBUF sb; char *fname; int included; const struct optstruct *opt; unsigned int dirlnk, filelnk; if((opt = optget(opts, "exclude-dir"))->enabled) { while(opt) { if(match_regex(dirname, opt->strarg) == 1) { if(!printinfected) logg("~%s: Excluded\n", dirname); return; } opt = opt->nextarg; } } if((opt = optget(opts, "include-dir"))->enabled) { included = 0; while(opt) { if(match_regex(dirname, opt->strarg) == 1) { included = 1; break; } opt = opt->nextarg; } if(!included) { if(!printinfected) logg("~%s: Excluded\n", dirname); return; } } if(depth > (unsigned int) optget(opts, "max-dir-recursion")->numarg) return; dirlnk = optget(opts, "follow-dir-symlinks")->numarg; filelnk = optget(opts, "follow-file-symlinks")->numarg; if((dd = opendir(dirname)) != NULL) { info.dirs++; depth++; while((dent = readdir(dd))) { if(dent->d_ino) { if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) { /* build the full name */ fname = malloc(strlen(dirname) + strlen(dent->d_name) + 2); if (fname == NULL) { /* oops, malloc() failed, print warning and return */ logg("!scandirs: Memory allocation failed for fname\n"); break; } if(!strcmp(dirname, PATHSEP)) sprintf(fname, PATHSEP"%s", dent->d_name); else sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name); /* stat the file */ if(LSTAT(fname, &sb) != -1) { if(!optget(opts, "cross-fs")->enabled) { if(sb.st_dev != dev) { if(!printinfected) logg("~%s: Excluded\n", fname); free(fname); continue; } } if(S_ISLNK(sb.st_mode)) { if(dirlnk != 2 && filelnk != 2) { if(!printinfected) logg("%s: Symbolic link\n", fname); } else if(CLAMSTAT(fname, &sb) != -1) { if(S_ISREG(sb.st_mode) && filelnk == 2) { scanfile(fname, engine, opts, options); } else if(S_ISDIR(sb.st_mode) && dirlnk == 2) { if(recursion) scandirs(fname, engine, opts, options, depth, dev); } else { if(!printinfected) logg("%s: Symbolic link\n", fname); } } } else if(S_ISREG(sb.st_mode)) { scanfile(fname, engine, opts, options); } else if(S_ISDIR(sb.st_mode) && recursion) { scandirs(fname, engine, opts, options, depth, dev); } } free(fname); } } } closedir(dd); } else { if(!printinfected) logg("~%s: Can't open directory.\n", dirname); info.errors++; } }
int remove_tree (const char *root) { char new_name[1024]; int err = 0; struct DIRECT *ent; struct stat sb; DIR *dir; /* * Make certain the directory exists. */ if (access (root, F_OK) != 0) return -1; /* * Open the source directory and read each entry. Every file * entry in the directory is copied with the UID and GID set * to the provided values. As an added security feature only * regular files (and directories ...) are copied, and no file * is made set-ID. */ dir = opendir (root); while ((ent = readdir (dir))) { /* * Skip the "." and ".." entries */ if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) continue; /* * Make the filename for the current entry. */ if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) { err++; break; } snprintf (new_name, sizeof new_name, "%s/%s", root, ent->d_name); if (LSTAT (new_name, &sb) == -1) continue; if (S_ISDIR (sb.st_mode)) { /* * Recursively delete this directory. */ if (remove_tree (new_name)) { err++; break; } if (rmdir (new_name)) { err++; break; } continue; } unlink (new_name); } closedir (dir); return err ? -1 : 0; }
int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid) { char src_name[1024]; char dst_name[1024]; char buf[1024]; int ifd; int ofd; int err = 0; int cnt; int set_orig = 0; struct DIRECT *ent; struct stat sb; struct link_name *lp; DIR *dir; /* * Make certain both directories exist. This routine is called * after the home directory is created, or recursively after the * target is created. It assumes the target directory exists. */ if (access (src_root, F_OK) != 0 || access (dst_root, F_OK) != 0) return -1; /* * Open the source directory and read each entry. Every file * entry in the directory is copied with the UID and GID set * to the provided values. As an added security feature only * regular files (and directories ...) are copied, and no file * is made set-ID. */ if (!(dir = opendir (src_root))) return -1; if (src_orig == 0) { src_orig = src_root; dst_orig = dst_root; set_orig++; } while ((ent = readdir (dir))) { /* * Skip the "." and ".." entries */ if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) continue; /* * Make the filename for both the source and the * destination files. */ if (strlen (src_root) + strlen (ent->d_name) + 2 > sizeof src_name) { err++; break; } snprintf (src_name, sizeof src_name, "%s/%s", src_root, ent->d_name); if (strlen (dst_root) + strlen (ent->d_name) + 2 > sizeof dst_name) { err++; break; } snprintf (dst_name, sizeof dst_name, "%s/%s", dst_root, ent->d_name); if (LSTAT (src_name, &sb) == -1) continue; if (S_ISDIR (sb.st_mode)) { /* * Create a new target directory, make it owned by * the user and then recursively copy that directory. */ #ifdef WITH_SELINUX selinux_file_context (dst_name); #endif mkdir (dst_name, sb.st_mode & 0777); chown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, gid == (gid_t) - 1 ? sb.st_gid : gid); if (copy_tree (src_name, dst_name, uid, gid)) { err++; break; } continue; } #ifdef S_IFLNK /* * Copy any symbolic links */ if (S_ISLNK (sb.st_mode)) { char oldlink[1024]; char dummy[1024]; int len; /* * Get the name of the file which the link points * to. If that name begins with the original * source directory name, that part of the link * name will be replaced with the original * destinateion directory name. */ if ((len = readlink (src_name, oldlink, sizeof (oldlink) - 1)) < 0) { err++; break; } oldlink[len] = '\0'; /* readlink() does not NUL-terminate */ if (!strncmp (oldlink, src_orig, strlen (src_orig))) { snprintf (dummy, sizeof dummy, "%s%s", dst_orig, oldlink + strlen (src_orig)); strcpy (oldlink, dummy); } #ifdef WITH_SELINUX selinux_file_context (dst_name); #endif if (symlink (oldlink, dst_name) || lchown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, gid == (gid_t) - 1 ? sb.st_gid : gid)) { err++; break; } continue; } #endif /* * See if this is a previously copied link */ if ((lp = check_link (src_name, &sb))) { if (link (lp->ln_name, dst_name)) { err++; break; } if (unlink (src_name)) { err++; break; } if (--lp->ln_count <= 0) remove_link (lp); continue; } /* * Deal with FIFOs and special files. The user really * shouldn't have any of these, but it seems like it * would be nice to copy everything ... */ if (!S_ISREG (sb.st_mode)) { #ifdef WITH_SELINUX selinux_file_context (dst_name); #endif if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) || chown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, gid == (gid_t) - 1 ? sb.st_gid : gid) || chmod (dst_name, sb.st_mode & 07777)) { err++; break; } continue; } /* * Create the new file and copy the contents. The new * file will be owned by the provided UID and GID values. */ if ((ifd = open (src_name, O_RDONLY)) < 0) { err++; break; } #ifdef WITH_SELINUX selinux_file_context (dst_name); #endif if ((ofd = open (dst_name, O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0 || chown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, gid == (gid_t) - 1 ? sb.st_gid : gid) || chmod (dst_name, sb.st_mode & 07777)) { close (ifd); err++; break; } while ((cnt = read (ifd, buf, sizeof buf)) > 0) { if (write (ofd, buf, cnt) != cnt) { cnt = -1; break; } } close (ifd); close (ofd); if (cnt == -1) { err++; break; } } closedir (dir); if (set_orig) { src_orig = 0; dst_orig = 0; } return err ? -1 : 0; }