Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

416 lines
11 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. netname.c
  5. Abstract:
  6. Routines for validating a network name and making sure
  7. that it is ok to use.
  8. Author:
  9. John Vert (jvert) 4/15/1997
  10. Revision History:
  11. --*/
  12. #include "clusrtlp.h"
  13. #include <lmerr.h>
  14. #include <lmcons.h>
  15. #include "icanon.h"
  16. #include "netcan.h"
  17. #include <nb30.h>
  18. #include <msgrutil.h>
  19. #include <lmaccess.h>
  20. #include <lmuse.h>
  21. #include <lmwksta.h>
  22. #include <netlogon.h>
  23. #include <logonp.h>
  24. #include <windns.h>
  25. #include <ipexport.h>
  26. NET_API_STATUS
  27. NET_API_FUNCTION
  28. NetpCheckNetBiosNameNotInUse(
  29. LPWSTR pszName
  30. );
  31. BOOL
  32. ClRtlIsNetNameValid(
  33. IN LPCWSTR NetName,
  34. OUT OPTIONAL CLRTL_NAME_STATUS *Result,
  35. IN BOOL CheckIfExists
  36. )
  37. /*++
  38. Routine Description:
  39. Validates a network name to make sure it is ok to use.
  40. If it is not ok, it optionally returns the reason.
  41. The checks this routine does include:
  42. Name must not be zero length (NetNameEmpty)
  43. After conversion to OEM, name must be <= MAX_COMPUTERNAME_LENGTH (NetNameTooLong)
  44. No spaces (NetNameInvalidChars)
  45. No internet characters "@, (NetNameInvalidChars)
  46. Name already present on network (NetNameInUse)
  47. This routine is netbios-centric in that the name passed in must meet the
  48. criteria for a valid netbios name. At some point, we'll need to pass in
  49. the type of validation since it is possible on NT5 to configure a
  50. netbios-less environment.
  51. Arguments:
  52. NetName - Supplies the network name.
  53. Result - if present, returns the exact check that failed.
  54. CheckIfExists - Specifies whether a check should be made to
  55. see if the network name exists on the network.
  56. Return Value:
  57. TRUE - the network name is valid.
  58. FALSE - the network name is not valid.
  59. --*/
  60. {
  61. DWORD UnicodeSize;
  62. DWORD OemSize;
  63. BOOL Valid = FALSE;
  64. CLRTL_NAME_STATUS Reason = NetNameOk;
  65. DWORD Status;
  66. //
  67. // Check the Unicode length.
  68. //
  69. UnicodeSize = lstrlenW(NetName);
  70. if (UnicodeSize == 0) {
  71. Reason = NetNameEmpty;
  72. goto error_exit;
  73. }
  74. if (UnicodeSize > MAX_COMPUTERNAME_LENGTH) {
  75. Reason = NetNameTooLong;
  76. goto error_exit;
  77. }
  78. //
  79. // netbios names are converted to multi-byte before being registered. Make
  80. // sure that when converted to MBCS, the name is not more than
  81. // MAX_COMPUTERNAME_LENGTH bytes long.
  82. //
  83. OemSize = WideCharToMultiByte(CP_OEMCP,
  84. 0,
  85. NetName,
  86. UnicodeSize,
  87. NULL,
  88. 0,
  89. NULL,
  90. NULL);
  91. if (OemSize > MAX_COMPUTERNAME_LENGTH) {
  92. Reason = NetNameTooLong;
  93. goto error_exit;
  94. }
  95. //
  96. // Now call NetpwNameValidate. This will only check for invalid characters since
  97. // we have already validated the length.
  98. //
  99. if (NetpwNameValidate((LPWSTR)NetName, NAMETYPE_COMPUTER, 0) != ERROR_SUCCESS) {
  100. Reason = NetNameInvalidChars;
  101. goto error_exit;
  102. }
  103. //
  104. // Now we need to check for an invalid DNS name. If this fails, it is
  105. // probably because of additional invalid characters. Currently we do not
  106. // support the thing net setup does where it creates an alternate DNS name
  107. // that is different than the netbios name. There should be no periods in
  108. // this name as well, since that will cause the DNS validate name check to
  109. // fail when this name is brought online.
  110. //
  111. Status = DnsValidateName_W( NetName, DnsNameHostnameLabel );
  112. if ( Status != ERROR_SUCCESS ) {
  113. if ( Status == DNS_ERROR_NON_RFC_NAME ) {
  114. Reason = NetNameDNSNonRFCChars;
  115. } else {
  116. Reason = NetNameInvalidChars;
  117. }
  118. goto error_exit;
  119. }
  120. //
  121. // Finally, check to see if this name is already present on the network.
  122. //
  123. if (CheckIfExists) {
  124. Status = NetpCheckNetBiosNameNotInUse((LPWSTR)NetName);
  125. if (Status != NERR_Success) {
  126. Reason = NetNameInUse;
  127. goto error_exit;
  128. }
  129. }
  130. Reason = NetNameOk;
  131. Valid = TRUE;
  132. error_exit:
  133. if (ARGUMENT_PRESENT(Result)) {
  134. *Result = Reason;
  135. }
  136. return(Valid);
  137. }
  138. #define clearncb(x) memset((char *)x,'\0',sizeof(NCB))
  139. /*++
  140. Routine Description:
  141. FmtNcbName - format a name NCB-style
  142. Given a name, a name type, and a destination address, this
  143. function copies the name and the type to the destination in
  144. the format used in the name fields of a Network Control
  145. Block.
  146. SIDE EFFECTS
  147. Modifies 16 bytes starting at the destination address.
  148. Arguments:
  149. DestBuf - Pointer to the destination buffer.
  150. Name - Unicode NUL-terminated name string
  151. Type - Name type number (0, 3, 5, or 32) (3=NON_FWD, 5=FWD)
  152. Return Value:
  153. NERR_Success - The operation was successful
  154. Translated Return Code from the Rtl Translate routine.
  155. NOTE: This should only be called from UNICODE
  156. --*/
  157. NET_API_STATUS
  158. MsgFmtNcbName(
  159. char * DestBuf,
  160. WCHAR * Name,
  161. DWORD Type)
  162. {
  163. DWORD i; // Counter
  164. NTSTATUS ntStatus;
  165. OEM_STRING ansiString;
  166. UNICODE_STRING unicodeString;
  167. PCHAR pAnsiString;
  168. //
  169. // Convert the unicode name string into an ansi string - using the
  170. // current locale.
  171. //
  172. unicodeString.Length = (USHORT)(wcslen(Name) * sizeof(WCHAR));
  173. unicodeString.MaximumLength = unicodeString.Length + sizeof(WCHAR);
  174. unicodeString.Buffer = Name;
  175. ntStatus = RtlUnicodeStringToOemString(
  176. &ansiString,
  177. &unicodeString,
  178. TRUE); // Allocate the ansiString Buffer.
  179. if (!NT_SUCCESS(ntStatus)) {
  180. return RtlNtStatusToDosError( ntStatus );
  181. }
  182. pAnsiString = ansiString.Buffer;
  183. *(pAnsiString+ansiString.Length) = '\0';
  184. //
  185. // copy each character until a NUL is reached, or until NCBNAMSZ-1
  186. // characters have been copied.
  187. //
  188. for (i=0; i < NCBNAMSZ - 1; ++i) {
  189. if (*pAnsiString == '\0') {
  190. break;
  191. }
  192. //
  193. // Copy the Name
  194. //
  195. *DestBuf++ = (char)toupper(*pAnsiString++);
  196. }
  197. //
  198. // Free the buffer that RtlUnicodeStringToOemString created for us.
  199. // NOTE: only the ansiString.Buffer portion is free'd.
  200. //
  201. RtlFreeOemString( &ansiString);
  202. //
  203. // Pad the name field with spaces
  204. //
  205. for(; i < NCBNAMSZ - 1; ++i) {
  206. *DestBuf++ = ' ';
  207. }
  208. //
  209. // Set the name type.
  210. //
  211. *DestBuf = (CHAR) Type; // Set name type
  212. return(NERR_Success);
  213. }
  214. NET_API_STATUS
  215. NET_API_FUNCTION
  216. NetpCheckNetBiosNameNotInUse(
  217. LPWSTR pszName
  218. )
  219. /*++
  220. Routine Description:
  221. Attempt to discover the if the name is in use. If the name shows up on any
  222. LANA then consider it in use.
  223. Arguments:
  224. pszName - name to check
  225. Return Value:
  226. NERR_Success if ok, NERR_NameInUse otherwise
  227. --*/
  228. {
  229. //
  230. // initial and delta value used to allocate NAME_BUFFER buffers
  231. //
  232. #define NUM_NAME_BUFFERS 10
  233. NCB ncb;
  234. LANA_ENUM lanaBuffer;
  235. DWORD index;
  236. UCHAR nbStatus;
  237. NET_API_STATUS netStatus = NERR_Success;
  238. DWORD numNameBuffers = NUM_NAME_BUFFERS;
  239. WORD aStatBufferSize = (WORD)(sizeof(ADAPTER_STATUS)+ numNameBuffers * sizeof(NAME_BUFFER));
  240. UCHAR staticAStat[ sizeof(ADAPTER_STATUS)+ NUM_NAME_BUFFERS * sizeof(NAME_BUFFER) ];
  241. PADAPTER_STATUS adapterStatus;
  242. PNAME_BUFFER nameBuffer;
  243. //
  244. // Find the number of networks by sending an enum request via
  245. // Netbios. there is no (easy) way to distinguish netbt from IPX.
  246. //
  247. clearncb(&ncb);
  248. ncb.ncb_command = NCBENUM; // Enumerate LANA nums (wait)
  249. ncb.ncb_buffer = (PUCHAR)&lanaBuffer;
  250. ncb.ncb_length = sizeof(LANA_ENUM);
  251. nbStatus = Netbios (&ncb);
  252. if (nbStatus != NRC_GOODRET) {
  253. return( NetpNetBiosStatusToApiStatus( nbStatus ) );
  254. }
  255. //
  256. // clear the NCB and format the remote name appropriately.
  257. //
  258. clearncb(&ncb);
  259. netStatus = MsgFmtNcbName( (char *)ncb.ncb_callname, pszName, 0x20);
  260. if ( netStatus != NERR_Success ) {
  261. return ( netStatus );
  262. }
  263. //
  264. // have our buffers initially point to the static buffer
  265. //
  266. adapterStatus = (PADAPTER_STATUS)staticAStat;
  267. nameBuffer = (PNAME_BUFFER)(adapterStatus + 1);
  268. //
  269. // cycle through the lanas, issueing an adapter status on the remote name.
  270. //
  271. for ( index = 0; index < lanaBuffer.length && netStatus == NERR_Success; index++ ) {
  272. NetpNetBiosReset( lanaBuffer.lana[index] );
  273. astat_retry:
  274. ncb.ncb_command = NCBASTAT;
  275. ncb.ncb_buffer = (PUCHAR)adapterStatus;
  276. ncb.ncb_length = aStatBufferSize;
  277. ncb.ncb_lana_num = lanaBuffer.lana[index];
  278. nbStatus = Netbios( &ncb );
  279. if ( nbStatus == NRC_INCOMP ) {
  280. //
  281. // buffer not large enough and we don't know how big a buffer we
  282. // need. allocate a larger buffer and retry the request until we
  283. // get success or another type of failure.
  284. //
  285. if ( (PUCHAR)adapterStatus != staticAStat ) {
  286. LocalFree( adapterStatus );
  287. }
  288. numNameBuffers += NUM_NAME_BUFFERS;
  289. aStatBufferSize = (WORD)(sizeof(ADAPTER_STATUS)+ numNameBuffers * sizeof(NAME_BUFFER));
  290. adapterStatus = LocalAlloc( LMEM_FIXED, aStatBufferSize );
  291. if ( adapterStatus == NULL ) {
  292. return netStatus; // err on the side of caution
  293. }
  294. nameBuffer = (PNAME_BUFFER)(adapterStatus + 1);
  295. goto astat_retry;
  296. } else
  297. if ( nbStatus == NRC_GOODRET ) {
  298. //
  299. // got something back. Look through the list of names to make sure
  300. // our name is really online. We couldv'e gotten here through a
  301. // stale name registration.
  302. //
  303. while ( adapterStatus->name_count-- ) {
  304. if (( nameBuffer->name_flags & GROUP_NAME ) == 0 ) {
  305. if ( _strnicmp( nameBuffer->name, ncb.ncb_callname, NCBNAMSZ - 1 ) == 0 ) {
  306. netStatus = NERR_NameInUse;
  307. break;
  308. }
  309. }
  310. ++nameBuffer;
  311. }
  312. }
  313. if ( netStatus != NERR_Success ) {
  314. break;
  315. }
  316. }
  317. if ( (PUCHAR)adapterStatus != staticAStat ) {
  318. LocalFree( adapterStatus );
  319. }
  320. return( netStatus );
  321. }