Line data Source code
1 : /*
2 : SSSD
3 :
4 : Kerberos 5 Backend Module - access control
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2010 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "util/util.h"
26 : #include "providers/krb5/krb5_auth.h"
27 : #include "providers/krb5/krb5_common.h"
28 : #include "providers/krb5/krb5_utils.h"
29 :
30 : struct krb5_access_state {
31 : struct tevent_context *ev;
32 : struct be_ctx *be_ctx;
33 :
34 : struct pam_data *pd;
35 : struct krb5_ctx *krb5_ctx;
36 : struct krb5child_req *kr;
37 :
38 : bool access_allowed;
39 : };
40 :
41 : static void krb5_access_done(struct tevent_req *subreq);
42 0 : struct tevent_req *krb5_access_send(TALLOC_CTX *mem_ctx,
43 : struct tevent_context *ev,
44 : struct be_ctx *be_ctx,
45 : struct pam_data *pd,
46 : struct krb5_ctx *krb5_ctx)
47 : {
48 : struct krb5_access_state *state;
49 : struct tevent_req *req;
50 : struct tevent_req *subreq;
51 : int ret;
52 : const char **attrs;
53 : struct ldb_result *res;
54 :
55 0 : req = tevent_req_create(mem_ctx, &state, struct krb5_access_state);
56 0 : if (req == NULL) {
57 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
58 0 : return NULL;
59 : }
60 :
61 0 : state->ev = ev;
62 0 : state->be_ctx = be_ctx;
63 0 : state->pd = pd;
64 0 : state->krb5_ctx = krb5_ctx;
65 0 : state->access_allowed = false;
66 :
67 0 : ret = krb5_setup(state, pd, krb5_ctx, be_ctx->domain->case_sensitive,
68 0 : &state->kr);
69 0 : if (ret != EOK) {
70 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n");
71 0 : goto done;
72 : }
73 :
74 0 : if (pd->cmd != SSS_PAM_ACCT_MGMT) {
75 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected pam task.\n");
76 0 : ret = EINVAL;
77 0 : goto done;
78 : }
79 :
80 0 : attrs = talloc_array(state, const char *, 5);
81 0 : if (attrs == NULL) {
82 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n");
83 0 : ret = ENOMEM;
84 0 : goto done;
85 : }
86 :
87 0 : attrs[0] = SYSDB_UPN;
88 0 : attrs[1] = SYSDB_UIDNUM;
89 0 : attrs[2] = SYSDB_GIDNUM;
90 0 : attrs[3] = SYSDB_CANONICAL_UPN;
91 0 : attrs[4] = NULL;
92 :
93 0 : ret = sysdb_get_user_attr(state, be_ctx->domain, state->pd->user, attrs,
94 : &res);
95 0 : if (ret) {
96 0 : DEBUG(SSSDBG_FUNC_DATA,
97 : "sysdb search for upn of user [%s] failed.\n", pd->user);
98 0 : goto done;
99 : }
100 :
101 0 : switch (res->count) {
102 : case 0:
103 0 : DEBUG(SSSDBG_FUNC_DATA,
104 : "No attributes for user [%s] found.\n", pd->user);
105 0 : ret = ENOENT;
106 0 : goto done;
107 : break;
108 : case 1:
109 0 : ret = find_or_guess_upn(state, res->msgs[0], krb5_ctx, be_ctx->domain,
110 0 : state->kr->user, pd->domain, &state->kr->upn);
111 0 : if (ret != EOK) {
112 0 : DEBUG(SSSDBG_OP_FAILURE, "find_or_guess_upn failed.\n");
113 0 : goto done;
114 : }
115 :
116 0 : state->kr->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM,
117 : 0);
118 0 : if (state->kr->uid == 0) {
119 0 : DEBUG(SSSDBG_CONF_SETTINGS,
120 : "UID for user [%s] not known.\n", pd->user);
121 0 : ret = ENOENT;
122 0 : goto done;
123 : }
124 :
125 0 : state->kr->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM,
126 : 0);
127 0 : if (state->kr->gid == 0) {
128 0 : DEBUG(SSSDBG_CONF_SETTINGS,
129 : "GID for user [%s] not known.\n", pd->user);
130 0 : ret = ENOENT;
131 0 : goto done;
132 : }
133 :
134 0 : break;
135 : default:
136 0 : DEBUG(SSSDBG_CRIT_FAILURE,
137 : "User search for [%s] returned > 1 results!\n", pd->user);
138 0 : ret = EINVAL;
139 0 : goto done;
140 : break;
141 : }
142 :
143 0 : subreq = handle_child_send(state, state->ev, state->kr);
144 0 : if (subreq == NULL) {
145 0 : DEBUG(SSSDBG_CRIT_FAILURE, "handle_child_send failed.\n");
146 0 : ret = ENOMEM;
147 0 : goto done;
148 : }
149 :
150 0 : tevent_req_set_callback(subreq, krb5_access_done, req);
151 0 : return req;
152 :
153 : done:
154 0 : if (ret == EOK) {
155 0 : tevent_req_done(req);
156 : } else {
157 0 : tevent_req_error(req, ret);
158 : }
159 0 : tevent_req_post(req, state->ev);
160 0 : return req;
161 : }
162 :
163 0 : static void krb5_access_done(struct tevent_req *subreq)
164 : {
165 0 : struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
166 0 : struct krb5_access_state *state = tevent_req_data(req,
167 : struct krb5_access_state);
168 : int ret;
169 0 : uint8_t *buf = NULL;
170 0 : ssize_t len = -1;
171 : int32_t msg_status;
172 :
173 0 : ret = handle_child_recv(subreq, state, &buf, &len);
174 0 : talloc_free(subreq);
175 0 : if (ret != EOK) {
176 0 : DEBUG(SSSDBG_CRIT_FAILURE,
177 : "child failed [%d][%s].\n", ret, strerror(ret));
178 0 : goto fail;
179 : }
180 :
181 0 : if ((size_t) len != sizeof(int32_t)) {
182 0 : DEBUG(SSSDBG_CRIT_FAILURE, "message has the wrong size.\n");
183 0 : ret = EINVAL;
184 0 : goto fail;
185 : }
186 :
187 0 : SAFEALIGN_COPY_INT32(&msg_status, buf, NULL);
188 :
189 0 : if (msg_status == EOK) {
190 0 : state->access_allowed = true;
191 : } else {
192 0 : state->access_allowed = false;
193 : }
194 :
195 0 : tevent_req_done(req);
196 0 : return;
197 :
198 : fail:
199 0 : tevent_req_error(req, ret);
200 0 : return;
201 : }
202 :
203 0 : int krb5_access_recv(struct tevent_req *req, bool *access_allowed)
204 : {
205 0 : struct krb5_access_state *state = tevent_req_data(req,
206 : struct krb5_access_state);
207 :
208 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
209 :
210 0 : *access_allowed = state->access_allowed;
211 :
212 0 : return EOK;
213 : }
|