ftp.nice.ch/pub/next/unix/communication/ft_bbs.1.0.s.tar.gz#/ft_bbs-1.0/filesys.c

This is filesys.c in view mode; [Download] [Up]

/* $Id: filesys.c,v 1.2 1995/12/19 19:30:47 eilts Exp eilts $ */
#include "bbs.h"

char *scratchfilename(char *path, const char *praefix, const char *suffix,
                      const char *scratchdir)
{
  char str[40];
  static char c1 = 'A'-1, c2 = 'A';
  
  c1++;
  if (c1 > 'Z') {
    c1 = 'A';
    c2++;
    if (c2 > 'Z')  c2 = 'A';
  }
  strcpy(path,scratchdir);
  strcat(path,"/");
  if (praefix != NULL)  strcat(path,praefix);
  sprintf(str,"%ld.%c%c",(long)time((TIME_T)0),c1,c2);
  strcat(path,str);
  if (suffix != NULL)  strcat(path,suffix);
  return path;
}

/*
int readmsgheader(msgheadertyp *msghdr, FILE *fp)
{
  int n = 0;
  char key[S_STRLEN+1], arg[STRLEN+1], zeile[STRLEN+1];

  *(msghdr->from) = '\0';
  *(msghdr->reply_to) = '\0';
  *(msghdr->to) = '\0';
  *(msghdr->cc) = '\0';
  *(msghdr->subject) = '\0';
  *(msghdr->date) = '\0';
  *(msghdr->msg_id) = '\0';
  do {
    if (fgetnln(zeile,STRLEN,fp) < 0)  return -1;
    str2cmdparams(zeile,key,arg);
    if (strcmp("From:",key) == 0) {
      strcpy(msghdr->from,arg);
      if (*(msghdr->reply_to) == '\0') {
	strcpy(msghdr->reply_to,msghdr->from);
      }
      n++;
    }
    if (strcmp("Return-To:",key) == 0) {
      strcpy(msghdr->reply_to,arg);
      n++;
    }
    if (strcmp("To:",key) == 0) {
      strcpy(msghdr->to,arg);
      n++;
    }
    if (strcmp("Cc:",key) == 0) {
      strcpy(msghdr->cc,arg);
      n++;
    }
    if (strcmp("Subject:",key) == 0) {
      strcpy(msghdr->subject,arg);
      n++;
    }
    if (strcmp("Date:",key) == 0) {
      strcpy(msghdr->date,arg);
      n++;
    }
    if (strcmp("Message-Id:",key) == 0) {
      strcpy(msghdr->msg_id,arg);
      n++;
    }
  } while(*zeile != '\0');
  return n;
}
*/

int checkfileperms(const char *path, const UID_T euid, const GID_T egid)
  /* Prueft das Objekt path, ob es ein lesbares File ist
     Reueckgabewerte:
       -EACCES: Objekt ist nicht ueberpruefbar (Dir im Pfad ohne x-Bit)
       -ENOENT: Objekt existiert nicht
        EFAULT: Objekt ist kein File
        EACCES: File ist nicht lesbar
	     0: Files ist lesbar
  */
{
  struct stat stats;
  
  if (stat(path,&stats) < 0) {
    return(-errno); /* EACCES, ENOENT */
  }
  else if (! S_ISREG(stats.st_mode)) {
    return(EFAULT);
  }
  else {
    if (getperms(&stats,euid,egid) & PERM_R) return(0);
  }
  return(EACCES);
}


int getperms(const struct stat *stats, const UID_T euid, const GID_T egid)
  /* Prueft die Zugriffsrechte einer Datei/Directory
  */
{
  int perm=0;
  
  if (euid==0) return PERM_R|PERM_W|PERM_X;
  if (euid==stats->st_uid) {
    if (S_IRUSR & stats->st_mode) perm = PERM_R;
    if (S_IWUSR & stats->st_mode) perm |= PERM_W;
    if (S_IXUSR & stats->st_mode) perm |= PERM_X;
  }
  else if (egid==stats->st_gid) {
    if (S_IRGRP & stats->st_mode) perm = PERM_R;
    if (S_IWGRP & stats->st_mode) perm |= PERM_W;
    if (S_IXGRP & stats->st_mode) perm |= PERM_X;
  }
  else {
    if (S_IROTH & stats->st_mode) perm = PERM_R;
    if (S_IWOTH & stats->st_mode) perm |= PERM_W;
    if (S_IXOTH & stats->st_mode) perm |= PERM_X;
  }
  return(perm);
}


char *chrootpath(char path[], const char *chrootcwd, const char *chrootdir)
/*
  Wandelt einen auf chrootcwd bezogenen beliebigen Pfad in einen bezueglich
  chrootcwd (bei chrootdir==NULL) (bzw. "/" bei chrootdir!=NULL) absoluten
  Pfad um.
  "path" wird dabei durch das Ergebnis ueberschrieben.
*/
{
  int k;
  char str[2*PATH_MAX+2], *sp1, *sp2;

  /* absoluten Pfad erzeugen */
  if (path[0]!='/') {
    strcpy(str,path);
    strcpy(path,chrootcwd);
    k = strlen(chrootcwd);
    k--;
    if (k>=0) {
      if (chrootcwd[k]!='/') {
        strcat(path,"/");
      }
    }
    strcat(path,str);
  }

  /* "/../"-Sequenzen kuerzen */
  while ((sp1=strstr(path,"/../"))!=(char *)NULL) {
    sp2 = sp1;
    if (sp1!=path) {
      sp1--;
      while (*sp1!='/') sp1--;
    }
    sp2 += 3*sizeof(char);
    do {
      *(sp1++) = *(sp2++);
    } while (*sp2!='\0');
    *sp1 = '\0';
  }
  
  /* "/./"-Sequenzen kuerzen */
  while ((sp1=strstr(path,"/./"))!=(char *)NULL) {
    sp2 = sp1 + 2*sizeof(char);
    do {
      *(sp1++) = *(sp2++);
    } while (*sp2!='\0');
    *sp1 = '\0';
  }
  
  /* Pfadende anpassen */
  k = strlen(path);
  if (k>=3) {
    if (path[k-3]=='/' && path[k-2]=='.' && path[k-1]=='.') {
    /* "/.." am Pfadende */
      if (k==3) {
        path[k-3] = '\0';
      }
      else {
        sp1 = &(path[k-4]);
	while (*sp1!='/') {
	  sp1--;
	}
	*sp1 = '\0';
      }
    }
  }
  if (k>=2) {
    if (path[k-2]=='/' && path[k-1]=='.') {
    /* "/." am Pfadende */
      path[k-2] = '\0';
    }
  }
  if (k>=1) {
    if (path[k-1]=='/') {
    /* "/" am Pfadende */
      path[k-1] = '\0';
    }
  }
  
  /* Pfad wieder absolut bezueglich "/" machen */
  if (chrootdir!=(char *)NULL) {
    strprepend(path,chrootdir);
  }

  /* leerer Pfad entspricht dem Wurzelverzeichnis */
  if (path[0]=='\0') {
    strcpy(path,"/");
  }

  return path;
}


char *getchrootcwd(chrootrecordtyp *chrootrecord)
  /*
  Gibt cwd, bezogen auf chrootdir, zurueck. Der chrootrecord wird entsprechend
  aktualisiert.
  Ist das nicht moeglich, weil chrootdir nicht den Anfang vom Pfad bildet,
  so wird NULL zurueckgegeben. Der Record ist dann undefiniert.
  */ 
{
  char *sp;

  getcwd(chrootrecord->cwd,PATH_MAX);
  if ((sp=getchrootpath(chrootrecord->cwd,chrootrecord->root)) != NULL) {
    strcpy(chrootrecord->cwdname,chrootrecord->rootname);
    strmaxcat(chrootrecord->cwdname,chrootrecord->cwd,PATH_MAX);
    stripslashes(chrootrecord->cwdname);
  }
  return(sp);
}


char *getchrootpath(char chrootpath[], const char *chrootdir)
  /*
  Kuerzt den in chrootpath stehenden Pfad um chrootdir.
  Ist das nicht moeglich, weil chrootdir nicht den Anfang vom Pfad bildet,
  so wird NULL zurueckgegeben.
  */ 
{
  int k, p;
  
  if (strstr(chrootpath,chrootdir)==chrootpath) {
    for (k=strlen(chrootdir),p=0;k<=strlen(chrootpath);k++) {
      chrootpath[p++] = chrootpath[k];
    }
    if (chrootpath[0]=='\0') {
      strcpy(chrootpath,"/");
    }
    return chrootpath;
  }
  else {
    return (char *)NULL;
  }
}


char *getrealdir(char dir[], const confrecordtyp *confrecord)
{
  char olddir[PATH_MAX+1];
  
  getcwd(olddir,PATH_MAX);
  if (chdir(dir) < 0) {
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","getrealdir","chdir %s: %m",
             dir);
    return(NULL);
  }
  getcwd(dir,PATH_MAX);
  chdir(olddir);
  
  return(dir);
}


int readconffile(confrecordtyp *confrecord, const char *conffile)
{
  int znr, n;
  char zeile[PATH_MAX+S_STRLEN+1], str[PATH_MAX+1], *sp, *key, *arg;
  FILE *fp;
  struct hostent *hostentp;
  extern int h_errno;

  /* Default-Werte */
  confrecord->idletimeout = IDLETIMEOUT;
  confrecord->logintimeout = LOGINTIMEOUT;
  confrecord->maxtries = MAXTRIES;
  strcpy(confrecord->bbsdpath,BBSDPATH);
  confrecord->bbsdwatchtime = BBSDWATCHTIME;
#ifdef BBSDUID
  strcpy(confrecord->bbsduid,BBSDUID);
#else
  strcpy(confrecord->bbsduid,SYSOP);
#endif
  strcpy(confrecord->usersfile,USERRECFILE);
  strcpy(confrecord->logfile,LOGFILENAME);
  strcpy(confrecord->termtable,TERMTABLE);
  strcpy(confrecord->vardir,VARDIR);
  strcpy(confrecord->maildir,MAILDIR);
  strcpy(confrecord->helpdir,HELPDIR);
  strcpy(confrecord->scratchdir,SCRATCHDIR);
  strcpy(confrecord->sysop,SYSOP);
  *confrecord->hostname = '\0';
  confrecord->lang = DEFLANGUAGE;
  strcpy(confrecord->authkey,BBS_AUTHKEY_FIX);
  strcpy(confrecord->rootdir,ROOT);
#ifdef NNTPSERVER
  strcpy(confrecord->nntpserver,NNTPSERVER);
#else
  strcpy(confrecord->nntpserver,"");
#endif
  strcpy(confrecord->nntppost,NNTPPOST);

  /* Config-File lesen */
  if ((fp=fopen(conffile,"r")) == NULL) {
    errormsg(E_SYSLOG|E_USER|E_CONSOLE,confrecord,NULL,"readconffile",
             "fopen %s: %m",conffile);
    return(-1);
  }
  znr = 0;
  while((n=fgetnln(zeile,PATH_MAX+S_STRLEN,fp)) >= 0) {
    znr++;
    if (n > PATH_MAX+S_STRLEN) {
      errormsg(E_SYSLOG|E_USER|E_CONSOLE,confrecord,NULL,"readconffile",
               "line %i too long",znr);
      return(-1);
    }
    split2key_arg(zeile,&key,&arg);
    lowercases(key);
    if (*key=='\0' || *key=='#') {
      /* */
    }
    else if (strncmp("idletimeout",key,6)==0) {
      confrecord->idletimeout = atoi(arg);
    }
    else if (strncmp("logintimeout",key,6)==0) {
      confrecord->logintimeout = atoi(arg);
    }
    else if (strncmp("maxtries",key,6)==0) {
      confrecord->maxtries = atoi(arg);
    }
    else if (strncmp("bbsdpath",key,6)==0) {
      strcpy(confrecord->bbsdpath,arg);
    }
    else if (strncmp("bbsdwatchtime",key,6)==0) {
      confrecord->bbsdwatchtime = atoi(arg);
    }
    else if (strncmp("bbsduid",key,6)==0) {
      strcpy(confrecord->bbsduid,arg);
    }
    else if (strncmp("usersfile",key,6)==0) {
      strcpy(confrecord->usersfile,arg);
    }
    else if (strncmp("logfile",key,6)==0) {
      strcpy(confrecord->logfile,arg);
    }
    else if (strncmp("termtable",key,6)==0) {
      strcpy(confrecord->termtable,arg);
    }
    else if (strncmp("vardir",key,6)==0) {
      strcpy(confrecord->vardir,arg);
    }
    else if (strncmp("maildir",key,6)==0) {
      strcpy(confrecord->maildir,arg);
    }
    else if (strncmp("helpdir",key,6)==0) {
      strcpy(confrecord->helpdir,arg);
    }
    else if (strncmp("scratchdir",key,6)==0) {
      strcpy(confrecord->scratchdir,arg);
    }
    else if (strncmp("sysop",key,5)==0) {
      strcpy(confrecord->sysop,arg);
    }
    else if (strncmp("lang",key,4)==0) {
      confrecord->lang = atoi(arg);
    }
    else if (strncmp("rootdir",key,6)==0) {
      strcpy(confrecord->rootdir,arg);
    }
    else if (strncmp("authkey",key,6)==0) {
      strcat(confrecord->authkey,arg);
    }
    else if (strncmp("nntpserver",key,6)==0) {
      strcpy(confrecord->nntpserver,arg);
    }
    else if (strncmp("nntppost",key,6)==0) {
      strcpy(confrecord->nntppost,arg);
    }
    else {
      errormsg(E_SYSLOG|E_USER|E_CONSOLE,confrecord,NULL,"readconffile",
               "wrong line %i (key %s)",znr,key);
      return(-1);
    }
  }
  
  /* '/' sollte Helpdir nicht abschliessen */
  n = strlen(confrecord->helpdir) - 1;
  if (confrecord->helpdir[n] == '/')  confrecord->helpdir[n] = '\0';
  /* '/' sollte Scratchdir nicht abschliessen */
  n = strlen(confrecord->scratchdir) - 1;
  if (confrecord->scratchdir[n] == '/')  confrecord->scratchdir[n] = '\0';
  
  /* einige Pfade aus vardir ableiten */
  n = strlen(confrecord->vardir) - 1;
  if (confrecord->vardir[n] == '/')  confrecord->vardir[n] = '\0';
  strcpy(str,confrecord->vardir);
  strcat(str,"/");
  strcpy(confrecord->sockpath,str);
  strcat(confrecord->sockpath,"bbs-socket");
  strcpy(confrecord->lockpath,str);
  strcat(confrecord->lockpath,"bbsd-lock");
  strcpy(confrecord->bbsdpidpath,str);
  strcat(confrecord->bbsdpidpath,"bbsdpid");
  strcpy(confrecord->bbsdkpidpath,str);
  strcat(confrecord->bbsdkpidpath,"bbsdkpid");
  strcpy(confrecord->kermrcpath,str);
  strcat(confrecord->kermrcpath,"kermrc");
  
  /* Hostnamen holen */
  if (gethostname(str,PATH_MAX) < 0) {
    errormsg(E_SYSLOG|E_USER|E_CONSOLE,confrecord,NULL,"readconffile",
	      "gethostname: %m");
    return(-1);
  }
  if ((hostentp=gethostbyname(str)) == NULL) {
    switch (h_errno) {
    case HOST_NOT_FOUND:
      sp = "Authoritative Answer Host not found";
      break;
    case TRY_AGAIN:
      sp = "Non-Authoritive Host not found, or SERVERFAIL";
      break;
    case NO_RECOVERY:
      sp = "Non recoverable errors, FORMERR, REFUSED, NOTIMP";
      break;
    case NO_DATA:
      sp = "Valid name, no data record of requested type";
      break;
    default:
      sp = "failed";
    }
    errormsg(E_SYSLOG|E_USER|E_CONSOLE,confrecord,NULL,"readconffile",
	      "gethostbyname %s: %s",str,sp);
    return(-1);
  }
  strmaxcpy(confrecord->hostname,hostentp->h_name,STRLEN);

  return 0;
}


#if 0

#ifndef NO_REGCOMP
#define NO_RE_COMP
#endif
int expandfilenames(const char *inpath, char outpath[],
                    const int maxoutpathlen, const confrecordtyp *confrecord)
  /*
  Expandiert eine Argumentezeile zu allen Files
  
  Rueckgabewerte:
    Anzahl der Files (>=0), wenn ok
    sonst < 0:
      -1: Bereichsueberlauf, Meldung in outpath
      -2: fehlerhaftes Pattern, Meldung in outpath
      -3: Fehler im RE-Vergleich
  */
{
  int nr, k, opos, p;
  SIZE_T membuflen;
  char inbuf[PATH_MAX+1], basedir[PATH_MAX+1], pattern[PATH_MAX+1],
       str[PATH_MAX+1], *memary[MAXARGS], *mbuf, *nbuf, *ipp, c;
  DIR *dp;
  struct dirent *dirp;
  struct stat stats;
#ifndef NO_REGCOMP
  regex_t preg;
  regmatch_t pmatch[1];
#else
#ifndef NO_RE_COMP
  char *sp;
#endif
#endif

  opos = 0;
  nr = 0;
  membuflen = 1024;
  if ((mbuf=(char *)malloc(membuflen)) == NULL) {
    strcpy(outpath,"malloc failed");
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","expandfilenames","malloc: %m");
    return(-1);
  }
  memary[0] = mbuf;
  
  /* Argumentezeile in Buffer kopieren und mittels ipp lesen */
  if (strlen(inpath) > PATH_MAX) {
    strcpy(outpath,"inpath too long");
    errormsg(E_LOGFILE|E_USER,confrecord,"bbs","expandfilenames",
             msg("expandfilenames",0,confrecord->lang));
    free(mbuf);
    return(-1);
  }
  strcpy(inbuf,inpath);
  ipp = inbuf;
  while (*ipp!='\0' && nr>=0) {
    /* a=argumentweise lesen, die Argumente sind durch Leerzeichen getrennt */
    while (*ipp==' ' && *ipp!='\0') ipp++;    /* zum Anfang des Argumentes */
    if (*ipp != '/') {                        /* absoluten Pfad erzeugen */
      getcwd(basedir,PATH_MAX);
      k = strlen(basedir);
      basedir[k++] = '/';
    }
    else {
      k = 0;
    }
    /* Argument nach basedir kopieren, dabei wird der Pfad absolut */
    while (*ipp!=' ' && *ipp!='\0' && k<PATH_MAX) {
      basedir[k++] = *ipp++;
    }
    basedir[k] = '\0';
    /* /a/b.../e/f aufspalten in /a/b.../e/ (basedir) und f (str) */
    while (basedir[--k] != '/') ;
    k++;
    strcpy(str,&(basedir[k]));
    basedir[k] = '\0';
    /* Shell-Metazeichen umwandeln in RE */
    p = 0;
    pattern[p++] = '^';
    k = 0;
    while ((c=str[k++]) != '\0') {
      switch (c) {
      case '.':
      pattern[p++] = '\\';
	pattern[p++] = '.';
	break;
      case '*':
	pattern[p++] = '.';
	pattern[p++] = '*';
	break;
      case '?':
	pattern[p++] = '.';
	pattern[p++] = '?';
	break;
      case ']':
	pattern[p++] = ']';
	pattern[p++] = '?';
	break;
      default:
	pattern[p++] = c;
      }
    }
    pattern[p++] = '$';
    pattern[p] = '\0';
    /* RE compilieren */
#ifndef NO_REGCOMP
    if ((k=regcomp(&preg,pattern,REG_EXTENDED|REG_NOSUB)) != 0) {
      regerror(k,&preg,outpath,PATH_MAX);
#else
#ifndef NO_RE_COMP
    if ((sp=re_comp(pattern)) != (char *)0) {
      strcpy(outpath,sp);
#endif
#endif
      errormsg(E_LOGFILE|E_USER,confrecord,"bbs","expandfilenames",
               msg("expandfilenames",1,confrecord->lang),outpath);
      free(mbuf);
      return(-2);
    }

    /* pattern mit allen Files in basedir vergleichen */
    if ((dp=opendir(basedir)) != NULL) {
      while ((dirp=readdir(dp)) != NULL) {
        strcpy(str,basedir);
        strcat(str,dirp->d_name);
	/* stat-Struct von allen Eintraegen in basedir holen */
        if (stat(str,&stats) == 0) {
          if (S_ISREG(stats.st_mode)) {
#ifndef NO_REGCOMP
       	    if ((k=regexec(&preg,dirp->d_name,0,pmatch,0)) == 0) {
#else
#ifndef NO_RE_COMP
            if ((k=re_exec(dirp->d_name)) == 1) {
#endif
#endif
	      /* Pattern passt */
	      /* Test, ob Filename schon vorhanden ist */
	      for (k=0; k<nr; k++) {
	        if ((p=strcmp(str,memary[k])) == 0) continue;
	      }
	      if (p != 0) {
	        /* Filename ist neu */
		/* Filename merken und diverse Ueberlauftests */
		k = (strlen(str)+1)*sizeof(char);
		if (k + memary[nr] - mbuf > membuflen) {
		  membuflen += 1024;
		  if ((nbuf=(char *)realloc((void *)mbuf,membuflen)) == NULL) {
		    strcpy(outpath,"realloc failed");
                    errormsg(E_LOGFILE|E_USER,confrecord,"bbs",
		             "expandfilenames","realloc: %m");
#ifndef NO_REGCOMP
  	  	    regfree(&preg);
#endif
                    free(mbuf);
		    return(-1);
		  }
		  if (nbuf != mbuf) {
		    for (p=0; p<=nr; p++)  memary[p] += nbuf - mbuf;
		    mbuf = nbuf;
		  }
		}
                strcpy(memary[nr],str);
	        memary[nr+1] = memary[nr] + k;
	        nr++;
	        if (nr >= MAXARGS) {
		  strcpy(outpath,"nr zu gross");
                  errormsg(E_LOGFILE|E_USER,confrecord,"bbs","expandfilenames",
		           msg("expandfilenames",2,confrecord->lang));
#ifndef NO_REGCOMP
	          regfree(&preg);
#endif
                  free(mbuf);
	          return(-1);
	        }
		/* Filename an outpath anhaengen */
	        for (k=0; str[k]!='\0' && opos<maxoutpathlen-2; opos++,k++) {
	          outpath[opos] = str[k];
                }
   	        outpath[opos++] = ' ';
	        outpath[opos] = '\0';
  	        if (opos > maxoutpathlen-2) {
		  strcpy(outpath,"outpath zu klein");
                  errormsg(E_LOGFILE|E_USER,confrecord,"bbs","expandfilenames",
			   msg("expandfilenames",3,confrecord->lang));
#ifndef NO_REGCOMP
	          regfree(&preg);
#endif
                  free(mbuf);
	          return(-1);
	        }	      
	      }			/* if (p...) */
	    }			/* if (S_ISREG...) */
#ifndef NO_REGCOMP
  	    else if (k != REG_NOMATCH) {
	      regerror(k,&preg,outpath,PATH_MAX);
              errormsg(E_LOGFILE|E_USER,confrecord,"bbs","expandfilenames",
		       "regexec: %s",outpath);
	      regfree(&preg);
#else
#ifndef NO_RE_COMP
  	    else if (k < 0) {
              errormsg(E_LOGFILE|E_USER,confrecord,"bbs","expandfilenames",
		       "re_exec: internal error");
#endif
#endif
              free(mbuf);
	      return(-3);
	    }
	  }
	}
      }				/* while ((dirp=...) */
    }				/* if ((dp=...) */
#ifndef NO_REGCOMP
    regfree(&preg);
#endif
  }				/* while(*ipp...) */
  free(mbuf);
  return nr;
}

#endif /* if 0 */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.