Line data Source code
1 : /*
2 : SSSD
3 :
4 : proxy_init.c
5 :
6 : Authors:
7 : Stephen Gallagher <sgallagh@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 "config.h"
26 :
27 : #include "util/sss_format.h"
28 : #include "providers/proxy/proxy.h"
29 :
30 : #define NSS_FN_NAME "_nss_%s_%s"
31 :
32 : #define ERROR_INITGR "The '%s' library does not provides the " \
33 : "_nss_XXX_initgroups_dyn function!\n" \
34 : "initgroups will be slow as it will require " \
35 : "full groups enumeration!\n"
36 : #define ERROR_NETGR "The '%s' library does not support netgroups.\n"
37 : #define ERROR_SERV "The '%s' library does not support services.\n"
38 :
39 0 : static void *proxy_dlsym(void *handle,
40 : const char *name,
41 : const char *libname)
42 : {
43 : char *funcname;
44 : void *funcptr;
45 :
46 0 : funcname = talloc_asprintf(NULL, NSS_FN_NAME, libname, name);
47 0 : if (funcname == NULL) {
48 0 : return NULL;
49 : }
50 :
51 0 : funcptr = dlsym(handle, funcname);
52 0 : talloc_free(funcname);
53 :
54 0 : return funcptr;
55 : }
56 :
57 0 : static errno_t proxy_id_conf(TALLOC_CTX *mem_ctx,
58 : struct be_ctx *be_ctx,
59 : char **_libname,
60 : char **_libpath,
61 : bool *_fast_alias)
62 : {
63 : TALLOC_CTX *tmp_ctx;
64 : char *libname;
65 : char *libpath;
66 : bool fast_alias;
67 : errno_t ret;
68 :
69 0 : tmp_ctx = talloc_new(NULL);
70 0 : if (tmp_ctx == NULL) {
71 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
72 0 : return ENOMEM;
73 : }
74 :
75 0 : ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
76 : CONFDB_PROXY_LIBNAME, NULL, &libname);
77 0 : if (ret != EOK) {
78 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n",
79 : ret, sss_strerror(ret));
80 0 : goto done;
81 0 : } else if (libname == NULL) {
82 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No library name given\n");
83 0 : ret = ENOENT;
84 0 : goto done;
85 : }
86 :
87 0 : ret = confdb_get_bool(be_ctx->cdb, be_ctx->conf_path,
88 : CONFDB_PROXY_FAST_ALIAS, false, &fast_alias);
89 0 : if (ret != EOK) {
90 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n",
91 : ret, sss_strerror(ret));
92 0 : goto done;
93 : }
94 :
95 0 : libpath = talloc_asprintf(tmp_ctx, "libnss_%s.so.2", libname);
96 0 : if (libpath == NULL) {
97 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
98 0 : ret = ENOMEM;
99 0 : goto done;
100 : }
101 :
102 0 : *_libname = talloc_steal(mem_ctx, libname);
103 0 : *_libpath = talloc_steal(mem_ctx, libpath);
104 0 : *_fast_alias = fast_alias;
105 :
106 0 : ret = EOK;
107 :
108 : done:
109 0 : talloc_free(tmp_ctx);
110 :
111 0 : return ret;
112 : }
113 :
114 0 : static errno_t proxy_id_load_symbols(struct proxy_nss_ops *ops,
115 : const char *libname,
116 : void *handle)
117 : {
118 : int i;
119 : struct {void **dest;
120 : const char *name;
121 : const char *custom_error;
122 : bool is_fatal;
123 0 : } symbols[] = {
124 0 : {(void**)&ops->getpwnam_r, "getpwnam_r", NULL, true},
125 0 : {(void**)&ops->getpwuid_r, "getpwuid_r", NULL, true},
126 0 : {(void**)&ops->setpwent, "setpwent", NULL, true},
127 0 : {(void**)&ops->getpwent_r, "getpwent_r", NULL, true},
128 0 : {(void**)&ops->endpwent, "endpwent", NULL, true},
129 0 : {(void**)&ops->getgrnam_r, "getgrnam_r", NULL, true},
130 0 : {(void**)&ops->getgrgid_r, "getgrgid_r", NULL, true},
131 0 : {(void**)&ops->setgrent, "setgrent", NULL, true},
132 0 : {(void**)&ops->getgrent_r, "getgrent_r", NULL, true},
133 0 : {(void**)&ops->endgrent, "endgrent", NULL, true},
134 0 : {(void**)&ops->initgroups_dyn, "initgroups_dyn", ERROR_INITGR, false},
135 0 : {(void**)&ops->setnetgrent, "setnetgrent", ERROR_NETGR, false},
136 0 : {(void**)&ops->getnetgrent_r, "getnetgrent_r", ERROR_NETGR, false},
137 0 : {(void**)&ops->endnetgrent, "endnetgrent", ERROR_NETGR, false},
138 0 : {(void**)&ops->getservbyname_r, "getservbyname_r", ERROR_SERV, false},
139 0 : {(void**)&ops->getservbyport_r, "getservbyport_r", ERROR_SERV, false},
140 0 : {(void**)&ops->setservent, "setservent", ERROR_SERV, false},
141 0 : {(void**)&ops->getservent_r, "getservent_r", ERROR_SERV, false},
142 0 : {(void**)&ops->endservent, "endservent", ERROR_SERV, false},
143 : {NULL, NULL, NULL, false}
144 : };
145 :
146 0 : for (i = 0; symbols[i].dest != NULL; i++) {
147 0 : *symbols[i].dest = proxy_dlsym(handle, symbols[i].name, libname);
148 0 : if (*symbols[i].dest == NULL) {
149 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load _nss_%s_%s, "
150 : "error: %s.\n", libname, symbols[i].name, dlerror());
151 :
152 0 : if (symbols[i].custom_error != NULL) {
153 0 : DEBUG(SSSDBG_CRIT_FAILURE, symbols[i].custom_error, libname);
154 : }
155 :
156 0 : if (symbols[i].is_fatal) {
157 0 : return ELIBBAD;
158 : }
159 : }
160 : }
161 :
162 0 : return EOK;
163 : }
164 :
165 0 : static errno_t proxy_setup_sbus(TALLOC_CTX *mem_ctx,
166 : struct proxy_auth_ctx *ctx,
167 : struct be_ctx *be_ctx)
168 : {
169 : char *sbus_address;
170 : errno_t ret;
171 :
172 0 : sbus_address = talloc_asprintf(mem_ctx, "unix:path=%s/%s_%s", PIPE_PATH,
173 0 : PROXY_CHILD_PIPE, be_ctx->domain->name);
174 0 : if (sbus_address == NULL) {
175 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed.\n");
176 0 : return ENOMEM;
177 : }
178 :
179 0 : ret = sbus_new_server(mem_ctx, be_ctx->ev, sbus_address, 0, be_ctx->gid,
180 : false, &ctx->sbus_srv, proxy_client_init, ctx);
181 0 : talloc_free(sbus_address);
182 0 : if (ret != EOK) {
183 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
184 0 : return ret;
185 : }
186 :
187 0 : return EOK;
188 : }
189 :
190 0 : static errno_t proxy_auth_conf(TALLOC_CTX *mem_ctx,
191 : struct be_ctx *be_ctx,
192 : char **_pam_target)
193 : {
194 : char *pam_target;
195 : errno_t ret;
196 :
197 0 : ret = confdb_get_string(be_ctx->cdb, mem_ctx, be_ctx->conf_path,
198 : CONFDB_PROXY_PAM_TARGET, NULL, &pam_target);
199 0 : if (ret != EOK) {
200 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n",
201 : ret, sss_strerror(ret));
202 0 : return ret;
203 : }
204 :
205 0 : if (pam_target == NULL) {
206 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing option %s.\n",
207 : CONFDB_PROXY_PAM_TARGET);
208 0 : return EINVAL;
209 : }
210 :
211 0 : *_pam_target = pam_target;
212 :
213 0 : return EOK;
214 : }
215 :
216 0 : static errno_t proxy_init_auth_ctx(TALLOC_CTX *mem_ctx,
217 : struct be_ctx *be_ctx,
218 : struct proxy_auth_ctx **_auth_ctx)
219 : {
220 : struct proxy_auth_ctx *auth_ctx;
221 : errno_t ret;
222 : int hret;
223 :
224 0 : auth_ctx = talloc_zero(mem_ctx, struct proxy_auth_ctx);
225 0 : if (auth_ctx == NULL) {
226 0 : return ENOMEM;
227 : }
228 :
229 0 : auth_ctx->be = be_ctx;
230 0 : auth_ctx->timeout_ms = SSS_CLI_SOCKET_TIMEOUT / 4;
231 0 : auth_ctx->next_id = 1;
232 :
233 0 : ret = proxy_auth_conf(auth_ctx, be_ctx, &auth_ctx->pam_target);
234 0 : if (ret != EOK) {
235 0 : goto done;
236 : }
237 :
238 0 : ret = proxy_setup_sbus(auth_ctx, auth_ctx, be_ctx);
239 0 : if (ret != EOK) {
240 0 : goto done;
241 : }
242 :
243 : /* Set up request hash table */
244 : /* FIXME: get max_children from configuration file */
245 0 : auth_ctx->max_children = 10;
246 :
247 0 : hret = hash_create(auth_ctx->max_children * 2, &auth_ctx->request_table,
248 : NULL, NULL);
249 0 : if (hret != HASH_SUCCESS) {
250 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize request table\n");
251 0 : ret = EIO;
252 0 : goto done;
253 : }
254 :
255 0 : *_auth_ctx = auth_ctx;
256 :
257 0 : ret = EOK;
258 :
259 : done:
260 0 : if (ret != EOK) {
261 0 : talloc_free(auth_ctx);
262 : }
263 :
264 0 : return ret;
265 : }
266 :
267 0 : errno_t sssm_proxy_init(TALLOC_CTX *mem_ctx,
268 : struct be_ctx *be_ctx,
269 : struct data_provider *provider,
270 : const char *module_name,
271 : void **_module_data)
272 : {
273 : struct proxy_auth_ctx *auth_ctx;
274 : errno_t ret;
275 :
276 0 : if (!dp_target_enabled(provider, module_name,
277 : DPT_ACCESS, DPT_AUTH, DPT_CHPASS)) {
278 0 : return EOK;
279 : }
280 :
281 : /* Initialize auth_ctx since one of the access, auth or chpass is set. */
282 :
283 0 : ret = proxy_init_auth_ctx(mem_ctx, be_ctx, &auth_ctx);
284 0 : if (ret != EOK) {
285 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create auth context [%d]: %s\n",
286 : ret, sss_strerror(ret));
287 0 : return ret;
288 : }
289 :
290 0 : *_module_data = auth_ctx;
291 :
292 0 : return EOK;
293 : }
294 :
295 0 : errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
296 : struct be_ctx *be_ctx,
297 : void *module_data,
298 : struct dp_method *dp_methods)
299 : {
300 : struct proxy_id_ctx *ctx;
301 : char *libname;
302 : char *libpath;
303 : errno_t ret;
304 :
305 0 : ctx = talloc_zero(mem_ctx, struct proxy_id_ctx);
306 0 : if (ctx == NULL) {
307 0 : return ENOMEM;
308 : }
309 :
310 0 : ctx->be = be_ctx;
311 :
312 0 : ret = proxy_id_conf(ctx, be_ctx, &libname, &libpath, &ctx->fast_alias);
313 0 : if (ret != EOK) {
314 0 : goto done;
315 : }
316 :
317 0 : ctx->handle = dlopen(libpath, RTLD_NOW);
318 0 : if (ctx->handle == NULL) {
319 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load %s module, "
320 : "error: %s\n", libpath, dlerror());
321 0 : ret = ELIBACC;
322 0 : goto done;
323 : }
324 :
325 0 : ret = proxy_id_load_symbols(&ctx->ops, libname, ctx->handle);
326 0 : if (ret != EOK) {
327 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n",
328 : ret, sss_strerror(ret));
329 0 : goto done;
330 : }
331 :
332 0 : dp_set_method(dp_methods, DPM_ACCOUNT_HANDLER,
333 : proxy_account_info_handler_send, proxy_account_info_handler_recv, ctx,
334 : struct proxy_id_ctx, struct be_acct_req, struct dp_reply_std);
335 :
336 0 : ret = EOK;
337 :
338 : done:
339 0 : if (ret != EOK) {
340 0 : talloc_free(ctx);
341 : }
342 :
343 0 : return ret;
344 : }
345 :
346 0 : errno_t sssm_proxy_auth_init(TALLOC_CTX *mem_ctx,
347 : struct be_ctx *be_ctx,
348 : void *module_data,
349 : struct dp_method *dp_methods)
350 : {
351 : struct proxy_auth_ctx *auth_ctx;
352 :
353 0 : auth_ctx = talloc_get_type(module_data, struct proxy_auth_ctx);
354 :
355 0 : dp_set_method(dp_methods, DPM_AUTH_HANDLER,
356 : proxy_pam_handler_send, proxy_pam_handler_recv, auth_ctx,
357 : struct proxy_auth_ctx, struct pam_data, struct pam_data *);
358 :
359 0 : return EOK;
360 : }
361 :
362 0 : errno_t sssm_proxy_chpass_init(TALLOC_CTX *mem_ctx,
363 : struct be_ctx *be_ctx,
364 : void *module_data,
365 : struct dp_method *dp_methods)
366 : {
367 0 : return sssm_proxy_auth_init(mem_ctx, be_ctx, module_data, dp_methods);
368 : }
369 :
370 0 : errno_t sssm_proxy_access_init(TALLOC_CTX *mem_ctx,
371 : struct be_ctx *be_ctx,
372 : void *module_data,
373 : struct dp_method *dp_methods)
374 : {
375 : struct proxy_auth_ctx *auth_ctx;
376 :
377 0 : auth_ctx = talloc_get_type(module_data, struct proxy_auth_ctx);
378 :
379 0 : dp_set_method(dp_methods, DPM_ACCESS_HANDLER,
380 : proxy_pam_handler_send, proxy_pam_handler_recv, auth_ctx,
381 : struct proxy_auth_ctx, struct pam_data, struct pam_data *);
382 :
383 0 : return EOK;
384 : }
|