Example #1
0
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;
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #4
0
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);
	}
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
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);
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
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;
}
Example #13
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;
}
Example #14
0
/*
 * 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;
}
Example #15
0
/*
 * 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;
}
Example #16
0
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;
}
Example #17
0
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);
	}
}
Example #18
0
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;
}
Example #19
0
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++;
    }
}
Example #20
0
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;
}
Example #21
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;
}