libwinutils.c 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with this
  4. * work for additional information regarding copyright ownership. The ASF
  5. * licenses this file to you under the Apache License, Version 2.0 (the
  6. * "License"); you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. * License for the specific language governing permissions and limitations under
  15. * the License.
  16. */
  17. #pragma comment(lib, "authz.lib")
  18. #pragma comment(lib, "netapi32.lib")
  19. #pragma comment(lib, "Secur32.lib")
  20. #pragma comment(lib, "Userenv.lib")
  21. #pragma comment(lib, "Ntdsapi.lib")
  22. #include "winutils.h"
  23. #include <ctype.h>
  24. #include <Winsvc.h>
  25. #include <authz.h>
  26. #include <sddl.h>
  27. #include <Ntdsapi.h>
  28. #include <malloc.h>
  29. #define WIDEN_STRING(x) WIDEN_STRING_(x)
  30. #define WIDEN_STRING_(x) L ## x
  31. #define STRINGIFY(x) STRINGIFY_(x)
  32. #define STRINGIFY_(x) #x
  33. #pragma message("WSCE config is " STRINGIFY(WSCE_CONFIG_DIR) "\\" STRINGIFY(WSCE_CONFIG_FILE))
  34. const WCHAR* wsceConfigRelativePath = WIDEN_STRING(STRINGIFY(WSCE_CONFIG_DIR)) L"\\" WIDEN_STRING(STRINGIFY(WSCE_CONFIG_FILE));
  35. /*
  36. * The array of 12 months' three-letter abbreviations
  37. */
  38. const LPCWSTR MONTHS[] = { L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun",
  39. L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" };
  40. /*
  41. * The WindowsAclMask and WinMasks contain the definitions used to establish
  42. * the mapping between Unix and Windows.
  43. * We set up the mapping with the following rules.
  44. * 1. Everyone will have WIN_ALL permissions;
  45. * 2. Owner will always have WIN_OWNER_SE permissions in addition;
  46. * 2. When Unix read/write/excute permission is set on the file, the
  47. * corresponding Windows allow ACE will be added to the file.
  48. * More details and explaination can be found in the following white paper:
  49. * http://technet.microsoft.com/en-us/library/bb463216.aspx
  50. */
  51. const ACCESS_MASK WinMasks[WIN_MASKS_TOTAL] =
  52. {
  53. /* WIN_READ */
  54. FILE_READ_DATA,
  55. /* WIN_WRITE */
  56. FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_APPEND_DATA | FILE_WRITE_EA |
  57. FILE_DELETE_CHILD,
  58. /* WIN_EXECUTE */
  59. FILE_EXECUTE,
  60. /* WIN_OWNER_SE */
  61. DELETE | WRITE_DAC | WRITE_OWNER | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES,
  62. /* WIN_ALL */
  63. READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  64. };
  65. //----------------------------------------------------------------------------
  66. // Function: GetFileInformationByName
  67. //
  68. // Description:
  69. // To retrieve the by handle file information given the file name
  70. //
  71. // Returns:
  72. // ERROR_SUCCESS: on success
  73. // error code: otherwise
  74. //
  75. // Notes:
  76. // If followLink parameter is set to TRUE, we will follow the symbolic link
  77. // or junction point to get the target file information. Otherwise, the
  78. // information for the symbolic link or junction point is retrieved.
  79. //
  80. DWORD GetFileInformationByName(
  81. __in LPCWSTR pathName,
  82. __in BOOL followLink,
  83. __out LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
  84. {
  85. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  86. BOOL isSymlink = FALSE;
  87. BOOL isJunction = FALSE;
  88. DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS;
  89. DWORD dwErrorCode = ERROR_SUCCESS;
  90. assert(lpFileInformation != NULL);
  91. if (!followLink)
  92. {
  93. if ((dwErrorCode = SymbolicLinkCheck(pathName, &isSymlink)) != ERROR_SUCCESS)
  94. return dwErrorCode;
  95. if ((dwErrorCode = JunctionPointCheck(pathName, &isJunction)) != ERROR_SUCCESS)
  96. return dwErrorCode;
  97. if (isSymlink || isJunction)
  98. dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
  99. }
  100. fileHandle = CreateFileW(
  101. pathName,
  102. FILE_READ_ATTRIBUTES,
  103. FILE_SHARE_READ,
  104. NULL,
  105. OPEN_EXISTING,
  106. dwFlagsAndAttributes,
  107. NULL);
  108. if (fileHandle == INVALID_HANDLE_VALUE)
  109. {
  110. dwErrorCode = GetLastError();
  111. return dwErrorCode;
  112. }
  113. if (!GetFileInformationByHandle(fileHandle, lpFileInformation))
  114. {
  115. dwErrorCode = GetLastError();
  116. CloseHandle(fileHandle);
  117. return dwErrorCode;
  118. }
  119. CloseHandle(fileHandle);
  120. return dwErrorCode;
  121. }
  122. //----------------------------------------------------------------------------
  123. // Function: IsLongWindowsPath
  124. //
  125. // Description:
  126. // Checks if the path is longer than MAX_PATH in which case it needs to be
  127. // prepended with \\?\ for Windows OS to understand it.
  128. //
  129. // Returns:
  130. // TRUE long path
  131. // FALSE otherwise
  132. static BOOL IsLongWindowsPath(__in PCWSTR path)
  133. {
  134. return (wcslen(path) + 1) > MAX_PATH;
  135. }
  136. //----------------------------------------------------------------------------
  137. // Function: IsPrefixedAlready
  138. //
  139. // Description:
  140. // Checks if the given path is already prepended with \\?\.
  141. //
  142. // Returns:
  143. // TRUE if yes
  144. // FALSE otherwise
  145. static BOOL IsPrefixedAlready(__in PCWSTR path)
  146. {
  147. static const PCWSTR LongPathPrefix = L"\\\\?\\";
  148. size_t Prefixlen = wcslen(LongPathPrefix);
  149. size_t i = 0;
  150. if (path == NULL || wcslen(path) < Prefixlen)
  151. {
  152. return FALSE;
  153. }
  154. for (i = 0; i < Prefixlen; ++i)
  155. {
  156. if (path[i] != LongPathPrefix[i])
  157. {
  158. return FALSE;
  159. }
  160. }
  161. return TRUE;
  162. }
  163. //----------------------------------------------------------------------------
  164. // Function: ConvertToLongPath
  165. //
  166. // Description:
  167. // Prepends the path with the \\?\ prefix if the path is longer than MAX_PATH.
  168. // On success, newPath should be freed with LocalFree(). Given that relative
  169. // paths cannot be longer than MAX_PATH, we will never prepend the prefix
  170. // to relative paths.
  171. //
  172. // Returns:
  173. // ERROR_SUCCESS on success
  174. // error code on failure
  175. DWORD ConvertToLongPath(__in PCWSTR path, __deref_out PWSTR *newPath)
  176. {
  177. DWORD dwErrorCode = ERROR_SUCCESS;
  178. static const PCWSTR LongPathPrefix = L"\\\\?\\";
  179. BOOL bAppendPrefix = IsLongWindowsPath(path) && !IsPrefixedAlready(path);
  180. HRESULT hr = S_OK;
  181. size_t newPathLen = wcslen(path) + (bAppendPrefix ? wcslen(LongPathPrefix) : 0);
  182. // Allocate the buffer for the output path (+1 for terminating NULL char)
  183. //
  184. PWSTR newPathValue = (PWSTR)LocalAlloc(LPTR, (newPathLen + 1) * sizeof(WCHAR));
  185. if (newPathValue == NULL)
  186. {
  187. dwErrorCode = GetLastError();
  188. goto ConvertToLongPathExit;
  189. }
  190. if (bAppendPrefix)
  191. {
  192. // Append the prefix to the path
  193. //
  194. hr = StringCchPrintfW(newPathValue, newPathLen + 1, L"%s%s",
  195. LongPathPrefix, path);
  196. if (FAILED(hr))
  197. {
  198. dwErrorCode = HRESULT_CODE(hr);
  199. goto ConvertToLongPathExit;
  200. }
  201. }
  202. else
  203. {
  204. // Just copy the original value into the output path. In this scenario
  205. // we are doing extra buffer copy. We decided to trade code simplicity
  206. // on the call site for small performance impact (extra allocation and
  207. // buffer copy). As paths are short, the impact is generally small.
  208. //
  209. hr = StringCchPrintfW(newPathValue, newPathLen + 1, L"%s", path);
  210. if (FAILED(hr))
  211. {
  212. dwErrorCode = HRESULT_CODE(hr);
  213. goto ConvertToLongPathExit;
  214. }
  215. }
  216. *newPath = newPathValue;
  217. ConvertToLongPathExit:
  218. if (dwErrorCode != ERROR_SUCCESS)
  219. {
  220. LocalFree(newPathValue);
  221. }
  222. return dwErrorCode;
  223. }
  224. //----------------------------------------------------------------------------
  225. // Function: IsDirFileInfo
  226. //
  227. // Description:
  228. // Test if the given file information is a directory
  229. //
  230. // Returns:
  231. // TRUE if it is a directory
  232. // FALSE otherwise
  233. //
  234. // Notes:
  235. //
  236. BOOL IsDirFileInfo(const BY_HANDLE_FILE_INFORMATION *fileInformation)
  237. {
  238. if ((fileInformation->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  239. == FILE_ATTRIBUTE_DIRECTORY)
  240. return TRUE;
  241. return FALSE;
  242. }
  243. //----------------------------------------------------------------------------
  244. // Function: CheckFileAttributes
  245. //
  246. // Description:
  247. // Check if the given file has all the given attribute(s)
  248. //
  249. // Returns:
  250. // ERROR_SUCCESS on success
  251. // error code otherwise
  252. //
  253. // Notes:
  254. //
  255. static DWORD FileAttributesCheck(
  256. __in LPCWSTR path, __in DWORD attr, __out PBOOL res)
  257. {
  258. DWORD attrs = INVALID_FILE_ATTRIBUTES;
  259. *res = FALSE;
  260. if ((attrs = GetFileAttributes(path)) != INVALID_FILE_ATTRIBUTES)
  261. *res = ((attrs & attr) == attr);
  262. else
  263. return GetLastError();
  264. return ERROR_SUCCESS;
  265. }
  266. //----------------------------------------------------------------------------
  267. // Function: IsDirectory
  268. //
  269. // Description:
  270. // Check if the given file is a directory
  271. //
  272. // Returns:
  273. // ERROR_SUCCESS on success
  274. // error code otherwise
  275. //
  276. // Notes:
  277. //
  278. DWORD DirectoryCheck(__in LPCWSTR pathName, __out PBOOL res)
  279. {
  280. return FileAttributesCheck(pathName, FILE_ATTRIBUTE_DIRECTORY, res);
  281. }
  282. //----------------------------------------------------------------------------
  283. // Function: IsReparsePoint
  284. //
  285. // Description:
  286. // Check if the given file is a reparse point
  287. //
  288. // Returns:
  289. // ERROR_SUCCESS on success
  290. // error code otherwise
  291. //
  292. // Notes:
  293. //
  294. static DWORD ReparsePointCheck(__in LPCWSTR pathName, __out PBOOL res)
  295. {
  296. return FileAttributesCheck(pathName, FILE_ATTRIBUTE_REPARSE_POINT, res);
  297. }
  298. //----------------------------------------------------------------------------
  299. // Function: CheckReparseTag
  300. //
  301. // Description:
  302. // Check if the given file is a reparse point of the given tag.
  303. //
  304. // Returns:
  305. // ERROR_SUCCESS on success
  306. // error code otherwise
  307. //
  308. // Notes:
  309. //
  310. static DWORD ReparseTagCheck(__in LPCWSTR path, __in DWORD tag, __out PBOOL res)
  311. {
  312. BOOL isReparsePoint = FALSE;
  313. HANDLE hFind = INVALID_HANDLE_VALUE;
  314. WIN32_FIND_DATA findData;
  315. DWORD dwRtnCode;
  316. if ((dwRtnCode = ReparsePointCheck(path, &isReparsePoint)) != ERROR_SUCCESS)
  317. return dwRtnCode;
  318. if (!isReparsePoint)
  319. {
  320. *res = FALSE;
  321. }
  322. else
  323. {
  324. if ((hFind = FindFirstFile(path, &findData)) == INVALID_HANDLE_VALUE)
  325. {
  326. return GetLastError();
  327. }
  328. else
  329. {
  330. *res = (findData.dwReserved0 == tag);
  331. FindClose(hFind);
  332. }
  333. }
  334. return ERROR_SUCCESS;
  335. }
  336. //----------------------------------------------------------------------------
  337. // Function: IsSymbolicLink
  338. //
  339. // Description:
  340. // Check if the given file is a symbolic link.
  341. //
  342. // Returns:
  343. // ERROR_SUCCESS on success
  344. // error code otherwise
  345. //
  346. // Notes:
  347. //
  348. DWORD SymbolicLinkCheck(__in LPCWSTR pathName, __out PBOOL res)
  349. {
  350. return ReparseTagCheck(pathName, IO_REPARSE_TAG_SYMLINK, res);
  351. }
  352. //----------------------------------------------------------------------------
  353. // Function: IsJunctionPoint
  354. //
  355. // Description:
  356. // Check if the given file is a junction point.
  357. //
  358. // Returns:
  359. // ERROR_SUCCESS on success
  360. // error code otherwise
  361. //
  362. // Notes:
  363. //
  364. DWORD JunctionPointCheck(__in LPCWSTR pathName, __out PBOOL res)
  365. {
  366. return ReparseTagCheck(pathName, IO_REPARSE_TAG_MOUNT_POINT, res);
  367. }
  368. //----------------------------------------------------------------------------
  369. // Function: GetSidFromAcctNameW
  370. //
  371. // Description:
  372. // To retrieve the SID for a user account
  373. //
  374. // Returns:
  375. // ERROR_SUCCESS: on success
  376. // Other error code: otherwise
  377. //
  378. // Notes:
  379. // Caller needs to destroy the memory of Sid by calling LocalFree()
  380. //
  381. DWORD GetSidFromAcctNameW(__in PCWSTR acctName, __out PSID *ppSid)
  382. {
  383. DWORD dwSidSize = 0;
  384. DWORD cchDomainName = 0;
  385. DWORD dwDomainNameSize = 0;
  386. LPWSTR domainName = NULL;
  387. SID_NAME_USE eSidType;
  388. DWORD dwErrorCode = ERROR_SUCCESS;
  389. // Validate the input parameters.
  390. //
  391. assert (acctName != NULL && ppSid != NULL);
  392. // Empty name is invalid. However, LookupAccountName() function will return a
  393. // false Sid, i.e. Sid for 'BUILDIN', for an empty name instead failing. We
  394. // report the error before calling LookupAccountName() function for this
  395. // special case. The error code returned here is the same as the last error
  396. // code set by LookupAccountName() function for an invalid name.
  397. //
  398. if (wcslen(acctName) == 0)
  399. return ERROR_NONE_MAPPED;
  400. // First pass to retrieve the buffer size.
  401. //
  402. LookupAccountName(
  403. NULL, // Computer name. NULL for the local computer
  404. acctName,
  405. NULL, // pSid. NULL to retrieve buffer size
  406. &dwSidSize,
  407. NULL, // Domain Name. NULL to retrieve buffer size
  408. &cchDomainName,
  409. &eSidType);
  410. if((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  411. {
  412. return dwErrorCode;
  413. }
  414. else
  415. {
  416. // Reallocate memory for the buffers.
  417. //
  418. *ppSid = (PSID)LocalAlloc(LPTR, dwSidSize);
  419. if (*ppSid == NULL)
  420. {
  421. return GetLastError();
  422. }
  423. dwDomainNameSize = (cchDomainName + 1) * sizeof(wchar_t);
  424. domainName = (LPWSTR)LocalAlloc(LPTR, dwDomainNameSize);
  425. if (domainName == NULL)
  426. {
  427. return GetLastError();
  428. }
  429. // Second pass to retrieve the SID and domain name.
  430. //
  431. if (!LookupAccountNameW(
  432. NULL, // Computer name. NULL for the local computer
  433. acctName,
  434. *ppSid,
  435. &dwSidSize,
  436. domainName,
  437. &cchDomainName,
  438. &eSidType))
  439. {
  440. LocalFree(domainName);
  441. return GetLastError();
  442. }
  443. assert(IsValidSid(*ppSid));
  444. }
  445. LocalFree(domainName);
  446. return ERROR_SUCCESS;
  447. }
  448. //----------------------------------------------------------------------------
  449. // Function: GetUnixAccessMask
  450. //
  451. // Description:
  452. // Compute the 3 bit Unix mask for the owner, group, or, others
  453. //
  454. // Returns:
  455. // The 3 bit Unix mask in INT
  456. //
  457. // Notes:
  458. //
  459. static INT GetUnixAccessMask(ACCESS_MASK Mask)
  460. {
  461. static const INT exe = 0x0001;
  462. static const INT write = 0x0002;
  463. static const INT read = 0x0004;
  464. INT mask = 0;
  465. if ((Mask & WinMasks[WIN_READ]) == WinMasks[WIN_READ])
  466. mask |= read;
  467. if ((Mask & WinMasks[WIN_WRITE]) == WinMasks[WIN_WRITE])
  468. mask |= write;
  469. if ((Mask & WinMasks[WIN_EXECUTE]) == WinMasks[WIN_EXECUTE])
  470. mask |= exe;
  471. return mask;
  472. }
  473. //----------------------------------------------------------------------------
  474. // Function: GetAccess
  475. //
  476. // Description:
  477. // Get Windows acces mask by AuthZ methods
  478. //
  479. // Returns:
  480. // ERROR_SUCCESS: on success
  481. //
  482. // Notes:
  483. //
  484. static DWORD GetAccess(AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClient,
  485. PSECURITY_DESCRIPTOR psd, PACCESS_MASK pAccessRights)
  486. {
  487. AUTHZ_ACCESS_REQUEST AccessRequest = {0};
  488. AUTHZ_ACCESS_REPLY AccessReply = {0};
  489. BYTE Buffer[1024];
  490. assert (pAccessRights != NULL);
  491. // Do AccessCheck
  492. AccessRequest.DesiredAccess = MAXIMUM_ALLOWED;
  493. AccessRequest.PrincipalSelfSid = NULL;
  494. AccessRequest.ObjectTypeList = NULL;
  495. AccessRequest.ObjectTypeListLength = 0;
  496. AccessRequest.OptionalArguments = NULL;
  497. RtlZeroMemory(Buffer, sizeof(Buffer));
  498. AccessReply.ResultListLength = 1;
  499. AccessReply.GrantedAccessMask = (PACCESS_MASK) (Buffer);
  500. AccessReply.Error = (PDWORD) (Buffer + sizeof(ACCESS_MASK));
  501. if (!AuthzAccessCheck(0,
  502. hAuthzClient,
  503. &AccessRequest,
  504. NULL,
  505. psd,
  506. NULL,
  507. 0,
  508. &AccessReply,
  509. NULL))
  510. {
  511. return GetLastError();
  512. }
  513. *pAccessRights = (*(const ACCESS_MASK *)(AccessReply.GrantedAccessMask));
  514. return ERROR_SUCCESS;
  515. }
  516. //----------------------------------------------------------------------------
  517. // Function: GetEffectiveRightsForSid
  518. //
  519. // Description:
  520. // Get Windows acces mask by AuthZ methods
  521. //
  522. // Returns:
  523. // ERROR_SUCCESS: on success
  524. //
  525. // Notes:
  526. // We run into problems for local user accounts when using the method
  527. // GetEffectiveRightsFromAcl(). We resort to using AuthZ methods as
  528. // an alternative way suggested on MSDN:
  529. // http://msdn.microsoft.com/en-us/library/windows/desktop/aa446637.aspx
  530. //
  531. static DWORD GetEffectiveRightsForSid(PSECURITY_DESCRIPTOR psd,
  532. PSID pSid,
  533. PACCESS_MASK pAccessRights)
  534. {
  535. AUTHZ_RESOURCE_MANAGER_HANDLE hManager = NULL;
  536. LUID unusedId = { 0 };
  537. AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext = NULL;
  538. DWORD dwRtnCode = ERROR_SUCCESS;
  539. DWORD ret = ERROR_SUCCESS;
  540. assert (pAccessRights != NULL);
  541. if (!AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT,
  542. NULL, NULL, NULL, NULL, &hManager))
  543. {
  544. return GetLastError();
  545. }
  546. // Pass AUTHZ_SKIP_TOKEN_GROUPS to the function to avoid querying user group
  547. // information for access check. This allows us to model POSIX permissions
  548. // on Windows, where a user can have less permissions than a group it
  549. // belongs to.
  550. if(!AuthzInitializeContextFromSid(AUTHZ_SKIP_TOKEN_GROUPS,
  551. pSid, hManager, NULL, unusedId, NULL, &hAuthzClientContext))
  552. {
  553. ret = GetLastError();
  554. goto GetEffectiveRightsForSidEnd;
  555. }
  556. if ((dwRtnCode = GetAccess(hAuthzClientContext, psd, pAccessRights))
  557. != ERROR_SUCCESS)
  558. {
  559. ret = dwRtnCode;
  560. goto GetEffectiveRightsForSidEnd;
  561. }
  562. GetEffectiveRightsForSidEnd:
  563. if (hManager != NULL)
  564. {
  565. (void)AuthzFreeResourceManager(hManager);
  566. }
  567. if (hAuthzClientContext != NULL)
  568. {
  569. (void)AuthzFreeContext(hAuthzClientContext);
  570. }
  571. return ret;
  572. }
  573. //----------------------------------------------------------------------------
  574. // Function: CheckAccessForCurrentUser
  575. //
  576. // Description:
  577. // Checks if the current process has the requested access rights on the given
  578. // path. Based on the following MSDN article:
  579. // http://msdn.microsoft.com/en-us/library/windows/desktop/ff394771(v=vs.85).aspx
  580. //
  581. // Returns:
  582. // ERROR_SUCCESS: on success
  583. //
  584. DWORD CheckAccessForCurrentUser(
  585. __in PCWSTR pathName,
  586. __in ACCESS_MASK requestedAccess,
  587. __out BOOL *allowed)
  588. {
  589. DWORD dwRtnCode = ERROR_SUCCESS;
  590. LPWSTR longPathName = NULL;
  591. HANDLE hProcessToken = NULL;
  592. PSECURITY_DESCRIPTOR pSd = NULL;
  593. AUTHZ_RESOURCE_MANAGER_HANDLE hManager = NULL;
  594. AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext = NULL;
  595. LUID Luid = {0, 0};
  596. ACCESS_MASK currentUserAccessRights = 0;
  597. // Prepend the long path prefix if needed
  598. dwRtnCode = ConvertToLongPath(pathName, &longPathName);
  599. if (dwRtnCode != ERROR_SUCCESS)
  600. {
  601. goto CheckAccessEnd;
  602. }
  603. // Get SD of the given path. OWNER and DACL security info must be
  604. // requested, otherwise, AuthzAccessCheck fails with invalid parameter
  605. // error.
  606. dwRtnCode = GetNamedSecurityInfo(longPathName, SE_FILE_OBJECT,
  607. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  608. DACL_SECURITY_INFORMATION,
  609. NULL, NULL, NULL, NULL, &pSd);
  610. if (dwRtnCode != ERROR_SUCCESS)
  611. {
  612. goto CheckAccessEnd;
  613. }
  614. // Get current process token
  615. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  616. {
  617. dwRtnCode = GetLastError();
  618. goto CheckAccessEnd;
  619. }
  620. if (!AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT, NULL, NULL,
  621. NULL, NULL, &hManager))
  622. {
  623. dwRtnCode = GetLastError();
  624. goto CheckAccessEnd;
  625. }
  626. if(!AuthzInitializeContextFromToken(0, hProcessToken, hManager, NULL,
  627. Luid, NULL, &hAuthzClientContext))
  628. {
  629. dwRtnCode = GetLastError();
  630. goto CheckAccessEnd;
  631. }
  632. dwRtnCode = GetAccess(hAuthzClientContext, pSd, &currentUserAccessRights);
  633. if (dwRtnCode != ERROR_SUCCESS)
  634. {
  635. goto CheckAccessEnd;
  636. }
  637. *allowed = ((currentUserAccessRights & requestedAccess) == requestedAccess);
  638. CheckAccessEnd:
  639. LocalFree(longPathName);
  640. LocalFree(pSd);
  641. if (hProcessToken != NULL)
  642. {
  643. CloseHandle(hProcessToken);
  644. }
  645. if (hManager != NULL)
  646. {
  647. (void)AuthzFreeResourceManager(hManager);
  648. }
  649. if (hAuthzClientContext != NULL)
  650. {
  651. (void)AuthzFreeContext(hAuthzClientContext);
  652. }
  653. return dwRtnCode;
  654. }
  655. //----------------------------------------------------------------------------
  656. // Function: FindFileOwnerAndPermissionByHandle
  657. //
  658. // Description:
  659. // Find the owner, primary group and permissions of a file object given the
  660. // the file object handle. The function will always follow symbolic links.
  661. //
  662. // Returns:
  663. // ERROR_SUCCESS: on success
  664. // Error code otherwise
  665. //
  666. // Notes:
  667. // - Caller needs to destroy the memeory of owner and group names by calling
  668. // LocalFree() function.
  669. //
  670. // - If the user or group name does not exist, the user or group SID will be
  671. // returned as the name.
  672. //
  673. DWORD FindFileOwnerAndPermissionByHandle(
  674. __in HANDLE fileHandle,
  675. __out_opt LPWSTR *pOwnerName,
  676. __out_opt LPWSTR *pGroupName,
  677. __out_opt PINT pMask)
  678. {
  679. LPWSTR path = NULL;
  680. DWORD cchPathLen = 0;
  681. DWORD dwRtnCode = ERROR_SUCCESS;
  682. DWORD ret = ERROR_SUCCESS;
  683. dwRtnCode = GetFinalPathNameByHandle(fileHandle, path, cchPathLen, 0);
  684. if (dwRtnCode == 0)
  685. {
  686. ret = GetLastError();
  687. goto FindFileOwnerAndPermissionByHandleEnd;
  688. }
  689. cchPathLen = dwRtnCode;
  690. path = (LPWSTR) LocalAlloc(LPTR, cchPathLen * sizeof(WCHAR));
  691. if (path == NULL)
  692. {
  693. ret = GetLastError();
  694. goto FindFileOwnerAndPermissionByHandleEnd;
  695. }
  696. dwRtnCode = GetFinalPathNameByHandle(fileHandle, path, cchPathLen, 0);
  697. if (dwRtnCode != cchPathLen - 1)
  698. {
  699. ret = GetLastError();
  700. goto FindFileOwnerAndPermissionByHandleEnd;
  701. }
  702. dwRtnCode = FindFileOwnerAndPermission(path, TRUE, pOwnerName, pGroupName, pMask);
  703. if (dwRtnCode != ERROR_SUCCESS)
  704. {
  705. ret = dwRtnCode;
  706. goto FindFileOwnerAndPermissionByHandleEnd;
  707. }
  708. FindFileOwnerAndPermissionByHandleEnd:
  709. LocalFree(path);
  710. return ret;
  711. }
  712. //----------------------------------------------------------------------------
  713. // Function: FindFileOwnerAndPermission
  714. //
  715. // Description:
  716. // Find the owner, primary group and permissions of a file object
  717. //
  718. // Returns:
  719. // ERROR_SUCCESS: on success
  720. // Error code otherwise
  721. //
  722. // Notes:
  723. // - Caller needs to destroy the memeory of owner and group names by calling
  724. // LocalFree() function.
  725. //
  726. // - If the user or group name does not exist, the user or group SID will be
  727. // returned as the name.
  728. //
  729. DWORD FindFileOwnerAndPermission(
  730. __in LPCWSTR pathName,
  731. __in BOOL followLink,
  732. __out_opt LPWSTR *pOwnerName,
  733. __out_opt LPWSTR *pGroupName,
  734. __out_opt PINT pMask)
  735. {
  736. DWORD dwRtnCode = 0;
  737. PSECURITY_DESCRIPTOR pSd = NULL;
  738. PSID psidOwner = NULL;
  739. PSID psidGroup = NULL;
  740. PSID psidEveryone = NULL;
  741. DWORD cbSid = SECURITY_MAX_SID_SIZE;
  742. PACL pDacl = NULL;
  743. BOOL isSymlink = FALSE;
  744. BY_HANDLE_FILE_INFORMATION fileInformation = {0};
  745. ACCESS_MASK ownerAccessRights = 0;
  746. ACCESS_MASK groupAccessRights = 0;
  747. ACCESS_MASK worldAccessRights = 0;
  748. DWORD ret = ERROR_SUCCESS;
  749. // Do nothing if the caller request nothing
  750. //
  751. if (pOwnerName == NULL && pGroupName == NULL && pMask == NULL)
  752. {
  753. return ret;
  754. }
  755. dwRtnCode = GetNamedSecurityInfo(pathName, SE_FILE_OBJECT,
  756. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  757. DACL_SECURITY_INFORMATION,
  758. &psidOwner, &psidGroup, &pDacl, NULL, &pSd);
  759. if (dwRtnCode != ERROR_SUCCESS)
  760. {
  761. ret = dwRtnCode;
  762. goto FindFileOwnerAndPermissionEnd;
  763. }
  764. if (pOwnerName != NULL)
  765. {
  766. dwRtnCode = GetAccntNameFromSid(psidOwner, pOwnerName);
  767. if (dwRtnCode == ERROR_NONE_MAPPED)
  768. {
  769. if (!ConvertSidToStringSid(psidOwner, pOwnerName))
  770. {
  771. ret = GetLastError();
  772. goto FindFileOwnerAndPermissionEnd;
  773. }
  774. }
  775. else if (dwRtnCode != ERROR_SUCCESS)
  776. {
  777. ret = dwRtnCode;
  778. goto FindFileOwnerAndPermissionEnd;
  779. }
  780. }
  781. if (pGroupName != NULL)
  782. {
  783. dwRtnCode = GetAccntNameFromSid(psidGroup, pGroupName);
  784. if (dwRtnCode == ERROR_NONE_MAPPED)
  785. {
  786. if (!ConvertSidToStringSid(psidGroup, pGroupName))
  787. {
  788. ret = GetLastError();
  789. goto FindFileOwnerAndPermissionEnd;
  790. }
  791. }
  792. else if (dwRtnCode != ERROR_SUCCESS)
  793. {
  794. ret = dwRtnCode;
  795. goto FindFileOwnerAndPermissionEnd;
  796. }
  797. }
  798. if (pMask == NULL) goto FindFileOwnerAndPermissionEnd;
  799. dwRtnCode = GetFileInformationByName(pathName,
  800. followLink, &fileInformation);
  801. if (dwRtnCode != ERROR_SUCCESS)
  802. {
  803. ret = dwRtnCode;
  804. goto FindFileOwnerAndPermissionEnd;
  805. }
  806. dwRtnCode = SymbolicLinkCheck(pathName, &isSymlink);
  807. if (dwRtnCode != ERROR_SUCCESS)
  808. {
  809. ret = dwRtnCode;
  810. goto FindFileOwnerAndPermissionEnd;
  811. }
  812. if (isSymlink)
  813. *pMask |= UX_SYMLINK;
  814. else if (IsDirFileInfo(&fileInformation))
  815. *pMask |= UX_DIRECTORY;
  816. else
  817. *pMask |= UX_REGULAR;
  818. if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
  819. psidOwner, &ownerAccessRights)) != ERROR_SUCCESS)
  820. {
  821. ret = dwRtnCode;
  822. goto FindFileOwnerAndPermissionEnd;
  823. }
  824. if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
  825. psidGroup, &groupAccessRights)) != ERROR_SUCCESS)
  826. {
  827. ret = dwRtnCode;
  828. goto FindFileOwnerAndPermissionEnd;
  829. }
  830. if ((psidEveryone = LocalAlloc(LPTR, cbSid)) == NULL)
  831. {
  832. ret = GetLastError();
  833. goto FindFileOwnerAndPermissionEnd;
  834. }
  835. if (!CreateWellKnownSid(WinWorldSid, NULL, psidEveryone, &cbSid))
  836. {
  837. ret = GetLastError();
  838. goto FindFileOwnerAndPermissionEnd;
  839. }
  840. if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
  841. psidEveryone, &worldAccessRights)) != ERROR_SUCCESS)
  842. {
  843. ret = dwRtnCode;
  844. goto FindFileOwnerAndPermissionEnd;
  845. }
  846. *pMask |= GetUnixAccessMask(ownerAccessRights) << 6;
  847. *pMask |= GetUnixAccessMask(groupAccessRights) << 3;
  848. *pMask |= GetUnixAccessMask(worldAccessRights);
  849. FindFileOwnerAndPermissionEnd:
  850. LocalFree(psidEveryone);
  851. LocalFree(pSd);
  852. return ret;
  853. }
  854. //----------------------------------------------------------------------------
  855. // Function: GetWindowsAccessMask
  856. //
  857. // Description:
  858. // Get the Windows AccessMask for user, group and everyone based on the Unix
  859. // permission mask
  860. //
  861. // Returns:
  862. // none
  863. //
  864. // Notes:
  865. // none
  866. //
  867. static void GetWindowsAccessMask(INT unixMask,
  868. ACCESS_MASK *userAllow,
  869. ACCESS_MASK *userDeny,
  870. ACCESS_MASK *groupAllow,
  871. ACCESS_MASK *groupDeny,
  872. ACCESS_MASK *otherAllow)
  873. {
  874. assert (userAllow != NULL && userDeny != NULL &&
  875. groupAllow != NULL && groupDeny != NULL &&
  876. otherAllow != NULL);
  877. *userAllow = WinMasks[WIN_ALL] | WinMasks[WIN_OWNER_SE];
  878. if ((unixMask & UX_U_READ) == UX_U_READ)
  879. *userAllow |= WinMasks[WIN_READ];
  880. if ((unixMask & UX_U_WRITE) == UX_U_WRITE)
  881. *userAllow |= WinMasks[WIN_WRITE];
  882. if ((unixMask & UX_U_EXECUTE) == UX_U_EXECUTE)
  883. *userAllow |= WinMasks[WIN_EXECUTE];
  884. *userDeny = 0;
  885. if ((unixMask & UX_U_READ) != UX_U_READ &&
  886. ((unixMask & UX_G_READ) == UX_G_READ ||
  887. (unixMask & UX_O_READ) == UX_O_READ))
  888. *userDeny |= WinMasks[WIN_READ];
  889. if ((unixMask & UX_U_WRITE) != UX_U_WRITE &&
  890. ((unixMask & UX_G_WRITE) == UX_G_WRITE ||
  891. (unixMask & UX_O_WRITE) == UX_O_WRITE))
  892. *userDeny |= WinMasks[WIN_WRITE];
  893. if ((unixMask & UX_U_EXECUTE) != UX_U_EXECUTE &&
  894. ((unixMask & UX_G_EXECUTE) == UX_G_EXECUTE ||
  895. (unixMask & UX_O_EXECUTE) == UX_O_EXECUTE))
  896. *userDeny |= WinMasks[WIN_EXECUTE];
  897. *groupAllow = WinMasks[WIN_ALL];
  898. if ((unixMask & UX_G_READ) == UX_G_READ)
  899. *groupAllow |= FILE_GENERIC_READ;
  900. if ((unixMask & UX_G_WRITE) == UX_G_WRITE)
  901. *groupAllow |= WinMasks[WIN_WRITE];
  902. if ((unixMask & UX_G_EXECUTE) == UX_G_EXECUTE)
  903. *groupAllow |= WinMasks[WIN_EXECUTE];
  904. *groupDeny = 0;
  905. if ((unixMask & UX_G_READ) != UX_G_READ &&
  906. (unixMask & UX_O_READ) == UX_O_READ)
  907. *groupDeny |= WinMasks[WIN_READ];
  908. if ((unixMask & UX_G_WRITE) != UX_G_WRITE &&
  909. (unixMask & UX_O_WRITE) == UX_O_WRITE)
  910. *groupDeny |= WinMasks[WIN_WRITE];
  911. if ((unixMask & UX_G_EXECUTE) != UX_G_EXECUTE &&
  912. (unixMask & UX_O_EXECUTE) == UX_O_EXECUTE)
  913. *groupDeny |= WinMasks[WIN_EXECUTE];
  914. *otherAllow = WinMasks[WIN_ALL];
  915. if ((unixMask & UX_O_READ) == UX_O_READ)
  916. *otherAllow |= WinMasks[WIN_READ];
  917. if ((unixMask & UX_O_WRITE) == UX_O_WRITE)
  918. *otherAllow |= WinMasks[WIN_WRITE];
  919. if ((unixMask & UX_O_EXECUTE) == UX_O_EXECUTE)
  920. *otherAllow |= WinMasks[WIN_EXECUTE];
  921. }
  922. //----------------------------------------------------------------------------
  923. // Function: GetWindowsDACLs
  924. //
  925. // Description:
  926. // Get the Windows DACs based the Unix access mask
  927. //
  928. // Returns:
  929. // ERROR_SUCCESS: on success
  930. // Error code: otherwise
  931. //
  932. // Notes:
  933. // - Administrators and SYSTEM are always given full permission to the file,
  934. // unless Administrators or SYSTEM itself is the file owner and the user
  935. // explictly set the permission to something else. For example, file 'foo'
  936. // belongs to Administrators, 'chmod 000' on the file will not directly
  937. // assign Administrators full permission on the file.
  938. // - Only full permission for Administrators and SYSTEM are inheritable.
  939. // - CREATOR OWNER is always given full permission and the permission is
  940. // inheritable, more specifically OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE
  941. // flags are set. The reason is to give the creator of child file full
  942. // permission, i.e., the child file will have permission mode 700 for
  943. // a user other than Administrator or SYSTEM.
  944. //
  945. static DWORD GetWindowsDACLs(__in INT unixMask,
  946. __in PSID pOwnerSid, __in PSID pGroupSid, __out PACL *ppNewDACL)
  947. {
  948. DWORD winUserAccessDenyMask;
  949. DWORD winUserAccessAllowMask;
  950. DWORD winGroupAccessDenyMask;
  951. DWORD winGroupAccessAllowMask;
  952. DWORD winOtherAccessAllowMask;
  953. PSID pEveryoneSid = NULL;
  954. DWORD cbEveryoneSidSize = SECURITY_MAX_SID_SIZE;
  955. PSID pSystemSid = NULL;
  956. DWORD cbSystemSidSize = SECURITY_MAX_SID_SIZE;
  957. BOOL bAddSystemAcls = FALSE;
  958. PSID pAdministratorsSid = NULL;
  959. DWORD cbAdministratorsSidSize = SECURITY_MAX_SID_SIZE;
  960. BOOL bAddAdministratorsAcls = FALSE;
  961. PSID pCreatorOwnerSid = NULL;
  962. DWORD cbCreatorOwnerSidSize = SECURITY_MAX_SID_SIZE;
  963. PACL pNewDACL = NULL;
  964. DWORD dwNewAclSize = 0;
  965. DWORD ret = ERROR_SUCCESS;
  966. GetWindowsAccessMask(unixMask,
  967. &winUserAccessAllowMask, &winUserAccessDenyMask,
  968. &winGroupAccessAllowMask, &winGroupAccessDenyMask,
  969. &winOtherAccessAllowMask);
  970. // Create a well-known SID for the Everyone group
  971. //
  972. if ((pEveryoneSid = LocalAlloc(LPTR, cbEveryoneSidSize)) == NULL)
  973. {
  974. ret = GetLastError();
  975. goto GetWindowsDACLsEnd;
  976. }
  977. if (!CreateWellKnownSid(WinWorldSid, NULL, pEveryoneSid, &cbEveryoneSidSize))
  978. {
  979. ret = GetLastError();
  980. goto GetWindowsDACLsEnd;
  981. }
  982. // Create a well-known SID for the Administrators group
  983. //
  984. if ((pAdministratorsSid = LocalAlloc(LPTR, cbAdministratorsSidSize)) == NULL)
  985. {
  986. ret = GetLastError();
  987. goto GetWindowsDACLsEnd;
  988. }
  989. if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL,
  990. pAdministratorsSid, &cbAdministratorsSidSize))
  991. {
  992. ret = GetLastError();
  993. goto GetWindowsDACLsEnd;
  994. }
  995. if (!EqualSid(pAdministratorsSid, pOwnerSid)
  996. && !EqualSid(pAdministratorsSid, pGroupSid))
  997. bAddAdministratorsAcls = TRUE;
  998. // Create a well-known SID for the SYSTEM
  999. //
  1000. if ((pSystemSid = LocalAlloc(LPTR, cbSystemSidSize)) == NULL)
  1001. {
  1002. ret = GetLastError();
  1003. goto GetWindowsDACLsEnd;
  1004. }
  1005. if (!CreateWellKnownSid(WinLocalSystemSid, NULL,
  1006. pSystemSid, &cbSystemSidSize))
  1007. {
  1008. ret = GetLastError();
  1009. goto GetWindowsDACLsEnd;
  1010. }
  1011. if (!EqualSid(pSystemSid, pOwnerSid)
  1012. && !EqualSid(pSystemSid, pGroupSid))
  1013. bAddSystemAcls = TRUE;
  1014. // Create a well-known SID for the Creator Owner
  1015. //
  1016. if ((pCreatorOwnerSid = LocalAlloc(LPTR, cbCreatorOwnerSidSize)) == NULL)
  1017. {
  1018. ret = GetLastError();
  1019. goto GetWindowsDACLsEnd;
  1020. }
  1021. if (!CreateWellKnownSid(WinCreatorOwnerSid, NULL,
  1022. pCreatorOwnerSid, &cbCreatorOwnerSidSize))
  1023. {
  1024. ret = GetLastError();
  1025. goto GetWindowsDACLsEnd;
  1026. }
  1027. // Create the new DACL
  1028. //
  1029. dwNewAclSize = sizeof(ACL);
  1030. dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
  1031. GetLengthSid(pOwnerSid) - sizeof(DWORD);
  1032. if (winUserAccessDenyMask)
  1033. dwNewAclSize += sizeof(ACCESS_DENIED_ACE) +
  1034. GetLengthSid(pOwnerSid) - sizeof(DWORD);
  1035. dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
  1036. GetLengthSid(pGroupSid) - sizeof(DWORD);
  1037. if (winGroupAccessDenyMask)
  1038. dwNewAclSize += sizeof(ACCESS_DENIED_ACE) +
  1039. GetLengthSid(pGroupSid) - sizeof(DWORD);
  1040. dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
  1041. GetLengthSid(pEveryoneSid) - sizeof(DWORD);
  1042. if (bAddSystemAcls)
  1043. {
  1044. dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
  1045. cbSystemSidSize - sizeof(DWORD);
  1046. }
  1047. if (bAddAdministratorsAcls)
  1048. {
  1049. dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
  1050. cbAdministratorsSidSize - sizeof(DWORD);
  1051. }
  1052. dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
  1053. cbCreatorOwnerSidSize - sizeof(DWORD);
  1054. pNewDACL = (PACL)LocalAlloc(LPTR, dwNewAclSize);
  1055. if (pNewDACL == NULL)
  1056. {
  1057. ret = GetLastError();
  1058. goto GetWindowsDACLsEnd;
  1059. }
  1060. if (!InitializeAcl(pNewDACL, dwNewAclSize, ACL_REVISION))
  1061. {
  1062. ret = GetLastError();
  1063. goto GetWindowsDACLsEnd;
  1064. }
  1065. if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
  1066. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1067. GENERIC_ALL, pCreatorOwnerSid))
  1068. {
  1069. ret = GetLastError();
  1070. goto GetWindowsDACLsEnd;
  1071. }
  1072. if (bAddSystemAcls &&
  1073. !AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
  1074. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1075. GENERIC_ALL, pSystemSid))
  1076. {
  1077. ret = GetLastError();
  1078. goto GetWindowsDACLsEnd;
  1079. }
  1080. if (bAddAdministratorsAcls &&
  1081. !AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
  1082. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1083. GENERIC_ALL, pAdministratorsSid))
  1084. {
  1085. ret = GetLastError();
  1086. goto GetWindowsDACLsEnd;
  1087. }
  1088. if (winUserAccessDenyMask &&
  1089. !AddAccessDeniedAceEx(pNewDACL, ACL_REVISION,
  1090. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1091. winUserAccessDenyMask, pOwnerSid))
  1092. {
  1093. ret = GetLastError();
  1094. goto GetWindowsDACLsEnd;
  1095. }
  1096. if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
  1097. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1098. winUserAccessAllowMask, pOwnerSid))
  1099. {
  1100. ret = GetLastError();
  1101. goto GetWindowsDACLsEnd;
  1102. }
  1103. if (winGroupAccessDenyMask &&
  1104. !AddAccessDeniedAceEx(pNewDACL, ACL_REVISION,
  1105. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1106. winGroupAccessDenyMask, pGroupSid))
  1107. {
  1108. ret = GetLastError();
  1109. goto GetWindowsDACLsEnd;
  1110. }
  1111. if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
  1112. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1113. winGroupAccessAllowMask, pGroupSid))
  1114. {
  1115. ret = GetLastError();
  1116. goto GetWindowsDACLsEnd;
  1117. }
  1118. if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
  1119. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  1120. winOtherAccessAllowMask, pEveryoneSid))
  1121. {
  1122. ret = GetLastError();
  1123. goto GetWindowsDACLsEnd;
  1124. }
  1125. *ppNewDACL = pNewDACL;
  1126. GetWindowsDACLsEnd:
  1127. LocalFree(pEveryoneSid);
  1128. LocalFree(pAdministratorsSid);
  1129. LocalFree(pSystemSid);
  1130. LocalFree(pCreatorOwnerSid);
  1131. if (ret != ERROR_SUCCESS) LocalFree(pNewDACL);
  1132. return ret;
  1133. }
  1134. //----------------------------------------------------------------------------
  1135. // Function: ChangeFileModeByMask
  1136. //
  1137. // Description:
  1138. // Change a file or direcotry at the path to Unix mode
  1139. //
  1140. // Returns:
  1141. // ERROR_SUCCESS: on success
  1142. // Error code: otherwise
  1143. //
  1144. // Notes:
  1145. // This function is long path safe, i.e. the path will be converted to long
  1146. // path format if not already converted. So the caller does not need to do
  1147. // the converstion before calling the method.
  1148. //
  1149. DWORD ChangeFileModeByMask(__in LPCWSTR path, INT mode)
  1150. {
  1151. LPWSTR longPathName = NULL;
  1152. PACL pNewDACL = NULL;
  1153. PSID pOwnerSid = NULL;
  1154. PSID pGroupSid = NULL;
  1155. PSECURITY_DESCRIPTOR pSD = NULL;
  1156. SECURITY_DESCRIPTOR_CONTROL control;
  1157. DWORD revision = 0;
  1158. PSECURITY_DESCRIPTOR pAbsSD = NULL;
  1159. PSECURITY_DESCRIPTOR pNonNullSD = NULL;
  1160. PACL pAbsDacl = NULL;
  1161. PACL pAbsSacl = NULL;
  1162. PSID pAbsOwner = NULL;
  1163. PSID pAbsGroup = NULL;
  1164. DWORD dwRtnCode = 0;
  1165. DWORD dwErrorCode = 0;
  1166. DWORD ret = ERROR_SUCCESS;
  1167. dwRtnCode = ConvertToLongPath(path, &longPathName);
  1168. if (dwRtnCode != ERROR_SUCCESS)
  1169. {
  1170. ret = dwRtnCode;
  1171. goto ChangeFileModeByMaskEnd;
  1172. }
  1173. // Get owner and group Sids
  1174. //
  1175. dwRtnCode = GetNamedSecurityInfoW(
  1176. longPathName,
  1177. SE_FILE_OBJECT,
  1178. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
  1179. &pOwnerSid,
  1180. &pGroupSid,
  1181. NULL,
  1182. NULL,
  1183. &pSD);
  1184. if (ERROR_SUCCESS != dwRtnCode)
  1185. {
  1186. ret = dwRtnCode;
  1187. goto ChangeFileModeByMaskEnd;
  1188. }
  1189. // SetSecurityDescriptorDacl function used below only accepts security
  1190. // descriptor in absolute format, meaning that its members must be pointers to
  1191. // other structures, rather than offsets to contiguous data.
  1192. // To determine whether a security descriptor is self-relative or absolute,
  1193. // call the GetSecurityDescriptorControl function and check the
  1194. // SE_SELF_RELATIVE flag of the SECURITY_DESCRIPTOR_CONTROL parameter.
  1195. //
  1196. if (!GetSecurityDescriptorControl(pSD, &control, &revision))
  1197. {
  1198. ret = GetLastError();
  1199. goto ChangeFileModeByMaskEnd;
  1200. }
  1201. // If the security descriptor is self-relative, we use MakeAbsoluteSD function
  1202. // to convert it to absolute format.
  1203. //
  1204. if ((control & SE_SELF_RELATIVE) == SE_SELF_RELATIVE)
  1205. {
  1206. DWORD absSDSize = 0;
  1207. DWORD daclSize = 0;
  1208. DWORD saclSize = 0;
  1209. DWORD ownerSize = 0;
  1210. DWORD primaryGroupSize = 0;
  1211. MakeAbsoluteSD(pSD, NULL, &absSDSize, NULL, &daclSize, NULL,
  1212. &saclSize, NULL, &ownerSize, NULL, &primaryGroupSize);
  1213. if ((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  1214. {
  1215. ret = dwErrorCode;
  1216. goto ChangeFileModeByMaskEnd;
  1217. }
  1218. if ((pAbsSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, absSDSize)) == NULL)
  1219. {
  1220. ret = GetLastError();
  1221. goto ChangeFileModeByMaskEnd;
  1222. }
  1223. if ((pAbsDacl = (PACL) LocalAlloc(LPTR, daclSize)) == NULL)
  1224. {
  1225. ret = GetLastError();
  1226. goto ChangeFileModeByMaskEnd;
  1227. }
  1228. if ((pAbsSacl = (PACL) LocalAlloc(LPTR, saclSize)) == NULL)
  1229. {
  1230. ret = GetLastError();
  1231. goto ChangeFileModeByMaskEnd;
  1232. }
  1233. if ((pAbsOwner = (PSID) LocalAlloc(LPTR, ownerSize)) == NULL)
  1234. {
  1235. ret = GetLastError();
  1236. goto ChangeFileModeByMaskEnd;
  1237. }
  1238. if ((pAbsGroup = (PSID) LocalAlloc(LPTR, primaryGroupSize)) == NULL)
  1239. {
  1240. ret = GetLastError();
  1241. goto ChangeFileModeByMaskEnd;
  1242. }
  1243. if (!MakeAbsoluteSD(pSD, pAbsSD, &absSDSize, pAbsDacl, &daclSize, pAbsSacl,
  1244. &saclSize, pAbsOwner, &ownerSize, pAbsGroup, &primaryGroupSize))
  1245. {
  1246. ret = GetLastError();
  1247. goto ChangeFileModeByMaskEnd;
  1248. }
  1249. }
  1250. // Get Windows DACLs based on Unix access mask
  1251. //
  1252. if ((dwRtnCode = GetWindowsDACLs(mode, pOwnerSid, pGroupSid, &pNewDACL))
  1253. != ERROR_SUCCESS)
  1254. {
  1255. ret = dwRtnCode;
  1256. goto ChangeFileModeByMaskEnd;
  1257. }
  1258. // Set the DACL information in the security descriptor; if a DACL is already
  1259. // present in the security descriptor, the DACL is replaced. The security
  1260. // descriptor is then used to set the security of a file or directory.
  1261. //
  1262. pNonNullSD = (pAbsSD != NULL) ? pAbsSD : pSD;
  1263. if (!SetSecurityDescriptorDacl(pNonNullSD, TRUE, pNewDACL, FALSE))
  1264. {
  1265. ret = GetLastError();
  1266. goto ChangeFileModeByMaskEnd;
  1267. }
  1268. // MSDN states "This function is obsolete. Use the SetNamedSecurityInfo
  1269. // function instead." However we have the following problem when using
  1270. // SetNamedSecurityInfo:
  1271. // - When PROTECTED_DACL_SECURITY_INFORMATION is not passed in as part of
  1272. // security information, the object will include inheritable permissions
  1273. // from its parent.
  1274. // - When PROTECTED_DACL_SECURITY_INFORMATION is passsed in to set
  1275. // permissions on a directory, the child object of the directory will lose
  1276. // inheritable permissions from their parent (the current directory).
  1277. // By using SetFileSecurity, we have the nice property that the new
  1278. // permissions of the object does not include the inheritable permissions from
  1279. // its parent, and the child objects will not lose their inherited permissions
  1280. // from the current object.
  1281. //
  1282. if (!SetFileSecurity(longPathName, DACL_SECURITY_INFORMATION, pNonNullSD))
  1283. {
  1284. ret = GetLastError();
  1285. goto ChangeFileModeByMaskEnd;
  1286. }
  1287. ChangeFileModeByMaskEnd:
  1288. pNonNullSD = NULL;
  1289. LocalFree(longPathName);
  1290. LocalFree(pSD);
  1291. LocalFree(pNewDACL);
  1292. LocalFree(pAbsDacl);
  1293. LocalFree(pAbsSacl);
  1294. LocalFree(pAbsOwner);
  1295. LocalFree(pAbsGroup);
  1296. LocalFree(pAbsSD);
  1297. return ret;
  1298. }
  1299. //----------------------------------------------------------------------------
  1300. // Function: GetAccntNameFromSid
  1301. //
  1302. // Description:
  1303. // To retrieve an account name given the SID
  1304. //
  1305. // Returns:
  1306. // ERROR_SUCCESS: on success
  1307. // Other error code: otherwise
  1308. //
  1309. // Notes:
  1310. // Caller needs to destroy the memory of account name by calling LocalFree()
  1311. //
  1312. DWORD GetAccntNameFromSid(__in PSID pSid, __out PWSTR *ppAcctName)
  1313. {
  1314. LPWSTR lpName = NULL;
  1315. DWORD cchName = 0;
  1316. LPWSTR lpDomainName = NULL;
  1317. DWORD cchDomainName = 0;
  1318. SID_NAME_USE eUse = SidTypeUnknown;
  1319. DWORD cchAcctName = 0;
  1320. DWORD dwErrorCode = ERROR_SUCCESS;
  1321. HRESULT hr = S_OK;
  1322. DWORD ret = ERROR_SUCCESS;
  1323. assert(ppAcctName != NULL);
  1324. // NOTE:
  1325. // MSDN says the length returned for the buffer size including the terminating
  1326. // null character. However we found it is not true during debuging.
  1327. //
  1328. LookupAccountSid(NULL, pSid, NULL, &cchName, NULL, &cchDomainName, &eUse);
  1329. if ((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  1330. return dwErrorCode;
  1331. lpName = (LPWSTR) LocalAlloc(LPTR, (cchName + 1) * sizeof(WCHAR));
  1332. if (lpName == NULL)
  1333. {
  1334. ret = GetLastError();
  1335. goto GetAccntNameFromSidEnd;
  1336. }
  1337. lpDomainName = (LPWSTR) LocalAlloc(LPTR, (cchDomainName + 1) * sizeof(WCHAR));
  1338. if (lpDomainName == NULL)
  1339. {
  1340. ret = GetLastError();
  1341. goto GetAccntNameFromSidEnd;
  1342. }
  1343. if (!LookupAccountSid(NULL, pSid,
  1344. lpName, &cchName, lpDomainName, &cchDomainName, &eUse))
  1345. {
  1346. ret = GetLastError();
  1347. goto GetAccntNameFromSidEnd;
  1348. }
  1349. // Buffer size = name length + 1 for '\' + domain length + 1 for NULL
  1350. cchAcctName = cchName + cchDomainName + 2;
  1351. *ppAcctName = (LPWSTR) LocalAlloc(LPTR, cchAcctName * sizeof(WCHAR));
  1352. if (*ppAcctName == NULL)
  1353. {
  1354. ret = GetLastError();
  1355. goto GetAccntNameFromSidEnd;
  1356. }
  1357. hr = StringCchCopyW(*ppAcctName, cchAcctName, lpDomainName);
  1358. if (FAILED(hr))
  1359. {
  1360. ret = HRESULT_CODE(hr);
  1361. goto GetAccntNameFromSidEnd;
  1362. }
  1363. hr = StringCchCatW(*ppAcctName, cchAcctName, L"\\");
  1364. if (FAILED(hr))
  1365. {
  1366. ret = HRESULT_CODE(hr);
  1367. goto GetAccntNameFromSidEnd;
  1368. }
  1369. hr = StringCchCatW(*ppAcctName, cchAcctName, lpName);
  1370. if (FAILED(hr))
  1371. {
  1372. ret = HRESULT_CODE(hr);
  1373. goto GetAccntNameFromSidEnd;
  1374. }
  1375. GetAccntNameFromSidEnd:
  1376. LocalFree(lpName);
  1377. LocalFree(lpDomainName);
  1378. if (ret != ERROR_SUCCESS)
  1379. {
  1380. LocalFree(*ppAcctName);
  1381. *ppAcctName = NULL;
  1382. }
  1383. return ret;
  1384. }
  1385. //----------------------------------------------------------------------------
  1386. // Function: GetLocalGroupsForUser
  1387. //
  1388. // Description:
  1389. // Get an array of groups for the given user.
  1390. //
  1391. // Returns:
  1392. // ERROR_SUCCESS on success
  1393. // Other error code on failure
  1394. //
  1395. // Notes:
  1396. // - NetUserGetLocalGroups() function only accepts full user name in the format
  1397. // [domain name]\[username]. The user input to this function can be only the
  1398. // username. In this case, NetUserGetLocalGroups() will fail on the first try,
  1399. // and we will try to find full user name using LookupAccountNameW() method,
  1400. // and call NetUserGetLocalGroups() function again with full user name.
  1401. // However, it is not always possible to find full user name given only user
  1402. // name. For example, a computer named 'win1' joined domain 'redmond' can have
  1403. // two different users, 'win1\alex' and 'redmond\alex'. Given only 'alex', we
  1404. // cannot tell which one is correct.
  1405. //
  1406. // - Caller needs to destroy the memory of groups by using the
  1407. // NetApiBufferFree() function
  1408. //
  1409. DWORD GetLocalGroupsForUser(
  1410. __in LPCWSTR user,
  1411. __out LPLOCALGROUP_USERS_INFO_0 *groups,
  1412. __out LPDWORD entries)
  1413. {
  1414. DWORD dwEntriesRead = 0;
  1415. DWORD dwTotalEntries = 0;
  1416. NET_API_STATUS nStatus = NERR_Success;
  1417. PSID pUserSid = NULL;
  1418. LPWSTR fullName = NULL;
  1419. DWORD dwRtnCode = ERROR_SUCCESS;
  1420. DWORD ret = ERROR_SUCCESS;
  1421. *groups = NULL;
  1422. *entries = 0;
  1423. nStatus = NetUserGetLocalGroups(NULL,
  1424. user,
  1425. 0,
  1426. 0,
  1427. (LPBYTE *) groups,
  1428. MAX_PREFERRED_LENGTH,
  1429. &dwEntriesRead,
  1430. &dwTotalEntries);
  1431. if (nStatus == NERR_Success)
  1432. {
  1433. *entries = dwEntriesRead;
  1434. return ERROR_SUCCESS;
  1435. }
  1436. else if (nStatus != NERR_UserNotFound)
  1437. {
  1438. return nStatus;
  1439. }
  1440. if ((dwRtnCode = GetSidFromAcctNameW(user, &pUserSid)) != ERROR_SUCCESS)
  1441. {
  1442. ret = dwRtnCode;
  1443. goto GetLocalGroupsForUserEnd;
  1444. }
  1445. if ((dwRtnCode = GetAccntNameFromSid(pUserSid, &fullName)) != ERROR_SUCCESS)
  1446. {
  1447. ret = dwRtnCode;
  1448. goto GetLocalGroupsForUserEnd;
  1449. }
  1450. nStatus = NetUserGetLocalGroups(NULL,
  1451. fullName,
  1452. 0,
  1453. 0,
  1454. (LPBYTE *) groups,
  1455. MAX_PREFERRED_LENGTH,
  1456. &dwEntriesRead,
  1457. &dwTotalEntries);
  1458. if (nStatus != NERR_Success)
  1459. {
  1460. // NERR_DCNotFound (2453) and NERR_UserNotFound (2221) are not published
  1461. // Windows System Error Code. All other error codes returned by
  1462. // NetUserGetLocalGroups() are valid System Error Codes according to MSDN.
  1463. ret = nStatus;
  1464. goto GetLocalGroupsForUserEnd;
  1465. }
  1466. *entries = dwEntriesRead;
  1467. GetLocalGroupsForUserEnd:
  1468. LocalFree(pUserSid);
  1469. LocalFree(fullName);
  1470. return ret;
  1471. }
  1472. //----------------------------------------------------------------------------
  1473. // Function: EnablePrivilege
  1474. //
  1475. // Description:
  1476. // Check if the process has the given privilege. If yes, enable the privilege
  1477. // to the process's access token.
  1478. //
  1479. // Returns:
  1480. // ERROR_SUCCESS on success
  1481. // GetLastError() on error
  1482. //
  1483. // Notes:
  1484. //
  1485. DWORD EnablePrivilege(__in LPCWSTR privilegeName)
  1486. {
  1487. HANDLE hToken = INVALID_HANDLE_VALUE;
  1488. TOKEN_PRIVILEGES tp = { 0 };
  1489. DWORD dwErrCode = ERROR_SUCCESS;
  1490. if (!OpenProcessToken(GetCurrentProcess(),
  1491. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
  1492. {
  1493. dwErrCode = GetLastError();
  1494. ReportErrorCode(L"OpenProcessToken", dwErrCode);
  1495. return dwErrCode;
  1496. }
  1497. tp.PrivilegeCount = 1;
  1498. if (!LookupPrivilegeValueW(NULL,
  1499. privilegeName, &(tp.Privileges[0].Luid)))
  1500. {
  1501. dwErrCode = GetLastError();
  1502. ReportErrorCode(L"LookupPrivilegeValue", dwErrCode);
  1503. CloseHandle(hToken);
  1504. return dwErrCode;
  1505. }
  1506. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1507. // As stated on MSDN, we need to use GetLastError() to check if
  1508. // AdjustTokenPrivileges() adjusted all of the specified privileges.
  1509. //
  1510. if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) {
  1511. dwErrCode = GetLastError();
  1512. }
  1513. CloseHandle(hToken);
  1514. return dwErrCode;
  1515. }
  1516. //----------------------------------------------------------------------------
  1517. // Function: ReportErrorCode
  1518. //
  1519. // Description:
  1520. // Report an error. Use FormatMessage function to get the system error message.
  1521. //
  1522. // Returns:
  1523. // None
  1524. //
  1525. // Notes:
  1526. //
  1527. //
  1528. void ReportErrorCode(LPCWSTR func, DWORD err)
  1529. {
  1530. DWORD len = 0;
  1531. LPWSTR msg = NULL;
  1532. assert(func != NULL);
  1533. len = FormatMessageW(
  1534. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  1535. NULL, err,
  1536. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1537. (LPWSTR)&msg, 0, NULL);
  1538. if (len > 0)
  1539. {
  1540. LogDebugMessage(L"%s error (%d): %s\n", func, err, msg);
  1541. fwprintf(stderr, L"%s error (%d): %s\n", func, err, msg);
  1542. }
  1543. else
  1544. {
  1545. LogDebugMessage(L"%s error code: %d.\n", func, err);
  1546. fwprintf(stderr, L"%s error code: %d.\n", func, err);
  1547. }
  1548. if (msg != NULL) LocalFree(msg);
  1549. }
  1550. //----------------------------------------------------------------------------
  1551. // Function: GetLibraryName
  1552. //
  1553. // Description:
  1554. // Given an address, get the file name of the library from which it was loaded.
  1555. //
  1556. // Notes:
  1557. // - The function allocates heap memory and points the filename out parameter to
  1558. // the newly allocated memory, which will contain the name of the file.
  1559. //
  1560. // - If there is any failure, then the function frees the heap memory it
  1561. // allocated and sets the filename out parameter to NULL.
  1562. //
  1563. void GetLibraryName(LPCVOID lpAddress, LPWSTR *filename)
  1564. {
  1565. SIZE_T ret = 0;
  1566. DWORD size = MAX_PATH;
  1567. HMODULE mod = NULL;
  1568. DWORD err = ERROR_SUCCESS;
  1569. MEMORY_BASIC_INFORMATION mbi;
  1570. ret = VirtualQuery(lpAddress, &mbi, sizeof(mbi));
  1571. if (ret == 0) goto cleanup;
  1572. mod = mbi.AllocationBase;
  1573. do {
  1574. *filename = (LPWSTR) realloc(*filename, size * sizeof(WCHAR));
  1575. if (*filename == NULL) goto cleanup;
  1576. GetModuleFileName(mod, *filename, size);
  1577. size <<= 1;
  1578. err = GetLastError();
  1579. } while (err == ERROR_INSUFFICIENT_BUFFER);
  1580. if (err != ERROR_SUCCESS) goto cleanup;
  1581. return;
  1582. cleanup:
  1583. if (*filename != NULL)
  1584. {
  1585. free(*filename);
  1586. *filename = NULL;
  1587. }
  1588. }
  1589. // Function: AssignLsaString
  1590. //
  1591. // Description:
  1592. // fills in values of LSA_STRING struct to point to a string buffer
  1593. //
  1594. // Returns:
  1595. // None
  1596. //
  1597. // IMPORTANT*** strBuf is not copied. It must be globally immutable
  1598. //
  1599. void AssignLsaString(__inout LSA_STRING * target, __in const char *strBuf)
  1600. {
  1601. target->Length = (USHORT)(sizeof(char)*strlen(strBuf));
  1602. target->MaximumLength = target->Length;
  1603. target->Buffer = (char *)(strBuf);
  1604. }
  1605. //----------------------------------------------------------------------------
  1606. // Function: RegisterWithLsa
  1607. //
  1608. // Description:
  1609. // Registers with local security authority and sets handle for use in later LSA
  1610. // operations
  1611. //
  1612. // Returns:
  1613. // ERROR_SUCCESS on success
  1614. // Other error code on failure
  1615. //
  1616. // Notes:
  1617. //
  1618. DWORD RegisterWithLsa(__in const char *logonProcessName, __out HANDLE * lsaHandle)
  1619. {
  1620. LSA_STRING processName;
  1621. LSA_OPERATIONAL_MODE o_mode; // never useful as per msdn docs
  1622. NTSTATUS registerStatus;
  1623. *lsaHandle = 0;
  1624. AssignLsaString(&processName, logonProcessName);
  1625. registerStatus = LsaRegisterLogonProcess(&processName, lsaHandle, &o_mode);
  1626. return LsaNtStatusToWinError( registerStatus );
  1627. }
  1628. //----------------------------------------------------------------------------
  1629. // Function: UnregisterWithLsa
  1630. //
  1631. // Description:
  1632. // Closes LSA handle allocated by RegisterWithLsa()
  1633. //
  1634. // Returns:
  1635. // None
  1636. //
  1637. // Notes:
  1638. //
  1639. void UnregisterWithLsa(__in HANDLE lsaHandle)
  1640. {
  1641. LsaClose(lsaHandle);
  1642. }
  1643. //----------------------------------------------------------------------------
  1644. // Function: LookupKerberosAuthenticationPackageId
  1645. //
  1646. // Description:
  1647. // Looks of the current id (integer index) of the Kerberos authentication package on the local
  1648. // machine.
  1649. //
  1650. // Returns:
  1651. // ERROR_SUCCESS on success
  1652. // Other error code on failure
  1653. //
  1654. // Notes:
  1655. //
  1656. DWORD LookupKerberosAuthenticationPackageId(__in HANDLE lsaHandle, __out ULONG * packageId)
  1657. {
  1658. NTSTATUS lookupStatus;
  1659. LSA_STRING pkgName;
  1660. AssignLsaString(&pkgName, MICROSOFT_KERBEROS_NAME_A);
  1661. lookupStatus = LsaLookupAuthenticationPackage(lsaHandle, &pkgName, packageId);
  1662. return LsaNtStatusToWinError( lookupStatus );
  1663. }
  1664. //----------------------------------------------------------------------------
  1665. // Function: CreateLogonTokenForUser
  1666. //
  1667. // Description:
  1668. // Contacts the local LSA and performs a logon without credential for the
  1669. // given principal. This logon token will be local machine only and have no
  1670. // network credentials attached.
  1671. //
  1672. // Returns:
  1673. // ERROR_SUCCESS on success
  1674. // Other error code on failure
  1675. //
  1676. // Notes:
  1677. // This call assumes that all required privileges have already been enabled (TCB etc).
  1678. // IMPORTANT **** tokenOriginName must be immutable!
  1679. //
  1680. DWORD CreateLogonTokenForUser(__in HANDLE lsaHandle,
  1681. __in const char * tokenSourceName,
  1682. __in const char * tokenOriginName, // must be immutable, will not be copied!
  1683. __in ULONG authnPkgId,
  1684. __in const wchar_t* principalName,
  1685. __out HANDLE *tokenHandle)
  1686. {
  1687. DWORD logonStatus = ERROR_ASSERTION_FAILURE; // Failure to set status should trigger error
  1688. TOKEN_SOURCE tokenSource;
  1689. LSA_STRING originName;
  1690. void * profile = NULL;
  1691. // from MSDN:
  1692. // The ClientUpn and ClientRealm members of the KERB_S4U_LOGON
  1693. // structure must point to buffers in memory that are contiguous
  1694. // to the structure itself. The value of the
  1695. // AuthenticationInformationLength parameter must take into
  1696. // account the length of these buffers.
  1697. const int principalNameBufLen = lstrlen(principalName)*sizeof(*principalName);
  1698. const int totalAuthInfoLen = sizeof(KERB_S4U_LOGON) + principalNameBufLen;
  1699. KERB_S4U_LOGON* s4uLogonAuthInfo = (KERB_S4U_LOGON*)calloc(totalAuthInfoLen, 1);
  1700. if (s4uLogonAuthInfo == NULL ) {
  1701. logonStatus = ERROR_NOT_ENOUGH_MEMORY;
  1702. goto done;
  1703. }
  1704. s4uLogonAuthInfo->MessageType = KerbS4ULogon;
  1705. s4uLogonAuthInfo->ClientUpn.Buffer = (wchar_t*)((char*)s4uLogonAuthInfo + sizeof *s4uLogonAuthInfo);
  1706. CopyMemory(s4uLogonAuthInfo->ClientUpn.Buffer, principalName, principalNameBufLen);
  1707. s4uLogonAuthInfo->ClientUpn.Length = (USHORT)principalNameBufLen;
  1708. s4uLogonAuthInfo->ClientUpn.MaximumLength = (USHORT)principalNameBufLen;
  1709. AllocateLocallyUniqueId(&tokenSource.SourceIdentifier);
  1710. StringCchCopyA(tokenSource.SourceName, TOKEN_SOURCE_LENGTH, tokenSourceName );
  1711. AssignLsaString(&originName, tokenOriginName);
  1712. {
  1713. DWORD cbProfile = 0;
  1714. LUID logonId;
  1715. QUOTA_LIMITS quotaLimits;
  1716. NTSTATUS subStatus;
  1717. NTSTATUS logonNtStatus = LsaLogonUser(lsaHandle,
  1718. &originName,
  1719. Batch, // SECURITY_LOGON_TYPE
  1720. authnPkgId,
  1721. s4uLogonAuthInfo,
  1722. totalAuthInfoLen,
  1723. 0,
  1724. &tokenSource,
  1725. &profile,
  1726. &cbProfile,
  1727. &logonId,
  1728. tokenHandle,
  1729. &quotaLimits,
  1730. &subStatus);
  1731. logonStatus = LsaNtStatusToWinError( logonNtStatus );
  1732. }
  1733. done:
  1734. // clean up
  1735. if (s4uLogonAuthInfo != NULL) {
  1736. free(s4uLogonAuthInfo);
  1737. }
  1738. if (profile != NULL) {
  1739. LsaFreeReturnBuffer(profile);
  1740. }
  1741. return logonStatus;
  1742. }
  1743. // NOTE: must free allocatedName
  1744. DWORD GetNameFromLogonToken(__in HANDLE logonToken, __out wchar_t **allocatedName)
  1745. {
  1746. DWORD userInfoSize = 0;
  1747. PTOKEN_USER user = NULL;
  1748. DWORD userNameSize = 0;
  1749. wchar_t * userName = NULL;
  1750. DWORD domainNameSize = 0;
  1751. wchar_t * domainName = NULL;
  1752. SID_NAME_USE sidUse = SidTypeUnknown;
  1753. DWORD getNameStatus = ERROR_ASSERTION_FAILURE; // Failure to set status should trigger error
  1754. BOOL tokenInformation = FALSE;
  1755. // call for sid size then alloc and call for sid
  1756. tokenInformation = GetTokenInformation(logonToken, TokenUser, NULL, 0, &userInfoSize);
  1757. assert (FALSE == tokenInformation);
  1758. // last call should have failed and filled in allocation size
  1759. if ((getNameStatus = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  1760. {
  1761. goto done;
  1762. }
  1763. user = (PTOKEN_USER)calloc(userInfoSize,1);
  1764. if (user == NULL)
  1765. {
  1766. getNameStatus = ERROR_NOT_ENOUGH_MEMORY;
  1767. goto done;
  1768. }
  1769. if (!GetTokenInformation(logonToken, TokenUser, user, userInfoSize, &userInfoSize)) {
  1770. getNameStatus = GetLastError();
  1771. goto done;
  1772. }
  1773. LookupAccountSid( NULL, user->User.Sid, NULL, &userNameSize, NULL, &domainNameSize, &sidUse );
  1774. // last call should have failed and filled in allocation size
  1775. if ((getNameStatus = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  1776. {
  1777. goto done;
  1778. }
  1779. userName = (wchar_t *)calloc(userNameSize, sizeof(wchar_t));
  1780. if (userName == NULL) {
  1781. getNameStatus = ERROR_NOT_ENOUGH_MEMORY;
  1782. goto done;
  1783. }
  1784. domainName = (wchar_t *)calloc(domainNameSize, sizeof(wchar_t));
  1785. if (domainName == NULL) {
  1786. getNameStatus = ERROR_NOT_ENOUGH_MEMORY;
  1787. goto done;
  1788. }
  1789. if (!LookupAccountSid( NULL, user->User.Sid, userName, &userNameSize, domainName, &domainNameSize, &sidUse )) {
  1790. getNameStatus = GetLastError();
  1791. goto done;
  1792. }
  1793. getNameStatus = ERROR_SUCCESS;
  1794. *allocatedName = userName;
  1795. userName = NULL;
  1796. done:
  1797. if (user != NULL) {
  1798. free( user );
  1799. user = NULL;
  1800. }
  1801. if (userName != NULL) {
  1802. free( userName );
  1803. userName = NULL;
  1804. }
  1805. if (domainName != NULL) {
  1806. free( domainName );
  1807. domainName = NULL;
  1808. }
  1809. return getNameStatus;
  1810. }
  1811. DWORD LoadUserProfileForLogon(__in HANDLE logonHandle, __out PROFILEINFO * pi)
  1812. {
  1813. wchar_t *userName = NULL;
  1814. DWORD loadProfileStatus = ERROR_ASSERTION_FAILURE; // Failure to set status should trigger error
  1815. loadProfileStatus = GetNameFromLogonToken( logonHandle, &userName );
  1816. if (loadProfileStatus != ERROR_SUCCESS) {
  1817. goto done;
  1818. }
  1819. assert(pi);
  1820. ZeroMemory( pi, sizeof(*pi) );
  1821. pi->dwSize = sizeof(*pi);
  1822. pi->lpUserName = userName;
  1823. pi->dwFlags = PI_NOUI;
  1824. // if the profile does not exist it will be created
  1825. if ( !LoadUserProfile( logonHandle, pi ) ) {
  1826. loadProfileStatus = GetLastError();
  1827. goto done;
  1828. }
  1829. loadProfileStatus = ERROR_SUCCESS;
  1830. done:
  1831. return loadProfileStatus;
  1832. }
  1833. DWORD UnloadProfileForLogon(__in HANDLE logonHandle, __in PROFILEINFO * pi)
  1834. {
  1835. DWORD touchProfileStatus = ERROR_ASSERTION_FAILURE; // Failure to set status should trigger error
  1836. assert(pi);
  1837. if ( !UnloadUserProfile(logonHandle, pi->hProfile ) ) {
  1838. touchProfileStatus = GetLastError();
  1839. goto done;
  1840. }
  1841. if (pi->lpUserName != NULL) {
  1842. free(pi->lpUserName);
  1843. pi->lpUserName = NULL;
  1844. }
  1845. ZeroMemory( pi, sizeof(*pi) );
  1846. touchProfileStatus = ERROR_SUCCESS;
  1847. done:
  1848. return touchProfileStatus;
  1849. }
  1850. //----------------------------------------------------------------------------
  1851. // Function: ChangeFileOwnerBySid
  1852. //
  1853. // Description:
  1854. // Change a file or directory ownership by giving new owner and group SIDs
  1855. //
  1856. // Returns:
  1857. // ERROR_SUCCESS: on success
  1858. // Error code: otherwise
  1859. //
  1860. // Notes:
  1861. // This function is long path safe, i.e. the path will be converted to long
  1862. // path format if not already converted. So the caller does not need to do
  1863. // the converstion before calling the method.
  1864. //
  1865. DWORD ChangeFileOwnerBySid(__in LPCWSTR path,
  1866. __in_opt PSID pNewOwnerSid, __in_opt PSID pNewGroupSid)
  1867. {
  1868. LPWSTR longPathName = NULL;
  1869. INT oldMode = 0;
  1870. SECURITY_INFORMATION securityInformation = 0;
  1871. DWORD dwRtnCode = ERROR_SUCCESS;
  1872. // Convert the path the the long path
  1873. //
  1874. dwRtnCode = ConvertToLongPath(path, &longPathName);
  1875. if (dwRtnCode != ERROR_SUCCESS)
  1876. {
  1877. goto ChangeFileOwnerByNameEnd;
  1878. }
  1879. // Get a pointer to the existing owner information and DACL
  1880. //
  1881. dwRtnCode = FindFileOwnerAndPermission(longPathName, FALSE, NULL, NULL, &oldMode);
  1882. if (dwRtnCode != ERROR_SUCCESS)
  1883. {
  1884. goto ChangeFileOwnerByNameEnd;
  1885. }
  1886. // We need SeTakeOwnershipPrivilege to set the owner if the caller does not
  1887. // have WRITE_OWNER access to the object; we need SeRestorePrivilege if the
  1888. // SID is not contained in the caller's token, and have the SE_GROUP_OWNER
  1889. // permission enabled.
  1890. //
  1891. if (EnablePrivilege(L"SeTakeOwnershipPrivilege") != ERROR_SUCCESS)
  1892. {
  1893. fwprintf(stdout, L"INFO: The user does not have SeTakeOwnershipPrivilege.\n");
  1894. }
  1895. if (EnablePrivilege(L"SeRestorePrivilege") != ERROR_SUCCESS)
  1896. {
  1897. fwprintf(stdout, L"INFO: The user does not have SeRestorePrivilege.\n");
  1898. }
  1899. assert(pNewOwnerSid != NULL || pNewGroupSid != NULL);
  1900. // Set the owners of the file.
  1901. //
  1902. if (pNewOwnerSid != NULL) securityInformation |= OWNER_SECURITY_INFORMATION;
  1903. if (pNewGroupSid != NULL) securityInformation |= GROUP_SECURITY_INFORMATION;
  1904. dwRtnCode = SetNamedSecurityInfoW(
  1905. longPathName,
  1906. SE_FILE_OBJECT,
  1907. securityInformation,
  1908. pNewOwnerSid,
  1909. pNewGroupSid,
  1910. NULL,
  1911. NULL);
  1912. if (dwRtnCode != ERROR_SUCCESS)
  1913. {
  1914. goto ChangeFileOwnerByNameEnd;
  1915. }
  1916. // Set the permission on the file for the new owner.
  1917. //
  1918. dwRtnCode = ChangeFileModeByMask(longPathName, oldMode);
  1919. if (dwRtnCode != ERROR_SUCCESS)
  1920. {
  1921. goto ChangeFileOwnerByNameEnd;
  1922. }
  1923. ChangeFileOwnerByNameEnd:
  1924. LocalFree(longPathName);
  1925. return dwRtnCode;
  1926. }
  1927. //-----------------------------------------------------------------------------
  1928. // Function: GetSecureJobObjectName
  1929. //
  1930. // Description:
  1931. // Creates a job object name usable in a secure environment: adds the Golbal\
  1932. //
  1933. DWORD GetSecureJobObjectName(
  1934. __in LPCWSTR jobName,
  1935. __in size_t cchSecureJobName,
  1936. __out_ecount(cchSecureJobName) LPWSTR secureJobName) {
  1937. HRESULT hr = StringCchPrintf(secureJobName, cchSecureJobName,
  1938. L"Global\\%s", jobName);
  1939. if (FAILED(hr)) {
  1940. return HRESULT_CODE(hr);
  1941. }
  1942. return ERROR_SUCCESS;
  1943. }
  1944. //-----------------------------------------------------------------------------
  1945. // Function: EnableImpersonatePrivileges
  1946. //
  1947. // Description:
  1948. // Enables the required privileges for S4U impersonation
  1949. //
  1950. // Returns:
  1951. // ERROR_SUCCESS: On success
  1952. //
  1953. DWORD EnableImpersonatePrivileges() {
  1954. DWORD dwError = ERROR_SUCCESS;
  1955. LPCWSTR privilege = NULL;
  1956. int crt = 0;
  1957. LPCWSTR privileges[] = {
  1958. SE_IMPERSONATE_NAME,
  1959. SE_TCB_NAME,
  1960. SE_ASSIGNPRIMARYTOKEN_NAME,
  1961. SE_INCREASE_QUOTA_NAME,
  1962. SE_RESTORE_NAME,
  1963. SE_DEBUG_NAME,
  1964. SE_SECURITY_NAME,
  1965. };
  1966. for (crt = 0; crt < sizeof(privileges)/sizeof(LPCWSTR); ++crt) {
  1967. LPCWSTR privilege = privileges[crt];
  1968. dwError = EnablePrivilege(privilege);
  1969. if( dwError != ERROR_SUCCESS ) {
  1970. LogDebugMessage(L"Failed to enable privilege: %s\n", privilege);
  1971. ReportErrorCode(L"EnablePrivilege", dwError);
  1972. goto done;
  1973. }
  1974. }
  1975. done:
  1976. return dwError;
  1977. }
  1978. //-----------------------------------------------------------------------------
  1979. // Function: KillTask
  1980. //
  1981. // Description:
  1982. // Kills a task via a jobobject. Outputs the
  1983. // appropriate information to stdout on success, or stderr on failure.
  1984. //
  1985. // Returns:
  1986. // ERROR_SUCCESS: On success
  1987. // GetLastError: otherwise
  1988. DWORD KillTask(PCWSTR jobObjName)
  1989. {
  1990. DWORD dwError = ERROR_SUCCESS;
  1991. HANDLE jobObject = OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, jobObjName);
  1992. if(jobObject == NULL)
  1993. {
  1994. dwError = GetLastError();
  1995. if(dwError == ERROR_FILE_NOT_FOUND)
  1996. {
  1997. // job object does not exist. assume its not alive
  1998. dwError = ERROR_SUCCESS;
  1999. }
  2000. goto done;
  2001. }
  2002. if(TerminateJobObject(jobObject, KILLED_PROCESS_EXIT_CODE) == 0)
  2003. {
  2004. dwError = GetLastError();
  2005. }
  2006. done:
  2007. CloseHandle(jobObject);
  2008. return dwError;
  2009. }
  2010. DWORD ChownImpl(
  2011. __in_opt LPCWSTR userName,
  2012. __in_opt LPCWSTR groupName,
  2013. __in LPCWSTR pathName) {
  2014. DWORD dwError;
  2015. PSID pNewOwnerSid = NULL;
  2016. PSID pNewGroupSid = NULL;
  2017. if (userName != NULL)
  2018. {
  2019. dwError = GetSidFromAcctNameW(userName, &pNewOwnerSid);
  2020. if (dwError != ERROR_SUCCESS)
  2021. {
  2022. ReportErrorCode(L"GetSidFromAcctName", dwError);
  2023. fwprintf(stderr, L"Invalid user name: %s\n", userName);
  2024. goto done;
  2025. }
  2026. }
  2027. if (groupName != NULL)
  2028. {
  2029. dwError = GetSidFromAcctNameW(groupName, &pNewGroupSid);
  2030. if (dwError != ERROR_SUCCESS)
  2031. {
  2032. ReportErrorCode(L"GetSidFromAcctName", dwError);
  2033. fwprintf(stderr, L"Invalid group name: %s\n", groupName);
  2034. goto done;
  2035. }
  2036. }
  2037. if (wcslen(pathName) == 0 || wcsspn(pathName, L"/?|><:*\"") != 0)
  2038. {
  2039. fwprintf(stderr, L"Incorrect file name format: %s\n", pathName);
  2040. goto done;
  2041. }
  2042. dwError = ChangeFileOwnerBySid(pathName, pNewOwnerSid, pNewGroupSid);
  2043. if (dwError != ERROR_SUCCESS)
  2044. {
  2045. ReportErrorCode(L"ChangeFileOwnerBySid", dwError);
  2046. goto done;
  2047. }
  2048. done:
  2049. LocalFree(pNewOwnerSid);
  2050. LocalFree(pNewGroupSid);
  2051. return dwError;
  2052. }
  2053. LPCWSTR GetSystemTimeString() {
  2054. __declspec(thread) static WCHAR buffer[1024];
  2055. DWORD dwError;
  2056. FILETIME ftime;
  2057. SYSTEMTIME systime;
  2058. LARGE_INTEGER counter, frequency;
  2059. int subSec;
  2060. double qpc;
  2061. HRESULT hr;
  2062. buffer[0] = L'\0';
  2063. // GetSystemTimePreciseAsFileTime is only available in Win8+ and our libs do not link against it
  2064. GetSystemTimeAsFileTime(&ftime);
  2065. if (!FileTimeToSystemTime(&ftime, &systime)) {
  2066. dwError = GetLastError();
  2067. LogDebugMessage(L"FileTimeToSystemTime error:%d\n", dwError);
  2068. goto done;
  2069. }
  2070. // Get the ms from QPC. GetSystemTimeAdjustment is ignored...
  2071. QueryPerformanceCounter(&counter);
  2072. QueryPerformanceFrequency(&frequency);
  2073. qpc = (double) counter.QuadPart / (double) frequency.QuadPart;
  2074. subSec = ((qpc - (long)qpc) * 1000000);
  2075. hr = StringCbPrintf(buffer, sizeof(buffer), L"%02d:%02d:%02d.%06d",
  2076. (int)systime.wHour, (int)systime.wMinute, (int)systime.wSecond, (int)subSec);
  2077. if (FAILED(hr)) {
  2078. LogDebugMessage(L"StringCbPrintf error:%d\n", hr);
  2079. }
  2080. done:
  2081. return buffer;
  2082. }
  2083. //----------------------------------------------------------------------------
  2084. // Function: LogDebugMessage
  2085. //
  2086. // Description:
  2087. // Sends a message to the debugger console, if one is attached
  2088. //
  2089. // Notes:
  2090. // Native debugger: windbg, ntsd, cdb, visual studio
  2091. //
  2092. VOID LogDebugMessage(LPCWSTR format, ...) {
  2093. LPWSTR buffer[8192];
  2094. va_list args;
  2095. HRESULT hr;
  2096. if (!IsDebuggerPresent()) return;
  2097. va_start(args, format);
  2098. hr = StringCbVPrintf(buffer, sizeof(buffer), format, args);
  2099. if (SUCCEEDED(hr)) {
  2100. OutputDebugString(buffer);
  2101. }
  2102. va_end(args);
  2103. }
  2104. //----------------------------------------------------------------------------
  2105. // Function: SplitStringIgnoreSpaceW
  2106. //
  2107. // Description:
  2108. // splits a null-terminated string based on a delimiter
  2109. //
  2110. // Returns:
  2111. // ERROR_SUCCESS: on success
  2112. // error code: otherwise
  2113. //
  2114. // Notes:
  2115. // The tokes are also null-terminated
  2116. // Caller should use LocalFree to clear outTokens
  2117. //
  2118. DWORD SplitStringIgnoreSpaceW(
  2119. __in size_t len,
  2120. __in_ecount(len) LPCWSTR source,
  2121. __in WCHAR deli,
  2122. __out size_t* count,
  2123. __out_ecount(count) WCHAR*** outTokens) {
  2124. size_t tokenCount = 0;
  2125. size_t crtSource;
  2126. size_t crtToken = 0;
  2127. WCHAR* lpwszTokenStart = NULL;
  2128. WCHAR* lpwszTokenEnd = NULL;
  2129. WCHAR* lpwszBuffer = NULL;
  2130. size_t tokenLength = 0;
  2131. size_t cchBufferLength = 0;
  2132. WCHAR crt;
  2133. WCHAR** tokens = NULL;
  2134. enum {BLANK, TOKEN, DELIMITER} State = BLANK;
  2135. for(crtSource = 0; crtSource < len; ++crtSource) {
  2136. crt = source[crtSource];
  2137. switch(State) {
  2138. case BLANK: // intentional fallthrough
  2139. case DELIMITER:
  2140. if (crt == deli) {
  2141. State = DELIMITER;
  2142. }
  2143. else if (!iswspace(crt)) {
  2144. ++tokenCount;
  2145. lpwszTokenEnd = lpwszTokenStart = source + crtSource;
  2146. State = TOKEN;
  2147. }
  2148. else {
  2149. State = BLANK;
  2150. }
  2151. break;
  2152. case TOKEN:
  2153. if (crt == deli) {
  2154. State = DELIMITER;
  2155. cchBufferLength += lpwszTokenEnd - lpwszTokenStart + 2;
  2156. }
  2157. else if (!iswspace(crt)) {
  2158. lpwszTokenEnd = source + crtSource;
  2159. }
  2160. break;
  2161. }
  2162. }
  2163. if (State == TOKEN) {
  2164. cchBufferLength += lpwszTokenEnd - lpwszTokenStart + 2;
  2165. }
  2166. LogDebugMessage(L"counted %d [buffer:%d] tokens in %s\n", tokenCount, cchBufferLength, source);
  2167. #define COPY_CURRENT_TOKEN \
  2168. tokenLength = lpwszTokenEnd - lpwszTokenStart + 1; \
  2169. tokens[crtToken] = lpwszBuffer; \
  2170. memcpy(tokens[crtToken], lpwszTokenStart, tokenLength*sizeof(WCHAR)); \
  2171. tokens[crtToken][tokenLength] = L'\0'; \
  2172. lpwszBuffer += (tokenLength+1); \
  2173. ++crtToken;
  2174. if (tokenCount) {
  2175. // We use one contigous memory for both the pointer arrays and the data copy buffers
  2176. // We cannot use in-place references (zero-copy) because the function users
  2177. // need null-terminated strings for the tokens
  2178. tokens = (WCHAR**) LocalAlloc(LPTR,
  2179. sizeof(WCHAR*) * tokenCount + // for the pointers
  2180. sizeof(WCHAR) * cchBufferLength); // for the data
  2181. // Data will be copied after the array
  2182. lpwszBuffer = (WCHAR*)(((BYTE*)tokens) + (sizeof(WCHAR*) * tokenCount));
  2183. State = BLANK;
  2184. for(crtSource = 0; crtSource < len; ++crtSource) {
  2185. crt = source[crtSource];
  2186. switch(State) {
  2187. case DELIMITER: // intentional fallthrough
  2188. case BLANK:
  2189. if (crt == deli) {
  2190. State = DELIMITER;
  2191. }
  2192. else if (!iswspace(crt)) {
  2193. lpwszTokenEnd = lpwszTokenStart = source + crtSource;
  2194. State = TOKEN;
  2195. }
  2196. else {
  2197. State = BLANK;
  2198. }
  2199. break;
  2200. case TOKEN:
  2201. if (crt == deli) {
  2202. COPY_CURRENT_TOKEN;
  2203. State = DELIMITER;
  2204. }
  2205. else if (!iswspace(crt)) {
  2206. lpwszTokenEnd = source + crtSource;
  2207. }
  2208. break;
  2209. }
  2210. }
  2211. // Copy out last token, if any
  2212. if (TOKEN == State) {
  2213. COPY_CURRENT_TOKEN;
  2214. }
  2215. }
  2216. *count = tokenCount;
  2217. *outTokens = tokens;
  2218. return ERROR_SUCCESS;
  2219. }
  2220. //----------------------------------------------------------------------------
  2221. // Function: BuildServiceSecurityDescriptor
  2222. //
  2223. // Description:
  2224. // Builds a security descriptor for an arbitrary object
  2225. //
  2226. // Returns:
  2227. // ERROR_SUCCESS: on success
  2228. // error code: otherwise
  2229. //
  2230. // Notes:
  2231. // The SD is a of the self-contained flavor (offsets, not pointers)
  2232. // Caller should use LocalFree to clear allocated pSD
  2233. //
  2234. DWORD BuildServiceSecurityDescriptor(
  2235. __in ACCESS_MASK accessMask,
  2236. __in size_t grantSidCount,
  2237. __in_ecount(grantSidCount) PSID* pGrantSids,
  2238. __in size_t denySidCount,
  2239. __in_ecount(denySidCount) PSID* pDenySids,
  2240. __in_opt PSID pOwner,
  2241. __out PSECURITY_DESCRIPTOR* pSD) {
  2242. DWORD dwError = ERROR_SUCCESS;
  2243. int crt = 0;
  2244. int len = 0;
  2245. EXPLICIT_ACCESS* eas = NULL;
  2246. LPWSTR lpszSD = NULL;
  2247. ULONG cchSD = 0;
  2248. HANDLE hToken = INVALID_HANDLE_VALUE;
  2249. DWORD dwBufferSize = 0;
  2250. PTOKEN_USER pTokenUser = NULL;
  2251. PTOKEN_PRIMARY_GROUP pTokenGroup = NULL;
  2252. PSECURITY_DESCRIPTOR pTempSD = NULL;
  2253. ULONG cbSD = 0;
  2254. TRUSTEE owner, group;
  2255. ZeroMemory(&owner, sizeof(owner));
  2256. // We'll need our own SID to add as SD owner
  2257. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
  2258. dwError = GetLastError();
  2259. LogDebugMessage(L"OpenProcessToken: %d\n", dwError);
  2260. goto done;
  2261. }
  2262. if (NULL == pOwner) {
  2263. if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize)) {
  2264. dwError = GetLastError();
  2265. if (ERROR_INSUFFICIENT_BUFFER != dwError) {
  2266. LogDebugMessage(L"GetTokenInformation: %d\n", dwError);
  2267. goto done;
  2268. }
  2269. }
  2270. pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwBufferSize);
  2271. if (NULL == pTokenUser) {
  2272. dwError = GetLastError();
  2273. LogDebugMessage(L"LocalAlloc:pTokenUser: %d\n", dwError);
  2274. goto done;
  2275. }
  2276. if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) {
  2277. dwError = GetLastError();
  2278. LogDebugMessage(L"GetTokenInformation: %d\n", dwError);
  2279. goto done;
  2280. }
  2281. if (!IsValidSid(pTokenUser->User.Sid)) {
  2282. dwError = ERROR_INVALID_PARAMETER;
  2283. LogDebugMessage(L"IsValidSid: %d\n", dwError);
  2284. goto done;
  2285. }
  2286. pOwner = pTokenUser->User.Sid;
  2287. }
  2288. dwBufferSize = 0;
  2289. if (!GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwBufferSize)) {
  2290. dwError = GetLastError();
  2291. if (ERROR_INSUFFICIENT_BUFFER != dwError) {
  2292. LogDebugMessage(L"GetTokenInformation: %d\n", dwError);
  2293. goto done;
  2294. }
  2295. }
  2296. pTokenGroup = (PTOKEN_USER) LocalAlloc(LPTR, dwBufferSize);
  2297. if (NULL == pTokenGroup) {
  2298. dwError = GetLastError();
  2299. LogDebugMessage(L"LocalAlloc:pTokenGroup: %d\n", dwError);
  2300. goto done;
  2301. }
  2302. if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dwBufferSize, &dwBufferSize)) {
  2303. dwError = GetLastError();
  2304. LogDebugMessage(L"GetTokenInformation: %d\n", dwError);
  2305. goto done;
  2306. }
  2307. if (!IsValidSid(pTokenGroup->PrimaryGroup)) {
  2308. dwError = ERROR_INVALID_PARAMETER;
  2309. LogDebugMessage(L"IsValidSid: %d\n", dwError);
  2310. goto done;
  2311. }
  2312. owner.TrusteeForm = TRUSTEE_IS_SID;
  2313. owner.TrusteeType = TRUSTEE_IS_UNKNOWN;
  2314. owner.ptstrName = (LPCWSTR) pOwner;
  2315. group.TrusteeForm = TRUSTEE_IS_SID;
  2316. group.TrusteeType = TRUSTEE_IS_UNKNOWN;
  2317. group.ptstrName = (LPCWSTR) pTokenGroup->PrimaryGroup;
  2318. eas = (EXPLICIT_ACCESS*) LocalAlloc(LPTR, sizeof(EXPLICIT_ACCESS) * (grantSidCount + denySidCount));
  2319. if (NULL == eas) {
  2320. dwError = ERROR_OUTOFMEMORY;
  2321. LogDebugMessage(L"LocalAlloc: %d\n", dwError);
  2322. goto done;
  2323. }
  2324. // Build the granted list
  2325. for (crt = 0; crt < grantSidCount; ++crt) {
  2326. eas[crt].grfAccessPermissions = accessMask;
  2327. eas[crt].grfAccessMode = GRANT_ACCESS;
  2328. eas[crt].grfInheritance = NO_INHERITANCE;
  2329. eas[crt].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2330. eas[crt].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
  2331. eas[crt].Trustee.ptstrName = (LPCWSTR) pGrantSids[crt];
  2332. eas[crt].Trustee.pMultipleTrustee = NULL;
  2333. eas[crt].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  2334. }
  2335. // Build the deny list
  2336. for (; crt < grantSidCount + denySidCount; ++crt) {
  2337. eas[crt].grfAccessPermissions = accessMask;
  2338. eas[crt].grfAccessMode = DENY_ACCESS;
  2339. eas[crt].grfInheritance = NO_INHERITANCE;
  2340. eas[crt].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2341. eas[crt].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
  2342. eas[crt].Trustee.ptstrName = (LPCWSTR) pDenySids[crt - grantSidCount];
  2343. eas[crt].Trustee.pMultipleTrustee = NULL;
  2344. eas[crt].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  2345. }
  2346. dwError = BuildSecurityDescriptor(
  2347. &owner,
  2348. &group,
  2349. crt,
  2350. eas,
  2351. 0, // cCountOfAuditEntries
  2352. NULL, // pListOfAuditEntries
  2353. NULL, // pOldSD
  2354. &cbSD,
  2355. &pTempSD);
  2356. if (ERROR_SUCCESS != dwError) {
  2357. LogDebugMessage(L"BuildSecurityDescriptor: %d\n", dwError);
  2358. goto done;
  2359. }
  2360. *pSD = pTempSD;
  2361. pTempSD = NULL;
  2362. if (IsDebuggerPresent()) {
  2363. ConvertSecurityDescriptorToStringSecurityDescriptor(*pSD,
  2364. SDDL_REVISION_1,
  2365. DACL_SECURITY_INFORMATION,
  2366. &lpszSD,
  2367. &cchSD);
  2368. LogDebugMessage(L"pSD: %.*s\n", cchSD, lpszSD);
  2369. }
  2370. done:
  2371. if (eas) LocalFree(eas);
  2372. if (pTokenUser) LocalFree(pTokenUser);
  2373. if (INVALID_HANDLE_VALUE != hToken) CloseHandle(hToken);
  2374. if (lpszSD) LocalFree(lpszSD);
  2375. if (pTempSD) LocalFree(pTempSD);
  2376. return dwError;
  2377. }
  2378. //----------------------------------------------------------------------------
  2379. // Function: MIDL_user_allocate
  2380. //
  2381. // Description:
  2382. // Hard-coded function name used by RPC midl code for allocations
  2383. //
  2384. // Notes:
  2385. // Must match the de-allocation mechanism used in MIDL_user_free
  2386. //
  2387. void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
  2388. {
  2389. return LocalAlloc(LPTR, len);
  2390. }
  2391. //----------------------------------------------------------------------------
  2392. // Function: MIDL_user_free
  2393. //
  2394. // Description:
  2395. // Hard-coded function name used by RPC midl code for deallocations
  2396. //
  2397. // NoteS:
  2398. // Must match the allocation mechanism used in MIDL_user_allocate
  2399. //
  2400. void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
  2401. {
  2402. LocalFree(ptr);
  2403. }