mirror of
				https://github.com/PowerShell/openssh-portable.git
				synced 2025-10-31 11:34:38 +01:00 
			
		
		
		
	upstream commit
move subprocess() so scp/sftp do not need uidswap.o; ok djm@ OpenBSD-Commit-ID: 6601b8360388542c2e5fef0f4085f8e54750bea8
This commit is contained in:
		
							parent
							
								
									b0d34132b3
								
							
						
					
					
						commit
						25cf9105b8
					
				
							
								
								
									
										155
									
								
								auth.c
									
									
									
									
									
								
							
							
						
						
									
										155
									
								
								auth.c
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | |||||||
| /* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm Exp $ */ | /* $OpenBSD: auth.c,v 1.125 2018/01/08 15:21:49 markus Exp $ */ | ||||||
| /*
 | /*
 | ||||||
|  * Copyright (c) 2000 Markus Friedl.  All rights reserved. |  * Copyright (c) 2000 Markus Friedl.  All rights reserved. | ||||||
|  * |  * | ||||||
| @ -28,6 +28,7 @@ | |||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <sys/socket.h> | #include <sys/socket.h> | ||||||
|  | #include <sys/wait.h> | ||||||
| 
 | 
 | ||||||
| #include <netinet/in.h> | #include <netinet/in.h> | ||||||
| 
 | 
 | ||||||
| @ -840,3 +841,155 @@ auth_get_canonical_hostname(struct ssh *ssh, int use_dns) | |||||||
| 		return dnsname; | 		return dnsname; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Runs command in a subprocess wuth a minimal environment. | ||||||
|  |  * Returns pid on success, 0 on failure. | ||||||
|  |  * The child stdout and stderr maybe captured, left attached or sent to | ||||||
|  |  * /dev/null depending on the contents of flags. | ||||||
|  |  * "tag" is prepended to log messages. | ||||||
|  |  * NB. "command" is only used for logging; the actual command executed is | ||||||
|  |  * av[0]. | ||||||
|  |  */ | ||||||
|  | pid_t | ||||||
|  | subprocess(const char *tag, struct passwd *pw, const char *command, | ||||||
|  |     int ac, char **av, FILE **child, u_int flags) | ||||||
|  | { | ||||||
|  | 	FILE *f = NULL; | ||||||
|  | 	struct stat st; | ||||||
|  | 	int fd, devnull, p[2], i; | ||||||
|  | 	pid_t pid; | ||||||
|  | 	char *cp, errmsg[512]; | ||||||
|  | 	u_int envsize; | ||||||
|  | 	char **child_env; | ||||||
|  | 
 | ||||||
|  | 	if (child != NULL) | ||||||
|  | 		*child = NULL; | ||||||
|  | 
 | ||||||
|  | 	debug3("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__, | ||||||
|  | 	    tag, command, pw->pw_name, flags); | ||||||
|  | 
 | ||||||
|  | 	/* Check consistency */ | ||||||
|  | 	if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && | ||||||
|  | 	    (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) { | ||||||
|  | 		error("%s: inconsistent flags", __func__); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) { | ||||||
|  | 		error("%s: inconsistent flags/output", __func__); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * If executing an explicit binary, then verify the it exists | ||||||
|  | 	 * and appears safe-ish to execute | ||||||
|  | 	 */ | ||||||
|  | 	if (*av[0] != '/') { | ||||||
|  | 		error("%s path is not absolute", tag); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	temporarily_use_uid(pw); | ||||||
|  | 	if (stat(av[0], &st) < 0) { | ||||||
|  | 		error("Could not stat %s \"%s\": %s", tag, | ||||||
|  | 		    av[0], strerror(errno)); | ||||||
|  | 		restore_uid(); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	if (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { | ||||||
|  | 		error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); | ||||||
|  | 		restore_uid(); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	/* Prepare to keep the child's stdout if requested */ | ||||||
|  | 	if (pipe(p) != 0) { | ||||||
|  | 		error("%s: pipe: %s", tag, strerror(errno)); | ||||||
|  | 		restore_uid(); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	restore_uid(); | ||||||
|  | 
 | ||||||
|  | 	switch ((pid = fork())) { | ||||||
|  | 	case -1: /* error */ | ||||||
|  | 		error("%s: fork: %s", tag, strerror(errno)); | ||||||
|  | 		close(p[0]); | ||||||
|  | 		close(p[1]); | ||||||
|  | 		return 0; | ||||||
|  | 	case 0: /* child */ | ||||||
|  | 		/* Prepare a minimal environment for the child. */ | ||||||
|  | 		envsize = 5; | ||||||
|  | 		child_env = xcalloc(sizeof(*child_env), envsize); | ||||||
|  | 		child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH); | ||||||
|  | 		child_set_env(&child_env, &envsize, "USER", pw->pw_name); | ||||||
|  | 		child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name); | ||||||
|  | 		child_set_env(&child_env, &envsize, "HOME", pw->pw_dir); | ||||||
|  | 		if ((cp = getenv("LANG")) != NULL) | ||||||
|  | 			child_set_env(&child_env, &envsize, "LANG", cp); | ||||||
|  | 
 | ||||||
|  | 		for (i = 0; i < NSIG; i++) | ||||||
|  | 			signal(i, SIG_DFL); | ||||||
|  | 
 | ||||||
|  | 		if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { | ||||||
|  | 			error("%s: open %s: %s", tag, _PATH_DEVNULL, | ||||||
|  | 			    strerror(errno)); | ||||||
|  | 			_exit(1); | ||||||
|  | 		} | ||||||
|  | 		if (dup2(devnull, STDIN_FILENO) == -1) { | ||||||
|  | 			error("%s: dup2: %s", tag, strerror(errno)); | ||||||
|  | 			_exit(1); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* Set up stdout as requested; leave stderr in place for now. */ | ||||||
|  | 		fd = -1; | ||||||
|  | 		if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) | ||||||
|  | 			fd = p[1]; | ||||||
|  | 		else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0) | ||||||
|  | 			fd = devnull; | ||||||
|  | 		if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) { | ||||||
|  | 			error("%s: dup2: %s", tag, strerror(errno)); | ||||||
|  | 			_exit(1); | ||||||
|  | 		} | ||||||
|  | 		closefrom(STDERR_FILENO + 1); | ||||||
|  | 
 | ||||||
|  | 		/* Don't use permanently_set_uid() here to avoid fatal() */ | ||||||
|  | 		if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { | ||||||
|  | 			error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, | ||||||
|  | 			    strerror(errno)); | ||||||
|  | 			_exit(1); | ||||||
|  | 		} | ||||||
|  | 		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { | ||||||
|  | 			error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, | ||||||
|  | 			    strerror(errno)); | ||||||
|  | 			_exit(1); | ||||||
|  | 		} | ||||||
|  | 		/* stdin is pointed to /dev/null at this point */ | ||||||
|  | 		if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && | ||||||
|  | 		    dup2(STDIN_FILENO, STDERR_FILENO) == -1) { | ||||||
|  | 			error("%s: dup2: %s", tag, strerror(errno)); | ||||||
|  | 			_exit(1); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		execve(av[0], av, child_env); | ||||||
|  | 		error("%s exec \"%s\": %s", tag, command, strerror(errno)); | ||||||
|  | 		_exit(127); | ||||||
|  | 	default: /* parent */ | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	close(p[1]); | ||||||
|  | 	if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) | ||||||
|  | 		close(p[0]); | ||||||
|  | 	else if ((f = fdopen(p[0], "r")) == NULL) { | ||||||
|  | 		error("%s: fdopen: %s", tag, strerror(errno)); | ||||||
|  | 		close(p[0]); | ||||||
|  | 		/* Don't leave zombie child */ | ||||||
|  | 		kill(pid, SIGTERM); | ||||||
|  | 		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) | ||||||
|  | 			; | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	/* Success */ | ||||||
|  | 	debug3("%s: %s pid %ld", __func__, tag, (long)pid); | ||||||
|  | 	if (child != NULL) | ||||||
|  | 		*child = f; | ||||||
|  | 	return pid; | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								auth.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								auth.h
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | |||||||
| /* $OpenBSD: auth.h,v 1.93 2017/08/18 05:36:45 djm Exp $ */ | /* $OpenBSD: auth.h,v 1.94 2018/01/08 15:21:49 markus Exp $ */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Copyright (c) 2000 Markus Friedl.  All rights reserved. |  * Copyright (c) 2000 Markus Friedl.  All rights reserved. | ||||||
| @ -221,6 +221,12 @@ void	 auth_debug_reset(void); | |||||||
| 
 | 
 | ||||||
| struct passwd *fakepw(void); | struct passwd *fakepw(void); | ||||||
| 
 | 
 | ||||||
|  | #define	SSH_SUBPROCESS_STDOUT_DISCARD  (1)     /* Discard stdout */ | ||||||
|  | #define	SSH_SUBPROCESS_STDOUT_CAPTURE  (1<<1)  /* Redirect stdout */ | ||||||
|  | #define	SSH_SUBPROCESS_STDERR_DISCARD  (1<<2)  /* Discard stderr */ | ||||||
|  | pid_t	subprocess(const char *, struct passwd *, | ||||||
|  |     const char *, int, char **, FILE **, u_int flags); | ||||||
|  | 
 | ||||||
| int	 sys_auth_passwd(Authctxt *, const char *); | int	 sys_auth_passwd(Authctxt *, const char *); | ||||||
| 
 | 
 | ||||||
| #define SKEY_PROMPT "\nS/Key Password: " | #define SKEY_PROMPT "\nS/Key Password: " | ||||||
|  | |||||||
							
								
								
									
										154
									
								
								misc.c
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								misc.c
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | |||||||
| /* $OpenBSD: misc.c,v 1.122 2017/12/08 02:14:33 djm Exp $ */ | /* $OpenBSD: misc.c,v 1.123 2018/01/08 15:21:49 markus Exp $ */ | ||||||
| /*
 | /*
 | ||||||
|  * Copyright (c) 2000 Markus Friedl.  All rights reserved. |  * Copyright (c) 2000 Markus Friedl.  All rights reserved. | ||||||
|  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved. |  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved. | ||||||
| @ -1740,158 +1740,6 @@ argv_assemble(int argc, char **argv) | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * Runs command in a subprocess wuth a minimal environment. |  | ||||||
|  * Returns pid on success, 0 on failure. |  | ||||||
|  * The child stdout and stderr maybe captured, left attached or sent to |  | ||||||
|  * /dev/null depending on the contents of flags. |  | ||||||
|  * "tag" is prepended to log messages. |  | ||||||
|  * NB. "command" is only used for logging; the actual command executed is |  | ||||||
|  * av[0]. |  | ||||||
|  */ |  | ||||||
| pid_t |  | ||||||
| subprocess(const char *tag, struct passwd *pw, const char *command, |  | ||||||
|     int ac, char **av, FILE **child, u_int flags) |  | ||||||
| { |  | ||||||
| 	FILE *f = NULL; |  | ||||||
| 	struct stat st; |  | ||||||
| 	int fd, devnull, p[2], i; |  | ||||||
| 	pid_t pid; |  | ||||||
| 	char *cp, errmsg[512]; |  | ||||||
| 	u_int envsize; |  | ||||||
| 	char **child_env; |  | ||||||
| 
 |  | ||||||
| 	if (child != NULL) |  | ||||||
| 		*child = NULL; |  | ||||||
| 
 |  | ||||||
| 	debug3("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__, |  | ||||||
| 	    tag, command, pw->pw_name, flags); |  | ||||||
| 
 |  | ||||||
| 	/* Check consistency */ |  | ||||||
| 	if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && |  | ||||||
| 	    (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) { |  | ||||||
| 		error("%s: inconsistent flags", __func__); |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 	if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) { |  | ||||||
| 		error("%s: inconsistent flags/output", __func__); |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * If executing an explicit binary, then verify the it exists |  | ||||||
| 	 * and appears safe-ish to execute |  | ||||||
| 	 */ |  | ||||||
| 	if (*av[0] != '/') { |  | ||||||
| 		error("%s path is not absolute", tag); |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 	temporarily_use_uid(pw); |  | ||||||
| 	if (stat(av[0], &st) < 0) { |  | ||||||
| 		error("Could not stat %s \"%s\": %s", tag, |  | ||||||
| 		    av[0], strerror(errno)); |  | ||||||
| 		restore_uid(); |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 	if (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { |  | ||||||
| 		error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); |  | ||||||
| 		restore_uid(); |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 	/* Prepare to keep the child's stdout if requested */ |  | ||||||
| 	if (pipe(p) != 0) { |  | ||||||
| 		error("%s: pipe: %s", tag, strerror(errno)); |  | ||||||
| 		restore_uid(); |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 	restore_uid(); |  | ||||||
| 
 |  | ||||||
| 	switch ((pid = fork())) { |  | ||||||
| 	case -1: /* error */ |  | ||||||
| 		error("%s: fork: %s", tag, strerror(errno)); |  | ||||||
| 		close(p[0]); |  | ||||||
| 		close(p[1]); |  | ||||||
| 		return 0; |  | ||||||
| 	case 0: /* child */ |  | ||||||
| 		/* Prepare a minimal environment for the child. */ |  | ||||||
| 		envsize = 5; |  | ||||||
| 		child_env = xcalloc(sizeof(*child_env), envsize); |  | ||||||
| 		child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH); |  | ||||||
| 		child_set_env(&child_env, &envsize, "USER", pw->pw_name); |  | ||||||
| 		child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name); |  | ||||||
| 		child_set_env(&child_env, &envsize, "HOME", pw->pw_dir); |  | ||||||
| 		if ((cp = getenv("LANG")) != NULL) |  | ||||||
| 			child_set_env(&child_env, &envsize, "LANG", cp); |  | ||||||
| 
 |  | ||||||
| 		for (i = 0; i < NSIG; i++) |  | ||||||
| 			signal(i, SIG_DFL); |  | ||||||
| 
 |  | ||||||
| 		if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { |  | ||||||
| 			error("%s: open %s: %s", tag, _PATH_DEVNULL, |  | ||||||
| 			    strerror(errno)); |  | ||||||
| 			_exit(1); |  | ||||||
| 		} |  | ||||||
| 		if (dup2(devnull, STDIN_FILENO) == -1) { |  | ||||||
| 			error("%s: dup2: %s", tag, strerror(errno)); |  | ||||||
| 			_exit(1); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/* Set up stdout as requested; leave stderr in place for now. */ |  | ||||||
| 		fd = -1; |  | ||||||
| 		if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) |  | ||||||
| 			fd = p[1]; |  | ||||||
| 		else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0) |  | ||||||
| 			fd = devnull; |  | ||||||
| 		if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) { |  | ||||||
| 			error("%s: dup2: %s", tag, strerror(errno)); |  | ||||||
| 			_exit(1); |  | ||||||
| 		} |  | ||||||
| 		closefrom(STDERR_FILENO + 1); |  | ||||||
| 
 |  | ||||||
| 		/* Don't use permanently_set_uid() here to avoid fatal() */ |  | ||||||
| 		if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { |  | ||||||
| 			error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, |  | ||||||
| 			    strerror(errno)); |  | ||||||
| 			_exit(1); |  | ||||||
| 		} |  | ||||||
| 		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { |  | ||||||
| 			error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, |  | ||||||
| 			    strerror(errno)); |  | ||||||
| 			_exit(1); |  | ||||||
| 		} |  | ||||||
| 		/* stdin is pointed to /dev/null at this point */ |  | ||||||
| 		if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 && |  | ||||||
| 		    dup2(STDIN_FILENO, STDERR_FILENO) == -1) { |  | ||||||
| 			error("%s: dup2: %s", tag, strerror(errno)); |  | ||||||
| 			_exit(1); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		execve(av[0], av, child_env); |  | ||||||
| 		error("%s exec \"%s\": %s", tag, command, strerror(errno)); |  | ||||||
| 		_exit(127); |  | ||||||
| 	default: /* parent */ |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	close(p[1]); |  | ||||||
| 	if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) |  | ||||||
| 		close(p[0]); |  | ||||||
| 	else if ((f = fdopen(p[0], "r")) == NULL) { |  | ||||||
| 		error("%s: fdopen: %s", tag, strerror(errno)); |  | ||||||
| 		close(p[0]); |  | ||||||
| 		/* Don't leave zombie child */ |  | ||||||
| 		kill(pid, SIGTERM); |  | ||||||
| 		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) |  | ||||||
| 			; |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 	/* Success */ |  | ||||||
| 	debug3("%s: %s pid %ld", __func__, tag, (long)pid); |  | ||||||
| 	if (child != NULL) |  | ||||||
| 		*child = f; |  | ||||||
| 	return pid; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* Returns 0 if pid exited cleanly, non-zero otherwise */ | /* Returns 0 if pid exited cleanly, non-zero otherwise */ | ||||||
| int | int | ||||||
| exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet) | exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet) | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								misc.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								misc.h
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | |||||||
| /* $OpenBSD: misc.h,v 1.69 2017/12/05 23:59:47 dtucker Exp $ */ | /* $OpenBSD: misc.h,v 1.70 2018/01/08 15:21:49 markus Exp $ */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Author: Tatu Ylonen <ylo@cs.hut.fi> |  * Author: Tatu Ylonen <ylo@cs.hut.fi> | ||||||
| @ -149,12 +149,6 @@ int	 argv_split(const char *, int *, char ***); | |||||||
| char	*argv_assemble(int, char **argv); | char	*argv_assemble(int, char **argv); | ||||||
| int	 exited_cleanly(pid_t, const char *, const char *, int); | int	 exited_cleanly(pid_t, const char *, const char *, int); | ||||||
| 
 | 
 | ||||||
| #define SSH_SUBPROCESS_STDOUT_DISCARD	(1)	/* Discard stdout */ |  | ||||||
| #define SSH_SUBPROCESS_STDOUT_CAPTURE	(1<<1)	/* Redirect stdout */ |  | ||||||
| #define SSH_SUBPROCESS_STDERR_DISCARD	(1<<2)	/* Discard stderr */ |  | ||||||
| pid_t	 subprocess(const char *, struct passwd *, |  | ||||||
|     const char *, int, char **, FILE **, u_int flags); |  | ||||||
| 
 |  | ||||||
| struct stat; | struct stat; | ||||||
| int	 safe_path(const char *, struct stat *, const char *, uid_t, | int	 safe_path(const char *, struct stat *, const char *, uid_t, | ||||||
| 	     char *, size_t); | 	     char *, size_t); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user