1

I have access to a university's Linux server where all students have accounts. I can retrieve their full name by typing the finger username, and their departments by typing id username. All the student usernames are consecutive. For example:

e205846
e205847
e205848
e205849
e205850
...

Is it possible for me to write a some kind of script and retrieve all the information to some kind of database? Or is there already an available tool for that? Also, as side note there some www folders in the Linux which has all the usernames.

Here is one example

e147290@beluga:~$ finger e204158
Login: e204158                          Name: april oneil
Directory: /home705/e204158             Shell: /bin/bash
Never logged in.
No mail.
No Plan.

e147290@beluga:~$ id e204159
uid=53653(e204158) gid=5621(ce_bs) groups=5621(ce_bs)
8
  • Can you list each of the fields you need from that output? E.G $user, $uid, $gid, $name. Some of that information will need a lookup outside of /etc/passwd.
    – Matt
    May 7, 2014 at 9:41
  • @mtm, I cannot list them separately.
    – ilhan
    May 7, 2014 at 12:13
  • 2
    If there is a legitimate reason for you to gather all those names, ask the admins.
    – Dubu
    May 7, 2014 at 13:05
  • 2
    getent passwd might work. May 7, 2014 at 13:08
  • @ilhan You can't list the fields that you want to collect into this database?? What are you trying to achieve?
    – Matt
    May 7, 2014 at 13:27

5 Answers 5

6

On Linux systems there's the getent program, which utilizes the standard get*ent(2) functions (getpwent() being the one to use here). What you want to retrieve are the contents of the passwd database (try man nsswitch.conf for a further understanding):

$ getent passwd
root:x:0:0:root:/root:/bin/bash
sashroot:x:0:0:root:/root:/bin/sash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:65004:65534:sync:/bin:/bin/sync
games:x:65005:65060:games:/usr/games:/bin/sh
man:x:65006:65012:man:/var/cache/man:/bin/sh
lp:x:65007:7:lp:/var/spool/lpd:/bin/sh
mail:x:65008:65008:mail:/var/mail:/bin/sh
...

It gets a lot more interesting after the standard system accounts scrolled by.

If you're not an a Linux system, you can get this rather easy by writing something that dumps the user database on its own by using the getpwent(2) function. An example in C would be something like this:

#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>

int
main(void)
{
    struct passwd *pwd;

    while ((pwd = getpwent()) != NULL) {
        printf("user = `%s', uid = %d, gid = %d, name = `%s'\n",
               pwd->pw_name, pwd->pw_uid, pwd->pw_gid, pwd->pw_gecos);
    }

    return 0;
}

Put this in a file test.c and build it with

$ gcc -o test test.c

Then you can call ./test and look what you get:

$ ./test
user = `root', uid = 0, gid = 0, name = `root'
user = `sashroot', uid = 0, gid = 0, name = `root'
user = `daemon', uid = 1, gid = 1, name = `daemon'
user = `bin', uid = 2, gid = 2, name = `bin'
user = `sys', uid = 3, gid = 3, name = `sys'
user = `sync', uid = 65004, gid = 65534, name = `sync'
user = `games', uid = 65005, gid = 65060, name = `games'
user = `man', uid = 65006, gid = 65012, name = `man'
user = `lp', uid = 65007, gid = 7, name = `lp'
user = `mail', uid = 65008, gid = 65008, name = `mail'
...

As above, it'll get more interesting later on.

The approach of using getwent() has the big advantage that you don't have to make any assumptions on how the login system is configured (/etc/passwd, LDAP, NIS, …?) but just let the system retrieve the information with its actual configuration.

Edit: It might happen that the passwd database's storage backend, e.g. LDAP, doesn't permit enumerating the database (and thus getpwent()) but only hand you out data sets explicitly requested by key (e.g. login name or UID, so getpwuid() or getpwnam() might work). In this case (and since your target user names are so neatly named) you could still "enumerate" manually with a modification of @masegaloeh's script:

#!/bin/bash

for i in {000000..999999}; do 
    getent passwd "e${i}" 2> /dev/null
done

How to do this in absence of getent with the system API (getpwnam(), getpwuid()) is left as an exercise to the reader.

7
  • 1
    It might be useful to use Python instead of C. You have access to low-level C libraries but data manipulation is much easier. May 7, 2014 at 14:31
  • It is not homework. There is a new foreign very hot female student (I'm foreign student too, anyway), I don't know her name. So, instead of manually checking the last 5000 accounts I thought that it would be better to build a database, check the last 7000 accounts, sort them by unique given names (like where a given name appears only once), and then concentrate on the departments in the Business Administration building. Then it would be easy to spot her. Plus, I'll check her name on Facebook. Nothing serious, I won't message or talk to her. I'm just curious. She is 11/10. :)
    – ilhan
    May 7, 2014 at 18:29
  • The account database may not always be enumeratable, so getent (or getpwent), even when available may not always work. May 7, 2014 at 18:52
  • 7
    @ilhan seriously? Sometimes Unix is not the answer. Put the laptop down, say "Hi, My name's ..."
    – Matt
    May 7, 2014 at 23:43
  • 1
    @mtm: With LDAP as backend, for example, you could deactivate enumeration (a.k.a. search) but tell LDAP to only give out records explicitely requested (by login or UID, for example). In this case, »enumerating« (by hand) over the user names via getpwnam() would work, getpwent() won't. May 7, 2014 at 23:53
5

getent is indeed the right way to access any database through the name switch on a Unix/Linux system, so it doesn't matter if accounts are stored locally in /etc/passwd, or if they are in LDAP, AD, NIS, or whatever service you have configured in nsswitch.conf.

So I'd do:

getent passwd | awk -F: '$1 ~"^e[0-9]*$" {print $5}'

This will print the full usernames for all accounts beginning with 'e' and followed by only digits.

If I needed to do this on a Windows system, I'd install cygwin and then do it as above :). In fact I just tested getent on Windows/cygwin and it works great (somewhat surprisingly).

4
  • Prints out 62 accounts' full names out of 48500 accounts.
    – ilhan
    May 7, 2014 at 18:16
  • @ilhan: Can you tell if just "getent passwd" generates all the expected user accounts? Do they all consist of the letter 'e' followed by only digits? That was my understanding, and is what the awk pattern is designed to match. May 8, 2014 at 18:22
  • getent passwd prints out many (not all) accounts such as e146178:x:6207:2191:benek celjina:/home705/e146178:/bin/bash which includes the username (e146178), full name (benek celjina), department (2191) which corresponds to gene_bs. Some of them were like wwwecon:x:21698:20000:ekonomi toplulugu:/homewww/wwwecon:/bin/tcsh gist.github.com/anonymous/de59bb84bdc8404c9cc0 gist.github.com/anonymous/15885f3798e64fb95c41
    – ilhan
    May 8, 2014 at 22:32
  • Student numbers are given in sequence order. My username number is e147200. Now, the last username is somewhere around e201000. Some usernames do not exist to trap email spammers. Some users are like michaeljackson if they are professors, or some users are like wwwstat (Statistics Department web server) if they are department web servers.
    – ilhan
    May 8, 2014 at 22:40
3

This bash script will do looping for you

#!/bin/bash
for i in {205846..205850}; do
    finger e${i}
    id e${i}
done

You just modify 205846 and 205850 to get different range

1

/etc/password output is your safest bet as finger will print duplicates if some part of the name matches.

The following bash script should do the trick, it'll output user $output of id user

l=$(grep "^UID_MIN" /etc/login.defs)

# get max UID limit
#l1=$(grep "^UID_MAX" /etc/login.defs)

# if not set, set manually
l1=4999

# get all users and assign to users array
users=$(awk -F':' -v "min=${l##UID_MIN}" -v "max=${l1##UID_MAX}" '{ if ( $3 >= min && $3 <= max ) print $0}' /etc/passwd | awk 'BEGIN { FS = ":" } ; { print $1 }')

# print the needed info
for user in $users ; do echo -n $user && echo -n " " && id $user ; done

If you change the last line to

for user in $users ; do echo "INSERT INTO users(name,groups) VALUES('$user', '`id $user`');" ; done

It'll get you SQL insert statements, e.g

INSERT INTO users(name,groups) VALUES('priit', 'uid=1056(priit) gid=1056(priit) grupid=1056(priit)');
2
  • If you use getent passwd instead of /etc/passwd you will get users from other databases as well (eg. LDAP or NIS)
    – mtak
    May 7, 2014 at 10:28
  • @mtak s/will/might/, those database may not necessarily be enumeratable. May 7, 2014 at 18:53
-3

You can get all user information from /etc/passwd

2
  • 1
    This is without much doubt plain wrong on every larger scale network, like the ones in a university and if it was done with /etc/passwd UNIX accounts the system operators would be either incredibly bored or just insane beyond belief. NIS/YP exists for at least 30 years. May 7, 2014 at 10:11
  • @AndreasWiese Yes. I agree with you. :) May 7, 2014 at 11:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .