Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Trying to take user input as username, read etc/passwd and output user ID

by charlesx1552 (Initiate)
on May 11, 2022 at 02:19 UTC ( [id://11143764]=perlquestion: print w/replies, xml ) Need Help??

charlesx1552 has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, I've been tasked with curating a program that takes in a username and checks with /etc/pass file, in hopes of it being valid and outputting the users ID and home directory This is what I have and it works but always says user invalid, leading me to believe something about the section regarding fields is incorrect... Thanks in advance!!

$filename = '/etc/passwd.bak'; open(FILE, $filename) or die "Could not read from $filename, program s +topped."; print "Please enter the username: \n"; $username = <STDIN>; while(<FILE>){ chomp $username; if ($username eq @fields[1]){ print "Home directory: $fields[5]\n"; print "Shell used: $fields[6]\n"; exit 0; } if ($username ne @fields[1]){ print "User: $username does not exist.\n"; exit 0; } @fields = split(':', $_); } close FILE;

Replies are listed 'Best First'.
Re: Trying to take user input as username, read etc/passwd and output user ID
by Fletch (Bishop) on May 11, 2022 at 03:54 UTC

    For one thing you split after trying to look at individual elements of your array so that’s the first thing to fix. Also @array[1] is a one element slice and isn’t the right way to access $array[1].

    Secondly unless you have a real good reason you probably want to be using getpwnam and friends instead of manually parsing the local passwd file. That will work where (say) accounts are coming from ldap or nis and you’ll get back a list of the fields if the user is valid and don’t need to parse anything yourself.

    also you chomp the user name scalar each line of your input file but don’t muck with $_ each line which probably isn't what you want either.

    good grief I’m half asleep and glossed over the exit calls. To start since you don’t split the line first the second if block will always be true and you’ll never read past the first line. Even if you were properly splitting things up earlier each time through the loop if you ever don’t have the first line matching that’s always going to bail out.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Trying to take user input as username, read etc/passwd and output user ID
by afoken (Chancellor) on May 11, 2022 at 05:18 UTC

    I can see only two reasons for manually parsing /etc/passwd:

    • Learning to handle CSV files
    • Very special needs

    To learn handling CSV files, there are much better ways. And even then, Text::CSV and Text::CSV_XS are the better way to handle CSV files, simply because those modules are prepared to handle all the nasty edge cases you didn't think about.

    Verifying a username and/or home directory does not seem like "very special needs".

    You probably just want to use getpwnam in list context, i.e.:

    my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell, + $expire) = getpwnam($login);

    User::pwent wraps that into a nice object:

    use User::pwent; # <-- replace getpwnam() and friends with functions r +eturning objects my $rec = getpwnam($login); say $rec->name,' has UID ',$rec->uid,', home ',$rec->dir,', shell ',$r +ec->shell;

    What's the difference to reading /etc/passwd?

    • Reading and splitting of /etc/passwd is done by the system C library.
    • Other sources of user records are queryed by the system C library.

    The second point is important: /etc/passwd is no longer the only source of user information, since at least three decades. NSS allows to add more records from other sources (NIS, NIS+, LDAP, AD, ...), and it should also allow to ignore /etc/passwd completely. PAM allows to do even more crazy stuff.

    The same applies to /etc/group and the getgr... functions, and also to /etc/services (getserv...), /etc/hosts (gethost...), /etc/protocols (getproto...).

    At work, all user and group information resides in a Samba 4 Active Directroy database (essentialy LDAP plus some extras), and the /etc/passwd on all Linux systems is at the bare minimum, just root and some system/daemon accounts. If you had an AD account, you could login into any Linux box, but you would not find your login in /etc/passwd. getpwnam works fine, and would return your user record, because at the C library level, LDAP would be queried and return your user record. Plus, it would continue to do so if we switched from AD to NIS+ or some fancy SQL database holding user records.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Trying to take user input as username, read etc/passwd and output user ID
by Discipulus (Canon) on May 11, 2022 at 08:32 UTC
    Hello charlesx1552 and welcome to the monastery and to the wonderful world of perl!

    Without entering in the matter of checking linux users (you got already authoritative suggestions) I'd like to point you to some general perl modern practices:

    • I dont see strict nor warnings in use.. this must be a mantra in all your programs

    • open(FILE, $filename) or die.. is correct but we dont use bareword filehandles since years: open(my $file_handle, $filename) or die .. is the idiomatic (idiomatic perl => good thing) form (see Is there a problem with using barewords as filehandles ?).

    • update you use the implicit opening mode! Please join us in the use of 4 arguments open like in open(my $fh, "<", "input.txt") Explicit -> more readable -> better

    • as already said you chomp $username in the wrong place: the right place is just after my $username = <STDIN>; (I added my to your line ;)

    • you (at least as presente here) use a poor indentation: you close 3 braces at the same level of indentation while they are not at the same level. See Perl::Tidy for a code beautifier, then it will be by heart

    • if A eq B .. if A ne B is logically wrong. if .... else... is what you want. Or in more complex cases if .. elsif .. else

    • while dealing with user inputs a typical error is to overlook what you got: I find useful, presenting something to the screen, to enclose these kind of things inside square brackets, like: print "User: [$username] does not exist.\n"; These brackets does not interefere with your output even in case of other brackets, like in: print "Home directory: [$fields[5]]\n";

    • as already said @array[0] is an array slice, so it is an array and $array[0] is the first element of the array, so a scalar.

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11143764]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (6)
As of 2024-03-29 09:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found