root/daemons/based/based_remote.c

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

DEFINITIONS

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

   1 /*
   2  * Copyright 2004-2023 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/msg_xml.h>
  31 #include <crm/common/ipc.h>
  32 #include <crm/common/ipc_internal.h>
  33 #include <crm/common/xml.h>
  34 #include <crm/common/remote_internal.h>
  35 #include <crm/cib/internal.h>
  36 
  37 #include "pacemaker-based.h"
  38 
  39 /* #undef HAVE_PAM_PAM_APPL_H */
  40 /* #undef HAVE_GNUTLS_GNUTLS_H */
  41 
  42 #ifdef HAVE_GNUTLS_GNUTLS_H
  43 #  include <gnutls/gnutls.h>
  44 #endif
  45 
  46 #include <pwd.h>
  47 #include <grp.h>
  48 #if HAVE_SECURITY_PAM_APPL_H
  49 #  include <security/pam_appl.h>
  50 #  define HAVE_PAM 1
  51 #else
  52 #  if HAVE_PAM_PAM_APPL_H
  53 #    include <pam/pam_appl.h>
  54 #    define HAVE_PAM 1
  55 #  endif
  56 #endif
  57 
  58 extern int remote_tls_fd;
  59 extern gboolean cib_shutdown_flag;
  60 
  61 int init_remote_listener(int port, gboolean encrypted);
  62 void cib_remote_connection_destroy(gpointer user_data);
  63 
  64 #ifdef HAVE_GNUTLS_GNUTLS_H
  65 gnutls_dh_params_t dh_params;
  66 gnutls_anon_server_credentials_t anon_cred_s;
  67 static void
  68 debug_log(int level, const char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70     fputs(str, stderr);
  71 }
  72 #endif
  73 
  74 #define REMOTE_AUTH_TIMEOUT 10000
  75 
  76 int num_clients;
  77 int authenticate_user(const char *user, const char *passwd);
  78 static int cib_remote_listen(gpointer data);
  79 static int cib_remote_msg(gpointer data);
  80 
  81 static void
  82 remote_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84     crm_info("No longer listening for remote connections");
  85     return;
  86 }
  87 
  88 int
  89 init_remote_listener(int port, gboolean encrypted)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91     int rc;
  92     int *ssock = NULL;
  93     struct sockaddr_in saddr;
  94     int optval;
  95 
  96     static struct mainloop_fd_callbacks remote_listen_fd_callbacks = {
  97         .dispatch = cib_remote_listen,
  98         .destroy = remote_connection_destroy,
  99     };
 100 
 101     if (port <= 0) {
 102         /* don't start it */
 103         return 0;
 104     }
 105 
 106     if (encrypted) {
 107 #ifndef HAVE_GNUTLS_GNUTLS_H
 108         crm_warn("TLS support is not available");
 109         return 0;
 110 #else
 111         crm_notice("Starting TLS listener on port %d", port);
 112         crm_gnutls_global_init();
 113         /* gnutls_global_set_log_level (10); */
 114         gnutls_global_set_log_function(debug_log);
 115         if (pcmk__init_tls_dh(&dh_params) != pcmk_rc_ok) {
 116             return -1;
 117         }
 118         gnutls_anon_allocate_server_credentials(&anon_cred_s);
 119         gnutls_anon_set_server_dh_params(anon_cred_s, dh_params);
 120 #endif
 121     } else {
 122         crm_warn("Starting plain-text listener on port %d", port);
 123     }
 124 #ifndef HAVE_PAM
 125     crm_warn("PAM is _not_ enabled!");
 126 #endif
 127 
 128     /* create server socket */
 129     ssock = malloc(sizeof(int));
 130     if(ssock == NULL) {
 131         crm_err("Listener socket allocation failed: %s", pcmk_rc_str(errno));
 132         return -1;
 133     }
 134 
 135     *ssock = socket(AF_INET, SOCK_STREAM, 0);
 136     if (*ssock == -1) {
 137         crm_err("Listener socket creation failed: %s", pcmk_rc_str(errno));
 138         free(ssock);
 139         return -1;
 140     }
 141 
 142     /* reuse address */
 143     optval = 1;
 144     rc = setsockopt(*ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
 145     if (rc < 0) {
 146         crm_err("Local address reuse not allowed on listener socket: %s",
 147                 pcmk_rc_str(errno));
 148     }
 149 
 150     /* bind server socket */
 151     memset(&saddr, '\0', sizeof(saddr));
 152     saddr.sin_family = AF_INET;
 153     saddr.sin_addr.s_addr = INADDR_ANY;
 154     saddr.sin_port = htons(port);
 155     if (bind(*ssock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
 156         crm_err("Cannot bind to listener socket: %s", pcmk_rc_str(errno));
 157         close(*ssock);
 158         free(ssock);
 159         return -2;
 160     }
 161     if (listen(*ssock, 10) == -1) {
 162         crm_err("Cannot listen on socket: %s", pcmk_rc_str(errno));
 163         close(*ssock);
 164         free(ssock);
 165         return -3;
 166     }
 167 
 168     mainloop_add_fd("cib-remote", G_PRIORITY_DEFAULT, *ssock, ssock, &remote_listen_fd_callbacks);
 169     crm_debug("Started listener on port %d", port);
 170 
 171     return *ssock;
 172 }
 173 
 174 static int
 175 check_group_membership(const char *usr, const char *grp)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177     int index = 0;
 178     struct passwd *pwd = NULL;
 179     struct group *group = NULL;
 180 
 181     CRM_CHECK(usr != NULL, return FALSE);
 182     CRM_CHECK(grp != NULL, return FALSE);
 183 
 184     pwd = getpwnam(usr);
 185     if (pwd == NULL) {
 186         crm_err("No user named '%s' exists!", usr);
 187         return FALSE;
 188     }
 189 
 190     group = getgrgid(pwd->pw_gid);
 191     if (group != NULL && pcmk__str_eq(grp, group->gr_name, pcmk__str_none)) {
 192         return TRUE;
 193     }
 194 
 195     group = getgrnam(grp);
 196     if (group == NULL) {
 197         crm_err("No group named '%s' exists!", grp);
 198         return FALSE;
 199     }
 200 
 201     while (TRUE) {
 202         char *member = group->gr_mem[index++];
 203 
 204         if (member == NULL) {
 205             break;
 206 
 207         } else if (pcmk__str_eq(usr, member, pcmk__str_none)) {
 208             return TRUE;
 209         }
 210     };
 211 
 212     return FALSE;
 213 }
 214 
 215 static gboolean
 216 cib_remote_auth(xmlNode * login)
     /* [previous][next][first][last][top][bottom][index][help] */
 217 {
 218     const char *user = NULL;
 219     const char *pass = NULL;
 220     const char *tmp = NULL;
 221 
 222     crm_log_xml_info(login, "Login: ");
 223     if (login == NULL) {
 224         return FALSE;
 225     }
 226 
 227     if (!pcmk__xe_is(login, T_CIB_COMMAND)) {
 228         crm_err("Unrecognizable message from remote client");
 229         crm_log_xml_info(login, "bad");
 230         return FALSE;
 231     }
 232 
 233     tmp = crm_element_value(login, "op");
 234     if (!pcmk__str_eq(tmp, "authenticate", pcmk__str_casei)) {
 235         crm_err("Wrong operation: %s", tmp);
 236         return FALSE;
 237     }
 238 
 239     user = crm_element_value(login, "user");
 240     pass = crm_element_value(login, "password");
 241 
 242     if (!user || !pass) {
 243         crm_err("missing auth credentials");
 244         return FALSE;
 245     }
 246 
 247     /* Non-root daemons can only validate the password of the
 248      * user they're running as
 249      */
 250     if (check_group_membership(user, CRM_DAEMON_GROUP) == FALSE) {
 251         crm_err("User is not a member of the required group");
 252         return FALSE;
 253 
 254     } else if (authenticate_user(user, pass) == FALSE) {
 255         crm_err("PAM auth failed");
 256         return FALSE;
 257     }
 258 
 259     return TRUE;
 260 }
 261 
 262 static gboolean
 263 remote_auth_timeout_cb(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {
 265     pcmk__client_t *client = data;
 266 
 267     client->remote->auth_timeout = 0;
 268 
 269     if (pcmk_is_set(client->flags, pcmk__client_authenticated)) {
 270         return FALSE;
 271     }
 272 
 273     mainloop_del_fd(client->remote->source);
 274     crm_err("Remote client authentication timed out");
 275 
 276     return FALSE;
 277 }
 278 
 279 static int
 280 cib_remote_listen(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282     int csock = 0;
 283     unsigned laddr;
 284     struct sockaddr_storage addr;
 285     char ipstr[INET6_ADDRSTRLEN];
 286     int ssock = *(int *)data;
 287     int rc;
 288 
 289     pcmk__client_t *new_client = NULL;
 290 
 291     static struct mainloop_fd_callbacks remote_client_fd_callbacks = {
 292         .dispatch = cib_remote_msg,
 293         .destroy = cib_remote_connection_destroy,
 294     };
 295 
 296     /* accept the connection */
 297     laddr = sizeof(addr);
 298     memset(&addr, 0, sizeof(addr));
 299     csock = accept(ssock, (struct sockaddr *)&addr, &laddr);
 300     if (csock == -1) {
 301         crm_err("Could not accept socket connection: %s", pcmk_rc_str(errno));
 302         return TRUE;
 303     }
 304 
 305     pcmk__sockaddr2str(&addr, ipstr);
 306     crm_debug("New %s connection from %s",
 307               ((ssock == remote_tls_fd)? "secure" : "clear-text"), ipstr);
 308 
 309     rc = pcmk__set_nonblocking(csock);
 310     if (rc != pcmk_rc_ok) {
 311         crm_err("Could not set socket non-blocking: %s " CRM_XS " rc=%d",
 312                 pcmk_rc_str(rc), rc);
 313         close(csock);
 314         return TRUE;
 315     }
 316 
 317     num_clients++;
 318 
 319     new_client = pcmk__new_unauth_client(NULL);
 320     new_client->remote = calloc(1, sizeof(pcmk__remote_t));
 321 
 322     if (ssock == remote_tls_fd) {
 323 #ifdef HAVE_GNUTLS_GNUTLS_H
 324         pcmk__set_client_flags(new_client, pcmk__client_tls);
 325 
 326         /* create gnutls session for the server socket */
 327         new_client->remote->tls_session = pcmk__new_tls_session(csock,
 328                                                                 GNUTLS_SERVER,
 329                                                                 GNUTLS_CRD_ANON,
 330                                                                 anon_cred_s);
 331         if (new_client->remote->tls_session == NULL) {
 332             close(csock);
 333             return TRUE;
 334         }
 335 #endif
 336     } else {
 337         pcmk__set_client_flags(new_client, pcmk__client_tcp);
 338         new_client->remote->tcp_socket = csock;
 339     }
 340 
 341     // Require the client to authenticate within this time
 342     new_client->remote->auth_timeout = g_timeout_add(REMOTE_AUTH_TIMEOUT,
 343                                                      remote_auth_timeout_cb,
 344                                                      new_client);
 345     crm_info("Remote CIB client pending authentication "
 346              CRM_XS " %p id: %s", new_client, new_client->id);
 347 
 348     new_client->remote->source =
 349         mainloop_add_fd("cib-remote-client", G_PRIORITY_DEFAULT, csock, new_client,
 350                         &remote_client_fd_callbacks);
 351 
 352     return TRUE;
 353 }
 354 
 355 void
 356 cib_remote_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 357 {
 358     pcmk__client_t *client = user_data;
 359     int csock = 0;
 360 
 361     if (client == NULL) {
 362         return;
 363     }
 364 
 365     crm_trace("Cleaning up after client %s disconnect",
 366               pcmk__client_name(client));
 367 
 368     num_clients--;
 369     crm_trace("Num unfree'd clients: %d", num_clients);
 370 
 371     switch (PCMK__CLIENT_TYPE(client)) {
 372         case pcmk__client_tcp:
 373             csock = client->remote->tcp_socket;
 374             break;
 375 #ifdef HAVE_GNUTLS_GNUTLS_H
 376         case pcmk__client_tls:
 377             if (client->remote->tls_session) {
 378                 void *sock_ptr = gnutls_transport_get_ptr(*client->remote->tls_session);
 379 
 380                 csock = GPOINTER_TO_INT(sock_ptr);
 381                 if (pcmk_is_set(client->flags,
 382                                 pcmk__client_tls_handshake_complete)) {
 383                     gnutls_bye(*client->remote->tls_session, GNUTLS_SHUT_WR);
 384                 }
 385                 gnutls_deinit(*client->remote->tls_session);
 386                 gnutls_free(client->remote->tls_session);
 387                 client->remote->tls_session = NULL;
 388             }
 389             break;
 390 #endif
 391         default:
 392             crm_warn("Unknown transport for client %s "
 393                      CRM_XS " flags=%#016" PRIx64,
 394                      pcmk__client_name(client), client->flags);
 395     }
 396 
 397     if (csock > 0) {
 398         close(csock);
 399     }
 400 
 401     pcmk__free_client(client);
 402 
 403     crm_trace("Freed the cib client");
 404 
 405     if (cib_shutdown_flag) {
 406         cib_shutdown(0);
 407     }
 408     return;
 409 }
 410 
 411 static void
 412 cib_handle_remote_msg(pcmk__client_t *client, xmlNode *command)
     /* [previous][next][first][last][top][bottom][index][help] */
 413 {
 414     const char *value = NULL;
 415 
 416     if (!pcmk__xe_is(command, T_CIB_COMMAND)) {
 417         crm_log_xml_trace(command, "bad");
 418         return;
 419     }
 420 
 421     if (client->name == NULL) {
 422         value = crm_element_value(command, F_CLIENTNAME);
 423         if (value == NULL) {
 424             client->name = strdup(client->id);
 425         } else {
 426             client->name = strdup(value);
 427         }
 428     }
 429 
 430     /* unset dangerous options */
 431     xml_remove_prop(command, F_ORIG);
 432     xml_remove_prop(command, F_CIB_HOST);
 433     xml_remove_prop(command, F_CIB_GLOBAL_UPDATE);
 434 
 435     crm_xml_add(command, F_TYPE, T_CIB);
 436     crm_xml_add(command, F_CIB_CLIENTID, client->id);
 437     crm_xml_add(command, F_CIB_CLIENTNAME, client->name);
 438     crm_xml_add(command, F_CIB_USER, client->user);
 439 
 440     if (crm_element_value(command, F_CIB_CALLID) == NULL) {
 441         char *call_uuid = crm_generate_uuid();
 442 
 443         /* fix the command */
 444         crm_xml_add(command, F_CIB_CALLID, call_uuid);
 445         free(call_uuid);
 446     }
 447 
 448     if (crm_element_value(command, F_CIB_CALLOPTS) == NULL) {
 449         crm_xml_add_int(command, F_CIB_CALLOPTS, 0);
 450     }
 451 
 452     crm_log_xml_trace(command, "Remote command: ");
 453     cib_common_callback_worker(0, 0, command, client, TRUE);
 454 }
 455 
 456 static int
 457 cib_remote_msg(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 458 {
 459     xmlNode *command = NULL;
 460     pcmk__client_t *client = data;
 461     int rc;
 462     int timeout = 1000;
 463 
 464     if (pcmk_is_set(client->flags, pcmk__client_authenticated)) {
 465         timeout = -1;
 466     }
 467 
 468     crm_trace("Remote %s message received for client %s",
 469               pcmk__client_type_str(PCMK__CLIENT_TYPE(client)),
 470               pcmk__client_name(client));
 471 
 472 #ifdef HAVE_GNUTLS_GNUTLS_H
 473     if ((PCMK__CLIENT_TYPE(client) == pcmk__client_tls)
 474         && !pcmk_is_set(client->flags, pcmk__client_tls_handshake_complete)) {
 475 
 476         int rc = pcmk__read_handshake_data(client);
 477 
 478         if (rc == EAGAIN) {
 479             /* No more data is available at the moment. Just return for now;
 480              * we'll get invoked again once the client sends more.
 481              */
 482             return 0;
 483         } else if (rc != pcmk_rc_ok) {
 484             return -1;
 485         }
 486 
 487         crm_debug("TLS handshake with remote CIB client completed");
 488         pcmk__set_client_flags(client, pcmk__client_tls_handshake_complete);
 489         if (client->remote->auth_timeout) {
 490             g_source_remove(client->remote->auth_timeout);
 491         }
 492 
 493         // Require the client to authenticate within this time
 494         client->remote->auth_timeout = g_timeout_add(REMOTE_AUTH_TIMEOUT,
 495                                                      remote_auth_timeout_cb,
 496                                                      client);
 497         return 0;
 498     }
 499 #endif
 500 
 501     rc = pcmk__read_remote_message(client->remote, timeout);
 502 
 503     /* must pass auth before we will process anything else */
 504     if (!pcmk_is_set(client->flags, pcmk__client_authenticated)) {
 505         xmlNode *reg;
 506         const char *user = NULL;
 507 
 508         command = pcmk__remote_message_xml(client->remote);
 509         if (cib_remote_auth(command) == FALSE) {
 510             free_xml(command);
 511             return -1;
 512         }
 513 
 514         crm_notice("Remote CIB client connection accepted");
 515         pcmk__set_client_flags(client, pcmk__client_authenticated);
 516         g_source_remove(client->remote->auth_timeout);
 517         client->remote->auth_timeout = 0;
 518         client->name = crm_element_value_copy(command, "name");
 519 
 520         user = crm_element_value(command, "user");
 521         if (user) {
 522             client->user = strdup(user);
 523         }
 524 
 525         /* send ACK */
 526         reg = create_xml_node(NULL, "cib_result");
 527         crm_xml_add(reg, F_CIB_OPERATION, CRM_OP_REGISTER);
 528         crm_xml_add(reg, F_CIB_CLIENTID, client->id);
 529         pcmk__remote_send_xml(client->remote, reg);
 530         free_xml(reg);
 531         free_xml(command);
 532     }
 533 
 534     command = pcmk__remote_message_xml(client->remote);
 535     while (command) {
 536         crm_trace("Remote client message received");
 537         cib_handle_remote_msg(client, command);
 538         free_xml(command);
 539         command = pcmk__remote_message_xml(client->remote);
 540     }
 541 
 542     if (rc == ENOTCONN) {
 543         crm_trace("Remote CIB client disconnected while reading from it");
 544         return -1;
 545     }
 546 
 547     return 0;
 548 }
 549 
 550 #ifdef HAVE_PAM
 551 static int
 552 construct_pam_passwd(int num_msg, const struct pam_message **msg,
     /* [previous][next][first][last][top][bottom][index][help] */
 553                      struct pam_response **response, void *data)
 554 {
 555     int count = 0;
 556     struct pam_response *reply;
 557     char *string = (char *)data;
 558 
 559     CRM_CHECK(data, return PAM_CONV_ERR);
 560     CRM_CHECK(num_msg == 1, return PAM_CONV_ERR);       /* We only want to handle one message */
 561 
 562     reply = calloc(1, sizeof(struct pam_response));
 563     CRM_ASSERT(reply != NULL);
 564 
 565     for (count = 0; count < num_msg; ++count) {
 566         switch (msg[count]->msg_style) {
 567             case PAM_TEXT_INFO:
 568                 crm_info("PAM: %s", msg[count]->msg);
 569                 break;
 570             case PAM_PROMPT_ECHO_OFF:
 571             case PAM_PROMPT_ECHO_ON:
 572                 reply[count].resp_retcode = 0;
 573                 reply[count].resp = string;     /* We already made a copy */
 574                 break;
 575             case PAM_ERROR_MSG:
 576                 /* In theory we'd want to print this, but then
 577                  * we see the password prompt in the logs
 578                  */
 579                 /* crm_err("PAM error: %s", msg[count]->msg); */
 580                 break;
 581             default:
 582                 crm_err("Unhandled conversation type: %d", msg[count]->msg_style);
 583                 goto bail;
 584         }
 585     }
 586 
 587     *response = reply;
 588     reply = NULL;
 589 
 590     return PAM_SUCCESS;
 591 
 592   bail:
 593     for (count = 0; count < num_msg; ++count) {
 594         if (reply[count].resp != NULL) {
 595             switch (msg[count]->msg_style) {
 596                 case PAM_PROMPT_ECHO_ON:
 597                 case PAM_PROMPT_ECHO_OFF:
 598                     /* Erase the data - it contained a password */
 599                     while (*(reply[count].resp)) {
 600                         *(reply[count].resp)++ = '\0';
 601                     }
 602                     free(reply[count].resp);
 603                     break;
 604             }
 605             reply[count].resp = NULL;
 606         }
 607     }
 608     free(reply);
 609     reply = NULL;
 610 
 611     return PAM_CONV_ERR;
 612 }
 613 #endif
 614 
 615 int
 616 authenticate_user(const char *user, const char *passwd)
     /* [previous][next][first][last][top][bottom][index][help] */
 617 {
 618 #ifndef HAVE_PAM
 619     gboolean pass = TRUE;
 620 #else
 621     int rc = 0;
 622     gboolean pass = FALSE;
 623     const void *p_user = NULL;
 624 
 625     struct pam_conv p_conv;
 626     struct pam_handle *pam_h = NULL;
 627     static const char *pam_name = NULL;
 628 
 629     if (pam_name == NULL) {
 630         pam_name = getenv("CIB_pam_service");
 631     }
 632     if (pam_name == NULL) {
 633         pam_name = "login";
 634     }
 635 
 636     p_conv.conv = construct_pam_passwd;
 637     p_conv.appdata_ptr = strdup(passwd);
 638 
 639     rc = pam_start(pam_name, user, &p_conv, &pam_h);
 640     if (rc != PAM_SUCCESS) {
 641         crm_err("Could not initialize PAM: %s (%d)", pam_strerror(pam_h, rc), rc);
 642         goto bail;
 643     }
 644 
 645     rc = pam_authenticate(pam_h, 0);
 646     if (rc != PAM_SUCCESS) {
 647         crm_err("Authentication failed for %s: %s (%d)", user, pam_strerror(pam_h, rc), rc);
 648         goto bail;
 649     }
 650 
 651     /* Make sure we authenticated the user we wanted to authenticate.
 652      * Since we also run as non-root, it might be worth pre-checking
 653      * the user has the same EID as us, since that the only user we
 654      * can authenticate.
 655      */
 656     rc = pam_get_item(pam_h, PAM_USER, &p_user);
 657     if (rc != PAM_SUCCESS) {
 658         crm_err("Internal PAM error: %s (%d)", pam_strerror(pam_h, rc), rc);
 659         goto bail;
 660 
 661     } else if (p_user == NULL) {
 662         crm_err("Unknown user authenticated.");
 663         goto bail;
 664 
 665     } else if (!pcmk__str_eq(p_user, user, pcmk__str_casei)) {
 666         crm_err("User mismatch: %s vs. %s.", (const char *)p_user, (const char *)user);
 667         goto bail;
 668     }
 669 
 670     rc = pam_acct_mgmt(pam_h, 0);
 671     if (rc != PAM_SUCCESS) {
 672         crm_err("Access denied: %s (%d)", pam_strerror(pam_h, rc), rc);
 673         goto bail;
 674     }
 675     pass = TRUE;
 676 
 677   bail:
 678     pam_end(pam_h, rc);
 679 #endif
 680     return pass;
 681 }

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