Leaked source code of windows server 2003
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.

2149 lines
54 KiB

  1. //============================================================================
  2. // Copyright (c) 1996, Microsoft Corporation
  3. //
  4. // File: script.c
  5. //
  6. // History:
  7. // Abolade-Gbadegesin 03-29-96 Created.
  8. //
  9. // This file contains functions implementing the NT port
  10. // of Win9x dial-up scripting, listed in alphabetical order.
  11. //
  12. // See scriptp.h for details on the NT implementation.
  13. //============================================================================
  14. #include <scriptp.h>
  15. #include <lmwksta.h> // For NetWkstaUserGetInfo
  16. #include <lmapibuf.h> // For NetApiBufferFree
  17. //
  18. // Handle of module-instance for this DLL
  19. //
  20. HANDLE g_hinst;
  21. //
  22. // global critical section used to synhronize access to IP address strings
  23. //
  24. CRITICAL_SECTION g_cs;
  25. //
  26. // name of file to which script syntax errors are logged
  27. //
  28. CHAR c_szScriptLog[] = RASSCRIPT_LOG;
  29. //
  30. // event handle which would be notified in case of IPAddress Change
  31. //
  32. HANDLE hIpAddressSet = INVALID_HANDLE_VALUE;
  33. #define NET_SVCS_GROUP "-k netsvcs"
  34. //----------------------------------------------------------------------------
  35. // Function: DLLMAIN
  36. //
  37. // DLL entry-point for RASSCRIPT
  38. //----------------------------------------------------------------------------
  39. BOOL
  40. WINAPI
  41. RasScriptDllMain(
  42. IN HINSTANCE hinstance,
  43. IN DWORD dwReason,
  44. IN PVOID pUnused
  45. ) {
  46. BOOL bRetVal = TRUE;
  47. if (dwReason == DLL_PROCESS_ATTACH) {
  48. g_hinst = (HANDLE)hinstance;
  49. try
  50. {
  51. InitializeCriticalSection(&g_cs);
  52. }
  53. except (EXCEPTION_EXECUTE_HANDLER)
  54. {
  55. bRetVal = FALSE;
  56. }
  57. }
  58. else
  59. if (dwReason == DLL_PROCESS_DETACH) {
  60. DeleteCriticalSection(&g_cs);
  61. }
  62. return bRetVal;
  63. }
  64. //----------------------------------------------------------------------------
  65. // Function: RasScriptExecute
  66. //
  67. // Examines the given connection, and if there is a script for the connection,
  68. // executes the script to completion.
  69. // Returns the error code from script processing if a script is given,
  70. // and returns NO_ERROR otherwise.
  71. //----------------------------------------------------------------------------
  72. DWORD
  73. APIENTRY
  74. RasScriptExecute(
  75. IN HRASCONN hrasconn,
  76. IN PBENTRY* pEntry,
  77. IN CHAR* pszUserName,
  78. IN CHAR* pszPassword,
  79. OUT CHAR* pszIpAddress
  80. ) {
  81. DWORD dwErr;
  82. HANDLE hevent = NULL, hscript = NULL;
  83. HANDLE hEvents[2];
  84. RASSCRPT_TRACE("RasScriptExecute");
  85. do {
  86. //
  87. // create event on which to receive notification
  88. //
  89. hevent = CreateEvent(NULL, FALSE, FALSE, NULL);
  90. if (!hevent) {
  91. dwErr = GetLastError();
  92. RASSCRPT_TRACE1("error %d creating event", dwErr);
  93. break;
  94. }
  95. // Create a separate event for SCRIPTCODE_IpAddressSet
  96. // event. We hit a timing window ow where we lose this
  97. // event (when we get a script complete event immediately
  98. // after a SCRIPTCODE_IpAddressSet event. bug 75226.
  99. hIpAddressSet = CreateEvent (NULL, FALSE, FALSE, NULL);
  100. if (!hIpAddressSet) {
  101. dwErr = GetLastError();
  102. RASSCRPT_TRACE1("error %d creating event", dwErr);
  103. break;
  104. }
  105. //
  106. // initialize script processing
  107. //
  108. dwErr = RasScriptInit(
  109. hrasconn, pEntry, pszUserName, pszPassword, 0, hevent,
  110. &hscript
  111. );
  112. if (dwErr != NO_ERROR) {
  113. RASSCRPT_TRACE1("error %d initializing scripting", dwErr);
  114. break;
  115. }
  116. hEvents[0] = hevent;
  117. hEvents[1] = hIpAddressSet;
  118. //
  119. // loop waiting for script to finish running
  120. //
  121. for ( ; ; ) {
  122. dwErr = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
  123. if (dwErr - WAIT_OBJECT_0 == 0) {
  124. //
  125. // Retrieve the code for the event which occurred
  126. //
  127. DWORD dwCode = RasScriptGetEventCode(hscript);
  128. RASSCRPT_TRACE1("RasScriptExecute: eventcode %d", dwCode);
  129. //
  130. // Handle the event
  131. //
  132. if (dwCode == SCRIPTCODE_Done ||
  133. dwCode == SCRIPTCODE_Halted ||
  134. dwCode == SCRIPTCODE_HaltedOnError) {
  135. RASSCRPT_TRACE("script processing completed");
  136. dwErr = NO_ERROR;
  137. break;
  138. }
  139. }
  140. else
  141. if (dwErr - WAIT_OBJECT_0 == 1) {
  142. //
  143. // The IP address has been changed;
  144. // read the new IP address into the caller's buffer
  145. //
  146. RASSCRPT_TRACE("IP address changed");
  147. dwErr = RasScriptGetIpAddress(hscript, pszIpAddress);
  148. RASSCRPT_TRACE2("RasScriptGetIpAddress(e=%d,a=%s)",dwErr,pszIpAddress);
  149. }
  150. }
  151. } while(FALSE);
  152. if (hscript) { RasScriptTerm(hscript); }
  153. if (hevent) { CloseHandle(hevent); }
  154. if (hIpAddressSet) { CloseHandle (hIpAddressSet); }
  155. return dwErr;
  156. }
  157. //----------------------------------------------------------------------------
  158. // Function: RasScriptGetEventCode
  159. //
  160. // This function should be called to retrieve the event-code
  161. // when the scripting thread signals an event.
  162. // The event codes which may be returned are as follows:
  163. //
  164. // NO_ERROR: no code has been set
  165. // SCRIPTCODE_Done: the script has finished running;
  166. // the thread blocks until RasScriptTerm is called.
  167. // SCRIPTCODE_InputNotify: data is available in the buffer; if the buffer
  168. // is full, the thread blocks until
  169. // RasScriptReceive is called and the data
  170. // is read successfully.
  171. // SCRIPTCODE_KeyboardEnable: the keyboard should be enabled.
  172. // SCRIPTCODE_KeyboardDisable: the keyboard should be disabled.
  173. // SCRIPTCODE_IpAddressSet: the IP address has changed; the new address
  174. // can be retrieved via RasScriptGetIPAddress.
  175. // SCRIPTCODE_HaltedOnError: the script has halted due to an error.
  176. //----------------------------------------------------------------------------
  177. DWORD
  178. RasScriptGetEventCode(
  179. IN HANDLE hscript
  180. ) {
  181. SCRIPTCB* pscript = (SCRIPTCB *)hscript;
  182. RASSCRPT_TRACE("RasGetEventCode");
  183. if (!pscript) { return ERROR_INVALID_PARAMETER; }
  184. return pscript->dwEventCode;
  185. }
  186. //----------------------------------------------------------------------------
  187. // Function: RasScriptGetIpAddress
  188. //
  189. // This function retrieves the current IP address as set by the script.
  190. //----------------------------------------------------------------------------
  191. DWORD
  192. RasScriptGetIpAddress(
  193. IN HANDLE hscript,
  194. OUT CHAR* pszIpAddress
  195. ) {
  196. SCRIPTCB* pscript = (SCRIPTCB *)hscript;
  197. RASSCRPT_TRACE("RasGetIpAddress");
  198. if (!pscript || !pszIpAddress) { return ERROR_INVALID_PARAMETER; }
  199. //
  200. // Access to the IP address string must be synchronized
  201. // since it may also be accessed via RxSetIPAddress
  202. //
  203. EnterCriticalSection(&g_cs);
  204. if (pscript->pszIpAddress) {
  205. lstrcpy(pszIpAddress, pscript->pszIpAddress);
  206. }
  207. else {
  208. lstrcpy(pszIpAddress, "0.0.0.0");
  209. }
  210. LeaveCriticalSection(&g_cs);
  211. return NO_ERROR;
  212. }
  213. //----------------------------------------------------------------------------
  214. // Function: RasScriptInit
  215. //
  216. // Initializes for script processing on the given HRASCONN.
  217. //
  218. // This function creates a thread which handles script input and output
  219. // on the given connection's port.
  220. //
  221. // If there is no script for the connection, this function returns an error
  222. // unless the flag RASSCRIPT_NotifyOnInput is specified, in which case
  223. // the thread loops posting receive-data requests on the connection's port
  224. // until RasScriptTerm is called.
  225. //
  226. // If there is a script for the connection, the thread runs the script
  227. // to completion. If the flag RASSCRIPT_NotifyOnInput is specified,
  228. // the caller is notified when data is received on the port. The caller
  229. // can then retrieve the data by calling RasScriptReceive.
  230. //
  231. // Notification may be event-based or message-based. By default, notification
  232. // is event-based, and "Hnotifier" is treated as an event-handle.
  233. // The event is signalled to by the scripting thread, and the caller retrieves
  234. // the event code by calling RasScriptGetEventCode.
  235. //
  236. // Setting the flag RASSCRIPT_HwndNotify selects message-based notification,
  237. // and indicates that "Hnotifier" is an HWND. The WM_RASSCRIPT event is sent
  238. // to the window by the scripting thread, and "LParam" in the message sent
  239. // contains the event code. See RasScriptGetEventCode for descriptions
  240. // of the codes sent by the scripting thread.
  241. //----------------------------------------------------------------------------
  242. DWORD
  243. APIENTRY
  244. RasScriptInit(
  245. IN HRASCONN hrasconn,
  246. IN PBENTRY* pEntry,
  247. IN CHAR* pszUserName,
  248. IN CHAR* pszPassword,
  249. IN DWORD dwFlags,
  250. IN HANDLE hNotifier,
  251. OUT HANDLE* phscript
  252. ) {
  253. DWORD dwErr, dwSyntaxError = NO_ERROR;
  254. static const CHAR szSwitch[] = MXS_SWITCH_TXT;
  255. SCRIPTCB* pscript = NULL;
  256. #ifdef UNICODEUI
  257. //
  258. // Define structures to use depending on whether or not the RAS UI
  259. // is being built with Unicode.
  260. //
  261. #define PUISTR CHAR*
  262. #define PUIRCS RASCONNSTATUSA*
  263. #define PUIRC RASCREDENTIALSA*
  264. RASCONNSTATUSW rcs;
  265. WCHAR* pszSwitch = StrDupWFromA(MXS_SWITCH_TXT);
  266. #else
  267. #define PUISTR CHAR*
  268. #define PUIRCS RASCONNSTATUSA*
  269. #define PUIRC RASCREDENTIALSA*
  270. RASCONNSTATUSA rcs;
  271. CHAR* pszSwitch = szSwitch;
  272. #endif
  273. RASSCRPT_TRACE_INIT("RASSCRPT");
  274. RASSCRPT_TRACE("RasScriptInit");
  275. //
  276. // validate arguments
  277. //
  278. if (phscript) { *phscript = NULL; }
  279. if (!hrasconn ||
  280. !pEntry ||
  281. !pszUserName ||
  282. !pszPassword ||
  283. !hNotifier ||
  284. !phscript) {
  285. RASSCRPT_TRACE("RasScriptInit: required parameter not specified");
  286. #ifdef UNICODEUI
  287. Free(pszSwitch);
  288. #endif
  289. return ERROR_INVALID_PARAMETER;
  290. }
  291. //
  292. // initialize script processing
  293. //
  294. do {
  295. DWORD dwsize;
  296. DWORD dwthread;
  297. HANDLE hthread;
  298. //
  299. // Load required DLL function pointers.
  300. //
  301. dwErr = LoadRasapi32Dll();
  302. if (dwErr)
  303. break;
  304. dwErr = LoadRasmanDll();
  305. if (dwErr)
  306. break;
  307. //
  308. // Initialize RAS
  309. //
  310. dwErr = g_pRasInitialize();
  311. if ( dwErr )
  312. break;
  313. /*
  314. //
  315. // Connect to the local rasman server
  316. //
  317. dwErr = g_pRasRpcConnect ( NULL, NULL );
  318. if (dwErr)
  319. break; */
  320. //
  321. // allocate space for a control block
  322. //
  323. pscript = Malloc(sizeof(*pscript));
  324. if (!pscript) {
  325. dwErr = GetLastError();
  326. RASSCRPT_TRACE2("error %d allocating %d bytes", dwErr, sizeof(*pscript));
  327. break;
  328. }
  329. //
  330. // initialize the control block
  331. //
  332. ZeroMemory(pscript, sizeof(*pscript));
  333. //
  334. // copy the argument fields
  335. //
  336. pscript->hrasconn = hrasconn;
  337. pscript->pEntry = pEntry;
  338. pscript->dwFlags = dwFlags;
  339. pscript->hNotifier = hNotifier;
  340. pscript->hport = g_pRasGetHport(hrasconn);
  341. if (pscript->pEntry->pszIpAddress) {
  342. //
  343. // Copy the IP address for the entry
  344. //
  345. pscript->pszIpAddress =
  346. Malloc(lstrlenUI(pscript->pEntry->pszIpAddress) + 1);
  347. if (pscript->pszIpAddress) {
  348. StrCpyAFromUI(
  349. pscript->pszIpAddress, pscript->pEntry->pszIpAddress
  350. );
  351. }
  352. else {
  353. RASSCRPT_TRACE("error copying entry's IP address");
  354. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  355. break;
  356. }
  357. }
  358. //
  359. // Initialize our Win9x-compatible session-config-info structure
  360. //
  361. ZeroMemory(&pscript->sci, sizeof(pscript->sci));
  362. pscript->sci.dwSize = sizeof(pscript->sci);
  363. StrCpyAFromUI(pscript->sci.szEntryName, pEntry->pszEntryName);
  364. lstrcpy(pscript->sci.szUserName, pszUserName);
  365. lstrcpy(pscript->sci.szPassword, pszPassword);
  366. //
  367. // See if the user name is missing;
  368. // if so, read the currently-logged on user's name
  369. //
  370. if (!pscript->sci.szUserName[0]) {
  371. WKSTA_USER_INFO_1* pwkui1 = NULL;
  372. //
  373. // Not all params were specified, so read the dial-params
  374. // for this phonebook entry
  375. //
  376. dwErr = NetWkstaUserGetInfo(NULL, 1, (LPBYTE*)&pwkui1);
  377. RASSCRPT_TRACE2("NetWkstaUserGetInfo(e=%d,u=(%ls))", dwErr,
  378. (pwkui1) ? pwkui1->wkui1_username : L"null");
  379. if (dwErr == NO_ERROR && pwkui1 != NULL) {
  380. StrCpyAFromUI(pscript->sci.szUserName,
  381. (LPCWSTR)pwkui1->wkui1_username);
  382. NetApiBufferFree(pwkui1);
  383. }
  384. }
  385. //
  386. // See if there is a script for this connection's state;
  387. // if there is one then the device-type will be "switch"
  388. // and the device-name will be the script path
  389. //
  390. ZeroMemory(&rcs, sizeof(rcs));
  391. rcs.dwSize = sizeof(rcs);
  392. dwErr = g_pRasGetConnectStatus(hrasconn, (PUIRCS)&rcs);
  393. if (dwErr != NO_ERROR) {
  394. RASSCRPT_TRACE1("error %d getting connect status", dwErr);
  395. break;
  396. }
  397. //
  398. // Check the device-type (will be "switch" for scripted entries)
  399. // and the device name (will be a filename for scripted entries)
  400. //
  401. if (lstrcmpiUI(rcs.szDeviceType, pszSwitch) == 0 &&
  402. GetFileAttributesUI(rcs.szDeviceName) != 0xFFFFFFFF) {
  403. CHAR szDevice[RAS_MaxDeviceName + 1], *pszDevice = szDevice;
  404. StrCpyAFromUI(szDevice, rcs.szDeviceName);
  405. //
  406. // The device-type is "Switch" and the device-name
  407. // contains the name of an existing file;
  408. // initialize the SCRIPTDATA structure.
  409. //
  410. dwErr = RsInitData(pscript, pszDevice);
  411. //
  412. // If there was a syntax error in the script, we continue
  413. // with the initialization, but record the error code.
  414. // on any other error, we immediately terminate initialization.
  415. //
  416. if (dwErr == ERROR_SCRIPT_SYNTAX) {
  417. dwSyntaxError = dwErr;
  418. }
  419. else
  420. if (dwErr != NO_ERROR) { break; }
  421. }
  422. //
  423. // Initialize RASMAN fields, allocating buffers for RASMAN I/O
  424. //
  425. dwsize = SIZE_RecvBuffer;
  426. dwErr = g_pRasGetBuffer(&pscript->pRecvBuffer, &dwsize);
  427. RASSCRPT_TRACE2("RasGetBuffer:e=%d,s=%d", dwErr, dwsize);
  428. if (dwErr != NO_ERROR) {
  429. RASSCRPT_TRACE1("error %d allocating receive-buffer", dwErr);
  430. break;
  431. }
  432. dwsize = SIZE_SendBuffer;
  433. dwErr = g_pRasGetBuffer(&pscript->pSendBuffer, &dwsize);
  434. RASSCRPT_TRACE2("RasGetBuffer:e=%d,s=%d", dwErr, dwsize);
  435. if (dwErr != NO_ERROR) {
  436. RASSCRPT_TRACE1("error %d alloacting send-buffer", dwErr);
  437. break;
  438. }
  439. //
  440. // Create synchronization events used to control the background thread
  441. //
  442. pscript->hRecvRequest = CreateEvent(NULL, FALSE, FALSE, NULL);
  443. if (!pscript->hRecvRequest) {
  444. RASSCRPT_TRACE1("error %d creating receive-event", dwErr = GetLastError());
  445. break;
  446. }
  447. pscript->hRecvComplete = CreateEvent(NULL, FALSE, FALSE, NULL);
  448. if (!pscript->hRecvComplete) {
  449. RASSCRPT_TRACE1("error %d creating received-event", dwErr = GetLastError());
  450. break;
  451. }
  452. pscript->hStopRequest = CreateEvent(NULL, FALSE, FALSE, NULL);
  453. if (!pscript->hStopRequest) {
  454. RASSCRPT_TRACE1("error %d creating stop-event", dwErr = GetLastError());
  455. break;
  456. }
  457. pscript->hStopComplete = CreateEvent(NULL, FALSE, FALSE, NULL);
  458. if (!pscript->hStopComplete) {
  459. RASSCRPT_TRACE1("error %d creating stopped-event", dwErr = GetLastError());
  460. break;
  461. }
  462. //
  463. // Create the thread which will receive data and process the script
  464. //
  465. hthread = CreateThread(
  466. NULL, 0, RsThread, (PVOID)pscript, 0, &dwthread
  467. );
  468. if (!hthread) {
  469. RASSCRPT_TRACE1("error %d creating script-thread", dwErr = GetLastError());
  470. break;
  471. }
  472. CloseHandle(hthread);
  473. pscript->dwFlags |= RASSCRIPT_ThreadCreated;
  474. if ((VOID*)pszSwitch != (VOID*)szSwitch) { Free0(pszSwitch); }
  475. //
  476. // we've successfully initialized, return control to caller
  477. //
  478. *phscript = (HANDLE)pscript;
  479. //
  480. // if there was a syntax error in the script, return the special
  481. // error code (ERROR_SCRIPT_SYNTAX) to indicate the problem;
  482. // otherwise return NO_ERROR.
  483. //
  484. return (dwSyntaxError ? dwSyntaxError : NO_ERROR);
  485. } while(FALSE);
  486. //
  487. // an error occurred, so do cleanup
  488. //
  489. if ((VOID*)pszSwitch != (VOID*)szSwitch) { Free0(pszSwitch); }
  490. RasScriptTerm((HANDLE)pscript);
  491. return (dwErr ? dwErr : ERROR_UNKNOWN);
  492. }
  493. //----------------------------------------------------------------------------
  494. // Function: RasScriptReceive
  495. //
  496. // Called to retrieve the contents of the scripting thread's input buffer.
  497. // When this function completes successfully, if the input buffer was full
  498. // and the scripting thread was blocked, the thread continues executing.
  499. //
  500. // On input, "PdwBufferSize" should contain the size of "PBuffer", unless
  501. // "PBuffer" is NULL, in which case "*PdwBufferSize" is treated as 0.
  502. // On output, "PdwBufferSize" contains the size required to read
  503. // the input buffer, and if the return value is NO_ERROR, then "PBuffer"
  504. // contains the data in the input buffer. If the return value is
  505. // ERROR_INSUFFICIENT_BUFFER, "PBuffer" was not large enough.
  506. //----------------------------------------------------------------------------
  507. DWORD
  508. APIENTRY
  509. RasScriptReceive(
  510. IN HANDLE hscript,
  511. IN BYTE* pBuffer,
  512. IN OUT DWORD* pdwBufferSize
  513. ) {
  514. SCRIPTCB* pscript = (SCRIPTCB *)hscript;
  515. RASSCRPT_TRACE("RasScriptReceive");
  516. //
  517. // return if the caller didn't request input-notification
  518. // or if no buffer-size is available
  519. //
  520. if (!pscript || !pdwBufferSize ||
  521. !(pscript->dwFlags & RASSCRIPT_NotifyOnInput)) {
  522. return ERROR_INVALID_PARAMETER;
  523. }
  524. //
  525. // return if no buffer or if buffer too small
  526. //
  527. if (!pBuffer || *pdwBufferSize < pscript->dwRecvSize) {
  528. *pdwBufferSize = pscript->dwRecvSize;
  529. return ERROR_INSUFFICIENT_BUFFER;
  530. }
  531. //
  532. // copy the data, and notify the thread that the data has been read
  533. //
  534. CopyMemory(pBuffer, pscript->pRecvBuffer, pscript->dwRecvSize);
  535. *pdwBufferSize = pscript->dwRecvSize;
  536. SetEvent(pscript->hRecvComplete);
  537. return NO_ERROR;
  538. }
  539. //----------------------------------------------------------------------------
  540. // Function: RasScriptSend
  541. //
  542. // This function transmits bytes over the connection's port.
  543. //
  544. // "DwBufferSize" contains the number of bytes to insert from "PBuffer"
  545. //----------------------------------------------------------------------------
  546. DWORD
  547. APIENTRY
  548. RasScriptSend(
  549. IN HANDLE hscript,
  550. IN BYTE* pBuffer,
  551. IN DWORD dwBufferSize
  552. ) {
  553. DWORD dwsize;
  554. DWORD dwErr;
  555. SCRIPTCB *pscript = (SCRIPTCB *)hscript;
  556. RASSCRPT_TRACE("RasScriptSend");
  557. if (!pscript || !pBuffer || !dwBufferSize) {
  558. return ERROR_INVALID_PARAMETER;
  559. }
  560. //
  561. // send all the data in the buffer
  562. //
  563. for (dwsize = min(dwBufferSize, SIZE_SendBuffer);
  564. dwBufferSize;
  565. dwBufferSize -= dwsize, pBuffer += dwsize,
  566. dwsize = min(dwBufferSize, SIZE_SendBuffer)) {
  567. CopyMemory(pscript->pSendBuffer, pBuffer, dwsize);
  568. dwErr = g_pRasPortSend(
  569. pscript->hport, pscript->pSendBuffer, dwsize
  570. );
  571. RASSCRPT_TRACE1("g_pRasPortSend=%d", dwErr);
  572. DUMPB(pBuffer, dwsize);
  573. }
  574. return NO_ERROR;
  575. }
  576. //----------------------------------------------------------------------------
  577. // Function: RasScriptTerm
  578. //
  579. // This function terminates script processing, stopping the scripting thread.
  580. // The return code is the code from processing the script, and it may be
  581. //
  582. // NO_ERROR: the script had finished running, or the connection
  583. // had no script and the scripting thread was acting
  584. // in simple I/O mode.
  585. // ERROR_MORE_DATA: the script was still running.
  586. //----------------------------------------------------------------------------
  587. DWORD
  588. APIENTRY
  589. RasScriptTerm(
  590. IN HANDLE hscript
  591. ) {
  592. SCRIPTCB* pscript = hscript;
  593. RASSCRPT_TRACE("RasScriptTerm");
  594. if (!pscript) { return ERROR_INVALID_PARAMETER; }
  595. //
  596. // stop the thread if it is running
  597. //
  598. if (pscript->dwFlags & RASSCRIPT_ThreadCreated) {
  599. SetEvent(pscript->hStopRequest);
  600. WaitForSingleObject(pscript->hStopComplete, INFINITE);
  601. }
  602. if (pscript->pdata) { RsDestroyData(pscript); }
  603. if (pscript->hStopRequest) { CloseHandle(pscript->hStopRequest); }
  604. if (pscript->hStopComplete) { CloseHandle(pscript->hStopComplete); }
  605. if (pscript->hRecvRequest) { CloseHandle(pscript->hRecvRequest); }
  606. if (pscript->hRecvComplete) { CloseHandle(pscript->hRecvComplete); }
  607. if (pscript->pRecvBuffer) { g_pRasFreeBuffer(pscript->pRecvBuffer); }
  608. if (pscript->pSendBuffer) { g_pRasFreeBuffer(pscript->pSendBuffer); }
  609. Free0(pscript->pszIpAddress);
  610. Free(pscript);
  611. RASSCRPT_TRACE_TERM();
  612. return NO_ERROR;
  613. }
  614. //----------------------------------------------------------------------------
  615. // Function: RsDestroyData
  616. //
  617. // This function destroys the SCRIPTDATA portion of a SCRIPTCB.
  618. //----------------------------------------------------------------------------
  619. DWORD
  620. RsDestroyData(
  621. IN SCRIPTCB* pscript
  622. ) {
  623. SCRIPTDATA* pdata = pscript->pdata;
  624. if (!pdata) { return ERROR_INVALID_PARAMETER; }
  625. if (pdata->pmoduledecl) { Decl_Delete((PDECL)pdata->pmoduledecl); }
  626. if (pdata->pastexec) {
  627. Astexec_Destroy(pdata->pastexec); Free(pdata->pastexec);
  628. }
  629. //
  630. // .Net bug# 522307 Specifying the dialup script file as the COM
  631. // Port of the Modem will cause explorer to AV.
  632. //
  633. if (pdata->pscanner)
  634. {
  635. Scanner_Destroy(pdata->pscanner);
  636. pdata->pscanner = NULL;
  637. }
  638. return NO_ERROR;
  639. }
  640. //----------------------------------------------------------------------------
  641. // Function: RsInitData
  642. //
  643. // This function initializes the SCRIPTDATA portion of a SCRIPTCB,
  644. // preparing for script-processing.
  645. //----------------------------------------------------------------------------
  646. DWORD
  647. RsInitData(
  648. IN SCRIPTCB* pscript,
  649. IN LPCSTR pszScriptPath
  650. ) {
  651. RES res;
  652. DWORD dwErr = ERROR_SUCCESS;
  653. SCRIPTDATA *pdata;
  654. RASSCRPT_TRACE("RsInitData");
  655. do {
  656. //
  657. // allocate space for the SCRIPTDATA;
  658. //
  659. pscript->pdata = pdata = Malloc(sizeof(*pdata));
  660. if (!pdata) {
  661. RASSCRPT_TRACE1("error %d allocating SCRIPTDATA", dwErr = GetLastError());
  662. break;
  663. }
  664. //
  665. // initialize the structure
  666. //
  667. ZeroMemory(pdata, sizeof(*pdata));
  668. pdata->hscript = (HANDLE)pscript;
  669. lstrcpy(pdata->script.szPath, pszScriptPath);
  670. //
  671. // create a scanner and use it to open the script
  672. //
  673. res = Scanner_Create(&pdata->pscanner, &pscript->sci);
  674. if (RFAILED(res)) {
  675. RASSCRPT_TRACE1("failure %d creating scanner", res);
  676. break;
  677. }
  678. res = Scanner_OpenScript(pdata->pscanner, pszScriptPath);
  679. if (res == RES_E_FAIL || RFAILED(res)) {
  680. RASSCRPT_TRACE1("failure %d opening script", res);
  681. //
  682. // .Net bug# 522307 Specifying the dialup script file as the COM
  683. // Port of the Modem will cause explorer to AV.
  684. //
  685. dwErr = ERROR_SCRIPT_SYNTAX;
  686. break;
  687. }
  688. //
  689. // allocate a script-execution handler
  690. //
  691. pdata->pastexec = Malloc(sizeof(*pdata->pastexec));
  692. if (!pdata->pastexec) {
  693. RASSCRPT_TRACE1("error %d allocating ASTEXEC", dwErr = GetLastError());
  694. break;
  695. }
  696. ZeroMemory(pdata->pastexec, sizeof(*pdata->pastexec));
  697. //
  698. // initialize the script-execution handler
  699. //
  700. res = Astexec_Init(
  701. pdata->pastexec, pscript, &pscript->sci,
  702. Scanner_GetStxerrHandle(pdata->pscanner)
  703. );
  704. if (!RSUCCEEDED(res)) {
  705. RASSCRPT_TRACE1("failure %d initializing ASTEXEC", res);
  706. break;
  707. }
  708. Astexec_SetHwnd(pdata->pastexec, (HWND)pdata);
  709. //
  710. // parse the script using the created scanner
  711. // and writing into the execution-handler's symbol-table
  712. //
  713. res = ModuleDecl_Parse(
  714. &pdata->pmoduledecl, pdata->pscanner,
  715. pdata->pastexec->pstSystem
  716. );
  717. if (RSUCCEEDED(res)) {
  718. //
  719. // generate code for the script
  720. //
  721. res = ModuleDecl_Codegen(pdata->pmoduledecl, pdata->pastexec);
  722. }
  723. //
  724. // see if anything went wrong
  725. //
  726. if (RFAILED(res)) {
  727. //
  728. // there was an error parsing the script.
  729. // we return the special error code ERROR_SCRIPT_SYNTAX
  730. // and log the errors to a file.
  731. //
  732. // This is not necessarily a fatal error, and so returning
  733. // the above error doesn't cause script-initialization to fail,
  734. // since if the user is in interactive mode, the connection
  735. // may be completed manually by typing into the terminal window.
  736. //
  737. // If we are not in interactive mode, this is a fatal error,
  738. // and RasScriptExecute handles the condition correctly
  739. // by terminating the script immediately
  740. //
  741. RASSCRPT_TRACE1("failure %d parsing script", res);
  742. RxLogErrors(
  743. (HANDLE)pscript, (VOID*)Scanner_GetStxerrHandle(pdata->pscanner)
  744. );
  745. Decl_Delete((PDECL)pdata->pmoduledecl);
  746. Astexec_Destroy(pdata->pastexec); Free(pdata->pastexec);
  747. Scanner_Destroy(pdata->pscanner);
  748. //
  749. // .Net bug# 522307 Specifying the dialup script file as the COM
  750. // Port of the Modem will cause explorer to AV.
  751. //
  752. pdata->pscanner = NULL;
  753. pscript->pdata = NULL;
  754. dwErr = ERROR_SCRIPT_SYNTAX;
  755. return dwErr;
  756. }
  757. //
  758. // all went well, return
  759. //
  760. return NO_ERROR;
  761. } while(FALSE);
  762. //
  763. // an error occurred, so do cleanup
  764. //
  765. if (pscript->pdata) { RsDestroyData(pscript); }
  766. return (dwErr ? dwErr : ERROR_UNKNOWN);
  767. }
  768. //----------------------------------------------------------------------------
  769. // Function: RsPostReceive
  770. //
  771. // Internal function:
  772. // posts receive-request to RASMAN
  773. //----------------------------------------------------------------------------
  774. DWORD
  775. RsPostReceive(
  776. IN SCRIPTCB* pscript
  777. ) {
  778. DWORD dwSize;
  779. DWORD dwErr;
  780. RASSCRPT_TRACE("RsPostReceive");
  781. dwSize = SIZE_RecvBuffer;
  782. dwErr = g_pRasPortReceive(
  783. pscript->hport, pscript->pRecvBuffer, &dwSize, SECS_RecvTimeout,
  784. pscript->hRecvRequest
  785. );
  786. RASSCRPT_TRACE2("RsPostReceive=%d,%d", dwErr, dwSize);
  787. return dwErr;
  788. }
  789. BOOL
  790. IsRasmanProcess()
  791. {
  792. CHAR *pszCmdLine = NULL;
  793. BOOL fRet = FALSE;
  794. pszCmdLine = GetCommandLineA();
  795. if( (NULL != pszCmdLine)
  796. && (strstr(pszCmdLine, NET_SVCS_GROUP)))
  797. {
  798. fRet = TRUE;
  799. }
  800. return fRet;
  801. }
  802. DWORD
  803. RsPostReceiveEx(
  804. IN SCRIPTCB* pscript
  805. ) {
  806. DWORD dwSize = 0;
  807. DWORD dwErr = ERROR_SUCCESS;
  808. RASSCRPT_TRACE("RsPostReceiveEx");
  809. if(IsRasmanProcess())
  810. {
  811. goto done;
  812. }
  813. RASSCRPT_TRACE("Calling RsPostReceiveEx");
  814. dwSize = SIZE_RecvBuffer;
  815. dwErr = g_pRasPortReceiveEx(
  816. pscript->hport,
  817. pscript->pRecvBuffer,
  818. &dwSize
  819. );
  820. done:
  821. RASSCRPT_TRACE2("RsPostReceiveEx=%d, %d",dwErr, dwSize );
  822. return dwErr;
  823. }
  824. //----------------------------------------------------------------------------
  825. // Function: RsSignal
  826. //
  827. // Internal function:
  828. // this is called to signal the notifier for a script, which may involve
  829. // setting an event or sending a message.
  830. //----------------------------------------------------------------------------
  831. VOID
  832. RsSignal(
  833. IN SCRIPTCB* pscript,
  834. IN DWORD dwEventCode
  835. ) {
  836. RASSCRPT_TRACE1("RsSignal: %d", dwEventCode);
  837. InterlockedExchange(&pscript->dwEventCode, dwEventCode);
  838. if (pscript->dwFlags & RASSCRIPT_HwndNotify) {
  839. SendNotifyMessage(
  840. (HWND)pscript->hNotifier, WM_RASAPICOMPLETE, 0, dwEventCode
  841. );
  842. }
  843. else {
  844. SetEvent(pscript->hNotifier);
  845. }
  846. }
  847. //----------------------------------------------------------------------------
  848. // Function: RsThread
  849. //
  850. // This function is the entry-point for the script processing thread.
  851. //
  852. // The scripting thread operates in a loop, posting receive requests
  853. // and receiving incoming data. If a script is associated with the port,
  854. // the thread also runs the script.
  855. //----------------------------------------------------------------------------
  856. DWORD
  857. RsThread(
  858. IN PVOID pParam
  859. ) {
  860. WORD wSize;
  861. #define POS_STOP 0
  862. #define POS_RECV 1
  863. #define POS_LAST 2
  864. BOOL bFirstRecv = TRUE;
  865. HANDLE hEvents[POS_LAST];
  866. SCRIPTCB* pscript = (SCRIPTCB *)pParam;
  867. SCRIPTDATA* pdata = pscript->pdata;
  868. DWORD dwErr, dwTicksBefore, dwTicksAfter, dwTicksElapsed;
  869. RASSCRPT_TRACE("RsThread");
  870. //
  871. // post receive-request to RASMAN
  872. //
  873. dwErr = RsPostReceive(pscript);
  874. if (dwErr != NO_ERROR && dwErr != PENDING) {
  875. RASSCRPT_TRACE1("error %d posting receive to RASMAN", dwErr);
  876. RsPostReceiveEx ( pscript );
  877. RsSignal(pscript, SCRIPTCODE_Halted);
  878. SetEvent(pscript->hStopComplete);
  879. return dwErr;
  880. }
  881. //
  882. // set up event array; we place the stop-request event first
  883. // in the array since the receive-event will be signalled more often
  884. // and placing it first might result in starvation
  885. // (waits are always satisfied by the first signalled object)
  886. //
  887. hEvents[POS_STOP] = pscript->hStopRequest;
  888. hEvents[POS_RECV] = pscript->hRecvRequest;
  889. if (pdata) { pdata->dwTimeout = INFINITE; }
  890. while (TRUE) {
  891. //
  892. // wait for receive to complete, for stop signal,
  893. // or for timeout to expire
  894. //
  895. // save the tick count so we can tell how long the wait lasted
  896. //
  897. dwTicksBefore = GetTickCount();
  898. dwErr = WaitForMultipleObjects(
  899. POS_LAST, hEvents, FALSE, pdata ? pdata->dwTimeout:INFINITE
  900. );
  901. dwTicksAfter = GetTickCount();
  902. //
  903. // see if the tick count wrapped around, and if so
  904. // adjust so we always get the correct elapsed time
  905. // from the expression (dwTicksAfter - dwTicksBefore)
  906. //
  907. if (dwTicksAfter < dwTicksBefore) {
  908. dwTicksAfter += MAXDWORD - dwTicksBefore;
  909. dwTicksBefore = 0;
  910. }
  911. dwTicksElapsed = dwTicksAfter - dwTicksBefore;
  912. RASSCRPT_TRACE1("RsThread: waited for %d milliseconds", dwTicksElapsed);
  913. //
  914. // if the timeout isn't INFINITE, decrement it by
  915. // the amount of time we've already waited
  916. //
  917. if (pdata && pdata->dwTimeout != INFINITE) {
  918. if (dwTicksElapsed >= pdata->dwTimeout) {
  919. pdata->dwTimeout = INFINITE;
  920. }
  921. else {
  922. pdata->dwTimeout -= dwTicksElapsed;
  923. }
  924. }
  925. //
  926. // Handle the return-code from WaitForMultipleObjects
  927. //
  928. if (dwErr == (WAIT_OBJECT_0 + POS_STOP)) {
  929. //
  930. // stop-request signalled, break
  931. //
  932. RASSCRPT_TRACE("RsThread: stop event signalled");
  933. RsSignal(pscript, SCRIPTCODE_Halted);
  934. break;
  935. }
  936. else
  937. if (dwErr == WAIT_TIMEOUT) {
  938. if (!pdata) { continue; }
  939. //
  940. // wait timed out, so that means we were blocked
  941. // on a "delay" or "waitfor ... until" statement;
  942. //
  943. Astexec_ClearPause(pdata->pastexec);
  944. //
  945. // if we blocked because of a "waitfor ... until",
  946. // finish processing the statement
  947. //
  948. if (Astexec_IsWaitUntil(pdata->pastexec)) {
  949. Astexec_SetStopWaiting(pdata->pastexec);
  950. Astexec_ClearWaitUntil(pdata->pastexec);
  951. }
  952. //
  953. // continue processing the script
  954. //
  955. if (RsThreadProcess(pscript) == ERROR_NO_MORE_ITEMS) {
  956. //
  957. // the script has stopped; if done, break;
  958. // otherwise, continue receiving data
  959. //
  960. if (pscript->dwEventCode == SCRIPTCODE_Done) {
  961. break;
  962. }
  963. else {
  964. //
  965. // Cleanup the script, but continue receiving data
  966. //
  967. RsDestroyData(pscript);
  968. pdata = pscript->pdata = NULL;
  969. }
  970. }
  971. }
  972. else
  973. if (dwErr == (WAIT_OBJECT_0 + POS_RECV)) {
  974. //
  975. // receive completed
  976. //
  977. RASMAN_INFO info;
  978. DWORD dwStart, dwRead;
  979. RASSCRPT_TRACE("RsThread: receive event signalled");
  980. //
  981. // Get the data received
  982. //
  983. dwErr = RsPostReceiveEx ( pscript );
  984. if ( NO_ERROR != dwErr
  985. && PENDING != dwErr )
  986. {
  987. RASSCRPT_TRACE1("error %d in RsPostReceiveEx", dwErr);
  988. RsSignal(pscript, SCRIPTCODE_Halted );
  989. break;
  990. }
  991. //
  992. // get the number of bytes received
  993. //
  994. dwErr = g_pRasGetInfo(NULL, pscript->hport, &info);
  995. if (dwErr != NO_ERROR) {
  996. RASSCRPT_TRACE1("error %d retrieving RASMAN_INFO", dwErr);
  997. RsSignal(pscript, SCRIPTCODE_Halted);
  998. break;
  999. }
  1000. if( (info.RI_LastError != NO_ERROR)
  1001. && (info.RI_ConnState != CONNECTING))
  1002. {
  1003. RASSCRPT_TRACE("Link dropped! port no longer in connecting state");
  1004. RsSignal(pscript, SCRIPTCODE_Halted);
  1005. break;
  1006. }
  1007. if (info.RI_LastError != NO_ERROR) {
  1008. RASSCRPT_TRACE1("last error: %d", info.RI_LastError);
  1009. continue;
  1010. }
  1011. RASSCRPT_TRACE1("RsThread: received %d bytes", info.RI_BytesReceived);
  1012. //
  1013. // on the first receive, we proceed even if there aren't any
  1014. // characters read, since we need to run the first script commands
  1015. //
  1016. if (!bFirstRecv && info.RI_BytesReceived == 0) {
  1017. //
  1018. // something went wrong, post another receive request
  1019. //
  1020. dwErr = RsPostReceive(pscript);
  1021. if ( dwErr != NO_ERROR
  1022. && dwErr != PENDING)
  1023. {
  1024. RASSCRPT_TRACE1("error %d in RsPostReceive", dwErr);
  1025. RsSignal(pscript, SCRIPTCODE_Halted);
  1026. break;
  1027. }
  1028. continue;
  1029. }
  1030. bFirstRecv = FALSE;
  1031. pscript->dwRecvSize = info.RI_BytesReceived;
  1032. pscript->dwRecvRead = 0;
  1033. DUMPB(pscript->pRecvBuffer, pscript->dwRecvSize);
  1034. //
  1035. // if the creator wants to know when data arrives,
  1036. // signal the creator's notification now;
  1037. // wait till the creator reads the data before proceeding
  1038. //
  1039. if (info.RI_BytesReceived &&
  1040. (pscript->dwFlags & RASSCRIPT_NotifyOnInput)) {
  1041. RsSignal(pscript, SCRIPTCODE_InputNotify);
  1042. WaitForSingleObject(pscript->hRecvComplete, INFINITE);
  1043. }
  1044. //
  1045. // if we have no script that's all we have to do,
  1046. // so just post another receive request and go back to waiting
  1047. //
  1048. if (!pdata) {
  1049. dwErr = RsPostReceive(pscript);
  1050. if ( dwErr != NO_ERROR
  1051. && dwErr != PENDING )
  1052. {
  1053. RASSCRPT_TRACE1("error %d in RsPostReceive",dwErr);
  1054. RsSignal(pscript, SCRIPTCODE_Halted);
  1055. break;
  1056. }
  1057. continue;
  1058. }
  1059. //
  1060. // read the data into the script's circular buffer
  1061. //
  1062. ReadIntoBuffer(pdata, &dwStart, &dwRead);
  1063. //
  1064. // do more script processing
  1065. //
  1066. if (RsThreadProcess(pscript) == ERROR_NO_MORE_ITEMS) {
  1067. //
  1068. // the script has stopped; if done, break;
  1069. // otherwise, continue receiving data
  1070. //
  1071. if (pscript->dwEventCode == SCRIPTCODE_Done) {
  1072. break;
  1073. }
  1074. else {
  1075. //
  1076. // Cleanup the script, but continue receiving data
  1077. //
  1078. RsDestroyData(pscript);
  1079. pdata = pscript->pdata = NULL;
  1080. }
  1081. }
  1082. }
  1083. }
  1084. //
  1085. // cancel any pending receives
  1086. //
  1087. g_pRasPortCancelReceive(pscript->hport);
  1088. SetEvent(pscript->hStopComplete);
  1089. RASSCRPT_TRACE("RsThread done");
  1090. return NO_ERROR;
  1091. }
  1092. //----------------------------------------------------------------------------
  1093. // Function: RsThreadProcess
  1094. //
  1095. // Called to process the script until it is blocked
  1096. // by a "waitfor" statement or a "delay" statement.
  1097. //----------------------------------------------------------------------------
  1098. DWORD
  1099. RsThreadProcess(
  1100. IN SCRIPTCB* pscript
  1101. ) {
  1102. RES res;
  1103. DWORD dwErr;
  1104. SCRIPTDATA *pdata = pscript->pdata;
  1105. RASSCRPT_TRACE("RsThreadProcess");
  1106. //
  1107. // now step through the script until we are blocked
  1108. // by a "delay" statement or a "waitfor" statement
  1109. //
  1110. dwErr = NO_ERROR;
  1111. do {
  1112. //
  1113. // break if its time to stop
  1114. //
  1115. if (WaitForSingleObject(pscript->hStopRequest, 0) == WAIT_OBJECT_0) {
  1116. SetEvent(pscript->hStopRequest);
  1117. break;
  1118. }
  1119. //
  1120. // process next command
  1121. //
  1122. // .Net bug# 525233 SECURITY: Specifying the dialup script file as the
  1123. // COM Port of the Modem and having show terminal window enabled will
  1124. // cause explorer to AV
  1125. //
  1126. if (!pdata->pastexec)
  1127. {
  1128. dwErr = ERROR_NO_MORE_ITEMS;
  1129. break;
  1130. }
  1131. res = Astexec_Next(pdata->pastexec);
  1132. //
  1133. // examine the resulting state
  1134. //
  1135. if (Astexec_IsDone(pdata->pastexec) ||
  1136. Astexec_IsHalted(pdata->pastexec)) {
  1137. //
  1138. // the script has come to an end, so set our stop event
  1139. // and break out of this loop
  1140. //
  1141. RASSCRPT_TRACE("RsThreadProcess: script completed");
  1142. //
  1143. // do stop-completion notification
  1144. //
  1145. if (Astexec_IsDone(pdata->pastexec)) {
  1146. RsSignal(pscript, SCRIPTCODE_Done);
  1147. }
  1148. else
  1149. if (!RFAILED(res)) {
  1150. RsSignal(pscript, SCRIPTCODE_Halted);
  1151. }
  1152. else {
  1153. RsSignal(pscript, SCRIPTCODE_HaltedOnError);
  1154. }
  1155. dwErr = ERROR_NO_MORE_ITEMS;
  1156. break;
  1157. }
  1158. else
  1159. if (Astexec_IsReadPending(pdata->pastexec)) {
  1160. //
  1161. // we're blocked waiting for input,
  1162. // so post another receive request and go back
  1163. // to waiting for data;
  1164. // if we're blocked on a "waitfor ... until"
  1165. // then the timeout will be in pdata->dwTimeout,
  1166. // otherwise pdata->dwTimeout will be INFINITE
  1167. // which is exactly how long we'll be waiting
  1168. //
  1169. RsPostReceive(pscript);
  1170. RASSCRPT_TRACE("RsThreadProcess: script waiting for input");
  1171. break;
  1172. }
  1173. else
  1174. if (Astexec_IsPaused(pdata->pastexec)) {
  1175. //
  1176. // we're blocked with a timeout, so pick up
  1177. // the timeout value from pdata->dwTimeout.
  1178. // we don't want to listen for input
  1179. // while we're blocked, so we don't post another receive-request
  1180. //
  1181. RASSCRPT_TRACE("RsThreadProcess: script paused");
  1182. break;
  1183. }
  1184. } while (TRUE);
  1185. return dwErr;
  1186. }
  1187. //----------------------------------------------------------------------------
  1188. // Function: RxLogErrors
  1189. //
  1190. // Logs script syntax errors to a file named %windir%\system32\ras\script.log
  1191. //----------------------------------------------------------------------------
  1192. DWORD
  1193. RxLogErrors(
  1194. IN HANDLE hscript,
  1195. IN HSA hsaStxerr
  1196. ) {
  1197. HANDLE hfile;
  1198. CHAR *pszPath;
  1199. STXERR stxerr;
  1200. SCRIPTDATA *pdata;
  1201. SCRIPTCB *pscript = hscript;
  1202. DWORD i, cel, dwErr, dwSize;
  1203. RASSCRPT_TRACE("RxLogErrors");
  1204. if (!pscript || !pscript->pdata) { return ERROR_INVALID_PARAMETER; }
  1205. pdata = pscript->pdata;
  1206. //
  1207. // get the pathname for the logfile
  1208. //
  1209. dwSize = ExpandEnvironmentStrings(c_szScriptLog, NULL, 0);
  1210. pszPath = Malloc((dwSize + 1) * sizeof(CHAR));
  1211. if (!pszPath) { return ERROR_NOT_ENOUGH_MEMORY; }
  1212. ExpandEnvironmentStrings(c_szScriptLog, pszPath, dwSize);
  1213. //
  1214. // create the file, overwriting it if it already exists
  1215. //
  1216. hfile = CreateFile(
  1217. pszPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
  1218. FILE_ATTRIBUTE_NORMAL, NULL
  1219. );
  1220. Free(pszPath);
  1221. if (INVALID_HANDLE_VALUE == hfile) {
  1222. dwErr = GetLastError();
  1223. RASSCRPT_TRACE1("error %d creating logfile", dwErr);
  1224. return dwErr;
  1225. }
  1226. //
  1227. // truncate the previous contents of the file, if any
  1228. //
  1229. SetFilePointer(hfile, 0, 0, FILE_BEGIN);
  1230. SetEndOfFile(hfile);
  1231. //
  1232. // get the number of syntax errors
  1233. //
  1234. cel = SAGetCount(hsaStxerr);
  1235. //
  1236. // append each error to the file
  1237. //
  1238. for (i = 0; i < cel; i++) {
  1239. UINT ids;
  1240. CHAR* pszErr;
  1241. BOOL bRet = SAGetItem(hsaStxerr, i, &stxerr);
  1242. if (!bRet) { continue; }
  1243. ids = IdsFromRes(Stxerr_GetRes(&stxerr));
  1244. if (ids == 0) { continue; }
  1245. //
  1246. // format the error message
  1247. //
  1248. ConstructMessage(
  1249. &pszErr, g_hinst, MAKEINTRESOURCE(ids), pdata->script.szPath,
  1250. Stxerr_GetLine(&stxerr), Stxerr_GetLexeme(&stxerr)
  1251. );
  1252. if (!pszErr) { continue; }
  1253. //
  1254. // write the message to the log file
  1255. //
  1256. dwSize = lstrlen(pszErr);
  1257. WriteFile(hfile, pszErr, lstrlen(pszErr), &dwSize, NULL);
  1258. WriteFile(hfile, "\r\n", 2, &dwSize, NULL);
  1259. //
  1260. // free the message pointer
  1261. //
  1262. GFree(pszErr);
  1263. }
  1264. CloseHandle(hfile);
  1265. return 0;
  1266. }
  1267. //----------------------------------------------------------------------------
  1268. // Function: RxReadFile
  1269. //
  1270. // Transfers data out of a RASMAN buffer into the circular buffer used
  1271. // by the Win9x scripting code
  1272. //----------------------------------------------------------------------------
  1273. BOOL
  1274. RxReadFile(
  1275. IN HANDLE hscript,
  1276. IN BYTE* pBuffer,
  1277. IN DWORD dwBufferSize,
  1278. OUT DWORD* pdwBytesRead
  1279. ) {
  1280. SCRIPTCB* pscript = (SCRIPTCB*)hscript;
  1281. DWORD dwRecvSize = pscript->dwRecvSize - pscript->dwRecvRead;
  1282. RASSCRPT_TRACE("RxReadFile");
  1283. if (!pdwBytesRead) { return FALSE; }
  1284. *pdwBytesRead = 0;
  1285. if ((INT)dwRecvSize <= 0) { return FALSE; }
  1286. if (!dwBufferSize) { return FALSE; }
  1287. *pdwBytesRead = min(dwBufferSize, dwRecvSize);
  1288. CopyMemory(
  1289. pBuffer, pscript->pRecvBuffer + pscript->dwRecvRead, *pdwBytesRead
  1290. );
  1291. pscript->dwRecvRead += *pdwBytesRead;
  1292. RASSCRPT_TRACE2("RxReadFile(rr=%d,br=%d)",pscript->dwRecvRead,*pdwBytesRead);
  1293. return TRUE;
  1294. }
  1295. //----------------------------------------------------------------------------
  1296. // Function: RxSetIPAddress
  1297. //
  1298. // Sets the IP address for the script's RAS entry
  1299. //----------------------------------------------------------------------------
  1300. DWORD
  1301. RxSetIPAddress(
  1302. IN HANDLE hscript,
  1303. IN LPCSTR lpszAddress
  1304. ) {
  1305. DWORD dwErr = NO_ERROR;
  1306. SCRIPTCB *pscript = (SCRIPTCB *)hscript;
  1307. RASSCRPT_TRACE1("RxSetIPAddress: %s", lpszAddress);
  1308. EnterCriticalSection(&g_cs);
  1309. //
  1310. // Free the existing IP address, if any
  1311. //
  1312. Free0(pscript->pszIpAddress);
  1313. //
  1314. // Allocate space for a copy of the address
  1315. //
  1316. pscript->pszIpAddress = Malloc(lstrlen(lpszAddress) + 1);
  1317. if (!pscript->pszIpAddress) { dwErr = ERROR_NOT_ENOUGH_MEMORY; }
  1318. else {
  1319. //
  1320. // Copy the new IP address
  1321. //
  1322. lstrcpy(pscript->pszIpAddress, lpszAddress);
  1323. }
  1324. LeaveCriticalSection(&g_cs);
  1325. //
  1326. // If successful, signal the caller that the IP address has changed
  1327. //
  1328. if (dwErr != NO_ERROR) {
  1329. RASSCRPT_TRACE1("error %d writing phonebook file", dwErr);
  1330. }
  1331. else {
  1332. if ( INVALID_HANDLE_VALUE != hIpAddressSet
  1333. && !(pscript->dwFlags & RASSCRIPT_HwndNotify))
  1334. {
  1335. DWORD dwEventCode = SCRIPTCODE_IpAddressSet;
  1336. RASSCRPT_TRACE1("RxSetIPAddress: %d", dwEventCode);
  1337. InterlockedExchange(&pscript->dwEventCode, dwEventCode);
  1338. SetEvent (hIpAddressSet);
  1339. }
  1340. else if (pscript->dwFlags & RASSCRIPT_HwndNotify)
  1341. RsSignal(pscript, SCRIPTCODE_IpAddressSet);
  1342. }
  1343. return dwErr;
  1344. }
  1345. //----------------------------------------------------------------------------
  1346. // Function: RxSetKeyboard
  1347. //
  1348. // Signals the script-owner to enable or disable keyboard input.
  1349. //----------------------------------------------------------------------------
  1350. DWORD
  1351. RxSetKeyboard(
  1352. IN HANDLE hscript,
  1353. IN BOOL bEnable
  1354. ) {
  1355. RASSCRPT_TRACE("RxSetKeyboard");
  1356. RsSignal(
  1357. (SCRIPTCB *)hscript,
  1358. bEnable ? SCRIPTCODE_KeyboardEnable : SCRIPTCODE_KeyboardDisable
  1359. );
  1360. return NO_ERROR;
  1361. }
  1362. //----------------------------------------------------------------------------
  1363. // Function: RxSendCreds
  1364. //
  1365. // Sends users password over the wire.
  1366. //----------------------------------------------------------------------------
  1367. DWORD
  1368. RxSendCreds(
  1369. IN HANDLE hscript,
  1370. IN CHAR controlchar
  1371. ) {
  1372. SCRIPTCB *pscript = (SCRIPTCB *) hscript;
  1373. DWORD dwErr;
  1374. RASSCRPT_TRACE("RasSendCreds");
  1375. dwErr = RasSendCreds(pscript->hport, controlchar);
  1376. RASSCRPT_TRACE1("RasSendCreds done. 0x%x", dwErr);
  1377. return (dwErr == NO_ERROR) ? RES_OK : RES_E_FAIL;
  1378. }
  1379. //----------------------------------------------------------------------------
  1380. // Function: RxSetPortData
  1381. //
  1382. // Changes settings for the COM port.
  1383. //----------------------------------------------------------------------------
  1384. DWORD
  1385. RxSetPortData(
  1386. IN HANDLE hscript,
  1387. IN VOID* pStatement
  1388. ) {
  1389. RES res;
  1390. STMT* pstmt;
  1391. RAS_PARAMS* pparam;
  1392. DWORD dwErr, dwFlags;
  1393. RASMAN_PORTINFO *prmpi;
  1394. SCRIPTCB *pscript = (SCRIPTCB *)hscript;
  1395. BYTE aBuffer[sizeof(RASMAN_PORTINFO) + sizeof(RAS_PARAMS) * 2];
  1396. RASSCRPT_TRACE("RxSetPortData");
  1397. //
  1398. // Retrieve the 'set port' statement
  1399. //
  1400. pstmt = (STMT*)pStatement;
  1401. dwFlags = SetPortStmt_GetFlags(pstmt);
  1402. //
  1403. // Set up the RASMAN_PORTINFO to be passed to RasPortSetInfo
  1404. //
  1405. prmpi = (RASMAN_PORTINFO*)aBuffer;
  1406. prmpi->PI_NumOfParams = 0;
  1407. pparam = prmpi->PI_Params;
  1408. //
  1409. // Collect the changes into the port-info structure
  1410. //
  1411. if (IsFlagSet(dwFlags, SPF_DATABITS)) {
  1412. lstrcpyA(pparam->P_Key, SER_DATABITS_KEY);
  1413. pparam->P_Type = Number;
  1414. pparam->P_Attributes = 0;
  1415. pparam->P_Value.Number = SetPortStmt_GetDatabits(pstmt);
  1416. RASSCRPT_TRACE1("GetDatabits==%d", pparam->P_Value.Number);
  1417. ++prmpi->PI_NumOfParams;
  1418. ++pparam;
  1419. }
  1420. if (IsFlagSet(dwFlags, SPF_STOPBITS)) {
  1421. lstrcpyA(pparam->P_Key, SER_STOPBITS_KEY);
  1422. pparam->P_Type = Number;
  1423. pparam->P_Attributes = 0;
  1424. pparam->P_Value.Number = SetPortStmt_GetStopbits(pstmt);
  1425. //
  1426. // The only 'stopbits' settings supported are 1 and 2;
  1427. // in order to set stopbits of 1, we need to pass 0
  1428. // to RasPortSetInfo, so the value is adjusted here.
  1429. //
  1430. if (pparam->P_Value.Number == 1) { --pparam->P_Value.Number; }
  1431. RASSCRPT_TRACE1("GetStopbits==%d", pparam->P_Value.Number);
  1432. ++prmpi->PI_NumOfParams;
  1433. ++pparam;
  1434. }
  1435. if (IsFlagSet(dwFlags, SPF_PARITY)) {
  1436. lstrcpyA(pparam->P_Key, SER_PARITY_KEY);
  1437. pparam->P_Type = Number;
  1438. pparam->P_Attributes = 0;
  1439. pparam->P_Value.Number = SetPortStmt_GetParity(pstmt);
  1440. RASSCRPT_TRACE1("GetParity==%d", pparam->P_Value.Number);
  1441. ++prmpi->PI_NumOfParams;
  1442. ++pparam;
  1443. }
  1444. //
  1445. // Send the changes down to RASMAN
  1446. //
  1447. if (!prmpi->PI_NumOfParams) { dwErr = NO_ERROR; }
  1448. else {
  1449. dwErr = g_pRasPortSetInfo(pscript->hport, prmpi);
  1450. RASSCRPT_TRACE1("g_pRasPortSetInfo==%d", dwErr);
  1451. if (dwErr != NO_ERROR) {
  1452. Stxerr_Add(
  1453. pscript->pdata->pastexec->hsaStxerr, "set port",
  1454. Ast_GetLine(pstmt), RES_E_FAIL
  1455. );
  1456. }
  1457. }
  1458. return (dwErr == NO_ERROR) ? RES_OK : RES_E_FAIL;
  1459. }
  1460. //----------------------------------------------------------------------------
  1461. // Function: RxWriteFile
  1462. //
  1463. // Transmits the given buffer thru RASMAN on a port
  1464. //----------------------------------------------------------------------------
  1465. VOID
  1466. RxWriteFile(
  1467. IN HANDLE hscript,
  1468. IN BYTE* pBuffer,
  1469. IN DWORD dwBufferSize,
  1470. OUT DWORD* pdwBytesWritten
  1471. ) {
  1472. RASSCRPT_TRACE("RxWriteFile");
  1473. if (!pdwBytesWritten) { return; }
  1474. RasScriptSend(hscript, pBuffer, dwBufferSize);
  1475. *pdwBytesWritten = dwBufferSize;
  1476. RASSCRPT_TRACE1("RxWriteFile(bw=%d)", *pdwBytesWritten);
  1477. }