123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973 |
- /**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- #pragma comment(lib, "authz.lib")
- #pragma comment(lib, "netapi32.lib")
- #pragma comment(lib, "Secur32.lib")
- #pragma comment(lib, "Userenv.lib")
- #pragma comment(lib, "Ntdsapi.lib")
- #include "winutils.h"
- #include <ctype.h>
- #include <Winsvc.h>
- #include <authz.h>
- #include <sddl.h>
- #include <Ntdsapi.h>
- #include <malloc.h>
- #define WIDEN_STRING(x) WIDEN_STRING_(x)
- #define WIDEN_STRING_(x) L ## x
- #define STRINGIFY(x) STRINGIFY_(x)
- #define STRINGIFY_(x) #x
- #pragma message("WSCE config is " STRINGIFY(WSCE_CONFIG_DIR) "\\" STRINGIFY(WSCE_CONFIG_FILE))
- const WCHAR* wsceConfigRelativePath = WIDEN_STRING(STRINGIFY(WSCE_CONFIG_DIR)) L"\\" WIDEN_STRING(STRINGIFY(WSCE_CONFIG_FILE));
- /*
- * The array of 12 months' three-letter abbreviations
- */
- const LPCWSTR MONTHS[] = { L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun",
- L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" };
- /*
- * The WindowsAclMask and WinMasks contain the definitions used to establish
- * the mapping between Unix and Windows.
- * We set up the mapping with the following rules.
- * 1. Everyone will have WIN_ALL permissions;
- * 2. Owner will always have WIN_OWNER_SE permissions in addition;
- * 2. When Unix read/write/excute permission is set on the file, the
- * corresponding Windows allow ACE will be added to the file.
- * More details and explaination can be found in the following white paper:
- * http://technet.microsoft.com/en-us/library/bb463216.aspx
- */
- const ACCESS_MASK WinMasks[WIN_MASKS_TOTAL] =
- {
- /* WIN_READ */
- FILE_READ_DATA,
- /* WIN_WRITE */
- FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_APPEND_DATA | FILE_WRITE_EA |
- FILE_DELETE_CHILD,
- /* WIN_EXECUTE */
- FILE_EXECUTE,
- /* WIN_OWNER_SE */
- DELETE | WRITE_DAC | WRITE_OWNER | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES,
- /* WIN_ALL */
- READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
- };
- //----------------------------------------------------------------------------
- // Function: GetFileInformationByName
- //
- // Description:
- // To retrieve the by handle file information given the file name
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // error code: otherwise
- //
- // Notes:
- // If followLink parameter is set to TRUE, we will follow the symbolic link
- // or junction point to get the target file information. Otherwise, the
- // information for the symbolic link or junction point is retrieved.
- //
- DWORD GetFileInformationByName(
- __in LPCWSTR pathName,
- __in BOOL followLink,
- __out LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
- {
- HANDLE fileHandle = INVALID_HANDLE_VALUE;
- BOOL isSymlink = FALSE;
- BOOL isJunction = FALSE;
- DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS;
- DWORD dwErrorCode = ERROR_SUCCESS;
- assert(lpFileInformation != NULL);
- if (!followLink)
- {
- if ((dwErrorCode = SymbolicLinkCheck(pathName, &isSymlink)) != ERROR_SUCCESS)
- return dwErrorCode;
- if ((dwErrorCode = JunctionPointCheck(pathName, &isJunction)) != ERROR_SUCCESS)
- return dwErrorCode;
- if (isSymlink || isJunction)
- dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
- }
- fileHandle = CreateFileW(
- pathName,
- FILE_READ_ATTRIBUTES,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- dwFlagsAndAttributes,
- NULL);
- if (fileHandle == INVALID_HANDLE_VALUE)
- {
- dwErrorCode = GetLastError();
- return dwErrorCode;
- }
- if (!GetFileInformationByHandle(fileHandle, lpFileInformation))
- {
- dwErrorCode = GetLastError();
- CloseHandle(fileHandle);
- return dwErrorCode;
- }
- CloseHandle(fileHandle);
- return dwErrorCode;
- }
- //----------------------------------------------------------------------------
- // Function: IsLongWindowsPath
- //
- // Description:
- // Checks if the path is longer than (MAX_PATH - 13) in which case it needs to
- // be prepended with \\?\ for Windows OS to understand it. The -13 is to
- // account for an additional constraint for directories that it must be possible
- // to append an additional path separator followed by an 8.3 file name.
- //
- // Returns:
- // TRUE long path
- // FALSE otherwise
- static BOOL IsLongWindowsPath(__in PCWSTR path)
- {
- return (wcslen(path) + 1) > (MAX_PATH - 13);
- }
- //----------------------------------------------------------------------------
- // Function: IsPrefixedAlready
- //
- // Description:
- // Checks if the given path is already prepended with \\?\.
- //
- // Returns:
- // TRUE if yes
- // FALSE otherwise
- static BOOL IsPrefixedAlready(__in PCWSTR path)
- {
- static const PCWSTR LongPathPrefix = L"\\\\?\\";
- size_t Prefixlen = wcslen(LongPathPrefix);
- size_t i = 0;
- if (path == NULL || wcslen(path) < Prefixlen)
- {
- return FALSE;
- }
- for (i = 0; i < Prefixlen; ++i)
- {
- if (path[i] != LongPathPrefix[i])
- {
- return FALSE;
- }
- }
- return TRUE;
- }
- //----------------------------------------------------------------------------
- // Function: ConvertToLongPath
- //
- // Description:
- // Prepends the path with the \\?\ prefix if the path is longer than MAX_PATH.
- // On success, newPath should be freed with LocalFree(). Given that relative
- // paths cannot be longer than MAX_PATH, we will never prepend the prefix
- // to relative paths.
- //
- // Returns:
- // ERROR_SUCCESS on success
- // error code on failure
- DWORD ConvertToLongPath(__in PCWSTR path, __deref_out PWSTR *newPath)
- {
- DWORD dwErrorCode = ERROR_SUCCESS;
- static const PCWSTR LongPathPrefix = L"\\\\?\\";
- BOOL bAppendPrefix = IsLongWindowsPath(path) && !IsPrefixedAlready(path);
- HRESULT hr = S_OK;
- size_t newPathLen = wcslen(path) + (bAppendPrefix ? wcslen(LongPathPrefix) : 0);
- // Allocate the buffer for the output path (+1 for terminating NULL char)
- //
- PWSTR newPathValue = (PWSTR)LocalAlloc(LPTR, (newPathLen + 1) * sizeof(WCHAR));
- if (newPathValue == NULL)
- {
- dwErrorCode = GetLastError();
- goto ConvertToLongPathExit;
- }
- if (bAppendPrefix)
- {
- // Append the prefix to the path
- //
- hr = StringCchPrintfW(newPathValue, newPathLen + 1, L"%s%s",
- LongPathPrefix, path);
- if (FAILED(hr))
- {
- dwErrorCode = HRESULT_CODE(hr);
- goto ConvertToLongPathExit;
- }
- }
- else
- {
- // Just copy the original value into the output path. In this scenario
- // we are doing extra buffer copy. We decided to trade code simplicity
- // on the call site for small performance impact (extra allocation and
- // buffer copy). As paths are short, the impact is generally small.
- //
- hr = StringCchPrintfW(newPathValue, newPathLen + 1, L"%s", path);
- if (FAILED(hr))
- {
- dwErrorCode = HRESULT_CODE(hr);
- goto ConvertToLongPathExit;
- }
- }
- *newPath = newPathValue;
- ConvertToLongPathExit:
- if (dwErrorCode != ERROR_SUCCESS)
- {
- LocalFree(newPathValue);
- }
- return dwErrorCode;
- }
- //----------------------------------------------------------------------------
- // Function: IsDirFileInfo
- //
- // Description:
- // Test if the given file information is a directory
- //
- // Returns:
- // TRUE if it is a directory
- // FALSE otherwise
- //
- // Notes:
- //
- BOOL IsDirFileInfo(const BY_HANDLE_FILE_INFORMATION *fileInformation)
- {
- if ((fileInformation->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- == FILE_ATTRIBUTE_DIRECTORY)
- return TRUE;
- return FALSE;
- }
- //----------------------------------------------------------------------------
- // Function: CheckFileAttributes
- //
- // Description:
- // Check if the given file has all the given attribute(s)
- //
- // Returns:
- // ERROR_SUCCESS on success
- // error code otherwise
- //
- // Notes:
- //
- static DWORD FileAttributesCheck(
- __in LPCWSTR path, __in DWORD attr, __out PBOOL res)
- {
- DWORD attrs = INVALID_FILE_ATTRIBUTES;
- *res = FALSE;
- if ((attrs = GetFileAttributes(path)) != INVALID_FILE_ATTRIBUTES)
- *res = ((attrs & attr) == attr);
- else
- return GetLastError();
- return ERROR_SUCCESS;
- }
- //----------------------------------------------------------------------------
- // Function: IsDirectory
- //
- // Description:
- // Check if the given file is a directory
- //
- // Returns:
- // ERROR_SUCCESS on success
- // error code otherwise
- //
- // Notes:
- //
- DWORD DirectoryCheck(__in LPCWSTR pathName, __out PBOOL res)
- {
- return FileAttributesCheck(pathName, FILE_ATTRIBUTE_DIRECTORY, res);
- }
- //----------------------------------------------------------------------------
- // Function: IsReparsePoint
- //
- // Description:
- // Check if the given file is a reparse point
- //
- // Returns:
- // ERROR_SUCCESS on success
- // error code otherwise
- //
- // Notes:
- //
- static DWORD ReparsePointCheck(__in LPCWSTR pathName, __out PBOOL res)
- {
- return FileAttributesCheck(pathName, FILE_ATTRIBUTE_REPARSE_POINT, res);
- }
- //----------------------------------------------------------------------------
- // Function: CheckReparseTag
- //
- // Description:
- // Check if the given file is a reparse point of the given tag.
- //
- // Returns:
- // ERROR_SUCCESS on success
- // error code otherwise
- //
- // Notes:
- //
- static DWORD ReparseTagCheck(__in LPCWSTR path, __in DWORD tag, __out PBOOL res)
- {
- BOOL isReparsePoint = FALSE;
- HANDLE hFind = INVALID_HANDLE_VALUE;
- WIN32_FIND_DATA findData;
- DWORD dwRtnCode;
- if ((dwRtnCode = ReparsePointCheck(path, &isReparsePoint)) != ERROR_SUCCESS)
- return dwRtnCode;
- if (!isReparsePoint)
- {
- *res = FALSE;
- }
- else
- {
- if ((hFind = FindFirstFile(path, &findData)) == INVALID_HANDLE_VALUE)
- {
- return GetLastError();
- }
- else
- {
- *res = (findData.dwReserved0 == tag);
- FindClose(hFind);
- }
- }
- return ERROR_SUCCESS;
- }
- //----------------------------------------------------------------------------
- // Function: IsSymbolicLink
- //
- // Description:
- // Check if the given file is a symbolic link.
- //
- // Returns:
- // ERROR_SUCCESS on success
- // error code otherwise
- //
- // Notes:
- //
- DWORD SymbolicLinkCheck(__in LPCWSTR pathName, __out PBOOL res)
- {
- return ReparseTagCheck(pathName, IO_REPARSE_TAG_SYMLINK, res);
- }
- //----------------------------------------------------------------------------
- // Function: IsJunctionPoint
- //
- // Description:
- // Check if the given file is a junction point.
- //
- // Returns:
- // ERROR_SUCCESS on success
- // error code otherwise
- //
- // Notes:
- //
- DWORD JunctionPointCheck(__in LPCWSTR pathName, __out PBOOL res)
- {
- return ReparseTagCheck(pathName, IO_REPARSE_TAG_MOUNT_POINT, res);
- }
- //----------------------------------------------------------------------------
- // Function: GetSidFromAcctNameW
- //
- // Description:
- // To retrieve the SID for a user account
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Other error code: otherwise
- //
- // Notes:
- // Caller needs to destroy the memory of Sid by calling LocalFree()
- //
- DWORD GetSidFromAcctNameW(__in PCWSTR acctName, __out PSID *ppSid)
- {
- DWORD dwSidSize = 0;
- DWORD cchDomainName = 0;
- DWORD dwDomainNameSize = 0;
- LPWSTR domainName = NULL;
- SID_NAME_USE eSidType;
- DWORD dwErrorCode = ERROR_SUCCESS;
- // Validate the input parameters.
- //
- assert (acctName != NULL && ppSid != NULL);
- // Empty name is invalid. However, LookupAccountName() function will return a
- // false Sid, i.e. Sid for 'BUILDIN', for an empty name instead failing. We
- // report the error before calling LookupAccountName() function for this
- // special case. The error code returned here is the same as the last error
- // code set by LookupAccountName() function for an invalid name.
- //
- if (wcslen(acctName) == 0)
- return ERROR_NONE_MAPPED;
- // First pass to retrieve the buffer size.
- //
- LookupAccountName(
- NULL, // Computer name. NULL for the local computer
- acctName,
- NULL, // pSid. NULL to retrieve buffer size
- &dwSidSize,
- NULL, // Domain Name. NULL to retrieve buffer size
- &cchDomainName,
- &eSidType);
- if((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
- {
- return dwErrorCode;
- }
- else
- {
- // Reallocate memory for the buffers.
- //
- *ppSid = (PSID)LocalAlloc(LPTR, dwSidSize);
- if (*ppSid == NULL)
- {
- return GetLastError();
- }
- dwDomainNameSize = (cchDomainName + 1) * sizeof(wchar_t);
- domainName = (LPWSTR)LocalAlloc(LPTR, dwDomainNameSize);
- if (domainName == NULL)
- {
- return GetLastError();
- }
- // Second pass to retrieve the SID and domain name.
- //
- if (!LookupAccountNameW(
- NULL, // Computer name. NULL for the local computer
- acctName,
- *ppSid,
- &dwSidSize,
- domainName,
- &cchDomainName,
- &eSidType))
- {
- LocalFree(domainName);
- return GetLastError();
- }
- assert(IsValidSid(*ppSid));
- }
- LocalFree(domainName);
- return ERROR_SUCCESS;
- }
- //----------------------------------------------------------------------------
- // Function: GetUnixAccessMask
- //
- // Description:
- // Compute the 3 bit Unix mask for the owner, group, or, others
- //
- // Returns:
- // The 3 bit Unix mask in INT
- //
- // Notes:
- //
- static INT GetUnixAccessMask(ACCESS_MASK Mask)
- {
- static const INT exe = 0x0001;
- static const INT write = 0x0002;
- static const INT read = 0x0004;
- INT mask = 0;
- if ((Mask & WinMasks[WIN_READ]) == WinMasks[WIN_READ])
- mask |= read;
- if ((Mask & WinMasks[WIN_WRITE]) == WinMasks[WIN_WRITE])
- mask |= write;
- if ((Mask & WinMasks[WIN_EXECUTE]) == WinMasks[WIN_EXECUTE])
- mask |= exe;
- return mask;
- }
- //----------------------------------------------------------------------------
- // Function: GetAccess
- //
- // Description:
- // Get Windows acces mask by AuthZ methods
- //
- // Returns:
- // ERROR_SUCCESS: on success
- //
- // Notes:
- //
- static DWORD GetAccess(AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClient,
- PSECURITY_DESCRIPTOR psd, PACCESS_MASK pAccessRights)
- {
- AUTHZ_ACCESS_REQUEST AccessRequest = {0};
- AUTHZ_ACCESS_REPLY AccessReply = {0};
- BYTE Buffer[1024];
- assert (pAccessRights != NULL);
- // Do AccessCheck
- AccessRequest.DesiredAccess = MAXIMUM_ALLOWED;
- AccessRequest.PrincipalSelfSid = NULL;
- AccessRequest.ObjectTypeList = NULL;
- AccessRequest.ObjectTypeListLength = 0;
- AccessRequest.OptionalArguments = NULL;
- RtlZeroMemory(Buffer, sizeof(Buffer));
- AccessReply.ResultListLength = 1;
- AccessReply.GrantedAccessMask = (PACCESS_MASK) (Buffer);
- AccessReply.Error = (PDWORD) (Buffer + sizeof(ACCESS_MASK));
- if (!AuthzAccessCheck(0,
- hAuthzClient,
- &AccessRequest,
- NULL,
- psd,
- NULL,
- 0,
- &AccessReply,
- NULL))
- {
- return GetLastError();
- }
- *pAccessRights = (*(const ACCESS_MASK *)(AccessReply.GrantedAccessMask));
- return ERROR_SUCCESS;
- }
- //----------------------------------------------------------------------------
- // Function: GetEffectiveRightsForSid
- //
- // Description:
- // Get Windows acces mask by AuthZ methods
- //
- // Returns:
- // ERROR_SUCCESS: on success
- //
- // Notes:
- // We run into problems for local user accounts when using the method
- // GetEffectiveRightsFromAcl(). We resort to using AuthZ methods as
- // an alternative way suggested on MSDN:
- // http://msdn.microsoft.com/en-us/library/windows/desktop/aa446637.aspx
- //
- static DWORD GetEffectiveRightsForSid(PSECURITY_DESCRIPTOR psd,
- PSID pSid,
- PACCESS_MASK pAccessRights)
- {
- AUTHZ_RESOURCE_MANAGER_HANDLE hManager = NULL;
- LUID unusedId = { 0 };
- AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext = NULL;
- DWORD dwRtnCode = ERROR_SUCCESS;
- DWORD ret = ERROR_SUCCESS;
- assert (pAccessRights != NULL);
- if (!AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT,
- NULL, NULL, NULL, NULL, &hManager))
- {
- return GetLastError();
- }
- // Pass AUTHZ_SKIP_TOKEN_GROUPS to the function to avoid querying user group
- // information for access check. This allows us to model POSIX permissions
- // on Windows, where a user can have less permissions than a group it
- // belongs to.
- if(!AuthzInitializeContextFromSid(AUTHZ_SKIP_TOKEN_GROUPS,
- pSid, hManager, NULL, unusedId, NULL, &hAuthzClientContext))
- {
- ret = GetLastError();
- goto GetEffectiveRightsForSidEnd;
- }
- if ((dwRtnCode = GetAccess(hAuthzClientContext, psd, pAccessRights))
- != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto GetEffectiveRightsForSidEnd;
- }
- GetEffectiveRightsForSidEnd:
- if (hManager != NULL)
- {
- (void)AuthzFreeResourceManager(hManager);
- }
- if (hAuthzClientContext != NULL)
- {
- (void)AuthzFreeContext(hAuthzClientContext);
- }
- return ret;
- }
- //----------------------------------------------------------------------------
- // Function: CheckAccessForCurrentUser
- //
- // Description:
- // Checks if the current process has the requested access rights on the given
- // path. Based on the following MSDN article:
- // http://msdn.microsoft.com/en-us/library/windows/desktop/ff394771(v=vs.85).aspx
- //
- // Returns:
- // ERROR_SUCCESS: on success
- //
- DWORD CheckAccessForCurrentUser(
- __in PCWSTR pathName,
- __in ACCESS_MASK requestedAccess,
- __out BOOL *allowed)
- {
- DWORD dwRtnCode = ERROR_SUCCESS;
- LPWSTR longPathName = NULL;
- HANDLE hProcessToken = NULL;
- PSECURITY_DESCRIPTOR pSd = NULL;
- AUTHZ_RESOURCE_MANAGER_HANDLE hManager = NULL;
- AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext = NULL;
- LUID Luid = {0, 0};
- ACCESS_MASK currentUserAccessRights = 0;
- // Prepend the long path prefix if needed
- dwRtnCode = ConvertToLongPath(pathName, &longPathName);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto CheckAccessEnd;
- }
- // Get SD of the given path. OWNER and DACL security info must be
- // requested, otherwise, AuthzAccessCheck fails with invalid parameter
- // error.
- dwRtnCode = GetNamedSecurityInfo(longPathName, SE_FILE_OBJECT,
- OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
- DACL_SECURITY_INFORMATION,
- NULL, NULL, NULL, NULL, &pSd);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto CheckAccessEnd;
- }
- // Get current process token
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
- {
- dwRtnCode = GetLastError();
- goto CheckAccessEnd;
- }
- if (!AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT, NULL, NULL,
- NULL, NULL, &hManager))
- {
- dwRtnCode = GetLastError();
- goto CheckAccessEnd;
- }
- if(!AuthzInitializeContextFromToken(0, hProcessToken, hManager, NULL,
- Luid, NULL, &hAuthzClientContext))
- {
- dwRtnCode = GetLastError();
- goto CheckAccessEnd;
- }
- dwRtnCode = GetAccess(hAuthzClientContext, pSd, ¤tUserAccessRights);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto CheckAccessEnd;
- }
- *allowed = ((currentUserAccessRights & requestedAccess) == requestedAccess);
- CheckAccessEnd:
- LocalFree(longPathName);
- LocalFree(pSd);
- if (hProcessToken != NULL)
- {
- CloseHandle(hProcessToken);
- }
- if (hManager != NULL)
- {
- (void)AuthzFreeResourceManager(hManager);
- }
- if (hAuthzClientContext != NULL)
- {
- (void)AuthzFreeContext(hAuthzClientContext);
- }
- return dwRtnCode;
- }
- //----------------------------------------------------------------------------
- // Function: FindFileOwnerAndPermissionByHandle
- //
- // Description:
- // Find the owner, primary group and permissions of a file object given the
- // the file object handle. The function will always follow symbolic links.
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code otherwise
- //
- // Notes:
- // - Caller needs to destroy the memeory of owner and group names by calling
- // LocalFree() function.
- //
- // - If the user or group name does not exist, the user or group SID will be
- // returned as the name.
- //
- DWORD FindFileOwnerAndPermissionByHandle(
- __in HANDLE fileHandle,
- __out_opt LPWSTR *pOwnerName,
- __out_opt LPWSTR *pGroupName,
- __out_opt PINT pMask)
- {
- LPWSTR path = NULL;
- DWORD cchPathLen = 0;
- DWORD dwRtnCode = ERROR_SUCCESS;
- DWORD ret = ERROR_SUCCESS;
- dwRtnCode = GetFinalPathNameByHandle(fileHandle, path, cchPathLen, 0);
- if (dwRtnCode == 0)
- {
- ret = GetLastError();
- goto FindFileOwnerAndPermissionByHandleEnd;
- }
- cchPathLen = dwRtnCode;
- path = (LPWSTR) LocalAlloc(LPTR, cchPathLen * sizeof(WCHAR));
- if (path == NULL)
- {
- ret = GetLastError();
- goto FindFileOwnerAndPermissionByHandleEnd;
- }
- dwRtnCode = GetFinalPathNameByHandle(fileHandle, path, cchPathLen, 0);
- if (dwRtnCode != cchPathLen - 1)
- {
- ret = GetLastError();
- goto FindFileOwnerAndPermissionByHandleEnd;
- }
- dwRtnCode = FindFileOwnerAndPermission(path, TRUE, pOwnerName, pGroupName, pMask);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionByHandleEnd;
- }
- FindFileOwnerAndPermissionByHandleEnd:
- LocalFree(path);
- return ret;
- }
- //----------------------------------------------------------------------------
- // Function: FindFileOwnerAndPermission
- //
- // Description:
- // Find the owner, primary group and permissions of a file object
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code otherwise
- //
- // Notes:
- // - Caller needs to destroy the memeory of owner and group names by calling
- // LocalFree() function.
- //
- // - If the user or group name does not exist, the user or group SID will be
- // returned as the name.
- //
- DWORD FindFileOwnerAndPermission(
- __in LPCWSTR pathName,
- __in BOOL followLink,
- __out_opt LPWSTR *pOwnerName,
- __out_opt LPWSTR *pGroupName,
- __out_opt PINT pMask)
- {
- DWORD dwRtnCode = 0;
- PSECURITY_DESCRIPTOR pSd = NULL;
- PSID psidOwner = NULL;
- PSID psidGroup = NULL;
- PSID psidEveryone = NULL;
- DWORD cbSid = SECURITY_MAX_SID_SIZE;
- PACL pDacl = NULL;
- BOOL isSymlink = FALSE;
- BY_HANDLE_FILE_INFORMATION fileInformation = {0};
- ACCESS_MASK ownerAccessRights = 0;
- ACCESS_MASK groupAccessRights = 0;
- ACCESS_MASK worldAccessRights = 0;
- DWORD ret = ERROR_SUCCESS;
- // Do nothing if the caller request nothing
- //
- if (pOwnerName == NULL && pGroupName == NULL && pMask == NULL)
- {
- return ret;
- }
- dwRtnCode = GetNamedSecurityInfo(pathName, SE_FILE_OBJECT,
- OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
- DACL_SECURITY_INFORMATION,
- &psidOwner, &psidGroup, &pDacl, NULL, &pSd);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionEnd;
- }
- if (pOwnerName != NULL)
- {
- dwRtnCode = GetAccntNameFromSid(psidOwner, pOwnerName);
- if (dwRtnCode == ERROR_NONE_MAPPED)
- {
- if (!ConvertSidToStringSid(psidOwner, pOwnerName))
- {
- ret = GetLastError();
- goto FindFileOwnerAndPermissionEnd;
- }
- }
- else if (dwRtnCode != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionEnd;
- }
- }
- if (pGroupName != NULL)
- {
- dwRtnCode = GetAccntNameFromSid(psidGroup, pGroupName);
- if (dwRtnCode == ERROR_NONE_MAPPED)
- {
- if (!ConvertSidToStringSid(psidGroup, pGroupName))
- {
- ret = GetLastError();
- goto FindFileOwnerAndPermissionEnd;
- }
- }
- else if (dwRtnCode != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionEnd;
- }
- }
- if (pMask == NULL) goto FindFileOwnerAndPermissionEnd;
- dwRtnCode = GetFileInformationByName(pathName,
- followLink, &fileInformation);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionEnd;
- }
- dwRtnCode = SymbolicLinkCheck(pathName, &isSymlink);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionEnd;
- }
- if (isSymlink)
- *pMask |= UX_SYMLINK;
- else if (IsDirFileInfo(&fileInformation))
- *pMask |= UX_DIRECTORY;
- else
- *pMask |= UX_REGULAR;
- if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
- psidOwner, &ownerAccessRights)) != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionEnd;
- }
- if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
- psidGroup, &groupAccessRights)) != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionEnd;
- }
- if ((psidEveryone = LocalAlloc(LPTR, cbSid)) == NULL)
- {
- ret = GetLastError();
- goto FindFileOwnerAndPermissionEnd;
- }
- if (!CreateWellKnownSid(WinWorldSid, NULL, psidEveryone, &cbSid))
- {
- ret = GetLastError();
- goto FindFileOwnerAndPermissionEnd;
- }
- if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
- psidEveryone, &worldAccessRights)) != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto FindFileOwnerAndPermissionEnd;
- }
- *pMask |= GetUnixAccessMask(ownerAccessRights) << 6;
- *pMask |= GetUnixAccessMask(groupAccessRights) << 3;
- *pMask |= GetUnixAccessMask(worldAccessRights);
- FindFileOwnerAndPermissionEnd:
- LocalFree(psidEveryone);
- LocalFree(pSd);
- return ret;
- }
- //----------------------------------------------------------------------------
- // Function: GetWindowsAccessMask
- //
- // Description:
- // Get the Windows AccessMask for user, group and everyone based on the Unix
- // permission mask
- //
- // Returns:
- // none
- //
- // Notes:
- // none
- //
- static void GetWindowsAccessMask(INT unixMask,
- ACCESS_MASK *userAllow,
- ACCESS_MASK *userDeny,
- ACCESS_MASK *groupAllow,
- ACCESS_MASK *groupDeny,
- ACCESS_MASK *otherAllow)
- {
- assert (userAllow != NULL && userDeny != NULL &&
- groupAllow != NULL && groupDeny != NULL &&
- otherAllow != NULL);
- *userAllow = WinMasks[WIN_ALL] | WinMasks[WIN_OWNER_SE];
- if ((unixMask & UX_U_READ) == UX_U_READ)
- *userAllow |= WinMasks[WIN_READ];
- if ((unixMask & UX_U_WRITE) == UX_U_WRITE)
- *userAllow |= WinMasks[WIN_WRITE];
- if ((unixMask & UX_U_EXECUTE) == UX_U_EXECUTE)
- *userAllow |= WinMasks[WIN_EXECUTE];
- *userDeny = 0;
- if ((unixMask & UX_U_READ) != UX_U_READ &&
- ((unixMask & UX_G_READ) == UX_G_READ ||
- (unixMask & UX_O_READ) == UX_O_READ))
- *userDeny |= WinMasks[WIN_READ];
- if ((unixMask & UX_U_WRITE) != UX_U_WRITE &&
- ((unixMask & UX_G_WRITE) == UX_G_WRITE ||
- (unixMask & UX_O_WRITE) == UX_O_WRITE))
- *userDeny |= WinMasks[WIN_WRITE];
- if ((unixMask & UX_U_EXECUTE) != UX_U_EXECUTE &&
- ((unixMask & UX_G_EXECUTE) == UX_G_EXECUTE ||
- (unixMask & UX_O_EXECUTE) == UX_O_EXECUTE))
- *userDeny |= WinMasks[WIN_EXECUTE];
- *groupAllow = WinMasks[WIN_ALL];
- if ((unixMask & UX_G_READ) == UX_G_READ)
- *groupAllow |= FILE_GENERIC_READ;
- if ((unixMask & UX_G_WRITE) == UX_G_WRITE)
- *groupAllow |= WinMasks[WIN_WRITE];
- if ((unixMask & UX_G_EXECUTE) == UX_G_EXECUTE)
- *groupAllow |= WinMasks[WIN_EXECUTE];
- *groupDeny = 0;
- if ((unixMask & UX_G_READ) != UX_G_READ &&
- (unixMask & UX_O_READ) == UX_O_READ)
- *groupDeny |= WinMasks[WIN_READ];
- if ((unixMask & UX_G_WRITE) != UX_G_WRITE &&
- (unixMask & UX_O_WRITE) == UX_O_WRITE)
- *groupDeny |= WinMasks[WIN_WRITE];
- if ((unixMask & UX_G_EXECUTE) != UX_G_EXECUTE &&
- (unixMask & UX_O_EXECUTE) == UX_O_EXECUTE)
- *groupDeny |= WinMasks[WIN_EXECUTE];
- *otherAllow = WinMasks[WIN_ALL];
- if ((unixMask & UX_O_READ) == UX_O_READ)
- *otherAllow |= WinMasks[WIN_READ];
- if ((unixMask & UX_O_WRITE) == UX_O_WRITE)
- *otherAllow |= WinMasks[WIN_WRITE];
- if ((unixMask & UX_O_EXECUTE) == UX_O_EXECUTE)
- *otherAllow |= WinMasks[WIN_EXECUTE];
- }
- //----------------------------------------------------------------------------
- // Function: GetWindowsDACLs
- //
- // Description:
- // Get the Windows DACs based the Unix access mask
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- // Notes:
- // - Administrators and SYSTEM are always given full permission to the file,
- // unless Administrators or SYSTEM itself is the file owner and the user
- // explictly set the permission to something else. For example, file 'foo'
- // belongs to Administrators, 'chmod 000' on the file will not directly
- // assign Administrators full permission on the file.
- // - Only full permission for Administrators and SYSTEM are inheritable.
- // - CREATOR OWNER is always given full permission and the permission is
- // inheritable, more specifically OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE
- // flags are set. The reason is to give the creator of child file full
- // permission, i.e., the child file will have permission mode 700 for
- // a user other than Administrator or SYSTEM.
- //
- static DWORD GetWindowsDACLs(__in INT unixMask,
- __in PSID pOwnerSid, __in PSID pGroupSid, __out PACL *ppNewDACL)
- {
- DWORD winUserAccessDenyMask;
- DWORD winUserAccessAllowMask;
- DWORD winGroupAccessDenyMask;
- DWORD winGroupAccessAllowMask;
- DWORD winOtherAccessAllowMask;
- PSID pEveryoneSid = NULL;
- DWORD cbEveryoneSidSize = SECURITY_MAX_SID_SIZE;
- PSID pSystemSid = NULL;
- DWORD cbSystemSidSize = SECURITY_MAX_SID_SIZE;
- BOOL bAddSystemAcls = FALSE;
- PSID pAdministratorsSid = NULL;
- DWORD cbAdministratorsSidSize = SECURITY_MAX_SID_SIZE;
- BOOL bAddAdministratorsAcls = FALSE;
- PSID pCreatorOwnerSid = NULL;
- DWORD cbCreatorOwnerSidSize = SECURITY_MAX_SID_SIZE;
- PACL pNewDACL = NULL;
- DWORD dwNewAclSize = 0;
- DWORD ret = ERROR_SUCCESS;
- GetWindowsAccessMask(unixMask,
- &winUserAccessAllowMask, &winUserAccessDenyMask,
- &winGroupAccessAllowMask, &winGroupAccessDenyMask,
- &winOtherAccessAllowMask);
- // Create a well-known SID for the Everyone group
- //
- if ((pEveryoneSid = LocalAlloc(LPTR, cbEveryoneSidSize)) == NULL)
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!CreateWellKnownSid(WinWorldSid, NULL, pEveryoneSid, &cbEveryoneSidSize))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- // Create a well-known SID for the Administrators group
- //
- if ((pAdministratorsSid = LocalAlloc(LPTR, cbAdministratorsSidSize)) == NULL)
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL,
- pAdministratorsSid, &cbAdministratorsSidSize))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!EqualSid(pAdministratorsSid, pOwnerSid)
- && !EqualSid(pAdministratorsSid, pGroupSid))
- bAddAdministratorsAcls = TRUE;
- // Create a well-known SID for the SYSTEM
- //
- if ((pSystemSid = LocalAlloc(LPTR, cbSystemSidSize)) == NULL)
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!CreateWellKnownSid(WinLocalSystemSid, NULL,
- pSystemSid, &cbSystemSidSize))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!EqualSid(pSystemSid, pOwnerSid)
- && !EqualSid(pSystemSid, pGroupSid))
- bAddSystemAcls = TRUE;
- // Create a well-known SID for the Creator Owner
- //
- if ((pCreatorOwnerSid = LocalAlloc(LPTR, cbCreatorOwnerSidSize)) == NULL)
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!CreateWellKnownSid(WinCreatorOwnerSid, NULL,
- pCreatorOwnerSid, &cbCreatorOwnerSidSize))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- // Create the new DACL
- //
- dwNewAclSize = sizeof(ACL);
- dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
- GetLengthSid(pOwnerSid) - sizeof(DWORD);
- if (winUserAccessDenyMask)
- dwNewAclSize += sizeof(ACCESS_DENIED_ACE) +
- GetLengthSid(pOwnerSid) - sizeof(DWORD);
- dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
- GetLengthSid(pGroupSid) - sizeof(DWORD);
- if (winGroupAccessDenyMask)
- dwNewAclSize += sizeof(ACCESS_DENIED_ACE) +
- GetLengthSid(pGroupSid) - sizeof(DWORD);
- dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
- GetLengthSid(pEveryoneSid) - sizeof(DWORD);
- if (bAddSystemAcls)
- {
- dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
- cbSystemSidSize - sizeof(DWORD);
- }
- if (bAddAdministratorsAcls)
- {
- dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
- cbAdministratorsSidSize - sizeof(DWORD);
- }
- dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
- cbCreatorOwnerSidSize - sizeof(DWORD);
- pNewDACL = (PACL)LocalAlloc(LPTR, dwNewAclSize);
- if (pNewDACL == NULL)
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!InitializeAcl(pNewDACL, dwNewAclSize, ACL_REVISION))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
- CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
- GENERIC_ALL, pCreatorOwnerSid))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (bAddSystemAcls &&
- !AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
- CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
- GENERIC_ALL, pSystemSid))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (bAddAdministratorsAcls &&
- !AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
- CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
- GENERIC_ALL, pAdministratorsSid))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (winUserAccessDenyMask &&
- !AddAccessDeniedAceEx(pNewDACL, ACL_REVISION,
- CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
- winUserAccessDenyMask, pOwnerSid))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
- CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
- winUserAccessAllowMask, pOwnerSid))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (winGroupAccessDenyMask &&
- !AddAccessDeniedAceEx(pNewDACL, ACL_REVISION,
- CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
- winGroupAccessDenyMask, pGroupSid))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
- CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
- winGroupAccessAllowMask, pGroupSid))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
- CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
- winOtherAccessAllowMask, pEveryoneSid))
- {
- ret = GetLastError();
- goto GetWindowsDACLsEnd;
- }
- *ppNewDACL = pNewDACL;
- GetWindowsDACLsEnd:
- LocalFree(pEveryoneSid);
- LocalFree(pAdministratorsSid);
- LocalFree(pSystemSid);
- LocalFree(pCreatorOwnerSid);
- if (ret != ERROR_SUCCESS) LocalFree(pNewDACL);
-
- return ret;
- }
- //----------------------------------------------------------------------------
- // Function: ChangeFileModeByMask
- //
- // Description:
- // Change a file or direcotry at the path to Unix mode
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- // Notes:
- // This function is long path safe, i.e. the path will be converted to long
- // path format if not already converted. So the caller does not need to do
- // the converstion before calling the method.
- //
- DWORD ChangeFileModeByMask(__in LPCWSTR path, INT mode)
- {
- LPWSTR longPathName = NULL;
- PACL pNewDACL = NULL;
- PSID pOwnerSid = NULL;
- PSID pGroupSid = NULL;
- PSECURITY_DESCRIPTOR pSD = NULL;
- SECURITY_DESCRIPTOR_CONTROL control;
- DWORD revision = 0;
- PSECURITY_DESCRIPTOR pAbsSD = NULL;
- PSECURITY_DESCRIPTOR pNonNullSD = NULL;
- PACL pAbsDacl = NULL;
- PACL pAbsSacl = NULL;
- PSID pAbsOwner = NULL;
- PSID pAbsGroup = NULL;
- DWORD dwRtnCode = 0;
- DWORD dwErrorCode = 0;
- DWORD ret = ERROR_SUCCESS;
- dwRtnCode = ConvertToLongPath(path, &longPathName);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto ChangeFileModeByMaskEnd;
- }
- // Get owner and group Sids
- //
- dwRtnCode = GetNamedSecurityInfoW(
- longPathName,
- SE_FILE_OBJECT,
- OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
- &pOwnerSid,
- &pGroupSid,
- NULL,
- NULL,
- &pSD);
- if (ERROR_SUCCESS != dwRtnCode)
- {
- ret = dwRtnCode;
- goto ChangeFileModeByMaskEnd;
- }
- // SetSecurityDescriptorDacl function used below only accepts security
- // descriptor in absolute format, meaning that its members must be pointers to
- // other structures, rather than offsets to contiguous data.
- // To determine whether a security descriptor is self-relative or absolute,
- // call the GetSecurityDescriptorControl function and check the
- // SE_SELF_RELATIVE flag of the SECURITY_DESCRIPTOR_CONTROL parameter.
- //
- if (!GetSecurityDescriptorControl(pSD, &control, &revision))
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- // If the security descriptor is self-relative, we use MakeAbsoluteSD function
- // to convert it to absolute format.
- //
- if ((control & SE_SELF_RELATIVE) == SE_SELF_RELATIVE)
- {
- DWORD absSDSize = 0;
- DWORD daclSize = 0;
- DWORD saclSize = 0;
- DWORD ownerSize = 0;
- DWORD primaryGroupSize = 0;
- MakeAbsoluteSD(pSD, NULL, &absSDSize, NULL, &daclSize, NULL,
- &saclSize, NULL, &ownerSize, NULL, &primaryGroupSize);
- if ((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
- {
- ret = dwErrorCode;
- goto ChangeFileModeByMaskEnd;
- }
- if ((pAbsSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, absSDSize)) == NULL)
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- if ((pAbsDacl = (PACL) LocalAlloc(LPTR, daclSize)) == NULL)
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- if ((pAbsSacl = (PACL) LocalAlloc(LPTR, saclSize)) == NULL)
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- if ((pAbsOwner = (PSID) LocalAlloc(LPTR, ownerSize)) == NULL)
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- if ((pAbsGroup = (PSID) LocalAlloc(LPTR, primaryGroupSize)) == NULL)
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- if (!MakeAbsoluteSD(pSD, pAbsSD, &absSDSize, pAbsDacl, &daclSize, pAbsSacl,
- &saclSize, pAbsOwner, &ownerSize, pAbsGroup, &primaryGroupSize))
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- }
- // Get Windows DACLs based on Unix access mask
- //
- if ((dwRtnCode = GetWindowsDACLs(mode, pOwnerSid, pGroupSid, &pNewDACL))
- != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto ChangeFileModeByMaskEnd;
- }
- // Set the DACL information in the security descriptor; if a DACL is already
- // present in the security descriptor, the DACL is replaced. The security
- // descriptor is then used to set the security of a file or directory.
- //
- pNonNullSD = (pAbsSD != NULL) ? pAbsSD : pSD;
- if (!SetSecurityDescriptorDacl(pNonNullSD, TRUE, pNewDACL, FALSE))
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- // MSDN states "This function is obsolete. Use the SetNamedSecurityInfo
- // function instead." However we have the following problem when using
- // SetNamedSecurityInfo:
- // - When PROTECTED_DACL_SECURITY_INFORMATION is not passed in as part of
- // security information, the object will include inheritable permissions
- // from its parent.
- // - When PROTECTED_DACL_SECURITY_INFORMATION is passsed in to set
- // permissions on a directory, the child object of the directory will lose
- // inheritable permissions from their parent (the current directory).
- // By using SetFileSecurity, we have the nice property that the new
- // permissions of the object does not include the inheritable permissions from
- // its parent, and the child objects will not lose their inherited permissions
- // from the current object.
- //
- if (!SetFileSecurity(longPathName, DACL_SECURITY_INFORMATION, pNonNullSD))
- {
- ret = GetLastError();
- goto ChangeFileModeByMaskEnd;
- }
- ChangeFileModeByMaskEnd:
- pNonNullSD = NULL;
- LocalFree(longPathName);
- LocalFree(pSD);
- LocalFree(pNewDACL);
- LocalFree(pAbsDacl);
- LocalFree(pAbsSacl);
- LocalFree(pAbsOwner);
- LocalFree(pAbsGroup);
- LocalFree(pAbsSD);
- return ret;
- }
- //----------------------------------------------------------------------------
- // Function: GetTokenInformationByClass
- //
- // Description:
- // Gets a class of information from a token. On success, this function has
- // dynamically allocated memory and set the ppTokenInformation parameter to
- // point to it. The caller owns this memory and is reponsible for releasing it
- // by calling LocalFree.
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- static DWORD GetTokenInformationByClass(__in HANDLE hToken,
- __in TOKEN_INFORMATION_CLASS class, __out_opt LPVOID *ppTokenInformation) {
- DWORD dwRtnCode = ERROR_SUCCESS;
- LPVOID pTokenInformation = NULL;
- DWORD dwSize = 0;
- // Call GetTokenInformation first time to get the required buffer size.
- if (!GetTokenInformation(hToken, class, NULL, 0, &dwSize)) {
- dwRtnCode = GetLastError();
- if (dwRtnCode != ERROR_INSUFFICIENT_BUFFER) {
- return dwRtnCode;
- }
- }
- // Allocate memory.
- pTokenInformation = LocalAlloc(LPTR, dwSize);
- if (!pTokenInformation) {
- return GetLastError();
- }
- // Call GetTokenInformation second time to fill our buffer with data.
- if (!GetTokenInformation(hToken, class, pTokenInformation, dwSize, &dwSize)) {
- LocalFree(pTokenInformation);
- return GetLastError();
- }
- *ppTokenInformation = pTokenInformation;
- return ERROR_SUCCESS;
- }
- //----------------------------------------------------------------------------
- // Function: GetWindowsDACLsForCreate
- //
- // Description:
- // Get the Windows discretionary access control list equivalent to the given
- // mode, suitable for creating a new file or directory. Ownership is assumed
- // to be the current process owner and primary group. On success, this function
- // has dynamically allocated memory and set the ppDACL parameter to point to it.
- // The caller owns this memory and is reponsible for releasing it by calling
- // LocalFree.
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- static DWORD GetWindowsDACLsForCreate(__in INT mode, __out PACL *ppDACL) {
- DWORD dwRtnCode = ERROR_SUCCESS;
- HANDLE hToken = NULL;
- DWORD dwSize = 0;
- PTOKEN_OWNER pTokenOwner = NULL;
- PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup = NULL;
- PSID pOwnerSid = NULL, pGroupSid = NULL;
- PACL pDACL = NULL;
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
- dwRtnCode = GetLastError();
- goto done;
- }
- dwRtnCode = GetTokenInformationByClass(hToken, TokenOwner, &pTokenOwner);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- pOwnerSid = pTokenOwner->Owner;
- dwRtnCode = GetTokenInformationByClass(hToken, TokenPrimaryGroup,
- &pTokenPrimaryGroup);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- pGroupSid = pTokenPrimaryGroup->PrimaryGroup;
- dwRtnCode = GetWindowsDACLs(mode, pOwnerSid, pGroupSid, &pDACL);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- *ppDACL = pDACL;
- done:
- if (hToken) {
- CloseHandle(hToken);
- }
- LocalFree(pTokenOwner);
- LocalFree(pTokenPrimaryGroup);
- return dwRtnCode;
- }
- //----------------------------------------------------------------------------
- // Function: CreateSecurityDescriptorForCreate
- //
- // Description:
- // Creates a security descriptor with the given DACL, suitable for creating a
- // new file or directory. On success, this function has dynamically allocated
- // memory and set the ppSD parameter to point to it. The caller owns this
- // memory and is reponsible for releasing it by calling LocalFree.
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- static DWORD CreateSecurityDescriptorForCreate(__in PACL pDACL,
- __out PSECURITY_DESCRIPTOR *ppSD) {
- DWORD dwRtnCode = ERROR_SUCCESS;
- PSECURITY_DESCRIPTOR pSD = NULL;
- pSD = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
- if (!pSD) {
- dwRtnCode = GetLastError();
- goto done;
- }
- if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
- dwRtnCode = GetLastError();
- goto done;
- }
- if (!SetSecurityDescriptorDacl(pSD, TRUE, pDACL, FALSE)) {
- dwRtnCode = GetLastError();
- goto done;
- }
- *ppSD = pSD;
- done:
- if (dwRtnCode != ERROR_SUCCESS) {
- LocalFree(pSD);
- }
- return dwRtnCode;
- }
- //----------------------------------------------------------------------------
- // Function: CreateDirectoryWithMode
- //
- // Description:
- // Create a directory with initial security descriptor containing a
- // discretionary access control list equivalent to the given mode.
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- // Notes:
- // This function is long path safe, i.e. the path will be converted to long
- // path format if not already converted. So the caller does not need to do
- // the conversion before calling the method.
- //
- DWORD CreateDirectoryWithMode(__in LPCWSTR lpPath, __in INT mode) {
- DWORD dwRtnCode = ERROR_SUCCESS;
- LPWSTR lpLongPath = NULL;
- PACL pDACL = NULL;
- PSECURITY_DESCRIPTOR pSD = NULL;
- SECURITY_ATTRIBUTES sa;
- dwRtnCode = ConvertToLongPath(lpPath, &lpLongPath);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- dwRtnCode = GetWindowsDACLsForCreate(mode, &pDACL);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- dwRtnCode = CreateSecurityDescriptorForCreate(pDACL, &pSD);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor = pSD;
- sa.bInheritHandle = FALSE;
- if (!CreateDirectoryW(lpLongPath, &sa)) {
- dwRtnCode = GetLastError();
- }
- done:
- LocalFree(lpLongPath);
- LocalFree(pDACL);
- LocalFree(pSD);
- return dwRtnCode;
- }
- //----------------------------------------------------------------------------
- // Function: CreateFileWithMode
- //
- // Description:
- // Create a file with initial security descriptor containing a discretionary
- // access control list equivalent to the given mode.
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- // Notes:
- // This function is long path safe, i.e. the path will be converted to long
- // path format if not already converted. So the caller does not need to do
- // the conversion before calling the method.
- //
- DWORD CreateFileWithMode(__in LPCWSTR lpPath, __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode, __in DWORD dwCreationDisposition, __in INT mode,
- __out PHANDLE pHFile) {
- DWORD dwRtnCode = ERROR_SUCCESS;
- LPWSTR lpLongPath = NULL;
- PACL pDACL = NULL;
- PSECURITY_DESCRIPTOR pSD = NULL;
- SECURITY_ATTRIBUTES sa;
- DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
- HANDLE hFile = INVALID_HANDLE_VALUE;
- dwRtnCode = ConvertToLongPath(lpPath, &lpLongPath);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- dwRtnCode = GetWindowsDACLsForCreate(mode, &pDACL);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- dwRtnCode = CreateSecurityDescriptorForCreate(pDACL, &pSD);
- if (dwRtnCode != ERROR_SUCCESS) {
- goto done;
- }
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor = pSD;
- sa.bInheritHandle = FALSE;
- hFile = CreateFileW(lpLongPath, dwDesiredAccess, dwShareMode, &sa,
- dwCreationDisposition, dwFlagsAndAttributes, NULL);
- if (hFile == INVALID_HANDLE_VALUE) {
- dwRtnCode = GetLastError();
- goto done;
- }
- *pHFile = hFile;
- done:
- LocalFree(lpLongPath);
- LocalFree(pDACL);
- LocalFree(pSD);
- return dwRtnCode;
- }
- //----------------------------------------------------------------------------
- // Function: GetAccntNameFromSid
- //
- // Description:
- // To retrieve an account name given the SID
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Other error code: otherwise
- //
- // Notes:
- // Caller needs to destroy the memory of account name by calling LocalFree()
- //
- DWORD GetAccntNameFromSid(__in PSID pSid, __out PWSTR *ppAcctName)
- {
- LPWSTR lpName = NULL;
- DWORD cchName = 0;
- LPWSTR lpDomainName = NULL;
- DWORD cchDomainName = 0;
- SID_NAME_USE eUse = SidTypeUnknown;
- DWORD cchAcctName = 0;
- DWORD dwErrorCode = ERROR_SUCCESS;
- HRESULT hr = S_OK;
- DWORD ret = ERROR_SUCCESS;
- assert(ppAcctName != NULL);
- // NOTE:
- // MSDN says the length returned for the buffer size including the terminating
- // null character. However we found it is not true during debuging.
- //
- LookupAccountSid(NULL, pSid, NULL, &cchName, NULL, &cchDomainName, &eUse);
- if ((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
- return dwErrorCode;
- lpName = (LPWSTR) LocalAlloc(LPTR, (cchName + 1) * sizeof(WCHAR));
- if (lpName == NULL)
- {
- ret = GetLastError();
- goto GetAccntNameFromSidEnd;
- }
- lpDomainName = (LPWSTR) LocalAlloc(LPTR, (cchDomainName + 1) * sizeof(WCHAR));
- if (lpDomainName == NULL)
- {
- ret = GetLastError();
- goto GetAccntNameFromSidEnd;
- }
- if (!LookupAccountSid(NULL, pSid,
- lpName, &cchName, lpDomainName, &cchDomainName, &eUse))
- {
- ret = GetLastError();
- goto GetAccntNameFromSidEnd;
- }
- // Buffer size = name length + 1 for '\' + domain length + 1 for NULL
- cchAcctName = cchName + cchDomainName + 2;
- *ppAcctName = (LPWSTR) LocalAlloc(LPTR, cchAcctName * sizeof(WCHAR));
- if (*ppAcctName == NULL)
- {
- ret = GetLastError();
- goto GetAccntNameFromSidEnd;
- }
- hr = StringCchCopyW(*ppAcctName, cchAcctName, lpDomainName);
- if (FAILED(hr))
- {
- ret = HRESULT_CODE(hr);
- goto GetAccntNameFromSidEnd;
- }
- hr = StringCchCatW(*ppAcctName, cchAcctName, L"\\");
- if (FAILED(hr))
- {
- ret = HRESULT_CODE(hr);
- goto GetAccntNameFromSidEnd;
- }
- hr = StringCchCatW(*ppAcctName, cchAcctName, lpName);
- if (FAILED(hr))
- {
- ret = HRESULT_CODE(hr);
- goto GetAccntNameFromSidEnd;
- }
- GetAccntNameFromSidEnd:
- LocalFree(lpName);
- LocalFree(lpDomainName);
- if (ret != ERROR_SUCCESS)
- {
- LocalFree(*ppAcctName);
- *ppAcctName = NULL;
- }
- return ret;
- }
- //----------------------------------------------------------------------------
- // Function: GetLocalGroupsForUser
- //
- // Description:
- // Get an array of groups for the given user.
- //
- // Returns:
- // ERROR_SUCCESS on success
- // Other error code on failure
- //
- // Notes:
- // - NetUserGetLocalGroups() function only accepts full user name in the format
- // [domain name]\[username]. The user input to this function can be only the
- // username. In this case, NetUserGetLocalGroups() will fail on the first try,
- // and we will try to find full user name using LookupAccountNameW() method,
- // and call NetUserGetLocalGroups() function again with full user name.
- // However, it is not always possible to find full user name given only user
- // name. For example, a computer named 'win1' joined domain 'redmond' can have
- // two different users, 'win1\alex' and 'redmond\alex'. Given only 'alex', we
- // cannot tell which one is correct.
- //
- // - Caller needs to destroy the memory of groups by using the
- // NetApiBufferFree() function
- //
- DWORD GetLocalGroupsForUser(
- __in LPCWSTR user,
- __out LPLOCALGROUP_USERS_INFO_0 *groups,
- __out LPDWORD entries)
- {
- DWORD dwEntriesRead = 0;
- DWORD dwTotalEntries = 0;
- NET_API_STATUS nStatus = NERR_Success;
- PSID pUserSid = NULL;
- LPWSTR fullName = NULL;
- DWORD dwRtnCode = ERROR_SUCCESS;
- DWORD ret = ERROR_SUCCESS;
- *groups = NULL;
- *entries = 0;
- nStatus = NetUserGetLocalGroups(NULL,
- user,
- 0,
- 0,
- (LPBYTE *) groups,
- MAX_PREFERRED_LENGTH,
- &dwEntriesRead,
- &dwTotalEntries);
- if (nStatus == NERR_Success)
- {
- *entries = dwEntriesRead;
- return ERROR_SUCCESS;
- }
- else if (nStatus != NERR_UserNotFound)
- {
- return nStatus;
- }
- if ((dwRtnCode = GetSidFromAcctNameW(user, &pUserSid)) != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto GetLocalGroupsForUserEnd;
- }
- if ((dwRtnCode = GetAccntNameFromSid(pUserSid, &fullName)) != ERROR_SUCCESS)
- {
- ret = dwRtnCode;
- goto GetLocalGroupsForUserEnd;
- }
- nStatus = NetUserGetLocalGroups(NULL,
- fullName,
- 0,
- 0,
- (LPBYTE *) groups,
- MAX_PREFERRED_LENGTH,
- &dwEntriesRead,
- &dwTotalEntries);
- if (nStatus != NERR_Success)
- {
- // NERR_DCNotFound (2453) and NERR_UserNotFound (2221) are not published
- // Windows System Error Code. All other error codes returned by
- // NetUserGetLocalGroups() are valid System Error Codes according to MSDN.
- ret = nStatus;
- goto GetLocalGroupsForUserEnd;
- }
- *entries = dwEntriesRead;
- GetLocalGroupsForUserEnd:
- LocalFree(pUserSid);
- LocalFree(fullName);
- return ret;
- }
- //----------------------------------------------------------------------------
- // Function: EnablePrivilege
- //
- // Description:
- // Check if the process has the given privilege. If yes, enable the privilege
- // to the process's access token.
- //
- // Returns:
- // ERROR_SUCCESS on success
- // GetLastError() on error
- //
- // Notes:
- //
- DWORD EnablePrivilege(__in LPCWSTR privilegeName)
- {
- HANDLE hToken = INVALID_HANDLE_VALUE;
- TOKEN_PRIVILEGES tp = { 0 };
- DWORD dwErrCode = ERROR_SUCCESS;
- if (!OpenProcessToken(GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
- {
- dwErrCode = GetLastError();
- ReportErrorCode(L"OpenProcessToken", dwErrCode);
- return dwErrCode;
- }
- tp.PrivilegeCount = 1;
- if (!LookupPrivilegeValueW(NULL,
- privilegeName, &(tp.Privileges[0].Luid)))
- {
- dwErrCode = GetLastError();
- ReportErrorCode(L"LookupPrivilegeValue", dwErrCode);
- CloseHandle(hToken);
- return dwErrCode;
- }
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- // As stated on MSDN, we need to use GetLastError() to check if
- // AdjustTokenPrivileges() adjusted all of the specified privileges.
- //
- if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) {
- dwErrCode = GetLastError();
- }
- CloseHandle(hToken);
- return dwErrCode;
- }
- //----------------------------------------------------------------------------
- // Function: ReportErrorCode
- //
- // Description:
- // Report an error. Use FormatMessage function to get the system error message.
- //
- // Returns:
- // None
- //
- // Notes:
- //
- //
- void ReportErrorCode(LPCWSTR func, DWORD err)
- {
- DWORD len = 0;
- LPWSTR msg = NULL;
- assert(func != NULL);
- len = FormatMessageW(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, err,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPWSTR)&msg, 0, NULL);
- if (len > 0)
- {
- LogDebugMessage(L"%s error (%d): %s\n", func, err, msg);
- fwprintf(stderr, L"%s error (%d): %s\n", func, err, msg);
- }
- else
- {
- LogDebugMessage(L"%s error code: %d.\n", func, err);
- fwprintf(stderr, L"%s error code: %d.\n", func, err);
- }
- if (msg != NULL) LocalFree(msg);
- }
- //----------------------------------------------------------------------------
- // Function: GetLibraryName
- //
- // Description:
- // Given an address, get the file name of the library from which it was loaded.
- //
- // Notes:
- // - The function allocates heap memory and points the filename out parameter to
- // the newly allocated memory, which will contain the name of the file.
- //
- // - If there is any failure, then the function frees the heap memory it
- // allocated and sets the filename out parameter to NULL.
- //
- void GetLibraryName(LPCVOID lpAddress, LPWSTR *filename)
- {
- SIZE_T ret = 0;
- DWORD size = MAX_PATH;
- HMODULE mod = NULL;
- DWORD err = ERROR_SUCCESS;
- MEMORY_BASIC_INFORMATION mbi;
- ret = VirtualQuery(lpAddress, &mbi, sizeof(mbi));
- if (ret == 0) goto cleanup;
- mod = mbi.AllocationBase;
- do {
- *filename = (LPWSTR) realloc(*filename, size * sizeof(WCHAR));
- if (*filename == NULL) goto cleanup;
- GetModuleFileName(mod, *filename, size);
- size <<= 1;
- err = GetLastError();
- } while (err == ERROR_INSUFFICIENT_BUFFER);
- if (err != ERROR_SUCCESS) goto cleanup;
- return;
- cleanup:
- if (*filename != NULL)
- {
- free(*filename);
- *filename = NULL;
- }
- }
- // Function: AssignLsaString
- //
- // Description:
- // fills in values of LSA_STRING struct to point to a string buffer
- //
- // Returns:
- // None
- //
- // IMPORTANT*** strBuf is not copied. It must be globally immutable
- //
- void AssignLsaString(__inout LSA_STRING * target, __in const char *strBuf)
- {
- target->Length = (USHORT)(sizeof(char)*strlen(strBuf));
- target->MaximumLength = target->Length;
- target->Buffer = (char *)(strBuf);
- }
- //----------------------------------------------------------------------------
- // Function: RegisterWithLsa
- //
- // Description:
- // Registers with local security authority and sets handle for use in later LSA
- // operations
- //
- // Returns:
- // ERROR_SUCCESS on success
- // Other error code on failure
- //
- // Notes:
- //
- DWORD RegisterWithLsa(__in const char *logonProcessName, __out HANDLE * lsaHandle)
- {
- LSA_STRING processName;
- LSA_OPERATIONAL_MODE o_mode; // never useful as per msdn docs
- NTSTATUS registerStatus;
- *lsaHandle = 0;
-
- AssignLsaString(&processName, logonProcessName);
- registerStatus = LsaRegisterLogonProcess(&processName, lsaHandle, &o_mode);
-
- return LsaNtStatusToWinError( registerStatus );
- }
- //----------------------------------------------------------------------------
- // Function: UnregisterWithLsa
- //
- // Description:
- // Closes LSA handle allocated by RegisterWithLsa()
- //
- // Returns:
- // None
- //
- // Notes:
- //
- void UnregisterWithLsa(__in HANDLE lsaHandle)
- {
- LsaClose(lsaHandle);
- }
- //----------------------------------------------------------------------------
- // Function: LookupKerberosAuthenticationPackageId
- //
- // Description:
- // Looks of the current id (integer index) of the Kerberos authentication package on the local
- // machine.
- //
- // Returns:
- // ERROR_SUCCESS on success
- // Other error code on failure
- //
- // Notes:
- //
- DWORD LookupKerberosAuthenticationPackageId(__in HANDLE lsaHandle, __out ULONG * packageId)
- {
- NTSTATUS lookupStatus;
- LSA_STRING pkgName;
- AssignLsaString(&pkgName, MICROSOFT_KERBEROS_NAME_A);
- lookupStatus = LsaLookupAuthenticationPackage(lsaHandle, &pkgName, packageId);
- return LsaNtStatusToWinError( lookupStatus );
- }
-
- //----------------------------------------------------------------------------
- // Function: CreateLogonTokenForUser
- //
- // Description:
- // Contacts the local LSA and performs a logon without credential for the
- // given principal. This logon token will be local machine only and have no
- // network credentials attached.
- //
- // Returns:
- // ERROR_SUCCESS on success
- // Other error code on failure
- //
- // Notes:
- // This call assumes that all required privileges have already been enabled (TCB etc).
- // IMPORTANT **** tokenOriginName must be immutable!
- //
- DWORD CreateLogonTokenForUser(__in HANDLE lsaHandle,
- __in const char * tokenSourceName,
- __in const char * tokenOriginName, // must be immutable, will not be copied!
- __in ULONG authnPkgId,
- __in const wchar_t* principalName,
- __out HANDLE *tokenHandle)
- {
- DWORD logonStatus = ERROR_ASSERTION_FAILURE; // Failure to set status should trigger error
- TOKEN_SOURCE tokenSource;
- LSA_STRING originName;
- void * profile = NULL;
- // from MSDN:
- // The ClientUpn and ClientRealm members of the KERB_S4U_LOGON
- // structure must point to buffers in memory that are contiguous
- // to the structure itself. The value of the
- // AuthenticationInformationLength parameter must take into
- // account the length of these buffers.
- const int principalNameBufLen = lstrlen(principalName)*sizeof(*principalName);
- const int totalAuthInfoLen = sizeof(KERB_S4U_LOGON) + principalNameBufLen;
- KERB_S4U_LOGON* s4uLogonAuthInfo = (KERB_S4U_LOGON*)calloc(totalAuthInfoLen, 1);
- if (s4uLogonAuthInfo == NULL ) {
- logonStatus = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
- }
- s4uLogonAuthInfo->MessageType = KerbS4ULogon;
- s4uLogonAuthInfo->ClientUpn.Buffer = (wchar_t*)((char*)s4uLogonAuthInfo + sizeof *s4uLogonAuthInfo);
- CopyMemory(s4uLogonAuthInfo->ClientUpn.Buffer, principalName, principalNameBufLen);
- s4uLogonAuthInfo->ClientUpn.Length = (USHORT)principalNameBufLen;
- s4uLogonAuthInfo->ClientUpn.MaximumLength = (USHORT)principalNameBufLen;
- AllocateLocallyUniqueId(&tokenSource.SourceIdentifier);
- StringCchCopyA(tokenSource.SourceName, TOKEN_SOURCE_LENGTH, tokenSourceName );
- AssignLsaString(&originName, tokenOriginName);
- {
- DWORD cbProfile = 0;
- LUID logonId;
- QUOTA_LIMITS quotaLimits;
- NTSTATUS subStatus;
- NTSTATUS logonNtStatus = LsaLogonUser(lsaHandle,
- &originName,
- Batch, // SECURITY_LOGON_TYPE
- authnPkgId,
- s4uLogonAuthInfo,
- totalAuthInfoLen,
- 0,
- &tokenSource,
- &profile,
- &cbProfile,
- &logonId,
- tokenHandle,
- "aLimits,
- &subStatus);
- logonStatus = LsaNtStatusToWinError( logonNtStatus );
- }
- done:
- // clean up
- if (s4uLogonAuthInfo != NULL) {
- free(s4uLogonAuthInfo);
- }
- if (profile != NULL) {
- LsaFreeReturnBuffer(profile);
- }
- return logonStatus;
- }
- // NOTE: must free allocatedName
- DWORD GetNameFromLogonToken(__in HANDLE logonToken, __out wchar_t **allocatedName)
- {
- DWORD userInfoSize = 0;
- PTOKEN_USER user = NULL;
- DWORD userNameSize = 0;
- wchar_t * userName = NULL;
- DWORD domainNameSize = 0;
- wchar_t * domainName = NULL;
- SID_NAME_USE sidUse = SidTypeUnknown;
- DWORD getNameStatus = ERROR_ASSERTION_FAILURE; // Failure to set status should trigger error
- BOOL tokenInformation = FALSE;
- // call for sid size then alloc and call for sid
- tokenInformation = GetTokenInformation(logonToken, TokenUser, NULL, 0, &userInfoSize);
- assert (FALSE == tokenInformation);
-
- // last call should have failed and filled in allocation size
- if ((getNameStatus = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
- {
- goto done;
- }
- user = (PTOKEN_USER)calloc(userInfoSize,1);
- if (user == NULL)
- {
- getNameStatus = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
- }
- if (!GetTokenInformation(logonToken, TokenUser, user, userInfoSize, &userInfoSize)) {
- getNameStatus = GetLastError();
- goto done;
- }
- LookupAccountSid( NULL, user->User.Sid, NULL, &userNameSize, NULL, &domainNameSize, &sidUse );
- // last call should have failed and filled in allocation size
- if ((getNameStatus = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
- {
- goto done;
- }
- userName = (wchar_t *)calloc(userNameSize, sizeof(wchar_t));
- if (userName == NULL) {
- getNameStatus = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
- }
- domainName = (wchar_t *)calloc(domainNameSize, sizeof(wchar_t));
- if (domainName == NULL) {
- getNameStatus = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
- }
- if (!LookupAccountSid( NULL, user->User.Sid, userName, &userNameSize, domainName, &domainNameSize, &sidUse )) {
- getNameStatus = GetLastError();
- goto done;
- }
- getNameStatus = ERROR_SUCCESS;
- *allocatedName = userName;
- userName = NULL;
- done:
- if (user != NULL) {
- free( user );
- user = NULL;
- }
- if (userName != NULL) {
- free( userName );
- userName = NULL;
- }
- if (domainName != NULL) {
- free( domainName );
- domainName = NULL;
- }
- return getNameStatus;
- }
- DWORD LoadUserProfileForLogon(__in HANDLE logonHandle, __out PROFILEINFO * pi)
- {
- wchar_t *userName = NULL;
- DWORD loadProfileStatus = ERROR_ASSERTION_FAILURE; // Failure to set status should trigger error
- loadProfileStatus = GetNameFromLogonToken( logonHandle, &userName );
- if (loadProfileStatus != ERROR_SUCCESS) {
- goto done;
- }
- assert(pi);
- ZeroMemory( pi, sizeof(*pi) );
- pi->dwSize = sizeof(*pi);
- pi->lpUserName = userName;
- pi->dwFlags = PI_NOUI;
- // if the profile does not exist it will be created
- if ( !LoadUserProfile( logonHandle, pi ) ) {
- loadProfileStatus = GetLastError();
- goto done;
- }
- loadProfileStatus = ERROR_SUCCESS;
- done:
- return loadProfileStatus;
- }
- DWORD UnloadProfileForLogon(__in HANDLE logonHandle, __in PROFILEINFO * pi)
- {
- DWORD touchProfileStatus = ERROR_ASSERTION_FAILURE; // Failure to set status should trigger error
- assert(pi);
- if ( !UnloadUserProfile(logonHandle, pi->hProfile ) ) {
- touchProfileStatus = GetLastError();
- goto done;
- }
- if (pi->lpUserName != NULL) {
- free(pi->lpUserName);
- pi->lpUserName = NULL;
- }
- ZeroMemory( pi, sizeof(*pi) );
- touchProfileStatus = ERROR_SUCCESS;
- done:
- return touchProfileStatus;
- }
- //----------------------------------------------------------------------------
- // Function: ChangeFileOwnerBySid
- //
- // Description:
- // Change a file or directory ownership by giving new owner and group SIDs
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- // Notes:
- // This function is long path safe, i.e. the path will be converted to long
- // path format if not already converted. So the caller does not need to do
- // the converstion before calling the method.
- //
- DWORD ChangeFileOwnerBySid(__in LPCWSTR path,
- __in_opt PSID pNewOwnerSid, __in_opt PSID pNewGroupSid)
- {
- LPWSTR longPathName = NULL;
- INT oldMode = 0;
- SECURITY_INFORMATION securityInformation = 0;
- DWORD dwRtnCode = ERROR_SUCCESS;
- // Convert the path the the long path
- //
- dwRtnCode = ConvertToLongPath(path, &longPathName);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto ChangeFileOwnerByNameEnd;
- }
- // Get a pointer to the existing owner information and DACL
- //
- dwRtnCode = FindFileOwnerAndPermission(longPathName, FALSE, NULL, NULL, &oldMode);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto ChangeFileOwnerByNameEnd;
- }
- // We need SeTakeOwnershipPrivilege to set the owner if the caller does not
- // have WRITE_OWNER access to the object; we need SeRestorePrivilege if the
- // SID is not contained in the caller's token, and have the SE_GROUP_OWNER
- // permission enabled.
- //
- if (EnablePrivilege(L"SeTakeOwnershipPrivilege") != ERROR_SUCCESS)
- {
- fwprintf(stdout, L"INFO: The user does not have SeTakeOwnershipPrivilege.\n");
- }
- if (EnablePrivilege(L"SeRestorePrivilege") != ERROR_SUCCESS)
- {
- fwprintf(stdout, L"INFO: The user does not have SeRestorePrivilege.\n");
- }
- assert(pNewOwnerSid != NULL || pNewGroupSid != NULL);
- // Set the owners of the file.
- //
- if (pNewOwnerSid != NULL) securityInformation |= OWNER_SECURITY_INFORMATION;
- if (pNewGroupSid != NULL) securityInformation |= GROUP_SECURITY_INFORMATION;
- dwRtnCode = SetNamedSecurityInfoW(
- longPathName,
- SE_FILE_OBJECT,
- securityInformation,
- pNewOwnerSid,
- pNewGroupSid,
- NULL,
- NULL);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto ChangeFileOwnerByNameEnd;
- }
- // Set the permission on the file for the new owner.
- //
- dwRtnCode = ChangeFileModeByMask(longPathName, oldMode);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto ChangeFileOwnerByNameEnd;
- }
- ChangeFileOwnerByNameEnd:
- LocalFree(longPathName);
- return dwRtnCode;
- }
- //-----------------------------------------------------------------------------
- // Function: GetSecureJobObjectName
- //
- // Description:
- // Creates a job object name usable in a secure environment: adds the Golbal\
- //
- DWORD GetSecureJobObjectName(
- __in LPCWSTR jobName,
- __in size_t cchSecureJobName,
- __out_ecount(cchSecureJobName) LPWSTR secureJobName) {
- HRESULT hr = StringCchPrintf(secureJobName, cchSecureJobName,
- L"Global\\%s", jobName);
- if (FAILED(hr)) {
- return HRESULT_CODE(hr);
- }
- return ERROR_SUCCESS;
- }
- //-----------------------------------------------------------------------------
- // Function: EnableImpersonatePrivileges
- //
- // Description:
- // Enables the required privileges for S4U impersonation
- //
- // Returns:
- // ERROR_SUCCESS: On success
- //
- DWORD EnableImpersonatePrivileges() {
- DWORD dwError = ERROR_SUCCESS;
- LPCWSTR privilege = NULL;
- int crt = 0;
- LPCWSTR privileges[] = {
- SE_IMPERSONATE_NAME,
- SE_TCB_NAME,
- SE_ASSIGNPRIMARYTOKEN_NAME,
- SE_INCREASE_QUOTA_NAME,
- SE_RESTORE_NAME,
- SE_DEBUG_NAME,
- SE_SECURITY_NAME,
- };
- for (crt = 0; crt < sizeof(privileges)/sizeof(LPCWSTR); ++crt) {
- LPCWSTR privilege = privileges[crt];
- dwError = EnablePrivilege(privilege);
- if( dwError != ERROR_SUCCESS ) {
- LogDebugMessage(L"Failed to enable privilege: %s\n", privilege);
- ReportErrorCode(L"EnablePrivilege", dwError);
- goto done;
- }
- }
- done:
- return dwError;
- }
- //-----------------------------------------------------------------------------
- // Function: KillTask
- //
- // Description:
- // Kills a task via a jobobject. Outputs the
- // appropriate information to stdout on success, or stderr on failure.
- //
- // Returns:
- // ERROR_SUCCESS: On success
- // GetLastError: otherwise
- DWORD KillTask(PCWSTR jobObjName)
- {
- DWORD dwError = ERROR_SUCCESS;
-
- HANDLE jobObject = OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, jobObjName);
- if(jobObject == NULL)
- {
- dwError = GetLastError();
- if(dwError == ERROR_FILE_NOT_FOUND)
- {
- // job object does not exist. assume its not alive
- dwError = ERROR_SUCCESS;
- }
- goto done;
- }
- if(TerminateJobObject(jobObject, KILLED_PROCESS_EXIT_CODE) == 0)
- {
- dwError = GetLastError();
- }
- done:
- CloseHandle(jobObject);
-
- return dwError;
- }
- DWORD ChownImpl(
- __in_opt LPCWSTR userName,
- __in_opt LPCWSTR groupName,
- __in LPCWSTR pathName) {
- DWORD dwError;
- PSID pNewOwnerSid = NULL;
- PSID pNewGroupSid = NULL;
- if (userName != NULL)
- {
- dwError = GetSidFromAcctNameW(userName, &pNewOwnerSid);
- if (dwError != ERROR_SUCCESS)
- {
- ReportErrorCode(L"GetSidFromAcctName", dwError);
- fwprintf(stderr, L"Invalid user name: %s\n", userName);
- goto done;
- }
- }
- if (groupName != NULL)
- {
- dwError = GetSidFromAcctNameW(groupName, &pNewGroupSid);
- if (dwError != ERROR_SUCCESS)
- {
- ReportErrorCode(L"GetSidFromAcctName", dwError);
- fwprintf(stderr, L"Invalid group name: %s\n", groupName);
- goto done;
- }
- }
- if (wcslen(pathName) == 0 || wcsspn(pathName, L"/?|><:*\"") != 0)
- {
- fwprintf(stderr, L"Incorrect file name format: %s\n", pathName);
- goto done;
- }
- dwError = ChangeFileOwnerBySid(pathName, pNewOwnerSid, pNewGroupSid);
- if (dwError != ERROR_SUCCESS)
- {
- ReportErrorCode(L"ChangeFileOwnerBySid", dwError);
- goto done;
- }
- done:
- LocalFree(pNewOwnerSid);
- LocalFree(pNewGroupSid);
- return dwError;
- }
- LPCWSTR GetSystemTimeString() {
- __declspec(thread) static WCHAR buffer[1024];
- DWORD dwError;
- FILETIME ftime;
- SYSTEMTIME systime;
- LARGE_INTEGER counter, frequency;
- int subSec;
- double qpc;
- HRESULT hr;
- buffer[0] = L'\0';
- // GetSystemTimePreciseAsFileTime is only available in Win8+ and our libs do not link against it
- GetSystemTimeAsFileTime(&ftime);
- if (!FileTimeToSystemTime(&ftime, &systime)) {
- dwError = GetLastError();
- LogDebugMessage(L"FileTimeToSystemTime error:%d\n", dwError);
- goto done;
- }
- // Get the ms from QPC. GetSystemTimeAdjustment is ignored...
-
- QueryPerformanceCounter(&counter);
- QueryPerformanceFrequency(&frequency);
- qpc = (double) counter.QuadPart / (double) frequency.QuadPart;
- subSec = ((qpc - (long)qpc) * 1000000);
- hr = StringCbPrintf(buffer, sizeof(buffer), L"%02d:%02d:%02d.%06d",
- (int)systime.wHour, (int)systime.wMinute, (int)systime.wSecond, (int)subSec);
- if (FAILED(hr)) {
- LogDebugMessage(L"StringCbPrintf error:%d\n", hr);
- }
- done:
- return buffer;
- }
- //----------------------------------------------------------------------------
- // Function: LogDebugMessage
- //
- // Description:
- // Sends a message to the debugger console, if one is attached
- //
- // Notes:
- // Native debugger: windbg, ntsd, cdb, visual studio
- //
- VOID LogDebugMessage(LPCWSTR format, ...) {
- LPWSTR buffer[8192];
- va_list args;
- HRESULT hr;
- if (!IsDebuggerPresent()) return;
- va_start(args, format);
- hr = StringCbVPrintf(buffer, sizeof(buffer), format, args);
- if (SUCCEEDED(hr)) {
- OutputDebugString(buffer);
- }
- va_end(args);
- }
- //----------------------------------------------------------------------------
- // Function: SplitStringIgnoreSpaceW
- //
- // Description:
- // splits a null-terminated string based on a delimiter
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // error code: otherwise
- //
- // Notes:
- // The tokes are also null-terminated
- // Caller should use LocalFree to clear outTokens
- //
- DWORD SplitStringIgnoreSpaceW(
- __in size_t len,
- __in_ecount(len) LPCWSTR source,
- __in WCHAR deli,
- __out size_t* count,
- __out_ecount(count) WCHAR*** outTokens) {
-
- size_t tokenCount = 0;
- size_t crtSource;
- size_t crtToken = 0;
- WCHAR* lpwszTokenStart = NULL;
- WCHAR* lpwszTokenEnd = NULL;
- WCHAR* lpwszBuffer = NULL;
- size_t tokenLength = 0;
- size_t cchBufferLength = 0;
- WCHAR crt;
- WCHAR** tokens = NULL;
- enum {BLANK, TOKEN, DELIMITER} State = BLANK;
- for(crtSource = 0; crtSource < len; ++crtSource) {
- crt = source[crtSource];
- switch(State) {
- case BLANK: // intentional fallthrough
- case DELIMITER:
- if (crt == deli) {
- State = DELIMITER;
- }
- else if (!iswspace(crt)) {
- ++tokenCount;
- lpwszTokenEnd = lpwszTokenStart = source + crtSource;
- State = TOKEN;
- }
- else {
- State = BLANK;
- }
- break;
- case TOKEN:
- if (crt == deli) {
- State = DELIMITER;
- cchBufferLength += lpwszTokenEnd - lpwszTokenStart + 2;
- }
- else if (!iswspace(crt)) {
- lpwszTokenEnd = source + crtSource;
- }
- break;
- }
- }
- if (State == TOKEN) {
- cchBufferLength += lpwszTokenEnd - lpwszTokenStart + 2;
- }
- LogDebugMessage(L"counted %d [buffer:%d] tokens in %s\n", tokenCount, cchBufferLength, source);
- #define COPY_CURRENT_TOKEN \
- tokenLength = lpwszTokenEnd - lpwszTokenStart + 1; \
- tokens[crtToken] = lpwszBuffer; \
- memcpy(tokens[crtToken], lpwszTokenStart, tokenLength*sizeof(WCHAR)); \
- tokens[crtToken][tokenLength] = L'\0'; \
- lpwszBuffer += (tokenLength+1); \
- ++crtToken;
- if (tokenCount) {
- // We use one contigous memory for both the pointer arrays and the data copy buffers
- // We cannot use in-place references (zero-copy) because the function users
- // need null-terminated strings for the tokens
-
- tokens = (WCHAR**) LocalAlloc(LPTR,
- sizeof(WCHAR*) * tokenCount + // for the pointers
- sizeof(WCHAR) * cchBufferLength); // for the data
- // Data will be copied after the array
- lpwszBuffer = (WCHAR*)(((BYTE*)tokens) + (sizeof(WCHAR*) * tokenCount));
-
- State = BLANK;
- for(crtSource = 0; crtSource < len; ++crtSource) {
- crt = source[crtSource];
- switch(State) {
- case DELIMITER: // intentional fallthrough
- case BLANK:
- if (crt == deli) {
- State = DELIMITER;
- }
- else if (!iswspace(crt)) {
- lpwszTokenEnd = lpwszTokenStart = source + crtSource;
- State = TOKEN;
- }
- else {
- State = BLANK;
- }
- break;
- case TOKEN:
- if (crt == deli) {
- COPY_CURRENT_TOKEN;
- State = DELIMITER;
- }
- else if (!iswspace(crt)) {
- lpwszTokenEnd = source + crtSource;
- }
- break;
- }
- }
- // Copy out last token, if any
- if (TOKEN == State) {
- COPY_CURRENT_TOKEN;
- }
- }
- *count = tokenCount;
- *outTokens = tokens;
- return ERROR_SUCCESS;
- }
- //----------------------------------------------------------------------------
- // Function: BuildServiceSecurityDescriptor
- //
- // Description:
- // Builds a security descriptor for an arbitrary object
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // error code: otherwise
- //
- // Notes:
- // The SD is a of the self-contained flavor (offsets, not pointers)
- // Caller should use LocalFree to clear allocated pSD
- //
- DWORD BuildServiceSecurityDescriptor(
- __in ACCESS_MASK accessMask,
- __in size_t grantSidCount,
- __in_ecount(grantSidCount) PSID* pGrantSids,
- __in size_t denySidCount,
- __in_ecount(denySidCount) PSID* pDenySids,
- __in_opt PSID pOwner,
- __out PSECURITY_DESCRIPTOR* pSD) {
- DWORD dwError = ERROR_SUCCESS;
- unsigned int crt = 0;
- int len = 0;
- EXPLICIT_ACCESS* eas = NULL;
- LPWSTR lpszSD = NULL;
- ULONG cchSD = 0;
- HANDLE hToken = INVALID_HANDLE_VALUE;
- DWORD dwBufferSize = 0;
- PTOKEN_USER pTokenUser = NULL;
- PTOKEN_PRIMARY_GROUP pTokenGroup = NULL;
- PSECURITY_DESCRIPTOR pTempSD = NULL;
- ULONG cbSD = 0;
- TRUSTEE owner, group;
- ZeroMemory(&owner, sizeof(owner));
- // We'll need our own SID to add as SD owner
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
- dwError = GetLastError();
- LogDebugMessage(L"OpenProcessToken: %d\n", dwError);
- goto done;
- }
- if (NULL == pOwner) {
- if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize)) {
- dwError = GetLastError();
- if (ERROR_INSUFFICIENT_BUFFER != dwError) {
- LogDebugMessage(L"GetTokenInformation: %d\n", dwError);
- goto done;
- }
- }
- pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwBufferSize);
- if (NULL == pTokenUser) {
- dwError = GetLastError();
- LogDebugMessage(L"LocalAlloc:pTokenUser: %d\n", dwError);
- goto done;
- }
- if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) {
- dwError = GetLastError();
- LogDebugMessage(L"GetTokenInformation: %d\n", dwError);
- goto done;
- }
- if (!IsValidSid(pTokenUser->User.Sid)) {
- dwError = ERROR_INVALID_PARAMETER;
- LogDebugMessage(L"IsValidSid: %d\n", dwError);
- goto done;
- }
- pOwner = pTokenUser->User.Sid;
- }
- dwBufferSize = 0;
- if (!GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwBufferSize)) {
- dwError = GetLastError();
- if (ERROR_INSUFFICIENT_BUFFER != dwError) {
- LogDebugMessage(L"GetTokenInformation: %d\n", dwError);
- goto done;
- }
- }
- pTokenGroup = (PTOKEN_USER) LocalAlloc(LPTR, dwBufferSize);
- if (NULL == pTokenGroup) {
- dwError = GetLastError();
- LogDebugMessage(L"LocalAlloc:pTokenGroup: %d\n", dwError);
- goto done;
- }
- if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dwBufferSize, &dwBufferSize)) {
- dwError = GetLastError();
- LogDebugMessage(L"GetTokenInformation: %d\n", dwError);
- goto done;
- }
- if (!IsValidSid(pTokenGroup->PrimaryGroup)) {
- dwError = ERROR_INVALID_PARAMETER;
- LogDebugMessage(L"IsValidSid: %d\n", dwError);
- goto done;
- }
- owner.TrusteeForm = TRUSTEE_IS_SID;
- owner.TrusteeType = TRUSTEE_IS_UNKNOWN;
- owner.ptstrName = (LPCWSTR) pOwner;
- group.TrusteeForm = TRUSTEE_IS_SID;
- group.TrusteeType = TRUSTEE_IS_UNKNOWN;
- group.ptstrName = (LPCWSTR) pTokenGroup->PrimaryGroup;
- eas = (EXPLICIT_ACCESS*) LocalAlloc(LPTR, sizeof(EXPLICIT_ACCESS) * (grantSidCount + denySidCount));
- if (NULL == eas) {
- dwError = ERROR_OUTOFMEMORY;
- LogDebugMessage(L"LocalAlloc: %d\n", dwError);
- goto done;
- }
- // Build the granted list
- for (crt = 0; crt < grantSidCount; ++crt) {
- eas[crt].grfAccessPermissions = accessMask;
- eas[crt].grfAccessMode = GRANT_ACCESS;
- eas[crt].grfInheritance = NO_INHERITANCE;
- eas[crt].Trustee.TrusteeForm = TRUSTEE_IS_SID;
- eas[crt].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
- eas[crt].Trustee.ptstrName = (LPCWSTR) pGrantSids[crt];
- eas[crt].Trustee.pMultipleTrustee = NULL;
- eas[crt].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
- }
- // Build the deny list
- for (; crt < grantSidCount + denySidCount; ++crt) {
- eas[crt].grfAccessPermissions = accessMask;
- eas[crt].grfAccessMode = DENY_ACCESS;
- eas[crt].grfInheritance = NO_INHERITANCE;
- eas[crt].Trustee.TrusteeForm = TRUSTEE_IS_SID;
- eas[crt].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
- eas[crt].Trustee.ptstrName = (LPCWSTR) pDenySids[crt - grantSidCount];
- eas[crt].Trustee.pMultipleTrustee = NULL;
- eas[crt].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
- }
- dwError = BuildSecurityDescriptor(
- &owner,
- &group,
- crt,
- eas,
- 0, // cCountOfAuditEntries
- NULL, // pListOfAuditEntries
- NULL, // pOldSD
- &cbSD,
- &pTempSD);
- if (ERROR_SUCCESS != dwError) {
- LogDebugMessage(L"BuildSecurityDescriptor: %d\n", dwError);
- goto done;
- }
-
- *pSD = pTempSD;
- pTempSD = NULL;
- if (IsDebuggerPresent()) {
- ConvertSecurityDescriptorToStringSecurityDescriptor(*pSD,
- SDDL_REVISION_1,
- DACL_SECURITY_INFORMATION,
- &lpszSD,
- &cchSD);
- LogDebugMessage(L"pSD: %.*s\n", cchSD, lpszSD);
- }
-
- done:
- if (eas) LocalFree(eas);
- if (pTokenUser) LocalFree(pTokenUser);
- if (INVALID_HANDLE_VALUE != hToken) CloseHandle(hToken);
- if (lpszSD) LocalFree(lpszSD);
- if (pTempSD) LocalFree(pTempSD);
- return dwError;
- }
- //----------------------------------------------------------------------------
- // Function: MIDL_user_allocate
- //
- // Description:
- // Hard-coded function name used by RPC midl code for allocations
- //
- // Notes:
- // Must match the de-allocation mechanism used in MIDL_user_free
- //
- void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
- {
- return LocalAlloc(LPTR, len);
- }
-
- //----------------------------------------------------------------------------
- // Function: MIDL_user_free
- //
- // Description:
- // Hard-coded function name used by RPC midl code for deallocations
- //
- // NoteS:
- // Must match the allocation mechanism used in MIDL_user_allocate
- //
- void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
- {
- LocalFree(ptr);
- }
|