Category: HOW-TOs

Shell Scripting and Security

Shell Scripting and Security


Dave Taylor
Tue, 02/13/2018 – 09:50

Basic ways you can use shell scripts to monitor password strength and secret accounts.

The internet ain’t what it used to be back in the old days. I
remember being online back when it was known as ARPAnet actually—back
when it was just universities and a handful of corporations interconnected.
Bad guys sneaking onto your computer? We were living in blissful
ignorance then.

Today the online world is quite a bit different, and a quick glimpse at
the news demonstrates that it’s not just global, but that bad actors,
as they say in security circles, are online and have access to your
system too. The idea that any device that’s online is vulnerable is
more true now than at any previous time in computing history.

Fortunately, a lot of smart people are working on security both for
networks and Internet of Things devices. We don’t want hackers
gaining control of our smart homes or autonomous cars.

Whether you have Linux running on your laptop or ancient PC file server
or whether you’re managing a data center, your system is also
vulnerable to malicious users. I can’t offer any sort of robust
solution in this article, but let’s have a look at some basic things
you can do with shell scripts to keep an eye on your system.

First and foremost, make sure you have complex non-guessable passwords
for all your accounts and particularly your administrative or root
account. It’s tough to check existing passwords, since they’re all
stored in an encrypted manner without spending oodles of CPU cycles
brute-forcing it, but how about a script where users can enter their password
and it’ll confirm whether it’s hard to guess?

Password Tester

The general rule of thumb with modern password creation is that you
should use a combination of uppercase, lowercase, digits and one or more punctuation
characters, and that the password should be longer, not shorter. So
“meow” is horrible as a password, and
“Passw0rd!” is
pretty good, but “F#g_flat_33” is a secure choice.

First things first though. A script that is checking passwords should
let users enter their password choice invisibly. You can do so with
the stty command:

stty -echo
echo -n "Enter password: "
read password
stty echo

Now the algorithmic approach to testing for a particular type of
character is simple. Remove every occurrence of that particular character
in the user input and compare it to the original. If they’re the same,
the user didn’t actually use that particular class of characters.

For example, here’s the code to test for the presence of lowercase

chop=$(echo "$password" | sed -E 's/[[:lower:]]//g')
echo "chopped to $chop"

if [ "$password" == "$chop" ] ; then
  echo "Fail: You haven't used any lowercase letters."

Notable here is the use of what are known as bracket expressions. Notice
I didn’t specify [a-z] above, but rather used the locale-smart range
:lower:. In a regular expression, that would have a pair of square
brackets around it: [:lower:]. But, since it’s part of a search
and replace pattern for sed, it picks up a second pair of square brackets
too: [[:lower:]].

It turns out there are a lot of bracket expressions, so you can use
to test for uppercase, :lower: for lowercase
letters, :digit: for the
digits and :punct: for punctuation. There are
plenty more, but those will suffice for the scope of this article.

The good news is that it’s straightforward to write a function that
will check for the specified bracket expression and output an appropriate
error as, well, appropriate:



  chop=$(echo "$password" | sed -E $sedpattern)

  if [ "$password" == "$chop" ] ; then
    echo "Fail: You haven't used any ${errormsg}."

Then you can invoke it like this:

checkfor "[[:lower:]]" "lowercase letters"
checkfor "[[:upper:]]" "uppercase letters"
checkfor "[[:digit:]]" "digits"
checkfor "[[:punct:]]" "punctuation"

Nice and short. So, let’s give this script a quick test at the
command line with the password “B3g”:

$ sh checkpw.sh
Enter password:
You entered B3g
Fail: You haven't used any punctuation.

An accurate error message. In the final script, of course, you won’t
echo the entered password, as that’s not so good from a privacy and
security perspective.

To test for length, it’s easy to use wc -c, but
there’s a special
variable reference format in shell scripts that offers access to the
number of characters too: ${#xxx}. For example, consider this brief

$ test="Hi Mom"
$ echo ${#test}

With this in mind, the test to see whether a specified sample password is
at least eight characters long is easily coded as:

if [ ${#password} -lt $minlength ] ; then
  echo "Fail: Password must be $minlength characters."

Set the $minlength variable to something reasonable at the top
of the script. I suggest 8 as a good minimum length.

I designed the script here to be purely informational, and if you
use a terrible password like “kitty”, you’re going to see a
lot of errors:

$ sh checkpw.sh
Enter password:
You entered kitty
Fail: You haven't used any uppercase letters.
Fail: You haven't used any digits.
Fail: You haven't used any punctuation.
Fail: Password must be at least 8 characters.

There are plenty of tweaks you can make if you want, ranging from having
a counter that can tell if there were more than zero errors with a
resultant success message if all tests succeed to having the script quit
as soon as the first error condition is encountered.

Now, with this script as a simple password-testing tool, it’s easy to
request every user set up a new, secure password that passes all
these tests.

New Account Creation

Another way to keep an eye on your system is to get a notification any
time a new account is created. Whether or not you’re the only admin,
that shouldn’t be something that happens too often. But, if you are the
only admin and it happens without you knowing? Danger, Will Robinson!

In the old days, salted (encrypted) passwords were part of what was
stored in /etc/passwd, but modern systems keep that encrypted data more
safely tucked away in /etc/shadow. User accounts, however, still show up
in the /etc/passwd file, so you can use that as the basis for this simple

The idea is that you’re going to grab all the user account names and
save them to a hidden file, and every time you run the script, you’ll
compare the latest to the saved. If there are new entries, that’s

This approach is definitely not robust, of course, and I wouldn’t
trust credit report data servers with a tool this lightweight, but
it’s an interesting script to consider nonetheless.

Let’s see how to pull out just user account names from the file:

$ cat /etc/passwd | cut -d: -f1
. . .

It’s all about that cut command! The
-d flag specifies the field
delimiter, and -f1 requests that just the first field is output. Given
an input line like this:


you can see that the output becomes just the account names. This
script could compare full files—heck, there’s even a Linux
command for the job—but you don’t want to get false positives if
users change their user names but otherwise leaves their accounts intact.
Further, I like clean, readable output, so that’s what this will

Here’s the full script:


# watch accounts - keep an eye on /etc/passwd,
#                  report if accounts change

compare=0               # by default, don't compare

trap "/bin/rm -f $tempfile" 0

if [ -s "$secretcopy" ] ; then
  lastrev="$(cat $secretcopy)"

cat $passwd | cut -d: -f1 > $tempfile

current="$(cat $tempfile)"

if [ $compare -eq 1 ] ; then
  if [ "$current" != "$lastrev" ] ; then
    echo "WARNING: password file has changed"
    diff $secretcopy $tempfile | grep '^[]' |
        sed 's//;s/>/Added:/'
   mv $tempfile $secretcopy

exit 0

This is a pretty simple script, all in all. Close inspection will reveal
that the secret copy of accounts will be saved in $HOME/.watchdb. The
trap command is used to ensure that the temp file is removed when the
script finishes up, of course.

The $compare variable relates to the case when it’s the very first
time you run the script. In that situation, there is no
.watchdb, so it
can’t be used to test or compare. Otherwise, the contents of that file
are stored in the local variable $secretcopy and
$compare is set to 1.

Block two is the actual comparison, and the only part that’s
interesting is the invocation of diff to compare the two files:

diff $secretcopy $tempfile | grep '^[]' |
   sed 's//;s/>/Added:/'

diff by default outputs commands for the ancient
ed editor, so you mask
that out by considering only lines that begin with a . Those denote entries that are only in the old version of the
password file (removed in the current live copy) and those only in
the new, live version (added accounts).

That’s it. Let’s run it once to create the secret archive file,
then I’ll change the password file to remove one account and create
another, then run the script again:

$ sh watchaccounts.sh
edit password file
$ sh watchaccounts.sh
WARNING: password file has changed
Removed: johndoe
Added: hack3r666

Nice, eh? Now, there are some useful additions to the script that you
consider, notably encrypting .watchdb for security and adding a prompt or
command flag to update the secret password file after changes have been


Programming in Color with ncurses

Programming in Color with ncurses


Jim Hall
Tue, 02/06/2018 – 14:36

Jim demonstrates color manipulation with
curses by adding colors to his terminal adventure

In parts one
and two
of my article series about programming with the ncurses
library, I introduced a few curses functions to draw text on the screen,
query characters from the screen and read from the keyboard. To demonstrate
several of these functions, I created a simple adventure game in
curses that
drew a game map and player character using simple characters. In this
follow-up article, I show how to add color to a curses program.

Drawing on the screen is all very well and good, but if it’s all white-on-black
text, your program might seem dull. Colors can help convey more
information—for example, if your program needs to indicate success or
failure. In such a
case, you could display text in green or red to help emphasize the outcome.
maybe you simply want to use colors to “snazz” up your program to make it look

In this article, I use a simple example to demonstrate color manipulation via the
curses functions. In my previous article, I wrote a basic adventure-style
game that lets you move a player character around a crudely drawn map.
However, the
map was entirely black and white text, relying on shapes to suggest water (~)
or mountains (^), so let’s update the game to use colors.

Color Essentials

Before you can use colors, your program needs to know if it can rely on the
terminal to display the colors correctly. On modern systems, this always
should be true. But in the classic days of computing, some terminals were
monochromatic, such as the venerable VT52 and VT100 terminals, usually
providing white-on-black or green-on-black text.

To query the terminal
capability for colors, use the has_colors() function. This will return a true
value if the terminal can display color, and a false value if not. It is
usually used to start an if block, like this:

if (has_colors() == FALSE) {
    printf("Your terminal does not support color\n");

Having determined that the terminal can display color, you then can set up
to use colors with the start_color() function. Now you’re ready to define
the colors your program will use.

In curses, you define colors in pairs: a foreground color on a background
color. This allows curses to set both color attributes at once,
which often is what you want to do. To establish a color pair, use
init_pair() to
define a foreground and background color, and associate it to an index
number. The general syntax is:

init_pair(index, foreground, background);

Consoles support only eight basic colors: black, red, green, yellow, blue,
magenta, cyan and white. These colors are defined for you with the following









Applying the Colors

In my adventure game, I’d like the grassy areas to be green and the
player’s “trail” to be a subtle yellow-on-green dotted path. Water
should be blue, with the tildes in the similar cyan color. I’d like mountains
be grey, but black text on a white background should make for a reasonable
compromise. To make the player’s character more visible, I’d like to use a
garish red-on-magenta scheme. I can define these colors pairs like so:

init_pair(2, COLOR_CYAN, COLOR_BLUE);

To make my color pairs easy to remember, my program defines a few symbolic

#define GRASS_PAIR     1
#define EMPTY_PAIR     1
#define WATER_PAIR     2
#define MOUNTAIN_PAIR  3
#define PLAYER_PAIR    4

With these constants, my color definitions become:


Whenever you want to display text using a color, you just need to tell
curses to
set that color attribute. For good programming practice, you also should tell
curses to undo the color combination when you’re done using the
colors. To set
the color, use attron() before calling functions like
mvaddch(), and then turn
off the color attributes with attroff() afterward. For example, when I draw
the player’s character, I might do this:

mvaddch(y, x, PLAYER);

Note that applying colors to your programs adds a subtle change to how you
query the screen. Normally, the value returned by mvinch() is of
type chtype
Without color attributes, this is basically an integer and can be used as
such. But, colors add extra attributes to the characters on the screen, so
chtype carries extra color information in an extended bit
pattern. If you use
mvinch(), the returned value will contain this extra color value. To extract
just the “text” value, such as in the is_move_okay() function,
need to apply a bitwise & with the A_CHARTEXT bit mask:

int is_move_okay(int y, int x)
    int testch;

    /* return true if the space is okay to move into */

    testch = mvinch(y, x);
    return (((testch & A_CHARTEXT) == GRASS)
            || ((testch & A_CHARTEXT) == EMPTY));

With these changes, I can update the adventure game to use colors:

/* quest.c */


#define GRASS     ' '
#define EMPTY     '.'
#define WATER     '~'
#define MOUNTAIN  '^'
#define PLAYER    '*'

#define GRASS_PAIR     1
#define EMPTY_PAIR     1
#define WATER_PAIR     2
#define MOUNTAIN_PAIR  3
#define PLAYER_PAIR    4

int is_move_okay(int y, int x);
void draw_map(void);

int main(void)
    int y, x;
    int ch;

    /* initialize curses */

    keypad(stdscr, TRUE);

    /* initialize colors */

    if (has_colors() == FALSE) {
        printf("Your terminal does not support color\n");



    /* initialize the quest map */


    /* start player at lower-left */

    y = LINES - 1;
    x = 0;

    do {
        /* by default, you get a blinking cursor - use it to
           indicate player * */

        mvaddch(y, x, PLAYER);
        move(y, x);

        ch = getch();

        /* test inputted key and determine direction */

        switch (ch) {
        case KEY_UP:
        case 'w':
        case 'W':
            if ((y > 0) && is_move_okay(y - 1, x)) {
                mvaddch(y, x, EMPTY);
                y = y - 1;
        case KEY_DOWN:
        case 's':
        case 'S':
            if ((y  0) && is_move_okay(y, x - 1)) {
                mvaddch(y, x, EMPTY);
                x = x - 1;
        case KEY_RIGHT:
        case 'd':
        case 'D':
            if ((x 

Unless you have a keen eye, you may not be able to spot all of the changes
necessary to support color in the adventure game. The diff tool shows all
the instances where functions were added or code was changed to support

$ diff quest-color/quest.c quest/quest.c
     return ((testch == GRASS) || (testch == EMPTY));

Let’s Play—Now in Color

The program now has a more pleasant color scheme, more closely matching the
original tabletop gaming map, with green fields, blue lake and imposing gray
mountains. The hero clearly stands out in red and magenta livery.

Figure 1. A Simple Tabletop Game Map, with a Lake and

Figure 2. The player starts the game in the lower-left corner.

Figure 3. The player can move around the play area, such as around the lake,
through the mountain pass and into unknown regions.

With colors, you can represent information more clearly. This simple
example uses colors to indicate playable areas (green) versus impassable
regions (blue or gray). I hope you will use this example game as a starting point or reference for
your own programs. You can do so much more with curses, depending on what you
need your program to do.

In a follow-up article, I plan to demonstrate other
features of the ncurses library, such as how to create windows and frames. In
the meantime, if you are interested in learning more about curses, I
encourage you to read Pradeep Padala’s NCURSES Programming
, at the
Linux Documentation Project.