Cover V03, I02
Article
Figure 1
Figure 2
Figure 3
Listing 1
Listing 2
Listing 3
Listing 4
Listing 5
Listing 6
Listing 7

mar94.tar


Listing 1: checker_proc.c

/*
* Processing routings for  Distributed File Checker
*
* Filename checker_proc.c
* Author:     Clive King
* Comment:    Server routines
* Version 1.1
* Date    05 Nov 1993
*
*/

#include <sys/time.h>
#include <malloc.h>
#include <rpc/rpc.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <syslog.h>
#ifdef SVR4
#include <sys/dirent.h>
#include <string.h>
#else
#include <sys/dir.h>
#include <strings.h>
#endif

#include "checker.h"
#include "checker_proc.h"

char *dirname;

namelist nl= NULL;
namelist *nlp;

/*
* routine called from server stub to check the attributes of the file
* and to return the state of the file in question
*/

access_struct *access_1(details)
nametype *details;
{
struct stat buf;
static access_struct file_report;   /* head of the linked list */
char *perms;  /* pointer to string to store permissions */
char *owner;  /* pointer to string to store owener */
char *grp;    /* pointer to string to store group */
char *date;   /* pointer to string to store date */

dirname = (char *)malloc( FILEMAX );
perms = (char *)malloc( PERMAX );
owner = (char *)malloc( NAMEMAX );
grp = (char *)malloc( NAMEMAX );
date = (char *)malloc( DATEMAX );

/* split the fields up into the consituent parts */
split_fields(details, dirname, perms, owner, grp, date);

xdr_free(xdr_access_struct, (char *)&file_report);

nlp = &file_report.access_struct_u.list;
nl = *nlp = (namenode *)malloc(sizeof(namenode));
file_report.access_struct_u.list->result = 0;

if (access(dirname, F_OK) != 0)    {
add_error("", "Can not access file");
return (&file_report);
}

if (stat(dirname, &buf) == -1)    {
add_error("", "Can not stat file");
return (&file_report);
}

/* check permissions of the file */
check_perms(&buf, perms[0], S_ISUID, S_ISGID, S_ISVTX, "permissions");
check_perms(&buf, perms[1], S_IRUSR, S_IWUSR, S_IXUSR, "owner permissions");
check_perms(&buf, perms[2], S_IRGRP, S_IWGRP, S_IXGRP, "group permissions");
check_perms(&buf, perms[3], S_IROTH, S_IWOTH, S_IXOTH, "other permissions");

check_owner(&buf, owner);  /* check ownership */
check_grp(&buf, grp);      /* check group */

/* do not check date field if NO_DATE_CHECK, */
if (strchr(date, NO_DATE_CHECK) == NULL)
check_date(&buf, date);

/* If the checks went well, put O.K. in the error field */
/* The client checks result to determine the test outcome */

if (file_report.access_struct_u.list->result == 0)    {
/* allocate first element in list to avoid xdr problems */
add_error("", "O.K.");
file_report.access_struct_u.list->result = 0;
}

return (&file_report);
}

/*  *********************************************************  */
/* check_perms -- determine if file permissions  are correct
*
* Argument - pointer to files stat structure
* Argument - string value of the correct file permissions
* Argument - Mask to check read (or setuid) field
* Argument - Mask to check write (or setgid) field
* Argument - Mask to check execute (or sticky bit) field
* Argument - error message base string
* Result
*   0 for correct permissions
*   1 for incorrect permissions
*   If an error occurs, then the global err_string is set.
*
* Global array err_string set with type of permissions error
*
*/

void check_perms(buf, value, rmask, wmask, xmask, errstr)
struct stat *buf;
char value;
int rmask;
int wmask;
int xmask;
char *errstr;
{
int tmp;
/* convert char to int */
tmp = value - '0';

if (buf->st_mode & rmask)    {       /* check read permssions */
if (tmp >= 4)
tmp -= 4;   /* the order of the = and - is important here */
else
if (rmask == S_ISUID)
add_error("set uid", errstr);
else
add_error("read", errstr);
}
else
if (tmp  >= 4)	   {
if (rmask == S_ISUID)
add_error("set uid", errstr);
else
add_error("read", errstr);
tmp -= 4;
}

if (buf->st_mode & wmask)    {       /* check write permissions */
if (tmp  >= 2)
tmp -= 2;
else
if (wmask == S_ISGID)
add_error("set gid", errstr);
else

add_error("write", errstr);
}
else
if (tmp  >= 2)	   {
if (wmask == S_ISGID)
add_error("set gid", errstr);
else
add_error("write", errstr);
tmp -= 2;
}

if (buf->st_mode & xmask) {     /* check execute permissions */
if (tmp  >= 1)
tmp -= 1;
else
if (xmask == S_ISVTX)
add_error("sticky", errstr);
else
add_error("execute", errstr);
}
else
if (tmp  >= 1)	   {
if (xmask == S_ISVTX)
add_error("sticky", errstr);
else
add_error("execute", errstr);
tmp -= 1;
}
}

/*  ***********************************************************  */
/* check_owner -- determine if the owner of the file is correct
*
* Argument -  pointer to files stat structure
* Argument -  string value the group should be
* Result
*   0 for correct ownership
*   1 for incorrect ownership
*   If an error occurs, then the global err_string is set.
*
*   Global array err_string is set with error string and correct owner name
*
*/
void check_owner(buffer, own)
struct stat *buffer;
char *own;
{
struct passwd *pass;

if ((pass = getpwnam(own)) == NULL)    {
add_error(own, " : no such user on this system");
return;
}

if (buffer->st_uid != pass->pw_uid)
add_error("incorrect owner : should be ", own);
}

/*  ***********************************************************  */
/* check_owner -- determine if the group of the file is correct
*
* Argument -  pointer to files stat structure
* Argument -  string value the group should be
* Result
*   0 for correct group
*   1 for incorrect group
*   If an error occurs, then the global err_string is set.
*
*   Global array err_string is set with error string and correct group name
*
*/
void check_grp(buffer, grp)
struct stat *buffer;
char *grp;
{
struct passwd *pass;
struct group *gr;

/* search through the groups file for the appropriate gid */
if ((gr = getgrnam(grp)) == NULL)    {
/* if the gid is not in groups but the file is owned by a user
we need to check the gid field in the passwd file */

if ((pass = getpwuid(atoi(grp))) == NULL)	{
add_error(grp, " : no such group on this system");
return;
}
else
if (buffer->st_gid != pass->pw_gid) {
add_error("incorrect group : should be ", grp);
return;
}
}
else
if (buffer->st_gid != gr->gr_gid) {
add_error("incorrect group : should be ", grp);
return;
}
}

/*  ***********************************************************  */
/* check_date -- Checks the date of the last modification time of the file
*               is after the latest acceptable revision date for that file
*
* Argument -  pointer to files stat structure
* Argument -  string value the date should be
*
* Result
*   0 for correct date
*   1 for incorrect date
*   If an error occurs, then the global err_string is set.
*
*   Global array err_string is set with error string and correct date
*
* Notes
*   Both UK and US date styles available, UK by default
*   Compile with -DUSDATE for US style dates
*/

void check_date(buffer, dat)
struct stat *buffer;
char *dat;
{
char *tmp;
int sep_count=0;
char day[3];
char month[3];
char year[5];
char nowdate[18];
char thedate[18];
struct tm tmtime;

int x = 0;
tmp = dat;

while(*tmp != NULL) {
if ( *tmp == DATE_SEPARATOR ) {
x = 0;
sep_count++;
}
else {
switch (sep_count) {
case DATE_FIELD_ONE : {
day[x] = *tmp;
day[x+1] = NULL;
break;
}
case DATE_FIELD_TWO : {
month[x] = *tmp;
month[x+1] = NULL;
break;
}
case 2 : {
year[x] = *tmp;
year[x+1] = NULL;
break;
}
}
x++;
}
tmp++;
}

/* get the date of the file */
tmtime = *gmtime(&buffer->st_mtime);

/* get it into a useable format of 01 0 and 1991 */
if (strftime(thedate, 18, "%Y%m%d", &tmtime) == 0)    {
add_error("strftime failed", "possible problem with date field");
return;
}

(void) sprintf(nowdate,"%s%s%s", year, month, day);

if (atoi(thedate) < atoi(nowdate)) {
add_error(dat, " is too old");
return;
}
}

/*  ***********************************************************  */
/* add_error -- adds an error to the current node
* Arguments
*   char * - the type of error
*   char * - nature of problem
* Result
*   adds an error message to the err_string field of the current node
*/

void add_error(type, str)
char *type;
char *str;
{
char error_string[100];
unsigned int strlength;

(void) sprintf(error_string, "%s  %s", type, str);

if ((nl = *nlp = (namenode *)malloc(sizeof(namenode))) == NULL) {
(void) syslog(LOG_ERR, "malloc failed for checker client");
exit(1);
}

strlength = strlen(error_string)+ strlen(dirname) + 5;
if ((nl->err_string = (char *) malloc(strlength)) == NULL)  {
(void) fprintf(stderr, "malloc failed");
exit(1);
}

(void) sprintf(nl->err_string, "%s : %s", dirname, error_string);
nl->result = 1;
nlp = &nl->next;
*nlp = NULL;
}

/*  ***********************************************************  */
/* split_fields -- Split a line passed to client into constituent parts
*
* Arguments
*    details - Line passed from the client
*    filename - name of the file : derived from details
*    perm - permissions on the file : derived from details
*    own - owner of the file : derived from details
*    grp -group of the file : derived from details
*    dates - : derived from details
*
* Result - returned via filename, perm, own, grp and dates
*/

void split_fields(details, filename, perm, own, grp, dates)
nametype *details;
char *filename;
char *perm;
char *own;
char *grp;
char *dates;
{
int x=0;
int seperator_count=0;
char *det;

/* to add more field, add to the case statement */
for(det=*details;(*det != '\n') && (*det != NULL);det++) {
if (*det == DETAILS_SEPARATOR)	{
seperator_count++;
x=0;
}
else {
switch (seperator_count) {
case 0:  {
filename[x] = *det;
filename[x+1] = NULL;
break;
}
case 1 : {
perm[x] = *det;
perm[x+1] = NULL;
break;
}
case 2 : {
own[x] = *det;
own[x+1] = NULL;
break;
}
case 3 : {
grp[x] = *det;
grp[x+1] = NULL;
break;
}
case 4 : {
dates[x] = *det;
dates[x+1] = NULL;
break;
}
}
x++;
}
}
}
/* End of File */