OSSP CVS Repository

ossp - ossp-pkg/rc/rc_file.c
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/rc/rc_file.c
/*  OSSP rc - Run-command processor
**  Copyright (c) 2002-2003 Ralf S. Engelschall
**  Copyright (c) 2002-2003 Cable & Wireless Deutschland GmbH
**  Copyright (c) 2002-2003 The OSSP Project <http://www.ossp.org/>
**
**  This file is part of OSSP rc, a portable Run-command processor
**  which can be found at http://www.ossp.org/pkg/lib/rc/
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  rc_file.c: Run-command processor ISO C source file
*/

#include <string.h>     /* For string copy and such data ops */
#include <stdlib.h>     /* For memory ops             */
#include <fcntl.h>      /* For reading rc files       */
#include <unistd.h>     /* For reading rc files       */
#include <ctype.h>      /* For isspace(3)             */
#include <pwd.h>        /* For getpwuid(3)            */

#include "rc.h"         /* Public Rc interface        */
#include "rc_const.h"   /* For configuration defaults */
#include "rc_config.h"  /* Option definitions         */
#include "rc_pcre.h"    /* For section parsing        */


/************************************************
* rcfileNew(void)                               *
* Construct a new rcfile                        *
************************************************/
rc_file_t *rcfileNew(const char *szName)
{
    rc_file_t *pRcfile = NULL;

    pRcfile = (rc_file_t *)calloc(1, sizeof(rc_file_t));    /* Allocate and clear */
    if (!pRcfile)                                           /* Ensure storage */
        RC_THROW(RC_ERR_MEM);

    if (szName) {
        pRcfile->m_szName = malloc((strlen(szName) + 1) * sizeof(char));
        strcpy(pRcfile->m_szName, szName);
    }
    else
        pRcfile->m_szName = NULL;

    /* Start section array with one empty allocated tail item */
    pRcfile->m_nSecs = 0;
    pRcfile->m_ppSecvec = malloc(sizeof(rc_section_t *));
    *pRcfile->m_ppSecvec = NULL;

    return(pRcfile);
}

/****************************************************
* rcfileParse(rc_file_t *)                          *
* Parse rcfile contents, initialize any sections    *
****************************************************/
rc_return_t rcfileParse(rc_file_t *pRcf)
{
    rc_script_t *pScript = NULL;
    char *szLocex = NULL;
    char *sBuf = NULL;
    int nFdrc = -1;
    int nRet  = 0;

    if (pRcf->m_nSecs > 0)
        RC_THROW(RC_ERR_USE); /* Only virgin rcfiles can be parsed */

    /* Build the location path name */
    if (!configGetval(RC_LOC_VAL))  /* Config should have */
        RC_THROW(RC_ERR_INT);       /* given a locs default */
    else { /* Only enter block with valid string, strdup can't handle NULL */
        /* FIXME mlelstv -- crashes on zero-length RC_LOC_VAL string */
        if (*(configGetval(RC_LOC_VAL) + strlen(configGetval(RC_LOC_VAL)) - 1) != '/') {
            /* FIXME mlelstv -- void pointer arithmetic from hell */
            szLocex = malloc(strlen(configGetval(RC_LOC_VAL)) + \
                             sizeof (char) + \
                             strlen("rc.") + \
                             strlen(pRcf->m_szName) + \
                             sizeof (char));
            strcpy(szLocex, configGetval(RC_LOC_VAL));
            strcat(szLocex, "/");
            strcat(szLocex, "rc."); /* FIXME: Make the prefix configurable */
            strcat(szLocex, pRcf->m_szName);
        }
        else {
            szLocex = malloc(strlen(configGetval(RC_LOC_VAL)) + \
                             strlen("rc.") + \
                             strlen(pRcf->m_szName) + \
                             sizeof (char));
            strcpy(szLocex, configGetval(RC_LOC_VAL));
            strcat(szLocex, "rc."); /* FIXME: Make the prefix configurable */
            strcat(szLocex, pRcf->m_szName);
        }
    }

    /* Open the rc file unconditionally */
    if ((nFdrc = open(szLocex, O_RDONLY)) == -1)
        RC_THROW(RC_ERR_RCF);

    /* Read data from the rcfile into a temporary script */
    pScript = scriptNew();
    sBuf = (char *)calloc(1, RC_READ_BUFSIZE);
    while ((nRet = read(nFdrc, sBuf, RC_READ_BUFSIZE)) > 0)
        scriptnAppend(pScript, sBuf, nRet);

    /* FIXME mlelstv -- errno is lost ? */
    if (nRet == -1) /* Handle read errors */
        RC_THROW(RC_ERR_IO);

    { /* Extract sections from script, and neatly place in rcfile */
        rc_section_t *pSec = NULL;
        char *piSecname    = NULL;
        int   nLabsize     = 0;
        int   nPribytes    = 0;
        char *piSubtemp    = NULL; /* To find priority and userid in substrings  */
        char *piBlocend    = NULL; /* Misnomer used to control section looping   */
        char *piStart      = NULL;
        char *piEnd        = NULL;
        char *piSep        = NULL;
        char *szUser       = NULL;
        char *szName       = NULL;
        char *szTemp       = NULL; /* Holds temporarily the pri and user strings */
        struct passwd *pPwd = NULL;
        long nPri          = 0;
        long nUid          = 0;
        int nUserbytes     = 0;
        int nTmp           = 0;
        char *pTmp         = NULL;
        int nOffset        = 0;
        int nFound         = 0;
        int nVecsize       = 0;
        int nSubstrings    = 0;
        int *pnVec         = NULL;
        const char *kszErr = NULL;
        const int kiRegopt = PCRE_DOTALL | PCRE_MULTILINE;
        /*const int kiRegopt = PCRE_DOTALL | PCRE_MULTILINE | PCRE_UNGREEDY;*/

        pcre *pRegex       = NULL;  /* Perl Compatible Regular Expression */
        pcre_extra *pExtra = NULL;  /* Used for studying an expression    */

        if ((pRegex = pcre_compile(configGetval(RC_DEF_VAL), kiRegopt, &kszErr, &nOffset, NULL)) == NULL)
            RC_THROW(RC_ERR_SYS);

        pExtra = pcre_study(pRegex, 0, &kszErr); /* Study the FSM */
        if (kszErr) {   /* Variable contains a string reference in case of errors */
            free(pRegex);
            RC_THROW(RC_ERR_SYS);
        }

        if (pcre_fullinfo(pRegex, pExtra, PCRE_INFO_CAPTURECOUNT, &nSubstrings)) {
            free(pRegex);
            RC_THROW(RC_ERR_SYS);
        }

        /***********************************************************************/
        /* Reminder: PCRE writes vectors to help identify substrings.          */
        /*           That means that in the following code we can              */
        /*           execute a compiled PCRE regex (ab)(\s)(.*)$               */
        /*                                                                     */
        /*           piBlocend + pnVec[0] = 'start of whole matched string'    */
        /*           piBlocend + pnVec[1] = 'end of whole matched string'      */
        /*           piBlocend + pnVec[2] = 'start of first substring (ab)'    */
        /*           piBlocend + pnVec[3] = 'end of first substring (ab)'      */
        /*           piBlocend + pnVec[4] = 'start of second substring (\s)'   */
        /*           piBlocend + pnVec[5] = 'end of second substring (\s)'     */
        /*           piBlocend + pnVec[6] = 'start of third substring (.*)'    */
        /*           piBlocend + pnVec[7] = 'end of third substring (.*)'      */
        /***********************************************************************/

        /* Use multiples of six, because PCRE needs 2x multiples of three */
        nVecsize = 6 * (nSubstrings > 0 ? nSubstrings : 1);
        nVecsize *= RC_GOOD_MEASURE; /* Add redundancy factor for error margin */
    /*    pAwesome += RC_GOOD_VIBRATIONS;*/ /* Add good vibes for super action */

        /* Filter the rc file for the section label, do it here the first time */
        pnVec = calloc(nVecsize, sizeof(int));  /* 2/3 vec 1/3 scrapinfo */
        nFound = pcre_exec(pRegex, pExtra, *pScript,\
            strlen(*pScript), 0, 0, pnVec, nVecsize);

        piBlocend = *pScript;   /* Start piBlocend pointing to the script object */
        while (nFound > 1) {    /* Loop as long as we have more sections */
            piSecname = piBlocend + *(pnVec + 2);
            nLabsize  = *(pnVec + 3) - *(pnVec + 2);

            /* Handle the section name and body */
            piStart   = piBlocend + *(pnVec + 6);
            piEnd     = piBlocend + *(pnVec + 7);
            szName = malloc((nLabsize + 1) * sizeof (char));
            strncpy(szName, piSecname, nLabsize);
            *(szName + nLabsize) = '\0';
            pSec = sectionNew(szName);
            free(szName);   /* Get rid of the temporary, actually   */
            szName = NULL;  /* just for making a new section string */
            sectionSetndata(pSec, piStart, piEnd - piStart);

            /* Handle the section parent */
            sectionSetparent(pSec, pRcf->m_szName);

            /* FIXME: Implement --ParseSectionParam for extra gravy */
            /* Handle the section priority */
            piStart = piBlocend + *(pnVec + 4);
            piEnd   = piBlocend + *(pnVec + 5);
            nPribytes = piEnd - piStart;
            szTemp  = malloc(nPribytes + sizeof (char));
            strncpy(szTemp, piStart, nPribytes);
            *(szTemp + nPribytes) = '\0';
            piSubtemp = strstr(szTemp, RC_DEF_PRG);
            if (piSubtemp) { /* Priority pattern found */
                for (pTmp = piSubtemp + strlen(RC_DEF_PRG); \
                    isspace(*pTmp); pTmp += 1)
                    continue; /* Strip */
                nPri = strtol(pTmp, &piSep, 10);
                if (pTmp == piSep)          /* No priority number follows */
                    RC_THROW(RC_ERR_USE);   /* which is an error */
                else
                    sectionSetpri(pSec, nPri);  /* Found a priority value */
            }
            else /* Fallback to default value */
                sectionSetpri(pSec, RC_DEF_PRI);

            /* Handle the section userid   */
            piSubtemp = strstr(szTemp, RC_DEF_UIG);
            if (piSubtemp) { /* Userid pattern found */
                for (nTmp = (int)piSubtemp + strlen(RC_DEF_UIG); \
                    isspace(*(char *)nTmp); nTmp += sizeof (char)); /* Strip */
                nUid = strtol((char *)nTmp, &piSep, 10);
                if ((char *)nTmp == piSep)      /* No userid number follows */
                {
                    nUserbytes = strspn((strcspn(piSep, " \t\n") * sizeof (char) + piSep), " \t\n");
                    nUserbytes = (strlen(piSep) - nUserbytes) * sizeof (char);
                    szUser = malloc(nUserbytes + sizeof (char));
                    if (!szUser)
                        RC_THROW(RC_ERR_MEM);
                    strncpy(szUser, (const char *)nTmp, nUserbytes);
                    *(szUser + nUserbytes) = '\0';
                    strtok(szUser, " \t\n");
                    pPwd = getpwnam(szUser);
                    if (pPwd) {
                        sectionSetuid(pSec, pPwd->pw_uid);  /* Set to given   */
                        sectionSetlogin(pSec, szUser);      /* uid and login  */
                    }
                    else
                        sectionSetuid(pSec, RC_DEF_UID);    /* Set to default */
                    free(szUser);
                }
                else {
                    pPwd = getpwuid(nUid);
                    if (pPwd) {
                        sectionSetuid(pSec, nUid);              /* Found a value */
                        sectionSetlogin(pSec, pPwd->pw_name);   /* uid and login  */
                    }
                    else
                        sectionSetuid(pSec, RC_DEF_UID);        /* Set to default */
                }
            }
            else /* Fallback to default value */
                sectionSetuid(pSec, RC_DEF_UID);

            /* Cleanup */
            free(szTemp);
            szTemp = NULL;

            /* Copy a new section to that found in the script object */
            pRcf->m_ppSecvec = realloc(pRcf->m_ppSecvec, sizeof(rc_section_t *) \
                                                       * (pRcf->m_nSecs + 2));
            pRcf->m_ppSecvec[pRcf->m_nSecs] = sectionCopy(pSec);
            pRcf->m_ppSecvec[pRcf->m_nSecs + 1] = NULL;
            pRcf->m_nSecs++;

            /* Clean up our temporary section */
            sectionDelete(pSec);
            pSec = NULL;

            /* Find end of section block */
            piBlocend += *(pnVec + 1);

            /* Try to match another section */
            nFound = pcre_exec(pRegex, pExtra, piBlocend,\
                strlen(piBlocend), 0, 0, pnVec, nVecsize);
        }

        /* release compiled regex */
        free(pRegex);

        /* Handle errors */
        if (nFound == 1)                        /* User gave no klammern */
            RC_THROW(RC_ERR_USE);               /* so complain about it */
        else if (nFound < PCRE_ERROR_NOMATCH)   /* Generic problem so */
            RC_THROW(RC_ERR_SYS);               /* return an error */
    }

    /* Deallocate and clean */
    scriptDelete(pScript);
    pScript = NULL;
    free(szLocex);
    szLocex = NULL;
    free(sBuf);
    sBuf = NULL;
    close(nFdrc);

    return(RC_OK);
}

/****************************************************
* rcfileGetsec(rc_file_t *, const char *)           *
* Get a section from the rcfile, and return it      *
****************************************************/
rc_section_t *rcfileGetsec(rc_file_t *pRcf, const char *szSec)
{
    int nIter = 0;

    assert(pRcf && szSec);

    /* Return the section if it is found */
    for (nIter = 0; nIter < pRcf->m_nSecs; nIter++) {
        if (!strcmp(pRcf->m_ppSecvec[nIter]->m_szName, szSec))
            return(pRcf->m_ppSecvec[nIter]);
    }

    return NULL;
}

/****************************************************
* rcfileAppendsec(rc_file_t *, rc_section_t *)      *
* Append a section to this rcfile                   *
****************************************************/
rc_return_t rcfileAppendsec(rc_file_t *pRcfile, rc_section_t *pInsec)
{
    assert(pRcfile && pInsec);  /* Parameters must be valid */

    /* Grow the number of sections */
    pRcfile->m_nSecs++;

    /* First make our vector larger to hold one more section */
    pRcfile->m_ppSecvec = realloc(pRcfile->m_ppSecvec, sizeof(rc_section_t *) \
                                                     * (pRcfile->m_nSecs + 1));
    pRcfile->m_ppSecvec[pRcfile->m_nSecs] = sectionNew(pInsec->m_szName);
    pRcfile->m_ppSecvec[pRcfile->m_nSecs + 1] = NULL;

    /* Simple value copy */
    pRcfile->m_ppSecvec[pRcfile->m_nSecs]->m_nPri  = pInsec->m_nPri;
    pRcfile->m_ppSecvec[pRcfile->m_nSecs]->m_nUid  = pInsec->m_nUid;

    /* Deep copy of parent */
    if (pInsec->m_szParent) {
        pRcfile->m_ppSecvec[pRcfile->m_nSecs]->m_szParent = \
            malloc((strlen(pInsec->m_szParent) + sizeof(char)) * sizeof(char));
        strcpy(pRcfile->m_ppSecvec[pRcfile->m_nSecs]->m_szParent, pInsec->m_szParent);
    }

    /* Deep copy of user name */
    if (pInsec->m_szLogin) {
        pRcfile->m_ppSecvec[pRcfile->m_nSecs]->m_szLogin = \
            malloc((strlen(pInsec->m_szLogin) + sizeof(char)) * sizeof(char));
        strcpy(pRcfile->m_ppSecvec[pRcfile->m_nSecs]->m_szLogin, pInsec->m_szLogin);
    }

    /* Deep copy of section text */
    if (scriptGetdata(pInsec->m_pData))
        scriptSetdata(pRcfile->m_ppSecvec[pRcfile->m_nSecs]->m_pData, scriptGetdata(pInsec->m_pData));

    return(RC_THROW(RC_OK));
}

/************************************************
* rcfileGetXXX(rc_file_t *)                     *
* Accessor methods                              *
************************************************/
const char *rcfileGetname(rc_file_t *pRcfile)
{ /* Name of rcfile, used for display during verbose */
    if (pRcfile)
        return(pRcfile->m_szName);
    else
        RC_THROW(RC_ERR_USE);

    return(0); /* Not reached */
}

/************************************************
* rcfileSetXXX(rc_file_t *, const ... *)        *
* Accessor methods                              *
************************************************/
rc_return_t rcfileSetname(rc_file_t *pRcfile, const char *szName)
{ /* Name of rcfile, used for display during verbose */
    if (pRcfile) {
        pRcfile->m_szName = malloc((strlen(szName) + 1) * sizeof (char));
        strcpy(pRcfile->m_szName, szName);
        return(RC_THROW(RC_OK));
    }

    return(RC_THROW(RC_ERR_USE));
}

/************************************************
* rcfileExists(rc_file_t *)                     *
* Tests for an existing rcfile object           *
************************************************/
short rcfileExists(rc_file_t *pRcfile)
{ /* Key on name of rcfile */
    if (pRcfile) {
        if (pRcfile->m_szName)
            return(TRUE);   /* Object does indeed exist */
        else
            return(FALSE);  /* Object does not exist    */
    }

    return(RC_THROW(RC_ERR_USE));
}

/************************************************
* rcfileDelete(rc_file_t *)                     *
* Destruct a rcfile                             *
************************************************/
rc_return_t rcfileDelete(rc_file_t *pRcfile)
{
    int nSecs = pRcfile->m_nSecs;

    assert(pRcfile); /* Stupidity check */

    /* Cleanup our junk */
    pRcfile->m_nSecs = 0;       /* Blank the section count    */
    if (pRcfile->m_szName) {    /* Destroy the rc name        */
        free(pRcfile->m_szName);
        pRcfile->m_szName = NULL;
    }
    while (--nSecs >= 0) {      /* Destroy the section vector */
        if (pRcfile->m_ppSecvec[nSecs]) {
            sectionDelete(pRcfile->m_ppSecvec[nSecs]);
            pRcfile->m_ppSecvec[nSecs] = NULL;
        }
    }
    free(pRcfile->m_ppSecvec);
    pRcfile->m_ppSecvec = NULL;
    free(pRcfile);
    pRcfile = NULL;

    return(RC_THROW(RC_OK));
}


CVSTrac 2.0.1