aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLebedev Vadim <abraham1901@gmail.com>2013-03-18 18:55:58 +0400
committerAdam Jahn <ajjahn@gmail.com>2013-03-19 21:14:30 -0400
commit32f1dc699c77ae665d8c8e39d8d9c2c3fb497df9 (patch)
tree6b2edbb451b76b18c3bbc3a49d591e91e24e2b06
parentd612151695cb9121d4aebcdb8a39c0ee87f7c612 (diff)
downloadpuppet-samba-32f1dc699c77ae665d8c8e39d8d9c2c3fb497df9.tar.gz
puppet-samba-32f1dc699c77ae665d8c8e39d8d9c2c3fb497df9.tar.bz2
Add implementation join Samba server into Active Directory
Conflicts: manifests/server/share.pp
-rw-r--r--README.md28
-rw-r--r--manifests/init.pp4
-rw-r--r--manifests/server.pp58
-rw-r--r--manifests/server/ads.pp116
-rw-r--r--manifests/server/share.pp5
-rw-r--r--manifests/server/winbind.pp16
-rw-r--r--templates/configure_active_directory.erb142
-rw-r--r--templates/verify_active_directory.erb107
8 files changed, 431 insertions, 45 deletions
diff --git a/README.md b/README.md
index 4a57fd7..6bb9a79 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,34 @@ Tweak and add the following to your site manifest:
}
}
+If you want join Samba server to Active Directory. Tested on Ubuntu 12.04.
+
+ node 'server.example.com' {
+ class {'samba::server':
+ workgroup => 'example',
+ server_string => "Example Samba Server",
+ interfaces => "eth0 lo",
+ security => 'ads'
+ }
+
+ samba::server::share {'ri-storage':
+ comment => 'RBTH User Storage',
+ path => "$smb_share",
+ browsable => true,
+ writable => true,
+ create_mask => 0770,
+ directory_mask => 0770,
+ }
+
+ class { 'samba::server::ads':
+ winbind_acct => $::domain_admin,
+ winbind_pass => $::admin_password,
+ realm => 'EXAMPLE.COM',
+ nsswitch => true,
+ target_ou => "Nix_Mashine"
+ }
+ }
+
Most configuration options are optional.
## Contributing
diff --git a/manifests/init.pp b/manifests/init.pp
index c71ee1d..8a914a4 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -1,3 +1,7 @@
class samba {
include samba::server
+
+ if samba::server::security == 'ads' {
+ include samba::server::ads
+ }
} \ No newline at end of file
diff --git a/manifests/server.pp b/manifests/server.pp
index cc1a951..9b6d3c0 100644
--- a/manifests/server.pp
+++ b/manifests/server.pp
@@ -18,53 +18,27 @@ class samba::server($interfaces = '',
notify => Class['samba::server::service']
}
- augeas { 'global-interfaces':
- context => $context,
- changes => $interfaces ? {
- default => ["set \"${target}/interfaces\" '${interfaces}'", "set \"${target}/bind interfaces only\" yes"],
- '' => ["rm \"${target}/interfaces\"", "rm \"${target}/bind interfaces only\""],
- },
- require => Augeas['global-section'],
- notify => Class['samba::server::service']
- }
- augeas { 'global-security':
- context => $context,
- changes => $security ? {
- default => "set \"${target}/security\" '${security}'",
- '' => "rm \"${target}/security\"",
- },
- require => Augeas['global-section'],
- notify => Class['samba::server::service']
- }
-
- augeas { 'global-server_string':
- context => $context,
- changes => $server_string ? {
- default => "set \"${target}/server string\" '${server_string}'",
- '' => "rm \"${target}/server string\"",
- },
- require => Augeas['global-section'],
- notify => Class['samba::server::service']
+ set_samba_option {
+ 'bind interfaces only': value => 'yes';
+ 'security': value => $security;
+ 'server string': value => $server_string;
+ 'unix password sync': value => $unix_password_sync;
+ 'workgroup': value => $workgroup;
}
+}
- augeas { 'global-unix_password_sync':
- context => $context,
- changes => $unix_password_sync ? {
- default => "set \"${target}/unix password sync\" '$unix_password_sync'",
- '' => "rm \"${target}/unix_password_sync\"",
- },
- require => Augeas['global-section'],
- notify => Class['samba::server::service']
+define set_samba_option ( $value = '', $signal = 'samba::server::service' ) {
+ $context = $samba::server::context
+ $target = $samba::server::target
+ $changes = $value ? {
+ default => "set \"${target}/$name\" $value",
+ '' => "rm ${target}/$name",
}
-
- augeas { 'global-workgroup':
+ augeas { "samba-$name":
context => $context,
- changes => $workgroup ? {
- default => "set ${target}/workgroup '${workgroup}'",
- '' => "rm ${target}/workgroup",
- },
+ changes => $changes,
require => Augeas['global-section'],
- notify => Class['samba::server::service']
+ notify => Class[$signal]
}
}
diff --git a/manifests/server/ads.pp b/manifests/server/ads.pp
new file mode 100644
index 0000000..1f8e602
--- /dev/null
+++ b/manifests/server/ads.pp
@@ -0,0 +1,116 @@
+# This module join samba server to Active Dirctory
+#
+# Copyright (c) 2013 Lebedev Vadim, abraham1901 at g mail dot c o m
+# Licensed under the MIT License, http://opensource.org/licenses/MIT
+
+class samba::server::ads($ensure = present,
+ $winbind_acct = 'admin',
+ $winbind_pass = 'SecretPass',
+ $realm = 'domain.com',
+ $winbind_uid = '10000-20000',
+ $winbind_gid = '10000-20000',
+ $winbind_enum_groups = 'yes',
+ $winbind_enum_users = 'yes',
+ $winbind_use_default_domain = 'yes',
+ $nsswitch = false,
+ $acl_group_control = 'yes',
+ $map_acl_inherit = 'yes',
+ $inherit_acls = 'yes',
+ $store_dos_attributes = 'yes',
+ $ea_support = 'yes',
+ $dos_filemode = 'yes',
+ $acl_check_permissions = false,
+ $map_system = 'no',
+ $map_archive = 'no',
+ $map_readonly = 'no',
+ $target_ou = 'Nix_Mashine') {
+
+ package{
+ 'krb5-user': ensure => installed;
+ 'winbind': ensure => installed;
+ 'expect': ensure => installed;
+ }
+
+ include samba::server::config
+ include samba::server::winbind
+
+ $signal = 'samba::server::winbind'
+
+ set_samba_option {
+ 'realm': value => $realm,
+ signal => $signal;
+ 'winbind uid': value => $winbind_uid,
+ signal => $signal;
+ 'winbind gid': value => $winbind_gid,
+ signal => $signal;
+ 'winbind enum groups': value => $winbind_enum_groups,
+ signal => $signal;
+ 'winbind enum users': value => $winbind_enum_users,
+ signal => $signal;
+ 'winbind use default domain': value => $winbind_use_default_domain,
+ signal => $signal;
+ 'acl group control': value => $acl_group_control;
+ 'map acl inherit': value => $map_acl_inherit;
+ 'inherit acls': value => $inherit_acls;
+ 'store dos attributes': value => $store_dos_attributes;
+ 'ea support': value => $ea_support;
+ 'dos filemode': value => $dos_filemode;
+ 'acl check permissions': value => $acl_check_permissions;
+ 'map system': value => $map_system;
+ 'map archive': value => $map_archive;
+ 'map readonly': value => $map_readonly;
+ }
+
+ $nss_file='etc/nsswitch.conf'
+
+ $changes=$nsswitch ? {
+ true => [
+ "set database[. = 'passwd']/service[1] compat",
+ "set database[. = 'passwd']/service[2] winbind",
+ "set database[. = 'group']/service[1] compat",
+ "set database[. = 'group']/service[2] winbind",
+ ],
+ false => [
+ "rm /files/${nss_file}/database[. = 'passwd']/service[. = 'winbind']",
+ "rm /files/${nss_file}/database[. = 'group']/service[. = 'winbind']",
+ ]
+ }
+
+ augeas { 'nsswitch':
+ context => "/files/${nss_file}",
+ changes => $changes
+ }
+
+ file {'verify_active_directory':
+ # this script returns 0 if join is intact
+ path => '/sbin/verify_active_directory',
+ owner => root,
+ group => root,
+ mode => "0755",
+ content => template("${module_name}/verify_active_directory.erb"),
+ require => [ Package['krb5-user', 'winbind', 'expect'],
+ Augeas['samba-realm', 'samba-security', 'samba-winbind enum users',
+ 'samba-winbind enum groups', 'samba-winbind uid', 'samba-winbind gid',
+ 'samba-winbind use default domain'] ],
+ }
+
+ file {'configure_active_directory':
+ # this script joins or leaves a domain
+ path => '/sbin/configure_active_directory',
+ owner => root,
+ group => root,
+ mode => "0755",
+ content => template("${module_name}/configure_active_directory.erb"),
+ require => [ Package['krb5-user', 'winbind', 'expect'],
+ Augeas['samba-realm', 'samba-security', 'samba-winbind enum users',
+ 'samba-winbind enum groups', 'samba-winbind uid', 'samba-winbind gid',
+ 'samba-winbind use default domain'] ],
+ }
+
+ exec {'join-active-directory':
+ # join the domain configured in samba.conf
+ command => '/sbin/configure_active_directory -j',
+ unless => '/sbin/verify_active_directory',
+ require => [ File['configure_active_directory', 'verify_active_directory'], Class['samba::server::winbind'] ],
+ }
+}
diff --git a/manifests/server/share.pp b/manifests/server/share.pp
index 7d308a0..b4eb02f 100644
--- a/manifests/server/share.pp
+++ b/manifests/server/share.pp
@@ -15,10 +15,9 @@ define samba::server::share($ensure = present,
$read_only = '',
$public = '',
$writable = '',
- $printable = '',
- ) {
+ $printable = '') {
- $context = '/files/etc/samba/smb.conf'
+ $context = $samba::server::context
$target = "target[. = '${name}']"
augeas { "${name}-section":
diff --git a/manifests/server/winbind.pp b/manifests/server/winbind.pp
new file mode 100644
index 0000000..76136b9
--- /dev/null
+++ b/manifests/server/winbind.pp
@@ -0,0 +1,16 @@
+class samba::server::winbind ($ensure = running, $enable = true) {
+ $service_name = 'winbind'
+
+ notify { 'winbind-service':
+ message => 'Check winbind service',
+ }
+
+ service { $service_name:
+ ensure => $ensure,
+ hasstatus => true,
+ hasrestart => true,
+ enable => $enable,
+ require => Class['samba::server::config']
+ }
+
+}
diff --git a/templates/configure_active_directory.erb b/templates/configure_active_directory.erb
new file mode 100644
index 0000000..35ba86f
--- /dev/null
+++ b/templates/configure_active_directory.erb
@@ -0,0 +1,142 @@
+#!/bin/bash
+
+# This script can cause a host to join or leave
+# the Windows Active Directory domain
+
+# variables
+#
+# specify a timeout for domain operations
+seconds=300
+#
+# post_join_delay seems to be necessary after joing domain
+post_join_delay=30
+#
+
+PROG=$(basename $0)
+
+function usage () {
+ cat >&2 <<- EOF
+ Usage: $PROG -[hjl]
+ -h help
+ -j join the domain
+ -l leave the domain
+ Return code indicates success (0) or failure.
+ EOF
+}
+
+# kinit and klist path depend on krb5 release
+export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/kerberos/bin
+
+NET=$(which net)
+if ! [ -x "$NET" ]; then
+ echo "ERROR: net command is missing or not executable." >&2
+ exit 1
+fi
+
+EXPECT=$(which expect)
+if ! [ -x "$EXPECT" ]; then
+ echo "ERROR: cannot run expect" >&2
+ exit 1
+fi
+
+if [ $# -eq 0 ]; then
+ usage
+ exit 2
+fi
+
+while getopts "hjlq" option
+do
+ case $option in
+ h ) usage; exit 0;;
+ j ) action="join";;
+ l ) action="leave";;
+ * ) usage; exit 2;;
+ esac
+done
+
+password="<%= scope.lookupvar('samba::server::ads::winbind_pass') -%>"
+
+# short hostname from facter
+my_hostname="<%= hostname -%>"
+
+# what account do we use for net ads commands?
+winbind_acct="<%= scope.lookupvar('samba::server::ads::winbind_acct') -%>"
+
+# which realm will we be joining?
+my_realm="<%= scope.lookupvar('samba::server::ads::realm') -%>"
+
+# where should we create computer accounts?
+target_ou="<%= scope.lookupvar('samba::server::ads::target_ou') -%>"
+
+echo "Please do not kill me; I may be slow" >&2
+
+#TODO, need write time check check_kdc_time
+#if ! /bin/check_kdc_time; then
+# echo "ERROR: time offset too large to manipulate domain" >&2
+# exit 1
+#else
+# echo "INFO: time offset seems ok" >&2
+#fi
+
+if [ "$action" = "leave" ]; then
+ logger -st $PROG "Leaving AD domain"
+ $NET ads $action -U ${winbind_acct}%${password} | grep Deleted && success=true || success=false
+ kdestroy
+ rm -f /etc/krb5.keytab
+ if [ $success = "true" ]; then
+ logger -st $PROG "Left AD domain"
+ else
+ logger -st $PROG "Failed to leave AD domain"
+ fi
+fi
+
+ad_settle() {
+ (
+ echo -n "Waiting $post_join_delay seconds"
+ for x in $(seq 1 $post_join_delay); do
+ echo -n "."
+ sleep 1
+ done
+ echo
+ ) >&2
+}
+
+# ldapmodify _does_ use the env var for sasl bind
+export KRB5CCNAME=$(umask 0077; mktemp -q winbind_cache.XXXXXXXX)
+
+if [ "$action" = "join" ]; then
+ logger -st $PROG "Joining AD domain" >&2
+ $NET ads $action -U ${winbind_acct}%${password} createcomputer="${target_ou}"\
+ | grep Joined && success=true || success=false
+
+if [ $success = "false" ]; then
+ echo ERROR: failed to join domain >&2
+ exit 2
+fi
+
+max_attempts=5
+for attempt in $(seq 1 $max_attempts); do
+ echo "$attempt of $max_attempts:"
+ ad_settle
+ echo "Getting TGT for ${winbind_acct}@${my_realm}" >&2
+ $EXPECT -c "spawn -noecho kinit -c $KRB5CCNAME ${winbind_acct}@${my_realm};
+ expect :;
+ send ${password}\n;
+ expect eof"
+ klist -c $KRB5CCNAME &> /dev/null && break
+done
+
+if [ $(wbinfo -u|wc -l) != 0 ]; then
+ success=true
+else
+ echo "ERROR: return user list from AD is empty" >&2
+ success=false
+fi
+
+# get rid of cred cache
+kdestroy -c $KRB5CCNAME &> /dev/null
+rm -f $KRB5CCNAME &> /dev/null || :
+
+fi
+
+[ "$success" = "true" ] && exit 0 || exit 1
diff --git a/templates/verify_active_directory.erb b/templates/verify_active_directory.erb
new file mode 100644
index 0000000..5a2a506
--- /dev/null
+++ b/templates/verify_active_directory.erb
@@ -0,0 +1,107 @@
+#!/bin/bash
+
+PROG=$(basename $0)
+export EXPIRATION=90
+
+# kinit and klist path depend on krb5 release
+export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/kerberos/bin
+
+EXPECT=$(which expect)
+if ! [ -x "$EXPECT" ]; then
+ echo "ERROR: cannot run expect" >&2
+ exit 1
+fi
+
+#TODO
+#if ! check_kdc_time; then
+# {
+# echo "===================================="
+# echo "WARNING: time offset seems too large"
+# echo "===================================="
+# } >&2
+#fi
+
+password="<%= scope.lookupvar('samba::server::ads::winbind_pass') -%>"
+
+# short hostname from facter
+my_hostname="<%= hostname -%>"
+
+winbind_acct="<%= scope.lookupvar('samba::server::ads::winbind_acct') -%>"
+
+default_realm=$(grep -i '^[[:space:]]*realm.*=' /etc/samba/smb.conf | sed 's/ //g' | sed 's/realm=//g')
+
+# if we're still here, let's try the testjoin
+do_testjoin() {
+ echo "Running net ads testjoin with EXPIRATION=$EXPIRATION" >&2
+ _cmd="net ads testjoin -P"
+ if [[ -n "$1" ]]; then
+ _cmd="${_cmd} $@"
+ fi
+ output=$(${_cmd} 2>&1)
+ grep -q 'Join is OK' <<< $output
+ _rc=$?
+ if [ ${_rc} -ne 0 ]; then
+ logger -st $PROG "Error: net ads testjoin -P failed: $output"
+ fi
+ return ${_rc}
+}
+do_testjoin
+if [ $? -ne 0 ]; then
+ # get verbose failure info
+ do_testjoin -d3
+fi
+
+
+# if we're still here, we need to:
+# - get a TGT that enables us to query the attribute 'useraccountcontrol'
+# - confirm that AD trusts us for GSSAPI delegation
+
+export KRB5CCNAME=$(umask 0077; mktemp -q winbind_cache.XXXXXXXX)
+
+get_tgt() {
+ (
+ $EXPECT -c "spawn -noecho kinit -c $KRB5CCNAME ${winbind_acct}@${default_realm};
+ expect :;
+ send ${password}\n;
+ expect eof"
+ ) &> /dev/null
+ klist -c $KRB5CCNAME &> /dev/null
+ return $?
+}
+
+# try this several times.
+max_attempts=5
+# assume non-zero for has_tgt
+has_tgt=1
+for attempt in $(seq 1 $max_attempts); do
+ # If we just joined the domain, it takes a small amount of time
+ # for AD to sort things out amongst the DC's, and it
+ # depends in part on DNS performance.
+ if get_tgt; then
+ has_tgt=0
+ break
+ fi
+ echo "." >&2
+ sleep 3
+done
+
+success=true
+
+if [ $has_tgt -ne 0 ]; then
+ logger -st $PROG "ERROR: failed to get TGT from AD"
+ success=false
+else
+ if [ $(wbinfo -u|wc -l) != 0 ]; then
+ success=true
+ else
+ echo "ERROR: return user list from AD is empty" >&2
+ success=false
+ fi
+
+ # get rid of cred cache
+ kdestroy -c $KRB5CCNAME &> /dev/null
+fi
+
+[[ $success == "false" ]] && exit 1
+
+exit 0