[MEDIUM] add user/groupname support

Patch from Marcus Rueckert for 1.2.17 :
 "I added the attached patch to haproxy. I don't have a static uid/gid for
  haproxy so i need to specify the username/groupname to run it as non
  root user."
diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt
index ab26df5..dbe78f5 100644
--- a/doc/haproxy-en.txt
+++ b/doc/haproxy-en.txt
@@ -112,6 +112,8 @@
   - maxconn <number>
   - uid <user id>
   - gid <group id>
+  - user <user name>
+  - group <group name>
   - chroot <directory>
   - nbproc <number>
   - daemon
@@ -197,9 +199,14 @@
 which the process will switch to after binding its listening sockets. The value
 '0', which normally represents the super-user, here indicates that the UID must
 not change during startup. It's the default behaviour. The 'gid' parameter does
-the same for the group identifier. It's particularly advised against use of
-generic accounts such as 'nobody' because it has the same consequences as using
-'root' if other services use them.
+the same for the group identifier. If setting an uid is not possible because of
+deployment constraints, it is possible to set a user name with the 'user'
+keyword followed by a valid user name. The same is true for the gid. It is
+possible to specify a group name after the 'group' keyword.
+
+It is particularly advised against use of generic accounts such as 'nobody'
+because it has the same consequences as using 'root' if other services use
+them.
 
 The 'chroot' parameter makes the process isolate itself in an empty directory
 just before switching its UID. This type of isolation (chroot) can sometimes
@@ -227,11 +234,18 @@
 Example :
 ---------
 
+    # with uid/gid
     global
         uid     30000
         gid     30000
         chroot  /var/chroot/haproxy
 
+    # with user/group
+    global
+        user    haproxy
+        group   public
+        chroot  /var/chroot/haproxy
+
 
 1.4) Startup modes
 ------------------
diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt
index 9282cb4..7f6d231 100644
--- a/doc/haproxy-fr.txt
+++ b/doc/haproxy-fr.txt
@@ -119,6 +119,8 @@
   - maxconn <nombre>
   - uid <identifiant>
   - gid <identifiant>
+  - user <nom d'utilisateur>
+  - group <nom de groupe>
   - chroot <répertoire>
   - nbproc <nombre>
   - daemon
@@ -208,9 +210,14 @@
 l'on ne souhaite pas changer cet identifiant et conserver la valeur courante.
 C'est la valeur par défaut. De la même manière, le paramètre 'gid' correspond à
 un identifiant de groupe, et utilise par défaut la valeur 0 pour ne rien
-changer. Il est particulièrement déconseillé d'utiliser des comptes génériques
-tels que 'nobody' car cette pratique revient à utiliser 'root' si d'autres
-processus utilisent les mêmes identifiants.
+changer. Dans le cas où il ne serait pas possible de spécifier un identifiant
+numérique pour l'uid, il est possible de spécifier un nom d'utilisateur après
+le mot-clé 'user'. De la même manière, il est possible de préciser un nom de
+groupe après le mot-clé 'group'.
+
+Il est particulièrement déconseillé d'utiliser des comptes génériques tels que
+'nobody' car cette pratique revient à utiliser 'root' si d'autres processus
+utilisent les mêmes identifiants.
 
 Le paramètre 'chroot' autorise à changer la racine du processus une fois le
 programme lancé, de sorte que ni le processus, ni l'un de ses descendants ne
@@ -246,11 +253,19 @@
 Exemple :
 ---------
 
+    # with uid/gid
     global
         uid        30000
         gid        30000
         chroot  /var/chroot/haproxy
 
+    # with user/group
+    global
+        user    haproxy
+        group   public
+        chroot  /var/chroot/haproxy
+
+
 1.4) Modes de fonctionnement
 ----------------------------
 Le service peut fonctionner dans plusieurs modes :
diff --git a/src/cfgparse.c b/src/cfgparse.c
index ae5433e..4c1f032 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -15,6 +15,8 @@
 #include <string.h>
 #include <netdb.h>
 #include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include <common/cfgparse.h>
 #include <common/config.h>
@@ -269,7 +271,7 @@
 	}
 	else if (!strcmp(args[0], "uid")) {
 		if (global.uid != 0) {
-			Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
+			Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
 			return 0;
 		}
 		if (*(args[1]) == 0) {
@@ -280,7 +282,7 @@
 	}
 	else if (!strcmp(args[0], "gid")) {
 		if (global.gid != 0) {
-			Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
+			Alert("parsing [%s:%d] : group/gid already specified. Continuing.\n", file, linenum);
 			return 0;
 		}
 		if (*(args[1]) == 0) {
@@ -289,6 +291,40 @@
 		}
 		global.gid = atol(args[1]);
 	}
+	/* user/group name handling */
+	else if (!strcmp(args[0], "user")) {
+		struct passwd *ha_user;
+		if (global.uid != 0) {
+			Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
+			return 0;
+		}
+		errno = 0;
+		ha_user = getpwnam(args[1]);
+		if (ha_user != NULL) {
+			global.uid = (int)ha_user->pw_uid;
+		}
+		else {
+			Alert("parsing [%s:%d] : cannot find user id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
+			exit(1);
+		}
+	}
+	else if (!strcmp(args[0], "group")) {
+		struct group *ha_group;
+		if (global.gid != 0) {
+			Alert("parsing [%s:%d] : gid/group was already specified. Continuing.\n", file, linenum, args[0]);
+			return 0;
+		}
+		errno = 0;
+		ha_group = getgrnam(args[1]);
+		if (ha_group != NULL) {
+			global.gid = (int)ha_group->gr_gid;
+		}
+		else {
+			Alert("parsing [%s:%d] : cannot find group id for '%s' (%d:%s)\n", file, linenum, args[1], errno, strerror(errno));
+			exit(1);
+		}
+	}
+	/* end of user/group name handling*/
 	else if (!strcmp(args[0], "nbproc")) {
 		if (global.nbproc != 0) {
 			Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);