[Coco] Uemacs

Jeff Teunissen deek at d2dc.net
Tue Feb 15 13:25:28 EST 2022


On Mon, Feb 14, 2022 at 7:56 PM Bill Gunshannon
<bill.gunshannon at hotmail.com> wrote:
>
> On 2/13/22 21:24, Jeff Teunissen wrote:
> > On Fri, Feb 11, 2022 at 12:42 PM Bill Gunshannon
[snip]

> > Huh, that's interesting. In that case, I wonder why it's broken.
>
> Didn't really take the time to look. Would rather figure out what
> it does and re-write it in C.  :-)

Here's my version. It requires the DCC compiler instead of the classic
Microware compiler, because it uses unsigned char and some C++-style
comments, but it does build on a CoCo. :)

----->8----- cut here -----8<-----
#include <stdio.h>
#include <fcntl.h>

#include <time.h>
#include <sgstat.h>
#include <signal.h>
#include <password.h>

direct char    namebuf[PWNSIZ];
direct char    passbuf[PWPSIZ];

#define LOGIN_RETRIES 3
#define FAIL_DELAY 2

#define prompt(x) \
    writeln (STDOUT_FILENO, x, sizeof (x) - 1)

/*
    These arrays cause the program to use slightly more memory than using
    pointers to constant strings, but they allow us to use 'sizeof' to get
    their lengths instead of 'strlen', which means no math being done at
    run-time.
*/
char LogPrompt[] = "Login: ";
char PassPrompt[] = "Password: ";

char NoPass[] = "Login incorrect\n";
char Bye[] = "Goodbye.\n";

char NewLine[] = "\n";

char Sorry[] = "can't open password file.\n";
char Dir[] = "can't find home directory; will use current.\n";
char XDir[] = "can't find exec directory; will use current.\n";

direct char saved = 0;
direct struct sgbuf savedSet, newSet;

direct char *username = NULL;

direct char motdbuf[120];    /* Buffer for message of the day */

trylogin();
chaincmd();
getstr();


trap(sig)
{
    rstEcho();
    exit(sig);
}


noEcho()
{
    if (!saved && -1 != _gs_opt (STDIN_FILENO, &savedSet)) {
        unsigned char    i;
        unsigned char    *old = (char *)&savedSet;
        register unsigned char *new = (char *)&newSet;

        for (i = 0; i < sizeof (struct sgbuf); i++)
            *new++ = *old++;

        newSet.sg_echo = 0;

        saved = 1;
    }

    _ss_opt (STDIN_FILENO, &newSet);
}


rstEcho()
{
    if (saved) _ss_opt (STDIN_FILENO, &savedSet);
}


getuser()
{
    prompt (LogPrompt);
    getstr (namebuf, sizeof (namebuf) - 1);
    if (*namebuf)
        return namebuf;

    return NULL;
}


getstr(buf, siz)
char    buf[];
int        siz;
{
    register char *i = buf;

    readln (STDIN_FILENO, buf, siz);

    while (*i && *i != '\n')
        ++i;
    *i = '\0';
}


getpass()
{
    noEcho();
    prompt (PassPrompt);
    getstr (passbuf, sizeof (passbuf) - 1);
    prompt (NewLine);
    rstEcho();

    return passbuf;
}


main (argc, argv)
int        argc;
char    **argv;
{
    register int    i;

    intercept (trap);
    asetuid (0);        // We're gonna need to be root a lot

    if (argc > 1) {        /* called with username, prefill it once */
        username = argv[1];
    } else {            /* No username, print banner */
        int    fd;

        if (-1 != (fd = open ("/DD/SYS/banner", O_RDONLY))) {
            while (readln (fd, motdbuf, sizeof (motdbuf)))
                writeln (STDOUT_FILENO, motdbuf, sizeof (motdbuf));

            close (fd);
        }
    }

    for (i = 0; i < LOGIN_RETRIES; i++) {
        trylogin (username);
        // if we even get here, it's a failure
        sleep (FAIL_DELAY);
        prompt (NoPass);
        username = NULL;
    }
    prompt (Bye);
    exit (1);
}


trylogin(name)
char    *name;
{
    register PWENT    *entry;
    char    *pass;
    int        fd;

    if ((!name || !*name) && !(name = getuser()))
        return;

    if (!(pass = getpass()))
        return;

    if (entry = getpwnam (name)) {
        if (*(entry->upw) == '*' || strucmp (pass, entry->upw))
            goto done;

        /* matched */
        setpr (getpid (), atoi (entry->upri));    // set priority, user inherits

        setuid (atoi (entry->uid));    // set new uid

        if (-1 == chdir (entry->udat))
            prompt (Dir);

        if (-1 == chxdir(entry->ucmd))
            prompt (XDir);

        /* Print MOTD */
        if (-1 != (fd = open ("/DD/SYS/motd", O_RDONLY))) {
            while (readln (fd, motdbuf, sizeof (motdbuf)))
                writeln (STDOUT_FILENO, motdbuf, sizeof (motdbuf));
            close (fd);
        }

        chaincmd (entry->ujob);
        exit (1);
    }
done:;
    endpwent();
}


chaincmd (cmd)
char *cmd;
{
    char            buf[80];
    char            *args;
    register char    *tmp = buf;

    /* First, fill buf from cmd */
    while (*cmd)
        *tmp++ = *cmd++;    // poor man's strcpy
    *tmp = '\0';

    /* Now, terminate the "program' at the first space */
    tmp = buf;                // back to the beginning
    while (*++tmp != ' ') ;    // find the first space
    *tmp++ = '\0';            // turn it into a nul
    args = tmp;

    /*
     * now args points at the start of the arguments, but it needs to end
     * with a newline, not a nul...
     */
    while (*++tmp) ;    // point tmp at the NUL at the end
    *tmp++ = '\n';
    *tmp = '\0';
    /*
     * By happy accident, the difference between tmp and args should now be
     * exactly the length of the parameters, so _again_ we don't need strlen.
     */
    chain (buf, tmp - args, args, 1, 1, 0);
}


More information about the Coco mailing list