Login.c -- Prompting for username and password with ndialog
Author: orc@pell.chi.il.us

> This code can be called by a login program to get a username and password. It expects that the world has been prepared by an `init_dialog` before it's called, and it leaves it up to the caller to call `end_dialog` when it wants to.

    /*
     * cc -c getuser.o getuser.c
     */
    #include <ndialog.h>
    #include <pwd.h>
    #include <sys/types.h>
    #include <unistd.h>

    #define ESIZE		20
    static char user[ESIZE];
    static char pass[ESIZE];
    static struct passwd *pw;
    static int retries;

    /*
     * pwcallback() is a local function that authenticates the user after they
     * enter a password.
     */
    static int
    pwcallback(void* obj, void* display)
    {
        char *ency;

        if ((pw = getpwnam(user)) != 0) {
    	if (pw->pw_passwd[0] == 0 && pass[0] == 0) {
    	    /* no password, so don't even check */
    	    return -1;
    	}
    	ency = crypt(pass, pw->pw_passwd);
    	memset(pass, 0, ESIZE);

    	if (strcmp(ency, pw->pw_passwd) == 0) {
    	    /* password matched; we can leave now */
    	    return -1;
    	}
        }
        /* complain bitterly and return */
        Error("login incorrect");
        return (--retries >= 0) ? 0 : -1;
    } /* pwcallback */

    /*
     * getuser() asks for a username and password.  If it's given a valid username
     * and password, it returns a pwent for that user, otherwise it spits up a
     * `login incorrect' error box and asks again, up to login_attempts times.
     * After that, it returns 0 and leaves the proper punishment up to the caller.
     */
    struct passwd *
    getuser(int login_attempts)
    {
        int rc;
        void *u_obj, *p_obj, *cancel, *chain;

        /* allocate the display fields */
        u_obj = newString(  0,0, ESIZE, ESIZE, user, 0, "Username", 0, 0);
        p_obj = newPWString(0,3, ESIZE, ESIZE, pass, 0, "Password", pwcallback, 0);
        cancel= newCancelButton(0, "Forget it", 0, 0);
        retries = login_attempts;

        /* build them into a ObjChain */
        chain = ObjChain(ObjChain(u_obj, p_obj), cancel);

        /* get the user input and clean up */
        rc = MENU(chain, -1, -1, 0, "Enter your username and password", 0);
        deleteObjChain(chain);

        /* and return the user info if there is any */
        return (rc == MENU_OK) ? pw : 0;
    } /* getuser */

Written March 1998 by David Parsons