From 2e9a2d80626757b51357d83c4b702939752b74ca Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Fri, 24 Jul 2015 10:35:07 +0200 Subject: [PATCH] netapi32: Implement DavGetHTTPFromUNCPath. --- dlls/netapi32/netapi32.c | 90 +++++++++++++++ dlls/netapi32/netapi32.spec | 1 + dlls/netapi32/tests/access.c | 218 +++++++++++++++++++++++++++++++++-- include/davclnt.h | 1 + 4 files changed, 301 insertions(+), 9 deletions(-) diff --git a/dlls/netapi32/netapi32.c b/dlls/netapi32/netapi32.c index 7a1d40845d..785a8d6baa 100644 --- a/dlls/netapi32/netapi32.c +++ b/dlls/netapi32/netapi32.c @@ -51,6 +51,7 @@ #include "winnls.h" #include "dsrole.h" #include "dsgetdc.h" +#include "davclnt.h" #include "wine/debug.h" #include "wine/library.h" #include "wine/list.h" @@ -3347,3 +3348,92 @@ NET_API_STATUS WINAPI NetLocalGroupSetMembers( debugstr_w(groupname), level, buf, totalentries); return NERR_Success; } + +/************************************************************ + * DavGetHTTPFromUNCPath (NETAPI32.@) + */ +DWORD WINAPI DavGetHTTPFromUNCPath(const WCHAR *unc_path, WCHAR *buf, DWORD *buflen) +{ + static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; + static const WCHAR httpsW[] = {'h','t','t','p','s',':','/','/',0}; + static const WCHAR sslW[] = {'S','S','L',0}; + static const WCHAR fmtW[] = {':','%','u',0}; + const WCHAR *p = unc_path, *q, *server, *path, *scheme = httpW; + UINT i, len_server, len_path = 0, len_port = 0, len, port = 0; + WCHAR *end, portbuf[12]; + + TRACE("(%s %p %p)\n", debugstr_w(unc_path), buf, buflen); + + if (p[0] != '\\' || p[1] != '\\' || !p[2]) return ERROR_INVALID_PARAMETER; + q = p += 2; + while (*q && *q != '\\' && *q != '/' && *q != '@') q++; + server = p; + len_server = q - p; + if (*q == '@') + { + p = ++q; + while (*p && (*p != '\\' && *p != '/' && *p != '@')) p++; + if (p - q == 3 && !memicmpW( q, sslW, 3 )) + { + scheme = httpsW; + q = p; + } + else if ((port = strtolW( q, &end, 10 ))) q = end; + else return ERROR_INVALID_PARAMETER; + } + if (*q == '@') + { + if (!(port = strtolW( ++q, &end, 10 ))) return ERROR_INVALID_PARAMETER; + q = end; + } + if (*q == '\\' || *q == '/') q++; + path = q; + while (*q++) len_path++; + if (len_path && (path[len_path - 1] == '\\' || path[len_path - 1] == '/')) + len_path--; /* remove trailing slash */ + + sprintfW( portbuf, fmtW, port ); + if (scheme == httpsW) + { + len = strlenW( httpsW ); + if (port && port != 443) len_port = strlenW( portbuf ); + } + else + { + len = strlenW( httpW ); + if (port && port != 80) len_port = strlenW( portbuf ); + } + len += len_server; + len += len_port; + if (len_path) len += len_path + 1; /* leading '/' */ + len++; /* nul */ + + if (*buflen < len) + { + *buflen = len; + return ERROR_INSUFFICIENT_BUFFER; + } + + memcpy( buf, scheme, strlenW(scheme) * sizeof(WCHAR) ); + buf += strlenW( scheme ); + memcpy( buf, server, len_server * sizeof(WCHAR) ); + buf += len_server; + if (len_port) + { + memcpy( buf, portbuf, len_port * sizeof(WCHAR) ); + buf += len_port; + } + if (len_path) + { + *buf++ = '/'; + for (i = 0; i < len_path; i++) + { + if (path[i] == '\\') *buf++ = '/'; + else *buf++ = path[i]; + } + } + *buf = 0; + *buflen = len; + + return ERROR_SUCCESS; +} diff --git a/dlls/netapi32/netapi32.spec b/dlls/netapi32/netapi32.spec index ede3986ce7..64314af8ba 100644 --- a/dlls/netapi32/netapi32.spec +++ b/dlls/netapi32/netapi32.spec @@ -1,3 +1,4 @@ +@ stdcall DavGetHTTPFromUNCPath(wstr ptr ptr) @ stub DsAddressToSiteNames @ stub DsAddressToSiteNamesEx @ stub DsDeregisterDnsHostRecords diff --git a/dlls/netapi32/tests/access.c b/dlls/netapi32/tests/access.c index 7675cbf8e7..a57c5643e3 100644 --- a/dlls/netapi32/tests/access.c +++ b/dlls/netapi32/tests/access.c @@ -56,15 +56,16 @@ static const WCHAR sInvalidName[] = {'\\',0}; static const WCHAR sInvalidName2[] = {'\\','\\',0}; static const WCHAR sEmptyStr[] = { 0 }; -static NET_API_STATUS (WINAPI *pNetApiBufferFree)(LPVOID)=NULL; -static NET_API_STATUS (WINAPI *pNetApiBufferSize)(LPVOID,LPDWORD)=NULL; -static NET_API_STATUS (WINAPI *pNetQueryDisplayInformation)(LPWSTR,DWORD,DWORD,DWORD,DWORD,LPDWORD,PVOID*)=NULL; -static NET_API_STATUS (WINAPI *pNetUserGetInfo)(LPCWSTR,LPCWSTR,DWORD,LPBYTE*)=NULL; -static NET_API_STATUS (WINAPI *pNetUserModalsGet)(LPCWSTR,DWORD,LPBYTE*)=NULL; -static NET_API_STATUS (WINAPI *pNetUserAdd)(LPCWSTR,DWORD,LPBYTE,LPDWORD)=NULL; -static NET_API_STATUS (WINAPI *pNetUserDel)(LPCWSTR,LPCWSTR)=NULL; -static NET_API_STATUS (WINAPI *pNetLocalGroupGetInfo)(LPCWSTR,LPCWSTR,DWORD,LPBYTE*)=NULL; -static NET_API_STATUS (WINAPI *pNetLocalGroupGetMembers)(LPCWSTR,LPCWSTR,DWORD,LPBYTE*,DWORD,LPDWORD,LPDWORD,PDWORD_PTR)=NULL; +static NET_API_STATUS (WINAPI *pNetApiBufferFree)(LPVOID); +static NET_API_STATUS (WINAPI *pNetApiBufferSize)(LPVOID,LPDWORD); +static NET_API_STATUS (WINAPI *pNetQueryDisplayInformation)(LPWSTR,DWORD,DWORD,DWORD,DWORD,LPDWORD,PVOID*); +static NET_API_STATUS (WINAPI *pNetUserGetInfo)(LPCWSTR,LPCWSTR,DWORD,LPBYTE*); +static NET_API_STATUS (WINAPI *pNetUserModalsGet)(LPCWSTR,DWORD,LPBYTE*); +static NET_API_STATUS (WINAPI *pNetUserAdd)(LPCWSTR,DWORD,LPBYTE,LPDWORD); +static NET_API_STATUS (WINAPI *pNetUserDel)(LPCWSTR,LPCWSTR); +static NET_API_STATUS (WINAPI *pNetLocalGroupGetInfo)(LPCWSTR,LPCWSTR,DWORD,LPBYTE*); +static NET_API_STATUS (WINAPI *pNetLocalGroupGetMembers)(LPCWSTR,LPCWSTR,DWORD,LPBYTE*,DWORD,LPDWORD,LPDWORD,PDWORD_PTR); +static DWORD (WINAPI *pDavGetHTTPFromUNCPath)(LPCWSTR,LPWSTR,LPDWORD); static BOOL init_access_tests(void) { @@ -352,6 +353,203 @@ static void run_localgroupgetinfo_tests(void) pNetApiBufferFree(buffer); } +static void test_DavGetHTTPFromUNCPath(void) +{ + static const WCHAR path[] = + {0}; + static const WCHAR path2[] = + {'c',':','\\',0}; + static const WCHAR path3[] = + {'\\','\\','.','\\','c',':',0}; + static const WCHAR path4[] = + {'\\','\\','.','\\','c',':','\\',0}; + static const WCHAR path5[] = + {'\\','\\','.','\\','c',':','\\','n','o','s','u','c','h','p','a','t','h',0}; + static const WCHAR path6[] = + {'\\','\\','n','o','s','u','c','h','s','e','r','v','e','r','\\','c',':','\\',0}; + static const WCHAR path7[] = + {'\\','.','\\','c',':',0}; + static const WCHAR path8[] = + {'\\','\\','.','\\','c',':','\\','\\',0}; + static const WCHAR path9[] = + {'\\','\\','.','@','S','S','L','\\','c',':',0}; + static const WCHAR path10[] = + {'\\','\\','.','@','s','s','l','\\','c',':',0}; + static const WCHAR path11[] = + {'\\','\\','.','@','t','l','s','\\','c',':',0}; + static const WCHAR path12[] = + {'\\','\\','.','@','S','S','L','@','4','4','3','\\','c',':',0}; + static const WCHAR path13[] = + {'\\','\\','.','@','S','S','L','@','8','0','\\','c',':',0}; + static const WCHAR path14[] = + {'\\','\\','.','@','8','0','\\','c',':',0}; + static const WCHAR path15[] = + {'\\','\\','.','@','8','0','8','0','\\','c',':',0}; + static const WCHAR path16[] = + {'\\','\\','\\','c',':',0}; + static const WCHAR path17[] = + {'\\','\\',0}; + static const WCHAR path18[] = + {'/','/','.','/','c',':',0}; + static const WCHAR path19[] = + {'\\','\\','.','\\','c',':','/',0}; + static const WCHAR path20[] = + {'\\','\\','.','\\','c',':','\\','\\','\\',0}; + static const WCHAR path21[] = + {'\\','\\','.','\\','\\','c',':',0}; + static const WCHAR path22[] = + {'\\','\\','.','\\','c',':','d','i','r',0}; + static const WCHAR path23[] = + {'\\','\\','.',0}; + static const WCHAR path24[] = + {'\\','\\','.','\\','d','i','r',0}; + static const WCHAR path25[] = + {'\\','\\','.','\\','\\',0}; + static const WCHAR path26[] = + {'\\','\\','.','\\','c',':','d','i','r','/',0}; + static const WCHAR path27[] = + {'\\','\\','.','/','c',':',0}; + static const WCHAR path28[] = + {'\\','\\','.','@','8','0','@','S','S','L','\\','c',':',0}; + static const WCHAR result[] = + {'h','t','t','p',':','/','/','.','/','c',':',0}; + static const WCHAR result2[] = + {'h','t','t','p',':','/','/','.','/','c',':','/','n','o','s','u','c','h','p','a','t','h',0}; + static const WCHAR result3[] = + {'h','t','t','p',':','/','/','n','o','s','u','c','h','s','e','r','v','e','r','/','c',':',0}; + static const WCHAR result4[] = + {'h','t','t','p',':','/','/','.','/','c',':','/',0}; + static const WCHAR result5[] = + {'h','t','t','p','s',':','/','/','.','/','c',':',0}; + static const WCHAR result6[] = + {'h','t','t','p','s',':','/','/','.',':','8','0','/','c',':',0}; + static const WCHAR result7[] = + {'h','t','t','p',':','/','/','.',':','8','0','8','0','/','c',':',0}; + static const WCHAR result8[] = + {'h','t','t','p',':','/','/','/','c',':',0}; + static const WCHAR result9[] = + {'h','t','t','p',':','/','/','.','/','c',':','/','/',0}; + static const WCHAR result10[] = + {'h','t','t','p',':','/','/','.','/','/','c',':',0}; + static const WCHAR result11[] = + {'h','t','t','p',':','/','/','.','/','c',':','d','i','r',0}; + static const WCHAR result12[] = + {'h','t','t','p',':','/','/','.',0}; + static const WCHAR result13[] = + {'h','t','t','p',':','/','/','.','/','d','i','r',0}; + static const WCHAR result14[] = + {'h','t','t','p',':','/','/','.','/',0}; + static const struct + { + const WCHAR *path; + DWORD size; + DWORD ret; + const WCHAR *ret_path; + DWORD ret_size; + int todo; + } + tests[] = + { + { path, MAX_PATH, ERROR_INVALID_PARAMETER, NULL, MAX_PATH }, + { path2, MAX_PATH, ERROR_INVALID_PARAMETER, NULL, MAX_PATH }, + { path3, MAX_PATH, ERROR_SUCCESS, result, 12 }, + { path4, MAX_PATH, ERROR_SUCCESS, result, 12 }, + { path5, MAX_PATH, ERROR_SUCCESS, result2, 23 }, + { path6, MAX_PATH, ERROR_SUCCESS, result3, 23 }, + { path7, MAX_PATH, ERROR_INVALID_PARAMETER, NULL, MAX_PATH }, + { path8, MAX_PATH, ERROR_SUCCESS, result4, 13 }, + { path9, MAX_PATH, ERROR_SUCCESS, result5, 13 }, + { path10, MAX_PATH, ERROR_SUCCESS, result5, 13 }, + { path11, MAX_PATH, ERROR_INVALID_PARAMETER, NULL, MAX_PATH }, + { path12, MAX_PATH, ERROR_SUCCESS, result5, 13 }, + { path13, MAX_PATH, ERROR_SUCCESS, result6, 16 }, + { path14, MAX_PATH, ERROR_SUCCESS, result, 12 }, + { path15, MAX_PATH, ERROR_SUCCESS, result7, 17 }, + { path16, MAX_PATH, ERROR_SUCCESS, result8, 11 }, + { path17, MAX_PATH, ERROR_INVALID_PARAMETER, NULL, MAX_PATH }, + { path18, MAX_PATH, ERROR_INVALID_PARAMETER, NULL, MAX_PATH }, + { path19, MAX_PATH, ERROR_SUCCESS, result, 12 }, + { path20, MAX_PATH, ERROR_SUCCESS, result9, 14 }, + { path21, MAX_PATH, ERROR_SUCCESS, result10, 13 }, + { path22, MAX_PATH, ERROR_SUCCESS, result11, 15 }, + { path23, MAX_PATH, ERROR_SUCCESS, result12, 9 }, + { path24, MAX_PATH, ERROR_SUCCESS, result13, 13 }, + { path25, MAX_PATH, ERROR_SUCCESS, result14, 10, 1 }, + { path26, MAX_PATH, ERROR_SUCCESS, result11, 15 }, + { path27, MAX_PATH, ERROR_SUCCESS, result, 12 }, + { path28, MAX_PATH, ERROR_INVALID_PARAMETER, NULL, MAX_PATH }, + }; + WCHAR buf[MAX_PATH]; + DWORD i, ret, size; + + if (!pDavGetHTTPFromUNCPath) + { + win_skip( "DavGetHTTPFromUNCPath is missing\n" ); + return; + } + + if (0) { /* crash */ + ret = pDavGetHTTPFromUNCPath( NULL, NULL, NULL ); + ok( ret == ERROR_INVALID_PARAMETER, "got %u\n", ret ); + } + + ret = pDavGetHTTPFromUNCPath( path, buf, NULL ); + ok( ret == ERROR_INVALID_PARAMETER, "got %u\n", ret ); + + size = 0; + ret = pDavGetHTTPFromUNCPath( path, NULL, &size ); + ok( ret == ERROR_INVALID_PARAMETER, "got %u\n", ret ); + + if (0) { /* crash */ + buf[0] = 0; + size = 0; + ret = pDavGetHTTPFromUNCPath( path, buf, &size ); + ok( ret == ERROR_INVALID_PARAMETER, "got %u\n", ret ); + + ret = pDavGetHTTPFromUNCPath( path3, buf, NULL ); + ok( ret == ERROR_INVALID_PARAMETER, "got %u\n", ret ); + } + + size = 0; + ret = pDavGetHTTPFromUNCPath( path3, NULL, &size ); + ok( ret == ERROR_INSUFFICIENT_BUFFER, "got %u\n", ret ); + + buf[0] = 0; + size = 0; + ret = pDavGetHTTPFromUNCPath( path3, buf, &size ); + ok( ret == ERROR_INSUFFICIENT_BUFFER, "got %u\n", ret ); + ok( size == 12, "got %u\n", size ); + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + { + buf[0] = 0; + size = tests[i].size; + ret = pDavGetHTTPFromUNCPath( tests[i].path, buf, &size ); + if (tests[i].todo) + { + ok( ret == tests[i].ret, "%u: expected %u got %u\n", i, tests[i].ret, ret ); + todo_wine { + if (tests[i].ret_path) + { + ok( !lstrcmpW( buf, tests[i].ret_path ), "%u: expected %s got %s\n", + i, wine_dbgstr_w(tests[i].ret_path), wine_dbgstr_w(buf) ); + } + ok( size == tests[i].ret_size, "%u: expected %u got %u\n", i, tests[i].ret_size, size ); + } + } + else + { + ok( ret == tests[i].ret, "%u: expected %u got %u\n", i, tests[i].ret, ret ); + if (tests[i].ret_path) + { + ok( !lstrcmpW( buf, tests[i].ret_path ), "%u: expected %s got %s\n", + i, wine_dbgstr_w(tests[i].ret_path), wine_dbgstr_w(buf) ); + } + ok( size == tests[i].ret_size, "%u: expected %u got %u\n", i, tests[i].ret_size, size ); + } + } +} + START_TEST(access) { HMODULE hnetapi32=LoadLibraryA("netapi32.dll"); @@ -365,6 +563,7 @@ START_TEST(access) pNetUserDel=(void*)GetProcAddress(hnetapi32, "NetUserDel"); pNetLocalGroupGetInfo=(void*)GetProcAddress(hnetapi32, "NetLocalGroupGetInfo"); pNetLocalGroupGetMembers=(void*)GetProcAddress(hnetapi32, "NetLocalGroupGetMembers"); + pDavGetHTTPFromUNCPath = (void*)GetProcAddress(hnetapi32, "DavGetHTTPFromUNCPath"); /* These functions were introduced with NT. It's safe to assume that * if one is not available, none are. @@ -383,5 +582,6 @@ START_TEST(access) run_localgroupgetinfo_tests(); } + test_DavGetHTTPFromUNCPath(); FreeLibrary(hnetapi32); } diff --git a/include/davclnt.h b/include/davclnt.h index a1643dd07a..dbb25ee9c4 100644 --- a/include/davclnt.h +++ b/include/davclnt.h @@ -65,6 +65,7 @@ typedef DWORD (*PFNDAVAUTHCALLBACK_FREECRED) typedef DWORD (*PFNDAVAUTHCALLBACK) (LPWSTR,LPWSTR,DWORD,DWORD,PDAV_CALLBACK_CRED,AUTHNEXTSTEP*,PFNDAVAUTHCALLBACK_FREECRED*); +DWORD WINAPI DavGetHTTPFromUNCPath(LPCWSTR,LPWSTR,LPDWORD); OPAQUE_HANDLE WINAPI DavRegisterAuthCallback(PFNDAVAUTHCALLBACK,ULONG); VOID WINAPI DavUnregisterAuthCallback(OPAQUE_HANDLE);