Line data Source code
1 : /*
2 : Authors:
3 : Jakub Hrozek <jhrozek@redhat.com>
4 :
5 : Copyright (C) 2013 Red Hat
6 :
7 : InfoPipe responder: the responder server
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 : #include <stdio.h>
24 : #include <unistd.h>
25 : #include <fcntl.h>
26 : #include <sys/types.h>
27 : #include <sys/stat.h>
28 : #include <sys/socket.h>
29 : #include <sys/un.h>
30 : #include <string.h>
31 : #include <sys/time.h>
32 : #include <errno.h>
33 : #include <popt.h>
34 : #include <dbus/dbus.h>
35 :
36 : #include "util/util.h"
37 : #include "util/strtonum.h"
38 : #include "sbus/sssd_dbus.h"
39 : #include "monitor/monitor_interfaces.h"
40 : #include "confdb/confdb.h"
41 : #include "responder/ifp/ifp_private.h"
42 : #include "responder/ifp/ifp_domains.h"
43 : #include "responder/ifp/ifp_components.h"
44 : #include "responder/common/responder_sbus.h"
45 :
46 : #define DEFAULT_ALLOWED_UIDS "0"
47 :
48 : static int ifp_sysbus_reconnect(struct sbus_request *dbus_req, void *data);
49 :
50 : struct mon_cli_iface monitor_ifp_methods = {
51 : { &mon_cli_iface_meta, 0 },
52 : .ping = monitor_common_pong,
53 : .resInit = monitor_common_res_init,
54 : .shutDown = NULL,
55 : .goOffline = NULL,
56 : .resetOffline = NULL,
57 : .rotateLogs = responder_logrotate,
58 : .sysbusReconnect = ifp_sysbus_reconnect,
59 : };
60 :
61 : static struct data_provider_iface ifp_dp_methods = {
62 : { &data_provider_iface_meta, 0 },
63 : .RegisterService = NULL,
64 : .pamHandler = NULL,
65 : .sudoHandler = NULL,
66 : .autofsHandler = NULL,
67 : .hostHandler = NULL,
68 : .getDomains = NULL,
69 : .getAccountInfo = NULL,
70 : };
71 :
72 0 : struct sss_cmd_table *get_ifp_cmds(void)
73 : {
74 : static struct sss_cmd_table ifp_cmds[] = {
75 : { SSS_GET_VERSION, sss_cmd_get_version },
76 : { SSS_CLI_NULL, NULL}
77 : };
78 :
79 0 : return ifp_cmds;
80 : }
81 :
82 0 : static void ifp_dp_reconnect_init(struct sbus_connection *conn,
83 : int status, void *pvt)
84 : {
85 0 : struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn);
86 : int ret;
87 :
88 : /* Did we reconnect successfully? */
89 0 : if (status == SBUS_RECONNECT_SUCCESS) {
90 0 : DEBUG(SSSDBG_TRACE_FUNC, "Reconnected to the Data Provider.\n");
91 :
92 : /* Identify ourselves to the data provider */
93 0 : ret = dp_common_send_id(be_conn->conn,
94 : DATA_PROVIDER_VERSION,
95 : "InfoPipe");
96 : /* all fine */
97 0 : if (ret == EOK) {
98 0 : handle_requests_after_reconnect(be_conn->rctx);
99 0 : return;
100 : }
101 : }
102 :
103 : /* Failed to reconnect */
104 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not reconnect to %s provider.\n",
105 : be_conn->domain->name);
106 : }
107 :
108 : static errno_t
109 0 : sysbus_init(TALLOC_CTX *mem_ctx,
110 : struct tevent_context *ev,
111 : const char *dbus_name,
112 : void *pvt,
113 : struct sysbus_ctx **sysbus)
114 : {
115 : DBusError dbus_error;
116 0 : DBusConnection *conn = NULL;
117 0 : struct sysbus_ctx *system_bus = NULL;
118 : errno_t ret;
119 :
120 0 : system_bus = talloc_zero(mem_ctx, struct sysbus_ctx);
121 0 : if (system_bus == NULL) {
122 0 : return ENOMEM;
123 : }
124 :
125 0 : dbus_error_init(&dbus_error);
126 :
127 : /* Connect to the well-known system bus */
128 0 : conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
129 0 : if (conn == NULL) {
130 0 : DEBUG(SSSDBG_CRIT_FAILURE,
131 : "Failed to connect to D-BUS system bus: [%s]\n",
132 : dbus_error.message);
133 0 : ret = ERR_NO_SYSBUS;
134 0 : goto fail;
135 : }
136 0 : dbus_connection_set_exit_on_disconnect(conn, FALSE);
137 :
138 0 : ret = dbus_bus_request_name(conn, dbus_name,
139 : /* We want exclusive access */
140 : DBUS_NAME_FLAG_DO_NOT_QUEUE,
141 : &dbus_error);
142 0 : if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
143 : /* We were unable to register on the system bus */
144 0 : DEBUG(SSSDBG_CRIT_FAILURE,
145 : "Unable to request name on the system bus: [%s]\n",
146 : dbus_error.message);
147 0 : ret = EIO;
148 0 : goto fail;
149 : }
150 :
151 0 : DEBUG(SSSDBG_TRACE_FUNC, "Listening on %s\n", dbus_name);
152 :
153 : /* Integrate with tevent loop */
154 0 : ret = sbus_init_connection(system_bus, ev, conn,
155 : SBUS_CONN_TYPE_SYSBUS,
156 : &system_bus->conn);
157 0 : if (ret != EOK) {
158 0 : DEBUG(SSSDBG_CRIT_FAILURE,
159 : "Could not integrate D-BUS into mainloop.\n");
160 0 : goto fail;
161 : }
162 :
163 0 : ret = ifp_register_sbus_interface(system_bus->conn, pvt);
164 0 : if (ret != EOK) {
165 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not register interfaces\n");
166 0 : goto fail;
167 : }
168 :
169 0 : ifp_register_nodes(pvt, system_bus->conn);
170 :
171 0 : *sysbus = system_bus;
172 0 : return EOK;
173 :
174 : fail:
175 0 : if (dbus_error_is_set(&dbus_error)) {
176 0 : DEBUG(SSSDBG_OP_FAILURE,
177 : "DBus error message: %s\n", dbus_error.message);
178 0 : dbus_error_free(&dbus_error);
179 : }
180 :
181 0 : if (conn) dbus_connection_unref(conn);
182 :
183 0 : talloc_free(system_bus);
184 0 : return ret;
185 : }
186 :
187 0 : static int ifp_sysbus_reconnect(struct sbus_request *dbus_req, void *data)
188 : {
189 0 : struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
190 0 : struct ifp_ctx *ifp_ctx = (struct ifp_ctx*) rctx->pvt_ctx;
191 : errno_t ret;
192 :
193 0 : DEBUG(SSSDBG_TRACE_FUNC, "Attempting to reconnect to the system bus\n");
194 :
195 0 : if (ifp_ctx->sysbus) {
196 0 : DEBUG(SSSDBG_TRACE_LIBS, "Already connected to sysbus\n");
197 0 : goto done;
198 : }
199 :
200 : /* Connect to the D-BUS system bus and set up methods */
201 0 : ret = sysbus_init(ifp_ctx, ifp_ctx->rctx->ev,
202 : IFACE_IFP,
203 : ifp_ctx, &ifp_ctx->sysbus);
204 0 : if (ret == ERR_NO_SYSBUS) {
205 0 : DEBUG(SSSDBG_MINOR_FAILURE,
206 : "The system bus is not available..\n");
207 0 : goto done;
208 0 : } else if (ret != EOK) {
209 0 : DEBUG(SSSDBG_CRIT_FAILURE,
210 : "Failed to connect to the system message bus\n");
211 0 : return ret;
212 : }
213 :
214 0 : DEBUG(SSSDBG_TRACE_LIBS, "Reconnected to the system bus!\n");
215 :
216 : done:
217 0 : return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
218 : }
219 :
220 0 : int ifp_process_init(TALLOC_CTX *mem_ctx,
221 : struct tevent_context *ev,
222 : struct confdb_ctx *cdb)
223 : {
224 : struct resp_ctx *rctx;
225 : struct sss_cmd_table *ifp_cmds;
226 : struct ifp_ctx *ifp_ctx;
227 : struct be_conn *iter;
228 : int ret;
229 : int max_retries;
230 : char *uid_str;
231 : char *attr_list_str;
232 : char *wildcard_limit_str;
233 :
234 0 : ifp_cmds = get_ifp_cmds();
235 0 : ret = sss_process_init(mem_ctx, ev, cdb,
236 : ifp_cmds,
237 : NULL, -1, NULL, -1,
238 : CONFDB_IFP_CONF_ENTRY,
239 : SSS_IFP_SBUS_SERVICE_NAME,
240 : SSS_IFP_SBUS_SERVICE_VERSION,
241 : &monitor_ifp_methods,
242 : "InfoPipe",
243 : &ifp_dp_methods.vtable,
244 : &rctx);
245 0 : if (ret != EOK) {
246 0 : DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
247 0 : return ret;
248 : }
249 :
250 0 : ifp_ctx = talloc_zero(rctx, struct ifp_ctx);
251 0 : if (ifp_ctx == NULL) {
252 0 : DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing ifp_ctx\n");
253 0 : ret = ENOMEM;
254 0 : goto fail;
255 : }
256 :
257 0 : ifp_ctx->rctx = rctx;
258 0 : ifp_ctx->rctx->pvt_ctx = ifp_ctx;
259 :
260 0 : ret = sss_names_init_from_args(ifp_ctx,
261 : "(?P<name>[^@]+)@?(?P<domain>[^@]*$)",
262 : "%1$s@%2$s", &ifp_ctx->snctx);
263 0 : if (ret != EOK) {
264 0 : DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing regex data\n");
265 0 : goto fail;
266 : }
267 :
268 0 : ret = confdb_get_string(ifp_ctx->rctx->cdb, ifp_ctx->rctx,
269 : CONFDB_IFP_CONF_ENTRY, CONFDB_SERVICE_ALLOWED_UIDS,
270 : DEFAULT_ALLOWED_UIDS, &uid_str);
271 0 : if (ret != EOK) {
272 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get allowed UIDs.\n");
273 0 : goto fail;
274 : }
275 :
276 0 : ret = csv_string_to_uid_array(ifp_ctx->rctx, uid_str, true,
277 0 : &ifp_ctx->rctx->allowed_uids_count,
278 0 : &ifp_ctx->rctx->allowed_uids);
279 0 : talloc_free(uid_str);
280 0 : if (ret != EOK) {
281 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set allowed UIDs.\n");
282 0 : goto fail;
283 : }
284 :
285 : /* Set up the negative cache */
286 0 : ret = confdb_get_int(cdb, CONFDB_NSS_CONF_ENTRY,
287 : CONFDB_NSS_ENTRY_NEG_TIMEOUT, 15,
288 : &ifp_ctx->neg_timeout);
289 0 : if (ret != EOK) {
290 0 : goto fail;
291 : }
292 :
293 0 : ret = sss_ncache_init(rctx, &ifp_ctx->ncache);
294 0 : if (ret != EOK) {
295 0 : DEBUG(SSSDBG_CRIT_FAILURE, "fatal error initializing negcache\n");
296 0 : goto fail;
297 : }
298 :
299 0 : ret = confdb_get_string(ifp_ctx->rctx->cdb, ifp_ctx->rctx,
300 : CONFDB_IFP_CONF_ENTRY, CONFDB_IFP_USER_ATTR_LIST,
301 : NULL, &attr_list_str);
302 0 : if (ret != EOK) {
303 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get user attribute list.\n");
304 0 : goto fail;
305 : }
306 :
307 0 : ifp_ctx->user_whitelist = ifp_parse_user_attr_list(ifp_ctx, attr_list_str);
308 0 : talloc_free(attr_list_str);
309 0 : if (ifp_ctx->user_whitelist == NULL) {
310 0 : DEBUG(SSSDBG_FATAL_FAILURE,
311 : "Failed to parse the allowed attribute list\n");
312 0 : goto fail;
313 : }
314 :
315 : /* Enable automatic reconnection to the Data Provider */
316 0 : ret = confdb_get_int(ifp_ctx->rctx->cdb,
317 : CONFDB_IFP_CONF_ENTRY,
318 : CONFDB_SERVICE_RECON_RETRIES,
319 : 3, &max_retries);
320 0 : if (ret != EOK) {
321 0 : DEBUG(SSSDBG_FATAL_FAILURE,
322 : "Failed to set up automatic reconnection\n");
323 0 : goto fail;
324 : }
325 :
326 : /* A bit convoluted way until we have a confdb_get_uint32 */
327 0 : ret = confdb_get_string(ifp_ctx->rctx->cdb,
328 0 : ifp_ctx->rctx,
329 : CONFDB_IFP_CONF_ENTRY,
330 : CONFDB_IFP_WILDCARD_LIMIT,
331 : NULL, /* no limit by default */
332 : &wildcard_limit_str);
333 0 : if (ret != EOK) {
334 0 : DEBUG(SSSDBG_FATAL_FAILURE,
335 : "Failed to retrieve limit for a wildcard search\n");
336 0 : goto fail;
337 : }
338 :
339 0 : if (wildcard_limit_str) {
340 0 : ifp_ctx->wildcard_limit = strtouint32(wildcard_limit_str, NULL, 10);
341 0 : ret = errno;
342 0 : if (ret != EOK) {
343 0 : goto fail;
344 : }
345 : }
346 :
347 0 : for (iter = ifp_ctx->rctx->be_conns; iter; iter = iter->next) {
348 0 : sbus_reconnect_init(iter->conn, max_retries,
349 : ifp_dp_reconnect_init, iter);
350 : }
351 :
352 : /* Connect to the D-BUS system bus and set up methods */
353 0 : ret = sysbus_init(ifp_ctx, ifp_ctx->rctx->ev,
354 : IFACE_IFP,
355 : ifp_ctx, &ifp_ctx->sysbus);
356 0 : if (ret == ERR_NO_SYSBUS) {
357 0 : DEBUG(SSSDBG_MINOR_FAILURE,
358 : "The system bus is not available..\n");
359 : /* Explicitly ignore, the D-Bus daemon will start us */
360 0 : } else if (ret != EOK) {
361 0 : DEBUG(SSSDBG_CRIT_FAILURE,
362 : "Failed to connect to the system message bus\n");
363 0 : talloc_free(ifp_ctx);
364 0 : return EIO;
365 : }
366 :
367 0 : ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL);
368 0 : if (ret != EOK) {
369 0 : DEBUG(SSSDBG_FATAL_FAILURE,
370 : "schedule_get_domains_tasks failed.\n");
371 0 : goto fail;
372 : }
373 :
374 0 : DEBUG(SSSDBG_TRACE_FUNC, "InfoPipe Initialization complete\n");
375 0 : return EOK;
376 :
377 : fail:
378 0 : talloc_free(rctx);
379 0 : return ret;
380 : }
381 :
382 0 : int main(int argc, const char *argv[])
383 : {
384 : int opt;
385 : poptContext pc;
386 : struct main_context *main_ctx;
387 : int ret;
388 : uid_t uid;
389 : gid_t gid;
390 :
391 0 : struct poptOption long_options[] = {
392 : POPT_AUTOHELP
393 0 : SSSD_MAIN_OPTS
394 0 : SSSD_SERVER_OPTS(uid, gid)
395 : POPT_TABLEEND
396 : };
397 :
398 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
399 0 : debug_level = SSSDBG_INVALID;
400 :
401 0 : umask(DFL_RSP_UMASK);
402 :
403 0 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
404 0 : while((opt = poptGetNextOpt(pc)) != -1) {
405 : switch(opt) {
406 : default:
407 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
408 : poptBadOption(pc, 0), poptStrerror(opt));
409 0 : poptPrintUsage(pc, stderr, 0);
410 0 : return 1;
411 : }
412 : }
413 :
414 0 : poptFreeContext(pc);
415 :
416 0 : DEBUG_INIT(debug_level);
417 :
418 : /* set up things like debug, signals, daemonization, etc... */
419 0 : debug_log_file = "sssd_ifp";
420 :
421 0 : ret = server_setup("sssd[ifp]", 0, 0, 0,
422 : CONFDB_IFP_CONF_ENTRY, &main_ctx);
423 0 : if (ret != EOK) return 2;
424 :
425 0 : ret = die_if_parent_died();
426 0 : if (ret != EOK) {
427 : /* This is not fatal, don't return */
428 0 : DEBUG(SSSDBG_MINOR_FAILURE,
429 : "Could not set up to exit when parent process does\n");
430 : }
431 :
432 0 : ret = ifp_process_init(main_ctx,
433 0 : main_ctx->event_ctx,
434 0 : main_ctx->confdb_ctx);
435 0 : if (ret != EOK) return 3;
436 :
437 : /* loop on main */
438 0 : server_loop(main_ctx);
439 0 : return 0;
440 : }
|