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)
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)
83   	{
84   	    crm_info("No longer listening for remote connections");
85   	    return;
86   	}
87   	
88   	int
89   	init_remote_listener(int port, gboolean encrypted)
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)
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)
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)
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)
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)
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)
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)
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,
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)
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  	
(1) Event path: Condition "pam_name == NULL", taking true branch.
629  	    if (pam_name == NULL) {
630  	        pam_name = getenv("CIB_pam_service");
631  	    }
(2) Event path: Condition "pam_name == NULL", taking true branch.
632  	    if (pam_name == NULL) {
633  	        pam_name = "login";
634  	    }
635  	
636  	    p_conv.conv = construct_pam_passwd;
(3) Event alloc_fn: Storage is returned from allocation function "strdup".
(4) Event var_assign: Assigning: "p_conv.appdata_ptr" = storage returned from "strdup(passwd)".
Also see events: [leaked_storage]
637  	    p_conv.appdata_ptr = strdup(passwd);
638  	
639  	    rc = pam_start(pam_name, user, &p_conv, &pam_h);
(5) Event path: Condition "rc != 0", taking false branch.
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);
(6) Event path: Condition "rc != 0", taking false branch.
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);
(7) Event path: Condition "rc != 0", taking false branch.
657  	    if (rc != PAM_SUCCESS) {
658  	        crm_err("Internal PAM error: %s (%d)", pam_strerror(pam_h, rc), rc);
659  	        goto bail;
660  	
(8) Event path: Condition "p_user == NULL", taking true branch.
661  	    } else if (p_user == NULL) {
662  	        crm_err("Unknown user authenticated.");
(9) Event path: Jumping to label "bail".
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
CID (unavailable; MK=0d8a38edbef16f97820418c75805fe97) (#1 of 1): Resource leak (RESOURCE_LEAK):
(10) Event leaked_storage: Variable "p_conv" going out of scope leaks the storage "p_conv.appdata_ptr" points to.
Also see events: [alloc_fn][var_assign]
680  	    return pass;
681  	}
682