2005-07-12 11:46:34 +00:00
/ *
backend code for provisioning a Samba4 server
Copyright Andrew Tridgell 2005
Released under the GNU GPL v2 or later
* /
/* used to generate sequence numbers for records */
provision _next _usn = 1 ;
2005-07-15 07:45:40 +00:00
sys = sys _init ( ) ;
2005-07-20 11:26:17 +00:00
/ *
return true if the current install seems to be OK
* /
function install _ok ( )
{
var lp = loadparm _init ( ) ;
var ldb = ldb _init ( ) ;
if ( lp . get ( "realm" ) == "" ) {
return false ;
}
var ok = ldb . connect ( lp . get ( "sam database" ) ) ;
if ( ! ok ) {
return false ;
}
var res = ldb . search ( "(name=Administrator)" ) ;
if ( res . length != 1 ) {
return false ;
}
return true ;
}
2005-07-12 11:46:34 +00:00
/ *
find a user or group from a list of possibilities
* /
function findnss ( )
{
var i ;
assert ( arguments . length >= 2 ) ;
var nssfn = arguments [ 0 ] ;
for ( i = 1 ; i < arguments . length ; i ++ ) {
if ( nssfn ( arguments [ i ] ) != undefined ) {
return arguments [ i ] ;
}
}
printf ( "Unable to find user/group for %s\n" , arguments [ 1 ] ) ;
assert ( i < arguments . length ) ;
}
/ *
add a foreign security principle
* /
function add _foreign ( str , sid , desc , unixname )
{
var add = "
dn : CN = $ { SID } , CN = ForeignSecurityPrincipals , $ { BASEDN }
objectClass : top
objectClass : foreignSecurityPrincipal
cn : $ { SID }
description : $ { DESC }
instanceType : 4
whenCreated : $ { LDAPTIME }
whenChanged : $ { LDAPTIME }
uSNCreated : 1
uSNChanged : 1
showInAdvancedViewOnly : TRUE
name : $ { SID }
objectGUID : $ { NEWGUID }
objectSid : $ { SID }
objectCategory : CN = Foreign - Security - Principal , CN = Schema , CN = Configuration , $ { BASEDN }
unixName : $ { UNIXNAME }
" ;
var sub = new Object ( ) ;
sub . SID = sid ;
sub . DESC = desc ;
sub . UNIXNAME = unixname ;
return str + substitute _var ( add , sub ) ;
}
/ *
return current time as a nt time string
* /
function nttime ( )
{
2005-07-15 07:45:40 +00:00
return "" + sys . nttime ( ) ;
2005-07-12 11:46:34 +00:00
}
/ *
return current time as a ldap time string
* /
function ldaptime ( )
{
2005-07-15 07:45:40 +00:00
return sys . ldaptime ( sys . nttime ( ) ) ;
2005-07-12 11:46:34 +00:00
}
/ *
return a date string suitable for a dns zone serial number
* /
function datestring ( )
{
2005-07-15 07:45:40 +00:00
var t = sys . gmtime ( sys . nttime ( ) ) ;
2005-07-12 11:46:34 +00:00
return sprintf ( "%04u%02u%02u%02u" ,
t . tm _year + 1900 , t . tm _mon + 1 , t . tm _mday , t . tm _hour ) ;
}
/ *
return first host IP
* /
function hostip ( )
{
2005-07-15 07:45:40 +00:00
var list = sys . interfaces ( ) ;
2005-07-12 11:46:34 +00:00
return list [ 0 ] ;
}
/ *
return current time as a ldap time string
* /
function nextusn ( )
{
provision _next _usn = provision _next _usn + 1 ;
return provision _next _usn ;
}
/ *
return first part of hostname
* /
function hostname ( )
{
2005-07-15 07:45:40 +00:00
var s = split ( "." , sys . hostname ( ) ) ;
2005-07-12 11:46:34 +00:00
return s [ 0 ] ;
}
2005-07-19 02:10:08 +00:00
/ *
erase an ldb , removing all records
* /
function ldb _erase ( ldb )
{
var attrs = new Array ( "dn" ) ;
/* delete the specials */
ldb . del ( "@INDEXLIST" ) ;
ldb . del ( "@ATTRIBUTES" ) ;
ldb . del ( "@SUBCLASSES" ) ;
ldb . del ( "@MODULES" ) ;
/* and the rest */
var res = ldb . search ( "(|(objectclass=*)(dn=*))" , attrs ) ;
var i ;
for ( i = 0 ; i < res . length ; i ++ ) {
ldb . del ( res [ i ] . dn ) ;
}
res = ldb . search ( "(objectclass=*)" , attrs ) ;
assert ( res . length == 0 ) ;
}
2005-07-12 11:46:34 +00:00
/ *
setup a ldb in the private dir
* /
function setup _ldb ( ldif , dbname , subobj )
{
var extra = "" ;
2005-07-15 05:40:34 +00:00
var ldb = ldb _init ( ) ;
2005-07-20 07:20:03 +00:00
var lp = loadparm _init ( ) ;
2005-07-15 05:40:34 +00:00
2005-07-12 11:46:34 +00:00
if ( arguments . length == 4 ) {
extra = arguments [ 3 ] ;
}
2005-07-19 11:55:35 +00:00
var dbfile = dbname ;
2005-07-20 07:20:03 +00:00
var src = lp . get ( "setup directory" ) + "/" + ldif ;
2005-07-12 11:46:34 +00:00
2005-07-15 07:45:40 +00:00
var data = sys . file _load ( src ) ;
2005-07-12 11:46:34 +00:00
data = data + extra ;
data = substitute _var ( data , subobj ) ;
2005-07-15 11:10:38 +00:00
var ok = ldb . connect ( dbfile ) ;
assert ( ok ) ;
2005-07-15 09:23:23 +00:00
2005-07-19 02:10:08 +00:00
ldb _erase ( ldb ) ;
2005-07-15 11:10:38 +00:00
ok = ldb . add ( data ) ;
2005-07-12 11:46:34 +00:00
assert ( ok ) ;
}
/ *
setup a file in the private dir
* /
function setup _file ( template , fname , subobj )
{
2005-07-20 07:20:03 +00:00
var lp = loadparm _init ( ) ;
2005-07-20 10:07:48 +00:00
var f = fname ;
2005-07-20 07:20:03 +00:00
var src = lp . get ( "setup directory" ) + "/" + template ;
2005-07-12 11:46:34 +00:00
2005-07-15 07:45:40 +00:00
sys . unlink ( f ) ;
2005-07-12 11:46:34 +00:00
2005-07-15 07:45:40 +00:00
var data = sys . file _load ( src ) ;
2005-07-12 11:46:34 +00:00
data = substitute _var ( data , subobj ) ;
2005-07-15 07:45:40 +00:00
ok = sys . file _save ( f , data ) ;
2005-07-12 11:46:34 +00:00
assert ( ok ) ;
}
/ *
provision samba4 - caution , this wipes all existing data !
* /
function provision ( subobj , message )
{
var data = "" ;
2005-07-20 10:07:48 +00:00
var lp = loadparm _init ( ) ;
var sys = sys _init ( ) ;
var smbconf = lp . get ( "config file" ) ;
2005-07-12 11:46:34 +00:00
/ *
some options need to be upper / lower case
* /
subobj . REALM = strlower ( subobj . REALM ) ;
subobj . HOSTNAME = strlower ( subobj . HOSTNAME ) ;
subobj . DOMAIN = strupper ( subobj . DOMAIN ) ;
subobj . NETBIOSNAME = strupper ( subobj . HOSTNAME ) ;
data = add _foreign ( data , "S-1-5-7" , "Anonymous" , "${NOBODY}" ) ;
data = add _foreign ( data , "S-1-1-0" , "World" , "${NOGROUP}" ) ;
data = add _foreign ( data , "S-1-5-2" , "Network" , "${NOGROUP}" ) ;
data = add _foreign ( data , "S-1-5-18" , "System" , "${ROOT}" ) ;
data = add _foreign ( data , "S-1-5-11" , "Authenticated Users" , "${USERS}" ) ;
provision _next _usn = 1 ;
2005-07-20 10:07:48 +00:00
/* only install a new smb.conf if there isn't one there already */
var st = sys . stat ( smbconf ) ;
if ( st == undefined ) {
message ( "Setting up smb.conf\n" ) ;
setup _file ( "provision.smb.conf" , smbconf , subobj ) ;
lp . reload ( ) ;
}
2005-07-12 11:46:34 +00:00
message ( "Setting up hklm.ldb\n" ) ;
setup _ldb ( "hklm.ldif" , "hklm.ldb" , subobj ) ;
message ( "Setting up sam.ldb\n" ) ;
setup _ldb ( "provision.ldif" , "sam.ldb" , subobj , data ) ;
message ( "Setting up rootdse.ldb\n" ) ;
setup _ldb ( "rootdse.ldif" , "rootdse.ldb" , subobj ) ;
message ( "Setting up secrets.ldb\n" ) ;
setup _ldb ( "secrets.ldif" , "secrets.ldb" , subobj ) ;
message ( "Setting up DNS zone file\n" ) ;
2005-07-20 10:07:48 +00:00
setup _file ( "provision.zone" ,
lp . get ( "private dir" ) + "/" + subobj . DNSDOMAIN + ".zone" ,
subobj ) ;
2005-07-12 11:46:34 +00:00
}
/ *
guess reasonably default options for provisioning
* /
function provision _guess ( )
{
var subobj = new Object ( ) ;
2005-07-19 00:16:43 +00:00
var nss = nss _init ( ) ;
2005-07-20 07:20:03 +00:00
var lp = loadparm _init ( ) ;
2005-07-20 07:29:23 +00:00
random _init ( local ) ;
2005-07-19 00:16:43 +00:00
2005-07-20 07:20:03 +00:00
subobj . REALM = lp . get ( "realm" ) ;
subobj . DOMAIN = lp . get ( "workgroup" ) ;
2005-07-12 11:46:34 +00:00
subobj . HOSTNAME = hostname ( ) ;
2005-07-20 10:07:48 +00:00
assert ( subobj . REALM ) ;
assert ( subobj . DOMAIN ) ;
assert ( subobj . HOSTNAME ) ;
2005-07-12 11:46:34 +00:00
subobj . HOSTIP = hostip ( ) ;
subobj . DOMAINGUID = randguid ( ) ;
subobj . DOMAINSID = randsid ( ) ;
subobj . HOSTGUID = randguid ( ) ;
subobj . INVOCATIONID = randguid ( ) ;
subobj . KRBTGTPASS = randpass ( 12 ) ;
subobj . MACHINEPASS = randpass ( 12 ) ;
subobj . ADMINPASS = randpass ( 12 ) ;
subobj . DEFAULTSITE = "Default-First-Site-Name" ;
subobj . NEWGUID = randguid ;
subobj . NTTIME = nttime ;
subobj . LDAPTIME = ldaptime ;
subobj . DATESTRING = datestring ;
subobj . USN = nextusn ;
2005-07-19 00:16:43 +00:00
subobj . ROOT = findnss ( nss . getpwnam , "root" ) ;
subobj . NOBODY = findnss ( nss . getpwnam , "nobody" ) ;
subobj . NOGROUP = findnss ( nss . getgrnam , "nogroup" , "nobody" ) ;
subobj . WHEEL = findnss ( nss . getgrnam , "wheel" , "root" ) ;
subobj . USERS = findnss ( nss . getgrnam , "users" , "guest" , "other" ) ;
2005-07-12 11:46:34 +00:00
subobj . DNSDOMAIN = strlower ( subobj . REALM ) ;
subobj . DNSNAME = sprintf ( "%s.%s" ,
strlower ( subobj . HOSTNAME ) ,
subobj . DNSDOMAIN ) ;
subobj . BASEDN = "DC=" + join ( ",DC=" , split ( "." , subobj . REALM ) ) ;
return subobj ;
}
2005-07-18 23:58:18 +00:00
/ *
search for one attribute as a string
* /
function searchone ( ldb , expression , attribute )
{
var attrs = new Array ( attribute ) ;
res = ldb . search ( expression , attrs ) ;
if ( res . length != 1 ||
res [ 0 ] [ attribute ] == undefined ) {
return undefined ;
}
return res [ 0 ] [ attribute ] ;
}
/ *
add a new user record
* /
function newuser ( username , unixname , password , message )
{
2005-07-20 07:20:03 +00:00
var lp = loadparm _init ( ) ;
var samdb = lp . get ( "sam database" ) ;
2005-07-18 23:58:18 +00:00
var ldb = ldb _init ( ) ;
2005-07-20 07:29:23 +00:00
random _init ( local ) ;
2005-07-18 23:58:18 +00:00
/* connect to the sam */
var ok = ldb . connect ( samdb ) ;
assert ( ok ) ;
/* find the DNs for the domain and the domain users group */
var domain _dn = searchone ( ldb , "objectClass=domainDNS" , "dn" ) ;
assert ( domain _dn != undefined ) ;
var dom _users = searchone ( ldb , "name=Domain Users" , "dn" ) ;
assert ( dom _users != undefined ) ;
var user _dn = sprintf ( "CN=%s,CN=Users,%s" , username , domain _dn ) ;
/ *
the new user record . note the reliance on the samdb module to fill
in a sid , guid etc
* /
var ldif = sprintf ( "
dn : % s
sAMAccountName : % s
name : % s
memberOf : % s
unixName : % s
objectGUID : % s
unicodePwd : % s
objectClass : user
" ,
user _dn , username , username , dom _users ,
unixname , randguid ( ) , password ) ;
/ *
add the user to the users group as well
* /
var modgroup = sprintf ( "
dn : % s
changetype : modify
add : member
member : % s
" ,
dom _users , user _dn ) ;
/ *
now the real work
* /
message ( "Adding user %s\n" , user _dn ) ;
ok = ldb . add ( ldif ) ;
if ( ok != true ) {
message ( "Failed to add %s - %s\n" , user _dn , ldb . errstring ( ) ) ;
return false ;
}
message ( "Modifying group %s\n" , dom _users ) ;
ok = ldb . modify ( modgroup ) ;
if ( ok != true ) {
message ( "Failed to modify %s - %s\n" , dom _users , ldb . errstring ( ) ) ;
return false ;
}
return true ;
}
2005-07-12 11:46:34 +00:00
return 0 ;