|
32 | 32 | #include <pwd.h> |
33 | 33 | #include <err.h> |
34 | 34 | #include <qubesdb-client.h> |
| 35 | +#include <dbus/dbus-connection.h> |
35 | 36 |
|
36 | 37 | #ifdef HAVE_PAM |
37 | 38 | #include <security/pam_appl.h> |
38 | 39 | #endif |
39 | 40 |
|
40 | 41 | pid_t child_pid = 0; |
41 | 42 |
|
| 43 | +static char **get_systemd_env_from_dbus(void) |
| 44 | +{ |
| 45 | + DBusConnection *dbus_conn = NULL; |
| 46 | + DBusError error_data = { 0 }; |
| 47 | + DBusMessage *env_request = NULL; |
| 48 | + const char *systemd_manager_str = "org.freedesktop.systemd1.Manager"; |
| 49 | + const char *environment_str = "Environment"; |
| 50 | + dbus_bool_t ret = FALSE; |
| 51 | + DBusMessage *env_reply = NULL; |
| 52 | + int reply_type = 0; |
| 53 | + DBusMessageIter reply_iter = { 0 }; |
| 54 | + DBusMessageIter reply_inner_iter = { 0 }; |
| 55 | + char *inner_iter_typesig = NULL; |
| 56 | + DBusMessageIter reply_arr_iter = { 0 }; |
| 57 | + int arr_item_type = 0; |
| 58 | + const char *env_val = NULL; |
| 59 | + char **env_arr = NULL; |
| 60 | + size_t env_arr_len = 0; |
| 61 | + |
| 62 | + dbus_error_init(&error_data); |
| 63 | + dbus_conn = dbus_bus_get(DBUS_BUS_SESSION, &error_data); |
| 64 | + if (dbus_conn == NULL) { |
| 65 | + warnx("Failed to initialize DBus, error name: '%s', error contents: '%s'\n", |
| 66 | + error_data.name, |
| 67 | + error_data.message); |
| 68 | + goto dbus_cleanup; |
| 69 | + } |
| 70 | + |
| 71 | + /* dbus_bus_get sets up our process to be killed if the DBus connection |
| 72 | + * closes. We don't want that, turn that off. |
| 73 | + */ |
| 74 | + dbus_connection_set_on_disconnect(dbus_conn, FALSE); |
| 75 | + |
| 76 | + env_request = dbus_message_new_method_call("org.freedesktop.systemd1", |
| 77 | + "/org/freedesktop/systemd1", |
| 78 | + "org.freedesktop.DBus.Properties", |
| 79 | + "Get"); |
| 80 | + if (env_request == NULL) { |
| 81 | + warnx("Failed to create DBus method call!\n"); |
| 82 | + goto dbus_cleanup; |
| 83 | + } |
| 84 | + |
| 85 | + ret = dbus_message_append_args(env_request, |
| 86 | + DBUS_TYPE_STRING, &systemd_manager_str, |
| 87 | + DBUS_TYPE_STRING, &environment_str, |
| 88 | + DBUS_TYPE_INVALID); |
| 89 | + if (ret == FALSE) { |
| 90 | + warnx("Failed to append arguments to DBus method call!\n"); |
| 91 | + goto dbus_cleanup; |
| 92 | + } |
| 93 | + |
| 94 | + env_reply = dbus_connection_send_with_reply_and_block(dbus_conn, |
| 95 | + env_request, |
| 96 | + 500, |
| 97 | + &error_data); |
| 98 | + if (env_reply == NULL) { |
| 99 | + warnx("Failed to request environment data from systemd, error name: '%s', error contents: '%s'\n", |
| 100 | + error_data.name, |
| 101 | + error_data.message); |
| 102 | + goto dbus_cleanup; |
| 103 | + } |
| 104 | + |
| 105 | + reply_type = dbus_message_get_type(env_reply); |
| 106 | + if (reply_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) { |
| 107 | + warnx("Did not get expected method reply from systemd!\n"); |
| 108 | + goto dbus_cleanup; |
| 109 | + } |
| 110 | + |
| 111 | + ret = dbus_message_iter_init(env_reply, &reply_iter); |
| 112 | + if (ret == FALSE) { |
| 113 | + warnx("systemd returned no environment variables!\n"); |
| 114 | + goto dbus_cleanup; |
| 115 | + } |
| 116 | + |
| 117 | + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT) { |
| 118 | + warnx("Did not get variant container from systemd!\n"); |
| 119 | + goto dbus_cleanup; |
| 120 | + } |
| 121 | + dbus_message_iter_recurse(&reply_iter, &reply_inner_iter); |
| 122 | + |
| 123 | + inner_iter_typesig = dbus_message_iter_get_signature(&reply_inner_iter); |
| 124 | + if (strcmp(inner_iter_typesig, "as") != 0) { |
| 125 | + warnx("Variant container from systemd does not contain a string array!\n"); |
| 126 | + goto dbus_cleanup; |
| 127 | + } |
| 128 | + dbus_message_iter_recurse(&reply_inner_iter, &reply_arr_iter); |
| 129 | + |
| 130 | + while ((current_type = dbus_message_iter_get_arg_type(&reply_arr_iter)) |
| 131 | + != DBUS_TYPE_INVALID) { |
| 132 | + if (current_type != DBUS_TYPE_STRING) { |
| 133 | + warnx("Non-string item found in string array!\n"); |
| 134 | + goto dbus_cleanup; |
| 135 | + } |
| 136 | + dbus_message_iter_get_basic(&reply_arr_iter, &env_val); |
| 137 | + env_arr_len++; |
| 138 | + env_arr = reallocarray(env_arr, env_arr_len, sizeof(char *)); |
| 139 | + if (env_arr == NULL) |
| 140 | + errx("Failed to allocate memory for environment array: %s\n", |
| 141 | + strerror(errno)); |
| 142 | + env_arr[env_arr_len - 1] = strdup(env_val); |
| 143 | + if (env_arr[env_arr_len - 1] == NULL) |
| 144 | + errx("Failed to allocate memory for environment item: %s\n", |
| 145 | + strerror(errno)); |
| 146 | + } |
| 147 | + |
| 148 | + env_arr_len++; |
| 149 | + env_arr = reallocarray(env_arr, env_arr_len, sizeof(char *)); |
| 150 | + if (env_arr == NULL) |
| 151 | + errx("Failed to allocate memory for environment array: %s\n", |
| 152 | + strerror(errno)); |
| 153 | + env_arr[env_arr_len - 1] = NULL; |
| 154 | + |
| 155 | +dbus_cleanup: |
| 156 | + if (dbus_conn != NULL) |
| 157 | + dbus_connection_unref(dbus_conn); |
| 158 | + if (env_request != NULL) |
| 159 | + dbus_message_unref(env_request); |
| 160 | + if (env_reply != NULL) |
| 161 | + dbus_message_unref(env_reply); |
| 162 | + if (inner_iter_typesig != NULL) |
| 163 | + dbus_free(inner_iter_typesig); |
| 164 | + return env_arr; |
| 165 | +} |
| 166 | + |
42 | 167 | #ifdef HAVE_PAM |
43 | 168 | static int pam_conv_callback(int num_msg, const struct pam_message **msg, |
44 | 169 | struct pam_response **resp, void *appdata_ptr __attribute__((__unused__))) |
@@ -79,6 +204,8 @@ static pid_t do_execute(char *user, char *path, char **argv) |
79 | 204 | int retval=0, status; |
80 | 205 | char **env; |
81 | 206 | char env_buf[256]; |
| 207 | + char **systemd_env; |
| 208 | + char **systemd_env_iter; |
82 | 209 | pam_handle_t *pamh=NULL; |
83 | 210 | pid_t pid; |
84 | 211 |
|
@@ -111,6 +238,11 @@ static pid_t do_execute(char *user, char *path, char **argv) |
111 | 238 | if (retval != PAM_SUCCESS) |
112 | 239 | goto error; |
113 | 240 |
|
| 241 | + /* TODO: This allocates a chunk of memory for strings, but we never free |
| 242 | + * it. Should we? |
| 243 | + */ |
| 244 | + systemd_env = get_systemd_env_from_dbus(); |
| 245 | + |
114 | 246 | /* provide env variables to PAM and the X session */ |
115 | 247 | retval = snprintf(env_buf, sizeof(env_buf), "HOME=%s", pw->pw_dir); |
116 | 248 | if ((unsigned int)retval >= sizeof(env_buf)) |
@@ -203,6 +335,15 @@ static pid_t do_execute(char *user, char *path, char **argv) |
203 | 335 | } |
204 | 336 | } |
205 | 337 |
|
| 338 | + if (systemd_env != NULL) { |
| 339 | + for (systemd_env_iter = systemd_env; *systemd_env_iter != NULL; |
| 340 | + systemd_env_iter++) { |
| 341 | + retval = pam_putenv(pamh, *systemd_env_iter); |
| 342 | + if (retval != PAM_SUCCESS) |
| 343 | + goto error; |
| 344 | + } |
| 345 | + } |
| 346 | + |
206 | 347 | /* authenticate */ |
207 | 348 | retval = pam_authenticate(pamh, 0); |
208 | 349 | if (retval != PAM_SUCCESS) |
|
0 commit comments