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