[MSWSOCK] Add wine debug messages on mswsock debug channel.
[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 #include <winreg.h>
14
15 #include "mswhelper.h"
16
17 #include <wine/debug.h>
18 WINE_DEFAULT_DEBUG_CHANNEL(mswsock);
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 TRACE("mwsNSPLookupServiceBegin %p %p %p %lx %p\n", lpProviderId, lpqsRestrictions, lpServiceClassInfo, dwControlFlags, lphLookup);
158 if (IsEqualGUID(lpProviderId, &guid_mswsock_TcpIp))
159 {
160 //OK
161 TRACE("TCPIP query\n");
162 }
163 else if (IsEqualGUID(lpProviderId, &guid_mswsock_NLA))
164 {
165 ERR("NLA queries are not supported yet\n");
166 WSASetLastError(WSASERVICE_NOT_FOUND);
167 return SOCKET_ERROR;
168 }
169 else
170 {
171 ERR("Unsupported GUID\n");
172 return ERROR_CALL_NOT_IMPLEMENTED;
173 }
174
175 /* allocate internal structure */
176 pLook = HeapAlloc(GetProcessHeap(), 0, sizeof(WSHANDLEINTERN));
177 if (!pLook)
178 {
179 ERR("Error allocating %d for handle\n", sizeof(WSHANDLEINTERN));
180 WSASetLastError(WSAEFAULT);
181 return SOCKET_ERROR;
182 }
183
184 *lphLookup = (HANDLE)pLook;
185
186 RtlZeroMemory(pLook, sizeof(*pLook));
187
188 /* Anyway the ControlFlags "should" be needed
189 in NSPLookupServiceNext. (see doku) But
190 thats not the fact ATM. */
191 pLook->dwControlFlags = dwControlFlags;
192 pLook->providerId = *lpProviderId;
193
194 #ifdef NSP_REDIRECT
195
196 if (IsEqualGUID(lpProviderId, &guid_mswsock_TcpIp))
197 {
198 pLook->rdrproc = rdrproc_tcpip;
199 }
200 else if (IsEqualGUID(lpProviderId, &guid_mswsock_NLA))
201 {
202 pLook->rdrproc = rdrproc_nla;
203 }
204 else
205 {
206 return ERROR_CALL_NOT_IMPLEMENTED;
207 }
208
209 if (pLook->rdrproc.NSPLookupServiceBegin(lpProviderId,
210 lpqsRestrictions,
211 lpServiceClassInfo,
212 dwControlFlags,
213 &pLook->rdrLookup) == NO_ERROR)
214 {
215 wsaErr = NO_ERROR;
216 }
217 else
218 {
219 wsaErr = WSAGetLastError();
220 }
221
222 /*
223 if (res)
224 res = WSAGetLastError();
225 */
226
227 #else /* NSP_REDIRECT */
228
229 wsaErr = ERROR_CALL_NOT_IMPLEMENTED;
230 if (IsEqualGUID(lpqsRestrictions->lpServiceClassId, &guid_NULL))
231 {
232 ERR("NULL GUID service class is not implemented yet\n");
233 wsaErr = ERROR_CALL_NOT_IMPLEMENTED;
234 }
235 else if (IsEqualGUID(lpqsRestrictions->lpServiceClassId, &guid_HOSTNAME))
236 {
237 TRACE("HOSTNAME GUID\n");
238 wsaErr = NSP_LookupServiceBeginW(pLook,
239 NULL,
240 NULL,
241 NSP_CALLID_HOSTNAME);
242 }
243 else if (IsEqualGUID(lpqsRestrictions->lpServiceClassId,
244 &guid_INET_HOSTADDRBYNAME))
245 {
246 TRACE("INET_HOSTADDRBYNAME GUID\n");
247 wsaErr = NSP_LookupServiceBeginW(pLook,
248 NULL,
249 lpqsRestrictions->lpszServiceInstanceName,
250 NSP_CALLID_HOSTBYNAME);
251 }
252 else if (IsEqualGUID(lpqsRestrictions->lpServiceClassId,
253 &guid_INET_SERVICEBYNAME))
254 {
255 TRACE("INET_SERVICEBYNAME\n");
256 wsaErr = NSP_LookupServiceBeginW(pLook,
257 NULL,
258 lpqsRestrictions->lpszServiceInstanceName,
259 NSP_CALLID_SERVICEBYNAME);
260 }
261 else if (IsEqualGUID(lpqsRestrictions->lpServiceClassId,
262 &guid_INET_HOSTADDRBYINETSTRING))
263 {
264 ERR("INET_HOSTADDRBYINETSTRING GUID service class is not implemented yet\n");
265 wsaErr = ERROR_CALL_NOT_IMPLEMENTED;
266 }
267
268 #endif /* NSP_REDIRECT */
269
270 if (wsaErr != NO_ERROR)
271 {
272 ERR("mwsNSPLookupServiceBegin wsaErr = %d\n", wsaErr);
273 WSASetLastError(wsaErr);
274 return SOCKET_ERROR;
275 }
276 return NO_ERROR;
277 }
278
279 INT
280 WSAAPI
281 mwsNSPLookupServiceNext(_In_ HANDLE hLookup,
282 _In_ DWORD dwControlFlags,
283 _Inout_ LPDWORD lpdwBufferLength,
284 //_Out_writes_bytes_to_(*lpdwBufferLength, *lpdwBufferLength)
285 LPWSAQUERYSETW lpqsResults)
286 {
287 PWSHANDLEINTERN pLook = hLookup;
288 int wsaErr = 0;
289
290 TRACE("mwsNSPLookupServiceNext %p %lx %p %p\n", pLook, dwControlFlags, lpdwBufferLength, lpqsResults);
291 #ifdef NSP_REDIRECT
292
293 INT res = pLook->rdrproc.NSPLookupServiceNext(pLook->rdrLookup,
294 dwControlFlags,
295 lpdwBufferLength,
296 lpqsResults);
297 wsaErr = WSAGetLastError();
298 if (res != ERROR_SUCCESS)
299 {
300 wsaErr = WSAGetLastError();
301
302 if (wsaErr == 0)
303 wsaErr = 0xFFFFFFFF;
304 }
305
306 #else /* NSP_REDIRECT */
307
308 if ((lpdwBufferLength == NULL) || (*lpdwBufferLength == 0))
309 {
310 wsaErr = WSA_NOT_ENOUGH_MEMORY;
311 goto End;
312 }
313
314 RtlZeroMemory(lpqsResults, *lpdwBufferLength);
315 lpqsResults->dwSize = sizeof(*lpqsResults);
316
317 wsaErr = NSP_LookupServiceNextW(pLook,
318 dwControlFlags,
319 lpqsResults,
320 lpdwBufferLength);
321
322
323 #endif /* NSP_REDIRECT */
324
325 End:
326 if (wsaErr != 0)
327 {
328 ERR("mwsNSPLookupServiceNext wsaErr = %d\n", wsaErr);
329 WSASetLastError(wsaErr);
330 return SOCKET_ERROR;
331 }
332 return NO_ERROR;
333 }
334
335 INT
336 WSAAPI
337 mwsNSPIoCtl(_In_ HANDLE hLookup,
338 _In_ DWORD dwControlCode,
339 _In_reads_bytes_(cbInBuffer) LPVOID lpvInBuffer,
340 _In_ DWORD cbInBuffer,
341 _Out_writes_bytes_to_(cbOutBuffer, *lpcbBytesReturned) LPVOID lpvOutBuffer,
342 _In_ DWORD cbOutBuffer,
343 _Out_ LPDWORD lpcbBytesReturned,
344 _In_opt_ LPWSACOMPLETION lpCompletion,
345 _In_ LPWSATHREADID lpThreadId)
346 {
347 ERR("mwsNSPIoCtl not implemented %p %lx %p %ld %p %ld %p %p %p\n", hLookup, dwControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, lpCompletion, lpThreadId);
348 WSASetLastError(WSAEOPNOTSUPP);
349 return ERROR_CALL_NOT_IMPLEMENTED;
350 }
351
352 INT
353 WSAAPI
354 mwsNSPLookupServiceEnd(_In_ HANDLE hLookup)
355 {
356 PWSHANDLEINTERN pLook = (PWSHANDLEINTERN)hLookup;
357 HANDLE hHeap = GetProcessHeap();
358 INT res = NO_ERROR;
359
360 TRACE("mwsNSPLookupServiceEnd %p\n", pLook);
361 #ifdef NSP_REDIRECT
362 res = pLook->rdrproc.NSPLookupServiceEnd(pLook->rdrLookup);
363 #endif
364
365 if (pLook->hostnameW != NULL)
366 HeapFree(hHeap, 0, pLook->hostnameW);
367
368 HeapFree(hHeap, 0, pLook);
369 return res;
370 }
371
372 INT
373 WSAAPI
374 mwsNSPSetService(_In_ LPGUID lpProviderId,
375 _In_ LPWSASERVICECLASSINFOW lpServiceClassInfo,
376 _In_ LPWSAQUERYSETW lpqsRegInfo,
377 _In_ WSAESETSERVICEOP essOperation,
378 _In_ DWORD dwControlFlags)
379 {
380 ERR("mwsNSPSetService not implemented %p %p %p %d %lx %ld %p %p %p\n", lpProviderId, lpServiceClassInfo, lpqsRegInfo, essOperation, dwControlFlags);
381 WSASetLastError(WSAEOPNOTSUPP);
382 return ERROR_CALL_NOT_IMPLEMENTED;
383 }
384
385 INT
386 WSAAPI
387 mwsNSPInstallServiceClass(_In_ LPGUID lpProviderId,
388 _In_ LPWSASERVICECLASSINFOW lpServiceClassInfo)
389 {
390 ERR("mwsNSPInstallServiceClass not implemented %p %p\n", lpProviderId, lpServiceClassInfo);
391 WSASetLastError(WSAEOPNOTSUPP);
392 return ERROR_CALL_NOT_IMPLEMENTED;
393 }
394
395 INT
396 WSAAPI
397 mwsNSPRemoveServiceClass(_In_ LPGUID lpProviderId,
398 _In_ LPGUID lpServiceClassId)
399 {
400 ERR("mwsNSPRemoveServiceClass not implemented %p %p\n", lpProviderId, lpServiceClassId);
401 WSASetLastError(WSAEOPNOTSUPP);
402 return ERROR_CALL_NOT_IMPLEMENTED;
403 }
404
405 INT
406 WSAAPI
407 mwsNSPGetServiceClassInfo(_In_ LPGUID lpProviderId,
408 _In_ LPDWORD lpdwBufSize,
409 _In_ LPWSASERVICECLASSINFOW lpServiceClassInfo)
410 {
411 ERR("mwsNSPGetServiceClassInfo not implemented %p %p %p\n", lpProviderId, lpdwBufSize, lpServiceClassInfo);
412 WSASetLastError(WSAEOPNOTSUPP);
413 return ERROR_CALL_NOT_IMPLEMENTED;
414 }
415
416 /*
417 hostnameA / hostnameW
418 * only used by HOSTBYNAME
419 * only one should be set
420
421 */
422 INT
423 NSP_LookupServiceBeginW(PWSHANDLEINTERN data,
424 CHAR* hostnameA,
425 WCHAR* hostnameW,
426 DWORD CallID)
427 {
428 HANDLE hHeap;
429
430 TRACE("NSP_LookupServiceBeginW %p %p %p %lx\n", data, hostnameA, hostnameW, CallID);
431 if (data->CallID != 0)
432 return WSAEFAULT;
433
434 data->CallID = CallID;
435
436 if ((CallID == NSP_CALLID_HOSTBYNAME) ||
437 (CallID == NSP_CALLID_SERVICEBYNAME))
438 {
439 hHeap = GetProcessHeap();
440
441 if (data->hostnameW != NULL)
442 HeapFree(hHeap, 0, data->hostnameW);
443
444 if (hostnameA != NULL)
445 {
446 data->hostnameW = StrA2WHeapAlloc(hHeap, hostnameA);
447 }
448 else
449 {
450 data->hostnameW = StrCpyHeapAllocW(hHeap, hostnameW);
451 }
452 }
453 else
454 {
455 ERR("NSP_LookupServiceBeginW unsupported CallID\n");
456 WSASetLastError(ERROR_CALL_NOT_IMPLEMENTED);
457 return ERROR_CALL_NOT_IMPLEMENTED;
458 }
459
460 return ERROR_SUCCESS;
461 }
462
463 INT
464 NSP_GetHostNameHeapAllocW(_Out_ WCHAR** hostname)
465 {
466 WCHAR* name;
467 HANDLE hHeap = GetProcessHeap();
468 DWORD bufCharLen = 0;
469
470 TRACE("NSP_GetHostNameHeapAllocW %p\n", hostname);
471 /* FIXME Use DnsGetHostName_W when available */
472 GetComputerNameExW(ComputerNameDnsHostname, NULL, &bufCharLen);
473 if (!bufCharLen)
474 {
475 ERR("NSP_GetHostNameHeapAllocW zero size for computername returned\n");
476 WSASetLastError(WSAEFAULT);
477 return SOCKET_ERROR;
478 }
479 name = HeapAlloc(hHeap, 0, bufCharLen*sizeof(WCHAR));
480 if (!GetComputerNameExW(ComputerNameDnsHostname,
481 name,
482 &bufCharLen))
483 {
484 ERR("NSP_GetHostNameHeapAllocW error obtaining computername %lx\n", GetLastError());
485 HeapFree(hHeap, 0, name);
486 WSASetLastError(WSAEFAULT);
487 return SOCKET_ERROR;
488 }
489
490 *hostname = name;
491 return ERROR_SUCCESS;
492 }
493
494 INT
495 NSP_GetHostByNameHeapAllocW(_In_ PWSHANDLEINTERN data,
496 _In_ DWORD dwControlFlags,
497 _Out_ PWSHOSTINFOINTERN hostinfo)
498 {
499 HANDLE hHeap = GetProcessHeap();
500 DNS_STATUS dns_status = { 0 };
501 /* include/WinDNS.h -- look up DNS_RECORD on MSDN */
502 PDNS_RECORDW dp;
503 PDNS_RECORDW curr;
504 INT result = ERROR_SUCCESS;
505 DWORD dwQueryFlags = DNS_QUERY_STANDARD;
506 PWCHAR Aliases[WS2_INTERNAL_MAX_ALIAS] = { 0 };
507 int AliasIndex = 0;
508
509 TRACE("NSP_GetHostByNameHeapAllocW %p %lx %p\n", data, dwControlFlags, hostinfo);
510 /* needed to be cleaned up if != NULL */
511 dp = NULL;
512
513 if (!data->hostnameW)
514 {
515 result = ERROR_INVALID_PARAMETER;
516 goto cleanup;
517 }
518
519 if ((data->dwControlFlags & LUP_DEEP) == 0)
520 {
521 TRACE("NSP_GetHostByNameHeapAllocW LUP_DEEP is not specified. Disabling recursion\n");
522 dwQueryFlags |= DNS_QUERY_NO_RECURSION;
523 }
524
525 /* DNS_TYPE_A: include/WinDNS.h */
526 /* DnsQuery -- lib/dnsapi/dnsapi/query.c */
527 dns_status = DnsQuery_W(data->hostnameW,
528 DNS_TYPE_A,
529 dwQueryFlags,
530 NULL /* extra dns servers */,
531 &dp,
532 NULL);
533 if (dns_status == ERROR_INVALID_NAME)
534 {
535 ERR("NSP_GetHostByNameHeapAllocW invalid name\n");
536 WSASetLastError(WSAEFAULT);
537 result = ERROR_INVALID_PARAMETER;
538 goto cleanup;
539 }
540
541 if ((dns_status != 0) || (dp == NULL))
542 {
543 ERR("NSP_GetHostByNameHeapAllocW not found %lx %p\n", dns_status, dp);
544 result = WSAHOST_NOT_FOUND;
545 goto cleanup;
546 }
547
548 //ASSERT(dp->wType == DNS_TYPE_A);
549 //ASSERT(dp->wDataLength == sizeof(DNS_A_DATA));
550 curr = dp;
551 while ((curr->pNext != NULL) || (curr->wType != DNS_TYPE_A))
552 {
553 if (curr->wType == DNS_TYPE_CNAME)
554 {
555 TRACE("NSP_GetHostByNameHeapAllocW found alias %ws\n", curr->Data.Cname.pNameHost);
556 Aliases[AliasIndex++] = curr->Data.Cname.pNameHost;
557 }
558 curr = curr->pNext;
559 }
560
561 if (curr->wType != DNS_TYPE_A)
562 {
563 ERR("NSP_GetHostByNameHeapAllocW last record is not of type A %d\n", curr->wType);
564 result = WSASERVICE_NOT_FOUND;
565 goto cleanup;
566 }
567 hostinfo->hostnameW = StrCpyHeapAllocW(hHeap, curr->pName);
568 hostinfo->addr4 = curr->Data.A.IpAddress;
569 if (AliasIndex)
570 {
571 hostinfo->servaliasesA = StrAryCpyHeapAllocWToA(hHeap, (WCHAR**)&Aliases);
572 }
573 result = ERROR_SUCCESS;
574
575 cleanup:
576 if (dp != NULL)
577 DnsRecordListFree(dp, DnsFreeRecordList);
578
579 return result;
580 }
581
582 #define SKIPWS(ptr, act) \
583 {while(*ptr && isspace(*ptr)) ptr++; if(!*ptr) act;}
584
585 #define SKIPANDMARKSTR(ptr, act) \
586 {while(*ptr && !isspace(*ptr)) ptr++; \
587 if(!*ptr) {act;} else { *ptr = 0; ptr++; }}
588
589 static
590 BOOL
591 DecodeServEntFromString(IN PCHAR ServiceString,
592 OUT PCHAR *ServiceName,
593 OUT PCHAR *PortNumberStr,
594 OUT PCHAR *ProtocolStr,
595 IN PCHAR *Aliases,
596 IN DWORD MaxAlias)
597 {
598 UINT NAliases = 0;
599
600 //WS_DbgPrint(MAX_TRACE, ("Parsing service ent [%s]\n", ServiceString));
601
602 SKIPWS(ServiceString, return FALSE);
603 *ServiceName = ServiceString;
604 SKIPANDMARKSTR(ServiceString, return FALSE);
605 SKIPWS(ServiceString, return FALSE);
606 *PortNumberStr = ServiceString;
607 SKIPANDMARKSTR(ServiceString, ;);
608
609 while (*ServiceString && NAliases < MaxAlias - 1)
610 {
611 SKIPWS(ServiceString, break);
612 if (*ServiceString)
613 {
614 SKIPWS(ServiceString, ;);
615 if (strlen(ServiceString))
616 {
617 //WS_DbgPrint(MAX_TRACE, ("Alias: %s\n", ServiceString));
618 *Aliases++ = ServiceString;
619 NAliases++;
620 }
621 SKIPANDMARKSTR(ServiceString, ;);
622 }
623 }
624 *Aliases = NULL;
625
626 *ProtocolStr = strchr(*PortNumberStr, '/');
627
628 if (!*ProtocolStr)
629 return FALSE;
630
631 **ProtocolStr = 0;
632 (*ProtocolStr)++;
633
634 //WS_DbgPrint(MAX_TRACE, ("Parsing done: %s %s %s %d\n",
635 // *ServiceName, *ProtocolStr, *PortNumberStr,
636 // NAliases));
637
638 return TRUE;
639 }
640
641 HANDLE
642 WSAAPI
643 OpenNetworkDatabase(_In_ LPCWSTR Name)
644 {
645 PWSTR ExpandedPath;
646 PWSTR DatabasePath;
647 INT ErrorCode;
648 HKEY DatabaseKey;
649 DWORD RegType;
650 DWORD RegSize = 0;
651 size_t StringLength;
652 HANDLE Handle;
653
654 TRACE("OpenNetworkDatabase %p\n", Name);
655 ExpandedPath = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR));
656 if (!ExpandedPath)
657 return INVALID_HANDLE_VALUE;
658
659 /* Open the database path key */
660 ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
661 L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
662 0,
663 KEY_READ,
664 &DatabaseKey);
665 if (ErrorCode == NO_ERROR)
666 {
667 TRACE("OpenNetworkDatabase registry key for network database exist\n");
668 /* Read the actual path */
669 ErrorCode = RegQueryValueEx(DatabaseKey,
670 L"DatabasePath",
671 NULL,
672 &RegType,
673 NULL,
674 &RegSize);
675
676 if (!RegSize)
677 {
678 ERR("OpenNetworkDatabase RegQueryValueEx failed to return size for DatabasePath %lx\n", ErrorCode);
679 RegCloseKey(DatabaseKey);
680 HeapFree(GetProcessHeap(), 0, ExpandedPath);
681 return INVALID_HANDLE_VALUE;
682 }
683 DatabasePath = HeapAlloc(GetProcessHeap(), 0, RegSize);
684 if (!DatabasePath)
685 {
686 ERR("OpenNetworkDatabase could not allocate %d for DatabasePath\n", RegSize);
687 RegCloseKey(DatabaseKey);
688 HeapFree(GetProcessHeap(), 0, ExpandedPath);
689 return INVALID_HANDLE_VALUE;
690 }
691
692 /* Read the actual path */
693 ErrorCode = RegQueryValueEx(DatabaseKey,
694 L"DatabasePath",
695 NULL,
696 &RegType,
697 (LPBYTE)DatabasePath,
698 &RegSize);
699
700 /* Close the key */
701 RegCloseKey(DatabaseKey);
702
703 if (ErrorCode)
704 {
705 ERR("OpenNetworkDatabase RegQueryValueEx failed to return value for DatabasePath %lx\n", ErrorCode);
706 HeapFree(GetProcessHeap(), 0, DatabasePath);
707 HeapFree(GetProcessHeap(), 0, ExpandedPath);
708 return INVALID_HANDLE_VALUE;
709 }
710
711 /* Expand the name */
712 ExpandEnvironmentStrings(DatabasePath, ExpandedPath, MAX_PATH);
713
714 HeapFree(GetProcessHeap(), 0, DatabasePath);
715 }
716 else
717 {
718 TRACE("OpenNetworkDatabase registry key for network database doesn't exist\n");
719 /* Use defalt path */
720 GetSystemDirectory(ExpandedPath, MAX_PATH);
721 StringCchLength(ExpandedPath, MAX_PATH, &StringLength);
722 if (ExpandedPath[StringLength - 1] != L'\\')
723 {
724 /* It isn't, so add it ourselves */
725 StringCchCat(ExpandedPath, MAX_PATH, L"\\");
726 }
727 StringCchCat(ExpandedPath, MAX_PATH, L"DRIVERS\\ETC\\");
728 }
729
730 /* Make sure that the path is backslash-terminated */
731 StringCchLength(ExpandedPath, MAX_PATH, &StringLength);
732 if (ExpandedPath[StringLength - 1] != L'\\')
733 {
734 /* It isn't, so add it ourselves */
735 StringCchCat(ExpandedPath, MAX_PATH, L"\\");
736 }
737
738 /* Add the database name */
739 StringCchCat(ExpandedPath, MAX_PATH, Name);
740
741 /* Return a handle to the file */
742 Handle = CreateFile(ExpandedPath,
743 FILE_READ_DATA,
744 FILE_SHARE_READ,
745 NULL,
746 OPEN_EXISTING,
747 FILE_ATTRIBUTE_NORMAL,
748 NULL);
749
750 HeapFree(GetProcessHeap(), 0, ExpandedPath);
751 return Handle;
752 }
753
754 INT
755 NSP_GetServiceByNameHeapAllocW(_In_ PWSHANDLEINTERN data,
756 _In_ DWORD dwControlFlags,
757 _Out_ PWSHOSTINFOINTERN hostinfo)
758 {
759 BOOL Found = FALSE;
760 HANDLE ServicesFile;
761 CHAR ServiceDBData[BUFSIZ * sizeof(WCHAR)] = { 0 };
762 PCHAR ThisLine = 0, NextLine = 0, ServiceName = 0, PortNumberStr = 0,
763 ProtocolStr = 0, Comment = 0, EndValid;
764 PCHAR Aliases[WS2_INTERNAL_MAX_ALIAS] = { 0 };
765 PCHAR* AliasPtr;
766 UINT i = 0;
767 DWORD ReadSize = 0;
768 HANDLE hHeap;
769 PCHAR nameA = NULL;
770 PCHAR nameServiceA = NULL;
771 PCHAR nameProtoA = NULL;
772 INT res = WSANO_RECOVERY;
773
774 TRACE("NSP_GetServiceByNameHeapAllocW %p %lx %p\n", data, dwControlFlags, hostinfo);
775 if (!data->hostnameW)
776 {
777 ERR("NSP_GetServiceByNameHeapAllocW service name not provided\n");
778 res = WSANO_RECOVERY;
779 goto End;
780 }
781
782 hHeap = GetProcessHeap();
783 nameA = StrW2AHeapAlloc(hHeap, data->hostnameW);
784
785 /* nameA has the form <service-name>/<protocol>
786 we split these now */
787 nameProtoA = strchr(nameA, '/');
788 if (nameProtoA == NULL)
789 {
790 ERR("NSP_GetServiceByNameHeapAllocW invalid service name %s\n", nameA);
791 res = WSANO_RECOVERY;
792 goto End;
793 }
794
795 nameProtoA++;
796 i = (DWORD)(nameProtoA - nameA - 1);
797 nameServiceA = (PCHAR)HeapAlloc(hHeap, 0, i + 1);
798 StringCbCopyA(nameServiceA, i + 1, nameA);
799 nameServiceA[i] = '\0';
800
801 ServicesFile = OpenNetworkDatabase(L"services");
802 if (ServicesFile == INVALID_HANDLE_VALUE)
803 {
804 ERR("NSP_GetServiceByNameHeapAllocW unable to open services file\n");
805 return WSANO_RECOVERY;
806 }
807
808 /* Scan the services file ...
809 *
810 * We will be share the buffer on the lines. If the line does not fit in
811 * the buffer, then moving it to the beginning of the buffer and read
812 * the remnants of line from file.
813 */
814
815 /* Initial Read */
816 if (!ReadFile(ServicesFile,
817 ServiceDBData,
818 sizeof( ServiceDBData ) - 1,
819 &ReadSize,
820 NULL))
821 {
822 ERR("NSP_GetServiceByNameHeapAllocW can't read services file %lx\n", GetLastError());
823 CloseHandle(ServicesFile);
824 return WSANO_RECOVERY;
825 }
826
827 ThisLine = NextLine = ServiceDBData;
828 EndValid = ServiceDBData + ReadSize;
829 ServiceDBData[sizeof(ServiceDBData) - 1] = '\0';
830
831 while (ReadSize)
832 {
833 for (; *NextLine != '\r' && *NextLine != '\n'; NextLine++)
834 {
835 if (NextLine == EndValid)
836 {
837 int LineLen = NextLine - ThisLine;
838
839 if (ThisLine == ServiceDBData)
840 {
841 ERR("NSP_GetServiceByNameHeapAllocW line too long\n");
842 CloseHandle(ServicesFile);
843 return WSANO_RECOVERY;
844 }
845
846 memmove(ServiceDBData, ThisLine, LineLen);
847
848 if (!ReadFile(ServicesFile,
849 ServiceDBData + LineLen,
850 sizeof( ServiceDBData )-1 - LineLen,
851 &ReadSize,
852 NULL))
853 {
854 break;
855 }
856
857 EndValid = ServiceDBData + LineLen + ReadSize;
858 NextLine = ServiceDBData + LineLen;
859 ThisLine = ServiceDBData;
860
861 if (!ReadSize) break;
862 }
863 }
864
865 *NextLine = '\0';
866 Comment = strchr(ThisLine, '#');
867
868 if (Comment)
869 *Comment = '\0'; /* Terminate at comment start */
870
871 if (DecodeServEntFromString(ThisLine,
872 &ServiceName,
873 &PortNumberStr,
874 &ProtocolStr,
875 Aliases,
876 WS2_INTERNAL_MAX_ALIAS) &&
877 (strlen(nameProtoA) == 0 || strcmp(ProtocolStr, nameProtoA) == 0))
878 {
879 Found = (strcmp(ServiceName, nameServiceA) == 0 || strcmp(PortNumberStr, nameServiceA) == 0);
880 AliasPtr = Aliases;
881 while ((!Found) && (*AliasPtr != NULL))
882 {
883 Found = (strcmp(*AliasPtr, nameServiceA) == 0);
884 AliasPtr++;
885 }
886 if (Found)
887 break;
888 }
889 NextLine++;
890 ThisLine = NextLine;
891 }
892
893 /* This we'll do no matter what */
894 CloseHandle(ServicesFile);
895
896 if (!Found)
897 {
898 ERR("NSP_GetServiceByNameHeapAllocW service not found\n");
899 return WSANO_DATA;
900 }
901
902 hostinfo->addr4 = 0;
903 hostinfo->servnameW = StrA2WHeapAlloc(hHeap, ServiceName);
904 hostinfo->servprotoW = StrA2WHeapAlloc(hHeap, ProtocolStr);
905 hostinfo->servaliasesA = StrAryCpyHeapAllocA(hHeap, (char**)&Aliases);
906 hostinfo->servport = atoi(PortNumberStr);
907
908 res = NO_ERROR;
909
910 End:
911 if (nameA)
912 HeapFree(hHeap, 0, nameA);
913
914 if (nameServiceA)
915 HeapFree(hHeap, 0, nameServiceA);
916
917 return res;
918 }
919
920 INT
921 NSP_LookupServiceNextW(_In_ PWSHANDLEINTERN data,
922 _In_ DWORD dwControlFlags,
923 _Inout_ LPWSAQUERYSETW lpRes,
924 _Inout_ LPDWORD lpResLen)
925 {
926 MSW_BUFFER buf;
927 WSHOSTINFOINTERN hostinfo;
928 INT result;
929 HANDLE hHeap = GetProcessHeap();
930 WCHAR* ServiceInstanceNameW = NULL;
931 /* cleanup-vars */
932 CHAR* ServiceInstanceNameA = NULL;
933 CHAR* ServiceProtocolNameA = NULL;
934
935 TRACE("NSP_LookupServiceNextW %p %lx %p %p\n", data, dwControlFlags, lpRes, lpResLen);
936 if (!data || (dwControlFlags & (~(DWORD)LUP_FLUSHPREVIOUS)) != 0 || !lpRes || !lpResLen || *lpResLen == 0)
937 return WSAEINVAL;
938 RtlZeroMemory(&hostinfo, sizeof(hostinfo));
939
940 /* init and build result-buffer */
941 mswBufferInit(&buf, (BYTE*)lpRes, *lpResLen);
942 mswBufferIncUsed(&buf, sizeof(*lpRes));
943
944 /* QueryDataSet-Size without "blob-data"-size! */
945 lpRes->dwSize = sizeof(*lpRes);
946 lpRes->dwNameSpace = NS_DNS;
947
948 if ((data->CallID == NSP_CALLID_HOSTNAME) ||
949 (data->CallID == NSP_CALLID_HOSTBYNAME) ||
950 (data->CallID == NSP_CALLID_SERVICEBYNAME))
951 {
952 /* FIXME remember what was returned and continue from there */
953 if (data->CallIDCounter >= 1)
954 {
955 ERR("NSP_LookupServiceNextW LUP_FLUSHPREVIOUS and more than one call not supported yet\n", data, dwControlFlags, lpRes, lpResLen);
956 result = WSA_E_NO_MORE;
957 goto End;
958 }
959 }
960 else
961 {
962 ERR("NSP_LookupServiceNextW unsupported CallID %lx\n", data->CallID);
963 result = WSAEOPNOTSUPP;
964 goto End;
965 }
966 data->CallIDCounter++;
967
968 if (data->CallID == NSP_CALLID_HOSTNAME)
969 {
970 result = NSP_GetHostNameHeapAllocW(&hostinfo.hostnameW);
971
972 if (result != ERROR_SUCCESS)
973 goto End;
974
975 hostinfo.addr4 = 0;
976 }
977 else if (data->CallID == NSP_CALLID_HOSTBYNAME)
978 {
979 result = NSP_GetHostByNameHeapAllocW(data,
980 dwControlFlags,
981 &hostinfo);
982 if (result != ERROR_SUCCESS)
983 goto End;
984 }
985 else
986 {
987 //ASSERT(data->CallID == NSP_CALLID_SERVICEBYNAME);
988 result = NSP_GetServiceByNameHeapAllocW(data,
989 dwControlFlags,
990 &hostinfo);
991 if (result != ERROR_SUCCESS)
992 goto End;
993 }
994
995 if (((LUP_RETURN_BLOB & data->dwControlFlags) != 0) ||
996 ((LUP_RETURN_NAME & data->dwControlFlags) != 0))
997 {
998 if (data->CallID == NSP_CALLID_HOSTNAME || data->CallID == NSP_CALLID_HOSTBYNAME)
999 {
1000 ServiceInstanceNameW = hostinfo.hostnameW;
1001 ServiceInstanceNameA = StrW2AHeapAlloc(hHeap, ServiceInstanceNameW);
1002 if (!ServiceInstanceNameA)
1003 {
1004 ERR("NSP_LookupServiceNextW not enough memory\n");
1005 result = WSA_NOT_ENOUGH_MEMORY;
1006 goto End;
1007 }
1008 }
1009 if (data->CallID == NSP_CALLID_SERVICEBYNAME)
1010 {
1011 ServiceInstanceNameW = hostinfo.servnameW;
1012 ServiceInstanceNameA = StrW2AHeapAlloc(hHeap, ServiceInstanceNameW);
1013 if (!ServiceInstanceNameA)
1014 {
1015 ERR("NSP_LookupServiceNextW not enough memory\n");
1016 result = WSA_NOT_ENOUGH_MEMORY;
1017 goto End;
1018 }
1019 ServiceProtocolNameA = StrW2AHeapAlloc(hHeap, hostinfo.servprotoW);
1020 if (!ServiceProtocolNameA)
1021 {
1022 ERR("NSP_LookupServiceNextW not enough memory\n");
1023 result = WSA_NOT_ENOUGH_MEMORY;
1024 goto End;
1025 }
1026 }
1027 }
1028
1029 if ((LUP_RETURN_ADDR & data->dwControlFlags) != 0)
1030 {
1031 if (!mswBufferAppendAddr_AddrInfoW(&buf, lpRes, hostinfo.addr4))
1032 {
1033 ERR("NSP_LookupServiceNextW provided buffer is too small\n");
1034 *lpResLen = buf.bytesUsed;
1035 result = WSAEFAULT;
1036 goto End;
1037 }
1038 }
1039
1040 if ((LUP_RETURN_BLOB & data->dwControlFlags) != 0)
1041 {
1042 if (data->CallID == NSP_CALLID_HOSTBYNAME)
1043 {
1044 /* Write data for PBLOB (hostent) */
1045 if (!mswBufferAppendBlob_Hostent(&buf,
1046 lpRes,
1047 (LUP_RETURN_ALIASES & data->dwControlFlags) != 0 ? hostinfo.servaliasesA : NULL,
1048 ServiceInstanceNameA,
1049 hostinfo.addr4))
1050 {
1051 ERR("NSP_LookupServiceNextW provided buffer is too small\n");
1052 *lpResLen = buf.bytesUsed;
1053 result = WSAEFAULT;
1054 goto End;
1055 }
1056 }
1057 else if (data->CallID == NSP_CALLID_SERVICEBYNAME)
1058 {
1059 /* Write data for PBLOB (servent) */
1060 if (!mswBufferAppendBlob_Servent(&buf,
1061 lpRes,
1062 ServiceInstanceNameA,/* ServiceName */
1063 (LUP_RETURN_ALIASES & data->dwControlFlags) != 0 ? hostinfo.servaliasesA : NULL,
1064 ServiceProtocolNameA,
1065 hostinfo.servport))
1066 {
1067 ERR("NSP_LookupServiceNextW provided buffer is too small\n");
1068 *lpResLen = buf.bytesUsed;
1069 result = WSAEFAULT;
1070 goto End;
1071 }
1072 }
1073 else
1074 {
1075 ERR("NSP_LookupServiceNextW LUP_RETURN_BLOB is supported only for NSP_CALLID_HOSTBYNAME and NSP_CALLID_SERVICEBYNAME\n");
1076 result = WSAEINVAL;
1077 goto End;
1078 }
1079 }
1080
1081 if ((LUP_RETURN_NAME & data->dwControlFlags) != 0)
1082 {
1083 /* HostByName sets the ServiceInstanceName to a
1084 (UNICODE)copy of hostent.h_name */
1085 lpRes->lpszServiceInstanceName = (LPWSTR)mswBufferEndPtr(&buf);
1086 if (!mswBufferAppendStrW(&buf, ServiceInstanceNameW))
1087 {
1088 ERR("NSP_LookupServiceNextW provided buffer is too small\n");
1089 lpRes->lpszServiceInstanceName = NULL;
1090 *lpResLen = buf.bytesUsed;
1091 result = WSAEFAULT;
1092 goto End;
1093 }
1094 }
1095
1096 *lpResLen = buf.bytesUsed;
1097
1098 result = ERROR_SUCCESS;
1099 End:
1100 /* cleanup */
1101 if (ServiceInstanceNameA != NULL)
1102 HeapFree(hHeap, 0, ServiceInstanceNameA);
1103
1104 if (ServiceProtocolNameA != NULL)
1105 HeapFree(hHeap, 0, ServiceProtocolNameA);
1106
1107 if (hostinfo.hostnameW != NULL)
1108 HeapFree(hHeap, 0, hostinfo.hostnameW);
1109
1110 if (hostinfo.servnameW != NULL)
1111 HeapFree(hHeap, 0, hostinfo.servnameW);
1112
1113 if (hostinfo.servprotoW != NULL)
1114 HeapFree(hHeap, 0, hostinfo.servprotoW);
1115
1116 TRACE("NSP_LookupServiceNextW returns %d needed bytes %ld\n", result, buf.bytesUsed);
1117 return result;
1118 }
1119
1120 /* Implementations - Exports */
1121 /*
1122 * @implemented
1123 */
1124 int
1125 WINAPI
1126 NSPStartup(_In_ LPGUID lpProviderId,
1127 _Out_ LPNSP_ROUTINE lpRout)
1128 {
1129 INT ret;
1130
1131 TRACE("NSPStartup %p %p\n", lpProviderId, lpRout);
1132 if (!lpRout || (lpRout->cbSize != sizeof(NSP_ROUTINE)))
1133 {
1134 ERR("NSPStartup invalid parameter\n");
1135 WSASetLastError(WSAEINVAL);
1136 return ERROR_INVALID_PARAMETER;
1137 }
1138
1139 mwsNSPInit();
1140
1141 /* set own Provider GUID - maybe we need
1142 here to set the original mswsock-GUID?! */
1143
1144 /* Win2k3 returns
1145 - Version 1.1
1146 - no NSPIoctl
1147 - sets cbSize to 44! */
1148 lpRout->dwMajorVersion = 1;
1149 lpRout->dwMinorVersion = 1;
1150 lpRout->cbSize = sizeof(*lpRout) - sizeof(lpRout->NSPIoctl);
1151 lpRout->NSPCleanup = &mwsNSPCleanUp;
1152 lpRout->NSPLookupServiceBegin = &mwsNSPLookupServiceBegin;
1153 lpRout->NSPLookupServiceNext = &mwsNSPLookupServiceNext;
1154 lpRout->NSPLookupServiceEnd = &mwsNSPLookupServiceEnd;
1155 lpRout->NSPSetService = &mwsNSPSetService;
1156 lpRout->NSPInstallServiceClass = &mwsNSPInstallServiceClass;
1157 lpRout->NSPRemoveServiceClass = &mwsNSPRemoveServiceClass;
1158 lpRout->NSPGetServiceClassInfo = &mwsNSPGetServiceClassInfo;
1159 lpRout->NSPIoctl = NULL;// &mwsNSPIoCtl;
1160
1161 ret = NO_ERROR;
1162
1163 return ret;
1164 }