You don't need to and shouldn't fiddle with /etc/passwd - useradd will simply fail if a user with that name already exists. So you should simply attempt to create that user and check if you succeeded - that way, even multiple concurrent copies of the script won't be able to step on each other's toes.
Don't try to find a UID yourself either. According to man useradd:
The default is to use the smallest ID value greater than 99 and greater than every other user. Values between 0 and 99 are typically reserved for system accounts.
That's exactly what you want anyway.
Also, you have tons of duplicate code in there. All these $i = 0; do { ... } while $foo; loops are very similar - factor out the code! Do It Once And Only Once.
Lastly, it would make the code much easier to read if you shuffle the prompts and text out of the code's way. As a bonus, if you give the prompts and messages names, the code becomes self documenting and you can get rid of all of that commentary as well.
#!/usr/bin/perl -w use strict; no warnings 'once'; use vars qw(%MSG %PROMPT); use Email::Valid; use Term::ReadKey; use Mail::Send; $ENV{PATH}=''; $|++; sub message { my $clear = shift; my $message = shift; system "/usr/bin/clear" if $clear; printf "\n$message", @_; } sub ask_user { my ($prompt, $check) = @_; local $_; { print "\n$prompt->[0]"; chomp($_ = <STDIN>); print("\n$prompt->[1]\n"), redo unless $check->(); } return $_; } eval do { local $/; <DATA> }; # read messages and prompts use constant GID => 100; use constant SHELL => '/bin/bash'; use constant LOG_FILE => "/home/newuser/downUnder.log"; my ($USERNAME, $FULL_NAME, $FIRST_NAME, $EMAIL, $PASSWD); message(1, $MSG{BANNER}); ask_user($PROMPT{MAKE_ACCOUNT}, sub { die "\nCiao!\n" if 'n' eq lc; return 1 if 'y' eq lc; return; }); message(1, $MSG{TOS}); ask_user($PROMPT{COMPLY}, sub { die "\nCiao!\n" if 'n' eq lc; return 1 if 'y' eq lc; return; }); { message(1, $MSG{COLLECTDETAILS}); $FULL_NAME = ask_user($PROMPT{FULL_NAME}, sub { /^\s*(\D+)\s+\D+\b/ ? ($FIRST_NAME = $1, return 1) : 0 }); $EMAIL = ask_user($PROMPT{EMAIL}, sub { Email::Valid->address(-address => $_, -mxcheck => 1) }); message(0, $MSG{CASESENSITIVE}); ReadMode 2; # cooked mode,echo off { $PASSWD = ask_user($PROMPT{PASSWD}, sub { length > 6 }); my $passwd2 = ask_user($PROMPT{CONFIRM}, sub { 1 }); print("\n\nYou typed two different passwords!\n"), redo if $PASSWD ne $passwd2; } ReadMode 0; # restore original settings message(0, $MSG{SUMMARY}, $FIRST_NAME, $FULL_NAME, $EMAIL); redo if 'n' eq lc ask_user($PROMPT{CORRECT}, sub { /^(y|n)$/i }); } $USERNAME = ask_user($PROMPT{USERNAME}, sub { return unless /\A\w+\z/; system( '/usr/bin/sudo', '/usr/sbin/useradd', '-s' => SHELL, '-g' => GID, '-p' => crypt($PASSWD, time()), '-c' => $FULL_NAME, '-m' => $_, ) and return; return 1; }); my $date = localtime; printf( { Mail::Send->new( Subject => 'New User Added!', To => 'root' )->open } $MSG{ADMINMAIL}, $date, $USERNAME, scalar getpwnam($USERNAME), $FULL_NAME, $EMAIL ); { open my $fh, ">>", LOG_FILE or warn "Failed opening log file: $!\n"; print $fh "$USERNAME :: $FULL_NAME :: $EMAIL - $date\n"; } message(1, $MSG{THANKSBYE}); sleep 30; __END__ %PROMPT = ( MAKE_ACCOUNT => [ "Are you going to make a shell account now? (y/n): ", "Not an option", ], COMPLY => [ "I fully understand/comply and respect the system (y/n): ", "Not an option", ], FULL_NAME => [ "(*) Your actual full name: ", "Full name is required!", ], EMAIL => [ "(*) Your email address: ", "Your *valid* email address is required!", ], PASSWD => [ "(*) Your account password (won't echo): ", "Your password has to be longer than 6 characters.", ], CONFIRM => [ "(*) Confirm your password by retyping it: ", "", ], CORRECT => [ "Now is your last chance to abort. Is this data correct? (y/n) +: ", "Not an option", ], USERNAME => [ "Please choose a username: ", "That username is invalid or taken.", ], ); %MSG = ( BANNER => <<"EOT", Welcome to the official server of the IIT Linux User's Group EOT TOS => <<"EOT", Ok here's the gig. I'm making this service, and everything associated with a shell account, freely available for your use, to do with as you please. It's my pleasure, and I hope you learn a whole lot. With this, comes responsibility on your part to use these tools in accordance with US laws and general morality. Simply, don't go hacking away at someone else's box, or do anything that will wind me up in jail. I might add as a side note that I log *everything* plus some, so don't do anything over the network that will make me suspicious. Also understand that, while this is my primary server, there are unexpected periods of downtime (generally attributed to the crappy network here at the school, and the strange electricity problems we have every so often). I promise absolute security with regard to your data; I can't promise complete integrity of the disks. There are occassional occurances of data loss, due to my mucking about, or some other such cause. Just bear this in mind. EOT COLLECTDETAILS => <<"EOT", Nothing of the following will be public. EOT CASESENSITIVE => <<"EOT", Note: The following items are case sensitive. EOT SUMMARY => <<"EOT", Ok, %s: Your name is %s. Your email is %s. EOT THANKSBYE => <<"EOT", OK, your brand spanking new account is ready to roll. You will want to open a secure shell (ssh) connection via either protocol 1 or 2 to this host and then use your newly created username and password to log into the system. Enjoy! And please always remember the following golden rules, and all will be well: #1) Respect the privacy of others. #2) Respect the security and integrity of this machine. #3) Think before you type. Love and Linux! (You will be automagically disconnected in 30 seconds) EOT ADMINMAIL => <<"EOT", Attention Administrator! A new user has recently been added. Information follows: Date: %s Username: %s (UID: %s) User: %s Email: %s EOT );
Makeshifts last the longest.
In reply to Re: Anonymous User Add For Linux Shell
by Aristotle
in thread Anonymous User Add For Linux Shell
by lacertus
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |