diff -Nuir rsync-3.0.6/authenticate.c rsync-3.0.6.new/authenticate.c
--- rsync-3.0.6/authenticate.c	2009-01-17 23:41:35.000000000 +0200
+++ rsync-3.0.6.new/authenticate.c	2009-08-26 15:44:30.625970000 +0300
@@ -247,16 +247,7 @@
 	}
 	*pass++ = '\0';
 
-	if (!(users = strdup(users)))
-		out_of_memory("auth_server");
-
-	for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
-		if (wildmatch(tok, line))
-			break;
-	}
-	free(users);
-
-	if (!tok) {
+	if (!user_in_list(line,users)) {
 		rprintf(FLOG, "auth failed on module %s from %s (%s): "
 			"unauthorized user\n",
 			lp_name(module), host, addr);
diff -Nuir rsync-3.0.6/clientserver.c rsync-3.0.6.new/clientserver.c
--- rsync-3.0.6/clientserver.c	2009-01-17 23:41:35.000000000 +0200
+++ rsync-3.0.6.new/clientserver.c	2009-08-26 15:52:55.410066548 +0300
@@ -467,6 +467,11 @@
 		return -1;
 	}
 
+	if (authorize_user(auth_user, i, &read_only) == 0 ){
+		io_printf(f_out, "@ERROR: user %s not authorized for module %s\n", auth_user, name);
+		return -1;
+	}
+
 	module_id = i;
 
 	if (lp_read_only(i))
@@ -483,7 +488,14 @@
 
 	if (am_root) {
 		p = lp_uid(i);
-		if (!name_to_uid(p, &uid)) {
+		if( !strcmp(p,"__auth__") ){
+			if( !name_to_uid(auth_user, &uid)) {
+				rprintf(FLOG, "Could not find uid for %s\n", auth_user);
+				io_printf(f_out, "@ERROR: could not find uid for %s\n", auth_user);
+				return -1;
+			}
+		}
+		else if (!name_to_uid(p, &uid)) {
 			if (!isDigit(p)) {
 				rprintf(FLOG, "Invalid uid %s\n", p);
 				io_printf(f_out, "@ERROR: invalid uid %s\n", p);
@@ -493,7 +505,14 @@
 		}
 
 		p = lp_gid(i);
-		if (!name_to_gid(p, &gid)) {
+		if( !strcmp(p,"__auth__") ){
+			if( !uname_to_gid(auth_user, &gid)) {
+				rprintf(FLOG, "Could not find gid for %s\n", auth_user);
+				io_printf(f_out, "@ERROR: could not find gid for %s\n", auth_user);
+				return -1;
+			}
+		}
+		else if (!name_to_gid(p, &gid)) {
 			if (!isDigit(p)) {
 				rprintf(FLOG, "Invalid gid %s\n", p);
 				io_printf(f_out, "@ERROR: invalid gid %s\n", p);
@@ -722,7 +741,7 @@
 		}
 #endif
 
-		if (setuid(uid)) {
+		if (setuid(uid) || seteuid(uid)) {
 			rsyserr(FLOG, errno, "setuid %d failed", (int)uid);
 			io_printf(f_out, "@ERROR: setuid failed\n");
 			return -1;
diff -Nuir rsync-3.0.6/loadparm.c rsync-3.0.6.new/loadparm.c
--- rsync-3.0.6/loadparm.c	2009-01-17 23:41:35.000000000 +0200
+++ rsync-3.0.6.new/loadparm.c	2009-08-26 15:58:29.048446915 +0300
@@ -122,6 +122,9 @@
 typedef struct
 {
 	char *auth_users;
+	char *rw_users;
+	char *ro_users;
+	char *deny_users;
 	char *charset;
 	char *comment;
 	char *dont_compress;
@@ -173,6 +176,9 @@
 static service sDefault =
 {
  /* auth_users; */		NULL,
+ /* rw_users; */		NULL,
+ /* ro_users; */		NULL,
+ /* deny_users; */		NULL,
  /* charset; */ 		NULL,
  /* comment; */ 		NULL,
  /* dont_compress; */		DEFAULT_DONT_COMPRESS,
@@ -303,6 +309,9 @@
  {"socket options",    P_STRING, P_GLOBAL,&Globals.socket_options,     NULL,0},
 
  {"auth users",        P_STRING, P_LOCAL, &sDefault.auth_users,        NULL,0},
+ {"rw users",		   P_STRING, P_LOCAL, &sDefault.rw_users,          NULL,0},
+ {"ro users",          P_STRING, P_LOCAL, &sDefault.ro_users,          NULL,0},
+ {"deny users",        P_STRING, P_LOCAL, &sDefault.deny_users,        NULL,0},
  {"charset",           P_STRING, P_LOCAL, &sDefault.charset,           NULL,0},
  {"comment",           P_STRING, P_LOCAL, &sDefault.comment,           NULL,0},
  {"dont compress",     P_STRING, P_LOCAL, &sDefault.dont_compress,     NULL,0},
@@ -396,6 +405,9 @@
 FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)
 
 FN_LOCAL_STRING(lp_auth_users, auth_users)
+FN_LOCAL_STRING(lp_rw_users, rw_users)
+FN_LOCAL_STRING(lp_ro_users, ro_users)
+FN_LOCAL_STRING(lp_deny_users, deny_users)
 FN_LOCAL_STRING(lp_charset, charset)
 FN_LOCAL_STRING(lp_comment, comment)
 FN_LOCAL_STRING(lp_dont_compress, dont_compress)
diff -Nuir rsync-3.0.6/main.c rsync-3.0.6.new/main.c
--- rsync-3.0.6/main.c	2009-02-05 04:27:07.000000000 +0200
+++ rsync-3.0.6.new/main.c	2009-08-26 16:00:02.611996546 +0300
@@ -43,6 +43,7 @@
 extern int do_stats;
 extern int got_xfer_error;
 extern int module_id;
+extern int read_only;
 extern int copy_links;
 extern int copy_dirlinks;
 extern int copy_unsafe_links;
@@ -692,7 +693,7 @@
 		exit_cleanup(RERR_SYNTAX);
 		return;
 	}
-	if (am_daemon && lp_read_only(module_id) && remove_source_files) {
+	if (am_daemon && (lp_read_only(module_id) || read_only) && remove_source_files) {
 		rprintf(FERROR,
 		    "ERROR: --remove-%s-files cannot be used with a read-only module\n",
 		    remove_source_files == 1 ? "source" : "sent");
@@ -861,7 +862,7 @@
 			argc, (long)getpid());
 	}
 
-	if (am_daemon && lp_read_only(module_id)) {
+	if (am_daemon && (lp_read_only(module_id) || read_only)) {
 		rprintf(FERROR,"ERROR: module is read only\n");
 		exit_cleanup(RERR_SYNTAX);
 		return;
diff -Nuir rsync-3.0.6/proto.h rsync-3.0.6.new/proto.h
--- rsync-3.0.6/proto.h	2009-05-08 20:43:22.000000000 +0300
+++ rsync-3.0.6.new/proto.h	2009-08-26 16:01:51.227724046 +0300
@@ -184,6 +184,9 @@
 char *lp_socket_options(void);
 int lp_rsync_port(void);
 char *lp_auth_users(int module_id);
+char *lp_rw_users(int module_id);
+char *lp_ro_users(int module_id);
+char *lp_deny_users(int module_id);
 char *lp_charset(int module_id);
 char *lp_comment(int module_id);
 char *lp_dont_compress(int module_id);
@@ -342,7 +345,11 @@
 pid_t do_fork(void);
 void kill_all(int sig);
 int name_to_uid(const char *name, uid_t *uid_p);
-int name_to_gid(const char *name, gid_t *gid_p);
+int uname_to_gid(const char *name, uid_t *gid_p);
+int name_to_gid(const char *name, gid_t *gid_p);
+int group_in_list(char *group, char *users);
+int user_in_list(char *user, char *users);
+int authorize_user(char *user, int module, int *read_only);
 int lock_range(int fd, int offset, int len);
 int glob_expand(const char *arg, char ***argv_p, int *argc_p, int *maxargs_p);
 void glob_expand_module(char *base1, char *arg, char ***argv_p, int *argc_p, int *maxargs_p);
diff -Nuir rsync-3.0.6/util.c rsync-3.0.6.new/util.c
--- rsync-3.0.6/util.c	2009-03-03 18:57:43.000000000 +0200
+++ rsync-3.0.6.new/util.c	2009-08-26 16:24:38.155679451 +0300
@@ -506,6 +506,18 @@
 	return 1;
 }
 
+/** Turn a user name into a gid */
+int uname_to_gid(const char *name, uid_t *gid_p)
+{
+	struct passwd *pass;
+	if (!name || !*name)
+		return 0;
+	if (!(pass = getpwnam(name)))
+		return 0;
+	*gid_p = pass->pw_gid;
+	return 1;
+}
+
 /** Turn a group name into a gid */
 int name_to_gid(const char *name, gid_t *gid_p)
 {
@@ -518,6 +530,156 @@
 	return 1;
 }
 
+/* Check if a user (not including his groups) are in the users list */
+int _user_in_list(char *user, char *users)
+{
+	char *user_list; 
+	char *tok;
+	char *p;
+
+	if (!(user_list = strdup(users)))
+		out_of_memory("user_in_list");
+
+	for (tok = strtok(user_list, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
+		if( *tok == '"'){
+			tok++;
+			p = strrchr(tok,'"');
+			if(p) *p=0;
+		}
+
+		if (wildmatch(tok, user))
+			break;
+	}
+	free(user_list);
+
+	if (tok) 
+		return 1;
+	else
+		return 0;
+}
+
+/* Check if a group is in the users list (simply concats the '@' sign to the name) */
+int group_in_list(char *group, char *users)
+{
+	char name[100];
+
+	snprintf(name,sizeof(name),"@%s",group);
+
+	return _user_in_list(name,users);
+}
+
+/* Check if a user or one of his groups are in the users list */
+int user_in_list(char *user, char *users)
+{
+	gid_t *groups;
+	int num_groups=0;
+	gid_t gid=-1;
+	int i;
+	int found = 0;
+
+	if( _user_in_list(user,users) )
+		return 1;
+
+	uname_to_gid(user,&gid);
+
+	if (getgrouplist(user, gid, NULL, &num_groups) < 0) 
+	{
+		groups = (gid_t *) malloc(num_groups * sizeof (gid_t));
+		if( !groups)
+			out_of_memory("authorize_user");
+
+		getgrouplist(user, gid, groups, &num_groups);
+	}
+
+	for( i = 0 ; i < num_groups ; i++ ){
+		if( group_in_list(getgrgid(groups[i])->gr_name,users) ){
+			found = 1;
+			break;
+		}
+	}
+
+	free(groups);
+	return found; 
+}
+
+int _authorize_user_groups(gid_t *groups, int num_groups, int module, int *read_only)
+{
+	int i;
+
+	if( read_only)
+		*read_only = 0; //default is read write (for backward compatibility)
+
+	for( i = 0 ; i < num_groups ; i++ ){
+		if( group_in_list(getgrgid(groups[i])->gr_name,lp_deny_users(module)) )
+			return 0;
+	}
+
+	for( i = 0 ; i < num_groups ; i++ ){
+		if( group_in_list(getgrgid(groups[i])->gr_name,lp_rw_users(module)) )
+			return 1;
+	}
+
+	for( i = 0 ; i < num_groups ; i++ ){
+		if( group_in_list(getgrgid(groups[i])->gr_name,lp_ro_users(module)) ){
+			if( read_only )
+				*read_only = 1;
+			return 1;
+		}		
+	}
+
+	return 1; //default is authorized (for backward compatibility)
+}
+
+/* Check if the user has authorization for a specific module.
+
+Authorization logic is as follows:
+1.	If the ACL contains a user-specific rule that matches the user, 
+	then the user is granted rights according to this rule (including denying access if the permission is “none”).
+2.	If the ACL contains a group-rule that denies access of a group the user belongs to (permission=none),  then access is denied.
+3.	If the ACL contains a group-rule that grants read/write access to a group the user belongs to, then the user gets read/write access
+4.	If the ACL contains a group-rule that grants read-only access to a group the user belongs to, then the user gets read-only access
+5.	The user is authorized access (for backward compatibility with older rsync versions)
+
+*/
+int authorize_user(char *user, int module, int *read_only)
+{
+	gid_t *groups;
+	int num_groups;
+	gid_t gid=-1;
+	int rc;
+
+	if( _user_in_list(user,lp_rw_users(module))){
+		if( read_only )
+			*read_only=0;
+		return 1;
+	}
+	else if( _user_in_list(user,lp_ro_users(module))){
+		if( read_only )
+			*read_only=1;
+		return 1;
+	}
+	else if( _user_in_list(user,lp_deny_users(module))){
+		//user in deny list
+		return 0;
+	}
+
+	uname_to_gid(user,&gid);
+
+	if (getgrouplist(user, gid, NULL, &num_groups) < 0) 
+	{
+		groups = (gid_t *) malloc(num_groups * sizeof (gid_t));
+		if( !groups)
+			out_of_memory("authorize_user");
+
+		getgrouplist(user, gid, groups, &num_groups);
+	}
+
+	rc = _authorize_user_groups(groups,num_groups,module,read_only);
+
+	free(groups);
+	return rc; 
+}
+
 /** Lock a byte range in a open file */
 int lock_range(int fd, int offset, int len)
 {
