Author Topic: 2023 Philosophy Seminar  (Read 568 times)

stanl

  • Pundit
  • *****
  • Posts: 1849
2023 Philosophy Seminar
« on: November 05, 2023, 09:41:29 am »
Trying to iterate multiple columns from security user logons to our 7 server environments [where an individual user could have mulriple logons - I decided to throw in columns from an ADSI lookup based on 'samaccountname' ... and for real fun asked the query to return the useracountcontrol... which in most cases gave 512 but in the few needed to be removed from privileges - 514....


and, I know you are now thinking "we already know that"


So, my question is simple: what is the difference between an enum, a map, an array, a list , a hashtable [as declared as such]... so that I can prove a return code of 514 is based on the B'or of 512/2  based on

SCRIPT = 1
ACCOUNTDISABLE = 2
HOMEDIR_REQUIRED = 8
LOCKOUT = 16
PASSWD_NOTREQD = 32
PASSWD_CANT_CHANGE = 64
ENCRYPTED_TEXT_PWD_ALLOWED = 128
TEMP_DUPLICATE_ACCOUNT = 256
NORMAL_ACCOUNT = 512
INTERDOMAIN_TRUST_ACCOUNT = 2048
WORKSTATION_TRUST_ACCOUNT = 4096
SERVER_TRUST_ACCOUNT = 8192
DONT_EXPIRE_PASSWORD = 65536
MNS_LOGON_ACCOUNT = 131072
SMARTCARD_REQUIRED = 262144
TRUSTED_FOR_DELEGATION = 524288
NOT_DELEGATED = 1048576
USE_DES_KEY_ONLY = 2097152
DONT_REQ_PREAUTH = 4194304
PASSWORD_EXPIRED = 8388608
TRUSTED_TO_AUTH_FOR_DELEGATION = 16777216
PARTIAL_SECRETS_ACCOUNT = 67108864


Based on what I Bing'd... calling the above an enum, is the best bet. NOTE: there is a lot on Tech Support about ADSI and the Extender so nothing against it.


But: retrieving a value of 514, how to determne the lookup(s) text for that value.

ChuckC

  • Sr. Member
  • ****
  • Posts: 435
Re: 2023 Philosophy Seminar
« Reply #1 on: November 07, 2023, 02:28:50 pm »
If you were working with C#, you'd declare an 'enum' type, possibly with an underlying 'uint' ['UInt32'] type, and apply the '[Flags]' attribute to it.

Combining flag bit values via bit-wise 'OR' operations is simple to produce a flags mask value.

Converting a flags mask value into individual bits and then deriving string name values is a bit more of a chore.  In effect, you have to take the flags mask and perform a bit-wise 'AND' operation with each defined flag bit value in the enumerated type and test for that bit's value or just for a non-zero value.  If there is a match, compute the necessary name value as a string and return it.  Given that there can be multiple bits enabled in the flags mask, the return value could have multiple string values with names for each enabled bit so using some kind of container/collection of strings is advisable.

If you need to maintain an association between each flag bit and its corresponding name in your return value(s), you could utilize a map.  The same map could also be utilized if just returning a name for each flag bit.

stanl

  • Pundit
  • *****
  • Posts: 1849
Re: 2023 Philosophy Seminar
« Reply #2 on: November 08, 2023, 02:32:13 am »
Thanks Chuck.  Looking over old adsi code I wrote in 2010 to parse the useraccountcontrol value. Was looking at a CLR option of a way to construct an enum.
Code: Winbatch

;Stan Littlefield, November 1, 2010
;/////////////////////////////////////////////////////////////////////////////////////////
oRoot = getobject("LDAP://RootDSE")
oLDAP = GetObject("LDAP://ou=admins,":oRoot.get("defaultnamingcontext")) ;substitute for your own value


ForEach user in olDAP
   If user.name=="CN=myadmin"  ;substitute for your own value
      tags=""
      iUser=user.Get("userAccountControl")
      While iUser > 0
         If iUser >= 134217728 && iUser <= 2147483647   ;Then - optional
            iUser = iUser - 134217728
            tags=tags:"USE_AES_KEYS":@CRLF
         elseif iUser >= 67108864 && iUser < 134217728  ;Then - optional
            iUser = iUser - 67108864
            tags=tags:"PARTIAL_SECRETS_ACCOUNT":@CRLF
         elseif iUser >= 16777216 && iUser < 67108864
            iUser= iUser - 16777216
            tags=tags:"TRUSTED_TO_AUTH_FOR_DELEGATION":@CRLF
         elseif iUser >= 8388608 && iUser < 16777216
            iUser= iUser - 8388608
            tags=tags:"PASSWORD_EXPIRED":@CRLF
         elseif iUser >= 4194304 && iUser < 8388608
            iUser= iUser - 4194304
            tags=tags:"DONT_REQ_PREAUTH":@CRLF
         elseif iUser >= 2097152 && iUser < 4194304
            iUser= iUser - 2097152
            tags=tags:"USE_DES_KEY_ONLY":@CRLF
         elseif iUser >= 1048576 && iUser < 2097152
            iUser= iUser - 1048576
            tags=tags:"NOT_DELEGATED":@CRLF
         elseif iUser >= 524288 && iUser < 1048576
            iUser= iUser - 524288
            tags=tags:"TRUSTED_FOR_DELEGATION":@CRLF
         elseif iUser >= 262144 && iUser < 524288
            iUser= iUser - 262144
            tags=tags:"SMARTCARD_REQUIRED":@CRLF
         elseif iUser >= 131072 && iUser < 262144
            iUser= iUser - 131072
            tags=tags:"MNS_LOGON_ACCOUNT":@CRLF
         elseif iUser >= 65536 && iUser < 131072
            iUser= iUser - 65536
            tags=tags:"DONT_EXPIRE_PASSWORD":@CRLF
         elseif iUser >= 8192 && iUser < 65536
            iUser= iUser - 8192
            tags=tags:"SERVER_TRUST_ACCOUNT":@CRLF
         elseif iUser >= 4096 && iUser < 8192
            iUser= iUser - 4096
            tags=tags:"WORKSTATION_TRUST_ACCOUNT":@CRLF
         elseif iUser >= 2048 && iUser < 4096
            iUser= iUser - 2048
            tags=tags:"INTERDOMAIN_TRUST_ACCOUNT":@CRLF
         elseif iUser >= 512 && iUser < 2048
            iUser= iUser - 512
            tags=tags:"NORMAL_ACCOUNT":@CRLF
         elseif iUser >= 256 && iUser < 512
            iUser= iUser - 256
            tags=tags:"TEMP_DUPLICATE_ACCOUNT":@CRLF
         elseif iUser >= 128 && iUser < 256
            iUser= iUser - 128
            tags=tags:"ENCRYPTED_TEXT_PWD_ALLOWED":@CRLF
         elseif iUser >= 64 && iUser < 128
            iUser= iUser - 64
            tags=tags:"PASSWD_CANT_CHANGE":@CRLF
         elseif iUser >= 32 && iUser < 64
            iUser= iUser - 32
            tags=tags:"PASSWD_NOTREQD":@CRLF
         elseif iUser >= 16 && iUser < 32
            iUser= iUser - 16
            tags=tags:"LOCKOUT":@CRLF
         elseif iUser >= 8 && iUser < 16
            iUser= iUser - 8
            tags=tags:"HOMEDIR_REQUIRED":@CRLF
         elseif iUser >= 2 && iUser < 8
            iUser= iUser - 2
            tags=tags:"ACCOUNTDISABLE":@CRLF
         elseif iUser >= 1 && iUser < 2
            iUser= iUser - 1
            tags=tags:"SCRIPT":@CRLF
         EndIf
   Endwhile
   Message("",tags)
   Endif
Next




iUser=0
oLDAP=0




Exit
;/////////////////////////////////////////////////////////////////////////////////////////


 

ChuckC

  • Sr. Member
  • ****
  • Posts: 435
Re: 2023 Philosophy Seminar
« Reply #3 on: November 08, 2023, 06:41:50 am »
You could dynamically compile some C# code into an in-memory assembly where it defines the enumerated type and provides a class with methods to perform the conversions between flag bit values and enumerated value names.  C# has support for getting the name of each value from an enum type and vice versa for providing a string name and getting the enum value.

stanl

  • Pundit
  • *****
  • Posts: 1849
Re: 2023 Philosophy Seminar
« Reply #4 on: November 09, 2023, 03:09:36 am »
You could dynamically compile some C# code into an in-memory assembly where it defines the enumerated type and provides a class with methods to perform the conversions between flag bit values and enumerated value names.  C# has support for getting the name of each value from an enum type and vice versa for providing a string name and getting the enum value.


Thanks again. I'm looking at playing with System.DirectoryServices Namespace for searching Active Directory. I found PS code for the enum - it returns one or more enum names based on bitwise or -  i.e. if useraccountcontrol returns 512 it returns NORMAL_ACCOUNT, while 514 returns ACCOUNTDISABLE + NORMAL_ACCOUNT => which is what I am after. I'll take a look at C# but out of laziness will probably just call PS code from WB's CLR ::)

td

  • Tech Support
  • *****
  • Posts: 4444
    • WinBatch
Re: 2023 Philosophy Seminar
« Reply #5 on: November 10, 2023, 07:55:39 am »
Another approach:

Code: Winbatch
EnumPairs = $"1,SCRIPT
2,ACCOUNTDISABLE
8,HOMEDIR_REQUIRED
16,LOCKOUT
32,PASSWD_NOTREQD
64,PASSWD_CANT_CHANGE
128,ENCRYPTED_TEXT_PWD_ALLOWED
256,TEMP_DUPLICATE_ACCOUNT
512,NORMAL_ACCOUNT2
2048,INTERDOMAIN_TRUST_ACCOUNT
4096,WORKSTATION_TRUST_ACCOUNT
8192,SERVER_TRUST_ACCOUNT
65536,DONT_EXPIRE_PASSWORD
131072,MNS_LOGON_ACCOUNT
262144,SMARTCARD_REQUIRED
524288,TRUSTED_FOR_DELEGATION
1048576,NOT_DELEGATED
2097152,USE_DES_KEY_ONLY
4194304,DONT_REQ_PREAUTH
8388608,PASSWORD_EXPIRED
16777216,TRUSTED_TO_AUTH_FOR_DELEGATION
67108864,PARTIAL_SECRETS_ACCOUNT$"

EnumPairs = StrReplace(EnumPairs, @cr, "") ; Remove editor dependence
UacSettings = MapCreate(EnumPairs, ",", @lf)

UserVals = 514
SettingsText = ""
foreach Key in UacSettings
   if UserVals & Key
      if SettingsText != "" then SettingsText :="|"
      SettingsText := UacSettings[Key]
      UserVals &= (~Key)
   endif
   if !UserVals then break
next

Message("User UAC Settings", SettingsText)

exit
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

  • Pundit
  • *****
  • Posts: 1849
Re: 2023 Philosophy Seminar
« Reply #6 on: November 10, 2023, 02:26:57 pm »
Damn. Pretty Slick.


EDIT:


So an enum could be treated as a Map by inverting the key|value. I now have several to test, and to return to my initial post where I stated:


So, my question is simple: what is the difference between an enum, a map, an array, a list , a hashtable [as declared as such].


I did modify the code you sent to use = instead of , for separator and, of course, still worked fine, and I appreciate making it simple w/out having to integrate PS code. ;)