1From 3f90452cb9d5dbb38906dd161b4dd639be4e45c9 Mon Sep 17 00:00:00 2001
2From: Philipp Zabel <philipp.zabel@gmail.com>
3Date: Sat, 19 Nov 2022 09:52:01 +0100
4Subject: [PATCH 88/92] libweston: Add user authentication support via PAM
5
6Add user authentication support for remote backends via PAM.
7This requires a configuration file /etc/pam.d/weston.
8
9Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
10(cherry picked from commit 0733c8f5715a06c1109d380093d4f2e040284140)
11Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
12---
13 libweston/auth.c               | 116 +++++++++++++++++++++++++++++++++
14 libweston/libweston-internal.h |   5 ++
15 libweston/meson.build          |  13 ++++
16 meson.build                    |   2 +
17 pam/meson.build                |   8 +++
18 pam/weston-remote-access       |   3 +
19 6 files changed, 147 insertions(+)
20 create mode 100644 libweston/auth.c
21 create mode 100644 pam/meson.build
22 create mode 100644 pam/weston-remote-access
23
24diff --git a/libweston/auth.c b/libweston/auth.c
25new file mode 100644
26index 0000000..2133abb
27--- /dev/null
28+++ b/libweston/auth.c
29@@ -0,0 +1,116 @@
30+/*
31+ * Copyright © 2022 Philipp Zabel
32+ *
33+ * Permission is hereby granted, free of charge, to any person obtaining
34+ * a copy of this software and associated documentation files (the
35+ * "Software"), to deal in the Software without restriction, including
36+ * without limitation the rights to use, copy, modify, merge, publish,
37+ * distribute, sublicense, and/or sell copies of the Software, and to
38+ * permit persons to whom the Software is furnished to do so, subject to
39+ * the following conditions:
40+ *
41+ * The above copyright notice and this permission notice (including the
42+ * next paragraph) shall be included in all copies or substantial
43+ * portions of the Software.
44+ *
45+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
49+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
50+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
51+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
52+ * SOFTWARE.
53+ */
54+
55+#include "config.h"
56+
57+#include <shared/xalloc.h>
58+#include <stdbool.h>
59+#include "libweston-internal.h"
60+
61+#ifdef HAVE_PAM
62+
63+#include <security/pam_appl.h>
64+#include <security/pam_misc.h>
65+
66+static int
67+weston_pam_conv(int num_msg, const struct pam_message **msg,
68+		struct pam_response **resp, void *appdata_ptr)
69+{
70+	const char *password = appdata_ptr;
71+	struct pam_response *rsp;
72+	int i;
73+
74+	if (!num_msg)
75+		return PAM_CONV_ERR;
76+
77+	rsp = calloc(num_msg, sizeof(*rsp));
78+	if (!rsp)
79+		return PAM_CONV_ERR;
80+
81+	for (i = 0; i < num_msg; i++) {
82+		switch (msg[i]->msg_style) {
83+		case PAM_PROMPT_ECHO_OFF:
84+			rsp[i].resp = strdup(password);
85+			break;
86+		case PAM_PROMPT_ECHO_ON:
87+			break;
88+		case PAM_ERROR_MSG:
89+			weston_log("PAM error message: %s\n", msg[i]->msg);
90+			break;
91+		case PAM_TEXT_INFO:
92+			weston_log("PAM info text: %s\n", msg[i]->msg);
93+			break;
94+		default:
95+			free(rsp);
96+			return PAM_CONV_ERR;
97+		}
98+	}
99+
100+	*resp = rsp;
101+	return PAM_SUCCESS;
102+}
103+
104+#endif
105+
106+WL_EXPORT bool
107+weston_authenticate_user(const char *username, const char *password)
108+{
109+	bool authenticated = false;
110+#ifdef HAVE_PAM
111+	struct pam_conv conv = {
112+		.conv = weston_pam_conv,
113+		.appdata_ptr = strdup(password),
114+	};
115+	struct pam_handle *pam;
116+	int ret;
117+
118+	conv.appdata_ptr = strdup(password);
119+
120+	ret = pam_start("weston-remote-access", username, &conv, &pam);
121+	if (ret != PAM_SUCCESS) {
122+		weston_log("PAM: start failed\n");
123+		goto out;
124+	}
125+
126+	ret = pam_authenticate(pam, 0);
127+	if (ret != PAM_SUCCESS) {
128+		weston_log("PAM: authentication failed\n");
129+		goto out;
130+	}
131+
132+	ret = pam_acct_mgmt(pam, 0);
133+	if (ret != PAM_SUCCESS) {
134+		weston_log("PAM: account check failed\n");
135+		goto out;
136+	}
137+
138+	authenticated = true;
139+out:
140+	ret = pam_end(pam, ret);
141+	assert(ret == PAM_SUCCESS);
142+	free(conv.appdata_ptr);
143+#endif
144+	return authenticated;
145+}
146diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h
147index bcfb153..ea5c478 100644
148--- a/libweston/libweston-internal.h
149+++ b/libweston/libweston-internal.h
150@@ -502,4 +502,9 @@ wl_data_device_manager_init(struct wl_display *display);
151 bool
152 weston_output_set_color_outcome(struct weston_output *output);
153
154+/* User authentication for remote backends */
155+
156+bool
157+weston_authenticate_user(const char *username, const char *password);
158+
159 #endif
160diff --git a/libweston/meson.build b/libweston/meson.build
161index 6906244..6f0b624 100644
162--- a/libweston/meson.build
163+++ b/libweston/meson.build
164@@ -10,6 +10,7 @@ deps_libweston = [
165 srcs_libweston = [
166 	git_version_h,
167 	'animation.c',
168+	'auth.c',
169 	'bindings.c',
170 	'clipboard.c',
171 	'color.c',
172@@ -79,6 +80,18 @@ if dep_egl.found() and dep_gbm.found()
173 	deps_libweston += [ dep_egl, dep_gbm ]
174 endif
175
176+if get_option('backend-vnc')
177+	dep_pam = dependency('pam', required: false)
178+	if not dep_pam.found()
179+		dep_pam = cc.find_library('pam')
180+	endif
181+	if not dep_pam.found()
182+		error('VNC backend requires libpam which was not found. Or, you can use \'-Dbackend-vnc=false\'.')
183+	endif
184+	config_h.set('HAVE_PAM', '1')
185+	deps_libweston += dep_pam
186+endif
187+
188 lib_weston = shared_library(
189 	'weston-@0@'.format(libweston_major),
190 	srcs_libweston,
191diff --git a/meson.build b/meson.build
192index e03d085..cc510f1 100644
193--- a/meson.build
194+++ b/meson.build
195@@ -44,6 +44,7 @@ dir_data_pc = join_paths(dir_data, 'pkgconfig')
196 dir_lib_pc = join_paths(dir_lib, 'pkgconfig')
197 dir_man = join_paths(dir_prefix, get_option('mandir'))
198 dir_protocol_libweston = join_paths('libweston-@0@'.format(libweston_major), 'protocols')
199+dir_sysconf = join_paths(dir_prefix, get_option('sysconfdir'))
200
201 public_inc = include_directories('include')
202 common_inc = [ include_directories('.'), public_inc ]
203@@ -191,6 +192,7 @@ subdir('wcap')
204 subdir('tests')
205 subdir('data')
206 subdir('man')
207+subdir('pam')
208
209 configure_file(output: 'config.h', configuration: config_h)
210
211diff --git a/pam/meson.build b/pam/meson.build
212new file mode 100644
213index 0000000..7b7eff8
214--- /dev/null
215+++ b/pam/meson.build
216@@ -0,0 +1,8 @@
217+if not get_option('backend-vnc')
218+	subdir_done()
219+endif
220+
221+install_data(
222+	'weston-remote-access',
223+	install_dir: join_paths(dir_sysconf, 'pam.d')
224+)
225diff --git a/pam/weston-remote-access b/pam/weston-remote-access
226new file mode 100644
227index 0000000..d3014dd
228--- /dev/null
229+++ b/pam/weston-remote-access
230@@ -0,0 +1,3 @@
231+#%PAM-1.0
232+auth    include login
233+account include login
234--
2352.20.1
236
237