root/daemons/based/based_remote.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. remote_connection_destroy
  2. init_remote_listener
  3. check_group_membership
  4. cib_remote_auth
  5. remote_auth_timeout_cb
  6. cib_remote_listen
  7. cib_remote_connection_destroy
  8. cib_handle_remote_msg
  9. cib_remote_msg
  10. construct_pam_passwd
  11. authenticate_user

   1 /*
   2  * Copyright 2004-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <crm/crm.h>
  12 
  13 #include <sys/param.h>
  14 #include <stdio.h>
  15 #include <sys/types.h>
  16 #include <sys/stat.h>
  17 #include <unistd.h>
  18 #include <inttypes.h>           // PRIx64
  19 #include <sys/socket.h>
  20 #include <arpa/inet.h>
  21 
  22 #include <netinet/ip.h>
  23 
  24 #include <stdlib.h>
  25 #include <errno.h>
  26 
  27 #include <glib.h>
  28 #include <libxml/tree.h>
  29 
  30 #include <crm/common/ipc.h>
  31 #include <crm/common/ipc_internal.h>
  32 #include <crm/common/xml.h>
  33 #include <crm/common/remote_internal.h>
  34 #include <crm/common/tls_internal.h>
  35 #include <crm/cib/internal.h>
  36 
  37 #include "pacemaker-based.h"
  38 
  39 #include <gnutls/gnutls.h>
  40 
  41 #include <pwd.h>
  42 #include <grp.h>
  43 #if HAVE_SECURITY_PAM_APPL_H
  44 #  include <security/pam_appl.h>
  45 #  define HAVE_PAM 1
  46 #elif HAVE_PAM_PAM_APPL_H
  47 #  include <pam/pam_appl.h>
  48 #  define HAVE_PAM 1
  49 #endif
  50 
  51 static pcmk__tls_t *tls = NULL;
  52 
  53 extern int remote_tls_fd;
  54 extern gboolean cib_shutdown_flag;
  55 
  56 int init_remote_listener(int port, gboolean encrypted);
  57 void cib_remote_connection_destroy(gpointer user_data);
  58 
  59 // @TODO This is rather short for someone to type their password
  60 #define REMOTE_AUTH_TIMEOUT 10000
  61 
  62 int num_clients;
  63 static bool authenticate_user(const char *user, const char *passwd);
  64 static int cib_remote_listen(gpointer data);
  65 static int cib_remote_msg(gpointer data);
  66 
  67 static void
  68 remote_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70     crm_info("No longer listening for remote connections");
  71     return;
  72 }
  73 
  74 int
  75 init_remote_listener(int port, gboolean encrypted)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77     int rc;
  78     int *ssock = NULL;
  79     struct sockaddr_in saddr;
  80     int optval;
  81 
  82     static struct mainloop_fd_callbacks remote_listen_fd_callbacks = {
  83         .dispatch = cib_remote_listen,
  84         .destroy = remote_connection_destroy,
  85     };
  86 
  87     if (port <= 0) {
  88         /* don't start it */
  89         return 0;
  90     }
  91 
  92     if (encrypted) {
  93         bool use_cert = pcmk__x509_enabled();
  94 
  95         crm_notice("Starting TLS listener on port %d", port);
  96 
  97         rc = pcmk__init_tls(&tls, true, use_cert ? GNUTLS_CRD_CERTIFICATE : GNUTLS_CRD_ANON);
  98         if (rc != pcmk_rc_ok) {
  99             return -1;
 100         }
 101     } else {
 102         crm_warn("Starting plain-text listener on port %d", port);
 103     }
 104 #ifndef HAVE_PAM
 105     crm_warn("This build does not support remote administrators "
 106              "because PAM support is not available");
 107 #endif
 108 
 109     /* create server socket */
 110     ssock = malloc(sizeof(int));
 111     if(ssock == NULL) {
 112         crm_err("Listener socket allocation failed: %s", pcmk_rc_str(errno));
 113         return -1;
 114     }
 115 
 116     *ssock = socket(AF_INET, SOCK_STREAM, 0);
 117     if (*ssock == -1) {
 118         crm_err("Listener socket creation failed: %s", pcmk_rc_str(errno));
 119         free(ssock);
 120         return -1;
 121     }
 122 
 123     /* reuse address */
 124     optval = 1;
 125     rc = setsockopt(*ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
 126     if (rc < 0) {
 127         crm_err("Local address reuse not allowed on listener socket: %s",
 128                 pcmk_rc_str(errno));
 129     }
 130 
 131     /* bind server socket */
 132     memset(&saddr, '\0', sizeof(saddr));
 133     saddr.sin_family = AF_INET;
 134     saddr.sin_addr.s_addr = INADDR_ANY;
 135     saddr.sin_port = htons(port);
 136     if (bind(*ssock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
 137         crm_err("Cannot bind to listener socket: %s", pcmk_rc_str(errno));
 138         close(*ssock);
 139         free(ssock);
 140         return -2;
 141     }
 142     if (listen(*ssock, 10) == -1) {
 143         crm_err("Cannot listen on socket: %s", pcmk_rc_str(errno));
 144         close(*ssock);
 145         free(ssock);
 146         return -3;
 147     }
 148 
 149     mainloop_add_fd("cib-remote", G_PRIORITY_DEFAULT, *ssock, ssock, &remote_listen_fd_callbacks);
 150     crm_debug("Started listener on port %d", port);
 151 
 152     return *ssock;
 153 }
 154 
 155 static int
 156 check_group_membership(const char *usr, const char *grp)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158     int index = 0;
 159     struct passwd *pwd = NULL;
 160     struct group *group = NULL;
 161 
 162     pwd = getpwnam(usr);
 163     if (pwd == NULL) {
 164         crm_notice("Rejecting remote client: '%s' is not a valid user", usr);
 165         return FALSE;
 166     }
 167 
 168     group = getgrgid(pwd->pw_gid);
 169     if (group != NULL && pcmk__str_eq(grp, group->gr_name, pcmk__str_none)) {
 170         return TRUE;
 171     }
 172 
 173     group = getgrnam(grp);
 174     if (group == NULL) {
 175         crm_err("Rejecting remote client: '%s' is not a valid group", grp);
 176         return FALSE;
 177     }
 178 
 179     while (TRUE) {
 180         char *member = group->gr_mem[index++];
 181 
 182         if (member == NULL) {
 183             break;
 184 
 185         } else if (pcmk__str_eq(usr, member, pcmk__str_none)) {
 186             return TRUE;
 187         }
 188     }
 189 
 190     crm_notice("Rejecting remote client: User '%s' is not a member of "
 191                "group '%s'", usr, grp);
 192     return FALSE;
 193 }
 194 
 195 static gboolean
 196 cib_remote_auth(xmlNode * login)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198     const char *user = NULL;
 199     const char *pass = NULL;
 200     const char *tmp = NULL;
 201 
 202     if (login == NULL) {
 203         return FALSE;
 204     }
 205 
 206     if (!pcmk__xe_is(login, PCMK__XE_CIB_COMMAND)) {
 207         crm_warn("Rejecting remote client: Unrecognizable message "
 208                  "(element '%s' not '" PCMK__XE_CIB_COMMAND "')", login->name);
 209         crm_log_xml_debug(login, "bad");
 210         return FALSE;
 211     }
 212 
 213     tmp = crm_element_value(login, PCMK_XA_OP);
 214     if (!pcmk__str_eq(tmp, "authenticate", pcmk__str_casei)) {
 215         crm_warn("Rejecting remote client: Unrecognizable message "
 216                  "(operation '%s' not 'authenticate')", tmp);
 217         crm_log_xml_debug(login, "bad");
 218         return FALSE;
 219     }
 220 
 221     user = crm_element_value(login, PCMK_XA_USER);
 222     pass = crm_element_value(login, PCMK__XA_PASSWORD);
 223     if (!user || !pass) {
 224         crm_warn("Rejecting remote client: No %s given",
 225                  ((user == NULL)? "username" : "password"));
 226         crm_log_xml_debug(login, "bad");
 227         return FALSE;
 228     }
 229 
 230     crm_log_xml_debug(login, "auth");
 231 
 232     return check_group_membership(user, CRM_DAEMON_GROUP)
 233            && authenticate_user(user, pass);
 234 }
 235 
 236 static gboolean
 237 remote_auth_timeout_cb(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239     pcmk__client_t *client = data;
 240 
 241     client->remote->auth_timeout = 0;
 242 
 243     if (pcmk_is_set(client->flags, pcmk__client_authenticated)) {
 244         return FALSE;
 245     }
 246 
 247     mainloop_del_fd(client->remote->source);
 248     crm_err("Remote client authentication timed out");
 249 
 250     return FALSE;
 251 }
 252 
 253 static int
 254 cib_remote_listen(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 255 {
 256     int csock = 0;
 257     unsigned laddr;
 258     struct sockaddr_storage addr;
 259     char ipstr[INET6_ADDRSTRLEN];
 260     int ssock = *(int *)data;
 261     int rc;
 262 
 263     pcmk__client_t *new_client = NULL;
 264 
 265     static struct mainloop_fd_callbacks remote_client_fd_callbacks = {
 266         .dispatch = cib_remote_msg,
 267         .destroy = cib_remote_connection_destroy,
 268     };
 269 
 270     /* accept the connection */
 271     laddr = sizeof(addr);
 272     memset(&addr, 0, sizeof(addr));
 273     csock = accept(ssock, (struct sockaddr *)&addr, &laddr);
 274     if (csock == -1) {
 275         crm_warn("Could not accept remote connection: %s", pcmk_rc_str(errno));
 276         return TRUE;
 277     }
 278 
 279     pcmk__sockaddr2str(&addr, ipstr);
 280 
 281     rc = pcmk__set_nonblocking(csock);
 282     if (rc != pcmk_rc_ok) {
 283         crm_warn("Dropping remote connection from %s because "
 284                  "it could not be set to non-blocking: %s",
 285                  ipstr, pcmk_rc_str(rc));
 286         close(csock);
 287         return TRUE;
 288     }
 289 
 290     num_clients++;
 291 
 292     new_client = pcmk__new_unauth_client(NULL);
 293     new_client->remote = pcmk__assert_alloc(1, sizeof(pcmk__remote_t));
 294 
 295     if (ssock == remote_tls_fd) {
 296         pcmk__set_client_flags(new_client, pcmk__client_tls);
 297 
 298         /* create gnutls session for the server socket */
 299         new_client->remote->tls_session = pcmk__new_tls_session(tls, csock);
 300         if (new_client->remote->tls_session == NULL) {
 301             close(csock);
 302             return TRUE;
 303         }
 304     } else {
 305         pcmk__set_client_flags(new_client, pcmk__client_tcp);
 306         new_client->remote->tcp_socket = csock;
 307     }
 308 
 309     // Require the client to authenticate within this time
 310     new_client->remote->auth_timeout = pcmk__create_timer(REMOTE_AUTH_TIMEOUT,
 311                                                           remote_auth_timeout_cb,
 312                                                           new_client);
 313     crm_info("%s connection from %s pending authentication for client %s",
 314              ((ssock == remote_tls_fd)? "Encrypted" : "Clear-text"),
 315              ipstr, new_client->id);
 316 
 317     new_client->remote->source =
 318         mainloop_add_fd("cib-remote-client", G_PRIORITY_DEFAULT, csock, new_client,
 319                         &remote_client_fd_callbacks);
 320 
 321     return TRUE;
 322 }
 323 
 324 void
 325 cib_remote_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 326 {
 327     pcmk__client_t *client = user_data;
 328     int csock = 0;
 329 
 330     if (client == NULL) {
 331         return;
 332     }
 333 
 334     crm_trace("Cleaning up after client %s disconnect",
 335               pcmk__client_name(client));
 336 
 337     num_clients--;
 338     crm_trace("Num unfree'd clients: %d", num_clients);
 339 
 340     switch (PCMK__CLIENT_TYPE(client)) {
 341         case pcmk__client_tcp:
 342             csock = client->remote->tcp_socket;
 343             break;
 344         case pcmk__client_tls:
 345             if (client->remote->tls_session) {
 346                 void *sock_ptr = gnutls_transport_get_ptr(client->remote->tls_session);
 347 
 348                 csock = GPOINTER_TO_INT(sock_ptr);
 349                 if (pcmk_is_set(client->flags,
 350                                 pcmk__client_tls_handshake_complete)) {
 351                     gnutls_bye(client->remote->tls_session, GNUTLS_SHUT_WR);
 352                 }
 353                 gnutls_deinit(client->remote->tls_session);
 354                 client->remote->tls_session = NULL;
 355             }
 356             break;
 357         default:
 358             crm_warn("Unknown transport for client %s "
 359                      QB_XS " flags=%#016" PRIx64,
 360                      pcmk__client_name(client), client->flags);
 361     }
 362 
 363     if (csock > 0) {
 364         close(csock);
 365     }
 366 
 367     pcmk__free_client(client);
 368 
 369     crm_trace("Freed the cib client");
 370 
 371     if (cib_shutdown_flag) {
 372         cib_shutdown(0);
 373     }
 374     return;
 375 }
 376 
 377 static void
 378 cib_handle_remote_msg(pcmk__client_t *client, xmlNode *command)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380     if (!pcmk__xe_is(command, PCMK__XE_CIB_COMMAND)) {
 381         crm_log_xml_trace(command, "bad");
 382         return;
 383     }
 384 
 385     if (client->name == NULL) {
 386         client->name = pcmk__str_copy(client->id);
 387     }
 388 
 389     /* unset dangerous options */
 390     pcmk__xe_remove_attr(command, PCMK__XA_SRC);
 391     pcmk__xe_remove_attr(command, PCMK__XA_CIB_HOST);
 392     pcmk__xe_remove_attr(command, PCMK__XA_CIB_UPDATE);
 393 
 394     crm_xml_add(command, PCMK__XA_T, PCMK__VALUE_CIB);
 395     crm_xml_add(command, PCMK__XA_CIB_CLIENTID, client->id);
 396     crm_xml_add(command, PCMK__XA_CIB_CLIENTNAME, client->name);
 397     crm_xml_add(command, PCMK__XA_CIB_USER, client->user);
 398 
 399     if (crm_element_value(command, PCMK__XA_CIB_CALLID) == NULL) {
 400         char *call_uuid = crm_generate_uuid();
 401 
 402         /* fix the command */
 403         crm_xml_add(command, PCMK__XA_CIB_CALLID, call_uuid);
 404         free(call_uuid);
 405     }
 406 
 407     if (crm_element_value(command, PCMK__XA_CIB_CALLOPT) == NULL) {
 408         crm_xml_add_int(command, PCMK__XA_CIB_CALLOPT, 0);
 409     }
 410 
 411     crm_log_xml_trace(command, "Remote command: ");
 412     cib_common_callback_worker(0, 0, command, client, TRUE);
 413 }
 414 
 415 static int
 416 cib_remote_msg(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418     xmlNode *command = NULL;
 419     pcmk__client_t *client = data;
 420     int rc;
 421     const char *client_name = pcmk__client_name(client);
 422 
 423     crm_trace("Remote %s message received for client %s",
 424               pcmk__client_type_str(PCMK__CLIENT_TYPE(client)), client_name);
 425 
 426     if ((PCMK__CLIENT_TYPE(client) == pcmk__client_tls)
 427         && !pcmk_is_set(client->flags, pcmk__client_tls_handshake_complete)) {
 428 
 429         int rc = pcmk__read_handshake_data(client);
 430 
 431         if (rc == EAGAIN) {
 432             /* No more data is available at the moment. Just return for now;
 433              * we'll get invoked again once the client sends more.
 434              */
 435             return 0;
 436         } else if (rc != pcmk_rc_ok) {
 437             return -1;
 438         }
 439 
 440         crm_debug("Completed TLS handshake with remote client %s", client_name);
 441         pcmk__set_client_flags(client, pcmk__client_tls_handshake_complete);
 442         if (client->remote->auth_timeout) {
 443             g_source_remove(client->remote->auth_timeout);
 444         }
 445 
 446         /* Now that the handshake is done, see if any client TLS certificate is
 447          * close to its expiration date and log if so.  If a TLS certificate is not
 448          * in use, this function will just return so we don't need to check for the
 449          * session type here.
 450          */
 451         pcmk__tls_check_cert_expiration(client->remote->tls_session);
 452 
 453         // Require the client to authenticate within this time
 454         client->remote->auth_timeout = pcmk__create_timer(REMOTE_AUTH_TIMEOUT,
 455                                                           remote_auth_timeout_cb,
 456                                                           client);
 457         return 0;
 458     }
 459 
 460     rc = pcmk__read_available_remote_data(client->remote);
 461     switch (rc) {
 462         case pcmk_rc_ok:
 463             break;
 464 
 465         case EAGAIN:
 466             /* We haven't read the whole message yet */
 467             return 0;
 468 
 469         default:
 470             /* Error */
 471             crm_trace("Error reading from remote client: %s", pcmk_rc_str(rc));
 472             return -1;
 473     }
 474 
 475     /* must pass auth before we will process anything else */
 476     if (!pcmk_is_set(client->flags, pcmk__client_authenticated)) {
 477         xmlNode *reg;
 478         const char *user = NULL;
 479 
 480         command = pcmk__remote_message_xml(client->remote);
 481         if (cib_remote_auth(command) == FALSE) {
 482             pcmk__xml_free(command);
 483             return -1;
 484         }
 485 
 486         pcmk__set_client_flags(client, pcmk__client_authenticated);
 487         g_source_remove(client->remote->auth_timeout);
 488         client->remote->auth_timeout = 0;
 489         client->name = crm_element_value_copy(command, PCMK_XA_NAME);
 490 
 491         user = crm_element_value(command, PCMK_XA_USER);
 492         if (user) {
 493             client->user = pcmk__str_copy(user);
 494         }
 495 
 496         crm_notice("Remote connection accepted for authenticated user %s "
 497                    QB_XS " client %s",
 498                    pcmk__s(user, ""), client_name);
 499 
 500         /* send ACK */
 501         reg = pcmk__xe_create(NULL, PCMK__XE_CIB_RESULT);
 502         crm_xml_add(reg, PCMK__XA_CIB_OP, CRM_OP_REGISTER);
 503         crm_xml_add(reg, PCMK__XA_CIB_CLIENTID, client->id);
 504         pcmk__remote_send_xml(client->remote, reg);
 505         pcmk__xml_free(reg);
 506         pcmk__xml_free(command);
 507     }
 508 
 509     command = pcmk__remote_message_xml(client->remote);
 510     if (command != NULL) {
 511         crm_trace("Remote message received from client %s", client_name);
 512         cib_handle_remote_msg(client, command);
 513         pcmk__xml_free(command);
 514     }
 515 
 516     return 0;
 517 }
 518 
 519 #ifdef HAVE_PAM
 520 /*!
 521  * \internal
 522  * \brief Pass remote user's password to PAM
 523  *
 524  * \param[in]  num_msg   Number of entries in \p msg
 525  * \param[in]  msg       Array of PAM messages
 526  * \param[out] response  Where to set response to PAM
 527  * \param[in]  data      User data (the password string)
 528  *
 529  * \return PAM return code (PAM_BUF_ERR for memory errors, PAM_CONV_ERR for all
 530  *         other errors, or PAM_SUCCESS on success)
 531  * \note See pam_conv(3) for more explanation
 532  */
 533 static int
 534 construct_pam_passwd(int num_msg, const struct pam_message **msg,
     /* [previous][next][first][last][top][bottom][index][help] */
 535                      struct pam_response **response, void *data)
 536 {
 537     /* In theory, multiple messages are allowed, but due to OS compatibility
 538      * issues, PAM implementations are recommended to only send one message at a
 539      * time. We can require that here for simplicity.
 540      */
 541     CRM_CHECK((num_msg == 1) && (msg != NULL) && (response != NULL)
 542               && (data != NULL), return PAM_CONV_ERR);
 543 
 544     switch (msg[0]->msg_style) {
 545         case PAM_PROMPT_ECHO_OFF:
 546         case PAM_PROMPT_ECHO_ON:
 547             // Password requested
 548             break;
 549         case PAM_TEXT_INFO:
 550             crm_info("PAM: %s", msg[0]->msg);
 551             data = NULL;
 552             break;
 553         case PAM_ERROR_MSG:
 554             /* In theory we should show msg[0]->msg, but that might
 555              * contain the password, which we don't want in the logs
 556              */
 557             crm_err("PAM reported an error");
 558             data = NULL;
 559             break;
 560         default:
 561             crm_warn("Ignoring PAM message of unrecognized type %d",
 562                      msg[0]->msg_style);
 563             return PAM_CONV_ERR;
 564     }
 565 
 566     *response = calloc(1, sizeof(struct pam_response));
 567     if (*response == NULL) {
 568         return PAM_BUF_ERR;
 569     }
 570     (*response)->resp_retcode = 0;
 571     (*response)->resp = pcmk__str_copy((const char *) data); // Caller will free
 572     return PAM_SUCCESS;
 573 }
 574 #endif
 575 
 576 /*!
 577  * \internal
 578  * \brief Verify the username and password passed for a remote CIB connection
 579  *
 580  * \param[in] user    Username passed for remote CIB connection
 581  * \param[in] passwd  Password passed for remote CIB connection
 582  *
 583  * \return \c true if the username and password are accepted, otherwise \c false
 584  * \note This function rejects all credentials when built without PAM support.
 585  */
 586 static bool
 587 authenticate_user(const char *user, const char *passwd)
     /* [previous][next][first][last][top][bottom][index][help] */
 588 {
 589 #ifdef HAVE_PAM
 590     int rc = 0;
 591     bool pass = false;
 592     const void *p_user = NULL;
 593     struct pam_conv p_conv;
 594     struct pam_handle *pam_h = NULL;
 595 
 596     static const char *pam_name = NULL;
 597 
 598     if (pam_name == NULL) {
 599         pam_name = getenv("CIB_pam_service");
 600         if (pam_name == NULL) {
 601             pam_name = "login";
 602         }
 603     }
 604 
 605     p_conv.conv = construct_pam_passwd;
 606     p_conv.appdata_ptr = (void *) passwd;
 607 
 608     rc = pam_start(pam_name, user, &p_conv, &pam_h);
 609     if (rc != PAM_SUCCESS) {
 610         crm_warn("Rejecting remote client for user %s "
 611                  "because PAM initialization failed: %s",
 612                  user, pam_strerror(pam_h, rc));
 613         goto bail;
 614     }
 615 
 616     // Check user credentials
 617     rc = pam_authenticate(pam_h, PAM_SILENT);
 618     if (rc != PAM_SUCCESS) {
 619         crm_notice("Access for remote user %s denied: %s",
 620                    user, pam_strerror(pam_h, rc));
 621         goto bail;
 622     }
 623 
 624     /* Get the authenticated user name (PAM modules can map the original name to
 625      * something else). Since the CIB manager runs as the daemon user (not
 626      * root), that is the only user that can be successfully authenticated.
 627      */
 628     rc = pam_get_item(pam_h, PAM_USER, &p_user);
 629     if (rc != PAM_SUCCESS) {
 630         crm_warn("Rejecting remote client for user %s "
 631                  "because PAM failed to return final user name: %s",
 632                  user, pam_strerror(pam_h, rc));
 633         goto bail;
 634     }
 635     if (p_user == NULL) {
 636         crm_warn("Rejecting remote client for user %s "
 637                  "because PAM returned no final user name", user);
 638         goto bail;
 639     }
 640 
 641     // @TODO Why do we require these to match?
 642     if (!pcmk__str_eq(p_user, user, pcmk__str_none)) {
 643         crm_warn("Rejecting remote client for user %s "
 644                  "because PAM returned different final user name %s",
 645                  user, p_user);
 646         goto bail;
 647     }
 648 
 649     // Check user account restrictions (expiration, etc.)
 650     rc = pam_acct_mgmt(pam_h, PAM_SILENT);
 651     if (rc != PAM_SUCCESS) {
 652         crm_notice("Access for remote user %s denied: %s",
 653                    user, pam_strerror(pam_h, rc));
 654         goto bail;
 655     }
 656     pass = true;
 657 
 658 bail:
 659     pam_end(pam_h, rc);
 660     return pass;
 661 #else
 662     // @TODO Implement for non-PAM environments
 663     crm_warn("Rejecting remote user %s because this build does not have "
 664              "PAM support", user);
 665     return false;
 666 #endif
 667 }

/* [previous][next][first][last][top][bottom][index][help] */