LogonUser
Martin Wilck
Martin.Wilck at Fujitsu-Siemens.com
Fri Nov 8 10:25:55 CST 2002
Patch: LogonUser.diff
This patch is incremental wrt my ComuterName (take 2) patch
(http://www.winehq.com/hypermail/wine-patches/2002/11/0080.html)
in the documentation subdirectory.
Also fixes an error I made in that patch in wine.conf.man.
Modified files:
wine: configure.ac
configure (not included in the patch)
wine/dlls/advapi32: Makefile.in
advapi.c
security.c
advapi32.spec
wine/include: config.h.in
winbase.h
wine/documentation: configuring.sgml
wine.conf.man
wine/documentation/samples: config
Log Message: Martin Wilck <martin.wilck at fujitsu-siemens.com>
Implement LogonUser() using an interface between Wine and
the PAM library.
Normally, this will validate Unix username/password pairs.
If PAM is suitably configured (for using winbind), usernames
and passwords can be obtained from a Windows Domain controller.
Introduce PAM related configuration options.
Differences to my previous Logonuser patch:
- configuration options instead of hard-coded defaults
- documentation update
- LogonUser() now in security.c
diff -ruNX ignore CVS/wine/configure.ac TMP/wine/configure.ac
--- CVS/wine/configure.ac Fri Nov 8 10:45:07 2002
+++ TMP/wine/configure.ac Fri Nov 8 10:45:59 2002
@@ -621,6 +621,13 @@
[AUDIOIOLIBS="-laudioio"
AC_DEFINE(HAVE_LIBAUDIOIO, 1, [Define if you have libaudioIO])])])
+dnl **** Check for PAM ****
+AC_SUBST(PAMLIBS,"")
+AC_CHECK_HEADERS(security/pam_appl.h,
+ [AC_CHECK_LIB(pam,pam_start,
+ [AC_DEFINE(HAVE_PAM,1,[Define if you have PAM including devel headers])
+ PAMLIBS="-lpam"],,)])
+
dnl **** Check for broken glibc mmap64 ****
AC_CACHE_CHECK( [whether mmap64 works defined as mmap], ac_cv_mmap64_works,
diff -ruNX ignore CVS/wine/dlls/advapi32/Makefile.in TMP/wine/dlls/advapi32/Makefile.in
--- CVS/wine/dlls/advapi32/Makefile.in Mon Oct 28 09:35:53 2002
+++ TMP/wine/dlls/advapi32/Makefile.in Fri Nov 8 10:45:59 2002
@@ -5,6 +5,7 @@
VPATH = @srcdir@
MODULE = advapi32.dll
IMPORTS = kernel32 ntdll
+EXTRALIBS = @PAMLIBS@
LDDLLFLAGS = @LDDLLFLAGS@
SYMBOLFILE = $(MODULE).tmp.o
diff -ruNX ignore CVS/wine/dlls/advapi32/advapi.c TMP/wine/dlls/advapi32/advapi.c
--- CVS/wine/dlls/advapi32/advapi.c Wed Aug 28 13:49:07 2002
+++ TMP/wine/dlls/advapi32/advapi.c Fri Nov 8 14:44:29 2002
@@ -121,3 +121,17 @@
TRACE("stub %s (harmless)\n", debugstr_w(lpMachineName));
return TRUE;
}
+
+/******************************************************************************
+ * Init function for advapi32 - needed to properly load the pam library.
+ */
+BOOL WINAPI DllMain ( HINSTANCE hinst, DWORD reason, LPVOID reserved )
+{
+#if HAVE_PAM
+ const static char soname[] = "libpam.so";
+ if ( reason == DLL_PROCESS_ATTACH
+ && ! wine_dlopen( soname, RTLD_NOW|RTLD_GLOBAL, NULL, 0 ) )
+ ERR ( "error opening %s\n", soname );
+#endif
+ return TRUE;
+}
diff -ruNX ignore CVS/wine/dlls/advapi32/advapi32.spec TMP/wine/dlls/advapi32/advapi32.spec
--- CVS/wine/dlls/advapi32/advapi32.spec Mon Sep 9 09:28:27 2002
+++ TMP/wine/dlls/advapi32/advapi32.spec Fri Nov 8 14:44:41 2002
@@ -127,8 +127,8 @@
@ stdcall IsValidSecurityDescriptor(ptr) IsValidSecurityDescriptor
@ stdcall IsValidSid(ptr) IsValidSid
@ stub LockServiceDatabase
-@ stub LogonUserA
-@ stub LogonUserW
+@ stdcall LogonUserA(ptr ptr ptr long long ptr) LogonUserA
+@ stdcall LogonUserW(ptr ptr ptr long long ptr) LogonUserW
@ stdcall LookupAccountNameA(str str ptr ptr ptr ptr ptr) LookupAccountNameA
@ stub LookupAccountNameW
@ stdcall LookupAccountSidA(ptr ptr ptr ptr ptr ptr ptr) LookupAccountSidA
diff -ruNX ignore CVS/wine/dlls/advapi32/security.c TMP/wine/dlls/advapi32/security.c
--- CVS/wine/dlls/advapi32/security.c Mon Oct 28 09:35:53 2002
+++ TMP/wine/dlls/advapi32/security.c Fri Nov 8 15:38:32 2002
@@ -17,8 +17,13 @@
*
* FIXME: for all functions thunking down to Rtl* functions: implement SetLastError()
*/
+#include "config.h"
#include <string.h>
+#include <stdlib.h>
+#if HAVE_PAM
+#include <security/pam_appl.h>
+#endif
#include "windef.h"
#include "winerror.h"
@@ -1093,3 +1098,288 @@
*pfResult=TRUE;
return TRUE;
}
+
+#if HAVE_PAM
+/******************************************************************************
+ * Helper functions for the PAM interface.
+ */
+
+/* FIXME: These should be made configurable options, at least the separator. */
+#define WINE_PAM_SERVICE "wine"
+/* This corresponds to the "winbind separator" setting in smb.conf. */
+#define WINE_WINBIND_SEPARATOR '\\'
+#define PAM_FAIL(x) ((x) != PAM_SUCCESS)
+
+/******************************************************************************
+ * PAM_error_to_dos [INTERNAL]
+ */
+static int PAM_error_to_dos ( pam_handle_t *pamh, int retcode )
+{
+ if ( pamh )
+ TRACE( "PAM error: %s\n", pam_strerror ( pamh, retcode ) );
+ switch ( retcode )
+ {
+ case PAM_SUCCESS: return ERROR_SUCCESS;
+ case PAM_AUTH_ERR: return ERROR_ACCESS_DENIED;
+ default: return ERROR_GEN_FAILURE;
+ }
+}
+
+/******************************************************************************
+ * PAM_logon_user_conv [INTERNAL]
+ * The "PAM conversation callback" for LogonUser().
+ */
+static int PAM_logon_user_conv ( int nmsg, const struct pam_message **msg,
+ struct pam_response **resp, void *ptr )
+{
+ int i;
+ struct pam_response *myresp;
+
+ /* PAM will free myresp and the response buffers when done. */
+ myresp = malloc ( nmsg * sizeof (struct pam_response) );
+ if (!myresp) return PAM_BUF_ERR;
+ memset ( myresp, 0, nmsg * sizeof (struct pam_response) );
+
+ /* Fill in our password as "response" to the prompt we never show. */
+ for (i = 0; i < nmsg; i++)
+ {
+ if ( msg[i]->msg_style == PAM_PROMPT_ECHO_OFF )
+ {
+ myresp[i].resp = strdup (ptr);
+ break;
+ }
+ }
+ *resp = myresp;
+ return PAM_SUCCESS;
+}
+
+/******************************************************************************
+ * PAM_get_config [INTERNAL]
+ * - Read the PAM configuration from Wine config.
+ * - Servicename is a newly allocated string, must be freed by caller.
+ */
+static BOOL PAM_get_config ( char **servicename, char *separator )
+{
+ const static char keyname[] = "Software\\Wine\\Wine\\Config\\Logon";
+ const static char pamname[] = "PamServiceName";
+ const static char sepname[] = "WinbindSeparator";
+ const static char default_pam[] = "other";
+ const static char default_sep = '\\';
+ HKEY hkey;
+ DWORD ret = ERROR_NOT_ENOUGH_MEMORY;
+ LONG len = 32, slen;
+ char *buf;
+ BOOL res = FALSE;
+
+ if ( RegOpenKeyA ( HKEY_LOCAL_MACHINE, keyname, &hkey ) != ERROR_SUCCESS )
+ return FALSE;
+ buf = HeapAlloc ( GetProcessHeap(), 0, len );
+
+ while ( buf )
+ {
+ ret = RegQueryValueExA ( hkey, pamname, NULL, NULL, buf, &len );
+ if ( ret != ERROR_MORE_DATA ) break;
+ buf = HeapReAlloc ( GetProcessHeap(), 0, buf, len );
+ }
+ if ( !buf ) {
+ SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
+ goto out;
+ }
+ else if ( ret == ERROR_FILE_NOT_FOUND )
+ strcpy ( buf, default_pam );
+ else if ( ret != ERROR_SUCCESS ) goto out;
+
+ slen = strlen ( buf ) + 1;
+ *servicename = HeapAlloc ( GetProcessHeap(), 0 , slen );
+ if ( !*servicename ) {
+ SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
+ goto out;
+ }
+ memcpy ( *servicename, buf, slen );
+
+ ret = RegQueryValueExA ( hkey, sepname, NULL, NULL, buf, &len );
+ if ( ret == ERROR_SUCCESS )
+ *separator = *buf;
+ else
+ *separator = default_sep;
+ res = TRUE;
+
+out:
+ if (buf) HeapFree ( GetProcessHeap(), 0, buf );
+ RegCloseKey ( hkey );
+ return res;
+}
+
+/******************************************************************************/
+#endif /* HAVE_PAM */
+
+/******************************************************************************
+ * LogonUserA [ADVAPI32.@]
+ *
+ * PARAMS
+ * lpUserName : (IN) user name
+ * lpDomain : (IN) domain name (will only work with PAM winbind support)
+ * lpPassword : (IN) Cleartext password
+ * dwLogonType : (IN) logon type, IGNORED
+ * dwLogonProvider : (IN) login provider, IGNORED
+ * phToken : (OUT) handle to user token, BOGUS
+ *
+ * RETURNS
+ * TRUE on success.
+ */
+BOOL WINAPI LogonUserA( LPSTR lpUserName, LPSTR lpDomain, LPSTR lpPassword,
+ DWORD dwLogonType, DWORD dwLogonProvider, LPHANDLE phToken )
+{
+#if ! HAVE_PAM
+ ERR( "stub - wine needs to be compiled against PAM library\n" );
+ SetLastError ( ERROR_NOT_SUPPORTED );
+ return FALSE;
+#else
+
+ char *pam_service = NULL;
+ char winbind_separator;
+ int ret;
+ char *user = NULL;
+ struct pam_conv conv = { PAM_logon_user_conv, NULL };
+ pam_handle_t *pamh = NULL;
+
+ FIXME( "returned token handle will be bogus!\n" );
+ FIXME( "ignoring type (%lx) and provider (%lx)\n", dwLogonType, dwLogonProvider );
+ TRACE( "user %s, domain %s\n", lpUserName, lpDomain );
+
+ if ( !lpUserName || !lpPassword || !phToken )
+ {
+ SetLastError ( ERROR_INVALID_PARAMETER );
+ goto abort;
+ }
+
+ if ( !PAM_get_config ( &pam_service, &winbind_separator ) )
+ goto abort;
+
+ if ( !lpDomain )
+ /* User name is "user at DNS-name" (UPN format),
+ * but we don't know how to convert DNS to NT domain name. */
+ {
+ char *p;
+ FIXME( "UPN format unsupported - trying unqualified name\n" );
+
+ user = strdup ( lpUserName );
+ if ( ! user ) goto outofmem;
+ p = strchr ( user, '@' );
+ if ( p ) *p = '\0';
+ }
+ else if ( *lpDomain == '\0' || ! strcmp ( lpDomain, "." ) )
+ {
+ user = strdup ( lpUserName );
+ if ( ! user ) goto outofmem;
+ }
+ else
+ {
+ int ldom = strlen ( lpDomain );
+ int lusr = strlen ( lpUserName );
+ user = malloc ( ldom + lusr + 2 );
+ if ( ! user ) goto outofmem;
+ strcpy ( user, lpDomain );
+ user[ldom] = winbind_separator;
+ strcpy ( user + ldom + 1, lpUserName );
+ }
+ TRACE( "PAM sevice %s, user name: %s\n", debugstr_a (pam_service), debugstr_a (user) );
+
+ conv.appdata_ptr = lpPassword;
+ if ( PAM_FAIL( ret = pam_start ( pam_service, user, &conv, &pamh )) )
+ goto pam_error;
+ if ( PAM_FAIL( ret = pam_authenticate ( pamh, PAM_SILENT ) ) )
+ goto pam_error;
+ pam_end ( pamh, PAM_SUCCESS );
+
+ *phToken = (HANDLE) 0xcafe;
+ HeapFree ( GetProcessHeap(), 0, pam_service );
+ free ( user );
+ TRACE( "-> successful\n" );
+ return TRUE;
+
+pam_error:
+ SetLastError ( PAM_error_to_dos ( pamh, ret ) );
+ goto abort;
+
+outofmem:
+ SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
+
+abort:
+ TRACE( "-> error %lu\n", GetLastError() );
+ if ( pam_service ) HeapFree ( GetProcessHeap(), 0, pam_service );
+ if ( pamh ) pam_end ( pamh, PAM_SUCCESS );
+ if ( user ) free ( user );
+ return FALSE;
+
+#endif /* HAVE_PAM */
+}
+
+/******************************************************************************
+ * LogonUserW [ADVAPI32.@]
+ *
+ * PARAMS
+ * lpUserNameW : (IN) user name
+ * lpDomainW : (IN) domain name (will only work with PAM winbind support)
+ * lpPasswordW : (IN) Cleartext password
+ * dwLogonType : (IN) logon type, IGNORED
+ * dwLogonProvider : (IN) login provider, IGNORED
+ * phToken : (OUT) handle to user token, IGNORED
+ *
+ * RETURNS
+ * TRUE on success.
+ */
+BOOL WINAPI LogonUserW( LPWSTR lpUserNameW, LPWSTR lpDomainW, LPWSTR lpPasswordW,
+ DWORD dwLogonType, DWORD dwLogonProvider, LPHANDLE phToken )
+{
+#if ! HAVE_PAM
+ ERR( "stub - wine needs to be compiled against PAM library\n" );
+ SetLastError ( ERROR_NOT_SUPPORTED );
+ return FALSE;
+#else
+
+ int ulen = 0, dlen = 0, plen = 0, ret;
+ LPSTR buf = NULL;
+ LPSTR lpUserName, lpPassword, lpDomain;
+
+ if ( !lpUserNameW || !lpPasswordW || !phToken )
+ {
+ SetLastError ( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+
+ ulen = WideCharToMultiByte( CP_ACP, 0, lpUserNameW, -1, NULL, 0, NULL, NULL );
+ plen = WideCharToMultiByte( CP_ACP, 0, lpPasswordW, -1, NULL, 0, NULL, NULL );
+ if ( lpDomainW )
+ dlen = WideCharToMultiByte( CP_ACP, 0, lpDomainW, -1, NULL, 0, NULL, NULL );
+
+ buf = HeapAlloc ( GetProcessHeap(), 0, ulen + plen + dlen );
+ if ( !buf )
+ {
+ SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
+ return FALSE;
+ }
+
+ lpUserName = buf;
+ WideCharToMultiByte( CP_ACP, 0, lpUserNameW, -1, lpUserName, ulen, NULL, NULL );
+
+ lpPassword = buf + ulen;
+ WideCharToMultiByte( CP_ACP, 0, lpPasswordW, -1, lpPassword, plen, NULL, NULL );
+
+ if ( lpDomainW )
+ {
+ lpDomain = lpPassword + plen;
+ WideCharToMultiByte( CP_ACP, 0, lpDomainW, -1, lpDomain, dlen, NULL, NULL );
+ }
+ else lpDomain = NULL;
+
+ ret = LogonUserA( lpUserName, lpDomain, lpPassword,
+ dwLogonType, dwLogonProvider, phToken );
+
+ memset ( buf, 0, ulen + plen ); /* erase password in memory */
+ HeapFree ( GetProcessHeap(), 0, buf );
+ return ret;
+
+#endif /* HAVE_PAM */
+}
+
diff -ruNX ignore CVS/wine/documentation/configuring.sgml TMP/wine/documentation/configuring.sgml
--- CVS/wine/documentation/configuring.sgml Fri Nov 8 16:37:45 2002
+++ TMP/wine/documentation/configuring.sgml Fri Nov 8 16:34:56 2002
@@ -968,6 +968,73 @@
</variablelist>
</sect3>
+ <sect3 id="logon-section">
+ <title>The [Logon] Section</title>
+ <para>
+ [Logon] contains settings related to user authentification.
+ <emphasis>Note that Wine does not support Windows NT security
+ concepts.</emphasis> In particular, Wine processes are not allowed to
+ "change personality", and Wine relies almost exclusively
+ on its Unix environment for determining file access rights, etc.
+ </para>
+ <para>
+ The logon functionality only enables Windows
+ programs to check for a valid login name and password from within Wine.
+ It is up to the Windows or Winelib application to do
+ something useful with this information. It is up to the system
+ administrator installing Wine (that is, YOU) to make sure the
+ application can't harm anything on your Unix system.
+ <emphasis>NEVER RUN WINE AS ROOT!!</emphasis>
+ </para>
+ <para>
+ The Logon functionality is only available if Wine was compiled against
+ the PAM (Pluggable Authetification Modules) library. This library is
+ part of all recent Linux distributions.
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term>PamServiceName</term>
+ <listitem>
+ <para>
+ This is the name of the "PAM service" associated with Wine. This name
+ corresponds to the name of a file in the PAM configuration directory
+ <filename>/etc/pam.d</filename>. It defaults to the service
+ <literal>other</literal>, which normally has very restrictive access
+ rights. You can set <literal>PamServiceName</literal> e.g. to
+ <literal>login</literal> to use the same settings as for Unix
+ authentification, or you can define a special PAM service for Wine and
+ call it e.g. <literal>wine</literal>. See the PAM documentation for details.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>WinbindSeparator</term>
+ <listitem>
+ <para>
+ This setting is useful if the Unix system setup uses the
+ <literal>pam_winbind</literal> module to authenticate
+ against a Windows Primary Domain Controller (PDC).
+ It makes only sense to set this up if your Unix
+ machine is configured to use <literal>pam_winbind</literal>.
+ </para>
+ <para>
+ When a user
+ authenticates with a Windows domain name and user name, these names
+ are concatenated with this character as separator to form a pseudo Unix user
+ name. This name is then passed to PAM for authentification against the
+ PDC. It must be set to the same value as the "winbind separator" in
+ the Samba configuration file <filename>smb.conf</filename>. See
+ the <command>winbindd(8)</command> manual page for
+ details. The default value for
+ <literal>WinbindSeparator</literal> is "\\" (the
+ backslash character).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect3>
+
<sect3 id="appdefaults-section">
<title>The [AppDefaults] Section</title>
<para>
diff -ruNX ignore CVS/wine/documentation/samples/config TMP/wine/documentation/samples/config
--- CVS/wine/documentation/samples/config Fri Nov 8 16:37:45 2002
+++ TMP/wine/documentation/samples/config Fri Nov 8 15:40:12 2002
@@ -263,6 +263,15 @@
;; HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ComputerName\ComputerName, too.
;"UseDnsComputerName" = "N"
+[Logon]
+;; If you have PAM in your system, the PAM service name (file name in /etc/pam.d)
+;; to use for Wine authentication. Default: "other".
+;"PamServiceName" = "wine"
+;; Character to separate Windows domain and user name for PAM_winbind queries.
+;; Should be set to the same value as the "winbind separator" in smb.conf(5).
+;; See man page of winbindd(8). Default: "\\".
+;"WinbindSeparator" = "+"
+
;; sample AppDefaults entries
;[AppDefaults\\iexplore.exe\\DllOverrides]
;"shlwapi" = "native"
diff -ruNX ignore CVS/wine/documentation/wine.conf.man TMP/wine/documentation/wine.conf.man
--- CVS/wine/documentation/wine.conf.man Fri Nov 8 16:37:45 2002
+++ TMP/wine/documentation/wine.conf.man Fri Nov 8 16:46:36 2002
@@ -303,15 +303,29 @@
.br
Defaults are read all, write to home files.
.PP
-.B [AppDefaults\\\\\\\\<appname>\\\\\\\\...]
-.PP
.B [Network]
-.br
+.PP
.I format: """UseDnsComputerName""=""<boolean>"""
.br
If Y, always override the registry setting for ComputerName
with the Unix hostname.
.PP
+.B [Logon]
+.PP
+.I format: """PamServiceName""=""<string>"""
+.br
+default: "other".
+.br
+Name of the PAM service (file in /etc/pam.d) determining
+authentification rules for Wine.
+.br
+.PP
+.I format: """WinbindSeparator""=""<character>"""
+.br
+default: "\\\\".
+.br
+Separator between Windows domain and user name. See winbindd(8).
+.PP
.B [AppDefaults\\\\\\\\<appname>\\\\\\\\...]
.PP
This section allows specifying application-specific values for
diff -ruNX ignore CVS/wine/include/config.h.in TMP/wine/include/config.h.in
--- CVS/wine/include/config.h.in Fri Nov 8 10:45:17 2002
+++ TMP/wine/include/config.h.in Fri Nov 8 10:45:59 2002
@@ -320,6 +320,9 @@
/* Define if you have NAS including devel headers */
#undef HAVE_NAS
+/* Define if you have PAM including devel headers */
+#undef HAVE_PAM
+
/* Define to 1 if you have the <ncurses.h> header file. */
#undef HAVE_NCURSES_H
diff -ruNX ignore CVS/wine/include/winbase.h TMP/wine/include/winbase.h
--- CVS/wine/include/winbase.h Fri Nov 8 16:37:45 2002
+++ TMP/wine/include/winbase.h Fri Nov 8 10:45:59 2002
@@ -1128,6 +1128,16 @@
#define SCS_POSIX_BINARY 4
#define SCS_OS216_BINARY 5
+/* LOGON support APIs */
+#define LOGON32_LOGON_INTERACTIVE 2
+#define LOGON32_LOGON_NETWORK 3
+#define LOGON32_LOGON_BATCH 4
+#define LOGON32_LOGON_SERVICE 5
+#define LOGON32_PROVIDER_DEFAULT 0
+#define LOGON32_PROVIDER_WINNT35 1
+#define LOGON32_PROVIDER_WINNT40 2
+#define LOGON32_PROVIDER_WINNT50 3
+
BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType );
BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType );
#define GetBinaryType WINELIB_NAME_AW(GetBinaryType)
@@ -1375,6 +1385,9 @@
BOOL WINAPI ImpersonateLoggedOnUser(HANDLE);
BOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL);
BOOL WINAPI IsProcessorFeaturePresent(DWORD);
+BOOL WINAPI LogonUserA(LPSTR,LPSTR,LPSTR,DWORD,DWORD,PHANDLE);
+BOOL WINAPI LogonUserW(LPWSTR,LPWSTR,LPWSTR,DWORD,DWORD,PHANDLE);
+#define LogonUser WINELIB_NAME_AW(LogonUser)
BOOL WINAPI LookupAccountSidA(LPCSTR,PSID,LPSTR,LPDWORD,LPSTR,LPDWORD,PSID_NAME_USE);
BOOL WINAPI LookupAccountSidW(LPCWSTR,PSID,LPWSTR,LPDWORD,LPWSTR,LPDWORD,PSID_NAME_USE);
#define LookupAccountSid WINELIB_NAME_AW(LookupAccountSid)
More information about the wine-patches
mailing list