PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/saltstack/salt/lib/python3.10/site-packages/salt/utils
Viewing File: /opt/saltstack/salt/lib/python3.10/site-packages/salt/utils/win_lgpo_reg.py
""" A Salt Util for working with the Registry.pol file. The Registry.pol file is the source of truth for registry settings that are configured via LGPO. """ import logging import os import re import struct import salt.modules.win_file import salt.utils.files import salt.utils.win_reg from salt.exceptions import CommandExecutionError CLASS_INFO = { "User": { "policy_path": os.path.join( os.getenv("WINDIR", r"C:\Windows"), "System32", "GroupPolicy", "User", "Registry.pol", ), "hive": "HKEY_USERS", "lgpo_section": "User Configuration", "gpt_extension_location": "gPCUserExtensionNames", "gpt_extension_guid": "[{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F73-3407-48AE-BA88-E8213C6761F1}]", }, "Machine": { "policy_path": os.path.join( os.getenv("WINDIR", r"C:\Windows"), "System32", "GroupPolicy", "Machine", "Registry.pol", ), "hive": "HKEY_LOCAL_MACHINE", "lgpo_section": "Computer Configuration", "gpt_extension_location": "gPCMachineExtensionNames", "gpt_extension_guid": "[{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F72-3407-48AE-BA88-E8213C6761F1}]", }, } REG_POL_HEADER = "\u5250\u6765\x01\x00" GPT_INI_PATH = os.path.join( os.getenv("WINDIR", "C:\\Windows"), "System32", "GroupPolicy", "gpt.ini" ) log = logging.getLogger(__name__) __virtualname__ = "lgpo_reg" def __virtual__(): """ Only works on Windows with the lgpo_reg module """ if not salt.utils.platform.is_windows(): return False, "LGPO_REG Util: Only available on Windows" return __virtualname__ def search_reg_pol(search_string, policy_data): """ Helper function to do a regex search of a string value in policy_data. This is used to search the policy data from a registry.pol file or from gpt.ini Args: search_string (str): The string to search for policy_data (str): The data to be searched Returns: bool: ``True`` if the regex search_string is found, otherwise ``False`` """ if policy_data: if search_string: log.debug("LGPO_REG Util: Searching for %s", search_string) match = re.search(search_string, policy_data, re.IGNORECASE) if match: log.debug("LGPO_REG Util: Found") return True return False def read_reg_pol_file(reg_pol_path): """ Helper function to read the content of the Registry.pol file Args: reg_pol_path (str): The path to the Registry.pol file Returns: bytes: The data as contained in the Registry.pol file """ return_data = None if os.path.exists(reg_pol_path): log.debug("LGPO_REG Util: Reading from %s", reg_pol_path) with salt.utils.files.fopen(reg_pol_path, "rb") as pol_file: return_data = pol_file.read() return return_data def write_reg_pol_data( data_to_write, policy_file_path, gpt_extension, gpt_extension_guid, gpt_ini_path=GPT_INI_PATH, ): """ Helper function to actually write the data to a Registry.pol file Also updates/edits the gpt.ini file to include the ADM policy extensions to let the computer know user and/or machine registry policy files need to be processed Args: data_to_write (bytes): Data to write into the user/machine registry.pol file policy_file_path (str): Path to the registry.pol file gpt_extension (str): GPT extension list name from _policy_info class for this registry class gpt_extension_location gpt_extension_guid (str): ADMX registry extension guid for the class gpt_ini_path (str): The path to the gpt.ini file Returns: bool: True if successful Raises: CommandExecutionError: On failure """ # Write Registry.pol file if not os.path.exists(policy_file_path): log.debug("LGPO_REG Util: Creating parent directories for Registry.pol") salt.modules.win_file.makedirs_(policy_file_path) if data_to_write is None: data_to_write = b"" try: with salt.utils.files.fopen(policy_file_path, "wb") as pol_file: reg_pol_header = REG_POL_HEADER.encode("utf-16-le") if not data_to_write.startswith(reg_pol_header): log.debug("LGPO_REG Util: Writing header to %s", policy_file_path) pol_file.write(reg_pol_header) log.debug("LGPO_REG Util: Writing to %s", policy_file_path) pol_file.write(data_to_write) # TODO: This needs to be more specific except Exception as e: # pylint: disable=broad-except msg = ( "An error occurred attempting to write to {}, the exception was: {}".format( policy_file_path, e ) ) log.exception(msg) raise CommandExecutionError(msg) # Write the gpt.ini file gpt_ini_data = "" if os.path.exists(gpt_ini_path): with salt.utils.files.fopen(gpt_ini_path, "r") as gpt_file: gpt_ini_data = gpt_file.read() # Make sure it has Windows Style line endings gpt_ini_data = ( gpt_ini_data.replace("\r\n", "_|-") .replace("\n", "_|-") .replace("_|-", "\r\n") ) if not search_reg_pol(r"\[General\]\r\n", gpt_ini_data): log.debug("LGPO_REG Util: Adding [General] section to gpt.ini") gpt_ini_data = "[General]\r\n" + gpt_ini_data if search_reg_pol(rf"{re.escape(gpt_extension)}=", gpt_ini_data): # ensure the line contains the ADM guid gpt_ext_loc = re.search( rf"^{re.escape(gpt_extension)}=.*\r\n", gpt_ini_data, re.IGNORECASE | re.MULTILINE, ) gpt_ext_str = gpt_ini_data[gpt_ext_loc.start() : gpt_ext_loc.end()] if not search_reg_pol( search_string=rf"{re.escape(gpt_extension_guid)}", policy_data=gpt_ext_str, ): log.debug("LGPO_REG Util: Inserting gpt extension GUID") gpt_ext_str = gpt_ext_str.split("=") gpt_ext_str[1] = gpt_extension_guid + gpt_ext_str[1] gpt_ext_str = "=".join(gpt_ext_str) gpt_ini_data = ( gpt_ini_data[0 : gpt_ext_loc.start()] + gpt_ext_str + gpt_ini_data[gpt_ext_loc.end() :] ) else: general_location = re.search( r"^\[General\]\r\n", gpt_ini_data, re.IGNORECASE | re.MULTILINE ) gpt_ini_data = "{}{}={}\r\n{}".format( gpt_ini_data[general_location.start() : general_location.end()], gpt_extension, gpt_extension_guid, gpt_ini_data[general_location.end() :], ) # https://technet.microsoft.com/en-us/library/cc978247.aspx if search_reg_pol(r"Version=", gpt_ini_data): version_loc = re.search( r"^Version=.*\r\n", gpt_ini_data, re.IGNORECASE | re.MULTILINE ) version_str = gpt_ini_data[version_loc.start() : version_loc.end()] version_str = version_str.split("=") version_nums = struct.unpack(b">2H", struct.pack(b">I", int(version_str[1]))) if gpt_extension.lower() == "gPCMachineExtensionNames".lower(): version_nums = (version_nums[0], version_nums[1] + 1) elif gpt_extension.lower() == "gPCUserExtensionNames".lower(): version_nums = (version_nums[0] + 1, version_nums[1]) version_num = struct.unpack(b">I", struct.pack(b">2H", *version_nums))[0] gpt_ini_data = "{}{}={}\r\n{}".format( gpt_ini_data[0 : version_loc.start()], "Version", version_num, gpt_ini_data[version_loc.end() :], ) else: general_location = re.search( r"^\[General\]\r\n", gpt_ini_data, re.IGNORECASE | re.MULTILINE ) if gpt_extension.lower() == "gPCMachineExtensionNames".lower(): version_nums = (0, 1) elif gpt_extension.lower() == "gPCUserExtensionNames".lower(): version_nums = (1, 0) gpt_ini_data = "{}{}={}\r\n{}".format( gpt_ini_data[general_location.start() : general_location.end()], "Version", int( "{}{}".format( str(version_nums[0]).zfill(4), str(version_nums[1]).zfill(4), ), 16, ), gpt_ini_data[general_location.end() :], ) if gpt_ini_data: try: with salt.utils.files.fopen(gpt_ini_path, "w") as gpt_file: gpt_file.write(gpt_ini_data) # TODO: This needs to be more specific except Exception as e: # pylint: disable=broad-except msg = ( "An error occurred attempting to write the gpg.ini file.\n" "path: {}\n" "exception: {}".format(gpt_ini_path, e) ) log.exception(msg) raise CommandExecutionError(msg) return True def reg_pol_to_dict(policy_data): """ Convert the data obtained from a Registry.pol file to a dictionary. Args: policy_data (bytes): The data as retrieved from the Registry.pol file Raises: SaltInvocationError: Invalid or corrupt policy data Returns: dict: A dictionary representation of the Registry.pol data """ # https://learn.microsoft.com/en-us/previous-versions/windows/desktop/Policy/registry-policy-file-format # https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gpreg/5c092c22-bf6b-4e7f-b180-b20743d368f5 reg_pol_header = REG_POL_HEADER.encode("utf-16-le") # If policy_data is None, that means the Registry.pol file is missing # So, we'll create it if policy_data is None: policy_data = reg_pol_header if not policy_data.startswith(reg_pol_header): msg = "LGPO_REG Util: Invalid Header. Registry.pol may be corrupt" raise CommandExecutionError(msg) # Strip the header information, we don't care about it now pol_file_data = policy_data.lstrip(reg_pol_header) if not pol_file_data: log.debug("LGPO_REG Util: No registry.pol data to return") return {} def strip_field_end(value): while value[-2:] == b"\x00\x00": value = value[:-2] return value log.debug("LGPO_REG Util: Unpacking reg pol data") reg_pol = {} # Each policy is inside square braces. In this case they're encoded # utf-16-le, so there's a null-byte for each character for policy in pol_file_data.split(b"]\x00[\x00"): # Now remove the lingering square braces policy = policy.replace(b"]\x00", b"").replace(b"[\x00", b"") # Each policy element is delimited by a semi-colon, encoded utf-16-le # The first 4 are the key, name, type and size # all remaining is data key, v_name, v_type, v_size, v_data = policy.split(b";\x00", 4) # Removing trailing null-bytes key = strip_field_end(key).decode("utf-16-le") v_name = strip_field_end(v_name).decode("utf-16-le") # v_type is one of (0, 1, 2, 3, 4, 5, 7, 11) as 32-bit little-endian v_type = struct.unpack("<i", v_type)[0] if v_type == 0: # REG_NONE : No Type # We don't know what this data is, so don't do anything pass elif v_type in (1, 2): # REG_SZ : String Type # REG_EXPAND_SZ : String with Environment Variables, ie %PATH% v_data = strip_field_end(v_data).decode("utf-16-le") elif v_type == 4: # REG_DWORD : 32-bit little endian v_data = struct.unpack("<i", v_data)[0] elif v_type == 5: # REG_DWORD : 32-bit big endian v_data = struct.unpack(">i", v_data)[0] elif v_type == 7: # REG_MULTI_SZ : Multiple strings, delimited by \x00 v_data = strip_field_end(v_data) if not v_data: v_data = None else: v_data = v_data.decode("utf-16-le").split("\x00") elif v_type == 11: # REG_QWORD : 64-bit little endian v_data = struct.unpack("<q", v_data)[0] else: msg = f"LGPO_REG Util: Found unknown registry type: {v_type}" raise CommandExecutionError(msg) # Lookup the REG Type from the number reg = salt.utils.win_reg.Registry() v_type = reg.vtype_reverse.get(v_type, "REG_NONE") # Make the dictionary entries reg_pol.setdefault(key, {}) if not v_name: reg_pol[key]["*"] = "CREATEKEY" else: reg_pol[key][v_name] = {"type": v_type, "data": v_data} return reg_pol def dict_to_reg_pol(data): """ Convert a dictionary to the bytes format expected by the Registry.pol file Args: data (dict): A dictionary containing the contents to be converted Returns: bytes: The data to be written to the Registry.pol file """ # https://learn.microsoft.com/en-us/previous-versions/windows/desktop/Policy/registry-policy-file-format # https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gpreg/5c092c22-bf6b-4e7f-b180-b20743d368f5 reg = salt.utils.win_reg.Registry() pol_enter_delim = "[".encode("utf-16-le") pol_exit_delim = "]".encode("utf-16-le") pol_section_delim = ";".encode("utf-16-le") pol_section_term = "\x00".encode("utf-16-le") policies = [] for key, value in data.items(): for v_name, d in value.items(): # Handle CREATEKEY entry if v_name == "*" and d == "CREATEKEY": v_name = "" d = {"type": "REG_NONE"} try: v_type = reg.vtype[d["type"]] except KeyError: msg = "LGPO_REG Util: Found unknown registry type: {}".format(d["type"]) raise CommandExecutionError(msg) # The first three items are pretty straight forward policy = [ # Key followed by null byte f"{key}".encode("utf-16-le") + pol_section_term, # Value name followed by null byte f"{v_name}".encode("utf-16-le") + pol_section_term, # Type in 32-bit little-endian struct.pack("<i", v_type), ] # The data is encoded depending on the Type if v_type == 0: # REG_NONE : No value v_data = b"" elif v_type in (1, 2): # REG_SZ : String Type # REG_EXPAND_SZ : String with Environment Variables, ie %PATH% # Value followed by null byte v_data = d["data"].encode("utf-16-le") + pol_section_term elif v_type == 4: # REG_DWORD : Little Endian # 32-bit little endian v_data = struct.pack("<i", int(d["data"])) elif v_type == 5: # REG_DWORD : Big Endian (not common) # 32-bit big endian v_data = struct.pack(">i", int(d["data"])) elif v_type == 7: # REG_MULTI_SZ : Multiple strings # Each element is delimited by \x00, terminated by \x00\x00 # Then the entire output is terminated with a null byte if d["data"] is None: # An None value just gets the section terminator v_data = pol_section_term elif len(d["data"]) == 0: # An empty list just gets the section terminator v_data = pol_section_term elif len(d["data"]) == 1 and not d["data"][0]: # An list with an empty value just gets the section terminator v_data = pol_section_term else: # All others will be joined with a null byte, the list # terminated, and the entire section terminated v_data = ( "\x00".join(d["data"]).encode("utf-16-le") + pol_section_term + pol_section_term ) elif v_type == 11: # REG_QWORD : Little Endian # 64-bit little endian v_data = struct.pack("<q", int(d["data"])) # Now that we have the data in the right format, let's calculate its size # 16-bit little endian with null terminator if len(v_data) > 65535: msg = "LGPO_REG Util: Size exceeds 65535 bytes" raise CommandExecutionError(msg) v_size = len(v_data).to_bytes(2, "little") + pol_section_term policy.append(v_size) policy.append(v_data) policies.append(pol_section_delim.join(policy)) policy_file_data = REG_POL_HEADER.encode("utf-16-le") for policy in policies: policy_file_data += pol_enter_delim + policy + pol_exit_delim return policy_file_data