/* The Macintosh POPmail client Eudora offers a possibility to perform the POP and SMTP conversations over a serial (dialup) connection. Therefore is needed a 'psuedo-account' on a machine where Eudora can login. That account must have permission to execute senndmail and popper, not only local but also remote (via rsh) on all machines where a popserver or smtpserver must be contacted. Eudora is secretive with the password while showing its progress (if properly configured), but nobody can prevent a curious Macontosh owner from looking with ResEdit (or alike's). It can be a security leak. This program srialpop is written to take care of these trade off's. It must be used as the pseudo-account's loginshell. The commands which are recognized by the program are 'logout' and 'exit' (to finish the session of course) and 'telnet ...' which performs a TCP/IP connection with the indicated host/port. The supplied portnumber is checked against a list of valid portnumbers (now only POP and SMTP). All other commands cause an exit with errormessage. So the pseudo-account doesn't need permissions to run popper and sendmail, neither needed are permissions to run rsh to another machine or let another machine rsh in. And a diligent user (Macintosh owner) who tries to login on the psuedo-account will discover that there is no fun. The program is straightforward and rather simple, and it is free. Yet I claim a copyright, with which I mean that anybody who feels a need to change (parts of) this program is under the obligation to document the changes and the need thereof in the program distribution files. Neither may this program be selled (as if anybody would buy this gadget), or distributed for a fee that extends a reasonable retribution for the 8k it occupies on disk or other media (I don't ask money, why should you). I have tested the program for some time now and found no bugs/problems. That doeesn't mean of course there are not. I offer this program free for everyone to use because I think it can be useful and is less dangerous then the shellscript suggested by Steve Dorner. But if you stumble over an error I am in no way responsible for the damage that can cause, however I don't expect disasters. I should welcome (by email) any notification of changes, corrections and enhancements in the form of the new program source or a diff. Rudi van Houten Ac.Comp.Centr.Utrecht Budapestlaan 6 3584 CD Utrecht Netherlands Known bugs: I found none. How to compile: On BSD-4.2 (4.3) it can be compiled without any defines. On System V (also HP/UX) the symbol SYSV must be defined. It is tested on the following configurations: Convex C220 (OS-9.1) compilation: 'cc -O -pcc' Sun-Sparcstation-330 (OS 4.1) compilation: 'cc -O' HP9000-832: compilation: 'cc -O -DSYSV' P9070 (Philips, an M68030 with SysV R3): compilation: 'cc -O -DSYSV' History: 9 dec 91 original version, only installed at ACCU The distribution contains one file 'srialpop.c' 11 dec 91 some changes in IO-handling after Steve Dorner viewed the program and made some sugeestions */ #ifdef SYSV #include #define bcopy(a,b,c) memcpy(b,a,c) #endif #include #include #include #include #include #include #include #include #define iBuflen 512 static char sBuf[iBuflen]; static short iValidPort[]= {25 /* SMTP */ ,109 /* POP2 */ ,110 /* POP3 */ }; #define iValidPortsCount sizeof(iValidPort)/sizeof(short) void errorexit(sFormat,uPar) char * sFormat; unsigned int uPar; { close(0); fprintf(stderr,sFormat,uPar); sleep(1); exit(1); } /* errorexit */ main() { int iSock, iPort, iChild; register int i, l; struct in_addr sInAddr; struct sockaddr_in sServer; struct hostent *psHost, *gethostbyname(), *gethostbyaddr(); struct sgttyb sTermHold, sTermCurr; char *psCommand, *psName, *psNumber; /* get stty structure sTermHold */ ioctl(0,TIOCGETP,&sTermHold); /* this is the main loop, it reads the telnet or exit commandline */ while (write(1,"%",1), (l= read(0,sBuf,iBuflen)) > 0) { if (sBuf[i= l - 1] == '\n') sBuf[l= i]= '\0'; if (l == 0) continue; if (strcmp(sBuf,"logout") == 0 || strcmp(sBuf,"exit") == 0) break; /* finished, logout now */ i= 0; psCommand= psName= psNumber= NULL; while (i < l && psNumber == NULL) { while (sBuf[i] == ' ' || sBuf[i] == '\t') i++; if (i >= l) break; if (psCommand == NULL) psCommand= &sBuf[i]; else if (psName == NULL) psName= &sBuf[i]; else psNumber= &sBuf[i]; do { i++; } while (sBuf[i] != ' ' && sBuf[i] != '\t' && i < l); sBuf[i++]= '\0'; } if (strcmp(psCommand,"telnet")) errorexit("Sorry, don't know '%s'\n",psCommand); if (psName == NULL || psNumber == NULL) errorexit("Sorry, hostname or portnumber missing\n",0); if (l= strlen(psNumber)) { for (i= 0; i < l; i++) if (!isdigit(psNumber[i])) errorexit("Portnumber (%s) not numeric\n",psNumber); iPort= atoi(psNumber); } else iPort= 0; for (i=0; iPort != iValidPort[i]; i++) if (i == iValidPortsCount) errorexit("Sorry, %d is not a valid port\n",iPort); /* (unsigned long)(-1) = 0xffffffff, returnvalue from inet_addr() if illegal address passed through. I assume then it is a domain name. Thanks to Edwin Kremer (edwin@cs.ruu.nl) for the trick */ if ((sInAddr.s_addr= inet_addr(psName)) == 0xffffffff) psHost= gethostbyname(psName); else psHost= gethostbyaddr((char*)&sInAddr,sizeof(struct in_addr),AF_INET); if( psHost == 0) errorexit("Cannot find server %s (host unknown)\n",psName); /* create socket */ if ((iSock= socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("Cannot open IP socket"); exit(1); } /* fill socket structure .....*/ sServer.sin_family= AF_INET; bcopy(psHost->h_addr,&sServer.sin_addr,psHost->h_length); sServer.sin_port= htons(iPort); /*........and connect */ if (connect(iSock,&sServer,sizeof(sServer)) < 0) { perror("connecting stream socket"); exit(1); } bcopy(&sTermHold,&sTermCurr,sizeof(struct sgttyb)); sTermCurr.sg_flags &= ~(ECHO | CRMOD); /* I don't see why raw mode is needed if (iPort == 25) sTermCurr.sg_flags |= RAW; */ ioctl(0,TIOCSETP,&sTermCurr); /* now fork a child to copy stdin to socket */ iChild= fork(); if (iChild < 0) { perror("Cannot fork"); exit(1); } if (iChild == 0) { /* the child copies stdin to the socket */ while ((l= read(0,sBuf,iBuflen)) > 0) write(iSock,sBuf,l); close(0); exit(0); } else /* if (iChild == 0) */ /* the parent copies the socket to stdout */ while ((l= read(iSock,sBuf,iBuflen)) > 0) write(1,sBuf,l); close(iSock); ioctl(0,TIOCSETP,&sTermHold); kill(iChild,SIGTERM); } /* main loop: while (write(1,"%",1), gets(sBuf) != NULL) */ close(0); close(1); close(2); exit(0); } /* main */