source: trunk/src/win32k/api/api.cpp@ 4998

Last change on this file since 4998 was 4998, checked in by bird, 25 years ago

pre-commit

File size: 21.8 KB
Line 
1/* $Id: api.cpp,v 1.3 2001-01-21 07:52:46 bird Exp $
2 *
3 * API Overload Init and Helper Function.
4 *
5 * Copyright (c) 2001 knut st. osmundsen (knut.stange.osmundsen@mynd.no)
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11/*******************************************************************************
12* Defined Constants And Macros *
13*******************************************************************************/
14#define INCL_DOSERRORS
15#define INCL_NOPMAPI
16#define INCL_OS2KRNL_ALL
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <os2.h>
23
24#include "devSegDf.h"
25#include "rmalloc.h"
26#include "new.h"
27
28#include <memory.h>
29#include <stdlib.h>
30#include <stddef.h>
31#include <string.h>
32
33#include "log.h"
34#include "OS2Krnl.h"
35#include "ldrCalls.h"
36#include "dev32.h"
37#include "api.h"
38#include "options.h"
39#include "locks.h"
40
41
42
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47typedef struct _MaskArray
48{
49 int cMasks; /* Number of elements in papszMasks. */
50 PSZ * papszMasks; /* Array of module/process masks. */
51} MASKARRAY, *PMASKARRAY;
52
53typedef struct _ApiDataEntry
54{
55 BOOL fEnabled; /* Only enabled if data was found in .INI file! */
56 MASKARRAY ProcessInc; /* Process inclusion rules. */
57 MASKARRAY ProcessExc; /* Process exclusion rules. */
58 MASKARRAY ModuleInc; /* Module inclusion rules. */
59 MASKARRAY ModuleExc; /* Module exclusion rules. */
60} APIDATAENTRY, *PAPIDATAENTRY;
61
62
63/*******************************************************************************
64* Global Variables *
65*******************************************************************************/
66APIDATAENTRY aApiData[API_CENTRIES]; /* Array of api info. */
67PSZ pszFile; /* Pointer to entire file mapping. */
68RWLOCK ApiInfoRWLock; /* Read/Write lock for api data. */
69
70
71/*******************************************************************************
72* Internal Functions *
73*******************************************************************************/
74APIRET apiReadIniFile(PSZ pszIniFile);
75APIRET apiParseIniFile(PSZ pszFile);
76PSZ apiStripIniLine(PSZ pszFile, PSZ * ppszFile);
77int apiInterpretApiNo(PSZ pszSection);
78void apiFreeApiData(PAPIDATAENTRY paNewApiData);
79void apiSortApiData(PAPIDATAENTRY paApiData);
80void apiSortMaskArray(PMASKARRAY pMasks);
81BOOL apiFindNameInMaskArray(PSZ pszName, PMASKARRAY pMasks);
82APIRET apiGetProccessName(PSZ pszName);
83APIRET apiGetModuleName(PSZ pszName, USHORT usCS, ULONG ulEIP);
84
85
86/**
87 * This function will read the ini file from a give disklocation.
88 * @returns OS/2 return code.
89 * @param pszIniFile Full path to the inifile.
90 * @sketch Open the file.
91 * Determin file size.
92 * Allocate memory for the file.
93 * Read the entire file.
94 * Parse the file
95 * Close the file.
96 * @status completely implemented.
97 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
98 * @remark Must hold the loader semaphore before calling this function!
99 */
100APIRET apiReadIniFile(PSZ pszIniFile)
101{
102 SFN sfn;
103 APIRET rc;
104
105 rc = IOSftOpen(pszIniFile,
106 OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
107 OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY,
108 (PSFN)SSToDS(&sfn),
109 NULL);
110 if (rc == NO_ERROR)
111 {
112 ULONG cbFile = 0;
113
114 rc = SftFileSize(sfn, &cbFile);
115 if (rc == NO_ERROR)
116 {
117 if (cbFile > 256*1024) /* Max size if 256 KB! */
118 {
119 rc = ERROR_NOT_ENOUGH_MEMORY;
120 kprintf(("apiReadIniFile: Files %s is too large (%d).\n", pszIniFile, cbFile));
121 }
122 else
123 {
124 PSZ pszNewFile = (PSZ)rmalloc((size_t) cbFile + 1);
125 if (pszNewFile)
126 {
127 ULONG cbRead;
128
129 rc = IOSftReadAt(sfn, &cbRead, pszNewFile, 0UL, 0UL);
130 if (rc == NO_ERROR)
131 {
132 memset(pszNewFile + cbRead, 0, (size_t)(cbFile + 1 - cbRead)); /* terminate the file. */
133 rc = apiParseIniFile(pszNewFile);
134 }
135 else
136 kprintf(("apiReadIniFile: Failed to read %s into memory, rc=%d. (size %d)\n", pszIniFile, rc, cbFile));
137
138 if (rc != NO_ERROR)
139 rfree(pszNewFile);
140 }
141 else
142 {
143 rc = ERROR_NOT_ENOUGH_MEMORY;
144 kprintf(("apiReadIniFile: Failed to allocate %d of resident memory.\n", cbFile));
145 }
146 }
147 }
148 else
149 kprintf(("apiReadIniFile: Failed to determin size of %s, rc=%d\n", pszIniFile, rc));
150
151 IOSftClose(sfn);
152 }
153 else
154 kprintf(("apiReadIniFile: Failed to open file %s, rc=%d\n", pszIniFile, rc));
155
156 return rc;
157}
158
159
160/**
161 * Parse the inifile.
162 * @returns OS/2 return code.
163 * @param pszFile Pointer to file mapping.
164 * @sketch
165 * @status completely implemented.
166 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
167 * @remark
168 */
169APIRET apiParseIniFile(PSZ pszFile)
170{
171 PAPIDATAENTRY paNewApiData;
172 PSZ * ppszFile = (PSZ*)SSToDS(&pszFile);
173 PSZ pszLine;
174 APIRET rc;
175
176 /*
177 * Allocate and zero temporary api data structure.
178 */
179 paNewApiData = (PAPIDATAENTRY)rmalloc(sizeof(aApiData));
180 if (paNewApiData == NULL)
181 {
182 kprintf(("apiParseIniFile: failed to allocate temporary struct.\n"));
183 return ERROR_NOT_ENOUGH_MEMORY;
184 }
185 memset(paNewApiData, 0, sizeof(aApiData));
186
187 /*
188 * We'll loop until end of file.
189 * This is a double loop. Outer loop on section level. Inner loop
190 * on Type level.
191 */
192 rc = NO_ERROR;
193 pszLine = apiStripIniLine(pszFile, ppszFile);
194 while (pszLine != NULL && rc == NO_ERROR)
195 {
196 char ch;
197
198 if ((ch = *pszLine) != '\0')
199 {
200 if (ch == '[')
201 {
202 int iApi = apiInterpretApiNo(pszLine);
203 if (iApi >= 0 && iApi < API_CENTRIES)
204 {
205 PMASKARRAY pMaskArray = &paNewApiData[iApi].ModuleExc;
206
207 /*
208 * Enable api data entry.
209 * Get a line.
210 * Check for end-of-file and new section.
211 * Skip empty lines.
212 * Uppercase the line.
213 * If "Type=" line Then Change type entry.
214 * Else Add line to current type entry (default to module exclude).
215 */
216 paNewApiData[iApi].fEnabled = TRUE;
217 while ((pszLine = apiStripIniLine(pszFile, ppszFile)) != NULL
218 && *pszLine != '[')
219 {
220 if (*pszLine == '\0')
221 continue;
222 strupr(pszLine);
223 if (strcmp("TYPE=", pszLine) == 0)
224 {
225 pszLine += 5;
226 if (strstr(pszLine, "PROC"))
227 pMaskArray = strstr(pszLine, "INC")
228 ? &paNewApiData[iApi].ProcessInc
229 : &paNewApiData[iApi].ProcessExc; /* default */
230 else
231 pMaskArray = strstr(pszLine, "INC")
232 ? &paNewApiData[iApi].ModuleInc
233 : &paNewApiData[iApi].ModuleExc; /* default */
234 }
235 else
236 {
237 if (pMaskArray->cMasks % 8 == 0)
238 {
239 void *pv = rrealloc(pMaskArray->papszMasks, 8 + pMaskArray->cMasks);
240 if (pv == NULL)
241 {
242 rc = ERROR_NOT_ENOUGH_MEMORY;
243 kprintf(("apiParseIniFile: Failed to allocate more mask array memory. %c masks\n", pMaskArray->cMasks));
244 break;
245 }
246 pMaskArray->papszMasks = (PSZ*)pv;
247 }
248 pMaskArray->papszMasks[pMaskArray->cMasks++] = pszLine;
249 }
250 } /* inner loop */
251 }
252 else
253 {
254 kprintf(("apiParseIniFile: bogus api no.%d (%s)\n", iApi, pszLine));
255 pszLine = apiStripIniLine(pszFile, ppszFile);
256 }
257 }
258 else
259 {
260 kprintf(("apiParseIniFile: bogus line encountered: %s\n", pszLine));
261 pszLine = apiStripIniLine(pszFile, ppszFile);
262 }
263 }
264 else
265 pszLine = apiStripIniLine(pszFile, ppszFile);
266 } /* outer loop */
267
268
269 /*
270 * If we were successfull we'll replace the existing api data with
271 * the data we've just read.
272 * (TODO: Not sure (ie. quite sure) if we need some kind of serialization here...)
273 * If not we'll free any used memory before returning failure.
274 */
275 if (rc == NO_ERROR)
276 {
277 apiSortApiData(paNewApiData);
278 RWLockAcquireWrite(&ApiInfoRWLock);
279 apiFreeApiData(&aApiData[0]);
280 memcpy(&aApiData[0], paNewApiData, sizeof(aApiData));
281 RWLockReleaseWrite(&ApiInfoRWLock);
282 }
283 else
284 apiFreeApiData(paNewApiData);
285 rfree(paNewApiData);
286
287 return rc;
288}
289
290
291
292/**
293 * Strips and extract a line advancing the *ppszFile pointer to
294 * the next line. Comments are also stripped.
295 * @returns Pointer to line. NULL if end of file.
296 * @param pszFile Pointer to line.
297 * @param ppszFile Pointer to pointer variable.
298 * @sketch
299 * @status completly implemented.
300 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
301 */
302PSZ apiStripIniLine(PSZ pszFile, PSZ * ppszFile)
303{
304 PSZ pszComment;
305 PSZ pszLine;
306 char ch;
307
308 /*
309 * If end of file Then return NULL.
310 */
311 if (*pszFile)
312 return NULL;
313
314 /*
315 * Strip start of line.
316 */
317 while ((ch = *pszFile) == ' ' || ch == '\t')
318 pszFile++;
319 pszLine = pszFile;
320
321 /*
322 * Look for the line end and any evt. comment (starts with a ';').
323 */
324 pszComment = NULL;
325 while ((ch = *pszFile) != '\r' && ch != '\n' && ch != '\0')
326 {
327 if (ch == ';')
328 pszComment = pszFile;
329 pszFile++;
330 }
331
332 /*
333 * Update pszComment with the line end if not already set (we'll
334 * use this pointer to right strip the line).
335 * If not last line, then terminate the line.
336 * Skip return and newline characters to position the *ppszFile pointer
337 * at the next line.
338 * Update the next line pointer.
339 */
340 if (pszComment == NULL)
341 pszComment = pszFile;
342 if (ch != '\0')
343 {
344 *pszFile = '\0';
345 while ((ch = *pszFile) == '\r' || ch == '\n')
346 pszFile++;
347 }
348 *ppszFile = pszFile;
349
350 /*
351 * Right strip the line (starts with pszComment).
352 */
353 pszComment--;
354 while ((ch = *pszComment) == ' ' || ch == '\t')
355 pszComment--;
356 pszComment[1] = '\0';
357
358 return pszLine;
359}
360
361
362/**
363 * Reads the section header '[<ApiNbr]' and translates it into an
364 * api index (into aApiData). Range is not checked.
365 * @returns API index. -1 on error. Check range!
366 * @param pszSection Pointer to the section header string.
367 * Assumes that it's pointing to the '['.
368 * @sketch Skip '['.
369 * Skip blanks.
370 * Convert decimal number string and return it.
371 * @status completely implemented.
372 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
373 * @remark Layz, we only read '[n' no checking for the ending ']'.
374 */
375int apiInterpretApiNo(PSZ pszSection)
376{
377 int iApi = 0;
378
379 pszSection++; /* skip '[' */
380 if (*pszSection < '0' || *pszSection > '9')
381 return -1;
382
383 while (*pszSection == ' ' || *pszSection == '\t')
384 pszSection++;
385
386 while (*pszSection >= '0' || *pszSection <= '9')
387 {
388 iApi = (iApi * 10) + *pszSection - '0';
389 pszSection++;
390 }
391
392 return iApi;
393}
394
395
396/**
397 * Frees internal data in a api data structure.
398 * @param paApiData Pointer to api data table.
399 * @sketch Loop thru all api entries and free mask array pointers.
400 * @status Completely implemented.
401 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
402 * @remark Any serialization is not my problem.
403 */
404void apiFreeApiData(PAPIDATAENTRY paApiData)
405{
406 int i;
407
408 for (i = 0; i < API_CENTRIES; i++)
409 {
410 if (paApiData[i].ProcessInc.cMasks)
411 rfree(paApiData[i].ProcessInc.papszMasks);
412 if (paApiData[i].ProcessExc.cMasks)
413 rfree(paApiData[i].ProcessExc.papszMasks);
414 if (paApiData[i].ModuleInc.cMasks)
415 rfree(paApiData[i].ModuleInc.papszMasks);
416 if (paApiData[i].ModuleExc.cMasks)
417 rfree(paApiData[i].ModuleExc.papszMasks);
418 }
419}
420
421
422/**
423 * Sort the entire api data structure.
424 * @param paApiData Pointer to api data to sort.
425 * @sketch Loop thru all entries and sort all four mask arrays.
426 * @status completely implemented.
427 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
428 * @remark See apiSortMaskArray.
429 */
430void apiSortApiData(PAPIDATAENTRY paApiData)
431{
432 int i;
433
434 for (i = 0; i < API_CENTRIES; i++)
435 {
436 apiSortMaskArray(&paApiData[i].ProcessInc);
437 apiSortMaskArray(&paApiData[i].ProcessExc);
438 apiSortMaskArray(&paApiData[i].ModuleInc);
439 apiSortMaskArray(&paApiData[i].ModuleExc);
440 }
441}
442
443
444/**
445 * Sorts the content of an mask array.
446 * Duplicates are removed.
447 * @param pMasks Pointer to a mask array structure.
448 * @sketch Use bouble sort.
449 * @status partially implemented.
450 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
451 * @remark Duplicate submasks aren't tested for.
452 * example: "DOSCALL1.DLL" is equal to "DOS*"
453 */
454void apiSortMaskArray(PMASKARRAY pMasks)
455{
456 int i;
457 PSZ pszTmp;
458
459 do
460 {
461 for (i = 1, pszTmp = NULL; i < pMasks->cMasks; i++)
462 {
463 int iDiff = strcmp(pMasks->papszMasks[i], pMasks->papszMasks[i-1]);
464 if (iDiff == 0)
465 { /* remove entry */
466 memmove(&pMasks->papszMasks[i], &pMasks->papszMasks[i+1],
467 (pMasks->cMasks - i - 1) * sizeof(pMasks->papszMasks[0]));
468 i--;
469 }
470 else if (iDiff < 0)
471 { /* Swap entries. */
472 PSZ pszTmp = pMasks->papszMasks[i];
473 pMasks->papszMasks[i] = pMasks->papszMasks[i-1];
474 pMasks->papszMasks[i-1] = pszTmp;
475 }
476 }
477 } while (pszTmp != NULL);
478}
479
480
481/**
482 * Searches a mask array if there is any match for the given name.
483 * @returns TRUE if found.
484 * FALSE if not found.
485 * @param pszName Pointer to name.
486 * @param pMasks Pointer to mask array.
487 * @sketch
488 * @status
489 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
490 * @remark
491 */
492BOOL apiFindNameInMaskArray(PSZ pszName, PMASKARRAY pMasks)
493{
494 return FALSE;
495}
496
497
498/**
499 * Get the current process executable name.
500 * @returns OS/2 return code.
501 * @param pszName Pointer to output name buffer.
502 * @sketch Get current ptda.
503 * Get module handle (hmte) from current ptda.
504 * Get pmte and smte from the hmte.
505 * Check if there is any path (full filename).
506 * Parse out filename+ext from full filename and copy it to pszName.
507 * return.
508 * @status completely implemented.
509 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
510 */
511APIRET apiGetProccessName(PSZ pszName)
512{
513 PPTDA pPTDA = ptdaGetCur();
514 if (pPTDA)
515 {
516 HMTE hmte = ptdaGet_ptda_module(pPTDA);
517 if (hmte)
518 {
519 PMTE pmte = ldrASMpMTEFromHandle(hmte);
520 PSMTE psmte;
521 if ( pmte
522 && (psmte = pmte->mte_swapmte)
523 && psmte->smte_path
524 && *psmte->smte_path)
525 {
526 /*
527 * Get executable name from swap mte.
528 * We parse out the filename+ext and copies it to the output buffer.
529 */
530 PCHAR psz;
531 PCHAR pszExt;
532 ldrGetFileName2(psmte->smte_path, (PCHAR*)SSToDS(&psz), (PCHAR*)SSToDS(&pszExt));
533 if (!psz) psz = psmte->smte_path;
534 strcpy(pszName, psz);
535 return NO_ERROR;
536 }
537 else
538 kprintf(("apiGetProcessName: failed to get pmte(0x%08x) from hmte(0x%04x) or no path.\n", pmte, hmte));
539 }
540 else
541 kprintf(("apiGetProcessName: This PTDA has no module handle. (pptda=0x%08x, hptda=0x%04)\n", pPTDA, ptdaGet_ptda_handle(pPTDA)));
542 }
543 else
544 kprintf(("apiGetProcessName: No current PTDA!\n"));
545
546 return ERROR_INVALID_PARAMETER;
547}
548
549/**
550 * Gets the module name from a given CS:EIP pair.
551 * @returns OS/2 return code.
552 * @param pszName Output buffer.
553 * @param usCS CS (code segment).
554 * @param ulEIP EIP (Extended Instruction Pointer).
555 * @sketch Get hmte from cs:eip.
556 * Get pmte and smte from the hmte.
557 * Check if there is any path (full filename).
558 * Parse out filename+ext from full filename and copy it to pszName.
559 * return.
560 * @status completely implemented.
561 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
562 */
563APIRET apiGetModuleName(PSZ pszName, USHORT usCS, ULONG ulEIP)
564{
565 HMTE hmte = VMGetOwner(usCS, ulEIP);
566 if (hmte)
567 {
568 PMTE pmte = ldrASMpMTEFromHandle(hmte);
569 PSMTE psmte;
570 if ( pmte
571 && (psmte = pmte->mte_swapmte)
572 && psmte->smte_path
573 && *psmte->smte_path)
574 {
575 /*
576 * Get executable name from swap mte.
577 * We parse out the filename+ext and copies it to the output buffer.
578 */
579 PCHAR psz;
580 PCHAR pszExt;
581 ldrGetFileName2(psmte->smte_path, (PCHAR*)SSToDS(&psz), (PCHAR*)SSToDS(&pszExt));
582 if (!psz) psz = psmte->smte_path;
583 strcpy(pszName, psz);
584 return NO_ERROR;
585 }
586 else
587 kprintf(("apiGetModuleName: failed to get pmte(0x%08x) from hmte(0x%04x) or no path.\n", pmte, hmte));
588 }
589 else
590 kprintf(("apiGetModuleName: failed to get hmte from cs=%04x eip=%08x\n", usCS, ulEIP));
591
592 /*
593 * We failed.
594 */
595 return ERROR_INVALID_PARAMETER;
596}
597
598
599
600/**
601 * Checks if an api enhancement is enabled for this process or/and module.
602 * Exclusion lists rulez over inclusion.
603 * Excluded processes rulez over included modules.
604 * @returns TRUE (!0) if it's enabled.
605 * FALSE (0) if it's disabled.
606 * @param iApi Api data id/index.
607 * @param usCS CS of the API caller.
608 * @param ulEIP EIP of the API caller.
609 * @sketch
610 * @status
611 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
612 * @remark
613 */
614BOOL _Optlink APIQueryEnabled(int iApi, USHORT usCS, LONG ulEIP)
615{
616 PAPIDATAENTRY pEntry;
617
618 /*
619 * Check if these enhancements are switched off globally.
620 */
621 if (isApiEnhDisabled())
622 return FALSE;
623
624 /*
625 * Aquire read lock.
626 */
627 RWLockAcquireRead(&ApiInfoRWLock);
628
629 /*
630 * Get data entry pointer.
631 * Check if entry is enabled.
632 */
633 BOOL fRet = FALSE;
634 pEntry = &aApiData[iApi];
635 if (pEntry->fEnabled)
636 {
637 CHAR szName[CCHMAXPATH];
638 PSZ pszName = (PSZ)SSToDS(&szName[0]);
639
640 if (pEntry->ProcessExc.cMasks > 0 || pEntry->ProcessInc.cMasks > 0)
641 {
642 if (!apiGetProccessName(pszName))
643 { /* TODO - fix this priority - it's probably wrong */
644 if (pEntry->ProcessExc.cMasks)
645 fRet = !apiFindNameInMaskArray(pszName, &pEntry->ProcessExc);
646 else if (pEntry->ProcessInc.cMasks)
647 fRet = apiFindNameInMaskArray(pszName, &pEntry->ProcessInc);
648 }
649 }
650
651 if ( !pEntry->ProcessExc.cMasks
652 && !fRet
653 && (pEntry->ModuleExc.cMasks > 0 || pEntry->ModuleInc.cMasks > 0))
654 {
655 if (!apiGetModuleName(pszName, usCS, ulEIP))
656 { /* TODO - fix this priority - it's probably wrong */
657 if (pEntry->ModuleExc.cMasks)
658 fRet = !apiFindNameInMaskArray(pszName, &pEntry->ModuleExc);
659 else if (pEntry->ProcessInc.cMasks)
660 fRet = apiFindNameInMaskArray(pszName, &pEntry->ModuleInc);
661 }
662 }
663 }
664
665
666 /*
667 * Release read lock.
668 */
669 RWLockReleaseRead(&ApiInfoRWLock);
670
671 return fRet;
672}
673
674
675
676/**
677 * Init The Api Overloading SubSystem.
678 * @returns OS/2 return code.
679 * @sketch Find Ini file location.
680 * Read the inifile and there by initiate the aApiData strcut.
681 * @status completly implemented.
682 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
683 */
684APIRET _Optlink APIInit(void)
685{
686 APIRET rc;
687
688 rc = apiReadIniFile(&szWin32kIni[0]);
689
690 return rc;
691}
692
Note: See TracBrowser for help on using the repository browser.