| /* |
| * 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 "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); |
| |
| const WCHAR sAdminUserName[] = {'A','d','m','i','n','i','s','t','r','a','t', |
| 'o','r',0}; |
| const WCHAR sGuestUserName[] = {'G','u','e','s','t',0}; |
| |
| /************************************************************ |
| * NETAPI_ValidateServername |
| * |
| * Validates server name |
| */ |
| 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. |
| */ |
| 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; \ |
| } |
| |
| /************************************************************ |
| * 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: |
| 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; |
| } |
| |
| /************************************************************ |
| * ACCESS_QueryAdminDisplayInformation |
| * |
| * Creates a buffer with information for the Admin User |
| */ |
| void ACCESS_QueryAdminDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize) |
| { |
| 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 |
| */ |
| void ACCESS_QueryGuestDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize) |
| { |
| 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. |
| */ |
| 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( |
| LPWSTR 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; |
| } |