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