#include <stdio.h>
#include <unistd.h>
#include <ctype.h>

#define PASSWD_MAX_TOKEN                100
#define PASSWD_COMMENT_CHAR             '#'
#define PASSWD_SUFFIX_FILE              "/etc/security/passwd.conf"
#define PASSWD_SERVICE_FORMAT           "passwd%s"
#define PASSWD_SERVICE_DEFAULT          "passwd"
#define PASSWD_FAIL_DELAY               2000000 /* usec delay on failure */
#define PASSWD_KEEP_UPTODATE            01
#define PASSWD_SERVICE_SUFFIX           02
#define PASSWD_GARBLED                  04

#define PASSWD_TRUE                     1
#define PASSWD_FALSE                    0

int parse_pass_args(int argc, const char **argv
                      , const char **suffix, const char **user)
{
    int passwd_flags = 0;

    *suffix = *user = NULL;

    while (--argc > 0) {
        if ( (*++argv)[0] == '-' ) {
            switch ((*argv)[1]) {
            case 'k':
                passwd_flags |= PASSWD_KEEP_UPTODATE;
                break;
            case 'N':
                passwd_flags |= PASSWD_SERVICE_SUFFIX;
                *suffix = 2+*argv;
                if (*suffix[0] || (--argc > 0 && (*suffix = *++argv))) {
                    break;
                }
                *suffix = NULL;
                passwd_flags |= PASSWD_GARBLED;
                break;
            default:
                fprintf(stderr,"passwd: unrecognized request; %s\n", argv[0]);
                passwd_flags |= PASSWD_GARBLED;
            }
        } else {
            if (getuid() == 0) {
                *user = *argv;
            } else {
                fprintf(stderr, "passwd: only superuser can give username\n");
                passwd_flags |= PASSWD_GARBLED;
            }
        }
    }

    if ((passwd_flags & PASSWD_GARBLED)) {
        fprintf(stderr, "usage: passwd [-k] [-N\"name\"] [\"username\"]\n"
                "\t-k          - keep non-expired authentication tokens\n"
                "\t              (this option is not supported by PNIAM)\n"
                "\t-N\"name\"    - add suffix \"name\" to PAM service name\n"
                "\t\"username\"  "
                            "- (superuser may) update tokens for named user\n"
            );
        exit(1);
    }

    return passwd_flags;
}
int get_token(FILE *fin, char *buffer)
{
    static int eof=PASSWD_FALSE;
    static int incomment=PASSWD_FALSE;
    int c;

    while (!eof) {
        while ((c = getc(fin)) != EOF && isspace(c)) {
            if (c == '\n')
                incomment = PASSWD_FALSE;
        }

        if (c == EOF) {
            eof = PASSWD_TRUE;
        } else if ( incomment || c == PASSWD_COMMENT_CHAR ) {

            /* c indicates a comment.. */
            while ((c = getc(fin)) != EOF && c != '\n');
            incomment = PASSWD_FALSE;
            if (c == EOF)
                eof = PASSWD_TRUE;

        } else {                                      /* this is a token */
            int i=0;
            while (i<PASSWD_MAX_TOKEN-1 && c != EOF
                   && !isspace(c) && c != PASSWD_COMMENT_CHAR) {
                buffer[i++] = c;
                c = getc(fin);
            }
            buffer[i] = '\0';                         /* <NUL> terminate */
            if (c == EOF)
                eof = PASSWD_TRUE;
            else if (c == PASSWD_COMMENT_CHAR) {
                incomment = PASSWD_TRUE;
            }
            return PASSWD_TRUE;
        }
    }

    return PASSWD_FALSE;
}

int service_ok(const char *suffix)
{
    char buffer[PASSWD_MAX_TOKEN];
    FILE *fin;
    int retval = PASSWD_FALSE;
    fin = fopen(PASSWD_SUFFIX_FILE, "r");
    if (fin == NULL) {
        return PASSWD_FALSE;
    }

    while (get_token(fin, buffer)) {
        if (!strcmp(suffix, buffer)) 
            retval = PASSWD_TRUE;
    }
    fclose(fin);

    return retval;
}
