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

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