/* This is csadmin (osh) Version 0.1 

----
Copyright (c) 1993 The Regents of the University of California
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that: (1) source code distributions
retain the above copyright notice and this paragraph in its entirety, (2)
distributions including binary code include the above copyright notice and
this paragraph in its entirety in the documentation or other materials
provided with the distribution, and (3) all advertising materials mentioning
features or use of this software display the following acknowledgement:
``This product includes software developed by the University of California,
Los Alamos National Laboratory and its contributors.'' Neither the name of
the University nore the names of its contributors may be used to endorse
or promote products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

static char *rcsid="@(#) $Id: osadmin.c,v 1.2 1994/11/08 02:35:11 mcn Exp $";

#ifdef HAVE_CONFIG_H
#include <defs.h>
#endif

#include <stdio.h>
#include <curses.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/file.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#include <signal.h>
#include <strings.h>

#include "struct.h"

struct entry Table[MAXTABLESIZE];

struct menuitem {
  char *text;
  int  answer;  /* 0 for no question, 1 for yes/no */
  int  def;     /* 1 for yes, 0 for no, don't care if answer=0 */
  };

void do_banner(name)
char *name;

{
move(0,0);
clrtoeol();
move(0,16);
standout();
addstr("Consultants Shell Admin. v1.0 -- User (");
if (name==NULL) addstr("*none*"); else addstr(name);
addstr(")");
standend();
}

void getstr2(what)
char *what;

{
char c;
int pointer=0;
int i;
int y,x;
int done=0;
char er,ki;

cbreak();
noecho();
while (!done) {
 refresh();
 getyx(stdscr,y,x);
 c=getch();
 if (c==er) { 
    if (pointer>0) {
	pointer--;
	move(y,x-1);
	addch(' ');
	move(y,x-1);
    } 
 } else
 if (c==ki) { 
    for (i=pointer;i>0;i--) {
	move(y,x-(pointer-i)-1);
	addch(' ');
	move(y,x-(pointer-i)-1);
	}
     pointer=0;
 } else
 if (c=='\n') done=1;
 else {
   *(what+(pointer++))=c;
    addch(c);
 }
}
*(what+(pointer))='\0';
printw("\n");
}

void put(what)
char *what;

{

move(LINES-1, 0);
addstr(what);
clrtoeol();
refresh();
return;
}

int ask(what)
char *what;

{
char c;
int answer=(-1);

move(LINES-1,0);
addstr(what);
addstr("? ");
clrtoeol();
cbreak();
noecho();
refresh();
while (answer==-1) {
 c=getch();
 if ((c=='y') || (c=='Y')) answer=1;
 if ((c=='n') || (c=='N')) answer=0;
}
echo();
nocbreak();
standout();
if (answer) addstr("Yes!"); else addstr("No.");
standend();
refresh();
return(answer);
}

char *asktxt(what)
char *what;

{
char *buf;

buf=(char *)malloc(78-strlen(what));
move(LINES-2,0);
addstr(what);
addstr(": ");
clrtoeol();
echo();
nocbreak();
refresh();
getstr2(buf);
return(buf);
}

char *search(prog,paths) /* Returns the pathname or NULL if not found */
char *prog;
char *paths[];

{
int i=0;
char buf[128];

while (paths[i]!=NULL) {
  strcpy(buf,paths[i]);
  strcat(buf,"/");
  strcat(buf,prog);
  if (access(buf,F_OK)==0) return(buf);
  i++;
}
return(NULL);
}


main()

{
char name[16]; /* Long group/login name? */
FILE *infile;
FILE *outfile;
int found;
char dummy[255],orig[255],*k;
int i,x;
char *tfile="/tmp/caXXXXXX";
int done=0,done2;
struct menuitem menu[42]; /* 21 x 2 */
extern void view_edit(),acl_list();

initscr();
while (!done) {
done2=0;
found=0;
i=0;
strcpy(tfile,"/tmp/caXXXXXX");
*name='\0';
clear();
echo();
nocbreak();
do_banner(NULL);
while (strlen(name)==0) {
  move(5,0);
  addstr("Enter User/Group Name to Add/Edit: (\"quit\" exits) ");
  clrtoeol();
  standout();
  refresh();
  getstr2(name);
  standend();
}
if (strcmp(name,"quit")==0) {
  done=1;
  clear();
  refresh();
  break;
}
infile=fopen(TABLE_NAME,"r");
while (!feof(infile)) {
 fgets(dummy,255,infile);
 if (strncmp(name,dummy,strlen(dummy)-1)==0) {
   found=1;
   fgets(dummy,255,infile); /* Get the { */
   fgets(dummy,255,infile);
   while (strncmp(dummy,"}",1)!=0) {
     strcpy(orig,dummy); /* Last character is \n */
     k=orig+strlen(orig)-1;
     *k='\0'; /* Get rid of the \n */
     if ((*orig=='+') || (*orig=='-')) {
	Table[i].prog_name=(char *)malloc(strlen(orig)+1);
	strcpy(Table[i].prog_name,orig);
	Table[i++].path=NULL;
     } else {
     Table[i].prog_name=(char *)malloc(strlen(orig)-strlen(index(orig,' '))-1);
     Table[i].path=(char *)malloc(strlen(index(orig,' '))-1); /* 1 nl 1 space */
     strcpy(Table[i].path,index(orig,' ')+1);
     k=(char *)index(orig,' ');
     *k='\0';
     strcpy(Table[i++].prog_name,orig);
     }
     fgets(dummy,255,infile);
   }
 }
}
fclose(infile); 
if (found) {
  infile=fopen(TABLE_NAME,"r");
  if ((outfile=fopen(mktemp(tfile),"w+"))==NULL) 
	fprintf(stderr,"Can't open %s\n",tfile);
  while (!feof(infile)) {
    fgets(dummy,255,infile);
    if (!feof(infile)) {
     if (strncmp(name,dummy,strlen(dummy)-1)==0)
      while ((strncmp(dummy,"}",1)!=0) && (!feof(infile))) fgets(dummy,255,infile);
     else fprintf(outfile,"%s",dummy);
    }
  }
  /* That will strip the current users info */
  fclose(infile);
  fclose(outfile);
  infile=fopen(tfile,"r");
  outfile=fopen(TABLE_NAME,"w+");
  fgets(dummy,255,infile);
  while (!feof(infile)) {
    fputs(dummy,outfile);
    fgets(dummy,255,infile);
  }
  fclose(infile);
} else outfile=fopen(TABLE_NAME,"a");

cbreak();
noecho();
while (!done2) {
 clear();
 do_banner(name);
 move(6,0);
 addstr("1) View/Edit Command Table");
 move(8,0);
 addstr("2) View/Edit Access Control List");
 move(10,0);
 addstr("3) Exit/Save");
 move(14,0);
 refresh();
 switch(getch()) {
	case '1': view_edit(name,&i);
		  break;
	case '2': acl_list(name,&i);
		  break;
	case '3': done2=1; break;
	default: break;
	}
} /* of !done2 */
found=0;
fprintf(outfile,"%s\n{\n",name);
for(x=0;x<i;x++)
  if ((*Table[x].prog_name=='+') || (*Table[x].prog_name=='-'))
	fprintf(outfile,"%s\n",Table[x].prog_name);
  else
        fprintf(outfile,"%s %s\n",Table[x].prog_name,Table[x].path);
fprintf(outfile,"}\n");
fclose(outfile);
} /* of while !done */
endwin();
} /* of main */

void acl_list(name,i)
int *i;
char *name;

{
int x,offset=0,current=0,d,temp;
int done=0;
struct menuitem Menu[MAXTABLESIZE];
char c;
char *e;
int k,y,adder,first;

clear();
for (x=0;x<*i;x++) {
  Menu[x].text=
    (char *)malloc(strlen(Table[x].prog_name)+1);
  strcpy(Menu[x].text,Table[x].prog_name);
  Menu[x].def=0;
  }
while (!done) {
  cbreak();
  noecho();
  do_banner(name);
  move(2,0);
  adder=0;
  first=-1;
  for (x=offset;x<MIN(*i,offset+LINES+adder-4);x++) {
  if ((*Menu[x].text!='+') && (*Menu[x].text!='-')) adder++;
  else {
    if (first==-1) first=x;
    if (current<x) current=x;
    printw("\n");
    if (x==current) standout();
    addstr(Menu[x].text);
    if (x==current)
	addstr(" <-- "); /* In case they don't have reverse */
    if (Menu[x].def) {
	getyx(stdscr,y,k);
	if (x!=current) clrtoeol();
	move(y,40);
	addstr("  D");
    }
    if (x==current) standend();
    clrtoeol();
  } /* of else */
} /* of for */
if ((x==0) || (first==-1)) {
  move(2,0);
  addstr("No Entries");
  }
refresh();
c=getch();
switch(c) {
  case 'q': case 'Q': done=1; break;
  case 'e': case 'E': /* Kill marked entires */
	if (ask("Really eliminate marked")) {
		for (x=0;x<*i;x++)
		  if (Menu[x].def) {
			free(Menu[x].text);
			Menu[x].text=NULL;
			Menu[x].def=0;
		  }
		d=0;
		for (x=0;x<*i;x++) {
		  while ((Menu[d].text==NULL) && (d<*i)) d++;
		  if (d==*i) break;
		  Menu[x].text=Menu[d].text;
		  Table[x].prog_name=Table[d].prog_name;
		  Table[x].path=Table[d++].path;
		}
		*i=x;
		offset=0;
	}
	clear();
	break;
  case 'd': case 'D':
	Menu[current].def=1-Menu[current].def;
	break;
  case 'k':
	if (current>0) {
		temp=current-1;
		while ((temp>0) && 
	  	  (*Menu[temp].text!='+') && (*Menu[temp].text!='-'))
			temp--;
		if (temp>=0) current=temp;
	}
	if (offset>current) offset=current;
	break;
  case 'j':
	if (current<*i-1) {
		temp=current+1;
		while ((temp<*i-1) && 
		  (*Menu[temp].text!='+') && (*Menu[temp].text!='-'))
			temp++;
		if (temp<*i-1) current=temp;
	}
	  if (current>offset+LINES+adder-4) offset++;
	break;
  case 'a': case 'A': 
	if ((e=asktxt("Enter new ACL entry"))==NULL)
		break;
	Table[*i].prog_name=(char *)malloc(strlen(e)+1);
	Table[*i].path=NULL;
	strcpy(Table[*i].prog_name,e);
	Menu[*i].text=(char *)malloc(strlen(Table[*i].path)+1);
	strcpy(Menu[*i].text,Table[*i].prog_name);
	Menu[*i].def=0;
	(*i)++;
	clear();
	break;
  case 'h': case 'H': default:
     put("(Q)uit, (E)liminiate Marked, (D)elete, (A)dd, (K/J) Up/Down.");
     break;
  } /* of switch */
 } /* of !done */
}

void view_edit(name,i)
int *i;
char *name;

{
int x,offset=0,current=0,d,temp;
int done=0;
struct menuitem Menu[MAXTABLESIZE];
char c;
char *e;
int k,y,adder,first;

clear();
for(x=0;x<*i;x++) {
  Menu[x].text=
    (char *)malloc(strlen(Table[x].prog_name)+3+strlen(Table[x].path));
  sprintf(Menu[x].text,"%s   %s",Table[x].prog_name,Table[x].path);
  Menu[x].def=0;
  }
while (!done) {
 cbreak();
 noecho();
 do_banner(name);
 move(2,0);
 adder=0;
 first=-1;
 for (x=offset;x<MIN(*i,offset+LINES+adder-4);x++) {
 if ((*Menu[x].text=='+') || (*Menu[x].text=='-')) adder++;
 else {
   if (first==-1) first=x;
   if (current<x) current=x;
   printw("\n");
   if (x==current)
	standout();
   addstr(Menu[x].text);
   if (x==current)
	addstr(" <-- "); /* In case they don't have reverse */
   if (Menu[x].def) {
	getyx(stdscr,y,k);
	if (x!=current) clrtoeol();
	move(y,40);
	addstr("  D");
   }
   if (x==current) {
	standend();
   }
   clrtoeol();
 } /* of else */
 } /* of for */
 if ((x==0) || (first==-1)) {
   move(2,0);
   addstr("No Entries");
   }
 refresh();
 c=getch();
 switch(c) {
   case 'q': case 'Q': done=1; break;
   case 'e': case 'E': /* Kill marked entries */
	if (ask("Really eliminate marked")) {
		for (x=0;x<*i;x++)
		   if (Menu[x].def) {
			free(Menu[x].text);
			Menu[x].text=NULL;
			
		   }
		d=0;
		for (x=0;x<*i;x++) {
		   while ((Menu[d].text==NULL) && (d<*i)) d++;
		   if (d==*i) break;
		   Menu[x].text=Menu[d].text;
		   Table[x].prog_name=Table[d].prog_name;
		   Table[x].path=Table[d++].path;
		}
		*i=x; /* Cut back menu */
		offset=0;
        }
	clear();
	break;
   case 'd': case 'D': /* Toggle current Entry */
	Menu[current].def=1-Menu[current].def;
	break;
   case 'k': /* Move up */
	if (current>0) {
		temp=current-1;
	        while ((temp>0) && 
		  ((*Menu[temp].text=='+') || (*Menu[temp].text=='-')))
                        temp--;
                if (temp>=0) current=temp;
        }
        if (offset>current) offset=current;
	break;
   case 'j': /* Move down */
	if (current<*i-1) {
	   temp=current+1;
	   while ((temp<*i-1) && 
	     ((*Menu[temp].text=='+') || (*Menu[temp].text=='-')))
		temp++;
	   if (temp<*i-1) current=temp;
	}
	if (current>offset+LINES+adder-4) offset++;
	break;
   case 'a': case 'A': /* Add an entry */
	if ((e=asktxt("Enter new command name"))==NULL)
		break;
	Table[*i].prog_name=(char *)malloc(strlen(e)+1);
	strcpy(Table[*i].prog_name,e);
	if ((e=search(e,SearchPaths))==NULL) {
		if (ask("Command not found in path. Enter path")) {
			if ((e=asktxt("Enter full path (ie. /bin/du)"))==NULL)
				free(Table[*i].prog_name);
		}	
		else {
			free(Table[*i].prog_name);
			break;
		}
	}
	if (e!=NULL) {
	 Table[*i].path=(char *)malloc(strlen(e)+1);
	 strcpy(Table[*i].path,e);
	 /* Now table is filled */
	 Menu[*i].text=(char *)malloc(strlen(Table[*i].path)+
		strlen(Table[*i].prog_name)+4);
	 sprintf(Menu[*i].text,"%s   %s",Table[*i].prog_name,
		Table[*i].path);
	 Menu[*i].def=0;
	 (*i)++;
	 clear();
	}
	break;
   case 'h':
   case 'H': 
   default:
    put("(Q)uit, (E)liminate Marked, (D)elete Current, (A)dd, (K/J) Up/Down.");
     break;
 } /* Of switch */
} /* of !done */
} /* of routine */


