How to import passwords to Heimdal?
Steve Gaarder
gaarder1 at math.cornell.edu
Thu Dec 8 09:07:42 MST 2011
I have created a procedure and a couple Python scripts to synchronize a
password from an MIT KDC to a Samba4 domain controller. The procedure is
below, the scripts are attached, and everything is also here:
http://www.math.cornell.edu/~gaarder/mit-samba-sync.html
Note that this assumes that the user already exists in Samba, and that the CN
of the user is the same as the username. (If you create the user with
samba-tool and specify a surname, you should use the --use-username-as-cn
option.)
Step 1 - export the user from MIT:
On the MIT KDC, use kdb5_util to dump the user's key data. Use the -b7 dump
format option. E.g.:
kdb5_util dump -b7 USERNAME.mit USERNAME at REALM.WHATSAMATTAU.EDU
Step 2 - transfer the dump file to the Samba domain controller via your
preferred method.
Step 3 - remove unneeded keys
A Kerberos principal's key may be encoded in several different ways. The only
one Samba needs is arcfour-hmac-md5 (type 23), and the conversion code may
choke on other types. The Python script filterdump.py will remove all but the
first type 23 key; use it thus:
python filterdump.py <USERNAME.mit >USERNAME.mitdump
Step 4 - decrypt and convert the dump to Heimdal format
The MIT tools do not provide a way to get an unencrypted key, so we have to
convert to Heimdal format to decrypt it. This step and the next one can be done
with one script - see below.
Step 5 - extract the key, convert it to base64, and put it in the Samba
database
Step 4 and this step can be done with the script syncdump.py. This script
requires the Heimdal tools hprop and hpropd and copy of the key that was used
to encrypt the dump. This key is the same as the MIT master key (unless you
used the -mkey_convert option when you made the dump) and needs to be in keytab
format (older MIT "stash" format will not work). Heimdal's ktutil can be used
to create the key; make sure that the enctype is the same. Run this script (as
root) thus:
python syncdump.py USERNAME.mitdump
That's it!
--
Steve Gaarder
System Administrator, Dept of Mathematics
Cornell University, Ithaca, NY, USA
gaarder at math.cornell.edu
-------------- next part --------------
# This program takes an MIT dump and removes all keys except the first
# type 23 (arcfour) key that it finds. This is done so that it can be
# passed to hprop without the latter choking on key types it doesn't support.
""" Copyright (C) 2011 Steven Gaarder and Cornell University.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
For a copy of the GNU General Public License, see
<http://www.gnu.org/licenses/>."""
import sys, string
for line in sys.stdin.readlines():
foundkey = False
f = string.split(line,"\t")
if f[0] != "princ":
sys.stdout.write(line)
continue
principal_length = f[2]
num_tl = f[3]
for j in range(0,4):
sys.stdout.write(f[j] + "\t")
num_keys = f[4]
sys.stdout.write("1\t") # we will only output one key
num_extra = f[5]
principal = f[6]
for j in range(5,15):
sys.stdout.write(f[j] +"\t")
# tl_data starts at 15
i = 15
for t in range(int(num_tl)):
sys.stdout.write(f[i] + "\t" + f[i+1] + "\t" +f[i+2] + "\t")
i = i + 3
for k in range(int(num_keys)):
keystr = ""
type23 = False
key_data_version = f[i]
i = i + 1
kvno = f[i]
i = i + 1
keystr = key_data_version + "\t" + kvno
for v in range(int(key_data_version)):
if f[i] == "23":
type23 = True
keystr = keystr + "\t" + f[i] + "\t" + f[i+1] + "\t" + f[i+2]
i = i + 3
if type23 and not foundkey:
sys.stdout.write(keystr)
foundkey = True
#print the rest
for j in range(i, len(f)):
sys.stdout.write("\t" + f[j])
-------------- next part --------------
# This program extracts a type 23 key from an MIT dump and installs the
# password in a Samba 4 LDB database. The dump file name should be
# given on the command line.
# A copy of the key (in keytab format) used to encrypt the MIT dump must be
# in /usr/local/private/x-key. This key must have the same enctype as
# the one used to encrypt.
# We assume that Samba 4 is intalled in /usr/local/samba and that Heimdal
# is in /usr/heimdal.
""" Copyright (C) 2011 Steven Gaarder and Cornell University.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
For a copy of the GNU General Public License, see
<http://www.gnu.org/licenses/>."""
import sys
import subprocess
import re
import base64
import StringIO
myrealm = "REALM.WHATSAMATTAU.EDU"
mybase = "dc=realm,dc=whatsamattau,dc=edu"
infile = sys.argv[1]
# Use hprop and hpropd to get a Heimdal-format key
pout = subprocess.Popen(["/usr/heimdal/libexec/hprop --database=" + infile + " --source=mit-dump --decrypt --master-key=/usr/local/private/x-key --stdout|/usr/heimdal/libexec/hpropd -n --print"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
outlist = pout.stdout.readlines()
pat = re.compile("(\w+)@" + myrealm + ".*\d+:\d*:23:(\w+):")
mat = pat.search(outlist[0])
username = mat.group(1)
b64key = base64.b64encode( mat.group(2).decode("hex"))
# check to see that the user is in the system
ldbfilename = "/usr/local/samba/private/sam.ldb.d/" + mybase.upper() + ".ldb"
pout = subprocess.Popen(["/usr/local/samba/bin/ldbsearch", "-H", ldbfilename, "-b", "CN=Users," + mybase, "CN=" + username, "cn" ], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
outlist = pout.stdout.readlines()
respat = re.compile("returned\s(\d+)\srecords")
found = 0
for line in outlist:
resmat = respat.search(line)
if resmat != None:
found = resmat.group(1)
if int(found) <= 0:
print "User not found in database"
sys.exit(1)
# run it
pinn = subprocess.Popen(["/usr/local/samba/bin/ldbmodify", "-H", ldbfilename, "-b", "CN=Users," + mybase, "-i", "--nosync", "--controls=relax:0" ], shell=False, stdin=subprocess.PIPE)
ldifstr="dn: CN=" + username + ",CN=Users," + mybase +"\n" + "changetype: modify\n" + "replace: unicodePwd\n" + "unicodePwd:: " + b64key +"\n"
pinn.communicate(input=ldifstr)
More information about the samba-technical
mailing list