xref: /reactos/dll/win32/mswsock/nsplookup.c (revision c2c66aff)
1 #include "precomp.h"
2 
3 #include <stdlib.h>
4 #include <ws2spi.h>
5 #include <nspapi.h>
6 #include <windef.h>
7 #include <winuser.h>
8 #include <windns.h>
9 #include <guiddef.h>
10 #include <svcguid.h>
11 #include <iptypes.h>
12 #include <strsafe.h>
13 #include <winreg.h>
14 
15 #include "mswhelper.h"
16 
17 #define NDEBUG
18 #include <debug.h>
19 
20 #define NSP_CALLID_DNS 0x0001
21 #define NSP_CALLID_HOSTNAME 0x0002
22 #define NSP_CALLID_HOSTBYNAME 0x0003
23 #define NSP_CALLID_SERVICEBYNAME 0x0004
24 
25 #ifndef BUFSIZ
26 #define BUFSIZ 1024
27 #endif // BUFSIZ
28 #ifndef WS2_INTERNAL_MAX_ALIAS
29 #define WS2_INTERNAL_MAX_ALIAS 512
30 #endif // WS2_INTERNAL_MAX_ALIAS
31 
32 //#define IP_LOCALHOST 0x0100007F
33 
34 //#define NSP_REDIRECT
35 
36 typedef struct {
37   WCHAR* hostnameW;
38   DWORD addr4;
39   WCHAR* servnameW;
40   WCHAR* servprotoW;
41   CHAR** servaliasesA; /* array */
42   WORD servport;
43 } WSHOSTINFOINTERN, *PWSHOSTINFOINTERN;
44 
45 typedef struct {
46   GUID providerId; /* Provider-ID */
47   DWORD dwControlFlags; /* dwControlFlags (WSALookupServiceBegin) */
48   DWORD CallID; /* List for LookupServiceNext-Calls */
49   DWORD CallIDCounter; /* call-count of the current CallID. */
50   WCHAR* hostnameW; /* hostbyname */
51 #ifdef NSP_REDIRECT
52   HANDLE rdrLookup;
53   NSP_ROUTINE rdrproc;
54 #endif
55 } WSHANDLEINTERN, *PWSHANDLEINTERN;
56 
57 static const GUID guid_NULL = {0};
58 static const GUID guid_HOSTNAME = SVCID_HOSTNAME;
59 static const GUID guid_INET_HOSTADDRBYINETSTRING = SVCID_INET_HOSTADDRBYINETSTRING;
60 static const GUID guid_INET_HOSTADDRBYNAME = SVCID_INET_HOSTADDRBYNAME;
61 static const GUID guid_INET_SERVICEBYNAME = SVCID_INET_SERVICEBYNAME;
62 
63 /* GUIDs - maybe they should be loaded from registry? */
64 /* Namespace: 32 */
65 static const GUID guid_mswsock_TcpIp = {/*Data1:*/ 0x22059D40,
66                                         /*Data2:*/ 0x7E9E,
67                                         /*Data3:*/ 0x11CF,
68                                         /*Data4:*/ {0xAE, 0x5A, 0x00, 0xAA, 0x00, 0xA7, 0x11, 0x2B}};
69 
70 /* {6642243A-3BA8-4AA6-BAA5-2E0BD71FDD83} */
71 /* Namespace: 15 */
72 static const GUID guid_mswsock_NLA = {/*Data1:*/ 0x6642243A,
73                                       /*Data2:*/ 0x3BA8,
74                                       /*Data3:*/ 0x4AA6,
75                                       /*Data4:*/ {0xBA, 0xA5, 0x2E, 0x0B, 0xD7, 0x1F, 0xDD, 0x83}};
76 
77 #ifdef NSP_REDIRECT
78 
79 typedef INT
80 (CALLBACK *lpRdrNSPStartup)(
81   LPGUID lpProviderId,
82   LPNSP_ROUTINE lpRout);
83 
84 const rdrLib = "mswsock.dll-original";
85 lpRdrNSPStartup rdrNSPStartup;
86 HANDLE hLib;
87 NSP_ROUTINE rdrproc_tcpip;
88 NSP_ROUTINE rdrproc_nla;
89 
90 #endif /* NSP_REDIRECT */
91 
92 /* Forwards */
93 INT
94 WINAPI
95 mswNSPStartup(
96   LPGUID lpProviderId,
97   LPNSP_ROUTINE lpRout);
98 
99 INT
100 NSP_LookupServiceBeginW(
101   PWSHANDLEINTERN data,
102   CHAR* hostnameA,
103   WCHAR* hostnameW,
104   DWORD CallID);
105 
106 INT
107 NSP_LookupServiceNextW(
108   _In_ PWSHANDLEINTERN data,
109   _In_ DWORD dwControlFlags,
110   _Inout_ LPWSAQUERYSETW lpRes,
111   _Inout_ LPDWORD lpResLen);
112 
113 INT
114 NSP_GetHostNameHeapAllocW(
115   _Out_ WCHAR** hostname);
116 
117 INT
118 NSP_GetHostByNameHeapAllocW(
119   _In_ PWSHANDLEINTERN data,
120   _In_ DWORD dwControlFlags,
121   _Out_ PWSHOSTINFOINTERN hostinfo);
122 
123 INT
124 NSP_GetServiceByNameHeapAllocW(
125   _In_ PWSHANDLEINTERN data,
126   _In_ DWORD dwControlFlags,
127   _Out_ PWSHOSTINFOINTERN hostinfo);
128 
129 /* Implementations - Internal */
130 
131 INT
132 WSAAPI
133 mwsNSPCleanUp(_In_ LPGUID lpProviderId)
134 {
135     //WSASetLastError(ERROR_CALL_NOT_IMPLEMENTED);
136     //return ERROR_CALL_NOT_IMPLEMENTED;
137     return ERROR_SUCCESS;
138 }
139 
140 INT
141 mwsNSPInit(VOID)
142 {
143     return ERROR_SUCCESS;
144 }
145 
146 INT
147 WSAAPI
148 mwsNSPLookupServiceBegin(_In_ LPGUID lpProviderId,
149                          _In_ LPWSAQUERYSETW lpqsRestrictions,
150                          _In_ LPWSASERVICECLASSINFOW lpServiceClassInfo,
151                          _In_ DWORD dwControlFlags,
152                          _Out_ LPHANDLE lphLookup)
153 {
154     PWSHANDLEINTERN pLook;
155     int wsaErr;
156 
157     if (IsEqualGUID(lpProviderId, &guid_mswsock_TcpIp))
158     {
159         //OK
160     }
161     else if (IsEqualGUID(lpProviderId, &guid_mswsock_NLA))
162     {
163         WSASetLastError(WSASERVICE_NOT_FOUND);
164         return SOCKET_ERROR;
165     }
166     else
167     {
168         return ERROR_CALL_NOT_IMPLEMENTED;
169     }
170 
171     /* allocate internal structure */
172     pLook = HeapAlloc(GetProcessHeap(), 0, sizeof(WSHANDLEINTERN));
173     if (!pLook)
174     {
175         WSASetLastError(WSAEFAULT);
176         return SOCKET_ERROR;
177     }
178 
179     *lphLookup = (HANDLE)pLook;
180 
181     RtlZeroMemory(pLook, sizeof(*pLook));
182 
183     /* Anyway the ControlFlags "should" be needed
184        in NSPLookupServiceNext. (see doku) But
185        thats not the fact ATM. */
186     pLook->dwControlFlags = dwControlFlags;
187     pLook->providerId = *lpProviderId;
188 
189 #ifdef NSP_REDIRECT
190 
191     if (IsEqualGUID(lpProviderId, &guid_mswsock_TcpIp))
192     {
193         pLook->rdrproc = rdrproc_tcpip;
194     }
195     else if (IsEqualGUID(lpProviderId, &guid_mswsock_NLA))
196     {
197         pLook->rdrproc = rdrproc_nla;
198     }
199     else
200     {
201         return ERROR_CALL_NOT_IMPLEMENTED;
202     }
203 
204     if (pLook->rdrproc.NSPLookupServiceBegin(lpProviderId,
205                                              lpqsRestrictions,
206                                              lpServiceClassInfo,
207                                              dwControlFlags,
208                                              &pLook->rdrLookup) == NO_ERROR)
209     {
210         wsaErr = NO_ERROR;
211     }
212     else
213     {
214         wsaErr = WSAGetLastError();
215     }
216 
217     /*
218     if (res)
219         res = WSAGetLastError();
220     */
221 
222 #else /* NSP_REDIRECT */
223 
224     wsaErr = ERROR_CALL_NOT_IMPLEMENTED;
225     if (IsEqualGUID(lpqsRestrictions->lpServiceClassId, &guid_NULL))
226     {
227         wsaErr = ERROR_CALL_NOT_IMPLEMENTED;
228     }
229     else if (IsEqualGUID(lpqsRestrictions->lpServiceClassId, &guid_HOSTNAME))
230     {
231         wsaErr = NSP_LookupServiceBeginW(pLook,
232                                          NULL,
233                                          NULL,
234                                          NSP_CALLID_HOSTNAME);
235     }
236     else if (IsEqualGUID(lpqsRestrictions->lpServiceClassId,
237                          &guid_INET_HOSTADDRBYNAME))
238     {
239        wsaErr = NSP_LookupServiceBeginW(pLook,
240                                         NULL,
241                                         lpqsRestrictions->lpszServiceInstanceName,
242                                         NSP_CALLID_HOSTBYNAME);
243     }
244     else if (IsEqualGUID(lpqsRestrictions->lpServiceClassId,
245                          &guid_INET_SERVICEBYNAME))
246     {
247        wsaErr = NSP_LookupServiceBeginW(pLook,
248                                         NULL,
249                                         lpqsRestrictions->lpszServiceInstanceName,
250                                         NSP_CALLID_SERVICEBYNAME);
251     }
252     else if (IsEqualGUID(lpqsRestrictions->lpServiceClassId,
253                          &guid_INET_HOSTADDRBYINETSTRING))
254     {
255         wsaErr = ERROR_CALL_NOT_IMPLEMENTED;
256     }
257 
258 #endif /* NSP_REDIRECT */
259 
260     if (wsaErr != NO_ERROR)
261     {
262         WSASetLastError(wsaErr);
263         return SOCKET_ERROR;
264     }
265     return NO_ERROR;
266 }
267 
268 INT
269 WSAAPI
270 mwsNSPLookupServiceNext(_In_ HANDLE hLookup,
271                         _In_ DWORD dwControlFlags,
272                         _Inout_ LPDWORD lpdwBufferLength,
273                         //_Out_writes_bytes_to_(*lpdwBufferLength, *lpdwBufferLength)
274                         LPWSAQUERYSETW lpqsResults)
275 {
276     PWSHANDLEINTERN pLook = hLookup;
277     int wsaErr = 0;
278 
279 #ifdef NSP_REDIRECT
280 
281     INT res = pLook->rdrproc.NSPLookupServiceNext(pLook->rdrLookup,
282                                                   dwControlFlags,
283                                                   lpdwBufferLength,
284                                                   lpqsResults);
285     wsaErr = WSAGetLastError();
286     if (res != ERROR_SUCCESS)
287     {
288         wsaErr = WSAGetLastError();
289 
290         if (wsaErr == 0)
291             wsaErr = 0xFFFFFFFF;
292     }
293 
294 #else /* NSP_REDIRECT */
295 
296     if ((lpdwBufferLength == NULL) || (*lpdwBufferLength == 0))
297     {
298         wsaErr = WSA_NOT_ENOUGH_MEMORY;
299         goto End;
300     }
301 
302     RtlZeroMemory(lpqsResults, *lpdwBufferLength);
303     lpqsResults->dwSize = sizeof(*lpqsResults);
304 
305     wsaErr = NSP_LookupServiceNextW(pLook,
306                                     dwControlFlags,
307                                     lpqsResults,
308                                     lpdwBufferLength);
309 
310 
311 #endif /* NSP_REDIRECT */
312 
313 End:
314     if (wsaErr != 0)
315     {
316         WSASetLastError(wsaErr);
317         return SOCKET_ERROR;
318     }
319     return NO_ERROR;
320 }
321 
322 INT
323 WSAAPI
324 mwsNSPIoCtl(_In_ HANDLE hLookup,
325             _In_ DWORD dwControlCode,
326             _In_reads_bytes_(cbInBuffer) LPVOID lpvInBuffer,
327             _In_ DWORD cbInBuffer,
328             _Out_writes_bytes_to_(cbOutBuffer, *lpcbBytesReturned) LPVOID lpvOutBuffer,
329             _In_ DWORD cbOutBuffer,
330             _Out_ LPDWORD lpcbBytesReturned,
331             _In_opt_ LPWSACOMPLETION lpCompletion,
332             _In_ LPWSATHREADID lpThreadId)
333 {
334     WSASetLastError(ERROR_CALL_NOT_IMPLEMENTED);
335     return ERROR_CALL_NOT_IMPLEMENTED;
336 }
337 
338 INT
339 WSAAPI
340 mwsNSPLookupServiceEnd(_In_ HANDLE hLookup)
341 {
342     PWSHANDLEINTERN pLook;
343     HANDLE hHeap;
344     INT res;
345 
346     res = NO_ERROR;
347     pLook = (PWSHANDLEINTERN)hLookup;
348     hHeap = GetProcessHeap();
349 
350 #ifdef NSP_REDIRECT
351     res = pLook->rdrproc.NSPLookupServiceEnd(pLook->rdrLookup);
352 #endif
353 
354     if (pLook->hostnameW != NULL)
355         HeapFree(hHeap, 0, pLook->hostnameW);
356 
357     HeapFree(hHeap, 0, pLook);
358     return res;
359 }
360 
361 INT
362 WSAAPI
363 mwsNSPSetService(_In_ LPGUID lpProviderId,
364                  _In_ LPWSASERVICECLASSINFOW lpServiceClassInfo,
365                  _In_ LPWSAQUERYSETW lpqsRegInfo,
366                  _In_ WSAESETSERVICEOP essOperation,
367                  _In_ DWORD dwControlFlags)
368 {
369     WSASetLastError(ERROR_CALL_NOT_IMPLEMENTED);
370     return ERROR_CALL_NOT_IMPLEMENTED;
371 }
372 
373 INT
374 WSAAPI
375 mwsNSPInstallServiceClass(_In_ LPGUID lpProviderId,
376                           _In_ LPWSASERVICECLASSINFOW lpServiceClassInfo)
377 {
378     WSASetLastError(ERROR_CALL_NOT_IMPLEMENTED);
379     return ERROR_CALL_NOT_IMPLEMENTED;
380 }
381 
382 INT
383 WSAAPI
384 mwsNSPRemoveServiceClass(_In_ LPGUID lpProviderId,
385                          _In_ LPGUID lpServiceClassId)
386 {
387     WSASetLastError(ERROR_CALL_NOT_IMPLEMENTED);
388     return ERROR_CALL_NOT_IMPLEMENTED;
389 }
390 
391 INT
392 WSAAPI
393 mwsNSPGetServiceClassInfo(_In_ LPGUID lpProviderId,
394                           _In_ LPDWORD lpdwBufSize,
395                           _In_ LPWSASERVICECLASSINFOW lpServiceClassInfo)
396 {
397     WSASetLastError(ERROR_CALL_NOT_IMPLEMENTED);
398     return ERROR_CALL_NOT_IMPLEMENTED;
399 }
400 
401 /*
402     hostnameA / hostnameW
403     * only used by HOSTBYNAME
404     * only one should be set
405 
406 */
407 INT
408 NSP_LookupServiceBeginW(PWSHANDLEINTERN data,
409                         CHAR* hostnameA,
410                         WCHAR* hostnameW,
411                         DWORD CallID)
412 {
413     HANDLE hHeap;
414 
415     if (data->CallID != 0)
416         return WSAEFAULT;
417 
418     data->CallID = CallID;
419 
420     if ((CallID == NSP_CALLID_HOSTBYNAME) ||
421         (CallID == NSP_CALLID_SERVICEBYNAME))
422     {
423         hHeap = GetProcessHeap();
424 
425         if (data->hostnameW != NULL)
426             HeapFree(hHeap, 0, data->hostnameW);
427 
428         if (hostnameA != NULL)
429         {
430             data->hostnameW = StrA2WHeapAlloc(hHeap, hostnameA);
431         }
432         else
433         {
434             data->hostnameW = StrCpyHeapAllocW(hHeap, hostnameW);
435         }
436     }
437 
438     WSASetLastError(0);
439 
440     return ERROR_SUCCESS;
441 }
442 
443 INT
444 NSP_GetHostNameHeapAllocW(_Out_ WCHAR** hostname)
445 {
446     WCHAR* name;
447     HANDLE hHeap = GetProcessHeap();
448     DWORD bufCharLen = MAX_COMPUTERNAME_LENGTH + 1;
449     DWORD bufByteLen = bufCharLen * sizeof(WCHAR);
450 
451     name = HeapAlloc(hHeap, 0, bufByteLen);
452 
453     if (!GetComputerNameExW(ComputerNameDnsHostname,
454                             name,
455                             &bufCharLen))
456     {
457         HeapFree(hHeap, 0, name);
458         WSASetLastError(WSAEFAULT);
459         return SOCKET_ERROR;
460     }
461 
462     *hostname = name;
463     return ERROR_SUCCESS;
464 }
465 
466 INT
467 NSP_GetHostByNameHeapAllocW(_In_ PWSHANDLEINTERN data,
468                             _In_ DWORD dwControlFlags,
469                             _Out_ PWSHOSTINFOINTERN hostinfo)
470 {
471     HANDLE hHeap = GetProcessHeap();
472     DNS_STATUS dns_status = { 0 };
473     /* include/WinDNS.h -- look up DNS_RECORD on MSDN */
474     PDNS_RECORDW dp;
475     PDNS_RECORDW curr;
476     INT result = ERROR_SUCCESS;
477     DWORD dwQueryFlags = DNS_QUERY_STANDARD;
478     PWCHAR Aliases[WS2_INTERNAL_MAX_ALIAS] = { 0 };
479     int AliasIndex = 0;
480 
481     /* needed to be cleaned up if != NULL */
482     dp = NULL;
483 
484     if (data->hostnameW == NULL)
485     {
486         result = ERROR_INVALID_PARAMETER;
487         goto cleanup;
488     }
489 
490     if ((data->dwControlFlags & LUP_DEEP) == 0)
491     {
492         dwQueryFlags |= DNS_QUERY_NO_RECURSION;
493     }
494 
495     /* DNS_TYPE_A: include/WinDNS.h */
496     /* DnsQuery -- lib/dnsapi/dnsapi/query.c */
497     dns_status = DnsQuery_W(data->hostnameW,
498                             DNS_TYPE_A,
499                             dwQueryFlags,
500                             NULL /* extra dns servers */,
501                             &dp,
502                             NULL);
503     if (dns_status == ERROR_INVALID_NAME)
504     {
505         WSASetLastError(WSAEFAULT);
506         result = ERROR_INVALID_PARAMETER;
507         goto cleanup;
508     }
509 
510     if ((dns_status != 0) || (dp == NULL))
511     {
512         result = WSAHOST_NOT_FOUND;
513         goto cleanup;
514     }
515 
516     //ASSERT(dp->wType == DNS_TYPE_A);
517     //ASSERT(dp->wDataLength == sizeof(DNS_A_DATA));
518     curr = dp;
519     while ((curr->pNext != NULL) || (curr->wType != DNS_TYPE_A))
520     {
521         if (curr->wType == DNS_TYPE_CNAME)
522         {
523             Aliases[AliasIndex++] = curr->Data.Cname.pNameHost;
524         }
525         curr = curr->pNext;
526     }
527 
528     if (curr->wType != DNS_TYPE_A)
529     {
530         result = WSASERVICE_NOT_FOUND;
531         goto cleanup;
532     }
533     hostinfo->hostnameW = StrCpyHeapAllocW(hHeap, curr->pName);
534     hostinfo->addr4 = curr->Data.A.IpAddress;
535     if (AliasIndex)
536     {
537         hostinfo->servaliasesA = StrAryCpyHeapAllocWToA(hHeap, (WCHAR**)&Aliases);
538     }
539     result = ERROR_SUCCESS;
540 
541 cleanup:
542     if (dp != NULL)
543         DnsRecordListFree(dp, DnsFreeRecordList);
544 
545     return result;
546 }
547 
548 #define SKIPWS(ptr, act) \
549 {while(*ptr && isspace(*ptr)) ptr++; if(!*ptr) act;}
550 
551 #define SKIPANDMARKSTR(ptr, act) \
552 {while(*ptr && !isspace(*ptr)) ptr++; \
553  if(!*ptr) {act;} else { *ptr = 0; ptr++; }}
554 
555 static
556 BOOL
557 DecodeServEntFromString(IN PCHAR ServiceString,
558                         OUT PCHAR *ServiceName,
559                         OUT PCHAR *PortNumberStr,
560                         OUT PCHAR *ProtocolStr,
561                         IN PCHAR *Aliases,
562                         IN DWORD MaxAlias)
563 {
564     UINT NAliases = 0;
565 
566     //WS_DbgPrint(MAX_TRACE, ("Parsing service ent [%s]\n", ServiceString));
567 
568     SKIPWS(ServiceString, return FALSE);
569     *ServiceName = ServiceString;
570     SKIPANDMARKSTR(ServiceString, return FALSE);
571     SKIPWS(ServiceString, return FALSE);
572     *PortNumberStr = ServiceString;
573     SKIPANDMARKSTR(ServiceString, ;);
574 
575     while (*ServiceString && NAliases < MaxAlias - 1)
576     {
577         SKIPWS(ServiceString, break);
578         if (*ServiceString)
579         {
580             SKIPWS(ServiceString, ;);
581             if (strlen(ServiceString))
582             {
583                 //WS_DbgPrint(MAX_TRACE, ("Alias: %s\n", ServiceString));
584                 *Aliases++ = ServiceString;
585                 NAliases++;
586             }
587             SKIPANDMARKSTR(ServiceString, ;);
588         }
589     }
590     *Aliases = NULL;
591 
592     *ProtocolStr = strchr(*PortNumberStr, '/');
593 
594     if (!*ProtocolStr)
595         return FALSE;
596 
597     **ProtocolStr = 0;
598     (*ProtocolStr)++;
599 
600     //WS_DbgPrint(MAX_TRACE, ("Parsing done: %s %s %s %d\n",
601     //           *ServiceName, *ProtocolStr, *PortNumberStr,
602     //            NAliases));
603 
604     return TRUE;
605 }
606 
607 HANDLE
608 WSAAPI
609 OpenNetworkDatabase(_In_ LPCWSTR Name)
610 {
611     PWSTR ExpandedPath;
612     PWSTR DatabasePath;
613     INT ErrorCode;
614     HKEY DatabaseKey;
615     DWORD RegType;
616     DWORD RegSize = 0;
617     size_t StringLength;
618     HANDLE ret;
619 
620     ExpandedPath = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR));
621     if (!ExpandedPath)
622         return INVALID_HANDLE_VALUE;
623 
624     /* Open the database path key */
625     ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
626                              L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
627                              0,
628                              KEY_READ,
629                              &DatabaseKey);
630     if (ErrorCode == NO_ERROR)
631     {
632         /* Read the actual path */
633         ErrorCode = RegQueryValueEx(DatabaseKey,
634                                     L"DatabasePath",
635                                     NULL,
636                                     &RegType,
637                                     NULL,
638                                     &RegSize);
639 
640         DatabasePath = HeapAlloc(GetProcessHeap(), 0, RegSize);
641         if (!DatabasePath)
642         {
643             HeapFree(GetProcessHeap(), 0, ExpandedPath);
644             return INVALID_HANDLE_VALUE;
645         }
646 
647         /* Read the actual path */
648         ErrorCode = RegQueryValueEx(DatabaseKey,
649                                     L"DatabasePath",
650                                     NULL,
651                                     &RegType,
652                                     (LPBYTE)DatabasePath,
653                                     &RegSize);
654 
655         /* Close the key */
656         RegCloseKey(DatabaseKey);
657 
658         /* Expand the name */
659         ExpandEnvironmentStrings(DatabasePath, ExpandedPath, MAX_PATH);
660 
661         HeapFree(GetProcessHeap(), 0, DatabasePath);
662     }
663     else
664     {
665         /* Use defalt path */
666         GetSystemDirectory(ExpandedPath, MAX_PATH);
667         StringCchLength(ExpandedPath, MAX_PATH, &StringLength);
668         if (ExpandedPath[StringLength - 1] != L'\\')
669         {
670             /* It isn't, so add it ourselves */
671             StringCchCat(ExpandedPath, MAX_PATH, L"\\");
672         }
673         StringCchCat(ExpandedPath, MAX_PATH, L"DRIVERS\\ETC\\");
674     }
675 
676     /* Make sure that the path is backslash-terminated */
677     StringCchLength(ExpandedPath, MAX_PATH, &StringLength);
678     if (ExpandedPath[StringLength - 1] != L'\\')
679     {
680         /* It isn't, so add it ourselves */
681         StringCchCat(ExpandedPath, MAX_PATH, L"\\");
682     }
683 
684     /* Add the database name */
685     StringCchCat(ExpandedPath, MAX_PATH, Name);
686 
687     /* Return a handle to the file */
688     ret = CreateFile(ExpandedPath,
689                       FILE_READ_DATA,
690                       FILE_SHARE_READ,
691                       NULL,
692                       OPEN_EXISTING,
693                       FILE_ATTRIBUTE_NORMAL,
694                       NULL);
695 
696     HeapFree(GetProcessHeap(), 0, ExpandedPath);
697     return ret;
698 }
699 
700 INT
701 NSP_GetServiceByNameHeapAllocW(_In_ PWSHANDLEINTERN data,
702                                _In_ DWORD dwControlFlags,
703                                _Out_ PWSHOSTINFOINTERN hostinfo)
704 {
705     BOOL Found = FALSE;
706     HANDLE ServicesFile;
707     CHAR ServiceDBData[BUFSIZ * sizeof(WCHAR)] = {0};
708     PCHAR ThisLine = 0, NextLine = 0, ServiceName = 0, PortNumberStr = 0,
709     ProtocolStr = 0, Comment = 0, EndValid;
710     PCHAR Aliases[WS2_INTERNAL_MAX_ALIAS] = {0};
711     PCHAR* AliasPtr;
712     UINT i = 0;
713     DWORD ReadSize = 0;
714     HANDLE hHeap;
715     PCHAR nameA = NULL;
716     PCHAR nameServiceA = NULL;
717     PCHAR nameProtoA = NULL;
718     INT res = WSANO_RECOVERY;
719 
720     if (!data->hostnameW)
721     {
722         res = WSANO_RECOVERY;
723         goto End;
724     }
725 
726     hHeap = GetProcessHeap();
727     nameA = StrW2AHeapAlloc(hHeap, data->hostnameW);
728 
729     /* nameA has the form <service-name>/<protocol>
730        we split these now */
731     nameProtoA = strchr(nameA, '/');
732     if (nameProtoA == NULL)
733     {
734         res = WSANO_RECOVERY;
735         goto End;
736     }
737 
738     nameProtoA++;
739     i = (DWORD)(nameProtoA - nameA - 1);
740     nameServiceA = (PCHAR)HeapAlloc(hHeap, 0, i + 1);
741     StringCbCopyA(nameServiceA, i + 1, nameA);
742     nameServiceA[i] = '\0';
743 
744     ServicesFile = OpenNetworkDatabase(L"services");
745     if (ServicesFile == INVALID_HANDLE_VALUE)
746     {
747         return WSANO_RECOVERY;
748     }
749 
750     /* Scan the services file ...
751     *
752     * We will be share the buffer on the lines. If the line does not fit in
753     * the buffer, then moving it to the beginning of the buffer and read
754     * the remnants of line from file.
755     */
756 
757     /* Initial Read */
758     ReadFile(ServicesFile,
759              ServiceDBData,
760              sizeof( ServiceDBData ) - 1,
761              &ReadSize,
762              NULL);
763 
764     ThisLine = NextLine = ServiceDBData;
765     EndValid = ServiceDBData + ReadSize;
766     ServiceDBData[sizeof(ServiceDBData) - 1] = '\0';
767 
768     while (ReadSize)
769     {
770         for (; *NextLine != '\r' && *NextLine != '\n'; NextLine++)
771         {
772             if (NextLine == EndValid)
773             {
774                 int LineLen = NextLine - ThisLine;
775 
776                 if (ThisLine == ServiceDBData)
777                 {
778                     //WS_DbgPrint(MIN_TRACE,("Line too long"));
779                     return WSANO_RECOVERY;
780                 }
781 
782                 memmove(ServiceDBData, ThisLine, LineLen);
783 
784                 ReadFile(ServicesFile,
785                          ServiceDBData + LineLen,
786                          sizeof( ServiceDBData )-1 - LineLen,
787                          &ReadSize,
788                          NULL);
789 
790                 EndValid = ServiceDBData + LineLen + ReadSize;
791                 NextLine = ServiceDBData + LineLen;
792                 ThisLine = ServiceDBData;
793 
794                 if (!ReadSize) break;
795             }
796         }
797 
798         *NextLine = '\0';
799         Comment = strchr(ThisLine, '#');
800 
801         if (Comment)
802             *Comment = '\0'; /* Terminate at comment start */
803 
804         if (DecodeServEntFromString(ThisLine,
805                                     &ServiceName,
806                                     &PortNumberStr,
807                                     &ProtocolStr,
808                                     Aliases,
809                                     WS2_INTERNAL_MAX_ALIAS) &&
810             (strlen(nameProtoA) == 0 || strcmp(ProtocolStr, nameProtoA) == 0))
811         {
812             Found = (strcmp(ServiceName, nameServiceA) == 0 || strcmp(PortNumberStr, nameServiceA) == 0);
813             AliasPtr = Aliases;
814             while ((!Found) && (*AliasPtr != NULL))
815             {
816                 Found = (strcmp(*AliasPtr, nameServiceA) == 0);
817                 AliasPtr++;
818             }
819             if (Found)
820                 break;
821         }
822         NextLine++;
823         ThisLine = NextLine;
824     }
825 
826     /* This we'll do no matter what */
827     CloseHandle(ServicesFile);
828 
829     if (!Found)
830     {
831         return WSANO_DATA;
832     }
833 
834     hostinfo->addr4 = 0;
835     hostinfo->servnameW = StrA2WHeapAlloc(hHeap, ServiceName);
836     hostinfo->servprotoW = StrA2WHeapAlloc(hHeap, ProtocolStr);
837     hostinfo->servaliasesA = StrAryCpyHeapAllocA(hHeap, (char**)&Aliases);
838     hostinfo->servport = atoi(PortNumberStr);
839 
840     res = NO_ERROR;
841 
842 End:
843     if (nameA != NULL)
844         HeapFree(hHeap, 0, nameA);
845 
846     if (nameServiceA != NULL)
847         HeapFree(hHeap, 0, nameServiceA);
848 
849     return res;
850 }
851 
852 INT
853 NSP_LookupServiceNextW(_In_ PWSHANDLEINTERN data,
854                        _In_ DWORD dwControlFlags,
855                        _Inout_ LPWSAQUERYSETW lpRes,
856                        _Inout_ LPDWORD lpResLen)
857 {
858     MSW_BUFFER buf;
859     WSHOSTINFOINTERN hostinfo;
860     INT result;
861     HANDLE hHeap = GetProcessHeap();
862     WCHAR* ServiceInstanceNameW = NULL;
863     /* cleanup-vars */
864     CHAR* ServiceInstanceNameA = NULL;
865     CHAR* ServiceProtocolNameA = NULL;
866 
867     RtlZeroMemory(&hostinfo, sizeof(hostinfo));
868 
869     /* init and build result-buffer */
870     mswBufferInit(&buf, (BYTE*)lpRes, *lpResLen);
871     mswBufferIncUsed(&buf, sizeof(*lpRes));
872 
873     /* QueryDataSet-Size without "blob-data"-size! */
874     lpRes->dwSize = sizeof(*lpRes);
875     lpRes->dwNameSpace = NS_DNS;
876 
877     if ((data->CallID == NSP_CALLID_HOSTNAME) ||
878         (data->CallID == NSP_CALLID_HOSTBYNAME) ||
879         (data->CallID == NSP_CALLID_SERVICEBYNAME))
880     {
881         if (data->CallIDCounter >= 1)
882         {
883             result = WSAENOMORE;
884             goto End;
885         }
886     }
887     else
888     {
889         result = WSANO_RECOVERY;
890         goto End;
891     }
892     data->CallIDCounter++;
893 
894     if (data->CallID == NSP_CALLID_HOSTNAME)
895     {
896         result = NSP_GetHostNameHeapAllocW(&hostinfo.hostnameW);
897 
898         if (result != ERROR_SUCCESS)
899             goto End;
900 
901         hostinfo.addr4 = 0;
902     }
903     else if (data->CallID == NSP_CALLID_HOSTBYNAME)
904     {
905         result = NSP_GetHostByNameHeapAllocW(data,
906                                              dwControlFlags,
907                                              &hostinfo);
908         if (result != ERROR_SUCCESS)
909             goto End;
910     }
911     else
912     {
913         ASSERT(data->CallID == NSP_CALLID_SERVICEBYNAME);
914         result = NSP_GetServiceByNameHeapAllocW(data,
915                                                 dwControlFlags,
916                                                 &hostinfo);
917         if (result != ERROR_SUCCESS)
918             goto End;
919     }
920 
921     if (((LUP_RETURN_BLOB & data->dwControlFlags) != 0) ||
922         ((LUP_RETURN_NAME & data->dwControlFlags) != 0))
923     {
924         if (data->CallID == NSP_CALLID_HOSTNAME || data->CallID == NSP_CALLID_HOSTBYNAME)
925         {
926             ServiceInstanceNameW = hostinfo.hostnameW;
927             ServiceInstanceNameA = StrW2AHeapAlloc(hHeap, ServiceInstanceNameW);
928             if (ServiceInstanceNameA == NULL)
929             {
930                 result = WSAEFAULT;
931                 goto End;
932 
933             }
934         }
935         if (data->CallID == NSP_CALLID_SERVICEBYNAME)
936         {
937             ServiceInstanceNameW = hostinfo.servnameW;
938             ServiceInstanceNameA = StrW2AHeapAlloc(hHeap, ServiceInstanceNameW);
939             if (ServiceInstanceNameA == NULL)
940             {
941                 result = WSAEFAULT;
942                 goto End;
943 
944             }
945             ServiceProtocolNameA = StrW2AHeapAlloc(hHeap, hostinfo.servprotoW);
946             if (ServiceProtocolNameA == NULL)
947             {
948                 result = WSAEFAULT;
949                 goto End;
950 
951             }
952         }
953     }
954 
955     if ((LUP_RETURN_ADDR & data->dwControlFlags) != 0)
956     {
957         if (!mswBufferAppendAddr_AddrInfoW(&buf, lpRes, hostinfo.addr4))
958         {
959             *lpResLen = buf.bytesUsed;
960             result = WSAEFAULT;
961             goto End;
962         }
963     }
964 
965     if ((LUP_RETURN_BLOB & data->dwControlFlags) != 0)
966     {
967         if (data->CallID == NSP_CALLID_HOSTBYNAME)
968         {
969             /* Write data for PBLOB (hostent) */
970             if (!mswBufferAppendBlob_Hostent(&buf,
971                                              lpRes,
972                                              (LUP_RETURN_ALIASES & data->dwControlFlags) != 0 ? hostinfo.servaliasesA : NULL,
973                                              ServiceInstanceNameA,
974                                              hostinfo.addr4))
975             {
976                 *lpResLen = buf.bytesUsed;
977                 result = WSAEFAULT;
978                 goto End;
979             }
980         }
981         else if (data->CallID == NSP_CALLID_SERVICEBYNAME)
982         {
983             /* Write data for PBLOB (servent) */
984             if (!mswBufferAppendBlob_Servent(&buf,
985                                              lpRes,
986                                              ServiceInstanceNameA,/* ServiceName */
987                                              (LUP_RETURN_ALIASES & data->dwControlFlags) != 0 ? hostinfo.servaliasesA : NULL,
988                                              ServiceProtocolNameA,
989                                              hostinfo.servport))
990             {
991                 *lpResLen = buf.bytesUsed;
992                 result = WSAEFAULT;
993                 goto End;
994             }
995         }
996         else
997         {
998             result = WSANO_RECOVERY;
999             goto End;
1000         }
1001     }
1002 
1003     if ((LUP_RETURN_NAME & data->dwControlFlags) != 0)
1004     {
1005         /* HostByName sets the ServiceInstanceName to a
1006            (UNICODE)copy of hostent.h_name */
1007         lpRes->lpszServiceInstanceName = (LPWSTR)mswBufferEndPtr(&buf);
1008         if (!mswBufferAppendStrW(&buf, ServiceInstanceNameW))
1009         {
1010             lpRes->lpszServiceInstanceName = NULL;
1011             *lpResLen = buf.bytesUsed;
1012             result = WSAEFAULT;
1013             goto End;
1014         }
1015     }
1016 
1017     *lpResLen = buf.bytesUsed;
1018 
1019     result = ERROR_SUCCESS;
1020 End:
1021     /* cleanup */
1022     if (ServiceInstanceNameA != NULL)
1023         HeapFree(hHeap, 0, ServiceInstanceNameA);
1024 
1025     if (ServiceProtocolNameA != NULL)
1026         HeapFree(hHeap, 0, ServiceProtocolNameA);
1027 
1028     if (hostinfo.hostnameW != NULL)
1029         HeapFree(hHeap, 0, hostinfo.hostnameW);
1030 
1031     if (hostinfo.servnameW != NULL)
1032         HeapFree(hHeap, 0, hostinfo.servnameW);
1033 
1034     if (hostinfo.servprotoW != NULL)
1035         HeapFree(hHeap, 0, hostinfo.servprotoW);
1036 
1037     return result;
1038 }
1039 
1040 /* Implementations - Exports */
1041 /*
1042  * @implemented
1043  */
1044 int
1045 WINAPI
1046 NSPStartup(_In_ LPGUID lpProviderId,
1047            _Out_ LPNSP_ROUTINE lpRout)
1048 {
1049     INT ret;
1050 
1051     if ((lpRout == NULL) ||
1052         (lpRout->cbSize != sizeof(NSP_ROUTINE)))
1053     {
1054         WSASetLastError(ERROR_INVALID_PARAMETER);
1055         return ERROR_INVALID_PARAMETER;
1056     }
1057 
1058     mwsNSPInit();
1059 
1060     /* set own Provider GUID - maybe we need
1061        here to set the original mswsock-GUID?! */
1062 
1063     /* Win2k3 returns
1064        - Version 1.1
1065        - no NSPIoctl
1066        - sets cbSize to 44! */
1067     lpRout->dwMajorVersion = 1;
1068     lpRout->dwMinorVersion = 1;
1069     lpRout->cbSize = sizeof(*lpRout) - sizeof(lpRout->NSPIoctl);
1070     lpRout->NSPCleanup = &mwsNSPCleanUp;
1071     lpRout->NSPLookupServiceBegin = &mwsNSPLookupServiceBegin;
1072     lpRout->NSPLookupServiceNext = &mwsNSPLookupServiceNext;
1073     lpRout->NSPLookupServiceEnd = &mwsNSPLookupServiceEnd;
1074     lpRout->NSPSetService = &mwsNSPSetService;
1075     lpRout->NSPInstallServiceClass = &mwsNSPInstallServiceClass;
1076     lpRout->NSPRemoveServiceClass = &mwsNSPRemoveServiceClass;
1077     lpRout->NSPGetServiceClassInfo = &mwsNSPGetServiceClassInfo;
1078     lpRout->NSPIoctl = NULL;// &mwsNSPIoCtl;
1079 
1080     ret = NO_ERROR;
1081 
1082     return ret;
1083 }
1084