
/*
 *  PASSWD.C
 *
 *  (C) Copyright 1989-1990 by Matthew Dillon,  All Rights Reserved.
 *
 */

#include "defs.h"

Prototype void RunPasswdEntry(void);
Prototype void RunPasswdEntryCmd(char *);
Prototype void RunPasswdEntryShell(char *);
Prototype void InteractiveTransfer(long, long, int);
Prototype void SendBreak(int);

#define BTOCP(bp,type)  ((type)((long)bp << 2))
#define SHELL_TIMEOUT	(60 * 10)   /*  10 minutes of idle  */

static struct passwd *Pas;
static char CmdBuf[256];
static char FifoName[256];
static char ScriptFile[256];

long FifoBase;
short RMsgIP;
short WMsgIP;

CheckLoginAndPassword()
{
    Pas = getpwnam(LoginBuf);

    if (Pas == NULL)
	return(0);
    if (strcmp(Pas->pw_passwd, "*") == 0)
	return(1);
    if (strcmp(PasswdBuf, Pas->pw_passwd) == 0)
	return(1);
    return(0);
}

void
RunPasswdEntry()
{
    if (Pas->pw_shell_arg0[0] == '*')
	RunPasswdEntryShell(Pas->pw_shell_arg0 + 1);
    else
	RunPasswdEntryCmd(Pas->pw_shell_arg0);
}

void
RunPasswdEntryCmd(arg0)
char *arg0;
{
    struct Process *proc = (struct Process *)FindTask(NULL);
    APTR oldConsoleTask;
    BPTR oldDir;
    BPTR DirLock;
    char smallBuf[8];

    sprintf(CmdBuf, "%s >null: <null: %s -Getty -DEVICE %s -UNIT %d",
	arg0,
	Pas->pw_shell_argn,
	DeviceName,
	DeviceUnit
    );

    if (BaudReport) {
	strcat(CmdBuf, " -BAUD ");
	sprintf(smallBuf, "%d", BaudRate);
	strcat(CmdBuf, smallBuf);
    }

    if (HardLink)
	strcat(CmdBuf, " -HLINK");

    DirLock = (BPTR)Lock(Pas->pw_dir, SHARED_LOCK);
    if (DirLock)
	oldDir = (BPTR)CurrentDir(DirLock);
    oldConsoleTask = proc->pr_ConsoleTask;

    ulog(1, "Execute %s\n", CmdBuf);

    Execute(CmdBuf, NullFH, NullFH);

    proc->pr_ConsoleTask = oldConsoleTask;
    if (DirLock)
	UnLock(CurrentDir(oldDir));
}

void
RunPasswdEntryShell(arg0)
char *arg0;
{
    long r;
    long mast_r;
    long mast_w;
    int propBreak = 0;
    FILE *fi;

    sprintf(ScriptFile, "T:%s.%s.script", DeviceName, DeviceUnit);
    sprintf(FifoName, "%s.%s", DeviceName, DeviceUnit);

    FifoBase = OpenLibrary(FIFONAME, 0);
    if (!FifoBase) {
	ulog(-1, "Unable to open fifo.library");
	return;
    }

    if (fi = fopen(ScriptFile, "w")) {
	fprintf(fi, "EXECUTE S:Shell-Startup\n");
	fprintf(fi, "FAILAT 99\n");     /*  DOESN'T WORK! */
	fprintf(fi, "CD %s\n", Pas->pw_dir);
	fprintf(fi, "NOREQ\n");
	if (*arg0) {
	    fprintf(fi, "%s %s\n", arg0, Pas->pw_shell_argn);
	    fprintf(fi, "ENDCLI >nil:\n");
	} else {
	    propBreak = 1;
	}
	fclose(fi);
    } else {
	CloseLibrary(FifoBase);
	ulog(-1, "can't create %s", ScriptFile);
	return;
    }

    sprintf(CmdBuf, "NewShell FIFO:%s/rwkecs From %s", FifoName, ScriptFile);
    Execute(CmdBuf, NULL, NULL);
    r = IoErr();
    if (r != 0) {
	CloseLibrary(FifoBase);
	ulog(-1, "Unable to start shell for %s %s", arg0, Pas->pw_shell_argn);
	remove(ScriptFile);
	return;
    }

    /*
     *	master side for shell, transfer serial device data to fifo and
     *	back again until EOF.
     */

    sprintf(CmdBuf, "%s_m", FifoName);
    mast_w = OpenFifo(CmdBuf, 256, FIFOF_WRITE | FIFOF_NORMAL | FIFOF_NBIO);
    sprintf(CmdBuf, "%s_s", FifoName);
    mast_r = OpenFifo(CmdBuf, 256, FIFOF_READ  | FIFOF_NORMAL | FIFOF_NBIO);
    if (mast_w && mast_r)
	InteractiveTransfer(mast_r, mast_w, propBreak);
    if (IoswIP) {
	AbortIO(&Iosw);
	WaitIO(&Iosw);
    }
    if (mast_w)
	CloseFifo(mast_w, FIFOF_EOF);
    if (mast_r)
	CloseFifo(mast_r, FIFOF_EOF);
    CloseLibrary(FifoBase);
    FifoBase = NULL;
    remove(ScriptFile);
}

void
InteractiveTransfer(mast_r, mast_w, propBreak)
long mast_r;
long mast_w;
int propBreak;
{
    Message RMsg;
    Message WMsg;
    short notdone = 1;
    long serWriteLen = 0;
    long idleTimeout = SHELL_TIMEOUT;
    long n;
    char *ptr;

    RMsg.mn_ReplyPort = IoSink;
    WMsg.mn_ReplyPort = IoSink;

    RequestFifo(mast_r, &RMsg, FREQ_RPEND);
    RMsgIP = 1;
    RxStart();
    Timeout(0);

    while (notdone) {
	long mask = Wait(SIGBREAKF_CTRL_C | (1 << IoSink->mp_SigBit));
	Message *msg;

	while (msg = GetMsg(IoSink)) {
	    if (msg == (Message *)&Iosr) {          /*  serial data   */
		IosrIP = 0;
		idleTimeout = SHELL_TIMEOUT;
ser_rretry:
		if (Iosr.IOSer.io_Actual > 0) {
		    if (propBreak) {
			unsigned char c = *(char *)Iosr.IOSer.io_Data;
			if (c < 0x20) {
			    switch(c) {
			    case 3:
			    case 4:
			    case 5:
			    case 6:
				SendBreak(c);
				Iosr.IOSer.io_Data = (APTR)((char *)Iosr.IOSer.io_Data + 1);
				--Iosr.IOSer.io_Actual;
				break;
			    }
			}
		    }
		    n = WriteFifo(mast_w, Iosr.IOSer.io_Data, Iosr.IOSer.io_Actual);
		    if (n != Iosr.IOSer.io_Actual) {
			if (WMsgIP == 0) {
			    RequestFifo(mast_w, &WMsg, FREQ_WAVAIL);
			    WMsgIP = 1;
			}
			continue;
		    }
		}
		RxStart();
	    } else if (msg == (Message *)&Iosw) {
		IoswIP = 0;
		ReadFifo(mast_r, &ptr, serWriteLen);
ser_wretry:
		n = ReadFifo(mast_r, &ptr, 0);
		if (n > 0) {
		    idleTimeout = SHELL_TIMEOUT;
		    Iosw.IOSer.io_Data = (APTR)ptr;
		    Iosw.IOSer.io_Length = n;
		    serWriteLen = n;
		    SendIO(&Iosw);
		    IoswIP = 1;
		}
		if (n < 0)
		    notdone = 0;
		if (RMsgIP == 0) {
		    RequestFifo(mast_r, &RMsg, FREQ_RPEND);
		    RMsgIP = 1;
		}
	    } else if (msg == (Message *)&Iot1) {   /*  carrier check */
		Iot1IP = 0;
		if (GetStatus() & CIAF_COMCD)       /*  lost carrier  */
		    notdone = 0;
		Iot1.tr_time.tv_secs = MainTimeout;
		Iot1.tr_time.tv_micro= 0;
		SendIO(&Iot1);
		Iot1IP = 1;
		idleTimeout -= MainTimeout;
		if (idleTimeout < 0)
		    notdone = 0;
	    } else if (msg == &RMsg) {              /*  <- fifo     */
		RMsgIP = 0;
		if (IoswIP == 0)
		    goto ser_wretry;
	    } else if (msg == &WMsg) {              /*  -> fifo     */
		WMsgIP = 0;
		if (IosrIP == 0)
		    goto ser_rretry;
	    }
	}
    }
    if (RMsgIP) {
	RequestFifo(mast_r, &RMsg, FREQ_ABORT);
	WaitMsg(&RMsg);
	RMsgIP = 0;
    }
    if (WMsgIP) {
	RequestFifo(mast_r, &WMsg, FREQ_ABORT);
	WaitMsg(&WMsg);
	WMsgIP = 0;
    }
}

void
SendBreak(c)
int c;
{
    char buf[256];
    long fh;

    sprintf(buf, "FIFO:%s/%c", FifoName, c | 'A');
    if (fh = Open(buf, 1005))
	Close(fh);
}

