VirtualBox

source: vbox/trunk/src/VBox/HostServices/auth/pam/VBoxAuthPAM.c@ 33185

Last change on this file since 33185 was 33185, checked in by vboxsync, 14 years ago

generalized and moved auth modules

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.7 KB
Line 
1/** @file
2 *
3 * VBox Remote Desktop Protocol:
4 * External Authentication Library:
5 * Linux PAM Authentication.
6 */
7
8/*
9 * Copyright (C) 2006-2010 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/* The PAM service name.
22 *
23 * The service name is the name of a file in the /etc/pam.d which contains
24 * authentication rules. It is possible to use an existing service
25 * name, like "login" for example. But if different set of rules
26 * is required, one can create a new file /etc/pam.d/vrdpauth
27 * specially for VRDP authentication. Note that the name of the
28 * service must be lowercase. See PAM documentation for details.
29 *
30 * The VRDPAuth module takes the PAM service name from the
31 * environment variable VRDP_AUTH_PAM_SERVICE. If the variable
32 * is not specified, then the 'login' PAM service is used.
33 */
34#define VRDP_AUTH_PAM_SERVICE_NAME_ENV "VRDP_AUTH_PAM_SERVICE"
35#define VRDP_AUTH_PAM_DEFAULT_SERVICE_NAME "login"
36
37
38/* The debug log file name.
39 *
40 * If defined, debug messages will be written to the file specified in the
41 * VRDP_AUTH_DEBUG_FILENAME environment variable:
42 *
43 * export VRDP_AUTH_DEBUG_FILENAME=pam.log
44 *
45 * The above will cause writing to the pam.log.
46 */
47#define VRDP_AUTH_DEBUG_FILENAME_ENV "VRDP_AUTH_DEBUG_FILENAME"
48
49
50/* Dynamic loading of the PAM library.
51 *
52 * If defined, the libpam.so is loaded dynamically.
53 * Enabled by default since it is often required,
54 * and does not harm.
55 */
56#define VRDP_PAM_DLLOAD
57
58
59#ifdef VRDP_PAM_DLLOAD
60/* The name of the PAM library */
61# ifdef RT_OS_SOLARIS
62# define VRDP_PAM_LIB "libpam.so.1"
63# else
64# define VRDP_PAM_LIB "libpam.so.0"
65# endif
66#endif /* VRDP_PAM_DLLOAD */
67
68
69#include <stdio.h>
70#include <stdlib.h>
71#include <stdarg.h>
72#include <string.h>
73#ifndef RT_OS_FREEBSD
74# include <malloc.h>
75#endif
76
77#include <security/pam_appl.h>
78
79#include <VBox/VRDPAuth.h>
80
81#ifdef VRDP_PAM_DLLOAD
82#include <dlfcn.h>
83
84static int (*fn_pam_start)(const char *service_name,
85 const char *user,
86 const struct pam_conv *pam_conversation,
87 pam_handle_t **pamh);
88static int (*fn_pam_authenticate)(pam_handle_t *pamh, int flags);
89static int (*fn_pam_acct_mgmt)(pam_handle_t *pamh, int flags);
90static int (*fn_pam_end)(pam_handle_t *pamh, int pam_status);
91static const char * (*fn_pam_strerror)(pam_handle_t *pamh, int errnum);
92#else
93#define fn_pam_start pam_start
94#define fn_pam_authenticate pam_authenticate
95#define fn_pam_acct_mgmt pam_acct_mgmt
96#define fn_pam_end pam_end
97#define fn_pam_strerror pam_strerror
98#endif /* VRDP_PAM_DLLOAD */
99
100static void debug_printf(const char *fmt, ...)
101{
102#ifdef VRDP_AUTH_DEBUG_FILENAME_ENV
103 va_list va;
104
105 char buffer[1024];
106
107 const char *filename = getenv (VRDP_AUTH_DEBUG_FILENAME_ENV);
108
109 va_start(va, fmt);
110
111 if (filename)
112 {
113 FILE *f;
114
115 vsnprintf (buffer, sizeof (buffer), fmt, va);
116
117 f = fopen (filename, "ab");
118 if (f != NULL)
119 {
120 fprintf (f, "%s", buffer);
121 fclose (f);
122 }
123 }
124
125 va_end (va);
126#endif /* VRDP_AUTH_DEBUG_FILENAME_ENV */
127}
128
129#ifdef VRDP_PAM_DLLOAD
130
131static void *gpvLibPam = NULL;
132
133typedef struct _SymMap
134{
135 void **ppfn;
136 const char *pszName;
137} SymMap;
138
139static SymMap symmap[] =
140{
141 { (void **)&fn_pam_start, "pam_start" },
142 { (void **)&fn_pam_authenticate, "pam_authenticate" },
143 { (void **)&fn_pam_acct_mgmt, "pam_acct_mgmt" },
144 { (void **)&fn_pam_end, "pam_end" },
145 { (void **)&fn_pam_strerror, "pam_strerror" },
146 { NULL, NULL }
147};
148
149static int vrdpauth_pam_init(void)
150{
151 SymMap *iter;
152
153 gpvLibPam = dlopen(VRDP_PAM_LIB, RTLD_LAZY | RTLD_GLOBAL);
154
155 if (!gpvLibPam)
156 {
157 debug_printf("vrdpauth_pam_init: dlopen %s failed\n", VRDP_PAM_LIB);
158 return PAM_SYSTEM_ERR;
159 }
160
161 iter = &symmap[0];
162
163 while (iter->pszName != NULL)
164 {
165 void *pv = dlsym (gpvLibPam, iter->pszName);
166
167 if (pv == NULL)
168 {
169 debug_printf("vrdpauth_pam_init: dlsym %s failed\n", iter->pszName);
170
171 dlclose(gpvLibPam);
172 gpvLibPam = NULL;
173
174 return PAM_SYSTEM_ERR;
175 }
176
177 *iter->ppfn = pv;
178
179 iter++;
180 }
181
182 return PAM_SUCCESS;
183}
184
185static void vrdpauth_pam_close(void)
186{
187 if (gpvLibPam)
188 {
189 dlclose(gpvLibPam);
190 gpvLibPam = NULL;
191 }
192
193 return;
194}
195#else
196static int vrdpauth_pam_init(void)
197{
198 return PAM_SUCCESS;
199}
200
201static void vrdpauth_pam_close(void)
202{
203 return;
204}
205#endif /* VRDP_PAM_DLLOAD */
206
207static const char *vrdpauth_get_pam_service (void)
208{
209 const char *service = getenv (VRDP_AUTH_PAM_SERVICE_NAME_ENV);
210
211 if (service == NULL)
212 {
213 service = VRDP_AUTH_PAM_DEFAULT_SERVICE_NAME;
214 }
215
216 debug_printf ("Using PAM service: %s\n", service);
217
218 return service;
219}
220
221typedef struct _PamContext
222{
223 char *szUser;
224 char *szPassword;
225} PamContext;
226
227static int conv (int num_msg, const struct pam_message **msg,
228 struct pam_response **resp, void *appdata_ptr)
229{
230 int i;
231 struct pam_response *r;
232
233 PamContext *ctx = (PamContext *)appdata_ptr;
234
235 if (ctx == NULL)
236 {
237 debug_printf("conv: ctx is NULL\n");
238 return PAM_CONV_ERR;
239 }
240
241 debug_printf("conv: num %d u[%s] p[%d]\n", num_msg, ctx->szUser, ctx->szPassword? strlen (ctx->szPassword): 0);
242
243 r = (struct pam_response *) calloc (num_msg, sizeof (struct pam_response));
244
245 if (r == NULL)
246 {
247 return PAM_CONV_ERR;
248 }
249
250 for (i = 0; i < num_msg; i++)
251 {
252 r[i].resp_retcode = 0;
253
254 if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
255 {
256 r[i].resp = strdup (ctx->szPassword);
257 debug_printf("conv: %d returning password [%d]\n", i, r[i].resp? strlen (r[i].resp): 0);
258 }
259 else if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON)
260 {
261 r[i].resp = strdup (ctx->szUser);
262 debug_printf("conv: %d returning name [%s]\n", i, r[i].resp);
263 }
264 else
265 {
266 debug_printf("conv: %d style %d: [%s]\n", i, msg[i]->msg_style, msg[i]->msg? msg[i]->msg: "(null)");
267 r[i].resp = NULL;
268 }
269 }
270
271 *resp = r;
272 return PAM_SUCCESS;
273}
274
275/* The VRDPAuth entry point must be visible. */
276#if defined(_MSC_VER) || defined(__OS2__)
277# define DECLEXPORT(type) __declspec(dllexport) type
278#else
279# ifdef VBOX_HAVE_VISIBILITY_HIDDEN
280# define DECLEXPORT(type) __attribute__((visibility("default"))) type
281# else
282# define DECLEXPORT(type) type
283# endif
284#endif
285
286/* prototype to prevent gcc warning */
287DECLEXPORT(VRDPAuthResult) VRDPAUTHCALL VRDPAuth (PVRDPAUTHUUID pUuid,
288 VRDPAuthGuestJudgement guestJudgement,
289 const char *szUser,
290 const char *szPassword,
291 const char *szDomain);
292DECLEXPORT(VRDPAuthResult) VRDPAUTHCALL VRDPAuth (PVRDPAUTHUUID pUuid,
293 VRDPAuthGuestJudgement guestJudgement,
294 const char *szUser,
295 const char *szPassword,
296 const char *szDomain)
297{
298 VRDPAuthResult result = VRDPAuthAccessDenied;
299
300 int rc;
301
302 PamContext ctx;
303 struct pam_conv pam_conversation;
304
305 pam_handle_t *pam_handle = NULL;
306
307 debug_printf("u[%s], d[%s], p[%d]\n", szUser, szDomain, szPassword? strlen (szPassword): 0);
308
309 ctx.szUser = (char *)szUser;
310 ctx.szPassword = (char *)szPassword;
311
312 pam_conversation.conv = conv;
313 pam_conversation.appdata_ptr = &ctx;
314
315 rc = vrdpauth_pam_init ();
316
317 if (rc == PAM_SUCCESS)
318 {
319 debug_printf("init ok\n");
320
321 rc = fn_pam_start(vrdpauth_get_pam_service (), szUser, &pam_conversation, &pam_handle);
322
323 if (rc == PAM_SUCCESS)
324 {
325 debug_printf("start ok\n");
326
327 rc = fn_pam_authenticate(pam_handle, 0);
328
329 if (rc == PAM_SUCCESS)
330 {
331 debug_printf("auth ok\n");
332
333 rc = fn_pam_acct_mgmt(pam_handle, 0);
334 if (rc == PAM_AUTHINFO_UNAVAIL
335 &&
336 getenv("VBOX_PAM_ALLOW_INACTIVE") != NULL)
337 {
338 debug_printf("PAM_AUTHINFO_UNAVAIL\n");
339 rc = PAM_SUCCESS;
340 }
341
342 if (rc == PAM_SUCCESS)
343 {
344 debug_printf("access granted\n");
345
346 result = VRDPAuthAccessGranted;
347 }
348 else
349 {
350 debug_printf("pam_acct_mgmt failed %d. %s\n", rc, fn_pam_strerror (pam_handle, rc));
351 }
352 }
353 else
354 {
355 debug_printf("pam_authenticate failed %d. %s\n", rc, fn_pam_strerror (pam_handle, rc));
356 }
357
358 fn_pam_end(pam_handle, rc);
359 }
360 else
361 {
362 debug_printf("pam_start failed %d\n", rc);
363 }
364
365 vrdpauth_pam_close ();
366
367 debug_printf("vrdpauth_pam_close completed\n");
368 }
369 else
370 {
371 debug_printf("vrdpauth_pam_init failed %d\n", rc);
372 }
373
374 return result;
375}
376
377/* Verify the function prototype. */
378static PVRDPAUTHENTRY gpfnAuthEntry = VRDPAuth;
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette