1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <security/pam_ext.h>
4 #include <syslog.h>
5 #include <stdlib.h>
6 
7 #include "alloc-util.h"
8 #include "errno-util.h"
9 #include "macro.h"
10 #include "pam-util.h"
11 
pam_log_oom(pam_handle_t * handle)12 int pam_log_oom(pam_handle_t *handle) {
13         /* This is like log_oom(), but uses PAM logging */
14         pam_syslog(handle, LOG_ERR, "Out of memory.");
15         return PAM_BUF_ERR;
16 }
17 
pam_bus_log_create_error(pam_handle_t * handle,int r)18 int pam_bus_log_create_error(pam_handle_t *handle, int r) {
19         /* This is like bus_log_create_error(), but uses PAM logging */
20         pam_syslog(handle, LOG_ERR, "Failed to create bus message: %s", strerror_safe(r));
21         return PAM_BUF_ERR;
22 }
23 
pam_bus_log_parse_error(pam_handle_t * handle,int r)24 int pam_bus_log_parse_error(pam_handle_t *handle, int r) {
25         /* This is like bus_log_parse_error(), but uses PAM logging */
26         pam_syslog(handle, LOG_ERR, "Failed to parse bus message: %s", strerror_safe(r));
27         return PAM_BUF_ERR;
28 }
29 
cleanup_system_bus(pam_handle_t * handle,void * data,int error_status)30 static void cleanup_system_bus(pam_handle_t *handle, void *data, int error_status) {
31         sd_bus_flush_close_unref(data);
32 }
33 
pam_acquire_bus_connection(pam_handle_t * handle,sd_bus ** ret)34 int pam_acquire_bus_connection(pam_handle_t *handle, sd_bus **ret) {
35         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
36         int r;
37 
38         assert(handle);
39         assert(ret);
40 
41         /* We cache the bus connection so that we can share it between the session and the authentication hooks */
42         r = pam_get_data(handle, "systemd-system-bus", (const void**) &bus);
43         if (r == PAM_SUCCESS && bus) {
44                 *ret = sd_bus_ref(TAKE_PTR(bus)); /* Increase the reference counter, so that the PAM data stays valid */
45                 return PAM_SUCCESS;
46         }
47         if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
48                 pam_syslog(handle, LOG_ERR, "Failed to get bus connection: %s", pam_strerror(handle, r));
49                 return r;
50         }
51 
52         r = sd_bus_open_system(&bus);
53         if (r < 0) {
54                 pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", strerror_safe(r));
55                 return PAM_SERVICE_ERR;
56         }
57 
58         r = pam_set_data(handle, "systemd-system-bus", bus, cleanup_system_bus);
59         if (r != PAM_SUCCESS) {
60                 pam_syslog(handle, LOG_ERR, "Failed to set PAM bus data: %s", pam_strerror(handle, r));
61                 return r;
62         }
63 
64         sd_bus_ref(bus);
65         *ret = TAKE_PTR(bus);
66 
67         return PAM_SUCCESS;
68 }
69 
pam_release_bus_connection(pam_handle_t * handle)70 int pam_release_bus_connection(pam_handle_t *handle) {
71         int r;
72 
73         r = pam_set_data(handle, "systemd-system-bus", NULL, NULL);
74         if (r != PAM_SUCCESS)
75                 pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data: %s", pam_strerror(handle, r));
76 
77         return r;
78 }
79 
pam_cleanup_free(pam_handle_t * handle,void * data,int error_status)80 void pam_cleanup_free(pam_handle_t *handle, void *data, int error_status) {
81         /* A generic destructor for pam_set_data() that just frees the specified data */
82         free(data);
83 }
84