lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 27 Jun 2018 18:14:47 +0200
From:   Lukas Czerner <lczerner@...hat.com>
To:     "Theodore Y. Ts'o" <tytso@....edu>
Cc:     linux-ext4@...r.kernel.org, adilger@...ger.ca
Subject: Re: test f_extent_htree fails on 1.44.3-rc1

On Wed, Jun 27, 2018 at 10:44:39AM -0400, Theodore Y. Ts'o wrote:
> On Wed, Jun 27, 2018 at 02:32:05PM +0200, Lukas Czerner wrote:
> > 
> > just letting you know that indeed, when disabling set_inode_xattr() in
> > __populate_fs() the test runs ok. If you don't already have one I'll
> > work on a patch to add this option.
> 
> Already done, I just didn't have a chance to send it out last night.

Meanwhile I've created something as well. I am not yet ready to send it
since I was going to review and create test for it. It has some more
functionality

It changes the -d option to work like this:

Options for populating file system with existing directory are separated by
comas, and may take an argument which is set off by an equals ('=') sign.
Directory option must be specified.

Valid options are:
	directory=<path to the directory to copy>
	owner=<uid>:<gid>
	noxattr

so you can do

mke2fs -d directory=/path/to/whatever,owner=200:200,noxattr /dev/device

I think I can also make it backwards compatible if needed. Just let me
know if I should finish, or drop it in favour of your version please.

Thanks!
-Lukas


diff --git a/misc/create_inode.c b/misc/create_inode.c
index caa36095..986c71c4 100644
--- a/misc/create_inode.c
+++ b/misc/create_inode.c
@@ -108,7 +108,7 @@ static errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino,
 
 /* Set the uid, gid, mode and time for the inode */
 static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t ino,
-				 struct stat *st)
+				 struct stat *st, uid_t uid, gid_t gid)
 {
 	errcode_t		retval;
 	struct ext2_inode	inode;
@@ -119,8 +119,14 @@ static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t ino,
 		return retval;
 	}
 
-	inode.i_uid = st->st_uid;
-	inode.i_gid = st->st_gid;
+	if (uid)
+		inode.i_uid = uid;
+	else
+		inode.i_uid = st->st_uid;
+	if (gid)
+		inode.i_gid = gid;
+	else
+		inode.i_gid = st->st_gid;
 	inode.i_mode |= st->st_mode;
 	inode.i_atime = st->st_atime;
 	inode.i_mtime = st->st_mtime;
@@ -712,13 +718,11 @@ static errcode_t path_append(struct file_info *target, const char *file)
 }
 
 /* Copy files from source_dir to fs */
-static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
-			       const char *source_dir, ext2_ino_t root,
-			       struct hdlinks_s *hdlinks,
+static errcode_t __populate_fs(ext2_filsys fs, struct hdlinks_s *hdlinks,
 			       struct file_info *target,
-			       struct fs_ops_callbacks *fs_callbacks)
+			       struct populate_fs_opts *pfs)
 {
-	const char	*name;
+	char		*name;
 	DIR		*dh;
 	struct dirent	*dent;
 	struct stat	st;
@@ -729,19 +733,22 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 	int		read_cnt;
 	int		hdlink;
 	size_t		cur_dir_path_len;
+	struct populate_fs_opts	pfs_r;
 
-	if (chdir(source_dir) < 0) {
+	memset(&pfs_r, 0, sizeof(struct populate_fs_opts));
+
+	if (chdir(pfs->source_dir) < 0) {
 		retval = errno;
 		com_err(__func__, retval,
 			_("while changing working directory to \"%s\""),
-			source_dir);
+			pfs->source_dir);
 		return retval;
 	}
 
 	if (!(dh = opendir("."))) {
 		retval = errno;
 		com_err(__func__, retval,
-			_("while opening directory \"%s\""), source_dir);
+			_("while opening directory \"%s\""), pfs->source_dir);
 		return retval;
 	}
 
@@ -763,7 +770,7 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 		    st.st_nlink > 1) {
 			hdlink = is_hardlink(hdlinks, st.st_dev, st.st_ino);
 			if (hdlink >= 0) {
-				retval = add_link(fs, parent_ino,
+				retval = add_link(fs, pfs->parent_ino,
 						  hdlinks->hdl[hdlink].dst_ino,
 						  name);
 				if (retval) {
@@ -784,9 +791,9 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 			goto out;
 		}
 
-		if (fs_callbacks && fs_callbacks->create_new_inode) {
-			retval = fs_callbacks->create_new_inode(fs,
-				target->path, name, parent_ino, root,
+		if (pfs->fs_callbacks && pfs->fs_callbacks->create_new_inode) {
+			retval = pfs->fs_callbacks->create_new_inode(fs,
+				target->path, name, pfs->parent_ino, pfs->root,
 				st.st_mode & S_IFMT);
 			if (retval)
 				goto out;
@@ -798,7 +805,8 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 		case S_IFIFO:
 #ifndef _WIN32
 		case S_IFSOCK:
-			retval = do_mknod_internal(fs, parent_ino, name, &st);
+			retval = do_mknod_internal(fs, pfs->parent_ino, name,
+						   &st);
 			if (retval) {
 				com_err(__func__, retval,
 					_("while creating special file "
@@ -831,8 +839,8 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 				goto out;
 			}
 			ln_target[read_cnt] = '\0';
-			retval = do_symlink_internal(fs, parent_ino, name,
-						     ln_target, root);
+			retval = do_symlink_internal(fs, pfs->parent_ino, name,
+						     ln_target, pfs->root);
 			free(ln_target);
 			if (retval) {
 				com_err(__func__, retval,
@@ -843,8 +851,8 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 			break;
 #endif
 		case S_IFREG:
-			retval = do_write_internal(fs, parent_ino, name, name,
-						   root);
+			retval = do_write_internal(fs, pfs->parent_ino,
+						   name, name, pfs->root);
 			if (retval) {
 				com_err(__func__, retval,
 					_("while writing file \"%s\""), name);
@@ -853,26 +861,29 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 			break;
 		case S_IFDIR:
 			/* Don't choke on /lost+found */
-			if (parent_ino == EXT2_ROOT_INO &&
+			if (pfs->parent_ino == EXT2_ROOT_INO &&
 			    strcmp(name, "lost+found") == 0)
 				goto find_lnf;
-			retval = do_mkdir_internal(fs, parent_ino, name,
-						   root);
+			retval = do_mkdir_internal(fs, pfs->parent_ino, name,
+						   pfs->root);
 			if (retval) {
 				com_err(__func__, retval,
 					_("while making dir \"%s\""), name);
 				goto out;
 			}
 find_lnf:
-			retval = ext2fs_namei(fs, root, parent_ino,
+			retval = ext2fs_namei(fs, pfs->root, pfs->parent_ino,
 					      name, &ino);
 			if (retval) {
 				com_err(name, retval, 0);
 					goto out;
 			}
 			/* Populate the dir recursively*/
-			retval = __populate_fs(fs, ino, name, root, hdlinks,
-					       target, fs_callbacks);
+			memcpy(&pfs_r, pfs, sizeof(struct populate_fs_opts));
+			pfs_r.parent_ino = ino;
+			pfs_r.source_dir = name;
+
+			retval = __populate_fs(fs, hdlinks, target, &pfs_r);
 			if (retval)
 				goto out;
 			if (chdir("..")) {
@@ -887,30 +898,35 @@ find_lnf:
 				_("ignoring entry \"%s\""), name);
 		}
 
-		retval =  ext2fs_namei(fs, root, parent_ino, name, &ino);
+		retval =  ext2fs_namei(fs, pfs->root, pfs->parent_ino, name,
+				       &ino);
 		if (retval) {
 			com_err(name, retval, _("while looking up \"%s\""),
 				name);
 			goto out;
 		}
 
-		retval = set_inode_extra(fs, ino, &st);
+		retval = set_inode_extra(fs, ino, &st, pfs->uid, pfs->gid);
 		if (retval) {
 			com_err(__func__, retval,
 				_("while setting inode for \"%s\""), name);
 			goto out;
 		}
 
-		retval = set_inode_xattr(fs, ino, name);
-		if (retval) {
-			com_err(__func__, retval,
-				_("while setting xattrs for \"%s\""), name);
-			goto out;
+		if (!(pfs->flags & POPULATE_FS_NOXATTR)) {
+			retval = set_inode_xattr(fs, ino, name);
+			if (retval) {
+				com_err(__func__, retval,
+					_("while setting xattrs for \"%s\""),
+					name);
+				goto out;
+			}
 		}
 
-		if (fs_callbacks && fs_callbacks->end_create_new_inode) {
-			retval = fs_callbacks->end_create_new_inode(fs,
-				target->path, name, parent_ino, root,
+		if (pfs->fs_callbacks &&
+		    pfs->fs_callbacks->end_create_new_inode) {
+			retval = pfs->fs_callbacks->end_create_new_inode(fs,
+				target->path, name, pfs->parent_ino, pfs->root,
 				st.st_mode & S_IFMT);
 			if (retval)
 				goto out;
@@ -950,9 +966,7 @@ out:
 	return retval;
 }
 
-errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
-		       const char *source_dir, ext2_ino_t root,
-		       struct fs_ops_callbacks *fs_callbacks)
+errcode_t populate_fs3(ext2_filsys fs, struct populate_fs_opts *pfs)
 {
 	struct file_info file_info;
 	struct hdlinks_s hdlinks;
@@ -976,16 +990,30 @@ errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
 	file_info.path_max_len = 255;
 	file_info.path = calloc(file_info.path_max_len, 1);
 
-	retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks,
-			       &file_info, fs_callbacks);
+	retval = __populate_fs(fs, &hdlinks, &file_info, pfs);
 
 	free(file_info.path);
 	free(hdlinks.hdl);
 	return retval;
 }
 
+errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
+		       char *source_dir, ext2_ino_t root,
+		       struct fs_ops_callbacks *fs_callbacks)
+{
+	struct populate_fs_opts pfs;
+
+	memset(&pfs, 0, sizeof(struct populate_fs_opts));
+	pfs.parent_ino = parent_ino;
+	pfs.root = root;
+	pfs.source_dir = source_dir;
+	pfs.fs_callbacks = fs_callbacks;
+
+	return populate_fs3(fs, &pfs);
+}
+
 errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
-		      const char *source_dir, ext2_ino_t root)
+		      char *source_dir, ext2_ino_t root)
 {
 	return populate_fs2(fs, parent_ino, source_dir, root, NULL);
 }
diff --git a/misc/create_inode.h b/misc/create_inode.h
index 17309c68..83e109b1 100644
--- a/misc/create_inode.h
+++ b/misc/create_inode.h
@@ -33,12 +33,25 @@ struct fs_ops_callbacks {
 		ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
 };
 
+#define POPULATE_FS_NOXATTR	1
+
+struct populate_fs_opts {
+	ext2_ino_t			parent_ino;
+	ext2_ino_t			root;
+	char 				*source_dir;
+	struct fs_ops_callbacks		*fs_callbacks;
+	uid_t				uid;
+	gid_t				gid;
+	int				flags;
+};
+
 /* For populating the filesystem */
 extern errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
-			     const char *source_dir, ext2_ino_t root);
+			     char *source_dir, ext2_ino_t root);
 extern errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
-			      const char *source_dir, ext2_ino_t root,
+			      char *source_dir, ext2_ino_t root,
 			      struct fs_ops_callbacks *fs_callbacks);
+extern errcode_t populate_fs3(ext2_filsys fs, struct populate_fs_opts *);
 extern errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd,
 				   const char *name, struct stat *st);
 extern errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd,
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index ce78b7c8..14796a54 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -113,7 +113,7 @@ static char *mount_dir;
 char *journal_device;
 static int sync_kludge;	/* Set using the MKE2FS_SYNC env. option */
 char **fs_types;
-const char *src_root_dir;  /* Copy files from the specified directory */
+struct populate_fs_opts *pfs = NULL; /* Copy the contents of the fiven directory */
 static char *undo_file;
 
 static int android_sparse_file; /* -E android_sparse */
@@ -782,6 +782,96 @@ static int set_os(struct ext2_super_block *sb, char *os)
 
 #define PATH_SET "PATH=/sbin"
 
+static void parse_populate_opts(struct populate_fs_opts *pfs,
+			       const char *opts)
+{
+	char	*buf, *token, *next, *p, *arg, *badopt = 0;
+	int	len;
+	int	usage = 0;
+	int	ret, i;
+
+	len = strlen(opts);
+	buf = malloc(len + 1);
+	if (!buf) {
+		fprintf(stderr, "%s",
+			_("Couldn't allocate memory to parse options!\n"));
+		exit(1);
+	}
+	strncpy(buf, opts, len + 1);
+	for (token = buf; token && *token; token = next) {
+		p = strchr(token, ',');
+		next = 0;
+		if (p) {
+			*p = 0;
+			next = p+1;
+		}
+		arg = strchr(token, '=');
+		if (arg) {
+			*arg = 0;
+			arg++;
+		}
+
+		if (strcmp(token, "directory") == 0) {
+			if (!arg) {
+				usage++;
+				badopt = token;
+				continue;
+			}
+			pfs->source_dir = strndup(arg, PATH_MAX);
+		} else if (strcmp(token, "owner") == 0) {
+			if (arg) {
+				pfs->uid = strtoul(arg, &p, 0);
+				if (*p != ':') {
+					fprintf(stderr,
+						_("Invalid owner: '%s'\n"),
+						arg);
+					usage++;
+					continue;
+				}
+				p++;
+				pfs->gid = strtoul(p, &p, 0);
+				if (*p) {
+					fprintf(stderr,
+						_("Invalid owner: '%s'\n"),
+						arg);
+					usage++;
+					continue;
+				}
+			} else {
+				pfs->uid = getuid();
+				pfs->gid = getgid();
+			}
+		} else if (strcmp(token, "noxattr") == 0) {
+			pfs->flags |= POPULATE_FS_NOXATTR;
+		} else {
+			usage++;
+			badopt = token;
+		}
+	}
+	/* source dir is mandatory */
+	if (!pfs->source_dir)
+		usage++;
+
+	if (usage) {
+		fprintf(stderr, _("\nBad option(s) specified: %s\n\n"
+			"Options for populating file system with existing "
+			"directory are separated by\n"
+			"comas, and may take an argument which is set off "
+			"by an equals ('=') sign.\n"
+			"Directory option must be specified."
+			"\n\nValid options are:\n"
+			"\tdirectory=<path to the directory to copy>\n"
+			"\towner=<uid>:<gid>\n"
+			"\tnoxattr\n"),
+			badopt ? badopt : "");
+		free(buf);
+		exit(1);
+	}
+
+	pfs->parent_ino = EXT2_ROOT_INO;
+	pfs->root = EXT2_ROOT_INO;
+}
+
 static void parse_extended_opts(struct ext2_super_block *param,
 				const char *opts)
 {
@@ -1488,6 +1578,7 @@ static void PRS(int argc, char *argv[])
 	errcode_t	retval;
 	char *		oldpath = getenv("PATH");
 	char *		extended_opts = 0;
+	char *		populate_opts = 0;
 	char *		fs_type = 0;
 	char *		usage_types = 0;
 	/*
@@ -1615,7 +1706,7 @@ profile_error:
 			}
 			break;
 		case 'd':
-			src_root_dir = optarg;
+			populate_opts = optarg;
 			break;
 		case 'D':
 			direct_io = 1;
@@ -2348,6 +2439,17 @@ profile_error:
 	if (extended_opts)
 		parse_extended_opts(&fs_param, extended_opts);
 
+	if (populate_opts) {
+		pfs = malloc(sizeof(struct populate_fs_opts));
+		if (!pfs) {
+			com_err(program_name, ENOMEM, "%s",
+				_("in malloc for populate_fs_opts"));
+			exit(1);
+		}
+		memset(pfs, 0, sizeof(struct populate_fs_opts));
+		parse_populate_opts(pfs, populate_opts);
+	}
+
 	if (explicit_fssize == 0 && offset > 0) {
 		fs_blocks_count -= offset / EXT2_BLOCK_SIZE(&fs_param);
 		ext2fs_blocks_count_set(&fs_param, fs_blocks_count);
@@ -3280,18 +3382,24 @@ no_journal:
 	if (retval)
 		com_err(program_name, retval, "while creating huge files");
 	/* Copy files from the specified directory */
-	if (src_root_dir) {
+	if (pfs) {
 		if (!quiet)
 			printf("%s", _("Copying files into the device: "));
 
+/*
 		retval = populate_fs(fs, EXT2_ROOT_INO, src_root_dir,
 				     EXT2_ROOT_INO);
+		*/
+		retval = populate_fs3(fs, pfs);
 		if (retval) {
 			com_err(program_name, retval, "%s",
 				_("while populating file system"));
 			exit(1);
 		} else if (!quiet)
 			printf("%s", _("done\n"));
+		if (pfs->source_dir)
+			free(pfs->source_dir);
+		free(pfs);
 	}
 
 	if (!quiet)

> 
> commit 8cec4acdc03a449e8b193948ebce22fe4ad21324
> Author: Theodore Ts'o <tytso@....edu>
> Date:   Tue Jun 26 15:21:28 2018 -0400
> 
>     tests, mke2fs: add option to suppress xattr copying to fix f_extent_htree
>     
>     If the developer is running with SELinux enabled on /tmp, the
>     f_extent_htree regression test will fail because mke2fs by default
>     copies the extended attributes into the newly created file system (if
>     a directory hierarchy is specified via the -d option).
>     
>     Fix this by adding a new extended option to mke2fs, -E no_copy_xattrs
>     and using it in f_extent_htree's test script.
>     
>     Reported-by: Lukas Czerner <lczerner@...hat.com>
>     Signed-off-by: Theodore Ts'o <tytso@....edu>
> 
> diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
> index fe859d458..0b04508ef 100644
> --- a/debugfs/debugfs.c
> +++ b/debugfs/debugfs.c
> @@ -55,6 +55,7 @@ int sci_idx;
>  ext2_filsys	current_fs;
>  quota_ctx_t	current_qctx;
>  ext2_ino_t	root, cwd;
> +int		no_copy_xattrs;
>  
>  static int debugfs_setup_tdb(const char *device_name, char *undo_file,
>  			     io_manager *io_ptr)
> diff --git a/misc/create_inode.c b/misc/create_inode.c
> index 6621b0ab7..05aa63638 100644
> --- a/misc/create_inode.c
> +++ b/misc/create_inode.c
> @@ -142,6 +142,9 @@ static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino,
>  	char				*list = NULL;
>  	int				i;
>  
> +	if (no_copy_xattrs)
> +		return 0;
> +
>  	size = llistxattr(filename, NULL, 0);
>  	if (size == -1) {
>  		retval = errno;
> diff --git a/misc/create_inode.h b/misc/create_inode.h
> index 3a376322a..b5eeb420f 100644
> --- a/misc/create_inode.h
> +++ b/misc/create_inode.h
> @@ -33,6 +33,9 @@ struct fs_ops_callbacks {
>  		ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
>  };
>  
> +extern int no_copy_xattrs; 	/* this should eventually be a flag
> +				   passed to populate_fs3() */
> +
>  /* For populating the filesystem */
>  extern errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
>  			     const char *source_dir, ext2_ino_t root);
> diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
> index 7b989e0bd..603e37e54 100644
> --- a/misc/mke2fs.8.in
> +++ b/misc/mke2fs.8.in
> @@ -338,6 +338,15 @@ small risk if the system crashes before the journal has been overwritten
>  entirely one time.  If the option value is omitted, it defaults to 1 to
>  enable lazy journal inode zeroing.
>  .TP
> +.BI no_copy_xattrs
> +Normally
> +.B mke2fs
> +will copy the extended attributes of the files in the directory
> +hierarchy specified via the (optional)
> +.B \-d
> +option.  This will disable the copy and leaves the files in the newly
> +created file system without any extended attributes.
> +.TP
>  .BI num_backup_sb= <0|1|2>
>  If the
>  .B sparse_super2
> diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> index ce78b7c82..b23ea766c 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -95,6 +95,7 @@ int	journal_size;
>  int	journal_flags;
>  static int	lazy_itable_init;
>  static int	packed_meta_blocks;
> +int		no_copy_xattrs;
>  static char	*bad_blocks_filename = NULL;
>  static __u32	fs_stride;
>  /* Initialize usr/grp quotas by default */
> @@ -880,6 +881,9 @@ static void parse_extended_opts(struct ext2_super_block *param,
>  				r_usage++;
>  				continue;
>  			}
> +		} else if (strcmp(token, "no_copy_xattrs") == 0) {
> +			no_copy_xattrs = 1;
> +			continue;
>  		} else if (strcmp(token, "num_backup_sb") == 0) {
>  			if (!arg) {
>  				r_usage++;
> diff --git a/tests/f_extent_htree/script b/tests/f_extent_htree/script
> index ccd97e14f..4939accc3 100644
> --- a/tests/f_extent_htree/script
> +++ b/tests/f_extent_htree/script
> @@ -30,8 +30,8 @@ fi
>  # make filesystem with enough inodes and blocks to hold all the test files
>  > $TMPFILE
>  NUM=$((NUM * 5 / 3))
> -echo "mke2fs -b $BSIZE -O dir_index,extent -d$SRC -N$NUM $TMPFILE $NUM" >> $OUT
> -$MKE2FS -b $BSIZE -O dir_index,extent -d$SRC -N$NUM $TMPFILE $NUM >> $OUT 2>&1
> +echo "mke2fs -b $BSIZE -O dir_index,extent -E no_copy_xattrs -d$SRC -N$NUM $TMPFILE $NUM" >> $OUT
> +$MKE2FS -b $BSIZE -O dir_index,extent -E no_copy_xattrs -d$SRC -N$NUM $TMPFILE $NUM >> $OUT 2>&1
>  rm -r $SRC
>  
>  # Run e2fsck to convert dir to htree before deleting the files, as mke2fs
> 
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ