Creating Active Directory Accounts

Using LDIF files and OpenLDAP tools

© 2009 Dennis Leeuw

Introduction

This document not only documents how to create accounts within Active Directory with the use of Open Source tools (mainly the OpenLDAP tools), but is also a place where I store everything that I found during my search for the knowledge required to create such accounts.

Microsoft can be best accessed through secure access. To accomplish this one should create a .ldaprc file in ones home directory with the following content:

use_sasl        on
ssl             on
sasl            start_tls
SASL_MECH       GSSAPI
tls_checkpeer   no
tls_ciphers     TLSv1
TLS_REQCERT     never
chasereferrals  yes
deref           always
uri             uri ldaps://ads.forest.example.com/
binddn          cn=administrator,cn=Users,dc=forest,dc=example,dc=com

# Tell GSSAPI not to negotiate a security or privacy layer since
# AD doesn't support nested security or privacy layers
sasl_secprops   minssf=0,maxssf=0
tls_cacertfile  ads.pem"

Microsoft stores passwords as a simple base64 encoded quoted string, thus the only way to set the password in a secure manner is by using an SSL encrypted connection, which Microsoft thus enforces on the connection to set the password. To make this possible, you need the server certificate from AD. The ads.pem file can be obtained from the AD server like this:

And use ldapadd or ldapmodify like this:

ldapadd -x -H ldaps://ads.forest.example.com:636/ \
-D "CN=Administrator,CN=Users,DC=forest,DC=example,DC=com" -W -f file.ldif

Groups

dn: CN=MyGroup,cn=Groups,dc=forest,dc=examle,dc=com
name: MyGroup
distinguishedName: CN=MyGroup,cn=Groups,dc=forest,dc=examle,dc=com
instanceType: 4
sAMAccountName: MyGroup
msSFU30Name: MyGroup
msSFU30NisDomain: forest
gidNumber: 666

Note: The NisDomain is needed to set the gidNumber. The gidNumber is not needed by AD, but is used for Unix interoperability.

A fixed value used in all LDIF account files is the instanceType, 4 means that the object is writable on this directory:
Value Description
0x00000001 The head of naming context
0x00000002 This replica is not instantiated
0x00000004 The object is writable on this directory
0x00000008 The naming context above this one on this directory is held
0x00000010 The naming context is in the process of being constructed for the first time via replication
0x00000020 The naming context is in the process of being removed from the local DSA

In LDIF files taken from AD you see a lot of extra fields. Setting one of those fields will most of the time make the server "unwilling to perform". Still I'd like to give some explanation about some of the fields so you know what they mean.

sAMAccountType
Internal nameHex valueLDIF value
SAM_GROUP_OBJECT0x10000000268435456
SAM_NON_SECURITY_GROUP_OBJECT0x10000001268435457
SAM_ALIAS_OBJECT0x20000000536870912
SAM_NON_SECURITY_ALIAS_OBJECT0x20000001536870913
SAM_USER_OBJECT0x30000000
SAM_NORMAL_USER_ACCOUNT0x30000000805306368
SAM_MACHINE_ACCOUNT0x30000001805306369
SAM_TRUST_ACCOUNT0x30000002805306370
SAM_APP_BASIC_GROUP1073741824
SAM_APP_QUERY_GROUP1073741825
SAM_ACCOUNT_TYPE_MAX2147483647

The User LDIF

To create users from an LDIF you first need to create the user, and make it disabled, then set the password and then enable the account. However we can use a single LDIF file to do all those steps at once.

The userAccountControl determines if an account is enabled or disabled. According to Microsoft's documentation the following values can be used and combined:
Tag Name Notes
SCRIPT 1
ACCOUNTDISABLE 2
HOMEDIR_REQUIRED 8
LOCKOUT 16
PASSWD_NOTREQD 32 You can not assign this permission
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
So 512 is a normal user account adding 2 results in a normal user account, but disabled.

To make sure that the account never expires we set the accountExpires value to 0, which seems to work. Although according to http://arnoutvandervorst.blogspot.com/2008/03/ldap-accountexpires-attribute-values.html, the initial value should be: 9223372036854775807.

Of course the user needs a password. To create the password do:

echo -n "\"password\"" | iconv -f UTF8 -t UTF16LE | base64 -w 0

Microsoft stores a quoted password in little endian UTF16 base64 encoded. The trivial command above takes care of it all. Note the -n option to echo, otherwise the carriage-return will also be part of the password.

The first part of the following LDIF creates the disabled user account, the second part sets the password and the last part enables the account:

dn: CN=Piet Prutser,CN=Users,DC=forest,DC=example,DC=com 
changetype: add 
objectClass: top 
objectClass: person 
objectClass: organizationalPerson 
objectClass: user 
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=example,DC=com
codePage: 0 
countryCode: 0 
distinguishedName: CN=Piet Prutser,CN=Users,DC=forest,DC=example,DC=com 
cn: Piet Prutser
sn: Prutser 
givenName: Piet 
displayName: Piet Prutser 
name: Piet Prutser 
telephoneNumber: 123456 
instanceType: 4 
userAccountControl: 514 
accountExpires: 0 
uidNumber: 600
gidNumber: 600 
sAMAccountName: pprutser 
userPrincipalName: P.Prutser@example.com 
altSecurityIdentities: Kerberos:pprutser@EXAMLE.COM
mail: P.Prutser@example.com
homeDirectory: \\ads\home\pprutser 
homeDrive: Z: 
unixHomeDirectory: /home/pprutser 
loginShell: /bin/bash 

dn: CN=Piet Prutser,OU=Users,DC=forest,DC=example,DC=com 
changetype: modify 
replace: unicodePwd 
unicodePwd::IlwwdFwwZVwwc1wwdFwwIgo=

dn: CN=Piet Prutser,OU=Users,DC=forest,DC=example,DC=com 
changetype: modify 
replace: userAccountControl
userAccountControl: 512

When you get an error report like this:

ldap_modify: Server is unwilling to perform (53) 
additional info: 0000001F: SvcErr: DSID-031A0FC0, problem 5003 (WILL_NOT_PERFORM), data 0
It means that the password (like the one in the example) is not a correct UTF16LE password (you didn't think I would actually put in a correct password with such weak encryption didn't you).

Machine accounts

dn: CN=HOSTNAME,ou=Computers,dc=forest,dc=example,dc=com
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
objectClass: computer
cn: HOSTNAME
distinguishedName: CN=HOSTNAME,ou=Computers,dc=forest,dc=example,dc=com
objectCategory: CN=Computer,CN=Schema,CN=Configuration,dc=forest,dc=example,dc=com
instanceType: 4
displayName: HOSTNAME$
name: HOSTNAME
userAccountControl: 4096
codePage: 0
countryCode: 0
accountExpires: 0
sAMAccountName: HOSTNAME$
dNSHostName: HOSTNAME.forest.example.com
servicePrincipalName: HOST/HOSTNAME
servicePrincipalName: HOST/HOSTNAME.forest.example.com

Fields that certainly will not be excepted are:

isCriticalSystemObject:
localPolicyFlags:
sAMAccountType: 
A special one which is also not accepted is primaryGroupID. Somehow Microsoft uses some predefined Group IDs:
513Domain Users
514Domain Guests
515Domain Computers
516Domain Controllers

Add users to groups

Within AD you have several places where lists of users are maintained who belong to a certain group. The user properties has a 'Member Of' tab and the group properties has a 'Member Of' and a 'Members' tab. The 'Member Of' tabs are not changeable. They only show to which group an object (group or user) belongs. The Members list is what we are concerned with. This one you can change. A simple LDIF like this:

dn: CN=groupname,ou=Groups,dc=forest,dc=example,dc=com
changetype: modify
add: member
member: CN=User Name,CN=Users,DC=forest,DC=example,DC=com
adds the use with user name 'User Name' to the group 'groupname'.