The Linux distillery
Bringing the world of Linux to you, David cuts through the tech and shows you how it works and how to use it, in terms that apply to any distro. RSS
Technology news and Jobs arrow The Linux distillery arrow Real world Linux programming
Real world Linux programming E-mail
by David M Williams   
Tuesday, 11 December 2007
I’ll leave the main program code – menu.c – right to the last page. The two configuration files needed are the list of users and authorisation levels, and the menu definition itself.

The list of users is defined in user.list with a username, an encrypted password, and a privilege level.

#
# username  password  access (0 is lowest)
#
# Blank lines and lines beginning with a '#' are treated as comments

davidw daDDC5rpKNN5c 5
fred frL8GUupUeU6A 1


The passwords can be generated using this simple program which calls the Linux crypt API function. As this is intended only for internal use it is extremely simple and doesn’t have any error checking. If you require usernames of more than 50 characters or passwords of more than 10 characters then you ought to change the code below or else a buffer overrun will occur.

#include <crypt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


main ()
{
 char *username;
 char *password;

 username = (char *) malloc (sizeof (char) * 50);
 password = (char *) malloc (sizeof (char) * 10);

 printf ("   Login: ");
 scanf ("%s", username);

 strcpy (password, getpass ("Password: "));

 printf ("Encrypted password is %s\n", crypt (password, username));

 free (username);
 free (password);
}


The menu is defined in menu.list and this has a more complex structure. Each line defines either a submenu or a genuine command. Commands provide the name of a program to be invoked as well as a flag indicating if super-user access is necessary for that program. Whether a submenu or a command, a minimum access level is given.

# Menu configuration file
#
# Blank lines and lines beginning with a '#' are treated as comments
#
# Lines beginning with 'Menu' indicate a new main menu entry
# These lines will also specify the access level required for entry to
# that menu option, and the following line will contain a textual description
# to be displayed.
#
# Lines that begin with 'Option' indicate an entry for the current menu
# item. These lines will also specify the access level required to use the
# item, whether the item requires root privileges (1 = yes) and the name of
# the script to run. The following line contains the textual description to
# be displayed.
#
# The scripts are all prefixed with the SCRIPTDIR prefix (from menu.h)
#
# Scripts must handle parameters and crashes themselves


Menu 3
Manage mail boxes

Option 3 1 viEditMailBox
Edit a specified mail box using vi

Option 3 1 EditMailBox
Read (and manage) a specified mail box


Menu 1
Testing stuff

Option 1 0 sayHi
Say Hi

Option 1 0 testRead
Read a number


Menu 1
Passwords

Option 1 1 chmenupass
Change password for this menu system


From here on in the rest is simple. All functionality can be implemented as simple, individual, stand-alone scripts. For instance, to allow staff to view a mailbox the following can be used:

#!/bin/sh

MAILPATH=/var/spool/mail

echo -n "What is the name of the mailbox to list? "
read MailBoxName

if [ -r $MAILPATH/$MailBoxName ]; then
 Mail -f $MAILPATH/$MailBoxName
else
 echo No such mailbox
fi


Instead, however, to let the help desk users edit and modify a mailbox, the following will work:

#!/bin/sh

MAILPATH=/var/spool/mail

echo -n "What is the name of the mailbox to edit? "
read MailBoxName

if [ -r $MAILPATH/$MailBoxName ]; then
 /bin/vi $MAILPATH/$MailBoxName
else
 echo No such mailbox
fi


The functionality need not be constrained to shell scripts, or indeed trite programs. Here’s one example of something more complex, namely adding new items to the end of the reverse DNS ARPA file, which is something web hosting services routinely require.

/*
 * arg 1 is the name of the Web node to create,
 * arg 2 is the full path of the ARPA file
 * returns an IP address
*/

#define SENTINEL "# New entries will be placed here - do not remove this line\n"

#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <time.h>


int main (int argc, char **argv)
{
 FILE *Infp;
 FILE *Outfp;

 char line [80];
 char ArpaFile [PATH_MAX];
 char TmpFile [PATH_MAX];
 int LastIp = 0;
 int NewIp = -1;


 if (argc != 3)
 {
  fprintf (stderr, "Bad parameters\n");
  exit (1);
 }


// Open the ARPA file and make a temporary file for writing

 strcpy (ArpaFile, argv [2]);
 strcpy (TmpFile, ArpaFile);
 strcat (TmpFile, ".tmp");


 if ((Infp = fopen (ArpaFile, "r")) <= 0)
 {
  fprintf (stderr, "Cannot open %s\n", ArpaFile);
  exit (1);
 }


 if ((Outfp = fopen (TmpFile, "w")) <= 0)
 {
  fprintf (stderr, "Cannot write to %s\n", TmpFile);
  fclose (Infp);
  exit (1);
 }


// Copy every line from the ARPA file to the temporary file
// If the line begins with a number, grab it as it is an IP address
// If the line is our SENTINEL line then insert a new line with a new IP
// address for the Web node specified.


 while (!feof (Infp))
 {
  fgets (line, 80, Infp);

  if (strcmp (line, SENTINEL) == 0) // Add our line
  {
   NewIp = LastIp + 1;
   fprintf (Outfp, "%-d\t\tIN\tPTR\t%s\n", NewIp,argv [1]);
  }
  else if (isdigit (line [0]))
   sscanf (line, "%d", &LastIp);

  fprintf (Outfp, "%s", line);
 }


 fclose (Infp);
 fclose (Outfp);


 if (NewIp == -1)
 {
  fprintf (stderr, "Could not find sentinel line.\n");
  unlink (TmpFile);
  exit (0);
 }


// Copy the new file back over the original arpa file

 rename (TmpFile, ArpaFile);

 printf ("192.168.1.%-d", NewIp);
 exit (0);
}



CONTINUED






 
< Next story in category   Previous story in the category >
iTWire user statistics Visitors last 30 days
Suscribers
904,266
13,751
#1 independent technology news advertise here
  •   *  
  • Search
  • AdvSeach
  • Login
  • Events
  • FreeStuff
Subscribe to our free e-newsletter