Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2016 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 "providers/backend.h"
22 : #include "providers/data_provider/dp_iface_generated.h"
23 : #include "providers/data_provider/dp_private.h"
24 : #include "providers/data_provider/dp_iface.h"
25 : #include "providers/data_provider/dp.h"
26 : #include "sbus/sssd_dbus.h"
27 : #include "sbus/sssd_dbus_errors.h"
28 : #include "util/util.h"
29 :
30 : struct dp_client {
31 : struct data_provider *provider;
32 : struct sbus_connection *conn;
33 : struct tevent_timer *timeout;
34 : const char *name;
35 : bool initialized;
36 : };
37 :
38 0 : const char *dp_client_to_string(enum dp_clients client)
39 : {
40 0 : switch (client) {
41 : case DPC_NSS:
42 0 : return "NSS";
43 : case DPC_PAM:
44 0 : return "PAM";
45 : case DPC_IFP:
46 0 : return "InfoPipe";
47 : case DPC_PAC:
48 0 : return "PAC";
49 : case DPC_SUDO:
50 0 : return "SUDO";
51 : case DPC_HOST:
52 0 : return "SSH";
53 : case DPC_AUTOFS:
54 0 : return "autofs";
55 : case DP_CLIENT_SENTINEL:
56 0 : return "Invalid";
57 : }
58 :
59 0 : return "Invalid";
60 : }
61 :
62 0 : static int dp_client_destructor(struct dp_client *dp_cli)
63 : {
64 : struct data_provider *provider;
65 : enum dp_clients client;
66 :
67 0 : if (dp_cli->provider == NULL) {
68 0 : return 0;
69 : }
70 :
71 0 : provider = dp_cli->provider;
72 :
73 0 : for (client = 0; client != DP_CLIENT_SENTINEL; client++) {
74 0 : if (provider->clients[client] == dp_cli) {
75 0 : provider->clients[client] = NULL;
76 0 : DEBUG(SSSDBG_TRACE_FUNC, "Removed %s client\n",
77 : dp_client_to_string(client));
78 0 : break;
79 : }
80 : }
81 :
82 0 : if (client == DP_CLIENT_SENTINEL) {
83 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown client removed...\n");
84 : }
85 :
86 0 : return 0;
87 : }
88 :
89 : static int
90 0 : dp_client_register(struct sbus_request *sbus_req,
91 : void *data,
92 : const char *client_name)
93 : {
94 : struct data_provider *provider;
95 : struct dp_client *dp_cli;
96 : struct DBusError *error;
97 : enum dp_clients client;
98 : errno_t ret;
99 :
100 0 : dp_cli = talloc_get_type(data, struct dp_client);
101 0 : if (dp_cli == NULL) {
102 : /* Do not send D-Bus error here. */
103 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Bug: dp_cli is NULL\n");
104 0 : return EINVAL;
105 : }
106 :
107 0 : provider = dp_cli->provider;
108 0 : dp_cli->name = talloc_strdup(dp_cli, client_name);
109 0 : if (dp_cli->name == NULL) {
110 0 : return ENOMEM;
111 : }
112 :
113 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Cancel DP ID timeout [%p]\n", dp_cli->timeout);
114 0 : talloc_zfree(dp_cli->timeout);
115 :
116 0 : for (client = 0; client != DP_CLIENT_SENTINEL; client++) {
117 0 : if (strcasecmp(client_name, dp_client_to_string(client)) == 0) {
118 0 : provider->clients[client] = dp_cli;
119 0 : break;
120 : }
121 : }
122 :
123 0 : if (client == DP_CLIENT_SENTINEL) {
124 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown client! [%s]\n", client_name);
125 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
126 : "Unknown client [%s]", client_name);
127 :
128 : /* Kill this client. */
129 0 : talloc_free(dp_cli);
130 0 : return sbus_request_fail_and_finish(sbus_req, error);
131 : }
132 :
133 0 : talloc_set_destructor(dp_cli, dp_client_destructor);
134 :
135 0 : ret = iface_dp_client_Register_finish(sbus_req);
136 0 : if (ret != EOK) {
137 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Unable to send ack to the client [%s], "
138 : "disconnecting...\n", client_name);
139 0 : sbus_disconnect(sbus_req->conn);
140 0 : return ret;
141 : }
142 :
143 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Added Frontend client [%s]\n", client_name);
144 :
145 0 : dp_cli->initialized = true;
146 0 : return EOK;
147 : }
148 :
149 : static void
150 0 : dp_client_handshake_timeout(struct tevent_context *ev,
151 : struct tevent_timer *te,
152 : struct timeval t,
153 : void *ptr)
154 : {
155 : struct dp_client *dp_cli;
156 :
157 0 : DEBUG(SSSDBG_OP_FAILURE,
158 : "Client timed out before identification [%p]!\n", te);
159 :
160 0 : dp_cli = talloc_get_type(ptr, struct dp_client);
161 :
162 0 : sbus_disconnect(dp_cli->conn);
163 0 : talloc_zfree(dp_cli);
164 0 : }
165 :
166 0 : errno_t dp_client_init(struct sbus_connection *conn, void *data)
167 : {
168 : struct data_provider *provider;
169 : struct dp_client *dp_cli;
170 : struct timeval tv;
171 : errno_t ret;
172 :
173 : static struct iface_dp_client iface_dp_client = {
174 : { &iface_dp_client_meta, 0 },
175 :
176 : .Register = dp_client_register,
177 : };
178 :
179 0 : provider = talloc_get_type(data, struct data_provider);
180 :
181 : /* When connection is lost we also free the client. */
182 0 : dp_cli = talloc_zero(conn, struct dp_client);
183 0 : if (dp_cli == NULL) {
184 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, killing connection.\n");
185 0 : talloc_free(conn);
186 0 : return ENOMEM;
187 : }
188 :
189 0 : dp_cli->provider = provider;
190 0 : dp_cli->conn = conn;
191 0 : dp_cli->initialized = false;
192 0 : dp_cli->timeout = NULL;
193 :
194 : /* Allow access from the SSSD user. */
195 0 : sbus_allow_uid(conn, &provider->uid);
196 :
197 : /* Setup timeout in case client fails to register himself in time. */
198 0 : tv = tevent_timeval_current_ofs(5, 0);
199 0 : dp_cli->timeout = tevent_add_timer(provider->ev, dp_cli, tv,
200 : dp_client_handshake_timeout, dp_cli);
201 0 : if (dp_cli->timeout == NULL) {
202 : /* Connection is closed in the caller. */
203 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, killing connection\n");
204 0 : return ENOMEM;
205 : }
206 :
207 0 : DEBUG(SSSDBG_CONF_SETTINGS,
208 : "Set-up Backend ID timeout [%p]\n", dp_cli->timeout);
209 :
210 : /* Setup D-Bus interfaces and methods. */
211 0 : ret = sbus_conn_register_iface(conn, &iface_dp_client.vtable,
212 : DP_PATH, dp_cli);
213 0 : if (ret != EOK) {
214 : /* Connection is closed in the caller. */
215 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register D-Bus interface, "
216 : "killing connection [%d]: %s\n", ret, sss_strerror(ret));
217 0 : return ret;
218 : }
219 :
220 0 : ret = dp_register_sbus_interface(conn, dp_cli);
221 0 : if (ret != EOK) {
222 : /* Connection is closed in the caller. */
223 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register D-Bus interface, "
224 : "killing connection [%d]: %s\n", ret, sss_strerror(ret));
225 0 : return ret;
226 : }
227 :
228 0 : return ret;
229 : }
230 :
231 : struct data_provider *
232 0 : dp_client_provider(struct dp_client *dp_cli)
233 : {
234 0 : if (dp_cli == NULL) {
235 0 : return NULL;
236 : }
237 :
238 0 : return dp_cli->provider;
239 : }
240 :
241 : struct be_ctx *
242 0 : dp_client_be(struct dp_client *dp_cli)
243 : {
244 0 : if (dp_cli == NULL || dp_cli->provider == NULL) {
245 0 : return NULL;
246 : }
247 :
248 0 : return dp_cli->provider->be_ctx;
249 : }
250 :
251 : struct sbus_connection *
252 0 : dp_client_conn(struct dp_client *dp_cli)
253 : {
254 0 : if (dp_cli == NULL) {
255 0 : return NULL;
256 : }
257 :
258 0 : return dp_cli->conn;
259 : }
|