--- Begin Message ---
Hi,
We use Cyrus SASL for years already with Cyrus IMAP and it has been
working great on Solaris. The last months we are securing our LDAP
environment and thus want to use LDAPS more and more. The native LDAP
support on Solaris is lacking the support for SSL in the current
codebase. So I wrote a small patch to add support for the native
Solaris LDAP library to support LDAPS sessions from saslauthd.
Please find attached a patch with the code changes we currently
use to support LDAPS on Solaris. Maybe it can be of use to other
people so it would be nice if it could be added to the default
codebase in one way or the other. Please review the patch and
see how it can be integrated either in its current form or any
other way (maybe better etc.) This also saves us keeping this
patch up to date for future version of the cyrus sasl codebase.
I also added an extra small patch for Cyrus imapd which makes
it possible to use Cyrus imap under Solaris and run it by
default as user cyrus(or any other user not being root)
under the Solaris 10 SMF (System Management Framework) with only
default security settings and so called net_privaddr priviledge
which means no need to run as root but still bind to tcp ports
under 1024.
Marco van Wieringen
diff -ru original/cyrus-sasl-2.1.22/saslauthd/lak.c cyrus-sasl-2.1.22/saslauthd/lak.c
--- original/cyrus-sasl-2.1.22/saslauthd/lak.c Sun May 15 07:49:51 2005
+++ cyrus-sasl-2.1.22/saslauthd/lak.c Wed Dec 19 19:29:42 2007
@@ -60,6 +60,21 @@
#include <sasl.h>
#include "lak.h"
+#if defined(_SOLARIS_SDK)
+/*
+ * Solaris SDK specific code.
+ * Added by Marco van Wieringen <mvw@xxxxxxxxxxxxxxx>
+ *
+ * Solaris Native LDAP doesn't define LDAP_OPT_SUCCESS but does LDAP_SUCCESS.
+ */
+#if !defined(LDAP_OPT_SUCCESS) && defined(LDAP_SUCCESS)
+#define LDAP_OPT_SUCCESS LDAP_SUCCESS
+#endif
+#if !defined(LDAP_SASL_QUIET)
+#define LDAP_SASL_QUIET 0
+#endif
+#endif
+
typedef struct lak_auth_method {
int method;
int (*check) (LAK *lak, const char *user, const char *service, const char *realm, const char *password) ;
@@ -270,47 +285,71 @@
conf->use_sasl = lak_config_switch(p);
} else if (!strcasecmp(key, "ldap_id") ||
- !strcasecmp(key, "ldap_sasl_authc_id"))
+ !strcasecmp(key, "ldap_sasl_authc_id")) {
strlcpy(conf->id, p, LAK_BUF_LEN);
- else if (!strcasecmp(key, "ldap_authz_id") ||
- !strcasecmp(key, "ldap_sasl_authz_id"))
+ } else if (!strcasecmp(key, "ldap_authz_id") ||
+ !strcasecmp(key, "ldap_sasl_authz_id")) {
strlcpy(conf->authz_id, p, LAK_BUF_LEN);
- else if (!strcasecmp(key, "ldap_realm") ||
- !strcasecmp(key, "ldap_sasl_realm"))
+ } else if (!strcasecmp(key, "ldap_realm") ||
+ !strcasecmp(key, "ldap_sasl_realm")) {
strlcpy(conf->realm, p, LAK_BUF_LEN);
- else if (!strcasecmp(key, "ldap_mech") ||
- !strcasecmp(key, "ldap_sasl_mech"))
+ } else if (!strcasecmp(key, "ldap_mech") ||
+ !strcasecmp(key, "ldap_sasl_mech")) {
strlcpy(conf->mech, p, LAK_BUF_LEN);
- else if (!strcasecmp(key, "ldap_sasl_secprops"))
+ } else if (!strcasecmp(key, "ldap_sasl_secprops")) {
strlcpy(conf->sasl_secprops, p, LAK_BUF_LEN);
- else if (!strcasecmp(key, "ldap_start_tls"))
+ } else if (!strcasecmp(key, "ldap_start_tls")) {
conf->start_tls = lak_config_switch(p);
- else if (!strcasecmp(key, "ldap_tls_check_peer"))
+#if !defined(_SOLARIS_SDK)
+ } else if (!strcasecmp(key, "ldap_tls_check_peer")) {
conf->tls_check_peer = lak_config_switch(p);
- else if (!strcasecmp(key, "ldap_tls_cacert_file"))
+ } else if (!strcasecmp(key, "ldap_tls_cacert_file")) {
strlcpy(conf->tls_cacert_file, p, LAK_PATH_LEN);
- else if (!strcasecmp(key, "ldap_tls_cacert_dir"))
+ } else if (!strcasecmp(key, "ldap_tls_cacert_dir")) {
strlcpy(conf->tls_cacert_dir, p, LAK_PATH_LEN);
- else if (!strcasecmp(key, "ldap_tls_ciphers"))
+ } else if (!strcasecmp(key, "ldap_tls_ciphers")) {
strlcpy(conf->tls_ciphers, p, LAK_BUF_LEN);
- else if (!strcasecmp(key, "ldap_tls_cert"))
+ } else if (!strcasecmp(key, "ldap_tls_cert")) {
strlcpy(conf->tls_cert, p, LAK_PATH_LEN);
- else if (!strcasecmp(key, "ldap_tls_key"))
+ } else if (!strcasecmp(key, "ldap_tls_key")) {
strlcpy(conf->tls_key, p, LAK_PATH_LEN);
- else if (!strcasecmp(key, "ldap_debug"))
+#else
+ } else if (!strcasecmp(key, "ldap_ssl_strength")) {
+ if (!strcasecmp(p, "weak")) {
+ conf->ssl_strength = LDAPSSL_AUTH_WEAK;
+ } else if (!strcasecmp(p, "cert")) {
+ conf->ssl_strength = LDAPSSL_AUTH_CERT;
+ } else if (!strcasecmp(p, "cncheck")) {
+ conf->ssl_strength = LDAPSSL_AUTH_CNCHECK;
+ } else {
+ conf->ssl_strength = LDAPSSL_AUTH_WEAK;
+ }
+
+ } else if (!strcasecmp(key, "ldap_ssl_certdb_path")) {
+ strlcpy(conf->ssl_certdb_path, p, LAK_PATH_LEN);
+
+ } else if (!strcasecmp(key, "ldap_ssl_keydb_path")) {
+ strlcpy(conf->ssl_keydb_path, p, LAK_PATH_LEN);
+
+ } else if (!strcasecmp(key, "ldap_ssl_secmod_path")) {
+ strlcpy(conf->ssl_secmod_path, p, LAK_PATH_LEN);
+#endif
+
+ } else if (!strcasecmp(key, "ldap_debug")) {
conf->debug = lak_config_int(p);
+ }
}
if (conf->version != LDAP_VERSION3 &&
@@ -378,7 +417,7 @@
conf->scope = LDAP_SCOPE_SUBTREE;
strlcpy(conf->group_attr, "uniqueMember", LAK_BUF_LEN);
conf->group_scope = LDAP_SCOPE_SUBTREE;
- conf->group_match_method = LAK_GROUP_MATCH_METHOD_ATTR;
+ conf->group_match_method = LAK_GROUP_MATCH_METHOD_ATTR;
conf->auth_method = LAK_AUTH_METHOD_BIND;
conf->timeout.tv_sec = 5;
conf->timeout.tv_usec = 0;
@@ -752,12 +791,214 @@
return;
}
+#if defined(_SOLARIS_SDK)
+/*
+ * Global variable defining if ssl is initialized.
+ */
+static char ldapssl_client_initialized = 0;
+
+/*
+ * Solaris specific function that initializes the ssl functions using the Native Solaris LDAP functions.
+ */
+static char *ldap_initialize_ssl_subsystem(
+ const char *ssl_certdb_path_keyword,
+ const char *ssl_certdb_path,
+ const char *ssl_keydb_path,
+ const char *ssl_secmod_path,
+ int ssl_strength)
+{
+ static char ldapssl_errmsg[512];
+ int rc;
+
+ if (ssl_certdb_path != (char *)NULL)
+ if (ldapssl_client_initialized == 0)
+ if ((rc = ldapssl_advclientauth_init(ssl_certdb_path, NULL,
+ (ssl_keydb_path != (char *)NULL), ssl_keydb_path, NULL,
+ (ssl_secmod_path != (char *)NULL), ssl_secmod_path, ssl_strength)) < 0)
+ snprintf(ldapssl_errmsg, sizeof(ldapssl_errmsg), "ldapssl_advclientauth_init failed : %s", ldapssl_err2string(rc));
+ else
+ ldapssl_client_initialized = 1;
+ else
+ snprintf(ldapssl_errmsg, sizeof(ldapssl_errmsg), "Cannot use ldapssl_advclientauth_init because %s is not set", ssl_certdb_path_keyword);
+
+ /*
+ * Return the errormessage if the initialization failed.
+ */
+ return((ldapssl_client_initialized == 0) ? ldapssl_errmsg : (char *)NULL);
+}
+
+/*
+ * Solaris specific function that mimics the OpenLDAP ldap_initialize function using the Native Solaris LDAP functions.
+ */
+static int ldap_initialize(LDAP **ldp, const char *url)
+{
+ LDAP *ld;
+ char use_ssl;
+ int urlerr, cnt;
+ LDAPURLDesc *ldapurl;
+ char *ldap_server, *ldap_servers;
+ char converted_ldap_servers[512];
+
+ *ldp = (LDAP *)NULL;
+
+ /*
+ * First convert any LDAP or LDAPS URL into something ldap_init or ldapssl_init understands.
+ */
+ ldap_servers = strdup(url);
+
+ use_ssl = 0;
+ cnt = 0;
+ if (ldap_servers != (char *)NULL) {
+ memset((caddr_t)converted_ldap_servers, 0, sizeof(converted_ldap_servers));
+
+ /*
+ * Split the given ldap_servers into their individual elements.
+ */
+ ldap_server = strtok(ldap_servers, " ");
+
+ while (ldap_server != (char *)NULL) {
+ /*
+ * See if this look like an URL.
+ */
+ if (strstr(ldap_server, "://") != (char *)NULL) {
+ /*
+ * See if the ldap URL is parse-able.
+ */
+ if ((urlerr = ldap_url_parse(ldap_server, &ldapurl)) == 0) {
+ /*
+ * See if there is no conflicting ldapserver configuration. And make sure
+ * its either a ldaps:// or ldap:// url other protocols we don't support.
+ */
+ if (!strncasecmp(ldap_server, "ldaps://", 8)) {
+ use_ssl = 1;
+ } else {
+ if (!strncasecmp(ldap_server, "ldap://", 7)) {
+ if (use_ssl) {
+ /*
+ * Using both LDAP and LDAPS in one definition makes no sense.
+ */
+ ldap_free_urldesc(ldapurl);
+ free(ldap_servers);
+ return(LDAP_NOT_SUPPORTED);
+ }
+ } else {
+ ldap_free_urldesc(ldapurl);
+ free(ldap_servers);
+ return(LDAP_PROTOCOL_ERROR);
+ }
+ }
+
+ /*
+ * Stuff an entry into the converted_ldap_servers string.
+ */
+ if (cnt++ == 0) {
+ if (ldapurl->lud_port)
+ snprintf(converted_ldap_servers, sizeof(converted_ldap_servers),
+ "%s:%ld", ldapurl->lud_host, ldapurl->lud_port);
+ else
+ snprintf(converted_ldap_servers, sizeof(converted_ldap_servers),
+ "%s", ldapurl->lud_host);
+ } else {
+ if (ldapurl->lud_port)
+ snprintf(converted_ldap_servers, sizeof(converted_ldap_servers),
+ "%s %s:%ld", converted_ldap_servers,
+ ldapurl->lud_host, ldapurl->lud_port);
+ else
+ snprintf(converted_ldap_servers, sizeof(converted_ldap_servers),
+ "%s %s", converted_ldap_servers, ldapurl->lud_host);
+ }
+
+ /*
+ * Free the parsed ldap URL.
+ */
+ ldap_free_urldesc(ldapurl);
+ } else {
+ free(ldap_servers);
+ return(LDAP_PROTOCOL_ERROR);
+ }
+ } else {
+ /*
+ * Stuff an entry into the converted_ldap_servers string.
+ */
+ if (cnt++ == 0) {
+ snprintf(converted_ldap_servers, sizeof(converted_ldap_servers),
+ "%s", ldap_server);
+ } else {
+ snprintf(converted_ldap_servers, sizeof(converted_ldap_servers),
+ "%s %s", converted_ldap_servers, ldap_server);
+ }
+ }
+
+ /*
+ * Get the next ldap server from the lak->conf->servers
+ */
+ ldap_server = strtok(NULL, " ");
+ }
+
+ /*
+ * Free the working copy with the ldap servers.
+ */
+ free(ldap_servers);
+
+ /*
+ * If we succeeded in initializing ssl we try ldapssl_init otherwise fallback to ldap_init.
+ */
+ if (ldapssl_client_initialized == 1) {
+ ld = ldapssl_init(converted_ldap_servers, LDAPS_PORT, 1);
+ } else {
+ ld = ldap_init(converted_ldap_servers, LDAP_PORT);
+ }
+
+ if (ld == (LDAP *)NULL) {
+ return(LDAP_OPERATIONS_ERROR);
+ } else {
+ *ldp = ld;
+ return(LDAP_SUCCESS);
+ }
+ } else {
+ return(LDAP_OPERATIONS_ERROR);
+ }
+}
+
+/*
+ * Initialize the ssl subsystem. Local gluecode around generic ldap_initialize_ssl_subsystem function.
+ */
+static int ldap_initialize_ssl(
+ LAK *lak)
+{
+ char *msg;
+
+ if ((msg = ldap_initialize_ssl_subsystem("ldap_ssl_certdb_path",
+ ISSET(lak->conf->ssl_certdb_path) ? lak->conf->ssl_certdb_path : (char *)NULL,
+ ISSET(lak->conf->ssl_keydb_path) ? lak->conf->ssl_keydb_path : (char *)NULL,
+ ISSET(lak->conf->ssl_secmod_path) ? lak->conf->ssl_secmod_path : (char *)NULL,
+ lak->conf->ssl_strength)) != (char *)NULL) {
+ syslog(LOG_ERR|LOG_AUTH, "%s", msg);
+ return(0);
+ } else {
+ return(1);
+ }
+}
+
+#endif
+
static int lak_connect(
LAK *lak)
{
int rc = 0;
char *p = NULL;
-
+#if defined(_SOLARIS_SDK) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
+ int timeout;
+#endif
+
+#if defined(_SOLARIS_SDK)
+ /*
+ * See if we need to initialize SSL.
+ */
+ if (strstr(lak->conf->servers, "ldaps://") != (char *)NULL)
+ ldap_initialize_ssl(lak);
+#else
+#if defined(LDAP_OPT_X_TLS_CACERTFILE)
if (ISSET(lak->conf->tls_cacert_file)) {
rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, lak->conf->tls_cacert_file);
if (rc != LDAP_SUCCESS) {
@@ -764,7 +1005,9 @@
syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_CACERTFILE (%s).", ldap_err2string (rc));
}
}
+#endif
+#if defined(LDAP_OPT_X_TLS_CACERTDIR)
if (ISSET(lak->conf->tls_cacert_dir)) {
rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR, lak->conf->tls_cacert_dir);
if (rc != LDAP_SUCCESS) {
@@ -771,7 +1014,9 @@
syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_CACERTDIR (%s).", ldap_err2string (rc));
}
}
+#endif
+#if defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
if (lak->conf->tls_check_peer != 0) {
rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &lak->conf->tls_check_peer);
if (rc != LDAP_SUCCESS) {
@@ -778,7 +1023,9 @@
syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_REQUIRE_CERT (%s).", ldap_err2string (rc));
}
}
-
+#endif
+
+#if defined(LDAP_OPT_X_TLS_CIPHER_SUITE)
if (ISSET(lak->conf->tls_ciphers)) {
/* set cipher suite, certificate and private key: */
rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, lak->conf->tls_ciphers);
@@ -786,7 +1033,9 @@
syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_CIPHER_SUITE (%s).", ldap_err2string (rc));
}
}
-
+#endif
+
+#if defined(LDAP_OPT_X_TLS_CERTFILE)
if (ISSET(lak->conf->tls_cert)) {
rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE, lak->conf->tls_cert);
if (rc != LDAP_SUCCESS) {
@@ -793,7 +1042,9 @@
syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_CERTFILE (%s).", ldap_err2string (rc));
}
}
-
+#endif
+
+#if defined(LDAP_OPT_X_TLS_KEYFILE)
if (ISSET(lak->conf->tls_key)) {
rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE, lak->conf->tls_key);
if (rc != LDAP_SUCCESS) {
@@ -800,6 +1051,8 @@
syslog (LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_X_TLS_KEYFILE (%s).", ldap_err2string (rc));
}
}
+#endif
+#endif
rc = ldap_initialize(&lak->ld, lak->conf->servers);
if (rc != LDAP_SUCCESS) {
@@ -807,12 +1060,15 @@
return LAK_CONNECT_FAIL;
}
+#if defined(LDAP_OPT_DEBUG_LEVEL)
if (lak->conf->debug) {
rc = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(lak->conf->debug));
if (rc != LDAP_OPT_SUCCESS)
syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_DEBUG_LEVEL %x.", lak->conf->debug);
}
+#endif
+#if defined(LDAP_OPT_PROTOCOL_VERSION)
rc = ldap_set_option(lak->ld, LDAP_OPT_PROTOCOL_VERSION, &(lak->conf->version));
if (rc != LDAP_OPT_SUCCESS) {
@@ -827,36 +1083,60 @@
lak->conf->version = LDAP_VERSION2;
}
+#endif
+#if !defined(_SOLARIS_SDK) && defined(LDAP_OPT_NETWORK_TIMEOUT)
rc = ldap_set_option(lak->ld, LDAP_OPT_NETWORK_TIMEOUT, &(lak->conf->timeout));
if (rc != LDAP_OPT_SUCCESS) {
syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_NETWORK_TIMEOUT %d.%d.", lak->conf->timeout.tv_sec, lak->conf->timeout.tv_usec);
}
+#elseif defined(_SOLARIS_SDK) && defined(LDAP_X_OPT_CONNECT_TIMEOUT)
+ /*
+ * Timeout is in miliseconds
+ */
+ timeout = (lak->conf->timeout.tv_sec * 1000) + (lak->conf->timeout.tv_usec % 1000);
+ rc = ldap_set_option(lak->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
+ if (rc != LDAP_OPT_SUCCESS) {
+ syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_X_OPT_CONNECT_TIMEOUT %ld.", timeout);
+ }
+#endif
+
+#if defined(LDAP_OPT_TIMELIMIT)
rc = ldap_set_option(lak->ld, LDAP_OPT_TIMELIMIT, &(lak->conf->time_limit));
if (rc != LDAP_OPT_SUCCESS) {
syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_TIMELIMIT %d.", lak->conf->time_limit);
}
+#endif
+#if defined(LDAP_OPT_DEREF)
rc = ldap_set_option(lak->ld, LDAP_OPT_DEREF, &(lak->conf->deref));
if (rc != LDAP_OPT_SUCCESS) {
syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_DEREF %d.", lak->conf->deref);
}
+#endif
+#if defined(LDAP_OPT_REFERRALS)
rc = ldap_set_option(lak->ld, LDAP_OPT_REFERRALS, lak->conf->referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
if (rc != LDAP_OPT_SUCCESS) {
syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_REFERRALS.");
}
+#endif
+#if defined(LDAP_OPT_SIZELIMIT)
rc = ldap_set_option(lak->ld, LDAP_OPT_SIZELIMIT, &(lak->conf->size_limit));
if (rc != LDAP_OPT_SUCCESS)
syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_SIZELIMIT %d.", lak->conf->size_limit);
+#endif
+#if defined(LDAP_OPT_RESTART)
rc = ldap_set_option(lak->ld, LDAP_OPT_RESTART, lak->conf->restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
if (rc != LDAP_OPT_SUCCESS) {
syslog(LOG_WARNING|LOG_AUTH, "Unable to set LDAP_OPT_RESTART.");
}
+#endif
+#if !defined(_SOLARIS_SDK)
if (lak->conf->start_tls) {
rc = ldap_start_tls_s(lak->ld, NULL, NULL);
@@ -866,6 +1146,7 @@
return LAK_CONNECT_FAIL;
}
}
+#endif
if (lak->conf->use_sasl) {
@@ -891,7 +1172,6 @@
}
}
-
return LAK_OK;
}
@@ -991,7 +1271,7 @@
static int lak_sasl_interact(
LDAP *ld,
- unsigned flags __attribute__((unused)),
+ unsigned flags,
void *def,
void *inter)
{
@@ -1675,7 +1955,7 @@
static int lak_check_password(
const char *hash,
const char *passwd,
- void *rock __attribute__((unused)))
+ void *rock)
{
int i, hlen;
@@ -1770,7 +2050,7 @@
static int lak_check_crypt(
const char *hash,
const char *passwd,
- void *rock __attribute__((unused)))
+ void *rock)
{
char *cred;
diff -ru original/cyrus-sasl-2.1.22/saslauthd/lak.h cyrus-sasl-2.1.22/saslauthd/lak.h
--- original/cyrus-sasl-2.1.22/saslauthd/lak.h Tue Feb 24 22:56:31 2004
+++ cyrus-sasl-2.1.22/saslauthd/lak.h Tue Oct 16 20:01:00 2007
@@ -98,6 +98,7 @@
char realm[LAK_BUF_LEN];
char sasl_secprops[LAK_BUF_LEN];
int start_tls;
+#if !defined(_SOLARIS_SDK)
int tls_check_peer;
char tls_cacert_file[LAK_PATH_LEN];
char tls_cacert_dir[LAK_PATH_LEN];
@@ -104,6 +105,12 @@
char tls_ciphers[LAK_BUF_LEN];
char tls_cert[LAK_PATH_LEN];
char tls_key[LAK_PATH_LEN];
+#else
+ char ssl_certdb_path[LAK_PATH_LEN];
+ char ssl_keydb_path[LAK_PATH_LEN];
+ char ssl_secmod_path[LAK_PATH_LEN];
+ int ssl_strength;
+#endif
int debug;
} LAK_CONF;
diff -ru original/cyrus-imapd-2.3.10/lib/util.c cyrus-imapd-2.3.10/lib/util.c
--- original/cyrus-imapd-2.3.10/lib/util.c Thu Sep 27 22:02:45 2007
+++ cyrus-imapd-2.3.10/lib/util.c Sun Nov 4 21:38:50 2007
@@ -370,7 +370,12 @@
int result;
static int uid = 0;
- if (uid) return setuid(uid);
+ if (uid) {
+ if (getuid() != uid)
+ return setuid(uid);
+ else
+ return 0;
+ }
p = getpwnam(CYRUS_USER);
if (p == NULL) {
@@ -382,22 +387,30 @@
newuid = p->pw_uid;
newgid = p->pw_gid;
- if (initgroups(CYRUS_USER, newgid)) {
- syslog(LOG_ERR, "unable to initialize groups for user %s: %s",
- CYRUS_USER, strerror(errno));
- return -1;
- }
+ if (newgid != getegid()) {
+ if (initgroups(CYRUS_USER, newgid)) {
+ syslog(LOG_ERR, "unable to initialize groups for user %s: %s",
+ CYRUS_USER, strerror(errno));
+ return -1;
+ }
- if (setgid(newgid)) {
- syslog(LOG_ERR, "unable to set group id to %d for user %s: %s",
- newgid, CYRUS_USER, strerror(errno));
- return -1;
+ if (setgid(newgid)) {
+ syslog(LOG_ERR, "unable to set group id to %d for user %s: %s",
+ newgid, CYRUS_USER, strerror(errno));
+ return -1;
+ }
}
- result = setuid(newuid);
+ if (newuid != geteuid()) {
+ result = setuid(newuid);
- /* Only set static uid if successful, else future calls won't reset gid */
- if (result == 0)
- uid = newuid;
+ /* Only set static uid if successful, else future calls won't reset gid */
+ if (result == 0)
+ uid = newuid;
+ } else {
+ result = 0;
+ uid = newuid;
+ }
+
return result;
}
--- End Message ---