Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2011 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <stdint.h>
22 : #include <errno.h>
23 : #include <talloc.h>
24 :
25 : #include "util/util.h"
26 : #include "responder/common/responder.h"
27 : #include "responder/common/responder_packet.h"
28 : #include "responder/sudo/sudosrv_private.h"
29 : #include "db/sysdb_sudo.h"
30 : #include "sss_client/sss_cli.h"
31 : #include "responder/common/negcache.h"
32 :
33 0 : static errno_t sudosrv_cmd_send_reply(struct sudo_cmd_ctx *cmd_ctx,
34 : uint8_t *response_body,
35 : size_t response_len)
36 : {
37 : errno_t ret;
38 0 : uint8_t *packet_body = NULL;
39 0 : size_t packet_len = 0;
40 0 : struct cli_ctx *cli_ctx = cmd_ctx->cli_ctx;
41 : TALLOC_CTX *tmp_ctx;
42 :
43 0 : tmp_ctx = talloc_new(NULL);
44 0 : if (!tmp_ctx) return ENOMEM;
45 :
46 0 : ret = sss_packet_new(cli_ctx->creq, 0,
47 0 : sss_packet_get_cmd(cli_ctx->creq->in),
48 0 : &cli_ctx->creq->out);
49 0 : if (ret != EOK) {
50 0 : DEBUG(SSSDBG_CRIT_FAILURE,
51 : "Unable to create a new packet [%d]; %s\n",
52 : ret, strerror(ret));
53 0 : goto done;
54 : }
55 :
56 0 : ret = sss_packet_grow(cli_ctx->creq->out, response_len);
57 0 : if (ret != EOK) {
58 0 : DEBUG(SSSDBG_CRIT_FAILURE,
59 : "Unable to create response: %s\n", strerror(ret));
60 0 : goto done;
61 : }
62 0 : sss_packet_get_body(cli_ctx->creq->out, &packet_body, &packet_len);
63 0 : memcpy(packet_body, response_body, response_len);
64 :
65 0 : sss_packet_set_error(cli_ctx->creq->out, EOK);
66 0 : sss_cmd_done(cmd_ctx->cli_ctx, cmd_ctx);
67 :
68 0 : ret = EOK;
69 :
70 : done:
71 0 : talloc_zfree(tmp_ctx);
72 0 : return ret;
73 : }
74 :
75 0 : static errno_t sudosrv_cmd_send_error(TALLOC_CTX *mem_ctx,
76 : struct sudo_cmd_ctx *cmd_ctx,
77 : uint32_t error)
78 : {
79 0 : uint8_t *response_body = NULL;
80 0 : size_t response_len = 0;
81 0 : int ret = EOK;
82 :
83 0 : if (error == EOK) {
84 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Everything is fine but we are "
85 : "returning error?\n");
86 0 : return EFAULT;
87 : }
88 :
89 0 : ret = sudosrv_build_response(mem_ctx, error, 0, NULL,
90 : &response_body, &response_len);
91 0 : if (ret != EOK) {
92 0 : return ret;
93 : }
94 :
95 0 : return sudosrv_cmd_send_reply(cmd_ctx, response_body, response_len);
96 : }
97 :
98 0 : errno_t sudosrv_cmd_done(struct sudo_cmd_ctx *cmd_ctx, int ret)
99 : {
100 0 : uint8_t *response_body = NULL;
101 0 : size_t response_len = 0;
102 0 : uint32_t num_rules = cmd_ctx->num_rules;
103 0 : struct sysdb_attrs **rules = cmd_ctx->rules;
104 :
105 0 : switch (ret) {
106 : case EOK:
107 : /*
108 : * Parent of cmd_ctx->rules is in-memory cache, we must not talloc_free it!
109 : */
110 0 : if (cmd_ctx->sudo_ctx->timed) {
111 : /* filter rules by time */
112 :
113 0 : DEBUG(SSSDBG_TRACE_FUNC, "Applying time restrictions on"
114 : "%u rules\n", cmd_ctx->num_rules);
115 :
116 0 : ret = sysdb_sudo_filter_rules_by_time(cmd_ctx, cmd_ctx->num_rules,
117 : cmd_ctx->rules, 0,
118 : &num_rules, &rules);
119 0 : if (ret != EOK) {
120 0 : return EFAULT;
121 : }
122 :
123 0 : DEBUG(SSSDBG_TRACE_FUNC, "Got %u rules after time filter\n",
124 : num_rules);
125 : }
126 :
127 : /* send result */
128 0 : ret = sudosrv_build_response(cmd_ctx, SSS_SUDO_ERROR_OK,
129 : num_rules, rules,
130 : &response_body, &response_len);
131 0 : if (ret != EOK) {
132 0 : return EFAULT;
133 : }
134 :
135 0 : ret = sudosrv_cmd_send_reply(cmd_ctx, response_body, response_len);
136 0 : break;
137 :
138 : case EAGAIN:
139 : /* async processing, just return here */
140 0 : return EOK;
141 :
142 : case EFAULT:
143 : /* very bad error */
144 0 : return EFAULT;
145 :
146 :
147 : /* case ENOENT:
148 : * - means user not found
149 : * - send error ENOENT
150 : */
151 :
152 : default:
153 : /* send error */
154 0 : ret = sudosrv_cmd_send_error(cmd_ctx, cmd_ctx, ret);
155 0 : break;
156 : }
157 :
158 0 : if (ret != EOK) {
159 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
160 0 : talloc_free(cmd_ctx->cli_ctx);
161 0 : return EFAULT;
162 : }
163 :
164 0 : return EOK;
165 : }
166 :
167 : static void sudosrv_cmd_parse_query_done(struct tevent_req *req);
168 :
169 0 : static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx)
170 : {
171 0 : struct tevent_req *req = NULL;
172 0 : struct sudo_cmd_ctx *cmd_ctx = NULL;
173 0 : uint8_t *query_body = NULL;
174 0 : size_t query_len = 0;
175 0 : uint32_t protocol = cli_ctx->cli_protocol_version->version;
176 : errno_t ret;
177 :
178 : /* create cmd_ctx */
179 :
180 0 : cmd_ctx = talloc_zero(cli_ctx, struct sudo_cmd_ctx);
181 0 : if (cmd_ctx == NULL) {
182 : /* kill the connection here as we have no context for reply */
183 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
184 0 : return ENOMEM;
185 : }
186 :
187 0 : cmd_ctx->domain = NULL;
188 0 : cmd_ctx->cli_ctx = cli_ctx;
189 0 : cmd_ctx->type = type;
190 0 : cmd_ctx->sudo_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct sudo_ctx);
191 0 : if (cmd_ctx->sudo_ctx == NULL) {
192 0 : DEBUG(SSSDBG_FATAL_FAILURE, "sudo_ctx not set, killing connection!\n");
193 0 : return EFAULT;
194 : }
195 :
196 : /* if protocol is invalid return */
197 0 : switch (protocol) {
198 : case 0:
199 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Protocol [%d] is not secure. "
200 : "SSSD does not allow to use this protocol.\n", protocol);
201 0 : ret = EFAULT;
202 0 : goto done;
203 : break;
204 : case SSS_SUDO_PROTOCOL_VERSION:
205 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Using protocol version [%d]\n",
206 : protocol);
207 0 : break;
208 : default:
209 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Invalid protocol version [%d]!\n",
210 : protocol);
211 0 : ret = EFAULT;
212 0 : goto done;
213 : }
214 :
215 : /* parse query */
216 :
217 0 : sss_packet_get_body(cli_ctx->creq->in, &query_body, &query_len);
218 0 : if (query_len <= 0 || query_body == NULL) {
219 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Query is empty\n");
220 0 : ret = EINVAL;
221 0 : goto done;
222 : }
223 :
224 0 : req = sudosrv_parse_query_send(cmd_ctx, cli_ctx->rctx,
225 : query_body, query_len);
226 0 : if (req == NULL) {
227 0 : ret = ENOMEM;
228 0 : goto done;
229 : }
230 :
231 0 : tevent_req_set_callback(req, sudosrv_cmd_parse_query_done, cmd_ctx);
232 :
233 0 : ret = EAGAIN;
234 :
235 : done:
236 0 : return sudosrv_cmd_done(cmd_ctx, ret);
237 : }
238 :
239 0 : static void sudosrv_cmd_parse_query_done(struct tevent_req *req)
240 : {
241 0 : struct sudo_cmd_ctx *cmd_ctx = NULL;
242 0 : struct sudo_dom_ctx *dom_ctx = NULL;
243 0 : struct sudo_ctx *sudo_ctx = NULL;
244 : errno_t ret;
245 :
246 0 : cmd_ctx = tevent_req_callback_data(req, struct sudo_cmd_ctx);
247 :
248 0 : ret = sudosrv_parse_query_recv(cmd_ctx, req, &cmd_ctx->uid,
249 : &cmd_ctx->username, &cmd_ctx->domain);
250 0 : talloc_zfree(req);
251 0 : if (ret != EOK) {
252 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid query [%d]: %s\n",
253 : ret, strerror(ret));
254 0 : goto done;
255 : }
256 :
257 0 : cmd_ctx->check_next = cmd_ctx->domain == NULL;
258 :
259 0 : switch (cmd_ctx->type) {
260 : case SSS_SUDO_DEFAULTS:
261 0 : DEBUG(SSSDBG_FUNC_DATA, "Requesting default options "
262 : "for [%s] from [%s]\n", cmd_ctx->username,
263 : cmd_ctx->domain ? cmd_ctx->domain->name : "<ALL>");
264 0 : break;
265 : case SSS_SUDO_USER:
266 0 : DEBUG(SSSDBG_FUNC_DATA, "Requesting rules "
267 : "for [%s] from [%s]\n", cmd_ctx->username,
268 : cmd_ctx->domain ? cmd_ctx->domain->name : "<ALL>");
269 0 : break;
270 : }
271 :
272 : /* create domain ctx */
273 :
274 0 : dom_ctx = talloc_zero(cmd_ctx, struct sudo_dom_ctx);
275 0 : if (dom_ctx == NULL) {
276 0 : ret = ENOMEM;
277 0 : goto done;
278 : }
279 0 : dom_ctx->cmd_ctx = cmd_ctx;
280 0 : dom_ctx->domain = cmd_ctx->domain != NULL ? cmd_ctx->domain
281 0 : : cmd_ctx->cli_ctx->rctx->domains;
282 :
283 0 : sudo_ctx = talloc_get_type(cmd_ctx->cli_ctx->rctx->pvt_ctx, struct sudo_ctx);
284 0 : ret = sss_ncache_check_user(sudo_ctx->ncache, sudo_ctx->neg_timeout,
285 0 : dom_ctx->domain, cmd_ctx->username);
286 0 : if (ret == EEXIST) {
287 0 : DEBUG(SSSDBG_TRACE_FUNC, "User [%s@%s] filtered out (ncache)\n",
288 : cmd_ctx->username, dom_ctx->domain->name);
289 0 : ret = ENOENT;
290 0 : goto done;
291 : }
292 :
293 0 : ret = sudosrv_get_sudorules(dom_ctx);
294 :
295 : done:
296 0 : sudosrv_cmd_done(cmd_ctx, ret);
297 0 : }
298 :
299 0 : static int sudosrv_cmd_get_sudorules(struct cli_ctx *cli_ctx)
300 : {
301 0 : return sudosrv_cmd(SSS_SUDO_USER, cli_ctx);
302 : }
303 :
304 0 : static int sudosrv_cmd_get_defaults(struct cli_ctx *cli_ctx)
305 : {
306 0 : return sudosrv_cmd(SSS_SUDO_DEFAULTS, cli_ctx);
307 : }
308 :
309 0 : struct cli_protocol_version *register_cli_protocol_version(void)
310 : {
311 : static struct cli_protocol_version sudo_cli_protocol_version[] = {
312 : {1, "2012-05-14", "require uid and domain"},
313 : {0, NULL, NULL}
314 : };
315 :
316 0 : return sudo_cli_protocol_version;
317 : }
318 :
319 0 : struct sss_cmd_table *get_sudo_cmds(void) {
320 : static struct sss_cmd_table sudo_cmds[] = {
321 : {SSS_GET_VERSION, sss_cmd_get_version},
322 : {SSS_SUDO_GET_SUDORULES, sudosrv_cmd_get_sudorules},
323 : {SSS_SUDO_GET_DEFAULTS, sudosrv_cmd_get_defaults},
324 : {SSS_CLI_NULL, NULL}
325 : };
326 :
327 0 : return sudo_cmds;
328 : }
|