"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.4.2/src/responder/pam/pamsrv.c" (19 Feb 2021, 16681 Bytes) of package /linux/misc/sssd-2.4.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pamsrv.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.1_vs_2.4.2.

    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 "config.h"
   37 #include "util/util.h"
   38 #include "db/sysdb.h"
   39 #include "confdb/confdb.h"
   40 #include "responder/common/responder_packet.h"
   41 #include "providers/data_provider.h"
   42 #include "responder/pam/pamsrv.h"
   43 #include "responder/common/negcache.h"
   44 #include "sss_iface/sss_iface_async.h"
   45 
   46 #define DEFAULT_PAM_FD_LIMIT 8192
   47 #define ALL_UIDS_ALLOWED "all"
   48 #define ALL_DOMAINS_ARE_PUBLIC "all"
   49 #define NO_DOMAINS_ARE_PUBLIC "none"
   50 #define DEFAULT_ALLOWED_UIDS ALL_UIDS_ALLOWED
   51 #define DEFAULT_PAM_CERT_AUTH false
   52 #define DEFAULT_PAM_CERT_DB_PATH SYSCONFDIR"/sssd/pki/sssd_auth_ca_db.pem"
   53 #define DEFAULT_PAM_INITGROUPS_SCHEME "no_session"
   54 
   55 static errno_t get_trusted_uids(struct pam_ctx *pctx)
   56 {
   57     char *uid_str;
   58     errno_t ret;
   59 
   60     ret = confdb_get_string(pctx->rctx->cdb, pctx->rctx,
   61                             CONFDB_PAM_CONF_ENTRY, CONFDB_PAM_TRUSTED_USERS,
   62                             DEFAULT_ALLOWED_UIDS, &uid_str);
   63     if (ret != EOK) {
   64         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get allowed UIDs.\n");
   65         goto done;
   66     }
   67 
   68     if (strcmp(uid_str, ALL_UIDS_ALLOWED) == 0) {
   69          DEBUG(SSSDBG_TRACE_FUNC, "All UIDs are allowed.\n");
   70          pctx->trusted_uids_count = 0;
   71     } else {
   72         ret = csv_string_to_uid_array(pctx->rctx, uid_str, true,
   73                                       &pctx->trusted_uids_count,
   74                                       &pctx->trusted_uids);
   75     }
   76 
   77     talloc_free(uid_str);
   78     if (ret != EOK) {
   79         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set allowed UIDs.\n");
   80         goto done;
   81     }
   82 
   83 done:
   84     return ret;
   85 }
   86 
   87 static errno_t get_public_domains(struct pam_ctx *pctx)
   88 {
   89     char *domains_str = NULL;
   90     errno_t ret;
   91 
   92     ret = confdb_get_string(pctx->rctx->cdb, pctx->rctx,
   93                             CONFDB_PAM_CONF_ENTRY, CONFDB_PAM_PUBLIC_DOMAINS,
   94                             NO_DOMAINS_ARE_PUBLIC, &domains_str);
   95     if (ret != EOK) {
   96         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get allowed UIDs.\n");
   97         goto done;
   98     }
   99 
  100     if (strcmp(domains_str, ALL_DOMAINS_ARE_PUBLIC) == 0) { /* all */
  101         /* copy all domains */
  102         ret = get_dom_names(pctx,
  103                             pctx->rctx->domains,
  104                             &pctx->public_domains,
  105                             &pctx->public_domains_count);
  106         if (ret != EOK) {
  107             DEBUG(SSSDBG_FATAL_FAILURE, "get_dom_names failed.\n");
  108             goto done;
  109         }
  110     } else if (strcmp(domains_str, NO_DOMAINS_ARE_PUBLIC) == 0) { /* none */
  111         pctx->public_domains = NULL;
  112         pctx->public_domains_count = 0;
  113     } else {
  114         ret = split_on_separator(pctx, domains_str, ',', true, false,
  115                                  &pctx->public_domains,
  116                                  &pctx->public_domains_count);
  117         if (ret != EOK) {
  118             DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed [%d][%s].\n",
  119                   ret, strerror(ret));
  120             goto done;
  121         }
  122     }
  123 
  124     ret = EOK;
  125 
  126 done:
  127     talloc_free(domains_str);
  128     return ret;
  129 }
  130 
  131 static errno_t get_app_services(struct pam_ctx *pctx)
  132 {
  133     errno_t ret;
  134 
  135     ret = confdb_get_string_as_list(pctx->rctx->cdb, pctx,
  136                                     CONFDB_PAM_CONF_ENTRY,
  137                                     CONFDB_PAM_APP_SERVICES,
  138                                     &pctx->app_services);
  139     if (ret == ENOENT) {
  140         pctx->app_services = talloc_zero_array(pctx, char *, 1);
  141         if (pctx->app_services == NULL) {
  142             return ENOMEM;
  143         }
  144         /* Allocating an empty array makes it easier for the consumer
  145          * to iterate over it
  146          */
  147     } else if (ret != EOK) {
  148         DEBUG(SSSDBG_CRIT_FAILURE,
  149               "Cannot read "CONFDB_PAM_APP_SERVICES" [%d]: %s\n",
  150               ret, sss_strerror(ret));
  151         return ret;
  152     }
  153 
  154     return EOK;
  155 }
  156 
  157 static void pam_get_domains_callback(void *pvt)
  158 {
  159     struct pam_ctx *pctx;
  160     int ret;
  161 
  162     pctx = talloc_get_type(pvt, struct pam_ctx);
  163     ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains);
  164     if (ret != EOK) {
  165         DEBUG(SSSDBG_OP_FAILURE, "p11_refresh_certmap_ctx failed.\n");
  166     }
  167 }
  168 
  169 static int pam_process_init(TALLOC_CTX *mem_ctx,
  170                             struct tevent_context *ev,
  171                             struct confdb_ctx *cdb,
  172                             int pipe_fd, int priv_pipe_fd)
  173 {
  174     struct resp_ctx *rctx;
  175     struct sss_cmd_table *pam_cmds;
  176     struct pam_ctx *pctx;
  177     int ret;
  178     int id_timeout;
  179     int fd_limit;
  180     char *tmpstr = NULL;
  181 
  182     pam_cmds = get_pam_cmds();
  183     ret = sss_process_init(mem_ctx, ev, cdb,
  184                            pam_cmds,
  185                            SSS_PAM_SOCKET_NAME, pipe_fd,
  186                            SSS_PAM_PRIV_SOCKET_NAME, priv_pipe_fd,
  187                            CONFDB_PAM_CONF_ENTRY,
  188                            SSS_BUS_PAM, SSS_PAM_SBUS_SERVICE_NAME,
  189                            sss_connection_setup,
  190                            &rctx);
  191     if (ret != EOK) {
  192         DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
  193         return ret;
  194     }
  195 
  196     pctx = talloc_zero(rctx, struct pam_ctx);
  197     if (!pctx) {
  198         ret = ENOMEM;
  199         goto done;
  200     }
  201 
  202     pctx->rctx = rctx;
  203     pctx->rctx->pvt_ctx = pctx;
  204 
  205     ret = get_trusted_uids(pctx);
  206     if (ret != EOK) {
  207         DEBUG(SSSDBG_FATAL_FAILURE, "get_trusted_uids failed: %d:[%s].\n",
  208               ret, sss_strerror(ret));
  209         goto done;
  210     }
  211 
  212     ret = get_public_domains(pctx);
  213     if (ret != EOK) {
  214         DEBUG(SSSDBG_FATAL_FAILURE, "get_public_domains failed: %d:[%s].\n",
  215               ret, sss_strerror(ret));
  216         goto done;
  217     }
  218 
  219     ret = get_app_services(pctx);
  220     if (ret != EOK) {
  221         DEBUG(SSSDBG_FATAL_FAILURE, "get_app_services failed: %d:[%s].\n",
  222               ret, sss_strerror(ret));
  223         goto done;
  224     }
  225 
  226     /* Set up the PAM identity timeout */
  227     ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
  228                          CONFDB_PAM_ID_TIMEOUT, 5,
  229                          &id_timeout);
  230     if (ret != EOK) goto done;
  231 
  232     pctx->id_timeout = (size_t)id_timeout;
  233 
  234     ret = sss_ncache_prepopulate(pctx->rctx->ncache, cdb, pctx->rctx);
  235     if (ret != EOK) {
  236         goto done;
  237     }
  238 
  239     /* Create table for initgroup lookups */
  240     ret = sss_hash_create(pctx, 0, &pctx->id_table);
  241     if (ret != EOK) {
  242         DEBUG(SSSDBG_FATAL_FAILURE,
  243               "Could not create initgroups hash table: [%s]\n",
  244               strerror(ret));
  245         goto done;
  246     }
  247 
  248     /* Set up file descriptor limits */
  249     ret = confdb_get_int(pctx->rctx->cdb,
  250                          CONFDB_PAM_CONF_ENTRY,
  251                          CONFDB_SERVICE_FD_LIMIT,
  252                          DEFAULT_PAM_FD_LIMIT,
  253                          &fd_limit);
  254     if (ret != EOK) {
  255         DEBUG(SSSDBG_FATAL_FAILURE,
  256               "Failed to set up file descriptor limit\n");
  257         goto done;
  258     }
  259     responder_set_fd_limit(fd_limit);
  260 
  261     ret = schedule_get_domains_task(rctx, rctx->ev, rctx, pctx->rctx->ncache,
  262                                     pam_get_domains_callback, pctx);
  263     if (ret != EOK) {
  264         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
  265         goto done;
  266     }
  267 
  268     /* Check if there is a prompting configuration */
  269     pctx->prompting_config_sections = NULL;
  270     pctx->num_prompting_config_sections = 0;
  271     ret = confdb_get_sub_sections(pctx, pctx->rctx->cdb, CONFDB_PC_CONF_ENTRY,
  272                                   &pctx->prompting_config_sections,
  273                                   &pctx->num_prompting_config_sections);
  274     if (ret != EOK && ret != ENOENT) {
  275         DEBUG(SSSDBG_OP_FAILURE, "confdb_get_sub_sections failed, not fatal.\n");
  276     }
  277 
  278     /* Check if certificate based authentication is enabled */
  279     ret = confdb_get_bool(pctx->rctx->cdb,
  280                           CONFDB_PAM_CONF_ENTRY,
  281                           CONFDB_PAM_CERT_AUTH,
  282                           DEFAULT_PAM_CERT_AUTH,
  283                           &pctx->cert_auth);
  284     if (ret != EOK) {
  285         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to determine get cert db path.\n");
  286         goto done;
  287     }
  288 
  289     if (pctx->cert_auth) {
  290         ret = p11_child_init(pctx);
  291         if (ret != EOK) {
  292             DEBUG(SSSDBG_FATAL_FAILURE, "p11_child_init failed.\n");
  293             goto done;
  294         }
  295 
  296         ret = confdb_get_string(pctx->rctx->cdb, pctx,
  297                                 CONFDB_PAM_CONF_ENTRY,
  298                                 CONFDB_PAM_CERT_DB_PATH,
  299                                 DEFAULT_PAM_CERT_DB_PATH,
  300                                 &pctx->ca_db);
  301         if (ret != EOK) {
  302             DEBUG(SSSDBG_FATAL_FAILURE,
  303                   "Failed to determine if certificate based authentication is " \
  304                   "enabled or not.\n");
  305             goto done;
  306         }
  307 
  308     }
  309 
  310     if (pctx->cert_auth || pctx->num_prompting_config_sections != 0) {
  311         ret = create_preauth_indicator();
  312         if (ret != EOK) {
  313             DEBUG(SSSDBG_OP_FAILURE,
  314                   "Failed to create pre-authentication indicator file, "
  315                   "Smartcard authentication or configured prompting might "
  316                   "not work as expected.\n");
  317         }
  318     }
  319 
  320     ret = confdb_get_string(pctx->rctx->cdb, pctx, CONFDB_PAM_CONF_ENTRY,
  321                             CONFDB_PAM_INITGROUPS_SCHEME,
  322                             DEFAULT_PAM_INITGROUPS_SCHEME, &tmpstr);
  323     if (ret != EOK) {
  324         DEBUG(SSSDBG_FATAL_FAILURE,
  325               "Failed to determine initgroups scheme.\n");
  326         goto done;
  327     }
  328     DEBUG(SSSDBG_TRACE_INTERNAL, "Found value [%s] for option [%s].\n", tmpstr,
  329                                  CONFDB_PAM_INITGROUPS_SCHEME);
  330 
  331     if (tmpstr == NULL) {
  332         pctx->initgroups_scheme = PAM_INITGR_NO_SESSION;
  333     } else {
  334         pctx->initgroups_scheme = pam_initgroups_string_to_enum(tmpstr);
  335         if (pctx->initgroups_scheme == PAM_INITGR_INVALID) {
  336             DEBUG(SSSDBG_FATAL_FAILURE, "Unknown value [%s] for option %s.\n",
  337                                         tmpstr, CONFDB_PAM_INITGROUPS_SCHEME);
  338             ret = EINVAL;
  339             goto done;
  340         }
  341     }
  342 
  343     ret = confdb_get_string(pctx->rctx->cdb, pctx, CONFDB_PAM_CONF_ENTRY,
  344                             CONFDB_PAM_GSSAPI_SERVICES, "-", &tmpstr);
  345     if (ret != EOK) {
  346         DEBUG(SSSDBG_FATAL_FAILURE,
  347               "Failed to determine gssapi services.\n");
  348         goto done;
  349     }
  350     DEBUG(SSSDBG_TRACE_INTERNAL, "Found value [%s] for option [%s].\n", tmpstr,
  351                                  CONFDB_PAM_GSSAPI_SERVICES);
  352 
  353     if (tmpstr != NULL) {
  354         ret = split_on_separator(pctx, tmpstr, ',', true, true,
  355                                  &pctx->gssapi_services, NULL);
  356         if (ret != EOK) {
  357             DEBUG(SSSDBG_MINOR_FAILURE,
  358                   "split_on_separator() failed [%d]: [%s].\n", ret,
  359                   sss_strerror(ret));
  360             goto done;
  361         }
  362     }
  363 
  364     ret = confdb_get_bool(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
  365                           CONFDB_PAM_GSSAPI_CHECK_UPN, true,
  366                           &pctx->gssapi_check_upn);
  367     if (ret != EOK) {
  368         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to read %s [%d]: %s\n",
  369               CONFDB_PAM_GSSAPI_CHECK_UPN, ret, sss_strerror(ret));
  370         goto done;
  371     }
  372 
  373     ret = confdb_get_string(pctx->rctx->cdb, pctx, CONFDB_PAM_CONF_ENTRY,
  374                             CONFDB_PAM_GSSAPI_INDICATORS_MAP, "-", &tmpstr);
  375     if (ret != EOK) {
  376         DEBUG(SSSDBG_FATAL_FAILURE,
  377               "Failed to determine gssapi services.\n");
  378         goto done;
  379     }
  380     DEBUG(SSSDBG_TRACE_INTERNAL, "Found value [%s] for option [%s].\n", tmpstr,
  381                                  CONFDB_PAM_GSSAPI_INDICATORS_MAP);
  382 
  383     if (tmpstr != NULL) {
  384         ret = split_on_separator(pctx, tmpstr, ',', true, true,
  385                                  &pctx->gssapi_indicators_map, NULL);
  386         if (ret != EOK) {
  387             DEBUG(SSSDBG_MINOR_FAILURE,
  388                   "split_on_separator() failed [%d]: [%s].\n", ret,
  389                   sss_strerror(ret));
  390             goto done;
  391         }
  392     }
  393 
  394     /* The responder is initialized. Now tell it to the monitor. */
  395     ret = sss_monitor_service_init(rctx, rctx->ev, SSS_BUS_PAM,
  396                                    SSS_PAM_SBUS_SERVICE_NAME,
  397                                    SSS_PAM_SBUS_SERVICE_VERSION,
  398                                    MT_SVC_SERVICE,
  399                                    &rctx->last_request_time, &rctx->mon_conn);
  400     if (ret != EOK) {
  401         DEBUG(SSSDBG_FATAL_FAILURE, "fatal error setting up message bus\n");
  402         goto done;
  403     }
  404 
  405     ret = sss_resp_register_service_iface(rctx);
  406     if (ret != EOK) {
  407         goto done;
  408     }
  409 
  410     ret = EOK;
  411 
  412 done:
  413     if (ret != EOK) {
  414         talloc_free(rctx);
  415     }
  416     return ret;
  417 }
  418 
  419 int main(int argc, const char *argv[])
  420 {
  421     int opt;
  422     poptContext pc;
  423     char *opt_logger = NULL;
  424     struct main_context *main_ctx;
  425     int ret;
  426     uid_t uid;
  427     gid_t gid;
  428     int pipe_fd = -1;
  429     int priv_pipe_fd = -1;
  430 
  431     struct poptOption long_options[] = {
  432         POPT_AUTOHELP
  433         SSSD_MAIN_OPTS
  434         SSSD_LOGGER_OPTS
  435         SSSD_SERVER_OPTS(uid, gid)
  436         SSSD_RESPONDER_OPTS
  437         POPT_TABLEEND
  438     };
  439 
  440     /* Set debug level to invalid value so we can decide if -d 0 was used. */
  441     debug_level = SSSDBG_INVALID;
  442 
  443     umask(DFL_RSP_UMASK);
  444 
  445     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
  446     while((opt = poptGetNextOpt(pc)) != -1) {
  447         switch(opt) {
  448         default:
  449             fprintf(stderr, "\nInvalid option %s: %s\n\n",
  450                              poptBadOption(pc, 0), poptStrerror(opt));
  451             poptPrintUsage(pc, stderr, 0);
  452             return 1;
  453         }
  454     }
  455 
  456     poptFreeContext(pc);
  457 
  458     DEBUG_INIT(debug_level);
  459 
  460     /* set up things like debug, signals, daemonization, etc. */
  461     debug_log_file = "sssd_pam";
  462 
  463     sss_set_logger(opt_logger);
  464 
  465     if (!is_socket_activated()) {
  466         /* Create pipe file descriptors here before privileges are dropped
  467          * in server_setup() */
  468         ret = create_pipe_fd(SSS_PAM_SOCKET_NAME, &pipe_fd, SCKT_RSP_UMASK);
  469         if (ret != EOK) {
  470             DEBUG(SSSDBG_FATAL_FAILURE,
  471                   "create_pipe_fd failed [%d]: %s.\n",
  472                   ret, sss_strerror(ret));
  473             return 2;
  474         }
  475 
  476         ret = create_pipe_fd(SSS_PAM_PRIV_SOCKET_NAME, &priv_pipe_fd,
  477                              DFL_RSP_UMASK);
  478         if (ret != EOK) {
  479             DEBUG(SSSDBG_FATAL_FAILURE,
  480                   "create_pipe_fd failed (privileged pipe) [%d]: %s.\n",
  481                   ret, sss_strerror(ret));
  482             return 2;
  483         }
  484     }
  485 
  486     /* server_setup() might switch to an unprivileged user, so the permissions
  487      * for p11_child.log have to be fixed first. */
  488     ret = chown_debug_file("p11_child", uid, gid);
  489     if (ret != EOK) {
  490         DEBUG(SSSDBG_MINOR_FAILURE,
  491               "Cannot chown the p11_child debug file, "
  492               "debugging might not work!\n");
  493     }
  494 
  495     ret = server_setup("pam", 0, uid, gid, CONFDB_PAM_CONF_ENTRY, &main_ctx);
  496     if (ret != EOK) return 2;
  497 
  498     ret = die_if_parent_died();
  499     if (ret != EOK) {
  500         /* This is not fatal, don't return */
  501         DEBUG(SSSDBG_OP_FAILURE,
  502               "Could not set up to exit when parent process does\n");
  503     }
  504 
  505     ret = pam_process_init(main_ctx,
  506                            main_ctx->event_ctx,
  507                            main_ctx->confdb_ctx,
  508                            pipe_fd, priv_pipe_fd);
  509     if (ret != EOK) return 3;
  510 
  511     /* loop on main */
  512     server_loop(main_ctx);
  513 
  514     return 0;
  515 }
  516