From: Gé van Geldorp Date: Sun, 20 Nov 2005 21:19:17 +0000 (+0000) Subject: New netapi32 vendor import X-Git-Tag: backups/ros-branch-0_2_9@19949~532 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=80b04bfdd60bd04674b70e389e7497707fade1b2 New netapi32 vendor import svn path=/trunk/; revision=19391 --- diff --git a/reactos/include/wine/lmbrowsr.h b/reactos/include/wine/lmbrowsr.h new file mode 100644 index 00000000000..9e6abf632ca --- /dev/null +++ b/reactos/include/wine/lmbrowsr.h @@ -0,0 +1,47 @@ +/* + * Copyright 2002 Andriy Palamarchuk + * + * Browser NET API calls + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_LMBROWSR_H +#define __WINE_LMBROWSR_H + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _BROWSER_EMULATED_DOMAIN { + LPWSTR DomainName; + LPWSTR EmulatedServerName; + DWORD Role; +} BROWSER_EMULATED_DOMAIN, *PBROWSER_EMULATED_DOMAIN; + +NET_API_STATUS WINAPI I_BrowserSetNetlogonState( + LPWSTR ServerName, LPWSTR DomainName, LPWSTR EmulatedServerName, + DWORD Role); + +NET_API_STATUS WINAPI I_BrowserQueryEmulatedDomains( + LPWSTR ServerName, PBROWSER_EMULATED_DOMAIN *EmulatedDomains, + LPDWORD EntriesRead); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/reactos/lib/aclui/precomp.h b/reactos/lib/aclui/precomp.h index 1581d31421e..ce0f130294d 100644 --- a/reactos/lib/aclui/precomp.h +++ b/reactos/lib/aclui/precomp.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #if SUPPORT_UXTHEME #include diff --git a/reactos/lib/directory.xml b/reactos/lib/directory.xml index b5e9e30ab4a..4ce3571dab0 100644 --- a/reactos/lib/directory.xml +++ b/reactos/lib/directory.xml @@ -176,6 +176,9 @@ + + + diff --git a/reactos/lib/netapi32/access.c b/reactos/lib/netapi32/access.c new file mode 100644 index 00000000000..e3e0a36a74d --- /dev/null +++ b/reactos/lib/netapi32/access.c @@ -0,0 +1,580 @@ +/* + * Copyright 2002 Andriy Palamarchuk + * + * netapi32 access functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "lmcons.h" +#include "lmaccess.h" +#include "lmapibuf.h" +#include "lmerr.h" +#include "netapi32_misc.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netapi32); + +static const WCHAR sAdminUserName[] = {'A','d','m','i','n','i','s','t','r','a','t', + 'o','r',0}; +static const WCHAR sGuestUserName[] = {'G','u','e','s','t',0}; + +/************************************************************ + * NETAPI_ValidateServername + * + * Validates server name + */ +static NET_API_STATUS NETAPI_ValidateServername(LPCWSTR ServerName) +{ + if (ServerName) + { + if (ServerName[0] == 0) + return ERROR_BAD_NETPATH; + else if ( + ((ServerName[0] == '\\') && + (ServerName[1] != '\\')) + || + ((ServerName[0] == '\\') && + (ServerName[1] == '\\') && + (ServerName[2] == 0)) + ) + return ERROR_INVALID_NAME; + } + return NERR_Success; +} + +/************************************************************ + * NETAPI_IsKnownUser + * + * Checks whether the user name indicates current user. + */ +static BOOL NETAPI_IsKnownUser(LPCWSTR UserName) +{ + DWORD dwSize = UNLEN + 1; + BOOL Result; + LPWSTR buf; + + if (!lstrcmpW(UserName, sAdminUserName) || + !lstrcmpW(UserName, sGuestUserName)) + return TRUE; + NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) &buf); + Result = GetUserNameW(buf, &dwSize); + + Result = Result && !lstrcmpW(UserName, buf); + NetApiBufferFree(buf); + + return Result; +} + +#define NETAPI_ForceKnownUser(UserName, FailureCode) \ + if (!NETAPI_IsKnownUser(UserName)) \ + { \ + FIXME("Can't find information for user %s\n", \ + debugstr_w(UserName)); \ + return FailureCode; \ + } + +/************************************************************ + * NetUserAdd (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetUserAdd(LPCWSTR servername, + DWORD level, LPBYTE bufptr, LPDWORD parm_err) +{ + NET_API_STATUS status; + FIXME("(%s, %ld, %p, %p) stub!\n", debugstr_w(servername), level, bufptr, parm_err); + + status = NETAPI_ValidateServername(servername); + if (status != NERR_Success) + return status; + + if ((bufptr != NULL) && (level > 0) && (level <= 4)) + { + PUSER_INFO_1 ui = (PUSER_INFO_1) bufptr; + TRACE("usri%ld_name: %s\n", level, debugstr_w(ui->usri1_name)); + TRACE("usri%ld_password: %s\n", level, debugstr_w(ui->usri1_password)); + TRACE("usri%ld_comment: %s\n", level, debugstr_w(ui->usri1_comment)); + } + return status; +} + +/************************************************************ + * NetUserDel (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetUserDel(LPCWSTR servername, LPCWSTR username) +{ + NET_API_STATUS status; + FIXME("(%s, %s) stub!\n", debugstr_w(servername), debugstr_w(username)); + + status = NETAPI_ValidateServername(servername); + if (status != NERR_Success) + return status; + + if (!NETAPI_IsKnownUser(username)) + return NERR_UserNotFound; + + /* Delete the user here */ + return status; +} + +/************************************************************ + * NetUserGetInfo (NETAPI32.@) + */ +NET_API_STATUS WINAPI +NetUserGetInfo(LPCWSTR servername, LPCWSTR username, DWORD level, + LPBYTE* bufptr) +{ + NET_API_STATUS status; + TRACE("(%s, %s, %ld, %p)\n", debugstr_w(servername), debugstr_w(username), + level, bufptr); + status = NETAPI_ValidateServername(servername); + if (status != NERR_Success) + return status; + NETAPI_ForceLocalComputer(servername, NERR_InvalidComputer); + NETAPI_ForceKnownUser(username, NERR_UserNotFound); + + switch (level) + { + case 0: + { + PUSER_INFO_0 ui; + int name_sz; + + name_sz = lstrlenW(username) + 1; + + /* set up buffer */ + NetApiBufferAllocate(sizeof(USER_INFO_0) + name_sz * sizeof(WCHAR), + (LPVOID *) bufptr); + + ui = (PUSER_INFO_0) *bufptr; + ui->usri0_name = (LPWSTR) (*bufptr + sizeof(USER_INFO_0)); + + /* get data */ + lstrcpyW(ui->usri0_name, username); + break; + } + + case 10: + { + PUSER_INFO_10 ui; + PUSER_INFO_0 ui0; + NET_API_STATUS status; + /* sizes of the field buffers in WCHARS */ + int name_sz, comment_sz, usr_comment_sz, full_name_sz; + + comment_sz = 1; + usr_comment_sz = 1; + full_name_sz = 1; + + /* get data */ + status = NetUserGetInfo(servername, username, 0, (LPBYTE *) &ui0); + if (status != NERR_Success) + { + NetApiBufferFree(ui0); + return status; + } + name_sz = lstrlenW(ui0->usri0_name) + 1; + + /* set up buffer */ + NetApiBufferAllocate(sizeof(USER_INFO_10) + + (name_sz + comment_sz + usr_comment_sz + + full_name_sz) * sizeof(WCHAR), + (LPVOID *) bufptr); + ui = (PUSER_INFO_10) *bufptr; + ui->usri10_name = (LPWSTR) (*bufptr + sizeof(USER_INFO_10)); + ui->usri10_comment = (LPWSTR) ( + ((PBYTE) ui->usri10_name) + name_sz * sizeof(WCHAR)); + ui->usri10_usr_comment = (LPWSTR) ( + ((PBYTE) ui->usri10_comment) + comment_sz * sizeof(WCHAR)); + ui->usri10_full_name = (LPWSTR) ( + ((PBYTE) ui->usri10_usr_comment) + usr_comment_sz * sizeof(WCHAR)); + + /* set data */ + lstrcpyW(ui->usri10_name, ui0->usri0_name); + NetApiBufferFree(ui0); + ui->usri10_comment[0] = 0; + ui->usri10_usr_comment[0] = 0; + ui->usri10_full_name[0] = 0; + break; + } + + case 1: + { + static const WCHAR homedirW[] = {'H','O','M','E',0}; + PUSER_INFO_1 ui; + PUSER_INFO_0 ui0; + NET_API_STATUS status; + /* sizes of the field buffers in WCHARS */ + int name_sz, password_sz, home_dir_sz, comment_sz, script_path_sz; + + password_sz = 1; /* not filled out for security reasons for NetUserGetInfo*/ + comment_sz = 1; + script_path_sz = 1; + + /* get data */ + status = NetUserGetInfo(servername, username, 0, (LPBYTE *) &ui0); + if (status != NERR_Success) + { + NetApiBufferFree(ui0); + return status; + } + name_sz = lstrlenW(ui0->usri0_name) + 1; + home_dir_sz = GetEnvironmentVariableW(homedirW, NULL,0); + /* set up buffer */ + NetApiBufferAllocate(sizeof(USER_INFO_1) + + (name_sz + password_sz + home_dir_sz + + comment_sz + script_path_sz) * sizeof(WCHAR), + (LPVOID *) bufptr); + + ui = (PUSER_INFO_1) *bufptr; + ui->usri1_name = (LPWSTR) (ui + 1); + ui->usri1_password = ui->usri1_name + name_sz; + ui->usri1_home_dir = ui->usri1_password + password_sz; + ui->usri1_comment = ui->usri1_home_dir + home_dir_sz; + ui->usri1_script_path = ui->usri1_comment + comment_sz; + /* set data */ + lstrcpyW(ui->usri1_name, ui0->usri0_name); + NetApiBufferFree(ui0); + ui->usri1_password[0] = 0; + ui->usri1_password_age = 0; + ui->usri1_priv = 0; + GetEnvironmentVariableW(homedirW, ui->usri1_home_dir,home_dir_sz); + ui->usri1_comment[0] = 0; + ui->usri1_flags = 0; + ui->usri1_script_path[0] = 0; + break; + } + case 2: + case 3: + case 4: + case 11: + case 20: + case 23: + case 1003: + case 1005: + case 1006: + case 1007: + case 1008: + case 1009: + case 1010: + case 1011: + case 1012: + case 1013: + case 1014: + case 1017: + case 1018: + case 1020: + case 1023: + case 1024: + case 1025: + case 1051: + case 1052: + case 1053: + { + FIXME("Level %ld is not implemented\n", level); + break; + } + default: + ERR("Invalid level %ld is specified\n", level); + return ERROR_INVALID_LEVEL; + } + return NERR_Success; +} + + + +/************************************************************ + * NetUserEnum (NETAPI32.@) + */ +NET_API_STATUS WINAPI +NetUserEnum(LPCWSTR servername, DWORD level, DWORD filter, LPBYTE* bufptr, + DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries, + LPDWORD resume_handle) +{ + FIXME("(%s,%ld, 0x%ld,%p,%ld,%p,%p,%p) stub!\n", debugstr_w(servername), level, + filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle); + + return ERROR_ACCESS_DENIED; +} + +/************************************************************ + * ACCESS_QueryAdminDisplayInformation + * + * Creates a buffer with information for the Admin User + */ +static void ACCESS_QueryAdminDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize) +{ + static const WCHAR sAdminUserName[] = { + 'A','d','m','i','n','i','s','t','r','a','t','o','r',0}; + + /* sizes of the field buffers in WCHARS */ + int name_sz, comment_sz, full_name_sz; + PNET_DISPLAY_USER usr; + + /* set up buffer */ + name_sz = lstrlenW(sAdminUserName); + comment_sz = 1; + full_name_sz = 1; + + *pdwSize = sizeof(NET_DISPLAY_USER); + *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR); + NetApiBufferAllocate(*pdwSize, (LPVOID *) buf); + + usr = *buf; + usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER)); + usr->usri1_comment = (LPWSTR) ( + ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR)); + usr->usri1_full_name = (LPWSTR) ( + ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR)); + + /* set data */ + lstrcpyW(usr->usri1_name, sAdminUserName); + usr->usri1_comment[0] = 0; + usr->usri1_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD; + usr->usri1_full_name[0] = 0; + usr->usri1_user_id = 500; + usr->usri1_next_index = 0; +} + +/************************************************************ + * ACCESS_QueryGuestDisplayInformation + * + * Creates a buffer with information for the Guest User + */ +static void ACCESS_QueryGuestDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize) +{ + static const WCHAR sGuestUserName[] = { + 'G','u','e','s','t',0 }; + + /* sizes of the field buffers in WCHARS */ + int name_sz, comment_sz, full_name_sz; + PNET_DISPLAY_USER usr; + + /* set up buffer */ + name_sz = lstrlenW(sGuestUserName); + comment_sz = 1; + full_name_sz = 1; + + *pdwSize = sizeof(NET_DISPLAY_USER); + *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR); + NetApiBufferAllocate(*pdwSize, (LPVOID *) buf); + + usr = *buf; + usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER)); + usr->usri1_comment = (LPWSTR) ( + ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR)); + usr->usri1_full_name = (LPWSTR) ( + ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR)); + + /* set data */ + lstrcpyW(usr->usri1_name, sGuestUserName); + usr->usri1_comment[0] = 0; + usr->usri1_flags = UF_ACCOUNTDISABLE | UF_SCRIPT | UF_NORMAL_ACCOUNT | + UF_DONT_EXPIRE_PASSWD; + usr->usri1_full_name[0] = 0; + usr->usri1_user_id = 500; + usr->usri1_next_index = 0; +} + +/************************************************************ + * NetQueryDisplayInformation (NETAPI32.@) + * Copies NET_DISPLAY_USER record. + */ +static void ACCESS_CopyDisplayUser(PNET_DISPLAY_USER dest, LPWSTR *dest_buf, + PNET_DISPLAY_USER src) +{ + LPWSTR str = *dest_buf; + + src->usri1_name = str; + lstrcpyW(src->usri1_name, dest->usri1_name); + str = (LPWSTR) ( + ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR)); + + src->usri1_comment = str; + lstrcpyW(src->usri1_comment, dest->usri1_comment); + str = (LPWSTR) ( + ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR)); + + src->usri1_flags = dest->usri1_flags; + + src->usri1_full_name = str; + lstrcpyW(src->usri1_full_name, dest->usri1_full_name); + str = (LPWSTR) ( + ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR)); + + src->usri1_user_id = dest->usri1_user_id; + src->usri1_next_index = dest->usri1_next_index; + *dest_buf = str; +} + +/************************************************************ + * NetQueryDisplayInformation (NETAPI32.@) + * + * The buffer structure: + * - array of fixed size record of the level type + * - strings, referenced by the record of the level type + */ +NET_API_STATUS WINAPI +NetQueryDisplayInformation( + LPCWSTR ServerName, DWORD Level, DWORD Index, DWORD EntriesRequested, + DWORD PreferredMaximumLength, LPDWORD ReturnedEntryCount, + PVOID *SortedBuffer) +{ + TRACE("(%s, %ld, %ld, %ld, %ld, %p, %p)\n", debugstr_w(ServerName), + Level, Index, EntriesRequested, PreferredMaximumLength, + ReturnedEntryCount, SortedBuffer); + NETAPI_ForceLocalComputer(ServerName, ERROR_ACCESS_DENIED); + switch (Level) + { + case 1: + { + /* current record */ + PNET_DISPLAY_USER inf; + /* current available strings buffer */ + LPWSTR str; + PNET_DISPLAY_USER admin, guest; + DWORD admin_size, guest_size; + LPWSTR name = NULL; + DWORD dwSize; + + /* sizes of the field buffers in WCHARS */ + int name_sz, comment_sz, full_name_sz; + + /* number of the records, returned in SortedBuffer + 3 - for current user, Administrator and Guest users + */ + int records = 3; + + FIXME("Level %ld partially implemented\n", Level); + *ReturnedEntryCount = records; + comment_sz = 1; + full_name_sz = 1; + + /* get data */ + dwSize = UNLEN + 1; + NetApiBufferAllocate(dwSize, (LPVOID *) &name); + if (!GetUserNameW(name, &dwSize)) + { + NetApiBufferFree(name); + return ERROR_ACCESS_DENIED; + } + name_sz = dwSize; + ACCESS_QueryAdminDisplayInformation(&admin, &admin_size); + ACCESS_QueryGuestDisplayInformation(&guest, &guest_size); + + /* set up buffer */ + dwSize = sizeof(NET_DISPLAY_USER) * records; + dwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR); + + NetApiBufferAllocate(dwSize + + admin_size - sizeof(NET_DISPLAY_USER) + + guest_size - sizeof(NET_DISPLAY_USER), + (LPVOID *) SortedBuffer); + inf = (PNET_DISPLAY_USER) *SortedBuffer; + str = (LPWSTR) ((PBYTE) inf + sizeof(NET_DISPLAY_USER) * records); + inf->usri1_name = str; + str = (LPWSTR) ( + ((PBYTE) str) + name_sz * sizeof(WCHAR)); + inf->usri1_comment = str; + str = (LPWSTR) ( + ((PBYTE) str) + comment_sz * sizeof(WCHAR)); + inf->usri1_full_name = str; + str = (LPWSTR) ( + ((PBYTE) str) + full_name_sz * sizeof(WCHAR)); + + /* set data */ + lstrcpyW(inf->usri1_name, name); + NetApiBufferFree(name); + inf->usri1_comment[0] = 0; + inf->usri1_flags = + UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD; + inf->usri1_full_name[0] = 0; + inf->usri1_user_id = 0; + inf->usri1_next_index = 0; + + inf++; + ACCESS_CopyDisplayUser(admin, &str, inf); + NetApiBufferFree(admin); + + inf++; + ACCESS_CopyDisplayUser(guest, &str, inf); + NetApiBufferFree(guest); + break; + } + + case 2: + case 3: + { + FIXME("Level %ld is not implemented\n", Level); + break; + } + + default: + ERR("Invalid level %ld is specified\n", Level); + return ERROR_INVALID_LEVEL; + } + return NERR_Success; +} + +/************************************************************ + * NetGetDCName (NETAPI32.@) + * + * Return the name of the primary domain controller (PDC) + */ + +NET_API_STATUS WINAPI +NetGetDCName(LPCWSTR servername, LPCWSTR domainname, LPBYTE *bufptr) +{ + FIXME("(%s, %s, %p) stub!\n", debugstr_w(servername), + debugstr_w(domainname), bufptr); + return NERR_DCNotFound; /* say we can't find a domain controller */ +} + + +/************************************************************ + * NetUserModalsGet (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetUserModalsGet(LPCWSTR szServer, DWORD level, LPBYTE *pbuffer) +{ + FIXME("(%s %ld %p) stub!\n", debugstr_w(szServer), level, pbuffer); + return NERR_InternalError; +} + +/************************************************************ + * NetLocalGroupAdd (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetLocalGroupAdd(LPCWSTR servername, DWORD level, + LPBYTE buf, LPDWORD parm_err) +{ + FIXME("(%s %ld %p %p) stub!\n", debugstr_w(servername), level, buf, parm_err); + return NERR_Success; +} + +/************************************************************ + * NetLocalGroupSetMember (NETAPI32.@) + */ + +NET_API_STATUS WINAPI NetLocalGroupSetMembers(LPCWSTR servername, + LPCWSTR groupname, DWORD level, LPBYTE buf, DWORD totalentries) +{ + FIXME("(%s %s %ld %p %ld) stub!\n", debugstr_w(servername), + debugstr_w(groupname),level, buf, totalentries); + return NERR_Success; +} diff --git a/reactos/lib/netapi32/apibuf.c b/reactos/lib/netapi32/apibuf.c new file mode 100644 index 00000000000..6a8b8db1bde --- /dev/null +++ b/reactos/lib/netapi32/apibuf.c @@ -0,0 +1,97 @@ +/* + * Copyright 2002 Andriy Palamarchuk + * + * Net API buffer calls + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "lmcons.h" +#include "lmapibuf.h" +#include "lmerr.h" +#include "winerror.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netapi32); + +/************************************************************ + * NetApiBufferAllocate (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetApiBufferAllocate(DWORD ByteCount, LPVOID* Buffer) +{ + TRACE("(%ld, %p)\n", ByteCount, Buffer); + *Buffer = HeapAlloc(GetProcessHeap(), 0, ByteCount); + if (*Buffer) + return NERR_Success; + else + return GetLastError(); +} + +/************************************************************ + * NetApiBufferFree (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetApiBufferFree(LPVOID Buffer) +{ + TRACE("(%p)\n", Buffer); + HeapFree(GetProcessHeap(), 0, Buffer); + return NERR_Success; +} + +/************************************************************ + * NetApiBufferReallocate (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetApiBufferReallocate(LPVOID OldBuffer, DWORD NewByteCount, + LPVOID* NewBuffer) +{ + TRACE("(%p, %ld, %p)\n", OldBuffer, NewByteCount, NewBuffer); + if (NewByteCount) + { + if (OldBuffer) + *NewBuffer = HeapReAlloc(GetProcessHeap(), 0, OldBuffer, NewByteCount); + else + *NewBuffer = HeapAlloc(GetProcessHeap(), 0, NewByteCount); + return *NewBuffer ? NERR_Success : GetLastError(); + } + else + { + if (!HeapFree(GetProcessHeap(), 0, OldBuffer)) return GetLastError(); + *NewBuffer = 0; + return NERR_Success; + } +} + +/************************************************************ + * NetApiBufferSize (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetApiBufferSize(LPVOID Buffer, LPDWORD ByteCount) +{ + DWORD dw; + + TRACE("(%p, %p)\n", Buffer, ByteCount); + if (Buffer == NULL) + return ERROR_INVALID_PARAMETER; + dw = HeapSize(GetProcessHeap(), 0, Buffer); + TRACE("size: %ld\n", dw); + if (dw != 0xFFFFFFFF) + *ByteCount = dw; + else + *ByteCount = 0; + + return NERR_Success; +} diff --git a/reactos/lib/netapi32/browsr.c b/reactos/lib/netapi32/browsr.c new file mode 100644 index 00000000000..3cda17ec7c8 --- /dev/null +++ b/reactos/lib/netapi32/browsr.c @@ -0,0 +1,61 @@ +/* + * Copyright 2002 Andriy Palamarchuk + * + * netapi32 browser functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "lmcons.h" +#include "lmbrowsr.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netapi32); + +/************************************************************ + * I_BrowserSetNetlogonState (NETAPI32.@) + */ +NET_API_STATUS WINAPI I_BrowserSetNetlogonState( + LPWSTR ServerName, LPWSTR DomainName, LPWSTR EmulatedServerName, + DWORD Role) +{ + return ERROR_NOT_SUPPORTED; +} + +/************************************************************ + * I_BrowserQueryEmulatedDomains (NETAPI32.@) + */ +NET_API_STATUS WINAPI I_BrowserQueryEmulatedDomains( + LPWSTR ServerName, PBROWSER_EMULATED_DOMAIN *EmulatedDomains, + LPDWORD EntriesRead) +{ + return ERROR_NOT_SUPPORTED; +} + +/************************************************************ + * NetShareEnum (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetShareEnum( LPWSTR servername, DWORD level, LPBYTE* bufptr, + DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries, LPDWORD resume_handle) +{ + FIXME("%s %ld %p %ld %p %p %p\n", debugstr_w(servername), level, bufptr, + prefmaxlen, entriesread, totalentries, resume_handle); + return ERROR_NOT_SUPPORTED; +} diff --git a/reactos/lib/netapi32/nbcmdqueue.c b/reactos/lib/netapi32/nbcmdqueue.c new file mode 100644 index 00000000000..d8948f79e3d --- /dev/null +++ b/reactos/lib/netapi32/nbcmdqueue.c @@ -0,0 +1,199 @@ +/* Copyright (c) 2003 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" +#include "wine/debug.h" +#include "nbcmdqueue.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netbios); + +struct NBCmdQueue +{ + HANDLE heap; + CRITICAL_SECTION cs; + PNCB head; +}; + +#define CANCEL_EVENT_PTR(ncb) (PHANDLE)((ncb)->ncb_reserve) +#define NEXT_PTR(ncb) (PNCB *)((ncb)->ncb_reserve + sizeof(HANDLE)) + +/* The reserved area of an ncb will be used for the following data: + * - a cancelled flag (BOOL, 4 bytes??) + * - a handle to an event that's set by a cancelled command on completion + * (HANDLE, 4 bytes) + * These members are used in the following way + * - on cancel, set the event member of the reserved field (with create event) + * - NBCmdComplete will delete the ncb from the queue of there's no event; + * otherwise it will set the event and not delete the ncb + * - cancel must lock the queue before finding the ncb in it, and can unlock it + * once it's set the event (and the cancelled flag) + * - NBCmdComplete must lock the queue before attempting to remove the ncb or + * check the event + * - NBCmdQueueCancelAll will lock the queue, and cancel all ncb's in the queue. + * It'll then unlock the queue, and wait on the event in the head of the queue + * until there's no more ncb's in the queue. + * Space optimization: use the handle as a boolean. NULL == 0 => not cancelled. + * Non-NULL == valid handle => cancelled. This allows storing a next pointer + * in the ncb's reserved field as well, avoiding a memory alloc for a new + * command (cool). + */ + +struct NBCmdQueue *NBCmdQueueCreate(HANDLE heap) +{ + struct NBCmdQueue *queue; + + if (heap == NULL) + heap = GetProcessHeap(); + queue = HeapAlloc(heap, 0, sizeof(struct NBCmdQueue)); + if (queue) + { + queue->heap = heap; + InitializeCriticalSection(&queue->cs); + queue->head = NULL; + } + return queue; +} + +UCHAR NBCmdQueueAdd(struct NBCmdQueue *queue, PNCB ncb) +{ + UCHAR ret; + + TRACE(": queue %p, ncb %p\n", queue, ncb); + + if (!queue) + return NRC_BADDR; + if (!ncb) + return NRC_INVADDRESS; + + *CANCEL_EVENT_PTR(ncb) = NULL; + EnterCriticalSection(&queue->cs); + *NEXT_PTR(ncb) = queue->head; + queue->head = ncb; + ret = NRC_GOODRET; + LeaveCriticalSection(&queue->cs); + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static PNCB *NBCmdQueueFindNBC(struct NBCmdQueue *queue, PNCB ncb) +{ + PNCB *ret; + + if (!queue || !ncb) + ret = NULL; + else + { + ret = &queue->head; + while (ret && *ret != ncb) + ret = NEXT_PTR(*ret); + } + return ret; +} + +UCHAR NBCmdQueueCancel(struct NBCmdQueue *queue, PNCB ncb) +{ + UCHAR ret; + PNCB *spot; + + TRACE(": queue %p, ncb %p\n", queue, ncb); + + if (!queue) + return NRC_BADDR; + if (!ncb) + return NRC_INVADDRESS; + + EnterCriticalSection(&queue->cs); + spot = NBCmdQueueFindNBC(queue, ncb); + if (spot) + { + *CANCEL_EVENT_PTR(*spot) = CreateEventW(NULL, FALSE, FALSE, NULL); + WaitForSingleObject(*CANCEL_EVENT_PTR(*spot), INFINITE); + CloseHandle(*CANCEL_EVENT_PTR(*spot)); + *spot = *NEXT_PTR(*spot); + if (ncb->ncb_retcode == NRC_CMDCAN) + ret = NRC_CMDCAN; + else + ret = NRC_CANOCCR; + } + else + ret = NRC_INVADDRESS; + LeaveCriticalSection(&queue->cs); + TRACE("returning 0x%02x\n", ret); + return ret; +} + +UCHAR NBCmdQueueComplete(struct NBCmdQueue *queue, PNCB ncb, UCHAR retcode) +{ + UCHAR ret; + PNCB *spot; + + TRACE(": queue %p, ncb %p\n", queue, ncb); + + if (!queue) + return NRC_BADDR; + if (!ncb) + return NRC_INVADDRESS; + + EnterCriticalSection(&queue->cs); + spot = NBCmdQueueFindNBC(queue, ncb); + if (spot) + { + if (*CANCEL_EVENT_PTR(*spot)) + SetEvent(*CANCEL_EVENT_PTR(*spot)); + else + *spot = *NEXT_PTR(*spot); + ret = NRC_GOODRET; + } + else + ret = NRC_INVADDRESS; + LeaveCriticalSection(&queue->cs); + TRACE("returning 0x%02x\n", ret); + return ret; +} + +UCHAR NBCmdQueueCancelAll(struct NBCmdQueue *queue) +{ + UCHAR ret; + + TRACE(": queue %p\n", queue); + + if (!queue) + return NRC_BADDR; + + EnterCriticalSection(&queue->cs); + while (queue->head) + { + TRACE(": waiting for ncb %p (command 0x%02x)\n", queue->head, + queue->head->ncb_command); + NBCmdQueueCancel(queue, queue->head); + } + LeaveCriticalSection(&queue->cs); + ret = NRC_GOODRET; + TRACE("returning 0x%02x\n", ret); + return ret; +} + +void NBCmdQueueDestroy(struct NBCmdQueue *queue) +{ + TRACE(": queue %p\n", queue); + + if (queue) + { + NBCmdQueueCancelAll(queue); + DeleteCriticalSection(&queue->cs); + HeapFree(queue->heap, 0, queue); + } +} diff --git a/reactos/lib/netapi32/nbcmdqueue.h b/reactos/lib/netapi32/nbcmdqueue.h new file mode 100644 index 00000000000..f06f95b539e --- /dev/null +++ b/reactos/lib/netapi32/nbcmdqueue.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2003 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __NBCMDQUEUE_H__ +#define __NBCMDQUEUE_H__ + +#include +#include "windef.h" +#include "winbase.h" +#include "nb30.h" + +/* This file defines a queue of pending NetBIOS commands. The queue operations + * are thread safe, with the exception of NBCmdQueueDestroy: ensure no other + * threads are manipulating the queue when calling NBCmdQueueDestroy. + */ + +struct NBCmdQueue; + +/* Allocates a new command queue from heap. */ +struct NBCmdQueue *NBCmdQueueCreate(HANDLE heap); + +/* Adds ncb to queue. Assumes queue is not NULL, and ncb is not already in the + * queue. If ncb is already in the queue, returns NRC_TOOMANY. + */ +UCHAR NBCmdQueueAdd(struct NBCmdQueue *queue, PNCB ncb); + +/* Cancels the given ncb. Blocks until the command completes. Implicitly + * removes ncb from the queue. Assumes queue and ncb are not NULL, and that + * ncb has been added to queue previously. + * Returns NRC_CMDCAN on a successful cancellation, NRC_CMDOCCR if the command + * completed before it could be cancelled, and various other return values for + * different failures. + */ +UCHAR NBCmdQueueCancel(struct NBCmdQueue *queue, PNCB ncb); + +/* Sets the return code of the given ncb, and implicitly removes the command + * from the queue. Assumes queue and ncb are not NULL, and that ncb has been + * added to queue previously. + * Returns NRC_GOODRET on success. + */ +UCHAR NBCmdQueueComplete(struct NBCmdQueue *queue, PNCB ncb, UCHAR retcode); + +/* Cancels all pending commands in the queue (useful for a RESET or a shutdown). + * Returns when all commands have been completed. + */ +UCHAR NBCmdQueueCancelAll(struct NBCmdQueue *queue); + +/* Frees all memory associated with the queue. Blocks until all commands + * pending in the queue have been completed. + */ +void NBCmdQueueDestroy(struct NBCmdQueue *queue); + +#endif /* __NBCMDQUEUE_H__ */ diff --git a/reactos/lib/netapi32/nbnamecache.c b/reactos/lib/netapi32/nbnamecache.c new file mode 100644 index 00000000000..1fdb70553d4 --- /dev/null +++ b/reactos/lib/netapi32/nbnamecache.c @@ -0,0 +1,215 @@ +/* Copyright (c) 2003 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This implementation uses a linked list, because I don't have a decent + * hash table implementation handy. This is somewhat inefficient, but it's + * rather more efficient than not having a name cache at all. + */ + +#include "config.h" +#include "wine/port.h" +#include "wine/debug.h" + +#include "nbnamecache.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netbios); + +typedef struct _NBNameCacheNode +{ + DWORD expireTime; + NBNameCacheEntry *entry; + struct _NBNameCacheNode *next; +} NBNameCacheNode; + +struct NBNameCache +{ + HANDLE heap; + CRITICAL_SECTION cs; + DWORD entryExpireTimeMS; + NBNameCacheNode *head; +}; + +/* Unlinks the node pointed to by *prev, and frees any associated memory. + * If that node's next pointed to another node, *prev now points to it. + * Assumes the caller owns cache's lock. + */ +static void NBNameCacheUnlinkNode(struct NBNameCache *cache, + NBNameCacheNode **prev) +{ + if (cache && prev && *prev) + { + NBNameCacheNode *next = (*prev)->next; + + HeapFree(cache->heap, 0, (*prev)->entry); + HeapFree(cache->heap, 0, *prev); + *prev = next; + } +} + +/* Walks the list beginning with cache->head looking for the node with name + * name. If the node is found, returns a pointer to the next pointer of the + * node _prior_ to the found node (or head if head points to it). Thus, if the + * node's all you want, dereference the return value twice. If you want to + * modify the list, modify the referent of the return value. + * While it's at it, deletes nodes whose time has expired (except the node + * you're looking for, of course). + * Returns NULL if the node isn't found. + * Assumes the caller owns cache's lock. + */ +static NBNameCacheNode **NBNameCacheWalk(struct NBNameCache *cache, + const char name[NCBNAMSZ]) +{ + NBNameCacheNode **ret = NULL; + + if (cache && cache->head) + { + NBNameCacheNode **ptr; + + ptr = &cache->head; + while (ptr && *ptr && (*ptr)->entry) + { + if (!memcmp((*ptr)->entry->name, name, NCBNAMSZ - 1)) + ret = ptr; + else + { + if (GetTickCount() > (*ptr)->expireTime) + NBNameCacheUnlinkNode(cache, ptr); + } + if (*ptr) + ptr = &(*ptr)->next; + } + } + return ret; +} + +struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS) +{ + struct NBNameCache *cache; + + + if (!heap) + heap = GetProcessHeap(); + cache = HeapAlloc(heap, 0, sizeof(struct NBNameCache)); + if (cache) + { + cache->heap = heap; + InitializeCriticalSection(&cache->cs); + cache->entryExpireTimeMS = entryExpireTimeMS; + cache->head = NULL; + } + return cache; +} + +BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry) +{ + BOOL ret; + + if (cache && entry) + { + NBNameCacheNode **node; + + EnterCriticalSection(&cache->cs); + node = NBNameCacheWalk(cache, (char*)entry->name); + if (node) + { + (*node)->expireTime = GetTickCount() + + cache->entryExpireTimeMS; + HeapFree(cache->heap, 0, (*node)->entry); + (*node)->entry = entry; + ret = TRUE; + } + else + { + NBNameCacheNode *newNode = HeapAlloc(cache->heap, 0, sizeof(NBNameCacheNode)); + if (newNode) + { + newNode->expireTime = GetTickCount() + + cache->entryExpireTimeMS; + newNode->entry = entry; + newNode->next = cache->head; + cache->head = newNode; + ret = TRUE; + } + else + ret = FALSE; + } + LeaveCriticalSection(&cache->cs); + } + else + ret = FALSE; + return ret; +} + +const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache, + const UCHAR name[NCBNAMSZ]) +{ + const NBNameCacheEntry *ret; + UCHAR printName[NCBNAMSZ]; + + memcpy(printName, name, NCBNAMSZ - 1); + printName[NCBNAMSZ - 1] = '\0'; + if (cache) + { + NBNameCacheNode **node; + + EnterCriticalSection(&cache->cs); + node = NBNameCacheWalk(cache, (char*)name); + if (node) + ret = (*node)->entry; + else + ret = NULL; + LeaveCriticalSection(&cache->cs); + } + else + ret = NULL; + return ret; +} + +BOOL NBNameCacheUpdateNBName(struct NBNameCache *cache, + const UCHAR name[NCBNAMSZ], const UCHAR nbname[NCBNAMSZ]) +{ + BOOL ret; + + if (cache) + { + NBNameCacheNode **node; + + EnterCriticalSection(&cache->cs); + node = NBNameCacheWalk(cache, (char*)name); + if (node && *node && (*node)->entry) + { + memcpy((*node)->entry->nbname, nbname, NCBNAMSZ); + ret = TRUE; + } + else + ret = FALSE; + LeaveCriticalSection(&cache->cs); + } + else + ret = FALSE; + return ret; +} + +void NBNameCacheDestroy(struct NBNameCache *cache) +{ + if (cache) + { + DeleteCriticalSection(&cache->cs); + while (cache->head) + NBNameCacheUnlinkNode(cache, &cache->head); + HeapFree(cache->heap, 0, cache); + } +} diff --git a/reactos/lib/netapi32/nbnamecache.h b/reactos/lib/netapi32/nbnamecache.h new file mode 100644 index 00000000000..04e366314ee --- /dev/null +++ b/reactos/lib/netapi32/nbnamecache.h @@ -0,0 +1,82 @@ +/* Copyright (c) 2003 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __WINE_NBNAMECACHE_H +#define __WINE_NBNAMECACHE_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "nb30.h" + +struct NBNameCache; + +/* Represents an entry in the name cache. If the NetBIOS name is known, it's + * in nbname. Otherwise, nbname begins with '*'. numAddresses defines the + * number of addresses in addresses. + * Notice that it allows multiple addresses per name, but doesn't explicitly + * allow group names. That's because all names so far are unique; if a use for + * group names comes up, adding a flag here is simple enough. + * Also, only the first NCBNAMSZ - 1 bytes are considered significant. This is + * because a name may have been resolved using DNS, and the suffix byte is + * always truncated for DNS lookups. + */ +typedef struct _NBNameCacheEntry +{ + UCHAR name[NCBNAMSZ]; + UCHAR nbname[NCBNAMSZ]; + DWORD numAddresses; + DWORD addresses[1]; +} NBNameCacheEntry; + +/* Functions that create, manipulate, and destroy a name cache. Thread-safe, + * with the exception of NBNameCacheDestroy--ensure that no other threads are + * manipulating the cache before destoying it. + */ + +/* Allocates a new name cache from heap, and sets the expire time on new + * entries to entryExpireTimeMS after a cache entry is added. + */ +struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS); + +/* Adds an entry to the cache. The entry is assumed to have been allocated + * from the same heap as the name cache; the name cache will own the entry + * from now on. The entry's expire time is initialized at this time to + * entryExpireTimeMS + the current time in MS. If an existing entry with the + * same name was in the cache, the entry is replaced. Returns TRUE on success + * or FALSE on failure. + */ +BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry); + +/* Finds the entry with name name in the cache and returns a pointer to it, or + * NULL if it isn't found. + */ +const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache, + const UCHAR name[NCBNAMSZ]); + +/* If the entry with name name is in the cache, updates its nbname member to + * nbname. The entry's expire time is implicitly updated to entryExpireTimeMS + * + the current time in MS, since getting the NetBIOS name meant validating + * the name and address anyway. + * Returns TRUE on success or FALSE on failure. + */ +BOOL NBNameCacheUpdateNBName(struct NBNameCache *cache, + const UCHAR name[NCBNAMSZ], const UCHAR nbname[NCBNAMSZ]); + +void NBNameCacheDestroy(struct NBNameCache *cache); + +#endif /* ndef __WINE_NBNAMECACHE_H */ diff --git a/reactos/lib/netapi32/nbt.c b/reactos/lib/netapi32/nbt.c new file mode 100644 index 00000000000..3125df0c592 --- /dev/null +++ b/reactos/lib/netapi32/nbt.c @@ -0,0 +1,1553 @@ +/* Copyright (c) 2003 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * I am heavily indebted to Chris Hertel's excellent Implementing CIFS, + * http://ubiqx.org/cifs/ , for whatever understanding I have of NBT. + * I also stole from Mike McCormack's smb.c and netapi32.c, although little of + * that code remains. + * Lack of understanding and bugs are my fault. + * + * FIXME: + * - Of the NetBIOS session functions, only client functions are supported, and + * it's likely they'll be the only functions supported. NBT requires session + * servers to listen on TCP/139. This requires root privilege, and Samba is + * likely to be listening here already. This further restricts NetBIOS + * applications, both explicit users and implicit ones: CreateNamedPipe + * won't actually create a listening pipe, for example, so applications can't + * act as RPC servers using a named pipe protocol binding, DCOM won't be able + * to support callbacks or servers over the named pipe protocol, etc. + * + * - Datagram support is omitted for the same reason. To send a NetBIOS + * datagram, you must include the NetBIOS name by which your application is + * known. This requires you to have registered the name previously, and be + * able to act as a NetBIOS datagram server (listening on UDP/138). + * + * - Name registration functions are omitted for the same reason--registering a + * name requires you to be able to defend it, and this means listening on + * UDP/137. + * Win98 requires you either use your computer's NetBIOS name (with the NULL + * suffix byte) as the calling name when creating a session, or to register + * a new name before creating one: it disallows '*' as the calling name. + * Win2K initially starts with an empty name table, and doesn't allow you to + * use the machine's NetBIOS name (with the NULL suffix byte) as the calling + * name. Although it allows sessions to be created with '*' as the calling + * name, doing so results in timeouts for all receives, because the + * application never gets them. + * So, a well-behaved Netbios application will typically want to register a + * name. I should probably support a do-nothing name list that allows + * NCBADDNAME to add to it, but doesn't actually register the name, or does + * attempt to register it without being able to defend it. + * + * - Name lookups may not behave quite as you'd expect/like if you have + * multiple LANAs. If a name is resolvable through DNS, or if you're using + * WINS, it'll resolve on _any_ LANA. So, a Call will succeed on any LANA as + * well. + * I'm not sure how Windows behaves in this case. I could try to force + * lookups to the correct adapter by using one of the GetPreferred* + * functions, but with the possibility of multiple adapters in the same + * same subnet, there's no guarantee that what IpHlpApi thinks is the + * preferred adapter will actually be a LANA. (It's highly probable because + * this is an unusual configuration, but not guaranteed.) + * + * See also other FIXMEs in the code. + */ + +#include "config.h" +#include + +#include "winsock2.h" +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "winreg.h" +#include "iphlpapi.h" + +#include "netbios.h" +#include "nbnamecache.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netbios); + +#define PORT_NBNS 137 +#define PORT_NBDG 138 +#define PORT_NBSS 139 + +#ifndef INADDR_NONE +#define INADDR_NONE ~0UL +#endif + +#define NBR_ADDWORD(p,word) (*(WORD *)(p)) = htons(word) +#define NBR_GETWORD(p) ntohs(*(WORD *)(p)) + +#define MIN_QUERIES 1 +#define MAX_QUERIES 0xffff +#define MIN_QUERY_TIMEOUT 100 +#define MAX_QUERY_TIMEOUT 0xffffffff +#define BCAST_QUERIES 3 +#define BCAST_QUERY_TIMEOUT 750 +#define WINS_QUERIES 3 +#define WINS_QUERY_TIMEOUT 750 +#define MAX_WINS_SERVERS 2 +#define MIN_CACHE_TIMEOUT 60000 +#define CACHE_TIMEOUT 360000 + +#define MAX_NBT_NAME_SZ (NCBNAMSZ * 2 + MAX_DOMAIN_NAME_LEN + 2) +#define SIMPLE_NAME_QUERY_PKT_SIZE 26 + MAX_NBT_NAME_SZ + +#define DEFAULT_NBT_SESSIONS 16 + +#define NBNS_TYPE_NB 0x0020 +#define NBNS_TYPE_NBSTAT 0x0021 +#define NBNS_CLASS_INTERNET 0x00001 +#define NBNS_HEADER_SIZE (sizeof(WORD) * 6) +#define NBNS_RESPONSE_AND_OPCODE 0xf800 +#define NBNS_RESPONSE_AND_QUERY 0x8000 +#define NBNS_REPLYCODE 0x0f + +#define NBSS_HDRSIZE 4 + +#define NBSS_MSG 0x00 +#define NBSS_REQ 0x81 +#define NBSS_ACK 0x82 +#define NBSS_NACK 0x83 +#define NBSS_RETARGET 0x84 +#define NBSS_KEEPALIVE 0x85 + +#define NBSS_ERR_NOT_LISTENING_ON_NAME 0x80 +#define NBSS_ERR_NOT_LISTENING_FOR_CALLER 0x81 +#define NBSS_ERR_BAD_NAME 0x82 +#define NBSS_ERR_INSUFFICIENT_RESOURCES 0x83 + +#define NBSS_EXTENSION 0x01 + +typedef struct _NetBTSession +{ + CRITICAL_SECTION cs; + SOCKET fd; + DWORD bytesPending; +} NetBTSession; + +typedef struct _NetBTAdapter +{ + MIB_IPADDRROW ipr; + WORD nameQueryXID; + struct NBNameCache *nameCache; + DWORD xmit_success; + DWORD recv_success; +} NetBTAdapter; + +static ULONG gTransportID; +static BOOL gEnableDNS; +static DWORD gBCastQueries; +static DWORD gBCastQueryTimeout; +static DWORD gWINSQueries; +static DWORD gWINSQueryTimeout; +static DWORD gWINSServers[MAX_WINS_SERVERS]; +static int gNumWINSServers; +static char gScopeID[MAX_DOMAIN_NAME_LEN]; +static DWORD gCacheTimeout; +static struct NBNameCache *gNameCache; + +/* Converts from a NetBIOS name into a Second Level Encoding-formatted name. + * Assumes p is not NULL and is either NULL terminated or has at most NCBNAMSZ + * bytes, and buffer has at least MAX_NBT_NAME_SZ bytes. Pads with space bytes + * if p is NULL-terminated. Returns the number of bytes stored in buffer. + */ +static int NetBTNameEncode(const UCHAR *p, UCHAR *buffer) +{ + int i,len=0; + + if (!p) return 0; + if (!buffer) return 0; + + buffer[len++] = NCBNAMSZ * 2; + for (i = 0; p[i] && i < NCBNAMSZ; i++) + { + buffer[len++] = ((p[i] & 0xf0) >> 4) + 'A'; + buffer[len++] = (p[i] & 0x0f) + 'A'; + } + while (len < NCBNAMSZ * 2) + { + buffer[len++] = 'C'; + buffer[len++] = 'A'; + } + if (*gScopeID) + { + int scopeIDLen = strlen(gScopeID); + + memcpy(buffer + len, gScopeID, scopeIDLen); + len += scopeIDLen; + } + buffer[len++] = 0; /* add second terminator */ + return len; +} + +/* Creates a NBT name request packet for name in buffer. If broadcast is true, + * creates a broadcast request, otherwise creates a unicast request. + * Returns the number of bytes stored in buffer. + */ +static DWORD NetBTNameReq(const UCHAR name[NCBNAMSZ], WORD xid, WORD qtype, + BOOL broadcast, UCHAR *buffer, int len) +{ + int i = 0; + + if (len < SIMPLE_NAME_QUERY_PKT_SIZE) return 0; + + NBR_ADDWORD(&buffer[i],xid); i+=2; /* transaction */ + if (broadcast) + { + NBR_ADDWORD(&buffer[i],0x0110); /* flags: r=req,op=query,rd=1,b=1 */ + i+=2; + } + else + { + NBR_ADDWORD(&buffer[i],0x0100); /* flags: r=req,op=query,rd=1,b=0 */ + i+=2; + } + NBR_ADDWORD(&buffer[i],0x0001); i+=2; /* one name query */ + NBR_ADDWORD(&buffer[i],0x0000); i+=2; /* zero answers */ + NBR_ADDWORD(&buffer[i],0x0000); i+=2; /* zero authorities */ + NBR_ADDWORD(&buffer[i],0x0000); i+=2; /* zero additional */ + + i += NetBTNameEncode(name, &buffer[i]); + + NBR_ADDWORD(&buffer[i],qtype); i+=2; + NBR_ADDWORD(&buffer[i],NBNS_CLASS_INTERNET); i+=2; + + return i; +} + +/* Sends a name query request for name on fd to destAddr. Sets SO_BROADCAST on + * fd if broadcast is TRUE. Assumes fd is not INVALID_SOCKET, and name is not + * NULL. + * Returns 0 on success, -1 on failure. + */ +static int NetBTSendNameQuery(SOCKET fd, const UCHAR name[NCBNAMSZ], WORD xid, + WORD qtype, DWORD destAddr, BOOL broadcast) +{ + int ret = 0, on = 1; + struct in_addr addr; + + addr.s_addr = destAddr; + TRACE("name %s, dest addr %s\n", name, inet_ntoa(addr)); + + if (broadcast) + ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (const char*)&on, sizeof(on)); + if(ret == 0) + { + WSABUF wsaBuf; + UCHAR buf[SIMPLE_NAME_QUERY_PKT_SIZE]; + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_addr.s_addr = destAddr; + sin.sin_family = AF_INET; + sin.sin_port = htons(PORT_NBNS); + + wsaBuf.buf = (CHAR*)buf; + wsaBuf.len = NetBTNameReq(name, xid, qtype, broadcast, buf, + sizeof(buf)); + if (wsaBuf.len > 0) + { + DWORD bytesSent; + + ret = WSASendTo(fd, &wsaBuf, 1, &bytesSent, 0, + (struct sockaddr*)&sin, sizeof(sin), NULL, NULL); + if (ret < 0 || bytesSent < wsaBuf.len) + ret = -1; + else + ret = 0; + } + else + ret = -1; + } + return ret; +} + +typedef BOOL (*NetBTAnswerCallback)(void *data, WORD answerCount, + WORD answerIndex, PUCHAR rData, WORD rdLength); + +/* Waits on fd until GetTickCount() returns a value greater than or equal to + * waitUntil for a name service response. If a name response matching xid + * is received, calls answerCallback once for each answer resource record in + * the response. (The callback's answerCount will be the total number of + * answers to expect, and answerIndex will be the 0-based index that's being + * sent this time.) Quits parsing if answerCallback returns FALSE. + * Returns NRC_GOODRET on timeout or a valid response received, something else + * on error. + */ +static UCHAR NetBTWaitForNameResponse(NetBTAdapter *adapter, SOCKET fd, + DWORD waitUntil, NetBTAnswerCallback answerCallback, void *data) +{ + BOOL found = FALSE; + DWORD now; + UCHAR ret = NRC_GOODRET; + + if (!adapter) return NRC_BADDR; + if (fd == INVALID_SOCKET) return NRC_BADDR; + if (!answerCallback) return NRC_BADDR; + + while (!found && ret == NRC_GOODRET && (now = GetTickCount()) < waitUntil) + { + DWORD msToWait = waitUntil - now; + struct fd_set fds; + struct timeval timeout = { msToWait / 1000, msToWait % 1000 }; + int r; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + r = select(fd + 1, &fds, NULL, NULL, &timeout); + if (r < 0) + ret = NRC_SYSTEM; + else if (r == 1) + { + /* FIXME: magic #, is this always enough? */ + UCHAR buffer[256]; + int fromsize; + struct sockaddr_in fromaddr; + WORD respXID, flags, queryCount, answerCount; + WSABUF wsaBuf = { sizeof(buffer), (CHAR*)buffer }; + DWORD bytesReceived, recvFlags = 0; + + fromsize = sizeof(fromaddr); + r = WSARecvFrom(fd, &wsaBuf, 1, &bytesReceived, &recvFlags, + (struct sockaddr*)&fromaddr, &fromsize, NULL, NULL); + if(r < 0) + { + ret = NRC_SYSTEM; + break; + } + + if (bytesReceived < NBNS_HEADER_SIZE) + continue; + + respXID = NBR_GETWORD(buffer); + if (adapter->nameQueryXID != respXID) + continue; + + flags = NBR_GETWORD(buffer + 2); + queryCount = NBR_GETWORD(buffer + 4); + answerCount = NBR_GETWORD(buffer + 6); + + /* a reply shouldn't contain a query, ignore bad packet */ + if (queryCount > 0) + continue; + + if ((flags & NBNS_RESPONSE_AND_OPCODE) == NBNS_RESPONSE_AND_QUERY) + { + if ((flags & NBNS_REPLYCODE) != 0) + ret = NRC_NAMERR; + else if ((flags & NBNS_REPLYCODE) == 0 && answerCount > 0) + { + PUCHAR ptr = buffer + NBNS_HEADER_SIZE; + BOOL shouldContinue = TRUE; + WORD answerIndex = 0; + + found = TRUE; + /* decode one answer at a time */ + while (ret == NRC_GOODRET && answerIndex < answerCount && + ptr - buffer < bytesReceived && shouldContinue) + { + WORD rLen; + + /* scan past name */ + for (; ptr[0] && ptr - buffer < bytesReceived; ) + ptr += ptr[0] + 1; + ptr++; + ptr += 2; /* scan past type */ + if (ptr - buffer < bytesReceived && ret == NRC_GOODRET + && NBR_GETWORD(ptr) == NBNS_CLASS_INTERNET) + ptr += sizeof(WORD); + else + ret = NRC_SYSTEM; /* parse error */ + ptr += sizeof(DWORD); /* TTL */ + rLen = NBR_GETWORD(ptr); + rLen = min(rLen, bytesReceived - (ptr - buffer)); + ptr += sizeof(WORD); + shouldContinue = answerCallback(data, answerCount, + answerIndex, ptr, rLen); + ptr += rLen; + answerIndex++; + } + } + } + } + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +typedef struct _NetBTNameQueryData { + NBNameCacheEntry *cacheEntry; + UCHAR ret; +} NetBTNameQueryData; + +/* Name query callback function for NetBTWaitForNameResponse, creates a cache + * entry on the first answer, adds each address as it's called again (as long + * as there's space). If there's an error that should be propagated as the + * NetBIOS error, modifies queryData's ret member to the proper return code. + */ +static BOOL NetBTFindNameAnswerCallback(void *pVoid, WORD answerCount, + WORD answerIndex, PUCHAR rData, WORD rLen) +{ + NetBTNameQueryData *queryData = (NetBTNameQueryData *)pVoid; + BOOL ret; + + if (queryData) + { + if (queryData->cacheEntry == NULL) + { + queryData->cacheEntry = HeapAlloc( + GetProcessHeap(), 0, sizeof(NBNameCacheEntry) + + (answerCount - 1) * sizeof(DWORD)); + if (queryData->cacheEntry) + queryData->cacheEntry->numAddresses = 0; + else + { + ret = FALSE; + queryData->ret = NRC_OSRESNOTAV; + } + } + if (rLen == 6 && queryData->cacheEntry && + queryData->cacheEntry->numAddresses < answerCount) + { + queryData->cacheEntry->addresses[queryData->cacheEntry-> + numAddresses++] = *(PDWORD)(rData + 2); + ret = queryData->cacheEntry->numAddresses < answerCount; + } + else + ret = FALSE; + } + else + ret = FALSE; + return ret; +} + +/* Workhorse NetBT name lookup function. Sends a name lookup query for + * ncb->ncb_callname to sendTo, as a broadcast if broadcast is TRUE, using + * adapter->nameQueryXID as the transaction ID. Waits up to timeout + * milliseconds, and retries up to maxQueries times, waiting for a reply. + * If a valid response is received, stores the looked up addresses as a + * NBNameCacheEntry in *cacheEntry. + * Returns NRC_GOODRET on success, though this may not mean the name was + * resolved--check whether *cacheEntry is NULL. + */ +static UCHAR NetBTNameWaitLoop(NetBTAdapter *adapter, SOCKET fd, PNCB ncb, + DWORD sendTo, BOOL broadcast, DWORD timeout, DWORD maxQueries, + NBNameCacheEntry **cacheEntry) +{ + unsigned int queries; + NetBTNameQueryData queryData; + + if (!adapter) return NRC_BADDR; + if (fd == INVALID_SOCKET) return NRC_BADDR; + if (!ncb) return NRC_BADDR; + if (!cacheEntry) return NRC_BADDR; + + queryData.cacheEntry = NULL; + queryData.ret = NRC_GOODRET; + for (queries = 0; queryData.cacheEntry == NULL && queries < maxQueries; + queries++) + { + if (!NCB_CANCELLED(ncb)) + { + int r = NetBTSendNameQuery(fd, ncb->ncb_callname, + adapter->nameQueryXID, NBNS_TYPE_NB, sendTo, broadcast); + + if (r == 0) + queryData.ret = NetBTWaitForNameResponse(adapter, fd, + GetTickCount() + timeout, NetBTFindNameAnswerCallback, + &queryData); + else + queryData.ret = NRC_SYSTEM; + } + else + queryData.ret = NRC_CMDCAN; + } + if (queryData.cacheEntry) + { + memcpy(queryData.cacheEntry->name, ncb->ncb_callname, NCBNAMSZ); + memcpy(queryData.cacheEntry->nbname, ncb->ncb_callname, NCBNAMSZ); + } + *cacheEntry = queryData.cacheEntry; + return queryData.ret; +} + +/* Attempts to add cacheEntry to the name cache in *nameCache; if *nameCache + * has not yet been created, creates it, using gCacheTimeout as the cache + * entry timeout. If memory allocation fails, or if NBNameCacheAddEntry fails, + * frees cacheEntry. + * Returns NRC_GOODRET on success, and something else on failure. + */ +static UCHAR NetBTStoreCacheEntry(struct NBNameCache **nameCache, + NBNameCacheEntry *cacheEntry) +{ + UCHAR ret; + + if (!nameCache) return NRC_BADDR; + if (!cacheEntry) return NRC_BADDR; + + if (!*nameCache) + *nameCache = NBNameCacheCreate(GetProcessHeap(), gCacheTimeout); + if (*nameCache) + ret = NBNameCacheAddEntry(*nameCache, cacheEntry) + ? NRC_GOODRET : NRC_OSRESNOTAV; + else + { + HeapFree(GetProcessHeap(), 0, cacheEntry); + ret = NRC_OSRESNOTAV; + } + return ret; +} + +/* Attempts to resolve name using inet_addr(), then gethostbyname() if + * gEnableDNS is TRUE, if the suffix byte is either <00> or <20>. If the name + * can be looked up, returns 0 and stores the looked up addresses as a + * NBNameCacheEntry in *cacheEntry. + * Returns NRC_GOODRET on success, though this may not mean the name was + * resolved--check whether *cacheEntry is NULL. Returns something else on + * error. + */ +static UCHAR NetBTinetResolve(const UCHAR name[NCBNAMSZ], + NBNameCacheEntry **cacheEntry) +{ + UCHAR ret = NRC_GOODRET; + + TRACE("name %s, cacheEntry %p\n", name, cacheEntry); + + if (!name) return NRC_BADDR; + if (!cacheEntry) return NRC_BADDR; + + if (isalnum(name[0]) && (name[NCBNAMSZ - 1] == 0 || + name[NCBNAMSZ - 1] == 0x20)) + { + CHAR toLookup[NCBNAMSZ]; + unsigned int i; + + for (i = 0; i < NCBNAMSZ - 1 && name[i] && name[i] != ' '; i++) + toLookup[i] = name[i]; + toLookup[i] = '\0'; + + if (isdigit(toLookup[0])) + { + unsigned long addr = inet_addr(toLookup); + + if (addr != INADDR_NONE) + { + *cacheEntry = HeapAlloc(GetProcessHeap(), + 0, sizeof(NBNameCacheEntry)); + if (*cacheEntry) + { + memcpy((*cacheEntry)->name, name, NCBNAMSZ); + memset((*cacheEntry)->nbname, 0, NCBNAMSZ); + (*cacheEntry)->nbname[0] = '*'; + (*cacheEntry)->numAddresses = 1; + (*cacheEntry)->addresses[0] = addr; + } + else + ret = NRC_OSRESNOTAV; + } + } + if (gEnableDNS && ret == NRC_GOODRET && !*cacheEntry) + { + struct hostent *host; + + if ((host = gethostbyname(toLookup)) != NULL) + { + for (i = 0; ret == NRC_GOODRET && host->h_addr_list && + host->h_addr_list[i]; i++) + ; + if (host->h_addr_list && host->h_addr_list[0]) + { + *cacheEntry = HeapAlloc( + GetProcessHeap(), 0, sizeof(NBNameCacheEntry) + + (i - 1) * sizeof(DWORD)); + if (*cacheEntry) + { + memcpy((*cacheEntry)->name, name, NCBNAMSZ); + memset((*cacheEntry)->nbname, 0, NCBNAMSZ); + (*cacheEntry)->nbname[0] = '*'; + (*cacheEntry)->numAddresses = i; + for (i = 0; i < (*cacheEntry)->numAddresses; i++) + (*cacheEntry)->addresses[i] = + (DWORD)host->h_addr_list[i]; + } + else + ret = NRC_OSRESNOTAV; + } + } + } + } + + TRACE("returning 0x%02x\n", ret); + return ret; +} + +/* Looks up the name in ncb->ncb_callname, first in the name caches (global + * and this adapter's), then using gethostbyname(), next by WINS if configured, + * and finally using broadcast NetBT name resolution. In NBT parlance, this + * makes this an "H-node". Stores an entry in the appropriate name cache for a + * found node, and returns it as *cacheEntry. + * Assumes data, ncb, and cacheEntry are not NULL. + * Returns NRC_GOODRET on success--which doesn't mean the name was resolved, + * just that all name lookup operations completed successfully--and something + * else on failure. *cacheEntry will be NULL if the name was not found. + */ +static UCHAR NetBTInternalFindName(NetBTAdapter *adapter, PNCB ncb, + const NBNameCacheEntry **cacheEntry) +{ + UCHAR ret = NRC_GOODRET; + + TRACE("adapter %p, ncb %p, cacheEntry %p\n", adapter, ncb, cacheEntry); + + if (!cacheEntry) return NRC_BADDR; + *cacheEntry = NULL; + + if (!adapter) return NRC_BADDR; + if (!ncb) return NRC_BADDR; + + if (ncb->ncb_callname[0] == '*') + ret = NRC_NOWILD; + else + { + *cacheEntry = NBNameCacheFindEntry(gNameCache, ncb->ncb_callname); + if (!*cacheEntry) + *cacheEntry = NBNameCacheFindEntry(adapter->nameCache, + ncb->ncb_callname); + if (!*cacheEntry) + { + NBNameCacheEntry *newEntry = NULL; + + ret = NetBTinetResolve(ncb->ncb_callname, &newEntry); + if (ret == NRC_GOODRET && newEntry) + { + ret = NetBTStoreCacheEntry(&gNameCache, newEntry); + if (ret != NRC_GOODRET) + newEntry = NULL; + } + else + { + SOCKET fd = WSASocketA(PF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, + 0, WSA_FLAG_OVERLAPPED); + + if(fd == INVALID_SOCKET) + ret = NRC_OSRESNOTAV; + else + { + int winsNdx; + + adapter->nameQueryXID++; + for (winsNdx = 0; ret == NRC_GOODRET && *cacheEntry == NULL + && winsNdx < gNumWINSServers; winsNdx++) + ret = NetBTNameWaitLoop(adapter, fd, ncb, + gWINSServers[winsNdx], FALSE, gWINSQueryTimeout, + gWINSQueries, &newEntry); + if (ret == NRC_GOODRET && newEntry) + { + ret = NetBTStoreCacheEntry(&gNameCache, newEntry); + if (ret != NRC_GOODRET) + newEntry = NULL; + } + if (ret == NRC_GOODRET && *cacheEntry == NULL) + { + DWORD bcastAddr = + adapter->ipr.dwAddr & adapter->ipr.dwMask; + + if (adapter->ipr.dwBCastAddr) + bcastAddr |= ~adapter->ipr.dwMask; + ret = NetBTNameWaitLoop(adapter, fd, ncb, bcastAddr, + TRUE, gBCastQueryTimeout, gBCastQueries, &newEntry); + if (ret == NRC_GOODRET && newEntry) + { + ret = NetBTStoreCacheEntry(&adapter->nameCache, + newEntry); + if (ret != NRC_GOODRET) + newEntry = NULL; + } + } + closesocket(fd); + } + } + *cacheEntry = newEntry; + } + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +typedef struct _NetBTNodeQueryData +{ + BOOL gotResponse; + PADAPTER_STATUS astat; + WORD astatLen; +} NetBTNodeQueryData; + +/* Callback function for NetBTAstatRemote, parses the rData for the node + * status and name list of the remote node. Always returns FALSE, since + * there's never more than one answer we care about in a node status response. + */ +static BOOL NetBTNodeStatusAnswerCallback(void *pVoid, WORD answerCount, + WORD answerIndex, PUCHAR rData, WORD rLen) +{ + NetBTNodeQueryData *data = (NetBTNodeQueryData *)pVoid; + + if (data && !data->gotResponse && rData && rLen >= 1) + { + /* num names is first byte; each name is NCBNAMSZ + 2 bytes */ + if (rLen >= rData[0] * (NCBNAMSZ + 2)) + { + WORD i; + PUCHAR src; + PNAME_BUFFER dst; + + data->gotResponse = TRUE; + data->astat->name_count = rData[0]; + for (i = 0, src = rData + 1, + dst = (PNAME_BUFFER)((PUCHAR)data->astat + + sizeof(ADAPTER_STATUS)); + i < data->astat->name_count && src - rData < rLen && + (PUCHAR)dst - (PUCHAR)data->astat < data->astatLen; + i++, dst++, src += NCBNAMSZ + 2) + { + UCHAR flags = *(src + NCBNAMSZ); + + memcpy(dst->name, src, NCBNAMSZ); + /* we won't actually see a registering name in the returned + * response. It's useful to see if no other flags are set; if + * none are, then the name is registered. */ + dst->name_flags = REGISTERING; + if (flags & 0x80) + dst->name_flags |= GROUP_NAME; + if (flags & 0x10) + dst->name_flags |= DEREGISTERED; + if (flags & 0x08) + dst->name_flags |= DUPLICATE; + if (dst->name_flags == REGISTERING) + dst->name_flags = REGISTERED; + } + /* arbitrarily set HW type to Ethernet */ + data->astat->adapter_type = 0xfe; + if (src - rData < rLen) + memcpy(data->astat->adapter_address, src, + min(rLen - (src - rData), 6)); + } + } + return FALSE; +} + +/* This uses the WINS timeout and query values, as they're the + * UCAST_REQ_RETRY_TIMEOUT and UCAST_REQ_RETRY_COUNT according to the RFCs. + */ +static UCHAR NetBTAstatRemote(NetBTAdapter *adapter, PNCB ncb) +{ + UCHAR ret = NRC_GOODRET; + const NBNameCacheEntry *cacheEntry = NULL; + + TRACE("adapter %p, NCB %p\n", adapter, ncb); + + if (!adapter) return NRC_BADDR; + if (!ncb) return NRC_INVADDRESS; + + ret = NetBTInternalFindName(adapter, ncb, &cacheEntry); + if (ret == NRC_GOODRET && cacheEntry) + { + if (cacheEntry->numAddresses > 0) + { + SOCKET fd = WSASocketA(PF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, + WSA_FLAG_OVERLAPPED); + + if(fd == INVALID_SOCKET) + ret = NRC_OSRESNOTAV; + else + { + NetBTNodeQueryData queryData; + DWORD queries; + PADAPTER_STATUS astat = (PADAPTER_STATUS)ncb->ncb_buffer; + + adapter->nameQueryXID++; + astat->name_count = 0; + queryData.gotResponse = FALSE; + queryData.astat = astat; + queryData.astatLen = ncb->ncb_length; + for (queries = 0; !queryData.gotResponse && + queries < gWINSQueries; queries++) + { + if (!NCB_CANCELLED(ncb)) + { + int r = NetBTSendNameQuery(fd, ncb->ncb_callname, + adapter->nameQueryXID, NBNS_TYPE_NBSTAT, + cacheEntry->addresses[0], FALSE); + + if (r == 0) + ret = NetBTWaitForNameResponse(adapter, fd, + GetTickCount() + gWINSQueryTimeout, + NetBTNodeStatusAnswerCallback, &queryData); + else + ret = NRC_SYSTEM; + } + else + ret = NRC_CMDCAN; + } + closesocket(fd); + } + } + else + ret = NRC_CMDTMO; + } + else if (ret == NRC_CMDCAN) + ; /* do nothing, we were cancelled */ + else + ret = NRC_CMDTMO; + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR NetBTAstat(void *adapt, PNCB ncb) +{ + NetBTAdapter *adapter = (NetBTAdapter *)adapt; + UCHAR ret; + + TRACE("adapt %p, NCB %p\n", adapt, ncb); + + if (!adapter) return NRC_ENVNOTDEF; + if (!ncb) return NRC_INVADDRESS; + if (!ncb->ncb_buffer) return NRC_BADDR; + if (ncb->ncb_length < sizeof(ADAPTER_STATUS)) return NRC_BUFLEN; + + if (ncb->ncb_callname[0] == '*') + { + DWORD physAddrLen; + MIB_IFROW ifRow; + PADAPTER_STATUS astat = (PADAPTER_STATUS)ncb->ncb_buffer; + + memset(astat, 0, sizeof(ADAPTER_STATUS)); + astat->rev_major = 3; + ifRow.dwIndex = adapter->ipr.dwIndex; + if (GetIfEntry(&ifRow) != NO_ERROR) + ret = NRC_BRIDGE; + else + { + physAddrLen = min(ifRow.dwPhysAddrLen, 6); + if (physAddrLen > 0) + memcpy(astat->adapter_address, ifRow.bPhysAddr, physAddrLen); + /* doubt anyone cares, but why not.. */ + if (ifRow.dwType == MIB_IF_TYPE_TOKENRING) + astat->adapter_type = 0xff; + else + astat->adapter_type = 0xfe; /* for Ethernet */ + astat->max_sess_pkt_size = 0xffff; + astat->xmit_success = adapter->xmit_success; + astat->recv_success = adapter->recv_success; + } + ret = NRC_GOODRET; + } + else + ret = NetBTAstatRemote(adapter, ncb); + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR NetBTFindName(void *adapt, PNCB ncb) +{ + NetBTAdapter *adapter = (NetBTAdapter *)adapt; + UCHAR ret; + const NBNameCacheEntry *cacheEntry = NULL; + PFIND_NAME_HEADER foundName; + + TRACE("adapt %p, NCB %p\n", adapt, ncb); + + if (!adapter) return NRC_ENVNOTDEF; + if (!ncb) return NRC_INVADDRESS; + if (!ncb->ncb_buffer) return NRC_BADDR; + if (ncb->ncb_length < sizeof(FIND_NAME_HEADER)) return NRC_BUFLEN; + + foundName = (PFIND_NAME_HEADER)ncb->ncb_buffer; + memset(foundName, 0, sizeof(FIND_NAME_HEADER)); + + ret = NetBTInternalFindName(adapter, ncb, &cacheEntry); + if (ret == NRC_GOODRET) + { + if (cacheEntry) + { + DWORD spaceFor = min((ncb->ncb_length - sizeof(FIND_NAME_HEADER)) / + sizeof(FIND_NAME_BUFFER), cacheEntry->numAddresses); + DWORD ndx; + + for (ndx = 0; ndx < spaceFor; ndx++) + { + PFIND_NAME_BUFFER findNameBuffer; + + findNameBuffer = + (PFIND_NAME_BUFFER)((PUCHAR)foundName + + sizeof(FIND_NAME_HEADER) + foundName->node_count * + sizeof(FIND_NAME_BUFFER)); + memset(findNameBuffer->destination_addr, 0, 2); + memcpy(findNameBuffer->destination_addr + 2, + &adapter->ipr.dwAddr, sizeof(DWORD)); + memset(findNameBuffer->source_addr, 0, 2); + memcpy(findNameBuffer->source_addr + 2, + &cacheEntry->addresses[ndx], sizeof(DWORD)); + foundName->node_count++; + } + if (spaceFor < cacheEntry->numAddresses) + ret = NRC_BUFLEN; + } + else + ret = NRC_CMDTMO; + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR NetBTSessionReq(SOCKET fd, const UCHAR *calledName, + const UCHAR *callingName) +{ + UCHAR buffer[NBSS_HDRSIZE + MAX_DOMAIN_NAME_LEN * 2], ret; + int r; + unsigned int len = 0; + DWORD bytesSent, bytesReceived, recvFlags = 0; + WSABUF wsaBuf; + + buffer[0] = NBSS_REQ; + buffer[1] = 0; + + len += NetBTNameEncode(calledName, &buffer[NBSS_HDRSIZE]); + len += NetBTNameEncode(callingName, &buffer[NBSS_HDRSIZE + len]); + + NBR_ADDWORD(&buffer[2], len); + + wsaBuf.len = len + NBSS_HDRSIZE; + wsaBuf.buf = (char*)buffer; + + r = WSASend(fd, &wsaBuf, 1, &bytesSent, 0, NULL, NULL); + if(r < 0 || bytesSent < len + NBSS_HDRSIZE) + { + ERR("send failed\n"); + return NRC_SABORT; + } + + /* I've already set the recv timeout on this socket (if it supports it), so + * just block. Hopefully we'll always receive the session acknowledgement + * within one timeout. + */ + wsaBuf.len = NBSS_HDRSIZE + 1; + r = WSARecv(fd, &wsaBuf, 1, &bytesReceived, &recvFlags, NULL, NULL); + if (r < 0 || bytesReceived < NBSS_HDRSIZE) + ret = NRC_SABORT; + else if (buffer[0] == NBSS_NACK) + { + if (r == NBSS_HDRSIZE + 1) + { + switch (buffer[NBSS_HDRSIZE]) + { + case NBSS_ERR_INSUFFICIENT_RESOURCES: + ret = NRC_REMTFUL; + break; + default: + ret = NRC_NOCALL; + } + } + else + ret = NRC_NOCALL; + } + else if (buffer[0] == NBSS_RETARGET) + { + FIXME("Got a session retarget, can't deal\n"); + ret = NRC_NOCALL; + } + else if (buffer[0] == NBSS_ACK) + ret = NRC_GOODRET; + else + ret = NRC_SYSTEM; + + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR NetBTCall(void *adapt, PNCB ncb, void **sess) +{ + NetBTAdapter *adapter = (NetBTAdapter *)adapt; + UCHAR ret; + const NBNameCacheEntry *cacheEntry = NULL; + + TRACE("adapt %p, ncb %p\n", adapt, ncb); + + if (!adapter) return NRC_ENVNOTDEF; + if (!ncb) return NRC_INVADDRESS; + if (!sess) return NRC_BADDR; + + ret = NetBTInternalFindName(adapter, ncb, &cacheEntry); + if (ret == NRC_GOODRET) + { + if (cacheEntry && cacheEntry->numAddresses > 0) + { + SOCKET fd; + + fd = WSASocketA(PF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + if (fd != INVALID_SOCKET) + { + DWORD timeout; + struct sockaddr_in sin; + + if (ncb->ncb_rto > 0) + { + timeout = ncb->ncb_rto * 500; + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, + sizeof(timeout)); + } + if (ncb->ncb_rto > 0) + { + timeout = ncb->ncb_sto * 500; + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, + sizeof(timeout)); + } + + memset(&sin, 0, sizeof(sin)); + memcpy(&sin.sin_addr, &cacheEntry->addresses[0], + sizeof(sin.sin_addr)); + sin.sin_family = AF_INET; + sin.sin_port = htons(PORT_NBSS); + /* FIXME: use nonblocking mode for the socket, check the + * cancel flag periodically + */ + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) + == SOCKET_ERROR) + ret = NRC_CMDTMO; + else + { + static UCHAR fakedCalledName[] = "*SMBSERVER"; + const UCHAR *calledParty = cacheEntry->nbname[0] == '*' + ? fakedCalledName : cacheEntry->nbname; + + ret = NetBTSessionReq(fd, calledParty, ncb->ncb_name); + if (ret != NRC_GOODRET && calledParty[0] == '*') + { + FIXME("NBT session to \"*SMBSERVER\" refused,\n"); + FIXME("should try finding name using ASTAT\n"); + } + } + if (ret != NRC_GOODRET) + closesocket(fd); + else + { + NetBTSession *session = HeapAlloc( + GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NetBTSession)); + + if (session) + { + session->fd = fd; + InitializeCriticalSection(&session->cs); + *sess = session; + } + else + { + ret = NRC_OSRESNOTAV; + closesocket(fd); + } + } + } + else + ret = NRC_OSRESNOTAV; + } + else + ret = NRC_NAMERR; + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +/* Notice that I don't protect against multiple thread access to NetBTSend. + * This is because I don't update any data in the adapter, and I only make a + * single call to WSASend, which I assume to act atomically (not interleaving + * data from other threads). + * I don't lock, because I only depend on the fd being valid, and this won't be + * true until a session setup is completed. + */ +static UCHAR NetBTSend(void *adapt, void *sess, PNCB ncb) +{ + NetBTAdapter *adapter = (NetBTAdapter *)adapt; + NetBTSession *session = (NetBTSession *)sess; + UCHAR buffer[NBSS_HDRSIZE], ret; + int r; + WSABUF wsaBufs[2]; + DWORD bytesSent; + + TRACE("adapt %p, session %p, NCB %p\n", adapt, session, ncb); + + if (!adapter) return NRC_ENVNOTDEF; + if (!ncb) return NRC_INVADDRESS; + if (!ncb->ncb_buffer) return NRC_BADDR; + if (!session) return NRC_SNUMOUT; + if (session->fd == INVALID_SOCKET) return NRC_SNUMOUT; + + buffer[0] = NBSS_MSG; + buffer[1] = 0; + NBR_ADDWORD(&buffer[2], ncb->ncb_length); + + wsaBufs[0].len = NBSS_HDRSIZE; + wsaBufs[0].buf = (char*)buffer; + wsaBufs[1].len = ncb->ncb_length; + wsaBufs[1].buf = (char*)ncb->ncb_buffer; + + r = WSASend(session->fd, wsaBufs, sizeof(wsaBufs) / sizeof(wsaBufs[0]), + &bytesSent, 0, NULL, NULL); + if (r == SOCKET_ERROR) + { + NetBIOSHangupSession(ncb); + ret = NRC_SABORT; + } + else if (bytesSent < NBSS_HDRSIZE + ncb->ncb_length) + { + FIXME("Only sent %ld bytes (of %d), hanging up session\n", bytesSent, + NBSS_HDRSIZE + ncb->ncb_length); + NetBIOSHangupSession(ncb); + ret = NRC_SABORT; + } + else + { + ret = NRC_GOODRET; + adapter->xmit_success++; + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR NetBTRecv(void *adapt, void *sess, PNCB ncb) +{ + NetBTAdapter *adapter = (NetBTAdapter *)adapt; + NetBTSession *session = (NetBTSession *)sess; + UCHAR buffer[NBSS_HDRSIZE], ret; + int r; + WSABUF wsaBufs[2]; + DWORD bufferCount, bytesReceived, flags; + + TRACE("adapt %p, session %p, NCB %p\n", adapt, session, ncb); + + if (!adapter) return NRC_ENVNOTDEF; + if (!ncb) return NRC_BADDR; + if (!ncb->ncb_buffer) return NRC_BADDR; + if (!session) return NRC_SNUMOUT; + if (session->fd == INVALID_SOCKET) return NRC_SNUMOUT; + + EnterCriticalSection(&session->cs); + bufferCount = 0; + if (session->bytesPending == 0) + { + bufferCount++; + wsaBufs[0].len = NBSS_HDRSIZE; + wsaBufs[0].buf = (char*)buffer; + } + wsaBufs[bufferCount].len = ncb->ncb_length; + wsaBufs[bufferCount].buf = (char*)ncb->ncb_buffer; + bufferCount++; + + flags = 0; + /* FIXME: should poll a bit so I can check the cancel flag */ + r = WSARecv(session->fd, wsaBufs, bufferCount, &bytesReceived, &flags, + NULL, NULL); + if (r == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) + { + LeaveCriticalSection(&session->cs); + ERR("Receive error, WSAGetLastError() returns %d\n", WSAGetLastError()); + NetBIOSHangupSession(ncb); + ret = NRC_SABORT; + } + else if (NCB_CANCELLED(ncb)) + { + LeaveCriticalSection(&session->cs); + ret = NRC_CMDCAN; + } + else + { + if (bufferCount == 2) + { + if (buffer[0] == NBSS_KEEPALIVE) + { + LeaveCriticalSection(&session->cs); + FIXME("Oops, received a session keepalive and lost my place\n"); + /* need to read another session header until we get a session + * message header. */ + NetBIOSHangupSession(ncb); + ret = NRC_SABORT; + } + else if (buffer[0] != NBSS_MSG) + { + LeaveCriticalSection(&session->cs); + FIXME("Received unexpected session msg type %d\n", buffer[0]); + NetBIOSHangupSession(ncb); + ret = NRC_SABORT; + } + else + { + if (buffer[1] & NBSS_EXTENSION) + { + LeaveCriticalSection(&session->cs); + FIXME("Received a message that's too long for my taste\n"); + NetBIOSHangupSession(ncb); + ret = NRC_SABORT; + } + else + { + session->bytesPending = NBSS_HDRSIZE + + NBR_GETWORD(&buffer[2]) - bytesReceived; + ncb->ncb_length = bytesReceived - NBSS_HDRSIZE; + LeaveCriticalSection(&session->cs); + } + } + } + else + { + if (bytesReceived < session->bytesPending) + session->bytesPending -= bytesReceived; + else + session->bytesPending = 0; + LeaveCriticalSection(&session->cs); + ncb->ncb_length = bytesReceived; + } + if (session->bytesPending > 0) + ret = NRC_INCOMP; + else + { + ret = NRC_GOODRET; + adapter->recv_success++; + } + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR NetBTHangup(void *adapt, void *sess) +{ + NetBTSession *session = (NetBTSession *)sess; + + TRACE("adapt %p, session %p\n", adapt, session); + + if (!session) return NRC_SNUMOUT; + + /* I don't lock the session, because NetBTRecv knows not to decrement + * past 0, so if a receive completes after this it should still deal. + */ + closesocket(session->fd); + session->fd = INVALID_SOCKET; + session->bytesPending = 0; + DeleteCriticalSection(&session->cs); + HeapFree(GetProcessHeap(), 0, session); + + return NRC_GOODRET; +} + +static void NetBTCleanupAdapter(void *adapt) +{ + TRACE("adapt %p\n", adapt); + if (adapt) + { + NetBTAdapter *adapter = (NetBTAdapter *)adapt; + + if (adapter->nameCache) + NBNameCacheDestroy(adapter->nameCache); + HeapFree(GetProcessHeap(), 0, adapt); + } +} + +static void NetBTCleanup(void) +{ + TRACE("\n"); + if (gNameCache) + { + NBNameCacheDestroy(gNameCache); + gNameCache = NULL; + } +} + +static UCHAR NetBTRegisterAdapter(PMIB_IPADDRROW ipRow) +{ + UCHAR ret; + NetBTAdapter *adapter; + + if (!ipRow) return NRC_BADDR; + + adapter = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NetBTAdapter)); + if (adapter) + { + memcpy(&adapter->ipr, ipRow, sizeof(MIB_IPADDRROW)); + if (!NetBIOSRegisterAdapter(gTransportID, ipRow->dwIndex, adapter)) + { + NetBTCleanupAdapter(adapter); + ret = NRC_SYSTEM; + } + else + ret = NRC_GOODRET; + } + else + ret = NRC_OSRESNOTAV; + return ret; +} + +/* Callback for NetBIOS adapter enumeration. Assumes closure is a pointer to + * a MIB_IPADDRTABLE containing all the IP adapters needed to be added to the + * NetBIOS adapter table. For each callback, checks if the passed-in adapt + * has an entry in the table; if so, this adapter was enumerated previously, + * and it's enabled. As a flag, the table's dwAddr entry is changed to + * INADDR_LOOPBACK, since this is an invalid address for a NetBT adapter. + * The NetBTEnum function will add any remaining adapters from the + * MIB_IPADDRTABLE to the NetBIOS adapter table. + */ +static BOOL NetBTEnumCallback(UCHAR totalLANAs, UCHAR lanaIndex, + ULONG transport, const NetBIOSAdapterImpl *data, void *closure) +{ + BOOL ret; + PMIB_IPADDRTABLE table = (PMIB_IPADDRTABLE)closure; + + if (table && data) + { + DWORD ndx; + + ret = FALSE; + for (ndx = 0; !ret && ndx < table->dwNumEntries; ndx++) + { + const NetBTAdapter *adapter = (const NetBTAdapter *)data->data; + + if (table->table[ndx].dwIndex == adapter->ipr.dwIndex) + { + NetBIOSEnableAdapter(data->lana); + table->table[ndx].dwAddr = INADDR_LOOPBACK; + ret = TRUE; + } + } + } + else + ret = FALSE; + return ret; +} + +/* Enumerates adapters by: + * - retrieving the IP address table for the local machine + * - eliminating loopback addresses from the table + * - eliminating redundant addresses, that is, multiple addresses on the same + * subnet + * Calls NetBIOSEnumAdapters, passing the resulting table as the callback + * data. The callback reenables each adapter that's already in the NetBIOS + * table. After NetBIOSEnumAdapters returns, this function adds any remaining + * adapters to the NetBIOS table. + */ +static UCHAR NetBTEnum(void) +{ + UCHAR ret; + DWORD size = 0; + + TRACE("\n"); + + if (GetIpAddrTable(NULL, &size, FALSE) == ERROR_INSUFFICIENT_BUFFER) + { + PMIB_IPADDRTABLE ipAddrs, coalesceTable = NULL; + DWORD numIPAddrs = (size - sizeof(MIB_IPADDRTABLE)) / + sizeof(MIB_IPADDRROW) + 1; + + ipAddrs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); + if (ipAddrs) + coalesceTable = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(MIB_IPADDRTABLE) + + (min(numIPAddrs, MAX_LANA + 1) - 1) * sizeof(MIB_IPADDRROW)); + if (ipAddrs && coalesceTable) + { + if (GetIpAddrTable(ipAddrs, &size, FALSE) == ERROR_SUCCESS) + { + DWORD ndx; + + for (ndx = 0; ndx < ipAddrs->dwNumEntries; ndx++) + { + if ((ipAddrs->table[ndx].dwAddr & + ipAddrs->table[ndx].dwMask) != + htonl((INADDR_LOOPBACK & IN_CLASSA_NET))) + { + BOOL newNetwork = TRUE; + DWORD innerIndex; + + /* make sure we don't have more than one entry + * for a subnet */ + for (innerIndex = 0; newNetwork && + innerIndex < coalesceTable->dwNumEntries; innerIndex++) + if ((ipAddrs->table[ndx].dwAddr & + ipAddrs->table[ndx].dwMask) == + (coalesceTable->table[innerIndex].dwAddr + & coalesceTable->table[innerIndex].dwMask)) + newNetwork = FALSE; + + if (newNetwork) + memcpy(&coalesceTable->table[ + coalesceTable->dwNumEntries++], + &ipAddrs->table[ndx], sizeof(MIB_IPADDRROW)); + } + } + + NetBIOSEnumAdapters(gTransportID, NetBTEnumCallback, + coalesceTable); + ret = NRC_GOODRET; + for (ndx = 0; ret == NRC_GOODRET && + ndx < coalesceTable->dwNumEntries; ndx++) + if (coalesceTable->table[ndx].dwAddr != INADDR_LOOPBACK) + ret = NetBTRegisterAdapter(&coalesceTable->table[ndx]); + } + else + ret = NRC_SYSTEM; + HeapFree(GetProcessHeap(), 0, ipAddrs); + HeapFree(GetProcessHeap(), 0, coalesceTable); + } + else + ret = NRC_OSRESNOTAV; + } + else + ret = NRC_SYSTEM; + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static const WCHAR VxD_MSTCPW[] = { 'S','Y','S','T','E','M','\\','C','u','r', + 'r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','S','e','r','v', + 'i','c','e','s','\\','V','x','D','\\','M','S','T','C','P','\0' }; +static const WCHAR NetBT_ParametersW[] = { 'S','Y','S','T','E','M','\\','C','u', + 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','S','e','r', + 'v','i','c','e','s','\\','N','e','t','B','T','\\','P','a','r','a','m','e','t', + 'e','r','s','\0' }; +static const WCHAR EnableDNSW[] = { 'E','n','a','b','l','e','D','N','S','\0' }; +static const WCHAR BcastNameQueryCountW[] = { 'B','c','a','s','t','N','a','m', + 'e','Q','u','e','r','y','C','o','u','n','t','\0' }; +static const WCHAR BcastNameQueryTimeoutW[] = { 'B','c','a','s','t','N','a','m', + 'e','Q','u','e','r','y','T','i','m','e','o','u','t','\0' }; +static const WCHAR NameSrvQueryCountW[] = { 'N','a','m','e','S','r','v', + 'Q','u','e','r','y','C','o','u','n','t','\0' }; +static const WCHAR NameSrvQueryTimeoutW[] = { 'N','a','m','e','S','r','v', + 'Q','u','e','r','y','T','i','m','e','o','u','t','\0' }; +static const WCHAR ScopeIDW[] = { 'S','c','o','p','e','I','D','\0' }; +static const WCHAR CacheTimeoutW[] = { 'C','a','c','h','e','T','i','m','e','o', + 'u','t','\0' }; +static const WCHAR Config_NetworkW[] = { 'S','o','f','t','w','a','r','e','\\', + 'W','i','n','e','\\','N','e','t','w','o','r','k','\0' }; + +/* Initializes global variables and registers the NetBT transport */ +void NetBTInit(void) +{ + HKEY hKey; + NetBIOSTransport transport; + LONG ret; + + TRACE("\n"); + + gEnableDNS = TRUE; + gBCastQueries = BCAST_QUERIES; + gBCastQueryTimeout = BCAST_QUERY_TIMEOUT; + gWINSQueries = WINS_QUERIES; + gWINSQueryTimeout = WINS_QUERY_TIMEOUT; + gNumWINSServers = 0; + memset(gWINSServers, 0, sizeof(gWINSServers)); + gScopeID[0] = '\0'; + gCacheTimeout = CACHE_TIMEOUT; + + /* Try to open the Win9x NetBT configuration key */ + ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, VxD_MSTCPW, 0, KEY_READ, &hKey); + /* If that fails, try the WinNT NetBT configuration key */ + if (ret != ERROR_SUCCESS) + ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, NetBT_ParametersW, 0, KEY_READ, + &hKey); + if (ret == ERROR_SUCCESS) + { + DWORD dword, size; + + size = sizeof(dword); + if (RegQueryValueExW(hKey, EnableDNSW, NULL, NULL, + (LPBYTE)&dword, &size) == ERROR_SUCCESS) + gEnableDNS = dword; + size = sizeof(dword); + if (RegQueryValueExW(hKey, BcastNameQueryCountW, NULL, NULL, + (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_QUERIES + && dword <= MAX_QUERIES) + gBCastQueries = dword; + size = sizeof(dword); + if (RegQueryValueExW(hKey, BcastNameQueryTimeoutW, NULL, NULL, + (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_QUERY_TIMEOUT + && dword <= MAX_QUERY_TIMEOUT) + gBCastQueryTimeout = dword; + size = sizeof(dword); + if (RegQueryValueExW(hKey, NameSrvQueryCountW, NULL, NULL, + (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_QUERIES + && dword <= MAX_QUERIES) + gWINSQueries = dword; + size = sizeof(dword); + if (RegQueryValueExW(hKey, NameSrvQueryTimeoutW, NULL, NULL, + (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_QUERY_TIMEOUT + && dword <= MAX_QUERY_TIMEOUT) + gWINSQueryTimeout = dword; + size = MAX_DOMAIN_NAME_LEN - 1; + if (RegQueryValueExW(hKey, ScopeIDW, NULL, NULL, (LPBYTE)gScopeID + 1, &size) + == ERROR_SUCCESS) + { + /* convert into L2-encoded version, suitable for use by + NetBTNameEncode */ + char *ptr, *lenPtr; + + for (ptr = gScopeID + 1; *ptr && + ptr - gScopeID < MAX_DOMAIN_NAME_LEN; ) + { + for (lenPtr = ptr - 1, *lenPtr = 0; *ptr && *ptr != '.' && + ptr - gScopeID < MAX_DOMAIN_NAME_LEN; ptr++) + *lenPtr += 1; + ptr++; + } + } + if (RegQueryValueExW(hKey, CacheTimeoutW, NULL, NULL, + (LPBYTE)&dword, &size) == ERROR_SUCCESS && dword >= MIN_CACHE_TIMEOUT) + gCacheTimeout = dword; + RegCloseKey(hKey); + } + /* WINE-specific NetBT registry settings. Because our adapter naming is + * different than MS', we can't do per-adapter WINS configuration in the + * same place. Just do a global WINS configuration instead. + */ + /* @@ Wine registry key: HKCU\Software\Wine\Network */ + if (RegOpenKeyW(HKEY_CURRENT_USER, Config_NetworkW, &hKey) == ERROR_SUCCESS) + { + static const char *nsValueNames[] = { "WinsServer", "BackupWinsServer" }; + char nsString[16]; + DWORD size, ndx; + + for (ndx = 0; ndx < sizeof(nsValueNames) / sizeof(nsValueNames[0]); + ndx++) + { + size = sizeof(nsString) / sizeof(char); + if (RegQueryValueExA(hKey, nsValueNames[ndx], NULL, NULL, + (LPBYTE)nsString, &size) == ERROR_SUCCESS) + { + unsigned long addr = inet_addr(nsString); + + if (addr != INADDR_NONE && gNumWINSServers < MAX_WINS_SERVERS) + gWINSServers[gNumWINSServers++] = addr; + } + } + RegCloseKey(hKey); + } + + transport.enumerate = NetBTEnum; + transport.astat = NetBTAstat; + transport.findName = NetBTFindName; + transport.call = NetBTCall; + transport.send = NetBTSend; + transport.recv = NetBTRecv; + transport.hangup = NetBTHangup; + transport.cleanupAdapter = NetBTCleanupAdapter; + transport.cleanup = NetBTCleanup; + memcpy(&gTransportID, TRANSPORT_NBT, sizeof(ULONG)); + NetBIOSRegisterTransport(gTransportID, &transport); +} diff --git a/reactos/lib/netapi32/netapi32.c b/reactos/lib/netapi32/netapi32.c new file mode 100644 index 00000000000..320109b1b8a --- /dev/null +++ b/reactos/lib/netapi32/netapi32.c @@ -0,0 +1,135 @@ +/* Copyright 2001 Mike McCormack + * Copyright 2003 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include "wine/debug.h" +#include "netbios.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netbios); + +HMODULE NETAPI32_hModule = 0; + +BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved); + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + { + DisableThreadLibraryCalls(hinstDLL); + NETAPI32_hModule = hinstDLL; + NetBIOSInit(); + NetBTInit(); + break; + } + case DLL_PROCESS_DETACH: + { + NetBIOSShutdown(); + break; + } + } + + return TRUE; +} + +NET_API_STATUS WINAPI NetServerEnum( + LPCWSTR servername, + DWORD level, + LPBYTE* bufptr, + DWORD prefmaxlen, + LPDWORD entriesread, + LPDWORD totalentries, + DWORD servertype, + LPCWSTR domain, + LPDWORD resume_handle +) +{ + FIXME("Stub (%s %ld %p %ld %p %p %ld %s %p)\n", debugstr_w(servername), + level, bufptr, prefmaxlen, entriesread, totalentries, servertype, + debugstr_w(domain), resume_handle); + + return ERROR_NO_BROWSER_SERVERS_FOUND; +} + + +/************************************************************ + * NetServerGetInfo (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetServerGetInfo(LMSTR servername, DWORD level, LPBYTE* bufptr) +{ + FIXME("stub (%p, %ld, %p)\n", servername, level, bufptr); + return ERROR_ACCESS_DENIED; +} + + +/************************************************************ + * NetStatisticsGet (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetStatisticsGet(LPWSTR server, LPWSTR service, + DWORD level, DWORD options, + LPBYTE *bufptr) +{ + TRACE("(%p, %p, %ld, %ld, %p)\n", server, service, level, options, bufptr); + return NERR_InternalError; +} + +DWORD WINAPI NetpNetBiosStatusToApiStatus(DWORD nrc) +{ + DWORD ret; + + switch (nrc) + { + case NRC_GOODRET: + ret = NO_ERROR; + break; + case NRC_NORES: + ret = NERR_NoNetworkResource; + break; + case NRC_DUPNAME: + ret = NERR_AlreadyExists; + break; + case NRC_NAMTFUL: + ret = NERR_TooManyNames; + break; + case NRC_ACTSES: + ret = NERR_DeleteLater; + break; + case NRC_REMTFUL: + ret = ERROR_REM_NOT_LIST; + break; + case NRC_NOCALL: + ret = NERR_NameNotFound; + break; + case NRC_NOWILD: + ret = ERROR_INVALID_PARAMETER; + break; + case NRC_INUSE: + ret = NERR_DuplicateName; + break; + case NRC_NAMERR: + ret = ERROR_INVALID_PARAMETER; + break; + case NRC_NAMCONF: + ret = NERR_DuplicateName; + break; + default: + ret = NERR_NetworkError; + } + return ret; +} diff --git a/reactos/lib/netapi32/netapi32.spec b/reactos/lib/netapi32/netapi32.spec new file mode 100644 index 00000000000..412ac72dabc --- /dev/null +++ b/reactos/lib/netapi32/netapi32.spec @@ -0,0 +1,275 @@ +@ stub I_BrowserDebugCall +@ stub I_BrowserDebugTrace +@ stdcall I_BrowserQueryEmulatedDomains(wstr ptr ptr) +@ stub I_BrowserQueryOtherDomains +@ stub I_BrowserQueryStatistics +@ stub I_BrowserResetNetlogonState +@ stub I_BrowserResetStatistics +@ stub I_BrowserServerEnum +@ stdcall I_BrowserSetNetlogonState(wstr wstr wstr long) +@ stub I_NetAccountDeltas +@ stub I_NetAccountSync +@ stub I_NetDatabaseDeltas +@ stub I_NetDatabaseRedo +@ stub I_NetDatabaseSync2 +@ stub I_NetDatabaseSync +@ stub I_NetDfsCreateExitPoint +@ stub I_NetDfsCreateLocalPartition +@ stub I_NetDfsDeleteExitPoint +@ stub I_NetDfsDeleteLocalPartition +@ stub I_NetDfsFixLocalVolume +@ stub I_NetDfsGetVersion +@ stub I_NetDfsIsThisADomainName +@ stub I_NetDfsModifyPrefix +@ stub I_NetDfsSetLocalVolumeState +@ stub I_NetDfsSetServerInfo +@ stub I_NetGetDCList +@ stub I_NetListCanonicalize +@ stub I_NetListTraverse +@ stub I_NetLogonControl2 +@ stub I_NetLogonControl +@ stub I_NetLogonSamLogoff +@ stub I_NetLogonSamLogon +@ stub I_NetLogonUasLogoff +@ stub I_NetLogonUasLogon +@ stub I_NetNameCanonicalize +@ stdcall I_NetNameCompare(ptr wstr wstr ptr ptr) +@ stdcall I_NetNameValidate(ptr wstr ptr ptr) +@ stub I_NetPathCanonicalize +@ stub I_NetPathCompare +@ stub I_NetPathType +@ stub I_NetServerAuthenticate2 +@ stub I_NetServerAuthenticate +@ stub I_NetServerPasswordSet +@ stub I_NetServerReqChallenge +@ stub I_NetServerSetServiceBits +@ stub I_NetServerSetServiceBitsEx +@ stub NetAlertRaise +@ stub NetAlertRaiseEx +@ stdcall NetApiBufferAllocate(long ptr) +@ stdcall NetApiBufferFree(ptr) +@ stdcall NetApiBufferReallocate(ptr long ptr) +@ stdcall NetApiBufferSize(ptr ptr) +@ stub NetAuditClear +@ stub NetAuditRead +@ stub NetAuditWrite +@ stub NetBrowserStatisticsGet +@ stub NetConfigGet +@ stub NetConfigGetAll +@ stub NetConfigSet +@ stub NetConnectionEnum +@ stub NetDfsAdd +@ stub NetDfsEnum +@ stub NetDfsGetInfo +@ stub NetDfsManagerGetConfigInfo +@ stub NetDfsMove +@ stub NetDfsRemove +@ stub NetDfsRename +@ stub NetDfsSetInfo +@ stub NetEnumerateTrustedDomains +@ stub NetErrorLogClear +@ stub NetErrorLogRead +@ stub NetErrorLogWrite +@ stub NetFileClose +@ stub NetFileEnum +@ stub NetFileGetInfo +@ stub NetGetAnyDCName +@ stdcall NetGetDCName(wstr wstr ptr) +@ stub NetGetDisplayInformationIndex +@ stdcall NetGetJoinInformation(wstr ptr ptr) +@ stub NetGroupAdd +@ stub NetGroupAddUser +@ stub NetGroupDel +@ stub NetGroupDelUser +@ stub NetGroupEnum +@ stub NetGroupGetInfo +@ stub NetGroupGetUsers +@ stub NetGroupSetInfo +@ stub NetGroupSetUsers +@ stdcall NetLocalGroupAdd(wstr long ptr ptr) +@ stub NetLocalGroupAddMember +@ stub NetLocalGroupAddMembers +@ stub NetLocalGroupDel +@ stub NetLocalGroupDelMember +@ stub NetLocalGroupDelMembers +@ stub NetLocalGroupEnum +@ stub NetLocalGroupGetInfo +@ stub NetLocalGroupGetMembers +@ stub NetLocalGroupSetInfo +@ stdcall NetLocalGroupSetMembers(wstr wstr long ptr ptr) +@ stub NetMessageBufferSend +@ stub NetMessageNameAdd +@ stub NetMessageNameDel +@ stub NetMessageNameEnum +@ stub NetMessageNameGetInfo +@ stdcall NetQueryDisplayInformation(wstr long long long long ptr ptr) +@ stub NetRemoteComputerSupports +@ stub NetRemoteTOD +@ stub NetReplExportDirAdd +@ stub NetReplExportDirDel +@ stub NetReplExportDirEnum +@ stub NetReplExportDirGetInfo +@ stub NetReplExportDirLock +@ stub NetReplExportDirSetInfo +@ stub NetReplExportDirUnlock +@ stub NetReplGetInfo +@ stub NetReplImportDirAdd +@ stub NetReplImportDirDel +@ stub NetReplImportDirEnum +@ stub NetReplImportDirGetInfo +@ stub NetReplImportDirLock +@ stub NetReplImportDirUnlock +@ stub NetReplSetInfo +@ stub NetRplAdapterAdd +@ stub NetRplAdapterDel +@ stub NetRplAdapterEnum +@ stub NetRplBootAdd +@ stub NetRplBootDel +@ stub NetRplBootEnum +@ stub NetRplClose +@ stub NetRplConfigAdd +@ stub NetRplConfigDel +@ stub NetRplConfigEnum +@ stub NetRplGetInfo +@ stub NetRplOpen +@ stub NetRplProfileAdd +@ stub NetRplProfileClone +@ stub NetRplProfileDel +@ stub NetRplProfileEnum +@ stub NetRplProfileGetInfo +@ stub NetRplProfileSetInfo +@ stub NetRplSetInfo +@ stub NetRplSetSecurity +@ stub NetRplVendorAdd +@ stub NetRplVendorDel +@ stub NetRplVendorEnum +@ stub NetRplWkstaAdd +@ stub NetRplWkstaClone +@ stub NetRplWkstaDel +@ stub NetRplWkstaEnum +@ stub NetRplWkstaGetInfo +@ stub NetRplWkstaSetInfo +@ stub NetScheduleJobAdd +@ stub NetScheduleJobDel +@ stub NetScheduleJobEnum +@ stub NetScheduleJobGetInfo +@ stub NetServerComputerNameAdd +@ stub NetServerComputerNameDel +@ stub NetServerDiskEnum +@ stdcall NetServerEnum(wstr long ptr long ptr ptr long wstr ptr) +@ stub NetServerEnumEx +@ stdcall NetServerGetInfo(wstr long ptr) +@ stub NetServerSetInfo +@ stub NetServerTransportAdd +@ stub NetServerTransportAddEx +@ stub NetServerTransportDel +@ stub NetServerTransportEnum +@ stub NetServiceControl +@ stub NetServiceEnum +@ stub NetServiceGetInfo +@ stub NetServiceInstall +@ stub NetSessionDel +@ stub NetSessionEnum +@ stub NetSessionGetInfo +@ stub NetShareAdd +@ stub NetShareCheck +@ stub NetShareDel +@ stub NetShareDelSticky +@ stdcall NetShareEnum(wstr long ptr long ptr ptr ptr) +@ stub NetShareEnumSticky +@ stub NetShareGetInfo +@ stub NetShareSetInfo +@ stdcall NetStatisticsGet(wstr wstr long long ptr) +@ stub NetUseAdd +@ stub NetUseDel +@ stub NetUseEnum +@ stub NetUseGetInfo +@ stdcall NetUserAdd(wstr long ptr ptr) +@ stub NetUserChangePassword +@ stdcall NetUserDel(wstr wstr) +@ stdcall NetUserEnum(wstr long long ptr long ptr ptr ptr) +@ stub NetUserGetGroups +@ stdcall NetUserGetInfo(wstr wstr long ptr) +@ stub NetUserGetLocalGroups +@ stdcall NetUserModalsGet(wstr long ptr) +@ stub NetUserModalsSet +@ stub NetUserSetGroups +@ stub NetUserSetInfo +@ stdcall NetWkstaGetInfo(wstr long ptr) +@ stub NetWkstaSetInfo +@ stub NetWkstaTransportAdd +@ stub NetWkstaTransportDel +@ stdcall NetWkstaTransportEnum (wstr long ptr long ptr ptr ptr) +@ stub NetWkstaUserEnum +@ stdcall NetWkstaUserGetInfo(wstr long ptr) +@ stub NetWkstaUserSetInfo +@ stdcall NetapipBufferAllocate(long ptr) NetApiBufferAllocate +@ stdcall Netbios(ptr) +@ stub NetpAccessCheck +@ stub NetpAccessCheckAndAudit +@ stub NetpAllocConfigName +@ stub NetpAllocStrFromStr +@ stub NetpAllocStrFromWStr +@ stub NetpAllocTStrFromString +@ stub NetpAllocWStrFromStr +@ stub NetpAllocWStrFromWStr +@ stub NetpApiStatusToNtStatus +@ stub NetpAssertFailed +@ stub NetpCloseConfigData +@ stub NetpCopyStringToBuffer +@ stub NetpCreateSecurityObject +@ stub NetpDbgDisplayServerInfo +@ stub NetpDbgPrint +@ stdcall NetpDeleteSecurityObject(long) ntdll.RtlDeleteSecurityObject +@ stdcall NetpGetComputerName(ptr) +@ stub NetpGetConfigBool +@ stub NetpGetConfigDword +@ stub NetpGetConfigTStrArray +@ stub NetpGetConfigValue +@ stub NetpGetDomainName +@ stub NetpGetFileSecurity +@ stub NetpGetPrivilege +@ stub NetpHexDump +@ stdcall NetpInitOemString(ptr str) ntdll.RtlInitAnsiString +@ stub NetpIsRemote +@ stub NetpIsUncComputerNameValid +@ stub NetpLocalTimeZoneOffset +@ stub NetpLogonPutUnicodeString +@ stub NetpNetBiosAddName +@ stub NetpNetBiosCall +@ stub NetpNetBiosDelName +@ stub NetpNetBiosGetAdapterNumbers +@ stub NetpNetBiosHangup +@ stub NetpNetBiosReceive +@ stub NetpNetBiosReset +@ stub NetpNetBiosSend +@ stdcall NetpNetBiosStatusToApiStatus(long) +@ stub NetpNtStatusToApiStatus +@ stub NetpOpenConfigData +@ stub NetpPackString +@ stub NetpReleasePrivilege +@ stub NetpSetConfigBool +@ stub NetpSetConfigDword +@ stub NetpSetConfigTStrArray +@ stub NetpSetFileSecurity +@ stub NetpSmbCheck +@ stub NetpStringToNetBiosName +@ stub NetpTStrArrayEntryCount +@ stub NetpwNameCanonicalize +@ stub NetpwNameCompare +@ stub NetpwNameValidate +@ stub NetpwPathCanonicalize +@ stub NetpwPathCompare +@ stub NetpwPathType +@ stub NlBindingAddServerToCache +@ stub NlBindingRemoveServerFromCache +@ stub NlBindingSetAuthInfo +@ stub RxNetAccessAdd +@ stub RxNetAccessDel +@ stub RxNetAccessEnum +@ stub RxNetAccessGetInfo +@ stub RxNetAccessGetUserPerms +@ stub RxNetAccessSetInfo +@ stub RxNetServerEnum +@ stub RxNetUserPasswordSet +@ stub RxRemoteApi diff --git a/reactos/lib/netapi32/netapi32.xml b/reactos/lib/netapi32/netapi32.xml new file mode 100644 index 00000000000..b5db33de5e8 --- /dev/null +++ b/reactos/lib/netapi32/netapi32.xml @@ -0,0 +1,27 @@ + + + . + include/wine + + + 0x600 + 0x501 + 0x501 + + wine + ntdll + kernel32 + advapi32 + ws2_32 + iphlpapi + access.c + apibuf.c + browsr.c + nbcmdqueue.c + nbnamecache.c + nbt.c + netapi32.c + netbios.c + wksta.c + netapi32.spec + diff --git a/reactos/lib/netapi32/netapi32_misc.h b/reactos/lib/netapi32/netapi32_misc.h new file mode 100644 index 00000000000..92cbc26d07a --- /dev/null +++ b/reactos/lib/netapi32/netapi32_misc.h @@ -0,0 +1,35 @@ +/* + * Copyright 2002 Andriy Palamarchuk + * + * netapi32 internal functions. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, writ +e to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_NETAPI32_MISC_H +#define __WINE_NETAPI32_MISC_H + +extern BOOL NETAPI_IsLocalComputer(LPCWSTR ServerName); + +#define NETAPI_ForceLocalComputer(ServerName, FailureCode) \ + if (!NETAPI_IsLocalComputer(ServerName)) \ + { \ + FIXME("Action Implemented for local computer only. " \ + "Requested for server %s\n", debugstr_w(ServerName)); \ + return FailureCode; \ + } + +#endif diff --git a/reactos/lib/netapi32/netbios.c b/reactos/lib/netapi32/netbios.c new file mode 100644 index 00000000000..71f503a2714 --- /dev/null +++ b/reactos/lib/netapi32/netbios.c @@ -0,0 +1,857 @@ +/* Copyright (c) 2003 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" +#include "wine/debug.h" +#include "nbcmdqueue.h" +#include "netbios.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netbios); + +/* This file provides a NetBIOS emulator that implements the NetBIOS interface, + * including thread safety and asynchronous call support. The protocol + * implementation is separate, with blocking (synchronous) functions. + */ + +#define ADAPTERS_INCR 8 +#define DEFAULT_NUM_SESSIONS 16 + +typedef struct _NetBIOSTransportTableEntry +{ + ULONG id; + NetBIOSTransport transport; +} NetBIOSTransportTableEntry; + +typedef struct _NetBIOSSession +{ + BOOL inUse; + UCHAR state; + UCHAR local_name[NCBNAMSZ]; + UCHAR remote_name[NCBNAMSZ]; + void *data; +} NetBIOSSession; + +/* This struct needs a little explanation, unfortunately. enabled is only + * used by nbInternalEnum (see). If transport_id is not 0 and transport + * is not NULL, the adapter is considered valid. (transport is a pointer to + * an entry in a NetBIOSTransportTableEntry.) data has data for the callers of + * NetBIOSEnumAdapters to be able to see. The lana is repeated there, even + * though I don't use it internally--it's for transports to use reenabling + * adapters using NetBIOSEnableAdapter. + */ +typedef struct _NetBIOSAdapter +{ + BOOL enabled; + BOOL shuttingDown; + LONG resetting; + ULONG transport_id; + NetBIOSTransport *transport; + NetBIOSAdapterImpl impl; + struct NBCmdQueue *cmdQueue; + CRITICAL_SECTION cs; + DWORD sessionsLen; + NetBIOSSession *sessions; +} NetBIOSAdapter; + +typedef struct _NetBIOSAdapterTable { + CRITICAL_SECTION cs; + BOOL enumerated; + BOOL enumerating; + UCHAR tableSize; + NetBIOSAdapter *table; +} NetBIOSAdapterTable; + +/* Just enough space for NBT right now */ +static NetBIOSTransportTableEntry gTransports[1]; +static UCHAR gNumTransports = 0; +static NetBIOSAdapterTable gNBTable; + +static UCHAR nbResizeAdapterTable(UCHAR newSize) +{ + UCHAR ret; + + if (gNBTable.table) + gNBTable.table = HeapReAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, gNBTable.table, + newSize * sizeof(NetBIOSAdapter)); + else + gNBTable.table = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, newSize * sizeof(NetBIOSAdapter)); + if (gNBTable.table) + { + gNBTable.tableSize = newSize; + ret = NRC_GOODRET; + } + else + ret = NRC_OSRESNOTAV; + return ret; +} + +void NetBIOSInit(void) +{ + memset(&gNBTable, 0, sizeof(gNBTable)); + InitializeCriticalSection(&gNBTable.cs); +} + +void NetBIOSShutdown(void) +{ + UCHAR i; + + EnterCriticalSection(&gNBTable.cs); + for (i = 0; i < gNBTable.tableSize; i++) + { + if (gNBTable.table[i].transport && + gNBTable.table[i].transport->cleanupAdapter) + gNBTable.table[i].transport->cleanupAdapter( + gNBTable.table[i].impl.data); + } + for (i = 0; i < gNumTransports; i++) + if (gTransports[i].transport.cleanup) + gTransports[i].transport.cleanup(); + LeaveCriticalSection(&gNBTable.cs); + DeleteCriticalSection(&gNBTable.cs); + HeapFree(GetProcessHeap(), 0, gNBTable.table); +} + +BOOL NetBIOSRegisterTransport(ULONG id, NetBIOSTransport *transport) +{ + BOOL ret; + + TRACE(": transport 0x%08lx, p %p\n", id, transport); + if (!transport) + ret = FALSE; + else if (gNumTransports >= sizeof(gTransports) / sizeof(gTransports[0])) + { + FIXME("You tried to add %d transports, but I only have space for %d\n", + gNumTransports + 1, sizeof(gTransports) / sizeof(gTransports[0])); + ret = FALSE; + } + else + { + UCHAR i; + + ret = FALSE; + for (i = 0; !ret && i < gNumTransports; i++) + { + if (gTransports[i].id == id) + { + WARN("Replacing NetBIOS transport ID %ld\n", id); + memcpy(&gTransports[i].transport, transport, + sizeof(NetBIOSTransport)); + ret = TRUE; + } + } + if (!ret) + { + gTransports[gNumTransports].id = id; + memcpy(&gTransports[gNumTransports].transport, transport, + sizeof(NetBIOSTransport)); + gNumTransports++; + ret = TRUE; + } + } + TRACE("returning %d\n", ret); + return ret; +} + +/* In this, I acquire the table lock to make sure no one else is modifying it. + * This is _probably_ overkill since it should only be called during the + * context of a NetBIOSEnum call, but just to be safe.. + */ +BOOL NetBIOSRegisterAdapter(ULONG transport, DWORD ifIndex, void *data) +{ + BOOL ret; + UCHAR i; + + TRACE(": transport 0x%08lx, ifIndex 0x%08lx, data %p\n", transport, ifIndex, + data); + for (i = 0; i < gNumTransports && gTransports[i].id != transport; i++) + ; + if (gTransports[i].id == transport) + { + NetBIOSTransport *transportPtr = &gTransports[i].transport; + + TRACE(": found transport %p for id 0x%08lx\n", transportPtr, transport); + + EnterCriticalSection(&gNBTable.cs); + ret = FALSE; + for (i = 0; i < gNBTable.tableSize && + gNBTable.table[i].transport != 0; i++) + ; + if (i == gNBTable.tableSize && gNBTable.tableSize < MAX_LANA + 1) + { + UCHAR newSize; + + if (gNBTable.tableSize < (MAX_LANA + 1) - ADAPTERS_INCR) + newSize = gNBTable.tableSize + ADAPTERS_INCR; + else + newSize = MAX_LANA + 1; + nbResizeAdapterTable(newSize); + } + if (i < gNBTable.tableSize && gNBTable.table[i].transport == 0) + { + TRACE(": registering as LANA %d\n", i); + gNBTable.table[i].transport_id = transport; + gNBTable.table[i].transport = transportPtr; + gNBTable.table[i].impl.lana = i; + gNBTable.table[i].impl.ifIndex = ifIndex; + gNBTable.table[i].impl.data = data; + gNBTable.table[i].cmdQueue = NBCmdQueueCreate(GetProcessHeap()); + InitializeCriticalSection(&gNBTable.table[i].cs); + gNBTable.table[i].enabled = TRUE; + ret = TRUE; + } + LeaveCriticalSection(&gNBTable.cs); + } + else + ret = FALSE; + TRACE("returning %d\n", ret); + return ret; +} + +/* In this, I acquire the table lock to make sure no one else is modifying it. + * This is _probably_ overkill since it should only be called during the + * context of a NetBIOSEnum call, but just to be safe.. + */ +void NetBIOSEnableAdapter(UCHAR lana) +{ + TRACE(": %d\n", lana); + if (lana < gNBTable.tableSize) + { + EnterCriticalSection(&gNBTable.cs); + if (gNBTable.table[lana].transport != 0) + gNBTable.table[lana].enabled = TRUE; + LeaveCriticalSection(&gNBTable.cs); + } +} + +static void nbShutdownAdapter(NetBIOSAdapter *adapter) +{ + if (adapter) + { + adapter->shuttingDown = TRUE; + NBCmdQueueCancelAll(adapter->cmdQueue); + if (adapter->transport->cleanupAdapter) + adapter->transport->cleanupAdapter(adapter->impl.data); + NBCmdQueueDestroy(adapter->cmdQueue); + DeleteCriticalSection(&adapter->cs); + memset(adapter, 0, sizeof(NetBIOSAdapter)); + } +} + +static void nbInternalEnum(void) +{ + UCHAR i; + + EnterCriticalSection(&gNBTable.cs); + TRACE("before mark\n"); + /* mark: */ + for (i = 0; i < gNBTable.tableSize; i++) + if (gNBTable.table[i].enabled && gNBTable.table[i].transport != 0) + gNBTable.table[i].enabled = FALSE; + + TRACE("marked, before store, %d transports\n", gNumTransports); + /* store adapters: */ + for (i = 0; i < gNumTransports; i++) + if (gTransports[i].transport.enumerate) + gTransports[i].transport.enumerate(); + + TRACE("before sweep\n"); + /* sweep: */ + for (i = 0; i < gNBTable.tableSize; i++) + if (!gNBTable.table[i].enabled && gNBTable.table[i].transport != 0) + nbShutdownAdapter(&gNBTable.table[i]); + gNBTable.enumerated = TRUE; + LeaveCriticalSection(&gNBTable.cs); +} + +UCHAR NetBIOSNumAdapters(void) +{ + UCHAR ret, i; + + if (!gNBTable.enumerated) + nbInternalEnum(); + for (i = 0, ret = 0; i < gNBTable.tableSize; i++) + if (gNBTable.table[i].transport != 0) + ret++; + return ret; +} + +void NetBIOSEnumAdapters(ULONG transport, NetBIOSEnumAdaptersCallback cb, + void *closure) +{ + TRACE("transport 0x%08lx, callback %p, closure %p\n", transport, cb, + closure); + if (cb) + { + BOOL enumAll = memcmp(&transport, ALL_TRANSPORTS, sizeof(ULONG)) == 0; + UCHAR i, numLANAs = 0; + + EnterCriticalSection(&gNBTable.cs); + if (!gNBTable.enumerating) + { + gNBTable.enumerating = TRUE; + nbInternalEnum(); + gNBTable.enumerating = FALSE; + } + for (i = 0; i < gNBTable.tableSize; i++) + if (enumAll || gNBTable.table[i].transport_id == transport) + numLANAs++; + if (numLANAs > 0) + { + UCHAR lanaIndex = 0; + + for (i = 0; i < gNBTable.tableSize; i++) + if (gNBTable.table[i].transport_id != 0 && + (enumAll || gNBTable.table[i].transport_id == transport)) + cb(numLANAs, lanaIndex++, gNBTable.table[i].transport_id, + &gNBTable.table[i].impl, closure); + } + LeaveCriticalSection(&gNBTable.cs); + } +} + +static NetBIOSAdapter *nbGetAdapter(UCHAR lana) +{ + NetBIOSAdapter *ret = NULL; + + TRACE(": lana %d, num allocated adapters %d\n", lana, gNBTable.tableSize); + if (lana < gNBTable.tableSize && gNBTable.table[lana].transport_id != 0 + && gNBTable.table[lana].transport) + ret = &gNBTable.table[lana]; + TRACE("returning %p\n", ret); + return ret; +} + +static UCHAR nbEnum(PNCB ncb) +{ + PLANA_ENUM lanas = (PLANA_ENUM)ncb->ncb_buffer; + UCHAR i, ret; + + TRACE(": ncb %p\n", ncb); + + if (!lanas) + ret = NRC_BUFLEN; + else if (ncb->ncb_length < sizeof(LANA_ENUM)) + ret = NRC_BUFLEN; + else + { + nbInternalEnum(); + lanas->length = 0; + for (i = 0; i < gNBTable.tableSize; i++) + if (gNBTable.table[i].transport) + { + lanas->length++; + lanas->lana[i] = i; + } + ret = NRC_GOODRET; + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR nbInternalHangup(NetBIOSAdapter *adapter, NetBIOSSession *session); + +static UCHAR nbCancel(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret; + + TRACE(": adapter %p, ncb %p\n", adapter, ncb); + + if (!adapter) return NRC_BRIDGE; + if (!ncb) return NRC_INVADDRESS; + + switch (ncb->ncb_command & 0x7f) + { + case NCBCANCEL: + case NCBADDNAME: + case NCBADDGRNAME: + case NCBDELNAME: + case NCBRESET: + case NCBSSTAT: + ret = NRC_CANCEL; + break; + + /* NCBCALL, NCBCHAINSEND/NCBSEND, NCBHANGUP all close the associated + * session if cancelled */ + case NCBCALL: + case NCBSEND: + case NCBCHAINSEND: + case NCBSENDNA: + case NCBCHAINSENDNA: + case NCBHANGUP: + { + if (ncb->ncb_lsn >= adapter->sessionsLen) + ret = NRC_SNUMOUT; + else if (!adapter->sessions[ncb->ncb_lsn].inUse) + ret = NRC_SNUMOUT; + else + { + ret = NBCmdQueueCancel(adapter->cmdQueue, ncb); + if (ret == NRC_CMDCAN || ret == NRC_CANOCCR) + nbInternalHangup(adapter, &adapter->sessions[ncb->ncb_lsn]); + } + break; + } + + default: + ret = NBCmdQueueCancel(adapter->cmdQueue, ncb); + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +/* Resizes adapter to contain space for at least sessionsLen sessions. + * If allocating more space for sessions, sets the adapter's sessionsLen to + * sessionsLen. If the adapter's sessionsLen was already at least sessionsLen, + * does nothing. Does not modify existing sessions. Assumes the adapter is + * locked. + * Returns NRC_GOODRET on success, and something else on failure. + */ +static UCHAR nbResizeAdapter(NetBIOSAdapter *adapter, UCHAR sessionsLen) +{ + UCHAR ret = NRC_GOODRET; + + if (adapter && adapter->sessionsLen < sessionsLen) + { + NetBIOSSession *newSessions; + + if (adapter->sessions) + newSessions = HeapReAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, adapter->sessions, sessionsLen * + sizeof(NetBIOSSession)); + else + newSessions = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sessionsLen * sizeof(NetBIOSSession)); + if (newSessions) + { + adapter->sessions = newSessions; + adapter->sessionsLen = sessionsLen; + } + else + ret = NRC_OSRESNOTAV; + } + return ret; +} + +static UCHAR nbReset(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret; + + TRACE(": adapter %p, ncb %p\n", adapter, ncb); + + if (!adapter) return NRC_BRIDGE; + if (!ncb) return NRC_INVADDRESS; + + if (InterlockedIncrement(&adapter->resetting) == 1) + { + UCHAR i, resizeTo; + + NBCmdQueueCancelAll(adapter->cmdQueue); + + EnterCriticalSection(&adapter->cs); + for (i = 0; i < adapter->sessionsLen; i++) + if (adapter->sessions[i].inUse) + nbInternalHangup(adapter, &adapter->sessions[i]); + if (!ncb->ncb_lsn) + resizeTo = ncb->ncb_callname[0] == 0 ? DEFAULT_NUM_SESSIONS : + ncb->ncb_callname[0]; + else if (adapter->sessionsLen == 0) + resizeTo = DEFAULT_NUM_SESSIONS; + else + resizeTo = 0; + if (resizeTo > 0) + ret = nbResizeAdapter(adapter, resizeTo); + else + ret = NRC_GOODRET; + LeaveCriticalSection(&adapter->cs); + } + else + ret = NRC_TOOMANY; + InterlockedDecrement(&adapter->resetting); + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR nbSStat(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret, i, spaceFor; + PSESSION_HEADER sstat; + + TRACE(": adapter %p, NCB %p\n", adapter, ncb); + + if (!adapter) return NRC_BADDR; + if (adapter->sessionsLen == 0) return NRC_ENVNOTDEF; + if (!ncb) return NRC_INVADDRESS; + if (!ncb->ncb_buffer) return NRC_BADDR; + if (ncb->ncb_length < sizeof(SESSION_HEADER)) return NRC_BUFLEN; + + sstat = (PSESSION_HEADER)ncb->ncb_buffer; + ret = NRC_GOODRET; + memset(sstat, 0, sizeof(SESSION_HEADER)); + spaceFor = (ncb->ncb_length - sizeof(SESSION_HEADER)) / + sizeof(SESSION_BUFFER); + EnterCriticalSection(&adapter->cs); + for (i = 0; ret == NRC_GOODRET && i < adapter->sessionsLen; i++) + { + if (adapter->sessions[i].inUse && (ncb->ncb_name[0] == '*' || + !memcmp(ncb->ncb_name, adapter->sessions[i].local_name, NCBNAMSZ))) + { + if (sstat->num_sess < spaceFor) + { + PSESSION_BUFFER buf; + + buf = (PSESSION_BUFFER)((PUCHAR)sstat + sizeof(SESSION_HEADER) + + sstat->num_sess * sizeof(SESSION_BUFFER)); + buf->lsn = i; + buf->state = adapter->sessions[i].state; + memcpy(buf->local_name, adapter->sessions[i].local_name, + NCBNAMSZ); + memcpy(buf->remote_name, adapter->sessions[i].remote_name, + NCBNAMSZ); + buf->rcvs_outstanding = buf->sends_outstanding = 0; + sstat->num_sess++; + } + else + ret = NRC_BUFLEN; + } + } + LeaveCriticalSection(&adapter->cs); + + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR nbCall(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret, i; + + TRACE(": adapter %p, NCB %p\n", adapter, ncb); + + if (!adapter) return NRC_BRIDGE; + if (adapter->sessionsLen == 0) return NRC_ENVNOTDEF; + if (!adapter->transport->call) return NRC_ILLCMD; + if (!ncb) return NRC_INVADDRESS; + + EnterCriticalSection(&adapter->cs); + for (i = 0; i < adapter->sessionsLen && adapter->sessions[i].inUse; i++) + ; + if (i < adapter->sessionsLen) + { + adapter->sessions[i].inUse = TRUE; + adapter->sessions[i].state = CALL_PENDING; + memcpy(adapter->sessions[i].local_name, ncb->ncb_name, NCBNAMSZ); + memcpy(adapter->sessions[i].remote_name, ncb->ncb_callname, NCBNAMSZ); + ret = NRC_GOODRET; + } + else + ret = NRC_LOCTFUL; + LeaveCriticalSection(&adapter->cs); + + if (ret == NRC_GOODRET) + { + ret = adapter->transport->call(adapter->impl.data, ncb, + &adapter->sessions[i].data); + if (ret == NRC_GOODRET) + { + ncb->ncb_lsn = i; + adapter->sessions[i].state = SESSION_ESTABLISHED; + } + else + { + adapter->sessions[i].inUse = FALSE; + adapter->sessions[i].state = 0; + } + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static UCHAR nbSend(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret; + NetBIOSSession *session; + + if (!adapter) return NRC_BRIDGE; + if (!adapter->transport->send) return NRC_ILLCMD; + if (!ncb) return NRC_INVADDRESS; + if (ncb->ncb_lsn >= adapter->sessionsLen) return NRC_SNUMOUT; + if (!adapter->sessions[ncb->ncb_lsn].inUse) return NRC_SNUMOUT; + if (!ncb->ncb_buffer) return NRC_BADDR; + + session = &adapter->sessions[ncb->ncb_lsn]; + if (session->state != SESSION_ESTABLISHED) + ret = NRC_SNUMOUT; + else + ret = adapter->transport->send(adapter->impl.data, session->data, ncb); + return ret; +} + +static UCHAR nbRecv(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret; + NetBIOSSession *session; + + if (!adapter) return NRC_BRIDGE; + if (!adapter->transport->recv) return NRC_ILLCMD; + if (!ncb) return NRC_INVADDRESS; + if (ncb->ncb_lsn >= adapter->sessionsLen) return NRC_SNUMOUT; + if (!adapter->sessions[ncb->ncb_lsn].inUse) return NRC_SNUMOUT; + if (!ncb->ncb_buffer) return NRC_BADDR; + + session = &adapter->sessions[ncb->ncb_lsn]; + if (session->state != SESSION_ESTABLISHED) + ret = NRC_SNUMOUT; + else + ret = adapter->transport->recv(adapter->impl.data, session->data, ncb); + return ret; +} + +static UCHAR nbInternalHangup(NetBIOSAdapter *adapter, NetBIOSSession *session) +{ + UCHAR ret; + + if (!adapter) return NRC_BRIDGE; + if (!session) return NRC_SNUMOUT; + + if (adapter->transport->hangup) + ret = adapter->transport->hangup(adapter->impl.data, session->data); + else + ret = NRC_ILLCMD; + EnterCriticalSection(&adapter->cs); + memset(session, 0, sizeof(NetBIOSSession)); + LeaveCriticalSection(&adapter->cs); + return NRC_GOODRET; +} + +static UCHAR nbHangup(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret; + NetBIOSSession *session; + + if (!adapter) return NRC_BRIDGE; + if (!ncb) return NRC_INVADDRESS; + if (ncb->ncb_lsn >= adapter->sessionsLen) return NRC_SNUMOUT; + if (!adapter->sessions[ncb->ncb_lsn].inUse) return NRC_SNUMOUT; + + session = &adapter->sessions[ncb->ncb_lsn]; + if (session->state != SESSION_ESTABLISHED) + ret = NRC_SNUMOUT; + else + { + session->state = HANGUP_PENDING; + ret = nbInternalHangup(adapter, session); + } + return ret; +} + +void NetBIOSHangupSession(PNCB ncb) +{ + NetBIOSAdapter *adapter; + + if (!ncb) return; + + adapter = nbGetAdapter(ncb->ncb_lana_num); + if (adapter) + { + if (ncb->ncb_lsn < adapter->sessionsLen && + adapter->sessions[ncb->ncb_lsn].inUse) + nbHangup(adapter, ncb); + } +} + +static UCHAR nbAStat(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret; + + if (!adapter) return NRC_BRIDGE; + if (!adapter->transport->astat) return NRC_ILLCMD; + if (!ncb) return NRC_INVADDRESS; + if (!ncb->ncb_buffer) return NRC_BADDR; + if (ncb->ncb_length < sizeof(ADAPTER_STATUS)) return NRC_BUFLEN; + + ret = adapter->transport->astat(adapter->impl.data, ncb); + if (ncb->ncb_callname[0] == '*') + { + PADAPTER_STATUS astat = (PADAPTER_STATUS)ncb->ncb_buffer; + + astat->max_sess = astat->max_cfg_sess = adapter->sessionsLen; + } + return ret; +} + +static UCHAR nbDispatch(NetBIOSAdapter *adapter, PNCB ncb) +{ + UCHAR ret, cmd; + + TRACE(": adapter %p, ncb %p\n", adapter, ncb); + + if (!adapter) return NRC_BRIDGE; + if (!ncb) return NRC_INVADDRESS; + + cmd = ncb->ncb_command & 0x7f; + if (cmd == NCBRESET) + ret = nbReset(adapter, ncb); + else + { + ret = NBCmdQueueAdd(adapter->cmdQueue, ncb); + if (ret == NRC_GOODRET) + { + switch (cmd) + { + case NCBCALL: + ret = nbCall(adapter, ncb); + break; + + /* WinNT doesn't chain sends, it always sends immediately. + * Doubt there's any real significance to the NA variants. + */ + case NCBSEND: + case NCBSENDNA: + case NCBCHAINSEND: + case NCBCHAINSENDNA: + ret = nbSend(adapter, ncb); + break; + + case NCBRECV: + ret = nbRecv(adapter, ncb); + break; + + case NCBHANGUP: + ret = nbHangup(adapter, ncb); + break; + + case NCBASTAT: + ret = nbAStat(adapter, ncb); + break; + + case NCBFINDNAME: + if (adapter->transport->findName) + ret = adapter->transport->findName(adapter->impl.data, + ncb); + else + ret = NRC_ILLCMD; + break; + + default: + FIXME("(%p): command code 0x%02x\n", ncb, ncb->ncb_command); + ret = NRC_ILLCMD; + } + NBCmdQueueComplete(adapter->cmdQueue, ncb, ret); + } + } + TRACE("returning 0x%02x\n", ret); + return ret; +} + +static DWORD WINAPI nbCmdThread(LPVOID lpVoid) +{ + PNCB ncb = (PNCB)lpVoid; + + if (ncb) + { + UCHAR ret; + NetBIOSAdapter *adapter = nbGetAdapter(ncb->ncb_lana_num); + + if (adapter) + ret = nbDispatch(adapter, ncb); + else + ret = NRC_BRIDGE; + ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret; + if (ncb->ncb_post) + ncb->ncb_post(ncb); + else if (ncb->ncb_event) + SetEvent(ncb->ncb_event); + } + return 0; +} + +UCHAR WINAPI Netbios(PNCB ncb) +{ + UCHAR ret, cmd; + + TRACE("ncb = %p\n", ncb); + + if (!ncb) return NRC_INVADDRESS; + + TRACE("ncb_command 0x%02x, ncb_lana_num %d, ncb_buffer %p, ncb_length %d\n", + ncb->ncb_command, ncb->ncb_lana_num, ncb->ncb_buffer, ncb->ncb_length); + cmd = ncb->ncb_command & 0x7f; + + if (cmd == NCBENUM) + ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = nbEnum(ncb); + else if (cmd == NCBADDNAME) + { + FIXME("NCBADDNAME: stub, returning success"); + ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = NRC_GOODRET; + } + else + { + NetBIOSAdapter *adapter; + + /* Apps not specifically written for WinNT won't do an NCBENUM first, + * so make sure the table has been enumerated at least once + */ + if (!gNBTable.enumerated) + nbInternalEnum(); + adapter = nbGetAdapter(ncb->ncb_lana_num); + if (!adapter) + ret = NRC_BRIDGE; + else + { + if (adapter->shuttingDown) + ret = NRC_IFBUSY; + else if (adapter->resetting) + ret = NRC_TOOMANY; + else + { + /* non-asynch commands first */ + if (cmd == NCBCANCEL) + ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = + nbCancel(adapter, ncb); + else if (cmd == NCBSSTAT) + ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = + nbSStat(adapter, ncb); + else + { + if (ncb->ncb_command & ASYNCH) + { + HANDLE thread = CreateThread(NULL, 0, nbCmdThread, ncb, + CREATE_SUSPENDED, NULL); + + if (thread != NULL) + { + ncb->ncb_retcode = ncb->ncb_cmd_cplt = NRC_PENDING; + if (ncb->ncb_event) + ResetEvent(ncb->ncb_event); + ResumeThread(thread); + CloseHandle(thread); + ret = NRC_GOODRET; + } + else + ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = + NRC_OSRESNOTAV; + } + else + ncb->ncb_retcode = ncb->ncb_cmd_cplt = ret = + nbDispatch(adapter, ncb); + } + } + } + } + TRACE("returning 0x%02x\n", ret); + return ret; +} diff --git a/reactos/lib/netapi32/netbios.h b/reactos/lib/netapi32/netbios.h new file mode 100644 index 00000000000..0130aaf701e --- /dev/null +++ b/reactos/lib/netapi32/netbios.h @@ -0,0 +1,183 @@ +/* Copyright (c) 2003 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __WINE_NETBIOS_H__ +#define __WINE_NETBIOS_H__ + +#include +#include "windef.h" +#include "winbase.h" +#include "lm.h" +#include "nb30.h" + +/* This file describes the interface WINE's NetBIOS implementation uses to + * interact with a transport implementation (where a transport might be + * NetBIOS-over-TCP/IP (aka NetBT, NBT), NetBIOS-over-IPX, etc.) + */ + +/** + * Public functions + */ + +void NetBIOSInit(void); +void NetBIOSShutdown(void); + +struct _NetBIOSTransport; + +/* A transport should register itself during its init function (see below) with + * a unique id (the transport_id of ACTION_HEADER, for example) and an + * implementation. Returns TRUE on success, and FALSE on failure. + */ +BOOL NetBIOSRegisterTransport(ULONG id, struct _NetBIOSTransport *transport); + +/* Registers an adapter with the given transport and ifIndex with NetBIOS. + * ifIndex is an interface index usable by the IpHlpApi. ifIndex is not + * required to be unique, but is required so that NetWkstaTransportEnum can use + * GetIfEntry to get the name and hardware address of the adapter. + * Returns TRUE on success, FALSE on failure. + * FIXME: need functions for retrieving the name and hardware index, rather + * than assuming a correlation with IpHlpApi. + */ +BOOL NetBIOSRegisterAdapter(ULONG transport, DWORD ifIndex, void *adapter); + +/* During enumeration, all adapters from your transport are disabled + * internally. If an adapter is still valid, reenable it with this function. + * Adapters you don't enable will have their transport's NetBIOSCleanupAdapter + * function (see below) called on them, and will be removed from the table. + * (This is to deal with lack of plug-and-play--sorry.) + */ +void NetBIOSEnableAdapter(UCHAR lana); + +/* Gets a quick count of the number of NetBIOS adapters. Not guaranteed not + * to change from one call to the next, depending on what's been enumerated + * lately. See also NetBIOSEnumAdapters. + */ +UCHAR NetBIOSNumAdapters(void); + +typedef struct _NetBIOSAdapterImpl { + UCHAR lana; + DWORD ifIndex; + void *data; +} NetBIOSAdapterImpl; + +typedef BOOL (*NetBIOSEnumAdaptersCallback)(UCHAR totalLANAs, UCHAR lanaIndex, + ULONG transport, const NetBIOSAdapterImpl *data, void *closure); + +/* Enumerates all NetBIOS adapters for the transport transport, or for all + * transports if transport is ALL_TRANSPORTS. Your callback will be called + * once for every enumerated adapter, with a count of how many adapters have + * been enumerated, a 0-based index relative to that count, the adapter's + * transport, and its ifIndex. + * Your callback should return FALSE if it no longer wishes to be called. + */ +void NetBIOSEnumAdapters(ULONG transport, NetBIOSEnumAdaptersCallback cb, + void *closure); + +/* Hangs up the session identified in the NCB; the NCB need not be a NCBHANGUP. + * Will result in the transport's hangup function being called, so release any + * locks you own before calling to avoid deadlock. + * This function is intended for use by a transport, if the session is closed + * by some error in the transport layer. + */ +void NetBIOSHangupSession(PNCB ncb); + +/** + * Functions a transport implementation must implement + */ + +/* This function is called to ask a transport implementation to enumerate any + * LANAs into the NetBIOS adapter table by: + * - calling NetBIOSRegisterAdapter for any new adapters + * - calling NetBIOSEnableAdapter for any existing adapters + * NetBIOSEnumAdapters (see) may be of use to determine which adapters already + * exist. + * A transport can assume no other thread is modifying the NetBIOS adapter + * table during the lifetime of its NetBIOSEnum function (and, therefore, that + * this function won't be called reentrantly). + */ +typedef UCHAR (*NetBIOSEnum)(void); + +/* A cleanup function for a transport. This is the last function called on a + * transport. + */ +typedef void (*NetBIOSCleanup)(void); + +/* Adapter functions */ + +/* Functions with direct mappings to the Netbios interface. These functions + * are expected to be synchronous, although the first four bytes of the + * reserved member of the ncb are a cancel flag. A long-running function + * should check whether this is not FALSE from time to time (see the + * NCB_CANCELLED macro), and return NRC_CMDCAN if it's been cancelled. (The + * remainder of the NCB's reserved field is, well, reserved.) + */ + +/* Used to see whether the pointer to an NCB has been cancelled. The NetBIOS + * interface designates certain functions as non-cancellable functions, but I + * use this flag for all NCBs. Support it if you can. + * FIXME: this isn't enough, need to support an EVENT or some such, because + * some calls (recv) will block indefinitely, so a reset, shutdown, etc. will + * never occur. + */ +#define NCB_CANCELLED(pncb) *(PBOOL)((pncb)->ncb_reserve) + +typedef UCHAR (*NetBIOSAstat)(void *adapter, PNCB ncb); +typedef UCHAR (*NetBIOSFindName)(void *adapter, PNCB ncb); + +/* Functions to support the session service */ + +/* Implement to support the NCBCALL command. If you need data stored for the + * session, return it in *session. You can clean it up in your NetBIOSHangup + * function (see). + */ +typedef UCHAR (*NetBIOSCall)(void *adapter, PNCB ncb, void **session); +typedef UCHAR (*NetBIOSSend)(void *adapter, void *session, PNCB ncb); +typedef UCHAR (*NetBIOSRecv)(void *adapter, void *session, PNCB ncb); +typedef UCHAR (*NetBIOSHangup)(void *adapter, void *session); + +/* The last function called on an adapter; it is not called reentrantly, and + * no new calls will be made on the adapter once this has been entered. Clean + * up any resources allocated for the adapter here. + */ +typedef void (*NetBIOSCleanupAdapter)(void *adapter); + +typedef struct _NetBIOSTransport +{ + NetBIOSEnum enumerate; + NetBIOSAstat astat; + NetBIOSFindName findName; + NetBIOSCall call; + NetBIOSSend send; + NetBIOSRecv recv; + NetBIOSHangup hangup; + NetBIOSCleanupAdapter cleanupAdapter; + NetBIOSCleanup cleanup; +} NetBIOSTransport; + +/* Transport-specific functions. When adding a transport, add a call to its + * init function in netapi32's DllMain. The transport can do any global + * initialization it needs here. It should call NetBIOSRegisterTransport to + * register itself with NetBIOS. + */ + +/* NetBIOS-over-TCP/IP (NetBT) functions */ + +/* Not defined by MS, so make my own private define: */ +#define TRANSPORT_NBT "MNBT" + +void NetBTInit(void); + +#endif /* ndef __WINE_NETBIOS_H__ */ diff --git a/reactos/lib/netapi32/wksta.c b/reactos/lib/netapi32/wksta.c new file mode 100644 index 00000000000..6ba66656da6 --- /dev/null +++ b/reactos/lib/netapi32/wksta.c @@ -0,0 +1,567 @@ +/* Copyright 2002 Andriy Palamarchuk + * Copyright (c) 2003 Juan Lang + * + * netapi32 user functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winsock2.h" +#include "nb30.h" +#include "lmcons.h" +#include "lmapibuf.h" +#include "lmerr.h" +#include "lmwksta.h" +#include "iphlpapi.h" +#include "winerror.h" +#undef WIN32_NO_STATUS +#include "ntstatus.h" +#include "winreg.h" +#include "winternl.h" +#include "ntsecapi.h" +#include "netbios.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netapi32); + +/************************************************************ + * NETAPI_IsLocalComputer + * + * Checks whether the server name indicates local machine. + */ +BOOL NETAPI_IsLocalComputer(LPCWSTR ServerName) +{ + if (!ServerName) + { + return TRUE; + } + else if (ServerName[0] == '\0') + return TRUE; + else + { + DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1; + BOOL Result; + LPWSTR buf; + + NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) &buf); + Result = GetComputerNameW(buf, &dwSize); + if (Result && (ServerName[0] == '\\') && (ServerName[1] == '\\')) + ServerName += 2; + Result = Result && !lstrcmpW(ServerName, buf); + NetApiBufferFree(buf); + + return Result; + } +} + +static void wprint_mac(WCHAR* buffer, int len, PMIB_IFROW ifRow) +{ + int i; + unsigned char val; + + if (!buffer) + return; + if (len < 1) + return; + if (!ifRow) + { + *buffer = '\0'; + return; + } + + for (i = 0; i < ifRow->dwPhysAddrLen && 2 * i < len; i++) + { + val = ifRow->bPhysAddr[i]; + if ((val >>4) >9) + buffer[2*i] = (WCHAR)((val >>4) + 'A' - 10); + else + buffer[2*i] = (WCHAR)((val >>4) + '0'); + if ((val & 0xf ) >9) + buffer[2*i+1] = (WCHAR)((val & 0xf) + 'A' - 10); + else + buffer[2*i+1] = (WCHAR)((val & 0xf) + '0'); + } + buffer[2*i]=(WCHAR)0; +} + +/* Theoretically this could be too short, except that MS defines + * MAX_ADAPTER_NAME as 128, and MAX_INTERFACE_NAME_LEN as 256, and both + * represent a count of WCHARs, so even with an extroardinarily long header + * this will be plenty + */ +#define MAX_TRANSPORT_NAME MAX_INTERFACE_NAME_LEN +#define MAX_TRANSPORT_ADDR 13 + +#define NBT_TRANSPORT_NAME_HEADER "\\Device\\NetBT_Tcpip_" +#define UNKNOWN_TRANSPORT_NAME_HEADER "\\Device\\UnknownTransport_" + +static void wprint_name(WCHAR *buffer, int len, ULONG transport, + PMIB_IFROW ifRow) +{ + WCHAR *ptr1, *ptr2; + const char *name; + + if (!buffer) + return; + if (!ifRow) + { + *buffer = '\0'; + return; + } + + if (!memcmp(&transport, TRANSPORT_NBT, sizeof(ULONG))) + name = NBT_TRANSPORT_NAME_HEADER; + else + name = UNKNOWN_TRANSPORT_NAME_HEADER; + + for (ptr1 = buffer; *name && ptr1 < buffer + len; ptr1++, name++) + *ptr1 = *name; + for (ptr2 = ifRow->wszName; *ptr2 && ptr1 < buffer + len; ptr1++, ptr2++) + *ptr1 = *ptr2; + *ptr1 = '\0'; +} + +/*********************************************************************** + * NetWkstaTransportEnum (NETAPI32.@) + */ + +struct WkstaTransportEnumData +{ + UCHAR n_adapt; + UCHAR n_read; + DWORD prefmaxlen; + LPBYTE *pbuf; + NET_API_STATUS ret; +}; + +/**********************************************************************/ + +static BOOL WkstaEnumAdaptersCallback(UCHAR totalLANAs, UCHAR lanaIndex, + ULONG transport, const NetBIOSAdapterImpl *data, void *closure) +{ + BOOL ret; + struct WkstaTransportEnumData *enumData = (struct WkstaTransportEnumData *) + closure; + + if (enumData && enumData->pbuf) + { + if (lanaIndex == 0) + { + DWORD toAllocate; + + enumData->n_adapt = totalLANAs; + enumData->n_read = 0; + + toAllocate = totalLANAs * (sizeof(WKSTA_TRANSPORT_INFO_0) + + MAX_TRANSPORT_NAME * sizeof(WCHAR) + + MAX_TRANSPORT_ADDR * sizeof(WCHAR)); + if (enumData->prefmaxlen != MAX_PREFERRED_LENGTH) + toAllocate = enumData->prefmaxlen; + NetApiBufferAllocate(toAllocate, (LPVOID *)enumData->pbuf); + } + if (*(enumData->pbuf)) + { + UCHAR spaceFor; + + if (enumData->prefmaxlen == MAX_PREFERRED_LENGTH) + spaceFor = totalLANAs; + else + spaceFor = enumData->prefmaxlen / + (sizeof(WKSTA_TRANSPORT_INFO_0) + (MAX_TRANSPORT_NAME + + MAX_TRANSPORT_ADDR) * sizeof(WCHAR)); + if (enumData->n_read < spaceFor) + { + PWKSTA_TRANSPORT_INFO_0 ti; + LPWSTR transport_name, transport_addr; + MIB_IFROW ifRow; + + ti = (PWKSTA_TRANSPORT_INFO_0)(*(enumData->pbuf) + + enumData->n_read * sizeof(WKSTA_TRANSPORT_INFO_0)); + transport_name = (LPWSTR)(*(enumData->pbuf) + + totalLANAs * sizeof(WKSTA_TRANSPORT_INFO_0) + + enumData->n_read * MAX_TRANSPORT_NAME * sizeof(WCHAR)); + transport_addr = (LPWSTR)(*(enumData->pbuf) + + totalLANAs * (sizeof(WKSTA_TRANSPORT_INFO_0) + + MAX_TRANSPORT_NAME * sizeof(WCHAR)) + + enumData->n_read * MAX_TRANSPORT_ADDR * sizeof(WCHAR)); + + ifRow.dwIndex = data->ifIndex; + GetIfEntry(&ifRow); + ti->wkti0_quality_of_service = 0; + ti->wkti0_number_of_vcs = 0; + ti->wkti0_transport_name = transport_name; + wprint_name(ti->wkti0_transport_name, MAX_TRANSPORT_NAME, + transport, &ifRow); + ti->wkti0_transport_address = transport_addr; + wprint_mac(ti->wkti0_transport_address, MAX_TRANSPORT_ADDR, + &ifRow); + if (!memcmp(&transport, TRANSPORT_NBT, sizeof(ULONG))) + ti->wkti0_wan_ish = TRUE; + else + ti->wkti0_wan_ish = FALSE; + TRACE("%d of %d:ti at %p\n", lanaIndex, totalLANAs, ti); + TRACE("transport_name at %p %s\n", + ti->wkti0_transport_name, + debugstr_w(ti->wkti0_transport_name)); + TRACE("transport_address at %p %s\n", + ti->wkti0_transport_address, + debugstr_w(ti->wkti0_transport_address)); + enumData->n_read++; + enumData->ret = NERR_Success; + ret = TRUE; + } + else + { + enumData->ret = ERROR_MORE_DATA; + ret = FALSE; + } + } + else + { + enumData->ret = ERROR_OUTOFMEMORY; + ret = FALSE; + } + } + else + ret = FALSE; + return ret; +} + +/**********************************************************************/ + +NET_API_STATUS WINAPI +NetWkstaTransportEnum(LPWSTR ServerName, DWORD level, PBYTE* pbuf, + DWORD prefmaxlen, LPDWORD read_entries, + PDWORD total_entries, PDWORD hresume) +{ + NET_API_STATUS ret; + + TRACE(":%s, 0x%08lx, %p, 0x%08lx, %p, %p, %p\n", debugstr_w(ServerName), + level, pbuf, prefmaxlen, read_entries, total_entries,hresume); + if (!NETAPI_IsLocalComputer(ServerName)) + { + FIXME(":not implemented for non-local computers\n"); + ret = ERROR_INVALID_LEVEL; + } + else + { + if (hresume && *hresume) + { + FIXME(":resume handle not implemented\n"); + return ERROR_INVALID_LEVEL; + } + + switch (level) + { + case 0: /* transport info */ + { + ULONG allTransports; + struct WkstaTransportEnumData enumData; + + if (NetBIOSNumAdapters() == 0) + return ERROR_NETWORK_UNREACHABLE; + if (!read_entries) + return STATUS_ACCESS_VIOLATION; + if (!total_entries || !pbuf) + return RPC_X_NULL_REF_POINTER; + + enumData.prefmaxlen = prefmaxlen; + enumData.pbuf = pbuf; + memcpy(&allTransports, ALL_TRANSPORTS, sizeof(ULONG)); + NetBIOSEnumAdapters(allTransports, WkstaEnumAdaptersCallback, + &enumData); + *read_entries = enumData.n_read; + *total_entries = enumData.n_adapt; + if (hresume) *hresume= 0; + ret = enumData.ret; + break; + } + default: + ERR("Invalid level %ld is specified\n", level); + ret = ERROR_INVALID_LEVEL; + } + } + return ret; +} + + +/************************************************************ + * NetWkstaUserGetInfo (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetWkstaUserGetInfo(LPWSTR reserved, DWORD level, + PBYTE* bufptr) +{ + TRACE("(%s, %ld, %p)\n", debugstr_w(reserved), level, bufptr); + switch (level) + { + case 0: + { + PWKSTA_USER_INFO_0 ui; + DWORD dwSize = UNLEN + 1; + + /* set up buffer */ + NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_0) + dwSize * sizeof(WCHAR), + (LPVOID *) bufptr); + + ui = (PWKSTA_USER_INFO_0) *bufptr; + ui->wkui0_username = (LPWSTR) (*bufptr + sizeof(WKSTA_USER_INFO_0)); + + /* get data */ + if (!GetUserNameW(ui->wkui0_username, &dwSize)) + { + NetApiBufferFree(ui); + return ERROR_NOT_ENOUGH_MEMORY; + } + else + NetApiBufferReallocate( + *bufptr, sizeof(WKSTA_USER_INFO_0) + + (lstrlenW(ui->wkui0_username) + 1) * sizeof(WCHAR), + (LPVOID *) bufptr); + break; + } + + case 1: + { + PWKSTA_USER_INFO_1 ui; + PWKSTA_USER_INFO_0 ui0; + DWORD dwSize; + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + LSA_HANDLE PolicyHandle; + PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo; + NTSTATUS NtStatus; + + /* sizes of the field buffers in WCHARS */ + int username_sz, logon_domain_sz, oth_domains_sz, logon_server_sz; + + FIXME("Level 1 processing is partially implemented\n"); + oth_domains_sz = 1; + logon_server_sz = 1; + + /* get some information first to estimate size of the buffer */ + ui0 = NULL; + NetWkstaUserGetInfo(NULL, 0, (PBYTE *) &ui0); + username_sz = lstrlenW(ui0->wkui0_username) + 1; + + ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); + NtStatus = LsaOpenPolicy(NULL, &ObjectAttributes, + POLICY_VIEW_LOCAL_INFORMATION, + &PolicyHandle); + if (NtStatus != STATUS_SUCCESS) + { + ERR("LsaOpenPolicyFailed with NT status %lx\n", + LsaNtStatusToWinError(NtStatus)); + NetApiBufferFree(ui0); + return ERROR_NOT_ENOUGH_MEMORY; + } + LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation, + (PVOID*) &DomainInfo); + logon_domain_sz = lstrlenW(DomainInfo->DomainName.Buffer) + 1; + LsaClose(PolicyHandle); + + /* set up buffer */ + NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_1) + + (username_sz + logon_domain_sz + + oth_domains_sz + logon_server_sz) * sizeof(WCHAR), + (LPVOID *) bufptr); + ui = (WKSTA_USER_INFO_1 *) *bufptr; + ui->wkui1_username = (LPWSTR) (*bufptr + sizeof(WKSTA_USER_INFO_1)); + ui->wkui1_logon_domain = (LPWSTR) ( + ((PBYTE) ui->wkui1_username) + username_sz * sizeof(WCHAR)); + ui->wkui1_oth_domains = (LPWSTR) ( + ((PBYTE) ui->wkui1_logon_domain) + + logon_domain_sz * sizeof(WCHAR)); + ui->wkui1_logon_server = (LPWSTR) ( + ((PBYTE) ui->wkui1_oth_domains) + + oth_domains_sz * sizeof(WCHAR)); + + /* get data */ + dwSize = username_sz; + lstrcpyW(ui->wkui1_username, ui0->wkui0_username); + NetApiBufferFree(ui0); + + lstrcpynW(ui->wkui1_logon_domain, DomainInfo->DomainName.Buffer, + logon_domain_sz); + LsaFreeMemory(DomainInfo); + + /* FIXME. Not implemented. Populated with empty strings */ + ui->wkui1_oth_domains[0] = 0; + ui->wkui1_logon_server[0] = 0; + break; + } + case 1101: + { + PWKSTA_USER_INFO_1101 ui; + DWORD dwSize = 1; + + FIXME("Stub. Level 1101 processing is not implemented\n"); + /* FIXME see also wkui1_oth_domains for level 1 */ + + /* set up buffer */ + NetApiBufferAllocate(sizeof(WKSTA_USER_INFO_1101) + dwSize * sizeof(WCHAR), + (LPVOID *) bufptr); + + ui = (PWKSTA_USER_INFO_1101) *bufptr; + ui->wkui1101_oth_domains = (LPWSTR)(ui + 1); + + /* get data */ + ui->wkui1101_oth_domains[0] = 0; + break; + } + default: + ERR("Invalid level %ld is specified\n", level); + return ERROR_INVALID_LEVEL; + } + return NERR_Success; +} + +/************************************************************ + * NetpGetComputerName (NETAPI32.@) + */ +NET_API_STATUS WINAPI NetpGetComputerName(LPWSTR *Buffer) +{ + DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1; + + TRACE("(%p)\n", Buffer); + NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) Buffer); + if (GetComputerNameW(*Buffer, &dwSize)) + { + NetApiBufferReallocate( + *Buffer, dwSize * sizeof(WCHAR), + (LPVOID *) Buffer); + return NERR_Success; + } + else + { + NetApiBufferFree(*Buffer); + return ERROR_NOT_ENOUGH_MEMORY; + } +} + +NET_API_STATUS WINAPI I_NetNameCompare(LPVOID p1, LPWSTR wkgrp, LPWSTR comp, + LPVOID p4, LPVOID p5) +{ + FIXME("(%p %s %s %p %p): stub\n", p1, debugstr_w(wkgrp), debugstr_w(comp), + p4, p5); + return ERROR_INVALID_PARAMETER; +} + +NET_API_STATUS WINAPI I_NetNameValidate(LPVOID p1, LPWSTR wkgrp, LPVOID p3, + LPVOID p4) +{ + FIXME("(%p %s %p %p): stub\n", p1, debugstr_w(wkgrp), p3, p4); + return ERROR_INVALID_PARAMETER; +} + +NET_API_STATUS WINAPI NetWkstaGetInfo( LPWSTR servername, DWORD level, + LPBYTE* bufptr) +{ + NET_API_STATUS ret; + + TRACE("%s %ld %p\n", debugstr_w( servername ), level, bufptr ); + if (servername) + { + if (!NETAPI_IsLocalComputer(servername)) + { + FIXME("remote computers not supported\n"); + return ERROR_INVALID_LEVEL; + } + } + if (!bufptr) return ERROR_INVALID_PARAMETER; + + switch (level) + { + case 100: + { + DWORD computerNameLen, domainNameLen, size; + WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1]; + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + LSA_HANDLE PolicyHandle; + NTSTATUS NtStatus; + + computerNameLen = MAX_COMPUTERNAME_LENGTH + 1; + GetComputerNameW(computerName, &computerNameLen); + computerNameLen++; /* include NULL terminator */ + + ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); + NtStatus = LsaOpenPolicy(NULL, &ObjectAttributes, + POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle); + if (NtStatus != STATUS_SUCCESS) + ret = LsaNtStatusToWinError(NtStatus); + else + { + PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo; + + LsaQueryInformationPolicy(PolicyHandle, + PolicyAccountDomainInformation, (PVOID*)&DomainInfo); + domainNameLen = lstrlenW(DomainInfo->DomainName.Buffer) + 1; + size = sizeof(WKSTA_INFO_100) + computerNameLen * sizeof(WCHAR) + + domainNameLen * sizeof(WCHAR); + ret = NetApiBufferAllocate(size, (LPVOID *)bufptr); + if (ret == NERR_Success) + { + PWKSTA_INFO_100 info = (PWKSTA_INFO_100)*bufptr; + OSVERSIONINFOW verInfo; + + info->wki100_platform_id = PLATFORM_ID_NT; + info->wki100_computername = (LPWSTR)(*bufptr + + sizeof(WKSTA_INFO_100)); + memcpy(info->wki100_computername, computerName, + computerNameLen * sizeof(WCHAR)); + info->wki100_langroup = (LPWSTR)(*bufptr + + sizeof(WKSTA_INFO_100) + computerNameLen * sizeof(WCHAR)); + memcpy(info->wki100_langroup, DomainInfo->DomainName.Buffer, + domainNameLen * sizeof(WCHAR)); + memset(&verInfo, 0, sizeof(verInfo)); + verInfo.dwOSVersionInfoSize = sizeof(verInfo); + GetVersionExW(&verInfo); + info->wki100_ver_major = verInfo.dwMajorVersion; + info->wki100_ver_minor = verInfo.dwMinorVersion; + } + LsaFreeMemory(DomainInfo); + LsaClose(PolicyHandle); + } + break; + } + + default: + FIXME("level %ld unimplemented\n", level); + ret = ERROR_INVALID_LEVEL; + } + return ret; +} + +/************************************************************ + * NetGetJoinInformation (NETAPI32.@) + */ +NET_API_STATUS NET_API_FUNCTION NetGetJoinInformation( + LPCWSTR Server, + LPWSTR *Name, + PNETSETUP_JOIN_STATUS type) +{ + FIXME("Stub %s %p %p\n", wine_dbgstr_w(Server), Name, type); + + *Name = NULL; + *type = NetSetupUnknownStatus; + + return NERR_Success; +} diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 295e45c3ab6..25e2e00f24b 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -54,7 +54,7 @@ reactos/lib/msacm # Out of sync reactos/lib/msimg32 # Synced to Wine-0_9_1 reactos/lib/msi # Synced to Wine-0_9_1 reactos/lib/msvideo # Out of sync -reactos/lib/netapi32 # Out of sync +reactos/lib/netapi32 # Synced to Wine-0_9_1 reactos/lib/objsel # Synced to Wine-0_9_1 reactos/lib/odbc32 # Out of sync. Depends on port of Linux ODBC. reactos/lib/ole32 # Synced to Wine-0_9_1 diff --git a/reactos/w32api/include/lm.h b/reactos/w32api/include/lm.h index db1779db6fc..e0baa6a5cd7 100644 --- a/reactos/w32api/include/lm.h +++ b/reactos/w32api/include/lm.h @@ -23,5 +23,6 @@ #include #include #include +#include #endif diff --git a/reactos/w32api/include/lmbrowsr.h b/reactos/w32api/include/lmbrowsr.h deleted file mode 100644 index e6f47969e5f..00000000000 --- a/reactos/w32api/include/lmbrowsr.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef _LMBROWSR_H -#define _LMBROWSR_H -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#ifdef __cplusplus -extern "C" { -#endif -#define BROWSER_ROLE_PDC 1 -#define BROWSER_ROLE_BDC 2 -typedef struct _BROWSER_STATISTICS { - LARGE_INTEGER StatisticsStartTime; - LARGE_INTEGER NumberOfServerAnnouncements; - LARGE_INTEGER NumberOfDomainAnnouncements; - ULONG NumberOfElectionPackets; - ULONG NumberOfMailslotWrites; - ULONG NumberOfGetBrowserServerListRequests; - ULONG NumberOfServerEnumerations; - ULONG NumberOfDomainEnumerations; - ULONG NumberOfOtherEnumerations; - ULONG NumberOfMissedServerAnnouncements; - ULONG NumberOfMissedMailslotDatagrams; - ULONG NumberOfMissedGetBrowserServerListRequests; - ULONG NumberOfFailedServerAnnounceAllocations; - ULONG NumberOfFailedMailslotAllocations; - ULONG NumberOfFailedMailslotReceives; - ULONG NumberOfFailedMailslotWrites; - ULONG NumberOfFailedMailslotOpens; - ULONG NumberOfDuplicateMasterAnnouncements; -LARGE_INTEGER NumberOfIllegalDatagrams; -} BROWSER_STATISTICS,*PBROWSER_STATISTICS,*LPBROWSER_STATISTICS; -typedef struct _BROWSER_STATISTICS_100 { - LARGE_INTEGER StartTime; - LARGE_INTEGER NumberOfServerAnnouncements; - LARGE_INTEGER NumberOfDomainAnnouncements; - ULONG NumberOfElectionPackets; - ULONG NumberOfMailslotWrites; - ULONG NumberOfGetBrowserServerListRequests; - LARGE_INTEGER NumberOfIllegalDatagrams; -} BROWSER_STATISTICS_100,*PBROWSER_STATISTICS_100; -typedef struct _BROWSER_STATISTICS_101 { - LARGE_INTEGER StartTime; - LARGE_INTEGER NumberOfServerAnnouncements; - LARGE_INTEGER NumberOfDomainAnnouncements; - ULONG NumberOfElectionPackets; - ULONG NumberOfMailslotWrites; - ULONG NumberOfGetBrowserServerListRequests; - LARGE_INTEGER NumberOfIllegalDatagrams; - ULONG NumberOfMissedServerAnnouncements; - ULONG NumberOfMissedMailslotDatagrams; - ULONG NumberOfMissedGetBrowserServerListRequests; - ULONG NumberOfFailedServerAnnounceAllocations; - ULONG NumberOfFailedMailslotAllocations; - ULONG NumberOfFailedMailslotReceives; - ULONG NumberOfFailedMailslotWrites; - ULONG NumberOfFailedMailslotOpens; - ULONG NumberOfDuplicateMasterAnnouncements; -} BROWSER_STATISTICS_101,*PBROWSER_STATISTICS_101; - -NET_API_STATUS WINAPI I_BrowserServerEnum(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,DWORD,LPCWSTR,PDWORD); -NET_API_STATUS WINAPI I_BrowserServerEnumEx(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,DWORD,LPCWSTR,LPCWSTR); -NET_API_STATUS WINAPI I_BrowserQueryEmulatedDomains(LPWSTR,PBYTE*,PDWORD); -NET_API_STATUS I_BrowserQueryOtherDomains(LPCWSTR,PBYTE*,PDWORD,PDWORD); -NET_API_STATUS I_BrowserResetNetlogonState(LPCWSTR); -NET_API_STATUS WINAPI I_BrowserSetNetlogonState(LPWSTR,LPWSTR,LPWSTR,DWORD); -NET_API_STATUS I_BrowserQueryStatistics(LPCWSTR,LPBROWSER_STATISTICS*); -NET_API_STATUS I_BrowserResetStatistics(LPCWSTR); -WORD I_BrowserServerEnumForXactsrv(LPCWSTR,LPCWSTR,ULONG,USHORT,PVOID,WORD,DWORD,PDWORD,PDWORD,DWORD,LPCWSTR,LPCWSTR,PWORD); -NET_API_STATUS I_BrowserDebugTrace(PWCHAR,PCHAR); -#ifdef __cplusplus -} -#endif -#endif diff --git a/reactos/w32api/include/lmjoin.h b/reactos/w32api/include/lmjoin.h new file mode 100644 index 00000000000..7c18ca0ef53 --- /dev/null +++ b/reactos/w32api/include/lmjoin.h @@ -0,0 +1,43 @@ +/* + * Copyright 2005 Ulrich Czekalla (For CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_LMJOIN_H +#define __WINE_LMJOIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum tagNETSETUP_JOIN_STATUS +{ + NetSetupUnknownStatus = 0, + NetSetupUnjoined, + NetSetupWorkgroupName, + NetSetupDomainName +} NETSETUP_JOIN_STATUS, *PNETSETUP_JOIN_STATUS; + +NET_API_STATUS NET_API_FUNCTION NetGetJoinInformation( + LPCWSTR Server, + LPWSTR *Name, + PNETSETUP_JOIN_STATUS type); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/reactos/w32api/include/ntsecapi.h b/reactos/w32api/include/ntsecapi.h index 16b0bcf83d2..0c8ae3e3136 100644 --- a/reactos/w32api/include/ntsecapi.h +++ b/reactos/w32api/include/ntsecapi.h @@ -125,16 +125,6 @@ extern "C" { #if !defined(_NTDEF_H) && !defined(_SUBAUTH_H) typedef LONG NTSTATUS, *PNTSTATUS; -typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; -typedef struct _STRING { - USHORT Length; - USHORT MaximumLength; - PCHAR Buffer; -} STRING, *PSTRING; #endif #if defined (_NTDEF_H)