/* $Cambridge: hermes/src/prayer/accountd/password.c,v 1.3 2008/09/16 09:59:54 dpc22 Exp $ */
/************************************************
 *    Prayer - a Webmail Interface              *
 ************************************************/

/* Copyright (c) University of Cambridge 2000 - 2002 */
/* See the file NOTICE for conditions of use and distribution. */

#include "accountd.h"

/* password_change_internal() *********************************************
 *
 * Change passwd using the passwd program
 *  config: Accountd configuration
 *     old: Old password
 *     new: New password
 *
 * Returns: Error response from passwd program. NIL => okay
 ************************************************************************/

static char *password_change_internal(struct config *config, char *old,
                                      char *new)
{
    struct pool *pool = pool_create(0);
    struct assoc *h = assoc_create(pool, 16, T);
    struct process process;
    char *msg;
    char *cmdline;

    assoc_update(h, "old", old, T);
    assoc_update(h, "new", new, T);

    /* Expand */
    cmdline = string_expand(pool, h, config->pwd_cmdline);

    process_clear(&process);

    if (!process_start(&process, cmdline,
                       config->pwd_pty, config->child_timeout)) {
        pool_free(pool);
        return ("Couldn't start the password program");
    }

    msg = process_run_script(&process, pool, h,
                             pool_strdup(pool, config->pwd_script), NIL,
                             0L);

    if (!process_stop(&process)) {
        pool_free(pool);
        return ("Error code from password program");
    }

    pool_free(pool);
    return (msg);
}


/* password_change() *****************************************************
 *
 * Change passwd using the passwd program
 *  config: Accountd configuration
 *  stream: iostream connection to client
 *      line: Arguments for PASSWORD command.
 *            Should be old password, then new password canon encoded
 *
 * Returns: T in all situations
 *   OK [text]. Password changed
 *   NO [text]. Failed to change password
 *  BAD [text]. Protocol error
 ************************************************************************/

BOOL
password_change(struct config * config, struct iostream * stream,
                char *line)
{
    char *old, *new;
    char *errmsg;

    if (!((old = string_get_token(&line)) && (old[0]))) {
        ioputs(stream, "BAD No old password" CRLF);
        ioflush(stream);
        return (T);
    }

    string_canon_decode(old);

    if (!((new = string_get_token(&line)) && (new[0]))) {
        ioputs(stream, "BAD No new password" CRLF);
        ioflush(stream);
        return (T);
    }

    string_canon_decode(new);

    if (!(errmsg = password_change_internal(config, old, new)))
        ioprintf(stream, "OK Changed password" CRLF);
    else if (errmsg[0])
        ioprintf(stream, "NO %s" CRLF, errmsg);
    else
        ioprintf(stream, "NO Failed to change password" CRLF);
    ioflush(stream);
    return (T);
}
