root/usr/src/lib/pam_modules/authtok_check/packlib.c
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Copyright (c) 2018, Joyent, Inc.
 */

/*
 * This program is copyright Alec Muffett 1993. The author disclaims all
 * responsibility or liability with respect to it's usage or its effect
 * upon hardware or computer systems, and maintains copyright as set out
 * in the "LICENCE" document which accompanies distributions of Crack v4.0
 * and upwards.
 */

#include "packer.h"

void
PWRemove(char *path)
{
        char fname[PATH_MAX];

        (void) snprintf(fname, sizeof (fname), "%s/%s", path,
            DICT_DATABASE_PWI);
        (void) unlink(fname);
        (void) snprintf(fname, sizeof (fname), "%s/%s", path,
            DICT_DATABASE_PWD);
        (void) unlink(fname);
        (void) snprintf(fname, sizeof (fname), "%s/%s", path,
            DICT_DATABASE_HWM);
        (void) unlink(fname);
}

PWDICT *
PWOpen(char *path, char *mode)
{
        PWDICT *pdesc;
        char iname[PATH_MAX];
        char dname[PATH_MAX];
        char wname[PATH_MAX];
        int fd_d;
        int fd_i;
        int fd_w;
        FILE *dfp;
        FILE *ifp;
        FILE *wfp;

        if ((pdesc = calloc(1, sizeof (PWDICT))) == NULL)
                return ((PWDICT *) 0);

        if (pdesc->header.pih_magic == PIH_MAGIC) {
                return ((PWDICT *) 0);
        }
        (void) memset(pdesc, '\0', sizeof (pdesc));

        (void) snprintf(iname, sizeof (iname), "%s/%s", path,
            DICT_DATABASE_PWI);
        (void) snprintf(dname, sizeof (dname), "%s/%s", path,
            DICT_DATABASE_PWD);
        (void) snprintf(wname, sizeof (wname), "%s/%s", path,
            DICT_DATABASE_HWM);

        if ((fd_d = open(dname, O_RDWR|O_CREAT, 0600)) == -1)
                syslog(LOG_ERR, "PWopen: can't open %s: %s", dname,
                    strerror(errno));
        if ((fd_i = open(iname, O_RDWR|O_CREAT, 0600)) == -1)
                syslog(LOG_ERR, "PWopen: can't open %s: %s", iname,
                    strerror(errno));
        if ((fd_w = open(wname, O_RDWR|O_CREAT, 0600)) == -1)
                syslog(LOG_ERR, "PWopen: can't open %s: %s", wname,
                    strerror(errno));

        if (!(pdesc->dfp = fdopen(fd_d, mode))) {
                return ((PWDICT *) 0);
        }

        if (!(pdesc->ifp = fdopen(fd_i, mode))) {
                (void) fclose(pdesc->dfp);
                return ((PWDICT *) 0);
        }

        if (pdesc->wfp = fdopen(fd_w, mode)) {
                pdesc->flags |= PFOR_USEHWMS;
        }

        ifp = pdesc->ifp;
        dfp = pdesc->dfp;
        wfp = pdesc->wfp;

        if (mode[0] == 'w') {
                pdesc->flags |= PFOR_WRITE;
                pdesc->header.pih_magic = PIH_MAGIC;
                pdesc->header.pih_blocklen = NUMWORDS;
                pdesc->header.pih_numwords = 0;

                (void) fwrite((char *)&(pdesc->header), sizeof (pdesc->header),
                    1, ifp);
        } else {
                pdesc->flags &= ~PFOR_WRITE;

                if (!fread((char *)&(pdesc->header), sizeof (pdesc->header),
                    1, ifp)) {
                        pdesc->header.pih_magic = 0;
                        (void) fclose(ifp);
                        (void) fclose(dfp);
                        return ((PWDICT *) 0);
                }

                if (pdesc->header.pih_magic != PIH_MAGIC) {
                        pdesc->header.pih_magic = 0;
                        (void) fclose(ifp);
                        (void) fclose(dfp);
                        return ((PWDICT *) 0);
                }

                if (pdesc->header.pih_blocklen != NUMWORDS) {
                        pdesc->header.pih_magic = 0;
                        (void) fclose(ifp);
                        (void) fclose(dfp);
                        return ((PWDICT *) 0);
                }

                if (pdesc->flags & PFOR_USEHWMS) {
                        if (fread(pdesc->hwms, 1, sizeof (pdesc->hwms), wfp) !=
                            sizeof (pdesc->hwms)) {
                                pdesc->flags &= ~PFOR_USEHWMS;
                        }
                }
        }
        return (pdesc);
}

int
PWClose(PWDICT *pwp)
{
        if (pwp->header.pih_magic != PIH_MAGIC) {
                return (-1);
        }

        if (pwp->flags & PFOR_WRITE) {
                pwp->flags |= PFOR_FLUSH;
                (void) PutPW(pwp, (char *)0);   /* flush last index if necess */

                if (fseek(pwp->ifp, 0L, 0)) {
                        return (-1);
                }

                if (!fwrite((char *)&pwp->header, sizeof (pwp->header),
                    1, pwp->ifp)) {
                        return (-1);
                }

                if (pwp->flags & PFOR_USEHWMS) {
                        int i;
                        for (i = 1; i <= 0xff; i++) {
                                if (!pwp->hwms[i]) {
                                        pwp->hwms[i] = pwp->hwms[i-1];
                                }
                        }
                        (void) fwrite(pwp->hwms, 1, sizeof (pwp->hwms),
                            pwp->wfp);
                }
        }

        (void) fclose(pwp->ifp);
        (void) fclose(pwp->dfp);
        (void) fclose(pwp->wfp);

        pwp->header.pih_magic = 0;

        free(pwp);

        return (0);
}

int
PutPW(PWDICT *pwp, char *string)
{
        if (!(pwp->flags & PFOR_WRITE)) {
                return (-1);
        }

        if (string) {
                (void) strncpy(pwp->data[pwp->count], string, MAXWORDLEN);
                pwp->data[pwp->count][MAXWORDLEN - 1] = '\0';

                pwp->hwms[string[0] & 0xff] = pwp->header.pih_numwords;

                ++(pwp->count);
                ++(pwp->header.pih_numwords);

        } else if (!(pwp->flags & PFOR_FLUSH)) {
                return (-1);
        }

        if ((pwp->flags & PFOR_FLUSH) || !(pwp->count % NUMWORDS)) {
                int i;
                uint32_t datum;
                register char *ostr;

                datum = (uint32_t)ftell(pwp->dfp);

                (void) fwrite((char *)&datum, sizeof (datum), 1, pwp->ifp);

                (void) fputs(pwp->data[0], pwp->dfp);
                (void) putc(0, pwp->dfp);

                ostr = pwp->data[0];

                for (i = 1; i < NUMWORDS; i++) {
                        register int j;
                        register char *nstr;

                        nstr = pwp->data[i];

                        if (nstr[0]) {
                                for (j = 0; ostr[j] && nstr[j] &&
                                    (ostr[j] == nstr[j]); j++)
                                        ;
                                (void) putc(j & 0xff, pwp->dfp);
                                (void) fputs(nstr + j, pwp->dfp);
                        }
                        (void) putc(0, pwp->dfp);

                        ostr = nstr;
                }

                (void) memset(pwp->data, '\0', sizeof (pwp->data));
                pwp->count = 0;
        }
        return (0);
}

char *
GetPW(PWDICT *pwp, uint32_t number)
{
        uint32_t datum;
        register int i;
        register char *ostr;
        register char *nstr;
        register char *bptr;
        char buffer[NUMWORDS * MAXWORDLEN];
        static char data[NUMWORDS][MAXWORDLEN];
        static uint32_t prevblock = 0xffffffff;
        uint32_t thisblock;

        thisblock = number / NUMWORDS;

        if (prevblock == thisblock) {
                return (data[number % NUMWORDS]);
        }

        if (fseek(pwp->ifp, sizeof (struct pi_header) +
            (thisblock * sizeof (uint32_t)), 0)) {
                return (NULL);
        }

        if (!fread((char *)&datum, sizeof (datum), 1, pwp->ifp)) {
                return (NULL);
        }

        if (fseek(pwp->dfp, datum, 0)) {
                return (NULL);
        }

        if (!fread(buffer, 1, sizeof (buffer), pwp->dfp)) {
                return (NULL);
        }

        prevblock = thisblock;

        bptr = buffer;

        for (ostr = data[0]; *(ostr++) = *(bptr++); /* nothing */)
                ;

        ostr = data[0];

        for (i = 1; i < NUMWORDS; i++) {
                nstr = data[i];
                (void) strcpy(nstr, ostr);
                ostr = nstr + *(bptr++);
                while (*(ostr++) = *(bptr++))
                        ;

                ostr = nstr;
        }

        return (data[number % NUMWORDS]);
}

uint32_t
FindPW(PWDICT *pwp, char *string)
{
        int lwm;
        int hwm;
        int idx;

        if (string == NULL)
                return (PW_WORDS(pwp));

        if (pwp->flags & PFOR_USEHWMS) {
                idx = string[0] & 0xff;
                lwm = idx ? pwp->hwms[idx - 1] : 0;
                hwm = pwp->hwms[idx];
        } else {
                lwm = 0;
                hwm = PW_WORDS(pwp) - 1;
        }

        for (;;) {
                int cmp;
                int pivot;
                char *this;

                pivot = lwm + ((hwm+1)-lwm)/2;

                if (feof(pwp->ifp) && feof(pwp->dfp) && feof(pwp->wfp))
                        break;

                if ((this = GetPW(pwp, pivot)) == NULL)
                        break;

                cmp = strcmp(string, this);             /* INLINE ? */

                if (cmp == 0)
                        return (pivot);
                else if (cmp < 0)
                        hwm = pivot-1;
                else
                        lwm = pivot+1;

                if (lwm > hwm)  /* searched all; not found */
                        break;
        }

        /* not found */
        return (PW_WORDS(pwp));
}