#!/usr/bin/perl -w # # Create UNIX user automatically for Samba / WinNT Domain Users # Copyright (C) 2000 SATOH Fumiyasu , Samba-JP Team # # Version: 1.0.0 (2000-08-13, since 2000-07-23) # License: GNU GPL ver.2 # # Requirements: # Perl 5.005 # rpcclient (Samba TNG 2.5.x) # useradd (most UN*Xes?) # # ToDo: # * Username mapping # * Username/groupname translation # * User/group restriction # * Set UNIX user's password, shell, and so on # * Create UNIX group automatically # * Check UNIX groupname validation (chars, length and misc) # * Check rpcclient version (TNG-alhpa required) # * Multiple DC (PDC and BDCs) support for fail safe # * Configuration file for this script # * How to log? # * Support your ideas and opinions :-) # * Fix my broken English :-X # * More testing # # Change log: # # 2000-08-13 SATOH Fumiyasu # * Version: 1.0.0 # * First release # Startup # ====================================================================== use 5.005; use strict; use Getopt::Std; use IO::File; my $usage = "usage: smbadduserscript dc username"; my $help =< $user_maxlen) { die "Username is too long: maximum length is $user_maxlen\n"; } if ($username =~ /$user_invalidchar/) { die "Username contains invalid characters: $user_invalidchar_note\n"; } if ($username =~ /$user_invalidpat/) { die "Username consists of invalid pattern: $user_invalidpat_note\n"; } # Groupname mapping file # ====================================================================== if (!-r $groupmap_file) { die "The groupname mapping file is not readable: $groupmap_file\n"; } my $fh_map = new IO::File("<$groupmap_file"); if (!defined($fh_map)) { die "Cannot open groupname mapping file: $groupmap_file\n"; } my %groupmap = (); while (my $line = <$fh_map>) { $line =~ s/#.*//; # Comment next if ($line !~ /\S/); # Null line if ($line =~ /^\s*(\S+)\s*=\s*(.*)\s*$/) { my ($unix, $smblist) = ($1, $2); foreach my $smb (split(/\s*,\s*/, $smblist)) { $smb =~ s/(^"\s*|\s*"$)//g; $groupmap{$smb} = $unix; } } else { warn "Invalid groupname mapping: line $. in $groupmap_file\n"; } } # Samba TNG rpcclient # ====================================================================== if (!-x $rpcclient_cmd) { die "The rpcclient command is not executable: $rpcclient_cmd\n"; } my $rpcclient_query = "samuser $username -u -g; enumgroups"; my @rpcclient_opt = ( "-s", "'$smbconf_file'", # smb.conf file "-S", "'$dc'", # Domain Controller "-U", "'$guest'", # Guest account name and password "-c", "'$rpcclient_query'", # Queries ); my $fh_rpc = new IO::File("$rpcclient_cmd @rpcclient_opt|"); if (!defined($fh_rpc)) { die "Cannot start rpcclient: $rpcclient_cmd\n"; } # Retrieve Domain User and Domain Group info. # ---------------------------------------------------------------------- # Discard some lines while (my $line = <$fh_rpc>) { if ($line =~ /User Info,/) { last; } } # Read user informations my %dom_user = (); while (my $line = <$fh_rpc>) { if ($line =~ /SAM Enumerate Groups/) { last; } elsif ($line =~ /^\s+Member Name:\s+([^:]+)\s+Type:\s+(.*)$/) { push(@{$dom_user{'groups'}}, $1); } elsif ($line =~ /^\s+([^\s:]+(?:\s[^\s:]+)*)\s*:\s+(.*)$/) { $dom_user{lc($1)} = $2; } } if (!%dom_user) { die "Cannot retrieve User informations from DC.\n"; } if (!exists($dom_user{'groups'})) { die "Cannot retrieve Groups (which the user is member of) from DC.\n"; } # Read Domain Group list my %dom_group = (); while (my $line = <$fh_rpc>) { if ($line =~ /^Group RID:\s+(\d+)\s+Group Name:\s+(.*)$/) { $dom_group{$1} = $2; } } if (!%dom_group) { die "Cannot retrieve Domain Group list from DC.\n"; } # Primary Domain Group name # ---------------------------------------------------------------------- my $dom_group = $dom_group{$dom_user{'group_rid'}}; # Create UNIX user # ====================================================================== # UNIX User info. # ---------------------------------------------------------------------- # Username my $unix_user = lc($username); # Comment (GECOS field in passwd database) my $unix_comment = $dom_user{'full name'}; $unix_comment =~ s/[:]/ /g; $unix_comment =~ s/[^\w\s"'`+\-*\/%&|#\$;.,~?!\^\(\)\[\]{}<>\\]//g; $unix_comment = "Unknown" if ($unix_comment !~ /\S/); $unix_comment .= ",NT Domain User"; # Primary Group my $unix_group = exists($groupmap{$dom_group}) ? $groupmap{$dom_group} : lc($dom_group); $unix_group =~ s/\s/_/g; if (!defined(getgrnam($unix_group))) { die "UNIX group not found: $unix_group\n"; } # Additional Groups my @unix_groups = (); foreach my $dom_group (@{$dom_user{'groups'}}) { my $unix_group = exists($groupmap{$dom_group}) ? $groupmap{$dom_group} : lc($dom_group); $unix_group =~ s/\s/_/g; if (defined(getgrnam($unix_group))) { push(@unix_groups, $unix_group); } } # Delete primary group from additional group list @unix_groups = grep(!/^\Q$unix_group\E$/, @unix_groups); # Create UNIX User # ---------------------------------------------------------------------- if (!-x $useradd_cmd) { die "The useradd command is not executable: $useradd_cmd\n"; } my @useradd_opt = ( "-m", # Create home dir if not exists "-g", $unix_group, # Primary UNIX group "-c", $unix_comment, # Comment (GECOS field) ); # Additional UNIX group if (@unix_groups) { push(@useradd_opt, "-G", join(",", @unix_groups)); } if (defined($opt_n)) { print "$useradd_cmd @useradd_opt $unix_user\n"; } else{ system($useradd_cmd, @useradd_opt, $unix_user); my $ret = $? >> 8; if ($ret) { die "The useradd command failed: exit code is $ret\n"; } } exit(0); # EOF