diff options
-rw-r--r-- | src/external/platform.m4 | 12 | ||||
-rw-r--r-- | src/responder/common/responder.h | 3 | ||||
-rw-r--r-- | src/responder/common/responder_common.c | 53 | ||||
-rw-r--r-- | src/sss_client/common.c | 81 | ||||
-rw-r--r-- | src/sss_client/pam_sss.c | 5 | ||||
-rw-r--r-- | src/sss_client/sss_cli.h | 11 |
6 files changed, 162 insertions, 3 deletions
diff --git a/src/external/platform.m4 b/src/external/platform.m4 index 71b4f2c8..ee009378 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 ea6ba583..deb1e5a3 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 ff27f62c..54d6c49e 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 6732c24f..237b90ab 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 6059dfaa..4208faa6 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 f3872657..f7e58fe9 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, |