/*
 * Copyright (c) 1990,1993 Regents of The University of Michigan.
 * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
 * All Rights Reserved.  See COPYRIGHT.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <atalk/afp.h>
#include <atalk/compat.h>
#include <atalk/logger.h>
#include <atalk/uam.h>
#include <atalk/util.h>

/*XXX in etc/papd/file.h */
struct papfile;
extern UAM_MODULE_EXPORT void append(struct papfile *, const char *, int);

/*! login and login_ext are almost the same */
static int noauth_login(void *obj, struct passwd **uam_pwd,
                        char *ibuf _U_, size_t ibuflen _U_,
                        char *rbuf _U_, size_t *rbuflen)
{
    struct passwd *pwent;
    char *guest, *username;
    *rbuflen = 0;
    LOG(log_info, logtype_uams, "login noauth");

    if (uam_afpserver_option(obj, UAM_OPTION_GUEST, (void *) &guest,
                             NULL) < 0) {
        return AFPERR_MISC;
    }

    if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
                             (void *) &username, NULL) < 0) {
        return AFPERR_MISC;
    }

    strcpy(username, guest);

    if ((pwent = getpwnam(guest)) == NULL) {
        LOG(log_error, logtype_uams, "noauth_login: getpwnam( %s ): %s",
            guest, strerror(errno));
        return AFPERR_BADUAM;
    }

    *uam_pwd = pwent;
    return AFP_OK;
}

static int noauth_login_ext(void *obj, char *uname _U_, struct passwd **uam_pwd,
                            char *ibuf, size_t ibuflen,
                            char *rbuf, size_t *rbuflen)
{
    return noauth_login(obj, uam_pwd, ibuf, ibuflen, rbuf, rbuflen);
}


/*! Printer NoAuthUAM Login */
static int noauth_printer(char *start, char *stop, char *username,
                          struct papfile *out)
{
    char	*data, *p, *q;
    static const char *loginok = "0\r";
    data = (char *)malloc(stop - start + 1);

    if (!data) {
        LOG(log_info, logtype_uams, "Bad Login NoAuthUAM: malloc");
        return -1;
    }

    strlcpy(data, start, stop - start + 1);

    /* We are looking for the following format in data:
     * (username)
     *
     * Hopefully username doesn't contain a ")"
     */

    if ((p = strchr(data, '(')) == NULL) {
        LOG(log_info, logtype_uams,
            "Bad Login NoAuthUAM: username not found in string");
        free(data);
        return -1;
    }

    p++;

    if ((q = strchr(p, ')')) == NULL) {
        LOG(log_info, logtype_uams,
            "Bad Login NoAuthUAM: username not found in string");
        free(data);
        return -1;
    }

    memcpy(username, p,  MIN(UAM_USERNAMELEN, q - p));
    /* Done copying username, clean up */
    free(data);

    if (getpwnam(username) == NULL) {
        LOG(log_info, logtype_uams, "Bad Login NoAuthUAM: %s: %s",
            username, strerror(errno));
        return -1;
    }

    /* Login successful */
    append(out, loginok, strlen(loginok));
    LOG(log_info, logtype_uams, "Login NoAuthUAM: %s", username);
    return 0;
}


static int uam_setup(void *handle, const char *path)
{
    if (uam_register(UAM_SERVER_LOGIN_EXT, path, "No User Authent",
                     noauth_login, NULL, NULL, noauth_login_ext) < 0) {
        return -1;
    }

    if (uam_register(UAM_SERVER_PRINTAUTH, path, "NoAuthUAM",
                     noauth_printer) < 0) {
        return -1;
    }

    return 0;
}

static void uam_cleanup(void)
{
    uam_unregister(UAM_SERVER_LOGIN, "No User Authent");
    uam_unregister(UAM_SERVER_PRINTAUTH, "NoAuthUAM");
}

UAM_MODULE_EXPORT struct uam_export uams_guest = {
    UAM_MODULE_SERVER,
    UAM_MODULE_VERSION,
    uam_setup, uam_cleanup
};
