summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/external/platform.m412
-rw-r--r--src/responder/common/responder.h3
-rw-r--r--src/responder/common/responder_common.c53
-rw-r--r--src/sss_client/common.c81
-rw-r--r--src/sss_client/pam_sss.c5
-rw-r--r--src/sss_client/sss_cli.h11
6 files changed, 162 insertions, 3 deletions
diff --git a/src/external/platform.m4 b/src/external/platform.m4
index 71b4f2c85..ee0093789 100644
--- a/src/external/platform.m4
+++ b/src/external/platform.m4
@@ -27,3 +27,15 @@ fi
AM_CONDITIONAL([HAVE_FEDORA], [test x"$osname" == xfedora])
AM_CONDITIONAL([HAVE_REDHAT], [test x"$osname" == xredhat])
AM_CONDITIONAL([HAVE_SUSE], [test x"$osname" == xsuse])
+
+AC_CHECK_MEMBERS([struct ucred.pid, struct ucred.uid, struct ucred.gid], , ,
+ [[#define _GNU_SOURCE
+ #include <sys/socket.h>]])
+
+if test x"$ac_cv_member_struct_ucred_pid" = xyes -a \
+ x"$ac_cv_member_struct_ucred_uid" = xyes -a \
+ x"$ac_cv_member_struct_ucred_gid" = xyes ; then
+ AC_DEFINE([HAVE_UCRED], [1], [Define if struct ucred is available])
+else
+ AC_MSG_WARN([struct ucred is not available])
+fi
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index ea6ba5831..deb1e5a3c 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -101,6 +101,9 @@ struct cli_ctx {
struct cli_request *creq;
struct cli_protocol_version *cli_protocol_version;
int priv;
+ int32_t client_euid;
+ int32_t client_egid;
+ int32_t client_pid;
};
struct sss_cmd_table {
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index ff27f62cf..54d6c49e1 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -19,6 +19,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/* for struct ucred */
+#define _GNU_SOURCE
+
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
@@ -29,7 +32,8 @@
#include <string.h>
#include <sys/time.h>
#include <errno.h>
-#include "popt.h"
+#include <popt.h>
+#include "config.h"
#include "util/util.h"
#include "db/sysdb.h"
#include "confdb/confdb.h"
@@ -61,6 +65,40 @@ static int client_destructor(struct cli_ctx *ctx)
return 0;
}
+static errno_t get_client_cred(struct cli_ctx *cctx)
+{
+#ifdef HAVE_UCRED
+ int ret;
+ struct ucred client_cred;
+ socklen_t client_cred_len = sizeof(client_cred);
+
+ cctx->client_euid = -1;
+ cctx->client_egid = -1;
+ cctx->client_pid = -1;
+
+ ret = getsockopt(cctx->cfd, SOL_SOCKET, SO_PEERCRED, &client_cred,
+ &client_cred_len);
+ if (ret != EOK) {
+ ret = errno;
+ DEBUG(1, ("getsock failed [%d][%s].\n", ret, strerror(ret)));
+ return ret;
+ }
+ if (client_cred_len != sizeof(struct ucred)) {
+ DEBUG(1, ("getsockopt returned unexpected message size.\n"));
+ return ENOMSG;
+ }
+
+ cctx->client_euid = client_cred.uid;
+ cctx->client_egid = client_cred.gid;
+ cctx->client_pid = client_cred.pid;
+
+ DEBUG(9, ("Client creds: euid[%d] egid[%d] pid[%d].\n",
+ cctx->client_euid, cctx->client_egid, cctx->client_pid));
+#endif
+
+ return EOK;
+}
+
static void client_send(struct cli_ctx *cctx)
{
int ret;
@@ -214,6 +252,12 @@ static void accept_priv_fd_handler(struct tevent_context *ev,
cctx->priv = 1;
+ ret = get_client_cred(cctx);
+ if (ret != EOK) {
+ DEBUG(2, ("get_client_cred failed, "
+ "client cred may not be available.\n"));
+ }
+
cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
TEVENT_FD_READ, client_fd_handler, cctx);
if (!cctx->cfde) {
@@ -240,6 +284,7 @@ static void accept_fd_handler(struct tevent_context *ev,
struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx);
struct cli_ctx *cctx;
socklen_t len;
+ int ret;
cctx = talloc_zero(rctx, struct cli_ctx);
if (!cctx) {
@@ -265,6 +310,12 @@ static void accept_fd_handler(struct tevent_context *ev,
return;
}
+ ret = get_client_cred(cctx);
+ if (ret != EOK) {
+ DEBUG(2, ("get_client_cred failed, "
+ "client cred may not be available.\n"));
+ }
+
cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
TEVENT_FD_READ, client_fd_handler, cctx);
if (!cctx->cfde) {
diff --git a/src/sss_client/common.c b/src/sss_client/common.c
index 6732c24fc..237b90aba 100644
--- a/src/sss_client/common.c
+++ b/src/sss_client/common.c
@@ -23,6 +23,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/* for struct ucred */
+#define _GNU_SOURCE
+
#include <nss.h>
#include <security/pam_modules.h>
#include <errno.h>
@@ -36,6 +39,10 @@
#include <string.h>
#include <fcntl.h>
#include <poll.h>
+
+#include <libintl.h>
+#define _(STRING) dgettext (PACKAGE, STRING)
+#include "config.h"
#include "sss_cli.h"
/* common functions */
@@ -632,6 +639,29 @@ enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
return sss_nss_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
}
+errno_t check_server_cred(int sockfd)
+{
+#ifdef HAVE_UCRED
+ int ret;
+ struct ucred server_cred;
+ socklen_t server_cred_len = sizeof(server_cred);
+
+ ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &server_cred,
+ &server_cred_len);
+ if (ret != 0) {
+ return errno;
+ }
+
+ if (server_cred_len != sizeof(struct ucred)) {
+ return ESSS_BAD_CRED_MSG;
+ }
+
+ if (server_cred.uid != 0 || server_cred.gid != 0) {
+ return ESSS_SERVER_NOT_TRUSTED;
+ }
+#endif
+ return 0;
+}
int sss_pam_make_request(enum sss_cli_command cmd,
struct sss_cli_req_data *rd,
uint8_t **repbuf, size_t *replen,
@@ -653,17 +683,66 @@ int sss_pam_make_request(enum sss_cli_command cmd,
if (ret != 0) return PAM_SERVICE_ERR;
if ( ! (stat_buf.st_uid == 0 &&
stat_buf.st_gid == 0 &&
- (stat_buf.st_mode&(S_IFSOCK|S_IRUSR|S_IWUSR)) == stat_buf.st_mode)) {
+ S_ISSOCK(stat_buf.st_mode) &&
+ (stat_buf.st_mode & ~S_IFMT) == 0600 )) {
+ *errnop = ESSS_BAD_PRIV_SOCKET;
return PAM_SERVICE_ERR;
}
ret = sss_cli_check_socket(errnop, SSS_PAM_PRIV_SOCKET_NAME);
} else {
+ ret = stat(SSS_PAM_SOCKET_NAME, &stat_buf);
+ if (ret != 0) return PAM_SERVICE_ERR;
+ if ( ! (stat_buf.st_uid == 0 &&
+ stat_buf.st_gid == 0 &&
+ S_ISSOCK(stat_buf.st_mode) &&
+ (stat_buf.st_mode & ~S_IFMT) == 0666 )) {
+ *errnop = ESSS_BAD_PUB_SOCKET;
+ return PAM_SERVICE_ERR;
+ }
+
ret = sss_cli_check_socket(errnop, SSS_PAM_SOCKET_NAME);
}
if (ret != NSS_STATUS_SUCCESS) {
return PAM_SERVICE_ERR;
}
+ ret = check_server_cred(sss_cli_sd);
+ if (ret != 0) {
+ sss_cli_close_socket();
+ *errnop = ret;
+ return PAM_SERVICE_ERR;
+ }
+
return sss_nss_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
}
+
+
+const char *ssscli_err2string(int err)
+{
+ const char *m;
+
+ switch(err) {
+ case ESSS_BAD_PRIV_SOCKET:
+ return _("Privileged socket has wrong ownership or permissions.");
+ break;
+ case ESSS_BAD_PUB_SOCKET:
+ return _("Public socket has wrong ownership or permissions.");
+ break;
+ case ESSS_BAD_CRED_MSG:
+ return _("Unexpected format of the server credential message.");
+ break;
+ case ESSS_SERVER_NOT_TRUSTED:
+ return _("SSSD is not run by root.");
+ break;
+ default:
+ m = strerror(err);
+ if (m == NULL) {
+ return _("An error occurred, but no description can be found.");
+ }
+ return m;
+ break;
+ }
+
+ return _("Unexpected error while looking for an error description");
+}
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index 6059dfaa1..4208faa62 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -877,10 +877,13 @@ static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi,
}
rd.data = buf;
+ errnop = 0;
ret = sss_pam_make_request(task, &rd, &repbuf, &replen, &errnop);
if (ret != NSS_STATUS_SUCCESS) {
- logger(pamh, LOG_ERR, "Request to sssd failed.");
+ if (errnop != 0) {
+ logger(pamh, LOG_ERR, "Request to sssd failed. %s", ssscli_err2string(errnop));
+ }
pam_status = PAM_SYSTEM_ERR;
goto done;
}
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index f38726579..f7e58fe93 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -406,6 +406,17 @@ enum user_info_type {
* @}
*/ /* end of group sss_pam_cli */
+enum sss_cli_error_codes {
+ ESSS_SSS_CLI_ERROR_START = 0x1000,
+ ESSS_BAD_PRIV_SOCKET,
+ ESSS_BAD_PUB_SOCKET,
+ ESSS_BAD_CRED_MSG,
+ ESSS_SERVER_NOT_TRUSTED,
+
+ ESS_SSS_CLI_ERROR_MAX
+};
+
+const char *ssscli_err2string(int err);
enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
struct sss_cli_req_data *rd,