Line data Source code
1 : /*
2 : SSSD
3 :
4 : PAM Responder
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
7 : Copyright (C) Sumit Bose <sbose@redhat.com> 2009
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 "db/sysdb.h"
38 : #include "confdb/confdb.h"
39 : #include "sbus/sssd_dbus.h"
40 : #include "responder/common/responder_packet.h"
41 : #include "providers/data_provider.h"
42 : #include "monitor/monitor_interfaces.h"
43 : #include "sbus/sbus_client.h"
44 : #include "responder/pam/pamsrv.h"
45 : #include "responder/common/negcache.h"
46 : #include "responder/common/responder_sbus.h"
47 :
48 : #define DEFAULT_PAM_FD_LIMIT 8192
49 : #define ALL_UIDS_ALLOWED "all"
50 : #define ALL_DOMAIMS_ARE_PUBLIC "all"
51 : #define NO_DOMAIMS_ARE_PUBLIC "none"
52 : #define DEFAULT_ALLOWED_UIDS ALL_UIDS_ALLOWED
53 : #define DEFAULT_PAM_CERT_AUTH false
54 : #define DEFAULT_PAM_CERT_DB_PATH SYSCONFDIR"/pki/nssdb"
55 :
56 : struct mon_cli_iface monitor_pam_methods = {
57 : { &mon_cli_iface_meta, 0 },
58 : .ping = monitor_common_pong,
59 : .resInit = monitor_common_res_init,
60 : .shutDown = NULL,
61 : .goOffline = NULL,
62 : .resetOffline = NULL,
63 : .rotateLogs = responder_logrotate,
64 : .clearMemcache = NULL,
65 : .clearEnumCache = NULL,
66 : .sysbusReconnect = NULL,
67 : };
68 :
69 : static struct data_provider_iface pam_dp_methods = {
70 : { &data_provider_iface_meta, 0 },
71 : .RegisterService = NULL,
72 : .pamHandler = NULL,
73 : .sudoHandler = NULL,
74 : .autofsHandler = NULL,
75 : .hostHandler = NULL,
76 : .getDomains = NULL,
77 : .getAccountInfo = NULL,
78 : };
79 :
80 0 : static void pam_dp_reconnect_init(struct sbus_connection *conn, int status, void *pvt)
81 : {
82 0 : struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn);
83 : int ret;
84 :
85 : /* Did we reconnect successfully? */
86 0 : if (status == SBUS_RECONNECT_SUCCESS) {
87 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Reconnected to the Data Provider.\n");
88 :
89 : /* Identify ourselves to the data provider */
90 0 : ret = dp_common_send_id(be_conn->conn,
91 : DATA_PROVIDER_VERSION,
92 : "PAM");
93 : /* all fine */
94 0 : if (ret == EOK) {
95 0 : handle_requests_after_reconnect(be_conn->rctx);
96 0 : return;
97 : }
98 : }
99 :
100 : /* Handle failure */
101 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not reconnect to %s provider.\n",
102 : be_conn->domain->name);
103 :
104 : /* FIXME: kill the frontend and let the monitor restart it ? */
105 : /* pam_shutdown(rctx); */
106 : }
107 :
108 0 : static errno_t get_trusted_uids(struct pam_ctx *pctx)
109 : {
110 : char *uid_str;
111 : errno_t ret;
112 :
113 0 : ret = confdb_get_string(pctx->rctx->cdb, pctx->rctx,
114 : CONFDB_PAM_CONF_ENTRY, CONFDB_PAM_TRUSTED_USERS,
115 : DEFAULT_ALLOWED_UIDS, &uid_str);
116 0 : if (ret != EOK) {
117 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get allowed UIDs.\n");
118 0 : goto done;
119 : }
120 :
121 0 : if (strcmp(uid_str, ALL_UIDS_ALLOWED) == 0) {
122 0 : DEBUG(SSSDBG_TRACE_FUNC, "All UIDs are allowed.\n");
123 0 : pctx->trusted_uids_count = 0;
124 : } else {
125 0 : ret = csv_string_to_uid_array(pctx->rctx, uid_str, true,
126 : &pctx->trusted_uids_count,
127 : &pctx->trusted_uids);
128 : }
129 :
130 0 : talloc_free(uid_str);
131 0 : if (ret != EOK) {
132 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set allowed UIDs.\n");
133 0 : goto done;
134 : }
135 :
136 : done:
137 0 : return ret;
138 : }
139 :
140 0 : static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx)
141 : {
142 0 : char *domains_str = NULL;
143 : errno_t ret;
144 :
145 0 : ret = confdb_get_string(pctx->rctx->cdb, pctx->rctx,
146 : CONFDB_PAM_CONF_ENTRY, CONFDB_PAM_PUBLIC_DOMAINS,
147 : NO_DOMAIMS_ARE_PUBLIC, &domains_str);
148 0 : if (ret != EOK) {
149 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get allowed UIDs.\n");
150 0 : goto done;
151 : }
152 :
153 0 : if (strcmp(domains_str, ALL_DOMAIMS_ARE_PUBLIC) == 0) { /* all */
154 : /* copy all domains */
155 0 : ret = get_dom_names(mem_ctx,
156 0 : pctx->rctx->domains,
157 : &pctx->public_domains,
158 : &pctx->public_domains_count);
159 0 : if (ret != EOK) {
160 0 : DEBUG(SSSDBG_FATAL_FAILURE, "get_dom_names failed.\n");
161 0 : goto done;
162 : }
163 0 : } else if (strcmp(domains_str, NO_DOMAIMS_ARE_PUBLIC) == 0) { /* none */
164 0 : pctx->public_domains = NULL;
165 0 : pctx->public_domains_count = 0;
166 : } else {
167 0 : ret = split_on_separator(mem_ctx, domains_str, ',', true, false,
168 : &pctx->public_domains,
169 : &pctx->public_domains_count);
170 0 : if (ret != EOK) {
171 0 : DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed [%d][%s].\n",
172 : ret, strerror(ret));
173 0 : goto done;
174 : }
175 : }
176 :
177 0 : ret = EOK;
178 :
179 : done:
180 0 : talloc_free(domains_str);
181 0 : return ret;
182 : }
183 :
184 0 : static int pam_process_init(TALLOC_CTX *mem_ctx,
185 : struct tevent_context *ev,
186 : struct confdb_ctx *cdb,
187 : int pipe_fd, int priv_pipe_fd)
188 : {
189 : struct resp_ctx *rctx;
190 : struct sss_cmd_table *pam_cmds;
191 : struct be_conn *iter;
192 : struct pam_ctx *pctx;
193 : int ret, max_retries;
194 : int id_timeout;
195 : int fd_limit;
196 :
197 0 : pam_cmds = get_pam_cmds();
198 0 : ret = sss_process_init(mem_ctx, ev, cdb,
199 : pam_cmds,
200 : SSS_PAM_SOCKET_NAME, pipe_fd,
201 : SSS_PAM_PRIV_SOCKET_NAME, priv_pipe_fd,
202 : CONFDB_PAM_CONF_ENTRY,
203 : SSS_PAM_SBUS_SERVICE_NAME,
204 : SSS_PAM_SBUS_SERVICE_VERSION,
205 : &monitor_pam_methods,
206 : "PAM", &pam_dp_methods.vtable,
207 : &rctx);
208 0 : if (ret != EOK) {
209 0 : DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
210 0 : return ret;
211 : }
212 :
213 0 : pctx = talloc_zero(rctx, struct pam_ctx);
214 0 : if (!pctx) {
215 0 : ret = ENOMEM;
216 0 : goto done;
217 : }
218 :
219 0 : pctx->rctx = rctx;
220 0 : pctx->rctx->pvt_ctx = pctx;
221 :
222 0 : ret = get_trusted_uids(pctx);
223 0 : if (ret != EOK) {
224 0 : DEBUG(SSSDBG_FATAL_FAILURE, "get_trusted_uids failed: %d:[%s].\n",
225 : ret, sss_strerror(ret));
226 0 : goto done;
227 : }
228 :
229 0 : ret = get_public_domains(pctx, pctx);
230 0 : if (ret != EOK) {
231 0 : DEBUG(SSSDBG_FATAL_FAILURE, "get_public_domains failed: %d:[%s].\n",
232 : ret, sss_strerror(ret));
233 0 : goto done;
234 : }
235 :
236 : /* Enable automatic reconnection to the Data Provider */
237 :
238 : /* FIXME: "retries" is too generic, either get it from a global config
239 : * or specify these retries are about the sbus connections to DP */
240 0 : ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
241 : CONFDB_SERVICE_RECON_RETRIES, 3, &max_retries);
242 0 : if (ret != EOK) {
243 0 : DEBUG(SSSDBG_FATAL_FAILURE,
244 : "Failed to set up automatic reconnection\n");
245 0 : goto done;
246 : }
247 :
248 0 : for (iter = pctx->rctx->be_conns; iter; iter = iter->next) {
249 0 : sbus_reconnect_init(iter->conn, max_retries,
250 : pam_dp_reconnect_init, iter);
251 : }
252 :
253 : /* Set up the negative cache */
254 0 : ret = confdb_get_int(cdb, CONFDB_NSS_CONF_ENTRY,
255 : CONFDB_NSS_ENTRY_NEG_TIMEOUT, 15,
256 : &pctx->neg_timeout);
257 0 : if (ret != EOK) goto done;
258 :
259 : /* Set up the PAM identity timeout */
260 0 : ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
261 : CONFDB_PAM_ID_TIMEOUT, 5,
262 : &id_timeout);
263 0 : if (ret != EOK) goto done;
264 :
265 0 : pctx->id_timeout = (size_t)id_timeout;
266 :
267 0 : ret = sss_ncache_init(pctx, &pctx->ncache);
268 0 : if (ret != EOK) {
269 0 : DEBUG(SSSDBG_FATAL_FAILURE,
270 : "fatal error initializing negative cache\n");
271 0 : goto done;
272 : }
273 :
274 0 : ret = sss_ncache_prepopulate(pctx->ncache, cdb, pctx->rctx);
275 0 : if (ret != EOK) {
276 0 : goto done;
277 : }
278 :
279 : /* Create table for initgroup lookups */
280 0 : ret = sss_hash_create(pctx, 10, &pctx->id_table);
281 0 : if (ret != EOK) {
282 0 : DEBUG(SSSDBG_FATAL_FAILURE,
283 : "Could not create initgroups hash table: [%s]\n",
284 : strerror(ret));
285 0 : goto done;
286 : }
287 :
288 : /* Set up file descriptor limits */
289 0 : ret = confdb_get_int(pctx->rctx->cdb,
290 : CONFDB_PAM_CONF_ENTRY,
291 : CONFDB_SERVICE_FD_LIMIT,
292 : DEFAULT_PAM_FD_LIMIT,
293 : &fd_limit);
294 0 : if (ret != EOK) {
295 0 : DEBUG(SSSDBG_FATAL_FAILURE,
296 : "Failed to set up file descriptor limit\n");
297 0 : goto done;
298 : }
299 0 : responder_set_fd_limit(fd_limit);
300 :
301 0 : ret = schedule_get_domains_task(rctx, rctx->ev, rctx, pctx->ncache);
302 0 : if (ret != EOK) {
303 0 : DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
304 0 : goto done;
305 : }
306 :
307 : /* Check if certificate based authentication is enabled */
308 0 : ret = confdb_get_bool(pctx->rctx->cdb,
309 : CONFDB_PAM_CONF_ENTRY,
310 : CONFDB_PAM_CERT_AUTH,
311 : DEFAULT_PAM_CERT_AUTH,
312 : &pctx->cert_auth);
313 0 : if (ret != EOK) {
314 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to determine get cert db path.\n");
315 0 : goto done;
316 : }
317 :
318 0 : pctx->p11_child_debug_fd = -1;
319 0 : if (pctx->cert_auth) {
320 0 : ret = p11_child_init(pctx);
321 0 : if (ret != EOK) {
322 0 : DEBUG(SSSDBG_FATAL_FAILURE, "p11_child_init failed.\n");
323 0 : goto done;
324 : }
325 :
326 0 : ret = confdb_get_string(pctx->rctx->cdb, pctx,
327 : CONFDB_PAM_CONF_ENTRY,
328 : CONFDB_PAM_CERT_DB_PATH,
329 : DEFAULT_PAM_CERT_DB_PATH,
330 : &pctx->nss_db);
331 0 : if (ret != EOK) {
332 0 : DEBUG(SSSDBG_FATAL_FAILURE,
333 : "Failed to determine if certificate based authentication is " \
334 : "enabled or not.\n");
335 0 : goto done;
336 : }
337 : }
338 :
339 0 : ret = EOK;
340 :
341 : done:
342 0 : if (ret != EOK) {
343 0 : talloc_free(rctx);
344 : }
345 0 : return ret;
346 : }
347 :
348 0 : int main(int argc, const char *argv[])
349 : {
350 : int opt;
351 : poptContext pc;
352 : struct main_context *main_ctx;
353 : int ret;
354 : uid_t uid;
355 : gid_t gid;
356 : int pipe_fd;
357 : int priv_pipe_fd;
358 :
359 0 : struct poptOption long_options[] = {
360 : POPT_AUTOHELP
361 0 : SSSD_MAIN_OPTS
362 0 : SSSD_SERVER_OPTS(uid, gid)
363 : POPT_TABLEEND
364 : };
365 :
366 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
367 0 : debug_level = SSSDBG_INVALID;
368 :
369 0 : umask(DFL_RSP_UMASK);
370 :
371 0 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
372 0 : while((opt = poptGetNextOpt(pc)) != -1) {
373 : switch(opt) {
374 : default:
375 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
376 : poptBadOption(pc, 0), poptStrerror(opt));
377 0 : poptPrintUsage(pc, stderr, 0);
378 0 : return 1;
379 : }
380 : }
381 :
382 0 : poptFreeContext(pc);
383 :
384 0 : DEBUG_INIT(debug_level);
385 :
386 : /* set up things like debug, signals, daemonization, etc... */
387 0 : debug_log_file = "sssd_pam";
388 :
389 : /* Crate pipe file descriptors here before privileges are dropped
390 : * in server_setup() */
391 0 : ret = create_pipe_fd(SSS_PAM_SOCKET_NAME, &pipe_fd, SCKT_RSP_UMASK);
392 0 : if (ret != EOK) {
393 0 : DEBUG(SSSDBG_FATAL_FAILURE,
394 : "create_pipe_fd failed [%d]: %s.\n",
395 : ret, sss_strerror(ret));
396 0 : return 2;
397 : }
398 :
399 0 : ret = create_pipe_fd(SSS_PAM_PRIV_SOCKET_NAME, &priv_pipe_fd,
400 : DFL_RSP_UMASK);
401 0 : if (ret != EOK) {
402 0 : DEBUG(SSSDBG_FATAL_FAILURE,
403 : "create_pipe_fd failed (priviledged pipe) [%d]: %s.\n",
404 : ret, sss_strerror(ret));
405 0 : return 2;
406 : }
407 :
408 0 : ret = server_setup("sssd[pam]", 0, uid, gid, CONFDB_PAM_CONF_ENTRY, &main_ctx);
409 0 : if (ret != EOK) return 2;
410 :
411 0 : ret = die_if_parent_died();
412 0 : if (ret != EOK) {
413 : /* This is not fatal, don't return */
414 0 : DEBUG(SSSDBG_OP_FAILURE,
415 : "Could not set up to exit when parent process does\n");
416 : }
417 :
418 0 : ret = pam_process_init(main_ctx,
419 0 : main_ctx->event_ctx,
420 0 : main_ctx->confdb_ctx,
421 : pipe_fd, priv_pipe_fd);
422 0 : if (ret != EOK) return 3;
423 :
424 : /* loop on main */
425 0 : server_loop(main_ctx);
426 :
427 0 : return 0;
428 : }
429 :
|