This is do.c in view mode; [Download] [Up]
/* $Id: do.c,v 1.2 1995/12/19 19:30:47 eilts Exp eilts $ */
#include "bbs.h"
#ifdef NNTPNEWS
int do_postart_nntp(const char *groups, const char *subject, const char *refs,
const char *letter, newsstattyp *newsrecord,
const confrecordtyp *confrecord)
{
char astr[ARG_MAX+1], str[STRLEN+1];
boolean deconnect_on_return = FALSE;
newsstattyp newsrec, *newsrecp;
newsrec.is_connected = FALSE;
if (newsrecord != NULL) {
newsrecp = newsrecord;
}
else {
newsrecp = &newsrec;
}
if (checknewsperms(confrecord) < 1) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_nntp",
"You are not allowed to post");
return 0;
}
strcpy(str,confrecord->userrecord.name);
if (strchr(str,'@') == NULL && strchr(str,'!') == NULL) {
strcat(str,"@");
strcat(str,confrecord->hostname);
}
if (*confrecord->userrecord.realname != '\0') {
sprintf(astr,"From: %s <%s>\nNewsgroups: %s\nSubject: %s",
confrecord->userrecord.realname,str,groups,subject);
}
else {
sprintf(astr,"From: %s\nNewsgroups: %s\nSubject: %s",str,groups,subject);
}
if (refs != NULL && *refs != '\0') {
strcat(astr,"\nReferences: ");
strcat(astr,refs);
}
strcat(astr,"\n\n");
if (! newsrecp->is_connected) {
if (nntp_connect(newsrecp,confrecord) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_nntp",
"cannot connect to Newsserver %s",confrecord->nntpserver);
return -1;
}
deconnect_on_return = TRUE;
}
if (nntp_postarticle(astr,letter,newsrecp,confrecord) == OK_POSTED) {
writetouser(confrecord,"article send");
}
else {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_nntp",
"posting failed, got %s",newsrecp->lastretstr);
writetouser(confrecord,"article NOT send");
return -1;
}
if (deconnect_on_return) nntp_close(newsrecp);
return 0;
}
int do_postart_inews(const char *groups, const char *subject, const char *refs,
const char *letter, const confrecordtyp *confrecord)
{
int status, pfds[2], fd, errfd, save_stderr;
PID_T pid;
SIZE_T len;
SSIZE_T bytes;
char astr[ARG_MAX+1], errfile[PATH_MAX+1];
struct stat stats;
if (checknewsperms(confrecord) < 1) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews",
"You are not allowed to post");
return 0;
}
sprintf(errfile,"%s/inews_err.%ld",confrecord->scratchdir,
(long)getpid());
if ((errfd=open(errfile,O_CREAT|O_TRUNC|O_RDWR,0600)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postaricle",
"open %s: %m", errfile);
return -1;
}
unlink(errfile);
if ((fd=open(letter,O_RDONLY)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews",
"open letter %s: %m", letter);
return -1;
}
if (pipe(pfds) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews","pipe: %m");
return -1;
}
if ((pid = fork()) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews","fork: %m");
return -1;
}
if (pid == 0) {
save_stderr = dup(STDERR_FILENO);
dup2(pfds[0],STDIN_FILENO);
close(pfds[1]);
dup2(errfd,STDOUT_FILENO);
dup2(errfd,STDERR_FILENO);
execl(INEWS,"inews: receiving from bbs","-h",(char *)0);
close(errfd);
dup2(STDERR_FILENO,save_stderr);
perror("execv INEWS");
errormsg(E_LOGFILE,confrecord,"bbs","do_postart_inews","execv INEWS: %m");
exit(1);
}
close(pfds[0]);
if (*confrecord->userrecord.realname != '\0') {
sprintf(astr,"From: %s <%s>\nNewsgroups: %s\nSubject: %s",
confrecord->userrecord.realname,confrecord->userrecord.name,
groups,subject);
}
else {
sprintf(astr,"From: %s\nNewsgroups: %s\nSubject:%s",
confrecord->userrecord.name,groups,subject);
}
if (refs != NULL && *refs != '\0') {
strcat(astr,"\nReferences: ");
strcat(astr,refs);
}
strcat(astr,"\n\n");
len = strlen(astr);
if (write(pfds[1],astr,len) != len) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews",
"write (header): %m");
}
else {
bytes = 0;
while (bytes >= 0 &&
(bytes=read(fd,(void *)astr,(SIZE_T)PATH_MAX)) > 0) {
bytes = writen(pfds[1],astr,bytes);
}
}
close(pfds[1]);
close(fd);
while (wait(&status) != pid);
if (fstat(errfd,&stats) == 0 && stats.st_size > 0) {
lseek(errfd,(OFF_T)0,SEEK_SET);
bytes = read(errfd,astr,STRLEN);
astr[bytes] = '\0';
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews",
"inews reports: %s",astr);
}
close(errfd);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
writetouser(confrecord,"article send");
}
else {
if (WIFEXITED(status)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews",
"inews exited with status %d",WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews",
"inews got signal %d",WTERMSIG(status));
if (WCOREDUMP(status)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_postart_inews",
"inews dumped core");
}
}
writetouser(confrecord,"article NOT send");
}
return 0;
}
void do_shownewsheader(const char *header, const confrecordtyp *confrecord)
{
int fd;
char scratch[PATH_MAX+1];
scratchfilename(scratch,"newsheader-",NULL,confrecord->scratchdir);
if ((fd=open(scratch,O_CREAT|O_TRUNC|O_RDWR,0600)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_shownewsheader",
"open %s: %m",scratch);
return;
}
write(fd,header,strlen(header));
close(fd);
do_showfile(scratch,NULL,NULL,NULL,confrecord);
unlink(scratch);
return;
}
#endif
void do_msgbrowser(const char params[], const confrecordtyp *confrecord)
/*
Format fuer params: -a Aktion -n Nummer [-i Message-Id]
Aktion ist R (lesen), D (loeschen), A (beantworten), G (downladen)
*/
{
int nr, lang;
char action, option, msg_id[STRLEN+1], str[STRLEN+1], spath[PATH_MAX+1];
chrootrecordtyp chrootrec;
lang = confrecord->userrecord.lang;
*msg_id = '\0';
nr = -1;
getarg(NULL,params);
while ((option=getarg(str,params)) != '\0') {
switch (option) {
case 'a':
action = *str;
break;
case 'n':
nr = atoi(str);
break;
case 'i':
strmaxcpy(msg_id,str,STRLEN);
break;
default:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_msgbrowser",
"%c: unknown option",option);
return;
}
}
if (nr < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_msgbrowser",
"No message number given");
return;
}
switch (action) {
case 'R':
if (getmessage(spath,nr,msg_id,confrecord) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_msgbrowser",
"message not found");
return;
}
do_showfile(spath,NULL,NULL,NULL,confrecord);
unlink(spath);
break;
case 'D':
if (removemessage(nr,msg_id,confrecord) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_msgbrowser",
"message cannot be removed");
}
break;
case 'A':
/* wird in menue_c erledigt */
break;
case 'G':
if (getmessage(spath,nr,msg_id,confrecord) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_msgbrowser",
"message not found");
return;
}
strcpy(chrootrec.root,"/");
getcwd(chrootrec.cwd,PATH_MAX);
do_get(spath,&chrootrec,protokollnamen,confrecord->userrecord.protokoll,
confrecord);
unlink(spath);
break;
}
return;
}
void do_sendmessage(const char params[], const char *chrootcwd,
const char *chrootdir, const confrecordtyp *confrecord)
/*
Format fuer params: -l letter -s subject -a address
*/
{
char letter[PATH_MAX+1], subject[STRLEN+1], address[ARG_MAX+1],
sender[2*S_STRLEN+4], str[ARG_MAX+1], option;
*letter = '\0';
*subject = '\0';
*address = '\0';
getarg(NULL,params);
while ((option=getarg(str,params)) != '\0') {
switch (option) {
case 'l':
strcpy(letter,str);
break;
case 's':
strcpy(subject,str);
break;
case 'a':
strcpy(address,str);
break;
default:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmessage",
"%c: unknown option",option);
return;
}
}
if (*letter == '\0') {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmessage",
"%s: no letter given",params);
return;
}
if (*address == '\0') {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmessage",
"%s: no address given",params);
return;
}
chrootpath(letter,chrootcwd,confrecord->scratchdir);
if (*subject == '\0') {
strcpy(subject,"no subject given");
}
if (*(confrecord->userrecord.realname)) {
sprintf(sender,"%s <%s>",confrecord->userrecord.realname,
confrecord->userrecord.name);
}
else {
sprintf(sender,"<%s>",confrecord->userrecord.name);
}
if (sendmessage(sender,address,subject,letter,confrecord) == 0) {
writetouser(confrecord,"message send");
}
else {
writetouser(confrecord,"message NOT send");
}
return;
}
int do_sendmail(const char params[], char *letter, const char *chrootcwd,
const char *chrootdir, const confrecordtyp *confrecord)
/*
Format fuer params: -l letter -a address [-s subject]
letter und address duerfen keine Whitespaces beinhalten
*/
{
int n, anz, status, pfds[2], fd, errfd, save_stderr, rw = -1;
PID_T pid;
SIZE_T len;
SSIZE_T bytes;
char *splits[MAXARGS+1], *arg[MAXARGS+1], str[PATH_MAX+2*STRLEN+20],
astr[ARG_MAX+1], address[ARG_MAX+1], subject[STRLEN+1],
errfile[PATH_MAX+1], option;
boolean sendok = FALSE;
struct stat stats;
*letter = '\0';
*address = '\0';
strcpy(subject,"no subject given");
getarg(NULL,params);
while ((option=getarg(str,params)) != '\0') {
switch (option) {
case 'a':
strcpy(address,str);
break;
case 's':
strcpy(subject,str);
break;
case 'l':
strcpy(letter,str);
if (chrootcwd != NULL) {
chrootpath(letter,chrootcwd,confrecord->scratchdir);
}
break;
default:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"%c: unknown option",option);
return -1;
}
}
if (strchr(address,'!') != NULL) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"no '!' in address allowed: %s",address);
return -1;
}
if (*address == '-') {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"no leading '-' in address allowed: %s",address);
return -1;
}
if (strcmp(address,confrecord->sysop) == 0) {
sendok = TRUE;
}
else {
if (checkmailperms(address,confrecord) != 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"You are not allowed to send to this destination");
return -1;
}
else {
sendok = TRUE;
}
}
if (sendok) {
sprintf(errfile,"%s/sendmail_err.%ld",confrecord->scratchdir,
(long)getpid());
if ((errfd=open(errfile,O_CREAT|O_TRUNC|O_RDWR,0600)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"open %s: %m", errfile);
return -1;
}
unlink(errfile);
if ((fd=open(letter,O_RDONLY)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"open letter %s: %m", letter);
return -1;
}
strcpy(astr,address);
anz = splitstring(splits,astr,',',MAXARGS);
arg[0] = "sendmail: receiving from bbs";
for (n=0; n < anz; n++) {
if ((arg[n+1]=(char *)malloc(strlen(splits[n]+1))) == NULL) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail","malloc: %m");
return -1;
}
parseaddrline(arg[n+1],str,splits[n]);
}
arg[n+1] = NULL;
if (pipe(pfds) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail","pipe: %m");
return -1;
}
if ((pid = fork()) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail","fork: %m");
return -1;
}
if (pid == 0) {
save_stderr = dup(STDERR_FILENO);
dup2(pfds[0],STDIN_FILENO);
close(pfds[1]);
dup2(errfd,STDOUT_FILENO);
dup2(errfd,STDERR_FILENO);
execv(SENDMAIL,arg);
close(errfd);
dup2(STDERR_FILENO,save_stderr);
perror("execv INEWS");
errormsg(E_LOGFILE,confrecord,"bbs","do_sendmail","execv SENDMAIL: %m");
exit(1);
}
close(pfds[0]);
if (*confrecord->userrecord.realname != '\0') {
sprintf(str,"From: %s <%s>\nTo: %s\nSubject: %s\n\n",
confrecord->userrecord.realname,
confrecord->userrecord.name,address,subject);
}
else {
sprintf(str,"From: %s\nTo: %s\nSubject: %s\n\n",
confrecord->userrecord.name,address,subject);
}
len = strlen(str);
if (write(pfds[1],str,len) != len) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"write (header): %m");
}
else {
bytes = 0;
while (bytes >= 0 &&
(bytes=read(fd,(void *)str,(SIZE_T)PATH_MAX)) > 0) {
bytes = writen(pfds[1],str,bytes);
}
}
close(pfds[1]);
close(fd);
while (wait(&status) != pid);
for (n=0; n < anz; n++) free(arg[n+1]);
if (fstat(errfd,&stats) == 0 && stats.st_size > 0) {
lseek(errfd,(OFF_T)0,SEEK_SET);
bytes = read(errfd,str,STRLEN);
str[bytes] = '\0';
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"sendmail reports: %s",str);
sendok = FALSE;
}
close(errfd);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
rw = 0;
sendok = TRUE;
}
else {
if (WIFEXITED(status)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"sendmail exited with status %d",WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"sendmail got signal %d",WTERMSIG(status));
if (WCOREDUMP(status)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"sendmail dumped core");
}
}
sendok = FALSE;
}
}
if (sendok) {
writetouser(confrecord,"mail send");
}
else {
writetouser(confrecord,"mail NOT send");
}
return rw;
}
void do_talk(const char params[], const confrecordtyp *confrecord)
{
int n;
if (*params == '\0') return;
n = 0;
n = atoi(params);
if (n < 1) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_talk","wrong pid %s",
params);
return;
}
iniconnecttouser(n,confrecord);
}
void do_sprache(const char params[], const char *sprachennamen[],
confrecordtyp *confrecord)
{
int lang;
char c;
c = params[0];
c = tolower(c);
if (c=='d') {
confrecord->userrecord.lang = GERMAN;
}
else if (c=='e') {
confrecord->userrecord.lang = ENGLISH;
}
lang = confrecord->userrecord.lang;
writetouser(confrecord,msg("do_sprache",0,lang),sprachennamen[lang]);
}
void do_autozmodem(const char params[], confrecordtyp *confrecord)
{
char c;
c = params[0];
c = tolower(c);
if (c=='y' || c=='j') {
confrecord->userrecord.autozmodem = TRUE;
}
else if (c=='n') {
confrecord->userrecord.autozmodem = FALSE;
}
if (confrecord->userrecord.autozmodem) {
writetouser(confrecord,msg("do_autozmodem",0,confrecord->userrecord.lang));
}
else {
writetouser(confrecord,msg("do_autozmodem",1,confrecord->userrecord.lang));
}
}
void do_fullist(const char params[], confrecordtyp *confrecord)
{
char c;
c = params[0];
c = tolower(c);
if (c=='y' || c=='j') {
confrecord->userrecord.fullist_on_cd = TRUE;
}
else if (c=='n') {
confrecord->userrecord.fullist_on_cd = FALSE;
}
if (confrecord->userrecord.fullist_on_cd) {
writetouser(confrecord,msg("do_fullist",0,confrecord->userrecord.lang));
}
else {
writetouser(confrecord,msg("do_fullist",1,confrecord->userrecord.lang));
}
}
void do_cd(const char params[], chrootrecordtyp *chrootrecord,
const confrecordtyp *confrecord)
{
int n;
boolean rootchg = FALSE, cdok = TRUE;
char *args[MAXARGS+1], *spary[MAXARGS+1], str[PATH_MAX+1], str2[PATH_MAX+1],
realpath[PATH_MAX+1], ndir[PATH_MAX+1], oldchrootdir[PATH_MAX+1],
oldrootname[PATH_MAX+1];
strmaxcpy(str,params,PATH_MAX);
splitparams(args,str);
if (args[0]==(char *)NULL) {
strcpy(str,confrecord->userrecord.home);
args[0] = str;
strmaxcpy(chrootrecord->root,chrootrecord->primaryroot,PATH_MAX);
strcpy(chrootrecord->rootname,"/");
chrootpath(args[0],chrootrecord->cwd,chrootrecord->root);
}
else if (strcmp(chrootrecord->root,chrootrecord->primaryroot)!=0 &&
strcmp(chrootrecord->cwd,"/")==0 && strcmp(args[0],"..")==0) {
strcpy(chrootrecord->root,chrootrecord->primaryroot);
strcpy(chrootrecord->rootname,"/");
rootchg = TRUE;
strcpy(args[0],"/");
chrootpath(args[0],chrootrecord->cwd,chrootrecord->root);
}
else {
strmaxcpy(ndir,args[0],PATH_MAX);
chrootpath(args[0],chrootrecord->cwd,chrootrecord->root);
if (access(args[0],F_OK)==0 &&
strcmp(chrootrecord->root,chrootrecord->primaryroot)==0) {
if ((n=readlink(args[0],realpath,PATH_MAX)) > 0) {
realpath[n] = '\0';
if (realpath[0] != '/') {
getcwd(str2,PATH_MAX);
strcat(str2,"/");
strprepend(realpath,str2);
}
if (strstr(realpath,chrootrecord->root) != realpath) {
cdok = FALSE;
strmaxcpy(str2,confrecord->rootdir,PATH_MAX);
splitstring(spary,str2,':',MAXARGS);
for (n=0; spary[n]!=NULL; n++) {
if (strstr(realpath,spary[n]) == realpath) {
cdok = TRUE;
break;
}
}
if (cdok) {
rootchg = TRUE;
strcpy(oldchrootdir,chrootrecord->root);
strcpy(oldrootname,chrootrecord->rootname);
strmaxcat(chrootrecord->rootname,"/",PATH_MAX);
strmaxcat(chrootrecord->rootname,ndir,PATH_MAX);
stripslashes(chrootrecord->rootname);
strmaxcpy(chrootrecord->root,realpath,PATH_MAX);
getrealdir(chrootrecord->root,confrecord);
}
else {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_cd",
msg("do_cd",0,confrecord->userrecord.lang));
}
}
}
}
}
if (cdok && chdir(args[0]) < 0) {
if (rootchg) {
strcpy(chrootrecord->root,oldchrootdir);
strcpy(chrootrecord->rootname,oldrootname);
}
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_cd","chdir %s: %m",
getchrootpath(str,chrootrecord->root));
}
getchrootcwd(chrootrecord);
#ifdef AUTOLISTFILE
if (checkfileperms(AUTOLISTFILE,geteuid(),getegid()) == 0) {
do_showfile(AUTOLISTFILE,NULL,chrootrecord->cwd,chrootrecord->root,
confrecord);
}
#endif
}
void do_get(const char params[], const chrootrecordtyp *chrootrecord,
const char *protokollnamen[], const int protokoll,
const confrecordtyp *confrecord)
{
UID_T euid;
GID_T egid;
int k, p;
char *args[MAXARGS+1], *inargs[MAXARGS+1], *files[MAXARGS+1],
str[ARG_MAX+1], path[PATH_MAX+1], kermrcpath[PATH_MAX+1];
strmaxcpy(str,params,ARG_MAX);
euid = geteuid();
egid = getegid();
bbslogn(LOG_FILE,confrecord,"%s: %s",protokollnamen[protokoll],str);
splitparams(inargs,str);
p = 0;
for (k=0;inargs[k]!=NULL;k++) {
if (*inargs[k]!='-') {
strmaxcpy(path,inargs[k],PATH_MAX);
chrootpath(path,chrootrecord->cwd,chrootrecord->root);
switch (checkfileperms(path,euid,egid)) {
case -EACCES:
case -ENOENT:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_get",
msg("do_get",0,confrecord->userrecord.lang),
getchrootpath(path,chrootrecord->root));
break;
case EFAULT:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_get",
msg("do_get",1,confrecord->userrecord.lang),
getchrootpath(path,chrootrecord->root));
break;
case EACCES:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_get",
msg("do_get",2,confrecord->userrecord.lang),
getchrootpath(path,chrootrecord->root));
break;
default:
files[p] = (char *)malloc((SIZE_T)PATH_MAX);
strcpy(files[p],path);
p++;
}
}
}
files[p] = NULL;
if (p == 0) return;
strcpy(path,".");
chrootpath(path,chrootrecord->cwd,chrootrecord->root);
p = 0;
switch (protokoll) {
case KERMITPROTO:
if ((errno=checkfileperms(confrecord->kermrcpath,euid,egid)) != 0) {
if (errno < 0) errno = -errno;
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_get",
"cannot access kermit configuration file\n%s:\n%m",
confrecord->kermrcpath);
break;
}
args[p++] = "kermit";
args[p++] = "-y";
strcpy(kermrcpath,confrecord->kermrcpath);
args[p++] = kermrcpath;
args[p++] = "-s";
for (k=0;files[k]!=NULL;k++) {
getchrootpath(files[k],path);
args[p++] = &(files[k][1]); /* wegen dem fuehrenden '/' */
}
args[p] = NULL;
execute(KERMIT,args,confrecord->userrecord.loglevel,confrecord);
break;
case ZMODEMPROTO:
args[p++] = "sz";
args[p++] = "-b";
for (k=0;files[k]!=NULL;k++) {
getchrootpath(files[k],path);
args[p++] = &(files[k][1]); /* wegen dem fuehrenden '/' */
}
args[p] = NULL;
execute(SZ,args,confrecord->userrecord.loglevel,confrecord);
break;
}
for (k=0;files[k]!=NULL;k++) {
free((void *)files[k]);
}
}
void do_home(const char params[], const chrootrecordtyp *chrootrecord,
userrecordtyp *userrecord, const confrecordtyp *confrecord)
{
char *args[MAXARGS+1], path[PATH_MAX+1], fullpath[PATH_MAX+1],
wdir[PATH_MAX+1];
strmaxcpy(path,params,PATH_MAX);
splitparams(args,path);
if (args[0]!=(char *)NULL) {
strcpy(fullpath,args[0]);
chrootpath(fullpath,chrootrecord->cwd,chrootrecord->root);
getcwd(wdir,PATH_MAX);
if (chdir(fullpath)<0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_home",
msg("do_home",0,confrecord->lang));
}
else if (userrecord->seclevel == HIGHSECURITY) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_home",
msg("do_home",1,confrecord->lang));
}
else {
mdefenv("HOME",fullpath);
chrootpath(args[0],chrootrecord->cwd,(char *)NULL);
strcpy(userrecord->home,args[0]);
}
chdir(wdir);
}
writetouser(confrecord,"Home: %s\n",userrecord->home);
}
void do_ls(const char params[], const chrootrecordtyp *chrootrecord,
const confrecordtyp *confrecord)
{
UID_T euid;
GID_T egid;
int n, anz;
char *args[MAXARGS+1], dir[PATH_MAX+1], tstr[ASCIITIMESTRLEN],
str[PATH_MAX+1], *sp, *sp2;
DIR *dp;
struct dirent *dirp;
struct stat stats;
tlistetyp *tliste;
strmaxcpy(str,params,PATH_MAX);
anz = splitparams(args,str);
if (anz == 0) {
strcpy(dir,".");
}
else {
strcpy(dir,args[0]);
}
chrootpath(dir,chrootrecord->cwd,chrootrecord->root);
if (stat(dir,&stats) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_ls","stat %s: %m",dir);
return;
}
if (! S_ISDIR(stats.st_mode)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_ls",
"%s is not a directory",dir);
return;
}
if ((dp=opendir(dir)) == NULL) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_ls","opendir %s: %m",dir);
return;
}
euid = geteuid();
egid = getegid();
tliste = (tlistetyp *)0;
/*
addstrtoliste(&tliste,TRUE,0,TL_BLOCKLEN,"",confrecord);
*/
anz = 0;
while ((dirp=readdir(dp)) != NULL) {
if (strcmp(dirp->d_name,".") == 0) continue;
if (strcmp(dirp->d_name,"..") == 0) continue;
if (stat(dirp->d_name,&stats) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_ls","stat %s: %m",
dirp->d_name);
continue;
}
n = getperms(&stats,euid,egid);
if (!(PERM_R & n)) continue;
if (S_ISREG(stats.st_mode)) {
strcpy(tstr,ctime(&(stats.st_mtime)));
tstr[7] = '\0';
tstr[10] = '\0';
tstr[19] = '\0';
tstr[24] = '\0';
sprintf(str,"%s\t%s %s %s %8ld",dirp->d_name,
&(tstr[8]),&(tstr[4]),&(tstr[20]),(long)stats.st_size);
addstrtoliste(&tliste,TRUE,anz,TL_BLOCKLEN,str,confrecord);
anz++;
}
else if (S_ISDIR(stats.st_mode) && (PERM_X & n)) {
strcpy(str,dirp->d_name);
strcat(str,"\t (Directory) ");
addstrtoliste(&tliste,TRUE,anz,TL_BLOCKLEN,str,confrecord);
anz++;
}
else {
continue;
}
}
sortliste(tliste,TL_BLOCKLEN,anz,confrecord);
for (n=0; n<anz; n++) {
readliste(&tliste,FALSE,n,TL_BLOCKLEN,&sp,confrecord);
sp2 = sp;
for (; *sp!='\t'; sp++) ;
*sp++ = '\0';
sprintf(str,"%s %s",sp,sp2);
addstrtoliste(&tliste,TRUE,n,TL_BLOCKLEN,str,confrecord);
}
tlpager(tliste,anz," Datum Bytes Name","dir",confrecord);
removeliste(&tliste,TRUE,TL_BLOCKLEN);
return;
}
void do_protokoll(const char params[], const char *protokollnamen[],
int *protokoll, confrecordtyp *confrecord)
{
char c;
c = params[0];
c = tolower(c);
if (c=='k') {
if (confrecord->userrecord.kermitok) {
*protokoll = KERMITPROTO;
mputenv("PROTOKOLL=KERMIT");
}
else {
writetouser(confrecord,msg("do_protokoll",0,
confrecord->userrecord.lang));
return;
}
}
else if (c=='z') {
*protokoll = ZMODEMPROTO;
mputenv("PROTOKOLL=ZMODEM");
}
confrecord->userrecord.protokoll = *protokoll;
writetouser(confrecord,"Protokoll: %s\n",protokollnamen[*protokoll]);
}
void do_put(const char params[], const chrootrecordtyp *chrootrecord,
const int protokoll, confrecordtyp *confrecord)
{
int p, rw = -1;
char *args[MAXARGS+1], *inargs[MAXARGS+1], str[PATH_MAX+1], path[PATH_MAX+1];
getcwd(path,PATH_MAX);
strmaxcpy(str,confrecord->userrecord.uploaddir,PATH_MAX);
chrootpath(str,chrootrecord->cwd,chrootrecord->root);
if (chdir(str) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_put","chdir %s: %m",
confrecord->userrecord.uploaddir);
return;
}
if (access(".",W_OK) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_put",
msg("do_put",0,confrecord->lang), chrootrecord->cwd);
if (chdir(path) < 0) {
errormsg(E_LOGFILE,confrecord,"bbs","do_put","chdir (r) %s: %m",path);
}
return;
}
strcpy(str,params);
splitparams(inargs,str);
p = 0;
switch (protokoll) {
case KERMITPROTO:
if ((errno=checkfileperms(confrecord->kermrcpath,geteuid(),getegid())) != 0) {
if (errno < 0) errno = -errno;
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_put",
"cannot access kermit configuration file\n%s:\n%m",
confrecord->kermrcpath);
break;
}
args[p++] = "kermit";
args[p++] = "-y";
args[p++] = confrecord->kermrcpath;
args[p++] = "-r";
args[p] = NULL;
rw = execute(KERMIT,args,confrecord->userrecord.loglevel,confrecord);
break;
case ZMODEMPROTO:
args[p++] = "rz";
#ifndef NO_RZ_BFLAG
args[p++] = "-b";
#endif
args[p] = NULL;
rw = execute(RZ,args,confrecord->userrecord.loglevel,confrecord);
break;
}
if (chdir(path) < 0) {
errormsg(E_LOGFILE,confrecord,"bbs","do_put","chdir (r) %s: %m",path);
}
if (rw == 0) {
writetouser(confrecord,msg("do_put",1,confrecord->lang),
confrecord->userrecord.uploaddir);
}
else {
writetouser(confrecord,msg("do_put",2,confrecord->lang),
confrecord->userrecord.uploaddir);
}
return;
}
void do_pwd(const char *chrootcwd, const confrecordtyp *confrecord)
{
writetouser(confrecord,"Directory: %s",chrootcwd);
}
void do_showenv(const userrecordtyp *userrecord,
const confrecordtyp *confrecord)
{
char str[STRLEN+1], str1[STRLEN+1];
sprintf(str1,"Username: %s\n", userrecord->name);
strmaxcpy(str,str1,STRLEN);
sprintf(str1,"Securitylevel: %d\n", userrecord->seclevel);
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Protokoll: %s\n", protokollnamen[userrecord->protokoll]);
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Auto-Z-Modem: %s\n", userrecord->autozmodem ? "on":"off");
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Fullist on cd: %s\n", userrecord->fullist_on_cd ? "yes":"no");
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Home: %s\n", userrecord->home);
strmaxcat(str,str1,STRLEN);
if (strcmp(userrecord->shell,NOSHELL)==0) {
sprintf(str1,"No shell\n");
}
else if (strcmp(userrecord->shell,RESHELL)==0) {
sprintf(str1,"'restricted' shell (%s)\n", RESHELL);
}
else {
sprintf(str1,"Shell: %s\n", userrecord->shell);
}
strmaxcat(str,str1,STRLEN);
if (userrecord->seclevel>=MEDIUMSECURITY) {
sprintf(str1,"Path: %s\n", userrecord->path);
strmaxcat(str,str1,STRLEN);
}
sprintf(str1,"Term: %s\n", userrecord->term);
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Lines: %d\n", userrecord->lines);
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Columns: %d\n", userrecord->columns);
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Charset: %s\n", userrecord->charset);
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Language: %s\n", sprachennamen[userrecord->lang]);
strmaxcat(str,str1,STRLEN);
sprintf(str1,"Permittions: %s\n", userrecord->permittions);
strmaxcat(str,str1,STRLEN);
writetouser(confrecord,str);
}
char do_showfile(const char *filepath, const char *header,
const char *chrootcwd, const char *chrootdir,
const confrecordtyp *confrecord)
{
int fd, pfds[2], maxz, k, offset, zeilen, zstep, lang, cntrlchars, status;
PID_T pid = 0;
SIZE_T len, stsize;
SSIZE_T bytes;
char str[PATH_MAX+1], prompt[S_STRLEN+1], buf[BUFSIZE], *mmp, *cp, key,
cascii;
char cset[] = {SPACE_KEY,BACKSPACE_KEY,DELETE_KEY,QUIT_KEY,'\0'};
char cset2[] = {'Y','J','N','\0'};
struct stat stats;
tlistetyp *tliste;
lang = confrecord->userrecord.lang;
strmaxcpy(str,filepath,PATH_MAX);
if (chrootcwd != NULL) {
chrootpath(str,chrootcwd,chrootdir);
}
switch (checkfileperms(str,geteuid(),getegid())) {
case -EACCES:
case -ENOENT:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
msg("do_showfile",0,lang),filepath);
return '\0';
break;
case EFAULT:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
msg("do_showfile",1,lang),filepath);
return '\0';
break;
case EACCES:
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
msg("do_showfile",2,lang),filepath);
return '\0';
break;
}
#ifdef GUNZIP
len = strlen(str) - 1;
if ((len>2 && str[len]=='z' && str[len-1]=='g' && str[len-2]=='.') ||
(len>1 && str[len]=='Z' && str[len-1]=='.')) {
pipe(pfds);
if ((pid = fork()) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile","fork: %m");
return '\0';
}
if (pid == 0) {
close(pfds[0]);
dup2(pfds[1],STDOUT_FILENO);
execl(GUNZIP,"gunzip","-c",str,(char *)0);
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"execl GUNZIP -c %s: %m",str);
exit(1);
}
close(pfds[1]);
sprintf(str,"%s/gunzip.%ld",confrecord->scratchdir,(long)getpid());
if ((fd=open(str,O_RDWR|O_CREAT|O_EXCL,0600)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"open %s: %m",str);
return '\0';
}
bytes = 0;
while (bytes >= 0 && (bytes=read(pfds[0],(void *)buf,(SIZE_T)BUFSIZE)) > 0) {
bytes = writen(fd,buf,bytes);
}
close(pfds[0]);
close(fd);
while (wait(&status) != pid);
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"gunzip exited with status %d",WEXITSTATUS(status));
}
else if (WIFSIGNALED(status)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"gunzip got signal %d",WTERMSIG(status));
if (WCOREDUMP(status)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_sendmail",
"gunzip dumped core");
}
}
}
#endif
if ((fd=open(str,O_RDONLY)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"open %s: %m",str);
return '\0';
}
if (pid > 0) unlink(str);
if (fstat(fd,&stats) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"fstat %s: %m",str);
return '\0';
}
stsize = stats.st_size;
#ifdef NO_MMAP
# ifdef NeXT
mmp = (char *)0;
if (map_fd(fd,(vm_offset_t)0,(vm_offset_t *)&mmp,TRUE,
(vm_size_t)stsize) != KERN_SUCCESS) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"map_fd: failed");
return '\0';
}
# else
if ((mmp=(char *)malloc(stsize)) == NULL) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"malloc: %m");
return '\0';
}
if (readn(fd,(void *)mmp,stsize) != stsize) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"read %s: %m",str);
return '\0';
}
# endif
#else
if ((mmp=(char *)mmap(0,stsize,PROT_READ,MAP_FILE|MAP_SHARED,fd,0)) == (CADDR_T) -1) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"mmap %s: %m",str);
return '\0';
}
#endif
key = 'N';
for (k=0, cp=mmp, cntrlchars=0; k<stsize; k++) {
if (!(isprint(*cp) || isspace(*cp))) cntrlchars++;
cp++;
}
if (cntrlchars*BINARYFACTOR > stsize) {
key = getkeyonprompt(msg("do_showfile",7,lang),cset2,TRUE,FALSE,
"showfile",confrecord);
}
if (key == 'N') {
cascii = 'U';
if (cntrlchars > 0) {
if (strcmp(confrecord->userrecord.charset,"?") == 0) {
key = getkeyonprompt(msg("do_showfile",8,lang),cset2,TRUE,FALSE,
"showfile",confrecord);
}
if (key == 'J' || key == 'Y' ||
strcasecmp(confrecord->userrecord.charset,"ascii") == 0) {
cascii = 'A';
}
else if (strcasecmp(confrecord->userrecord.charset,"next") == 0) {
cascii = 'N';
}
}
cp = mmp;
tliste = (tlistetyp *)0;
zeilen = 0;
do {
addstrtoliste(&tliste,FALSE,zeilen++,TL_BLOCKLEN,cp,confrecord);
for (k=0; *cp!='\n' && k<COLS && (OFF_T)(cp-mmp)<stsize; cp++) {
k += strlen(recode(str,*cp,cascii));
}
if (*cp=='\n' && (OFF_T)(cp-mmp)<stsize) {
cp++;
}
} while ((OFF_T)(cp-mmp)<stsize);
move(0,0);
clear();
if (header != NULL) {
maxz = confrecord->userrecord.lines - 2;
standout();
addstr_withmargin(header);
standend();
}
else {
maxz = confrecord->userrecord.lines - 1;
}
zstep = maxz - 2;
offset = 0;
do {
if (header != NULL) {
move(1,0);
clrtobot();
}
else {
move(0,0);
clear();
}
for (k=offset; k<offset+maxz && k<zeilen; k++) {
readliste(&tliste,FALSE,k,TL_BLOCKLEN,&cp,confrecord);
linerecodeout(cp,mmp,stsize,cascii,COLS);
}
if (zeilen > maxz) {
if (offset+maxz < zeilen) {
if (offset == 0) {
strcpy(prompt,msg("do_showfile",4,lang));
}
else {
sprintf(prompt,msg("do_showfile",5,lang),offset);
}
}
else {
strcpy(prompt,msg("do_showfile",3,lang));
}
}
else {
strcpy(prompt,msg("do_showfile",6,lang));
}
key = getkeyonprompt(prompt,cset,TRUE,FALSE,"showfile",confrecord);
if (pagerstep(key) < 0) {
offset -= zstep;
}
else if (pagerstep(key) > 0) {
offset += zstep;
}
if (offset > zeilen-maxz) offset = zeilen-maxz;
if (offset < 0) offset = 0;
} while (pagerquit(key) == 0);
removeliste(&tliste,FALSE,TL_BLOCKLEN);
}
#ifdef NO_MMAP
# ifdef NeXT
if (vm_deallocate(task_self(),(vm_address_t)mmp,(vm_size_t)stsize) !=
KERN_SUCCESS) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_showfile",
"vm_deallocate: failed");
}
# else
free(mmp);
# endif
#else
munmap(mmp,stsize);
#endif
close(fd);
return key;
}
int do_term(const char params[], userrecordtyp *userrecord,
confrecordtyp *confrecord)
{
int n;
boolean size_changed=FALSE;
char *args[MAXARGS+1], str[PATH_MAX+1];
#ifdef TIOCGWINSZ
char tgetentbuf[TGETENTBUF];
struct winsize termsize;
#endif
strmaxcpy(str,params,PATH_MAX);
splitparams(args,str);
if (args[0]!=(char *)NULL) {
if (strcmp(args[0],"*")!=0) {
if (! termexists(args[0])) {
errormsg(E_LOGFILE|E_USER|E_CONSOLE,confrecord,NULL,"do_term",
"Terminaltype %s does not exist",args[0]);
return(-1);
}
strmaxcpy(userrecord->term,args[0],S_STRLEN);
mdefenv("TERM",args[0]);
}
if (args[1]!=(char *)NULL) {
if (isdigit(args[1][0])) {
n = atoi(args[1]);
if (n>0 && n<1000) {
userrecord->lines = n;
mdefenv("LINES","%d",n);
size_changed = TRUE;
}
}
if (args[2]!=(char *)NULL) {
if (isdigit(args[2][0])) {
n = atoi(args[2]);
if (n>0 && n<1000) {
userrecord->columns = n;
mdefenv("COLUMNS","%d",n);
size_changed = TRUE;
}
}
}
}
}
if (confrecord->curses_on) {
#ifdef TIOCGWINSZ
if (size_changed) {
ioctl(STDIN_FILENO,TIOCGWINSZ, (char *)&termsize);
termsize.ws_row = userrecord->lines;
termsize.ws_col = userrecord->columns;
ioctl(STDIN_FILENO,TIOCSWINSZ, (char *)&termsize);
tgetent(tgetentbuf,userrecord->term);
endwin();
confrecord->curses_on = FALSE;
window_on(&save_termios,&ttystate,confrecord);
}
#endif
writetouser(confrecord,"Term: %s\nLines: %d\nColumns: %d\nCharset: %s\n",
userrecord->term,userrecord->lines, userrecord->columns,
userrecord->charset);
}
return(0);
}
int do_newpasswd(const char params[], userrecordtyp *userrecord,
const confrecordtyp *confrecord)
{
boolean passwdchanged=FALSE;
char *args[MAXARGS+1], str[S_STRLEN+PASS_MAX+2], salt[9];
userrecordtyp urec;
#ifndef NO_CRYPT
void to64(char *, long, int);
#endif
strmaxcpy(str,params,S_STRLEN+PASS_MAX+1);
if (splitparams(args,str) != 2) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_newpasswd",
"wrong number of args");
return(-1);
}
if (strlen(args[1]) > PASS_MAX) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_newpasswd",
"password too long");
return(-1);
}
if (userrecord->seclevel != HIGHSECURITY) {
#ifndef NO_CRYPT
SRANDOM(time((TIME_T)0));
# ifdef NEWSALT
salt[0] = _PASSWORD_EFMT1;
to64(&salt[1], (long)(29 * 25), 4);
to64(&salt[5], RANDOM(), 4);
# else
to64(&salt[0], RANDOM(), 2);
# endif
#endif
if (strcmp(userrecord->name,args[0]) == 0) {
strmaxcpy(userrecord->passwd,CRYPTFUNC(args[1],salt),PASSCRYPTED_LEN);
saveuserrecord(userrecord,confrecord);
passwdchanged = TRUE;
}
else if (strcmp(userrecord->name,confrecord->sysop) == 0) {
if (! getuserrecord(&urec,args[0],confrecord)) {
errormsg(E_LOGFILE|E_USER,confrecord,"bbs","do_newpasswd",
msg("do_newpasswd",0,userrecord->lang),args[0]);
return(-1);
}
strmaxcpy(urec.passwd,CRYPTFUNC(args[1],salt),PASSCRYPTED_LEN);
saveuserrecord(&urec,confrecord);
passwdchanged = TRUE;
}
}
if (passwdchanged) {
bbslog(LOG_FILE,confrecord,msg("do_newpasswd",1,userrecord->lang),
args[0],userrecord->name);
writetouser(confrecord,msg("do_newpasswd",2,userrecord->lang));
}
else {
writetouser(confrecord,msg("do_newpasswd",3,userrecord->lang));
}
return(0);
}
#ifndef NO_CRYPT
void to64(char *s, long v, int n)
{
static U_CHAR itoa64[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
while (--n >= 0) {
*s++ = itoa64[v&0x3f];
v >>= 6;
}
}
#endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.