Line data Source code
1 : /*
2 : SSSD
3 :
4 : Authors:
5 : Stephen Gallagher <sgallagh@redhat.com>
6 :
7 : Copyright (C) 2012 Red Hat
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 :
24 : #include <errno.h>
25 :
26 : #include "util/util.h"
27 : #include "util/strtonum.h"
28 : #include "db/sysdb.h"
29 : #include "db/sysdb_services.h"
30 : #include "providers/ldap/ldap_common.h"
31 : #include "providers/ldap/sdap_async.h"
32 :
33 : struct sdap_services_get_state {
34 : struct tevent_context *ev;
35 : struct sdap_id_ctx *id_ctx;
36 : struct sdap_domain *sdom;
37 : struct sdap_id_op *op;
38 : struct sysdb_ctx *sysdb;
39 : struct sss_domain_info *domain;
40 : struct sdap_id_conn_ctx *conn;
41 :
42 : const char *name;
43 : const char *protocol;
44 :
45 : char *filter;
46 : const char **attrs;
47 :
48 : int filter_type;
49 :
50 : int dp_error;
51 : int sdap_ret;
52 : bool noexist_delete;
53 : };
54 :
55 : static errno_t
56 : services_get_retry(struct tevent_req *req);
57 : static void
58 : services_get_connect_done(struct tevent_req *subreq);
59 : static void
60 : services_get_done(struct tevent_req *subreq);
61 :
62 : struct tevent_req *
63 0 : services_get_send(TALLOC_CTX *mem_ctx,
64 : struct tevent_context *ev,
65 : struct sdap_id_ctx *id_ctx,
66 : struct sdap_domain *sdom,
67 : struct sdap_id_conn_ctx *conn,
68 : const char *name,
69 : const char *protocol,
70 : int filter_type,
71 : bool noexist_delete)
72 : {
73 : errno_t ret;
74 : struct tevent_req *req;
75 : struct sdap_services_get_state *state;
76 : const char *attr_name;
77 : char *clean_name;
78 0 : char *clean_protocol = NULL;
79 :
80 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_services_get_state);
81 0 : if (!req) return NULL;
82 :
83 0 : state->ev = ev;
84 0 : state->id_ctx = id_ctx;
85 0 : state->sdom = sdom;
86 0 : state->conn = conn;
87 0 : state->dp_error = DP_ERR_FATAL;
88 0 : state->domain = sdom->dom;
89 0 : state->sysdb = sdom->dom->sysdb;
90 0 : state->name = name;
91 0 : state->protocol = protocol;
92 0 : state->filter_type = filter_type;
93 0 : state->noexist_delete = noexist_delete;
94 :
95 0 : state->op = sdap_id_op_create(state, state->conn->conn_cache);
96 0 : if (!state->op) {
97 0 : DEBUG(SSSDBG_MINOR_FAILURE, "sdap_id_op_create failed\n");
98 0 : ret = ENOMEM;
99 0 : goto error;
100 : }
101 :
102 0 : switch(filter_type) {
103 : case BE_FILTER_NAME:
104 0 : attr_name = id_ctx->opts->service_map[SDAP_AT_SERVICE_NAME].name;
105 0 : break;
106 : case BE_FILTER_IDNUM:
107 0 : attr_name = id_ctx->opts->service_map[SDAP_AT_SERVICE_PORT].name;
108 0 : break;
109 : default:
110 0 : ret = EINVAL;
111 0 : goto error;
112 : }
113 :
114 0 : ret = sss_filter_sanitize(state, name, &clean_name);
115 0 : if (ret != EOK) goto error;
116 :
117 0 : if (protocol) {
118 0 : ret = sss_filter_sanitize(state, protocol, &clean_protocol);
119 0 : if (ret != EOK) goto error;
120 : }
121 :
122 0 : if (clean_protocol) {
123 0 : state->filter = talloc_asprintf(
124 : state, "(&(%s=%s)(%s=%s)(objectclass=%s))",
125 : attr_name, clean_name,
126 0 : id_ctx->opts->service_map[SDAP_AT_SERVICE_PROTOCOL].name,
127 : clean_protocol,
128 0 : id_ctx->opts->service_map[SDAP_OC_SERVICE].name);
129 : } else {
130 0 : state->filter =
131 0 : talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
132 : attr_name, clean_name,
133 0 : id_ctx->opts->service_map[SDAP_OC_SERVICE].name);
134 : }
135 0 : talloc_zfree(clean_name);
136 0 : talloc_zfree(clean_protocol);
137 0 : if (!state->filter) {
138 0 : DEBUG(SSSDBG_MINOR_FAILURE,
139 : "Failed to build the base filter\n");
140 0 : ret = ENOMEM;
141 0 : goto error;
142 : }
143 0 : DEBUG(SSSDBG_TRACE_LIBS,
144 : "Preparing to search for services with filter [%s]\n",
145 : state->filter);
146 :
147 0 : ret = build_attrs_from_map(state, id_ctx->opts->service_map,
148 : SDAP_OPTS_SERVICES, NULL,
149 0 : &state->attrs, NULL);
150 0 : if (ret != EOK) goto error;
151 :
152 0 : ret = services_get_retry(req);
153 0 : if (ret != EOK) goto error;
154 :
155 0 : return req;
156 :
157 : error:
158 0 : tevent_req_error(req, ret);
159 0 : tevent_req_post(req, ev);
160 0 : return req;
161 : }
162 :
163 : static errno_t
164 0 : services_get_retry(struct tevent_req *req)
165 : {
166 : errno_t ret;
167 0 : struct sdap_services_get_state *state =
168 0 : tevent_req_data(req, struct sdap_services_get_state);
169 : struct tevent_req *subreq;
170 :
171 0 : subreq = sdap_id_op_connect_send(state->op, state, &ret);
172 0 : if (!subreq) {
173 0 : return ret;
174 : }
175 :
176 0 : tevent_req_set_callback(subreq, services_get_connect_done, req);
177 0 : return EOK;
178 : }
179 :
180 : static void
181 0 : services_get_connect_done(struct tevent_req *subreq)
182 : {
183 : errno_t ret;
184 0 : struct tevent_req *req =
185 0 : tevent_req_callback_data(subreq, struct tevent_req);
186 0 : struct sdap_services_get_state *state =
187 0 : tevent_req_data(req, struct sdap_services_get_state);
188 0 : int dp_error = DP_ERR_FATAL;
189 :
190 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
191 0 : talloc_zfree(subreq);
192 :
193 0 : if (ret != EOK) {
194 0 : state->dp_error = dp_error;
195 0 : tevent_req_error(req, ret);
196 0 : return;
197 : }
198 :
199 0 : subreq = sdap_get_services_send(state, state->ev,
200 : state->domain, state->sysdb,
201 0 : state->id_ctx->opts,
202 0 : state->sdom->service_search_bases,
203 : sdap_id_op_handle(state->op),
204 0 : state->attrs, state->filter,
205 0 : dp_opt_get_int(state->id_ctx->opts->basic,
206 : SDAP_SEARCH_TIMEOUT),
207 : false);
208 0 : if (!subreq) {
209 0 : tevent_req_error(req, ENOMEM);
210 0 : return;
211 : }
212 0 : tevent_req_set_callback(subreq, services_get_done, req);
213 : }
214 :
215 : static void
216 0 : services_get_done(struct tevent_req *subreq)
217 : {
218 : errno_t ret;
219 : uint16_t port;
220 0 : struct tevent_req *req =
221 0 : tevent_req_callback_data(subreq, struct tevent_req);
222 0 : struct sdap_services_get_state *state =
223 0 : tevent_req_data(req, struct sdap_services_get_state);
224 0 : int dp_error = DP_ERR_FATAL;
225 :
226 0 : ret = sdap_get_services_recv(NULL, subreq, NULL);
227 0 : talloc_zfree(subreq);
228 :
229 : /* Check whether we need to try again with another
230 : * failover server.
231 : */
232 0 : ret = sdap_id_op_done(state->op, ret, &dp_error);
233 0 : if (dp_error == DP_ERR_OK && ret != EOK) {
234 : /* retry */
235 0 : ret = services_get_retry(req);
236 0 : if (ret != EOK) {
237 0 : tevent_req_error(req, ret);
238 0 : return;
239 : }
240 :
241 : /* Return to the mainloop to retry */
242 0 : return;
243 : }
244 0 : state->sdap_ret = ret;
245 :
246 : /* An error occurred. */
247 0 : if (ret && ret != ENOENT) {
248 0 : state->dp_error = dp_error;
249 0 : tevent_req_error(req, ret);
250 0 : return;
251 : }
252 :
253 0 : if (ret == ENOENT && state->noexist_delete == true) {
254 : /* Ensure that this entry is removed from the sysdb */
255 0 : switch(state->filter_type) {
256 : case BE_FILTER_NAME:
257 0 : ret = sysdb_svc_delete(state->domain, state->name,
258 : 0, state->protocol);
259 0 : if (ret != EOK) {
260 0 : tevent_req_error(req, ret);
261 0 : return;
262 : }
263 0 : break;
264 :
265 : case BE_FILTER_IDNUM:
266 0 : port = strtouint16(state->name, NULL, 10);
267 0 : if (errno) {
268 0 : tevent_req_error(req, errno);
269 0 : return;
270 : }
271 :
272 0 : ret = sysdb_svc_delete(state->domain, NULL, port,
273 : state->protocol);
274 0 : if (ret != EOK) {
275 0 : tevent_req_error(req, ret);
276 0 : return;
277 : }
278 0 : break;
279 :
280 : default:
281 0 : tevent_req_error(req, EINVAL);
282 0 : return;
283 : }
284 : }
285 :
286 0 : state->dp_error = DP_ERR_OK;
287 0 : tevent_req_done(req);
288 : }
289 :
290 : errno_t
291 0 : services_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret)
292 : {
293 0 : struct sdap_services_get_state *state =
294 0 : tevent_req_data(req, struct sdap_services_get_state);
295 :
296 0 : if (dp_error_out) {
297 0 : *dp_error_out = state->dp_error;
298 : }
299 :
300 0 : if (sdap_ret) {
301 0 : *sdap_ret = state->sdap_ret;
302 : }
303 :
304 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
305 :
306 0 : return EOK;
307 : }
|