summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/Makefile.am2
-rw-r--r--server/man/sssd-krb5.5.xml17
-rw-r--r--server/providers/krb5/krb5_auth.c105
-rw-r--r--server/providers/krb5/krb5_auth.h3
-rw-r--r--server/providers/krb5/krb5_child.c363
-rw-r--r--server/providers/krb5/tgt_req_child.c183
6 files changed, 464 insertions, 209 deletions
diff --git a/server/Makefile.am b/server/Makefile.am
index 20df79e47..e475e2552 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -404,7 +404,7 @@ libsss_proxy_la_LDFLAGS = \
libsss_krb5_la_SOURCES = \
providers/krb5/krb5_auth.c \
- providers/krb5/tgt_req_child.c
+ providers/krb5/krb5_child.c
libsss_krb5_la_CFLAGS = \
$(AM_CFLAGS) \
$(KRB5_CFLAGS)
diff --git a/server/man/sssd-krb5.5.xml b/server/man/sssd-krb5.5.xml
index 3a22afcdb..188cc9133 100644
--- a/server/man/sssd-krb5.5.xml
+++ b/server/man/sssd-krb5.5.xml
@@ -37,7 +37,7 @@
<refsect1 id='file-format'>
<title>CONFIGURATION OPTIONS</title>
<para>
- If the auth-module krb5 is used in a SSSD domain, the following
+ If the auth-module krb5 is used in a SSSD domain, the following
options must be used. See the
<citerefentry>
<refentrytitle>sssd.conf</refentrytitle>
@@ -76,6 +76,21 @@
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>krb5changepw_principle (string)</term>
+ <listitem>
+ <para>
+ The priciple of the change password service.
+ If only the 'identifier/instance' part of the
+ principle are given the realm part is added
+ automatically.
+ </para>
+ <para>
+ Default: kadmin/changepw
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
</refsect1>
diff --git a/server/providers/krb5/krb5_auth.c b/server/providers/krb5/krb5_auth.c
index b1fe47a14..b9574660d 100644
--- a/server/providers/krb5/krb5_auth.c
+++ b/server/providers/krb5/krb5_auth.c
@@ -102,6 +102,19 @@ static int krb5_setup(struct be_req *req, const char *user_princ_str,
kr->req = req;
kr->krb5_ctx = krb5_ctx;
+ switch(pd->cmd) {
+ case SSS_PAM_AUTHENTICATE:
+ kr->client = tgt_req_child;
+ break;
+ case SSS_PAM_CHAUTHTOK:
+ kr->client = changepw_child;
+ break;
+ default:
+ DEBUG(1, ("PAM command [%d] not supported.\n", pd->cmd));
+ kerr = EINVAL;
+ goto failed;
+ }
+
kerr = krb5_init_context(&kr->ctx);
if (kerr != 0) {
KRB5_DEBUG(1, kerr);
@@ -185,7 +198,7 @@ static void wait_for_child_handler(struct tevent_context *ev,
return;
}
-static int fork_tgt_req_child(struct krb5_req *kr)
+static int fork_child(struct krb5_req *kr)
{
int pipefd[2];
pid_t pid;
@@ -200,7 +213,7 @@ static int fork_tgt_req_child(struct krb5_req *kr)
if (pid == 0) { /* child */
close(pipefd[0]);
- tgt_req_child(pipefd[1], kr);
+ kr->client(pipefd[1], kr);
} else if (pid > 0) { /* parent */
kr->child_pid = pid;
kr->fd = pipefd[0];
@@ -296,29 +309,29 @@ static ssize_t read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
return state->len;
}
-struct tgt_req_state {
+struct handle_child_state {
struct krb5_req *kr;
ssize_t len;
uint8_t *buf;
};
-static void tgt_req_done(struct tevent_req *subreq);
+static void handle_child_done(struct tevent_req *subreq);
-static struct tevent_req *tgt_req_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+static struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct krb5_req *kr)
{
int ret;
struct tevent_req *req;
struct tevent_req *subreq;
- struct tgt_req_state *state;
+ struct handle_child_state *state;
- ret = fork_tgt_req_child(kr);
+ ret = fork_child(kr);
if (ret != EOK) {
- DEBUG(1, ("fork_tgt_req_child failed.\n"));
+ DEBUG(1, ("fork_child failed.\n"));
return NULL;
}
- req = tevent_req_create(mem_ctx, &state, struct tgt_req_state);
+ req = tevent_req_create(mem_ctx, &state, struct handle_child_state);
if (req == NULL) {
return NULL;
}
@@ -329,15 +342,16 @@ static struct tevent_req *tgt_req_send(TALLOC_CTX *mem_ctx, struct tevent_contex
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, tgt_req_done, req);
+ tevent_req_set_callback(subreq, handle_child_done, req);
return req;
}
-static void tgt_req_done(struct tevent_req *subreq)
+static void handle_child_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
- struct tgt_req_state *state = tevent_req_data(req, struct tgt_req_state);
+ struct handle_child_state *state = tevent_req_data(req,
+ struct handle_child_state);
uint64_t error;
state->len = read_pipe_recv(subreq, state, &state->buf, &error);
@@ -352,9 +366,10 @@ static void tgt_req_done(struct tevent_req *subreq)
return;
}
-static ssize_t tgt_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+static ssize_t handle_child_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
uint8_t **buf, uint64_t *error) {
- struct tgt_req_state *state = tevent_req_data(req, struct tgt_req_state);
+ struct handle_child_state *state = tevent_req_data(req,
+ struct handle_child_state);
enum tevent_req_state tstate;
if (tevent_req_is_error(req, &tstate, error)) {
@@ -378,7 +393,7 @@ static void krb5_pam_handler(struct be_req *be_req)
pd = talloc_get_type(be_req->req_data, struct pam_data);
- if (pd->cmd != SSS_PAM_AUTHENTICATE) {
+ if (pd->cmd != SSS_PAM_AUTHENTICATE && pd->cmd != SSS_PAM_CHAUTHTOK) {
DEBUG(4, ("krb5 does not handles pam task %d.\n", pd->cmd));
pam_status = PAM_SUCCESS;
goto done;
@@ -465,9 +480,9 @@ static void get_user_upn_done(void *pvt, int err, struct ldb_result *res)
goto failed;
}
- req = tgt_req_send(be_req, be_req->be_ctx->ev, kr);
+ req = handle_child_send(be_req, be_req->be_ctx->ev, kr);
if (req == NULL) {
- DEBUG(1, ("tgt_req_send failed.\n"));
+ DEBUG(1, ("handle_child_send failed.\n"));
goto failed;
}
@@ -488,7 +503,6 @@ static void krb5_pam_handler_done(struct tevent_req *req)
struct pam_data *pd = kr->pd;
struct be_req *be_req = kr->req;
struct krb5_ctx *krb5_ctx = kr->krb5_ctx;
- struct tgt_req_state *state = tevent_req_data(req, struct tgt_req_state);
int ret;
uint8_t *buf;
ssize_t len;
@@ -504,10 +518,10 @@ static void krb5_pam_handler_done(struct tevent_req *req)
pd->pam_status = PAM_SYSTEM_ERR;
krb5_cleanup(kr);
- len = tgt_req_recv(req, state, &buf, &error);
+ len = handle_child_recv(req, pd, &buf, &error);
talloc_zfree(req);
if (len == -1) {
- DEBUG(1, ("tgt_req request failed\n"));
+ DEBUG(1, ("child failed\n"));
goto done;
}
@@ -568,13 +582,31 @@ static void krb5_pam_handler_done(struct tevent_req *req)
if (pd->pam_status == PAM_SUCCESS &&
be_req->be_ctx->domain->cache_credentials == TRUE) {
- password = talloc_size(be_req, pd->authtok_size + 1);
+
+ switch(pd->cmd) {
+ case SSS_PAM_AUTHENTICATE:
+ password = talloc_size(be_req, pd->authtok_size + 1);
+ if (password != NULL) {
+ memcpy(password, pd->authtok, pd->authtok_size);
+ password[pd->authtok_size] = '\0';
+ }
+ break;
+ case SSS_PAM_CHAUTHTOK:
+ password = talloc_size(be_req, pd->newauthtok_size + 1);
+ if (password != NULL) {
+ memcpy(password, pd->newauthtok, pd->newauthtok_size);
+ password[pd->newauthtok_size] = '\0';
+ }
+ break;
+ default:
+ DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd));
+ }
+
if (password == NULL) {
- DEBUG(0, ("talloc_size failed, offline auth may not work.\n"));
+ DEBUG(0, ("password not available, offline auth may not work.\n"));
goto done;
}
- memcpy(password, pd->authtok, pd->authtok_size);
- password[pd->authtok_size] = '\0';
+
talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
subreq = sysdb_cache_password_send(be_req, be_req->be_ctx->ev,
@@ -617,6 +649,12 @@ struct bet_ops krb5_auth_ops = {
.finalize = NULL,
};
+struct bet_ops krb5_chpass_ops = {
+ .check_online = NULL,
+ .handler = krb5_pam_handler,
+ .finalize = NULL,
+};
+
int sssm_krb5_auth_init(struct be_ctx *bectx, struct bet_ops **ops,
void **pvt_auth_data)
@@ -668,6 +706,19 @@ int sssm_krb5_auth_init(struct be_ctx *bectx, struct bet_ops **ops,
if (ret != EOK) goto fail;
ctx->try_simple_upn = bool_value;
+ ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
+ "krb5changepw_principle", "kadmin/changepw",
+ &value);
+ if (ret != EOK) goto fail;
+ if (strchr(value, '@') == NULL) {
+ value = talloc_asprintf_append(value, "@%s", ctx->realm);
+ if (value == NULL) {
+ DEBUG(7, ("talloc_asprintf_append failed.\n"));
+ goto fail;
+ }
+ }
+ ctx->changepw_principle = value;
+
/* TODO: set options */
sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO,
@@ -687,3 +738,9 @@ fail:
talloc_free(ctx);
return ret;
}
+
+int sssm_krb5_chpass_init(struct be_ctx *bectx, struct bet_ops **ops,
+ void **pvt_auth_data)
+{
+ return sssm_krb5_auth_init(bectx, ops, pvt_auth_data);
+}
diff --git a/server/providers/krb5/krb5_auth.h b/server/providers/krb5/krb5_auth.h
index 540f65fa0..0db3ef056 100644
--- a/server/providers/krb5/krb5_auth.h
+++ b/server/providers/krb5/krb5_auth.h
@@ -62,6 +62,7 @@ struct krb5_ctx {
char *kdcip;
char *realm;
bool try_simple_upn;
+ char *changepw_principle;
};
struct krb5_req {
@@ -77,6 +78,7 @@ struct krb5_req {
struct be_req *req;
struct pam_data *pd;
struct krb5_ctx *krb5_ctx;
+ void (*client)(int fd, struct krb5_req *kr);
};
static krb5_context krb5_error_ctx;
@@ -88,5 +90,6 @@ static const char *__krb5_error_msg;
} while(0);
void tgt_req_child(int fd, struct krb5_req *kr);
+void changepw_child(int fd, struct krb5_req *kr);
#endif /* __KRB5_AUTH_H__ */
diff --git a/server/providers/krb5/krb5_child.c b/server/providers/krb5/krb5_child.c
new file mode 100644
index 000000000..daa2f71ee
--- /dev/null
+++ b/server/providers/krb5/krb5_child.c
@@ -0,0 +1,363 @@
+/*
+ SSSD
+
+ Kerberos 5 Backend Module -- tgt_req and changepw child
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2009 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <krb5/krb5.h>
+#include <sys/types.h>
+
+#include <security/pam_modules.h>
+
+#include "util/util.h"
+#include "providers/dp_backend.h"
+#include "providers/krb5/krb5_auth.h"
+
+struct response {
+ size_t max_size;
+ size_t size;
+ uint8_t *buf;
+};
+
+static struct response *init_response(TALLOC_CTX *mem_ctx) {
+ struct response *r;
+ r = talloc(mem_ctx, struct response);
+ r->buf = talloc_size(mem_ctx, MAX_CHILD_MSG_SIZE);
+ if (r->buf == NULL) {
+ DEBUG(1, ("talloc_size failed.\n"));
+ return NULL;
+ }
+ r->max_size = MAX_CHILD_MSG_SIZE;
+ r->size = 0;
+
+ return r;
+}
+
+static errno_t pack_response_packet(struct response *resp, int status, int type, const char *data)
+{
+ int len;
+ int p=0;
+
+ len = strlen(data)+1;
+ if ((3*sizeof(int32_t) + len +1) > resp->max_size) {
+ DEBUG(1, ("response message too big.\n"));
+ return ENOMEM;
+ }
+
+ ((int32_t *)(&resp->buf[p]))[0] = status;
+ p += sizeof(int32_t);
+
+ ((int32_t *)(&resp->buf[p]))[0] = type;
+ p += sizeof(int32_t);
+
+ ((int32_t *)(&resp->buf[p]))[0] = len;
+ p += sizeof(int32_t);
+
+ memcpy(&resp->buf[p], data, len);
+ p += len;
+
+ resp->size = p;
+
+ return EOK;
+}
+
+static struct response * prepare_response_message(struct krb5_req *kr,
+ krb5_error_code kerr, int pam_status)
+{
+ const char *cc_name = NULL;
+ char *msg = NULL;
+ const char *krb5_msg = NULL;
+ int ret;
+ struct response *resp;
+
+ resp = init_response(kr);
+ if (resp == NULL) {
+ DEBUG(1, ("init_response failed.\n"));
+ return NULL;
+ }
+
+ if (kerr == 0) {
+ cc_name = krb5_cc_get_name(kr->ctx, kr->cc);
+ if (cc_name == NULL) {
+ DEBUG(1, ("krb5_cc_get_name failed.\n"));
+ return NULL;
+ }
+
+ msg = talloc_asprintf(kr, "%s=%s",CCACHE_ENV_NAME, cc_name);
+ if (msg == NULL) {
+ DEBUG(1, ("talloc_asprintf failed.\n"));
+ return NULL;
+ }
+
+ ret = pack_response_packet(resp, PAM_SUCCESS, PAM_ENV_ITEM, msg);
+ talloc_zfree(msg);
+ } else {
+ krb5_msg = krb5_get_error_message(krb5_error_ctx, kerr);
+ if (krb5_msg == NULL) {
+ DEBUG(1, ("krb5_get_error_message failed.\n"));
+ return NULL;
+ }
+
+ ret = pack_response_packet(resp, pam_status, PAM_USER_INFO, krb5_msg);
+ krb5_free_error_message(krb5_error_ctx, krb5_msg);
+ }
+
+ if (ret != EOK) {
+ DEBUG(1, ("pack_response_packet failed.\n"));
+ return NULL;
+ }
+
+ return resp;
+}
+
+static errno_t become_user(uid_t uid, gid_t gid)
+{
+ int ret;
+ ret = setgid(gid);
+ if (ret == -1) {
+ DEBUG(1, ("setgid failed [%d][%s].\n", errno, strerror(errno)));
+ return errno;
+ }
+
+ ret = setuid(uid);
+ if (ret == -1) {
+ DEBUG(1, ("setuid failed [%d][%s].\n", errno, strerror(errno)));
+ return errno;
+ }
+
+ ret = setegid(gid);
+ if (ret == -1) {
+ DEBUG(1, ("setegid failed [%d][%s].\n", errno, strerror(errno)));
+ return errno;
+ }
+
+ ret = seteuid(uid);
+ if (ret == -1) {
+ DEBUG(1, ("seteuid failed [%d][%s].\n", errno, strerror(errno)));
+ return errno;
+ }
+
+ return EOK;
+}
+
+static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
+ char *password)
+{
+ krb5_error_code kerr = 0;
+
+ kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
+ password, NULL, NULL, 0, NULL,
+ kr->options);
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ return kerr;
+ }
+
+ kerr = krb5_cc_default(kr->ctx, &kr->cc);
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ return kerr;
+ }
+
+ kerr = krb5_cc_initialize(kr->ctx, kr->cc, kr->princ);
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ return kerr;
+ }
+
+ kerr = krb5_cc_store_cred(kr->ctx, kr->cc, kr->creds);
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ krb5_cc_destroy(kr->ctx, kr->cc);
+ return kerr;
+ }
+
+ return 0;
+
+}
+
+void changepw_child(int fd, struct krb5_req *kr)
+{
+ int ret;
+ krb5_error_code kerr = 0;
+ char *pass_str = NULL;
+ char *newpass_str = NULL;
+ struct response *resp = NULL;
+ int pam_status = PAM_SYSTEM_ERR;
+ int result_code = -1;
+ krb5_data result_code_string;
+ krb5_data result_string;
+
+ if (kr->pd->priv != 1) {
+ ret = become_user(kr->pd->pw_uid, kr->pd->gr_gid);
+ if (ret != EOK) {
+ DEBUG(1, ("become_user failed.\n"));
+ kerr = KRB5KRB_ERR_GENERIC;
+ goto sendresponse;
+ }
+ } else {
+/* TODO: implement password reset by root */
+ DEBUG(1, ("Password reset not implemented.\n"));
+ kerr = KRB5KRB_ERR_GENERIC;
+ goto sendresponse;
+ }
+
+ pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok,
+ kr->pd->authtok_size);
+ if (pass_str == NULL) {
+ DEBUG(1, ("talloc_strndup failed.\n"));
+ kerr = KRB5KRB_ERR_GENERIC;
+ goto sendresponse;
+ }
+
+ kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
+ pass_str, NULL, NULL, 0,
+ kr->krb5_ctx->changepw_principle,
+ kr->options);
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ if (kerr == KRB5_KDC_UNREACH) {
+ pam_status = PAM_AUTHINFO_UNAVAIL;
+ }
+ goto sendresponse;
+ }
+
+ memset(pass_str, 0, kr->pd->authtok_size);
+ talloc_zfree(pass_str);
+ memset(kr->pd->authtok, 0, kr->pd->authtok_size);
+
+ newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok,
+ kr->pd->newauthtok_size);
+ if (newpass_str == NULL) {
+ DEBUG(1, ("talloc_strndup failed.\n"));
+ kerr = KRB5KRB_ERR_GENERIC;
+ goto sendresponse;
+ }
+
+ kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code,
+ &result_code_string, &result_string);
+
+ if (kerr != 0 || result_code != 0) {
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ }
+
+ if (result_code_string.length > 0) {
+ DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code,
+ result_code_string.length, result_code_string.data));
+ }
+
+ if (result_string.length > 0) {
+ DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code,
+ result_string.length, result_string.data));
+ }
+
+ goto sendresponse;
+ }
+
+
+ kerr = get_and_save_tgt(kr, newpass_str);
+ memset(newpass_str, 0, kr->pd->newauthtok_size);
+ talloc_zfree(newpass_str);
+ memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size);
+
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ if (kerr == KRB5_KDC_UNREACH) {
+ pam_status = PAM_AUTHINFO_UNAVAIL;
+ }
+ }
+
+sendresponse:
+ resp = prepare_response_message(kr, kerr, pam_status);
+ if (resp == NULL) {
+ DEBUG(1, ("prepare_response_message failed.\n"));
+ krb5_cc_destroy(kr->ctx, kr->cc);
+ _exit(-1);
+ }
+
+ ret = write(fd, resp->buf, resp->size);
+ if (ret == -1) {
+ DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno)));
+ krb5_cc_destroy(kr->ctx, kr->cc);
+ _exit(ret);
+ }
+
+ krb5_cc_close(kr->ctx, kr->cc);
+
+
+ _exit(0);
+}
+
+void tgt_req_child(int fd, struct krb5_req *kr)
+{
+ int ret;
+ krb5_error_code kerr = 0;
+ char *pass_str = NULL;
+ int pam_status = PAM_SYSTEM_ERR;
+ struct response *resp = NULL;
+
+ ret = become_user(kr->pd->pw_uid, kr->pd->gr_gid);
+ if (ret != EOK) {
+ DEBUG(1, ("become_user failed.\n"));
+ kerr = KRB5KRB_ERR_GENERIC;
+ goto sendresponse;
+ }
+
+ pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok,
+ kr->pd->authtok_size);
+ if (pass_str == NULL) {
+ DEBUG(1, ("talloc_strndup failed.\n"));
+ kerr = KRB5KRB_ERR_GENERIC;
+ goto sendresponse;
+ }
+
+ kerr = get_and_save_tgt(kr, pass_str);
+ memset(pass_str, 0, kr->pd->authtok_size);
+ talloc_zfree(pass_str);
+ memset(kr->pd->authtok, 0, kr->pd->authtok_size);
+
+ if (kerr != 0) {
+ KRB5_DEBUG(1, kerr);
+ if (kerr == KRB5_KDC_UNREACH) {
+ pam_status = PAM_AUTHINFO_UNAVAIL;
+ }
+ }
+
+sendresponse:
+ resp = prepare_response_message(kr, kerr, pam_status);
+ if (resp == NULL) {
+ DEBUG(1, ("prepare_response_message failed.\n"));
+ krb5_cc_destroy(kr->ctx, kr->cc);
+ _exit(-1);
+ }
+
+ ret = write(fd, resp->buf, resp->size);
+ if (ret == -1) {
+ DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno)));
+ krb5_cc_destroy(kr->ctx, kr->cc);
+ _exit(ret);
+ }
+
+ krb5_cc_close(kr->ctx, kr->cc);
+
+
+ _exit(0);
+}
diff --git a/server/providers/krb5/tgt_req_child.c b/server/providers/krb5/tgt_req_child.c
deleted file mode 100644
index af9f52ff3..000000000
--- a/server/providers/krb5/tgt_req_child.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- SSSD
-
- Kerberos 5 Backend Module -- tgt_req child
-
- Authors:
- Sumit Bose <sbose@redhat.com>
-
- Copyright (C) 2009 Red Hat
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-#include <krb5/krb5.h>
-#include <sys/types.h>
-
-#include <security/pam_modules.h>
-
-#include "util/util.h"
-#include "providers/dp_backend.h"
-#include "providers/krb5/krb5_auth.h"
-
-static int pack_response_packet(uint8_t *buf, int status, int type,
- const char *data)
-{
- int len;
- int p=0;
-
- if ((3*sizeof(int32_t) + strlen(data)+1) > MAX_CHILD_MSG_SIZE) {
- return -1;
- }
-
- ((int32_t *)(&buf[p]))[0] = status;
- p += sizeof(int32_t);
-
- ((int32_t *)(&buf[p]))[0] = type;
- p += sizeof(int32_t);
-
- len = strlen(data)+1;
- ((int32_t *)(&buf[p]))[0] = len;
- p += sizeof(int32_t);
-
- memcpy(&buf[p], data, len);
- p += len;
-
- return p;
-}
-
-void tgt_req_child(int fd, struct krb5_req *kr)
-{
- int ret;
- krb5_error_code kerr = 0;
- char *pass_str = NULL;
- uint8_t buf[MAX_CHILD_MSG_SIZE];
- int size = 0;
- const char *cc_name;
- char *env;
- const char *krb5_error_msg;
- int pam_status = PAM_SYSTEM_ERR;
-
- ret = setgid(kr->pd->gr_gid);
- if (ret == -1) {
- DEBUG(1, ("setgid failed [%d][%s].\n", errno, strerror(errno)));
- _exit(-1);
- }
-
- ret = setuid(kr->pd->pw_uid);
- if (ret == -1) {
- DEBUG(1, ("setuid failed [%d][%s].\n", errno, strerror(errno)));
- _exit(-1);
- }
-
- ret = setegid(kr->pd->gr_gid);
- if (ret == -1) {
- DEBUG(1, ("setegid failed [%d][%s].\n", errno, strerror(errno)));
- _exit(-1);
- }
-
- ret = seteuid(kr->pd->pw_uid);
- if (ret == -1) {
- DEBUG(1, ("seteuid failed [%d][%s].\n", errno, strerror(errno)));
- _exit(-1);
- }
-
- pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok,
- kr->pd->authtok_size);
- if (pass_str == NULL) {
- DEBUG(1, ("talloc_strndup failed.\n"));
- _exit(-1);
- }
-
- kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
- pass_str, NULL, NULL, 0, NULL,
- kr->options);
- if (kerr != 0) {
- KRB5_DEBUG(1, kerr);
- if (kerr == KRB5_KDC_UNREACH) {
- pam_status = PAM_AUTHINFO_UNAVAIL;
- }
- goto childfailed;
- }
-
- memset(pass_str, 0, kr->pd->authtok_size);
- talloc_free(pass_str);
- memset(kr->pd->authtok, 0, kr->pd->authtok_size);
-
- kerr = krb5_cc_default(kr->ctx, &kr->cc);
- if (kerr != 0) {
- KRB5_DEBUG(1, kerr);
- goto childfailed;
- }
-
- kerr = krb5_cc_initialize(kr->ctx, kr->cc, kr->princ);
- if (kerr != 0) {
- KRB5_DEBUG(1, kerr);
- goto childfailed;
- }
-
- kerr = krb5_cc_store_cred(kr->ctx, kr->cc, kr->creds);
- if (kerr != 0) {
- KRB5_DEBUG(1, kerr);
- krb5_cc_destroy(kr->ctx, kr->cc);
- goto childfailed;
- }
-
- cc_name = krb5_cc_get_name(kr->ctx, kr->cc);
- if (cc_name == NULL) {
- DEBUG(1, ("krb5_cc_get_name failed.\n"));
- krb5_cc_destroy(kr->ctx, kr->cc);
- _exit(-1);
- }
-
- env = talloc_asprintf(kr, "%s=%s",CCACHE_ENV_NAME, cc_name);
- if (env == NULL) {
- DEBUG(1, ("talloc_asprintf failed.\n"));
- krb5_cc_destroy(kr->ctx, kr->cc);
- _exit(-1);
- }
-
- size = pack_response_packet(buf, PAM_SUCCESS, PAM_ENV_ITEM, env);
- if (size < 0) {
- DEBUG(1, ("failed to create response message.\n"));
- krb5_cc_destroy(kr->ctx, kr->cc);
- _exit(-1);
- }
-
- kerr = 0;
-
-childfailed:
- if (kerr != 0 ) {
- krb5_error_msg = krb5_get_error_message(krb5_error_ctx, kerr);
- size = pack_response_packet(buf, pam_status, PAM_USER_INFO,
- krb5_error_msg);
- if (size < 0) {
- DEBUG(1, ("failed to create response message.\n"));
- krb5_cc_destroy(kr->ctx, kr->cc);
- _exit(-1);
- }
- krb5_free_error_message(krb5_error_ctx, krb5_error_msg);
- }
-
- ret = write(fd, buf, size);
- if (ret == -1) {
- DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno)));
- krb5_cc_destroy(kr->ctx, kr->cc);
- _exit(ret);
- }
-
- krb5_cc_close(kr->ctx, kr->cc);
-
-
- _exit(0);
-}