#!/usr/bin/env ruby require 'time' require 'active_samba_ldap' require 'active_samba_ldap/command' argv, opts, options = ActiveSambaLdap::Command.parse_options do |opts, options| options.ou = nil options.computer_account = false options.uid = nil options.gid = nil options.supplementary_groups = [] options.create_group = true options.home_directory = nil options.home_directory_mode = nil options.shell = nil options.comment = nil options.setup_home_directory = true options.skeleton_directory = nil options.time = 0 options.expire_date = nil options.can_change_password = nil options.must_change_password = nil options.samba_home_unc = nil options.samba_home_drive = nil options.samba_logon_script = nil options.samba_profile_path = nil options.samba_account_flags = nil options.canonical_name = nil options.given_name = nil options.surname = nil options.mail_addresses = nil options.mail_to_addresses = nil opts.banner += " USER_NAME" opts.on("-o", "--ou=OU", "add the user in the organizational unit OU", "(relative to the user suffix)") do |ou| if /^ou=/ =~ ou options.ou = ou else options.ou = "ou=#{ou}" end end opts.on("-c", "--[no-]computer-account", "is a Windows Workstation", "(otherwise, Windows user)", "(#{options.computer_account})") {|options.computer_account|} opts.on("-u", "--uid=UID", Integer, "uid") {|options.uid|} opts.on("-g", "--gid=GID", "gid") {|options.gid|} opts.on("-G", "--groups=GID1,GID2,GID3", Array, "supplementary groups (comma separated)") do |groups| options.supplementary_groups = groups end opts.on("--[no-]create-group", "create a group for the user", "(#{options.create_group})") {|options.create_group|} opts.on("-c", "--comment=COMMENT", "set the GECOS field for the new user account") {|options.comment|} opts.on("-s", "--shell=SHELL", "shell") {|options.shell|} opts.on("-G", "--given-name=NAME", "given name") {|options.given_name|} opts.on("-N", "--canonical-name=NAME", "canonical name") {|options.canonical_name|} opts.on("-S", "--surname=NAME", "surname") {|options.surname|} opts.on("-d", "--home-directory=HOME_DIR", "home directory") {|options.home_directory|} opts.on("--home-directory-mode=MODE", "permission of home directory") {|options.home_directory_mode|} opts.on("--[no-]setup-home-directory", "setup home directory", "(#{options.setup_home_directory}") {|options.setup_home_directory|} opts.on("-k", "--skel=DIR", "--skeleton-directory=DIR", "skeleton directory") {|options.skeleton_directory|} opts.on("--time=TIME", Integer, "wait TIME seconds before exiting", "(#{options.time})") {|options.time|} opts.separator("") opts.separator("For samba accounts:") opts.on("-e", "--expire-date=DATE", "expire date") do |date| options.expire_date = Time.parse(date) end opts.on("-C", "--[no-]can-change-password", "can change password") do |bool| options.can_change_password = bool end opts.on("-M", "--[no-]must-change-password", "must change password") do |bool| options.must_change_password = bool end opts.on("--samba-home-path=UNC", "sambaHomePath", "(SMB home share, like '\\\\PDC\\user'") do |unc| options.samba_home_unc = unc end opts.on("--samba-home-drive=DRIVE", "sambaHomeDrive", "(letter associated with home share,", " like 'H:')") do |drive| options.samba_home_drive = drive end opts.on("--samba-logon-script=SCRIPT", "sambaLogonScript", "(DOS script to execute on login)") do |script| options.samba_logon_script = script end opts.on("--samba-profile-path=PATH", "sambaProfilePath", "(profile directory,", " like '\\\\PDC\\profiles\\user')") do |path| options.samba_profile_path = path end opts.on("--samba-account-flags=FLAGS", "sambaAcctFlags", "(samba account control bits,", " like '[NDHTUMWSLXI]')") {|options.samba_account_flags|} # opts.on("--mail-addresses=ADDRESS1,ADDRESS2,ADDRESS3", # Array, # "mailAddresses (comma separated)") {|options.mail_addresses|} # opts.on("--mail-to-addresses=ADDRESS1,ADDRESS2,ADDRESS3", # Array, # "mailToAddresses (forward address)", # "(comma separated)") do |addresses| # options.mail_to_addresses = addresses # end end name = nil if argv.size == 1 name = argv.first else $stderr.puts opts exit 1 end unless Process.uid.zero? $stderr.puts "need root authority." exit 1 end ActiveSambaLdap::Base.establish_connection("update") class User < ActiveSambaLdap::SambaUser ldap_mapping end class Computer < ActiveSambaLdap::SambaComputer ldap_mapping end class Group < ActiveSambaLdap::SambaGroup ldap_mapping end class UnixIdPool < ActiveSambaLdap::UnixIdPool ldap_mapping end member_class = options.computer_account ? Computer : User member_type = member_class.name.downcase if options.computer_account name = name.chomp("$") + "$" end unless member_class.valid_name?(name) $stderr.puts "'#{name}' is illegal #{member_type} name" exit 1 end if member_class.exists?(name) $stderr.puts "#{member_type} '#{name}' already exists." exit 1 end create_options = { :uid => [name, options.ou].compact.join(","), :uid_number => options.uid, :gid_number => options.gid, :create_group => options.create_group, :group_class => Group, :home_directory => options.home_directory, :login_shell => options.shell, :given_name => options.given_name, :cn => options.canonical_name, :sn => options.surname, :gecos => options.comment, :samba_acct_flags => options.samba_account_flags, } if !create_options[:cn] and options.given_name and options.surname create_options[:cn] = "#{options.given_name} #{options.surname}" end if options.computer_account create_options[:description] = "Computer" create_options[:gecos] ||= "Computer" else create_options.merge!(:can_change_password => options.can_change_password, :must_change_password => options.must_change_password, :user_logon_script => options.samba_logon_script, :user_home_unc => options.samba_home_unc, :user_home_drive => options.samba_home_drive, :user_profile => options.samba_profile_path) if options.expire_date create_options[:samba_kickoff_time] = options.expire_date.to_i.to_s end end member = nil begin member = member_class.create(create_options) rescue ActiveSambaLdap::UidNumberAlreadyExists $stderr.puts "UID '#{uid_number}' already exists" exit 1 rescue ActiveSambaLdap::GidNumberDoesNotExist, ActiveSambaLdap::GroupDoesNotExist, ActiveSambaLdap::GroupDoesNotHaveSambaSID $stderr.puts $! exit 1 end unless member.errors.empty? member.errors.each_full do |message| $stderr.puts(message) end exit 1 end if options.setup_home_directory begin setup_options = { :mode => options.home_directory_mode, :skeleton_directory => options.skeleton_directory, } member.setup_home_directory(setup_options) rescue SystemCallError $stderr.puts $! exit 1 end end [member.gid_number, *options.supplementary_groups].each do |group| group = Group.find_by_name_or_gid_number(group) if options.computer_account group.computers << member else group.users << member end end ActiveSambaLdap::Base.restart_nscd ActiveSambaLdap::Base.clear_active_connections!