From:	SMTP%"DSJ@WKUVX1.WKU.EDU" 21-DEC-1993 10:53:45.15
To:	EVERHART
CC:	
Subj:	OCTOBER93.FILOWN

X-FileServer: Digital Systems Journal File Server <DSJ@WKUVX1.WKU.EDU>
Date: Tue, 21 Dec 1993 09:55:07 CDT
Sender: DSJ-Mgr@WKUVX1.WKU.EDU
Errors-To: DSJ-Mgr@WKUVX1.WKU.EDU
Warnings-To: <>
From: DSJ-Mgr@WKUVX1.WKU.EDU
Reply-To: DSJ@WKUVX1.WKU.EDU
Subject: OCTOBER93.FILOWN
To: EVERHART@arisia.gce.com

$ !
$ ! File : EXTRACT_HEADER.COM
$ !
$ ! Procedure to extract a macro definition from a library and convert
$ ! it to a VAX C header file.
$ !
$ ! Written by Dennis Leiterman
$ ! 12-Mar-1993
$ !
$ INPUT_LOOP:
$ if (p1 .eqs. "") then inquire p1 "Enter module to be extracted "
$ if (p1 .eqs. "") then goto input_loop
$ if (p2 .eqs. "") then p2 := "lib"
$ set on
$ on error then goto exit
$ library/extract=$'p1'/output='p1'/macro sys$library:'p2'.mlb
$ set noon
$ open/read in_file 'p1'.mar
$ open/write out_file 'p1'.h
$ write out_file "#ifndef ___''p1'__LOADED"
$ write out_file "#define ___''p1'__LOADED 1"
$ write out_file ""
$ write out_file "/*"
$ write out_file "This file has been created using the macro definitions"
$ write out_file "located in ''p2'.mlb.  All the $EQU statements have been"
$ write out_file "changed to #define statements and the extension is changed"
$ write out_file "to a .h"
$ write out_file "*/"
$ loop:
$ read/end_of_file=done/error=done in_file in_buff
$ if (f$extract(0, 4, in_buff) .eqs. "$EQU") then -
	write out_file "#define ''f$extract(4,80,in_buff)'"
$ goto loop
$ DONE:
$ write out_file ""
$ write out_file "#endif /* ''p1' loaded */"
$ close in_file
$ close out_file
$ delete 'p1'.mar;
$ EXIT:
$ exit


/*
  Program to read the INDEXF.SYS and check ownership of 
  file headers -vs- the directory where they reside
  
  Written by Dennis Leiterman
  2-Mar-1993

  History:
*/

/* Standard definitions  */
#include	<stdio>
#include	<descrip>

/* RMS definitions       */
#include	<fibdef>	/* File information block definitions */
#include	<fiddef>	/* File Identification definitions    */
#include	<iodef>		/* QIO definitions                    */
#include	<ssdef>		/* System Service messages            */
#include	<hm2def>	/* Taken from LIB.MLB                 */
#include	<fh2def>	/* Taken from LIB.MLB                 */

#define		RECORD_SIZE	FH2$C_LEVEL2 /* Record size of indexf */
#define		BLOCK_SIZE	128	     /* Block size            */
#define		MAX_HEADERS	100000	 /* Maximum number of headers */

main(int argc, char **argv)
{
	struct fibdef	fib;
	struct { int	fib_len, fib_address; } fib_desc;
	struct { short	status; int count; short filler; } iosb;
	struct { 
		unsigned char valid;		/* Valid byte       */
		unsigned int  owner;		/* Owner identifier */
		struct fiddef fid;		/* File FID         */
		struct fiddef backlink;		/* Directory FID    */
		} header_array[MAX_HEADERS];

	struct	dsc$descriptor_s filename_desc;
	struct	dsc$descriptor_s device_desc;
	struct	dsc$descriptor_s file_owner_desc;
	struct	dsc$descriptor_s directory_owner_desc;


/* System declarations */

	int	sys$assign(), sys$dassgn(), sys$qiow(),
		lib$int_over(), lib$fid_to_name(), sys$idtoasc();

/* Program declarations */

	unsigned char *header_ptr;
	unsigned char block_buffer[RECORD_SIZE * BLOCK_SIZE];

	char	
		command_file[80],	/* Name of command file */
		log_file[80],		/* Name of the log file */
		file_owner[40],		/* For sys$idtoasc      */
		directory_owner[40],	/* Owner of directory   */
		device_name[80],	/* Device to check      */
		filename[132];		/* Store file name from */
                                        /* lib$fid_to_name()    */
	int	
		validate_header();	/* Check header function */

	unsigned int
		long_buff,		/* Long int general variable */
		vbn,			/* Virtual block number   */
		header_count = 0,	/* Total headers found */
		status,			/* General purpose status */
		file_index;		/* File index number */

	unsigned short	
		function_code,		/* Function code for QIO  */
		filename_length,	/* Length returned */
		file_owner_length,	/* Length from sys$idtoasc */
		directory_owner_length, /* Directory length */
		device_channel;		/* Disk channel           */

	register i;			/* General purpose index  */

	void	supply_help(void);	/* Give some help         */

	FILE	*command_file_ptr;	/* Command file to change ownership */
	FILE	*log_file_ptr;		/* Log file */

/* See if a device is supplied on the command line */
	if (argc != 2) {
	  printf("RIN-E-NODEV, No device supplied\n");
	  supply_help();
	  exit(1);
	} /* End of device check */
	strcpy(&device_name, argv[1]);

/* Make a command and log file using the device name */
	for (i=0; i <= strlen(device_name) && device_name[i] != ':'; i++)
		command_file[i] = log_file[i] = device_name[i];
	command_file[i] = '\0';
	log_file[i] = '\0';
	strcat(command_file, "_misowned.com");
	strcat(log_file, "_misowned.log");
	if ((command_file_ptr = fopen(command_file, "w")) == NULL) {
		perror("open"); 
		exit();
	}
	if ((log_file_ptr = fopen(log_file, "w")) == NULL) {
		perror("open"); 
		exit();
	}
	fprintf(command_file_ptr, "$ set noon \n");

/* Make a descriptor for the device name */
	device_desc.dsc$w_length  = strlen(device_name);
	device_desc.dsc$a_pointer = &device_name;
	device_desc.dsc$b_class   = DSC$K_CLASS_S;
	device_desc.dsc$b_dtype   = DSC$K_DTYPE_T;

/* Make a descriptor for the file name */
	filename_desc.dsc$w_length  = sizeof(filename);
	filename_desc.dsc$a_pointer = &filename;
	filename_desc.dsc$b_class   = DSC$K_CLASS_S;
	filename_desc.dsc$b_dtype   = DSC$K_DTYPE_T;

/* Make a descriptor for the file owner name */
	file_owner_desc.dsc$w_length  = sizeof(file_owner);
	file_owner_desc.dsc$a_pointer = &file_owner;
	file_owner_desc.dsc$b_class   = DSC$K_CLASS_S;
	file_owner_desc.dsc$b_dtype   = DSC$K_DTYPE_T;

/* Make a descriptor for the directory owner name */
	directory_owner_desc.dsc$w_length  = sizeof(directory_owner);
	directory_owner_desc.dsc$a_pointer = &directory_owner;
	directory_owner_desc.dsc$b_class   = DSC$K_CLASS_S;
	directory_owner_desc.dsc$b_dtype   = DSC$K_DTYPE_T;

/* First assign a channel to the device */
	status = sys$assign(&device_desc, &device_channel, 0, 0);
	if ((status &1) != 1) exit(status);

/* Zero out the fib data structure */
	memset(&fib, 0, sizeof(fib));

/* Access the INDEXF.SYS file */

	fib.fib$r_fid_overlay.fib$w_fid[0] = FID$C_INDEXF;
	fib.fib$r_fid_overlay.fib$w_fid[1] = FID$C_INDEXF;
	fib.fib$r_fid_overlay.fib$w_fid[2] = 0;

	fib_desc.fib_len = FIB$K_LENGTH;
	fib_desc.fib_address = &fib;

	function_code = IO$_ACCESS | IO$M_ACCESS;
	status = sys$qiow(0, 			/*  Event flag     */
			device_channel,         /*  Channel        */
			function_code, 		/*  Function Code  */
			&iosb,			/*  I/O Status     */ 
			0, 0,      		/*  No AST         */
			&fib_desc, 		/*  FIB            */
			0, 0, 0, 0, 0);
	if ((status & 1) != 1) exit(status);
	if ((iosb.status & 1) != 1) exit(iosb.status);

/* Now read in the home block */
	function_code = IO$_READVBLK;
	status = sys$qiow(0,			/*  Event flag      */
			device_channel, 	/*  Channel         */
			function_code, 		/*  Function Code   */
			&iosb,			/*  I/O Status      */
			0, 0, 			/*  No AST          */
			&block_buffer,		/*  Stuff data here */
			RECORD_SIZE, 		/*  Size of buffer  */
			2,			/*  Virtual block   */
			0, 0, 0);
	if ((status &1) != 1) exit(status);
	if ((iosb.status & 1) != 1) exit(iosb.status);

/* Find out where the data starts */

	vbn = block_buffer[HM2$W_IBMAPVBN] + block_buffer[HM2$W_IBMAPSIZE];

/* Start reading headers */

	for ( ;iosb.status != SS$_ENDOFFILE; vbn += BLOCK_SIZE)
	{
	function_code = IO$_READVBLK;
	status = sys$qiow(0,			  /*  Event flag      */
			device_channel, 	  /*  Channel         */
			function_code, 		  /*  Function Code   */
			&iosb,			  /*  I/O Status      */
			0, 0, 			  /*  No AST          */
			&block_buffer,		  /*  Stuff data here */
			sizeof(block_buffer),     /*  Size of buffer  */
			vbn,			  /*  Virtual block   */
			0, 0, 0);
	if ((status &1) != 1) exit(status);
	if (iosb.status != SS$_ENDOFFILE) {
		if ((iosb.status & 1) != 1) exit(iosb.status);
	}

/* Validate header */
	 for (header_ptr = block_buffer, i = 1; 
		i <= (iosb.count / RECORD_SIZE); 
		i++, header_ptr += RECORD_SIZE, header_count++) {ff>
		file_index = 0;
/* See if it is a valid header */
	    if (validate_header(header_ptr)) {
		memcpy(&file_index, header_ptr + FH2$W_FID_NUM, 2);
		file_index += (*(header_ptr + FH2$B_FID_NMX) * 65536);
/* See if it is a directory file, if so store it but make the valid
   byte 2 instead of 1 */
		memcpy(&long_buff, (header_ptr + FH2$L_FILECHAR), 4);
		if (long_buff & FH2$M_DIRECTORY) 
			header_array[file_index].valid = 2;
		else 
			header_array[file_index].valid = 1;  /* Valid file header */

		memcpy(&header_array[file_index].owner,
			header_ptr + FH2$L_FILEOWNER, 4);
		memcpy(&header_array[file_index].fid.fid$w_num,
			header_ptr + FH2$W_FID, 6);
		memcpy(&header_array[file_index].backlink.fid$w_num,
			header_ptr + FH2$W_BACKLINK, 6);
	    } /* End of valid header tasks */
	else header_array[file_index].valid = 0;   /* Not a valid header */
         } /* End of IF loop for header_array store tasks */
        } /* End of IF loop */
/*
   When we come here, we have stored all the valid file and directory
   headers in our array.  Now lets check the owner of the file with 
   the owner of the backlink pointer.  If they don't match, flag them.
   With the count of valid headers found, check if the header array is
   valid, an entry exists for all possible headers in the INDEXF.SYS file.
   If the header was valid, we marked it as; 1 = file header, 2 = directory
   header.  If this is a valid file header check the owner ship of the file
   against the owner of the backlink, which is the FID of the directory
   file where the file resides.  If they don't match, use the owner UIC
   to find an entry in the rights database and find out in ascii who owns
   the file and the directory where is resides.  Print out this info to
   the log file and print it out to the command file to correct ownership.
*/
	for (i = 1; i <= header_count; i++) {
	  if (header_array[i].valid == 1) {  /* 1 = file  2 = directory */
	    if (header_array[i].backlink.fid$w_num == 0) continue;
	     if (header_array[i].owner != 
	       header_array[header_array[i].backlink.fid$w_num].owner) {
		 status = lib$fid_to_name(&device_desc, 
		   &header_array[i].fid.fid$w_num,
		   &filename_desc, 
		   &filename_length, 0, 0);
		 filename[filename_length] = '\0';
		 if (filename_length == 0) continue; /* Didn't find file name */

	status = sys$idtoasc(header_array[i].owner, 
				&file_owner_length,
				&file_owner_desc, 0, 0, 0);
		if (status != SS$_NOSUCHID) {
		if ((status &1) != 1) exit(status);
		file_owner[file_owner_length] = '\0';
		} else strcpy(&file_owner, "<UNKNOWN>");

	status = 
	sys$idtoasc(header_array[header_array[i].backlink.fid$w_num].owner, 
				&directory_owner_length,
				&directory_owner_desc, 0, 0, 0);
		if (status != SS$_NOSUCHID) {
		if ((status &1) != 1) exit(status);
		directory_owner[directory_owner_length] = '\0';
		} else strcpy(&directory_owner, "<UNKNOWN>");

        fprintf (log_file_ptr, "%s owned by %s directory owned by %s\n", 
		filename, file_owner, directory_owner);
	fprintf(command_file_ptr, "$ set file %s /owner=parent\n", filename);

	     } /* End misowned file check */
	  } /* End valid file IF */
	} /* End of FOR loop */

/* Were done, deaccess the file */
	function_code = IO$_DEACCESS;
	status = sys$qiow(0, 			/*  Event flag     */
			device_channel,         /*  Channel        */
			function_code, 		/*  Function Code  */
			&iosb,			/*  I/O Status     */ 
			0, 0,      		/*  No AST         */
			&fib_desc, 		/*  FIB            */
			0, 0, 0, 0, 0);
	if ((status & 1) != 1) exit(status);
	if ((iosb.status & 1) != 1) exit(iosb.status);

	status = sys$dassgn(device_channel);
	if ((status & 1) != 1) exit(status);

} /* End of program */

/* Function to supply help */

void	supply_help(void)
{
    printf("\n");
    printf("This program will find any files in a directory that are\n");
    printf("not owned by the UIC or identifier of that directory.\n\n");
    printf("To use this program, install it as a foriegn command;\n\n");
    printf("$ FIND_MISOWNED := $device[directory]FIND_MISOWNED\n\n");
    printf("Then type in;\n\n");
    printf("$ FIND_MISOWNED device_name\n\n");
    printf("This program will produce a log file and a command file\n");
    printf("Check the log file for what files the program found and who\n");
    printf("owns them, you can use the command file to correct the ownership.\n");

    return;
}

/* 
   Validate Header function, these steps were taken from the VMS File Systems
   Internal book by Kirby McCoy.  
   
   Written by Dennis Leiterman 25-Feb-1993
*/

/* Standard definitions  */
#include	<stdio>

/* RMS definitions       */
#include	<fh2def>	/* Taken from LIB.MLB */

int validate_header(unsigned char *header_char_ptr)
{
	unsigned short	*header_word_ptr;

	unsigned int
		long_buff,		/* Long int general buffer           */
		status,			/* General purpose return check      */
		int_over_disable = 0,	/* Turn off integer overflow         */
		int_over_save;		/* Store whatever is was             */

	unsigned short 
		short_buff,		/* Short int general buffer          */
		checksum;		/* Used to calculate header checksum */

	register i;			/* General purpose index	     */

	header_word_ptr = header_char_ptr;
/*
   Lets see if the file has been deleted, no sense going any further if it is.
*/
	memcpy(&long_buff, (header_char_ptr + FH2$L_FILECHAR), 4);
	if (long_buff & FH2$M_MARKDEL) return 0;

	memcpy(&short_buff, (header_char_ptr + FH2$W_FID_NUM), 2);
	if ( (short_buff == 0) &&
	     (*(header_char_ptr + FH2$B_FID_NMX) == 0) &&
	     (*(header_char_ptr + FH2$B_FID_RVN) == 0) ) return 0;
	if ( *(header_word_ptr + 255) == 0) return 0;
/* 
   Verify that the offset to the data area (FH2$B_IDOFFSET) is past the 
   FH2$L_HIGHWATER offset.  FH2$B_IDOFFSET is the word offset to the data area.
*/
        if (header_word_ptr + *(header_char_ptr + FH2$B_IDOFFSET) <
		*(header_char_ptr + FH2$L_HIGHWATER)) return 0;

/* Next check is making sure all the offsets are greater then the one before. */
        if (*(header_char_ptr + FH2$B_IDOFFSET) > 
	       	*(header_char_ptr + FH2$B_MPOFFSET)) return 0;
	if (*(header_char_ptr + FH2$B_MPOFFSET) > 
		*(header_char_ptr + FH2$B_ACOFFSET)) return 0;
	if (*(header_char_ptr + FH2$B_ACOFFSET) > 
		*(header_char_ptr + FH2$B_RSOFFSET)) return 0;

/* Now check some other values. */
	if ((*(header_char_ptr + FH2$W_STRUCLEV + 1) != 2) &&
	   (*(header_char_ptr + FH2$W_STRUCLEV) < 1)) return 0;
	if ( *(header_char_ptr + FH2$B_MAP_INUSE) >
	   ( *(header_char_ptr + FH2$B_ACOFFSET) - 
		*(header_char_ptr + FH2$B_MPOFFSET)) ) return 0;
/*
   Verify header with simple word checksum,  255 words added together 
   with no regard to overflow must match the 256th word of the header.
*/
	int_over_save = lib$int_over(&int_over_disable); /* Turn it off */
	for (i=0, checksum=0; i < 255; i++)  checksum += *(header_word_ptr + i);
	lib$int_over(&int_over_save);		  /* Restore it */
	if (checksum != *(header_word_ptr + i)) return 0;  /* Bad checksum, return */

	return 1; /* Everything checked out, return success */
} /* End function VALIDATE_HEADER */
