OSSP CVS Repository

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

ossp-pkg/rc/rc_script.c 1.26
/*  OSSP rc - Run-command processor
**  Copyright (c) 2002 Ralf S. Engelschall
**  Copyright (c) 2002 Cable & Wireless Deutschland GmbH
**  Copyright (c) 2002 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_script.c: Run-command processor ISO C source file
*/

#include <string.h>
#include <stdlib.h>
#include <unistd.h>     /* For mkstemp(3)             */
#include <fcntl.h>      /* For open(2)                */
#include <ctype.h>      /* For isspace(3)             */
#include <pwd.h>        /* For getpwuid(3)            */

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


/************************************************
* scriptCopy(rc_script_t *)                     *
* Copy constructor                              *
************************************************/
rc_script_t *scriptCopy(rc_script_t *pOrig)
{
    rc_script_t *pNew = NULL;

    pNew = (rc_script_t *)malloc(sizeof(rc_script_t));
    *pNew = malloc((strlen(scriptTostring(pOrig)) + 1) * sizeof(char));
    if (pNew)
        strcpy(*pNew, scriptTostring(pOrig));
    else
        RC_THROW(RC_ERR_MEM);

    return(pNew);
}

/************************************************
* scriptNew(void)                               *
* Construct a script                            *
************************************************/
rc_script_t *scriptNew(void)
{
    rc_script_t *pScript = NULL;

    pScript = (rc_script_t *)malloc(sizeof(rc_script_t));
    *pScript = NULL;

    return(pScript);
}

/****************************************************
* scriptAppend(rc_script_t *, const char *, size_t) *
* Append text to a script                           *
****************************************************/
rc_return_t scriptAppend(rc_script_t *pScript, const char *szInbuf, size_t Size)
{
    int nResize     = 0;
    void *pvRealloc = NULL;

    assert(pScript); /* Script parameter must be valid */

    if (!szInbuf) {
        return(RC_THROW(RC_ERR_USE));
    }

    /* Short circuit in case of dumb noop call */
    if (Size == 0)
        return(RC_THROW(RC_OK));

    /* Add 2 to end of nResize to ensure that a \0 precedes any strings */
    nResize = (*pScript != NULL ? strlen(*pScript) : 0) + Size + 2;
    /* Don't trust realloc(3) in this case */
    if ((pvRealloc = calloc(1, (size_t)nResize)) == NULL) {
        return(RC_THROW(RC_ERR_MEM));
    }

    /* Coerce strings into one Script again */
    if (*pScript) {
        strcpy(pvRealloc, *pScript);
        strncat(pvRealloc, szInbuf, Size);
    }
    else
        strncpy(pvRealloc, szInbuf, Size);

    /* Cleanup and deallocate memory */
    if (*pScript) {
        free(*pScript);
        *pScript = NULL;
    }
    *pScript = pvRealloc;

    return(RC_THROW(RC_OK));
}

/************************************************
* scriptSection(rc_script_t *, const char *)    *
* Parse a script for a given section            *
************************************************/
rc_section_t *scriptSection(rc_script_t *pScript, const char *kszSecname)
{
    rc_section_t *pSec = NULL;
    char *piLabstart   = NULL;
    int   nLabsize     = 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 *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;
    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    */

    assert(pScript);            /* Check for a valid incoming script  */
    assert(configGetval(RC_DEF_VAL));

    if (!kszSecname)    /* If we get a NULL section label, then throw up */
        RC_THROW(RC_ERR_USE);

    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))
        RC_THROW(RC_ERR_SYS);

    /* 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 */

    /***********************************************************************/
    /* 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 (.*)'      */
    /***********************************************************************/

    /* 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 */
        piLabstart = piBlocend + *(pnVec + 2);
        nLabsize   = *(pnVec + 3) - *(pnVec + 2);

        /* Test the substring. If it matches our label, make a new section */
        if (strncmp(piLabstart, kszSecname, nLabsize) == 0 \
            && nLabsize == strlen(kszSecname) * sizeof (char)) {
            /* Handle the section body */
            piStart   = piBlocend + *(pnVec + 6);
            piEnd     = piBlocend + *(pnVec + 7);
            pSec = sectionNew(kszSecname);
            sectionSetndata(pSec, piStart, piEnd - piStart);

            /* FIXME: Implement --ParseSectionParam for extra gravy */
            /* Handle the section priority */
            piStart = piBlocend + *(pnVec + 4);
            piEnd   = piBlocend + *(pnVec + 5);
            szTemp  = malloc((piEnd - piStart + 1) * sizeof (char));
            strncpy(szTemp, piStart, piEnd - piStart + 1);
            piSubtemp = strstr(szTemp, RC_DEF_PRG);
            if (piSubtemp) { /* Priority pattern found */
                for (nTmp = (int)piSubtemp + strlen(RC_DEF_PRG);\
                    isspace(nTmp); nTmp += sizeof (char)); /* Strip */
                nPri = strtol((char *)nTmp, &piSep, 10);
                if ((char *)nTmp == piSep)  /* No priority number follows */
                    sectionSetpri(pSec, RC_DEF_PRI); /* 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(nTmp); nTmp += sizeof (char)); /* Strip */
                nUid = strtol((char *)nTmp, &piSep, 10);
                if ((char *)nTmp == piSep)      /* No userid number follows */
                {
                    nUserbytes = (strcspn(piSep, " \t\n") + sizeof (char)) * sizeof (char);
                    szUser = malloc(nUserbytes);
                    if (!szUser)
                        RC_THROW(RC_ERR_MEM);
                    strncpy(szUser, (const char *)nTmp, nUserbytes);
                    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;

            return(pSec); /* Section found, so return the text */
        }

        /* Looks like we didn't find the section yet, so keep trying */
        piBlocend += *(pnVec + 1);  /* Find end of section block */
        nFound = pcre_exec(pRegex, pExtra, piBlocend,\
            strlen(piBlocend), 0, 0, pnVec, nVecsize);
    }

    /* Under correct conditions, the section subscript was returned in loop */
    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 */

    return(NULL);                           /* Probably not found */
}

/************************************************
* scriptTostring(rc_script_t *)                 *
* Return the private script data as a string    *
************************************************/
const char *scriptTostring(rc_script_t *pScript)
{
    /* Don't remove this! It encapsulates the script object, */
    /*                    which might not be a simple string */
    if (pScript)
        return(*pScript);
    else
        return(NULL);
}

/************************************************
* scriptDump(rc_script_t *)                     *
* Print a script to standard out                *
************************************************/
rc_return_t scriptDump(rc_script_t *pScript)
{
    /* Don't remove this! It encapsulates the script object, */
    /*                    which might not be a simple string */
    if (pScript) {
        fprintf(stdout, "%s", *pScript);
        return(RC_THROW(RC_OK));
    }
    else
        return(RC_THROW(RC_ERR_USE));
}

/************************************************
* scriptWrite(rc_script_t *, const char *)      *
* Print a script to a file                      *
************************************************/
rc_return_t scriptWrite(rc_script_t *pScript, const char *szPath)
{
    int nFdtmp = open(szPath, O_WRONLY | O_CREAT, 0600);
    FILE *pStream = NULL;

    /* Initial sanity checks */
    if (!pScript || nFdtmp < 0)
        return(RC_THROW(RC_ERR_USE));
    else
        pStream = fdopen(nFdtmp, "w");

    /* Don't remove this! It encapsulates the script object, */
    /*                    which might not be a simple string */
    if (pStream) {
        fprintf(pStream, "%s", *pScript);
        fclose(pStream);
        return(RC_THROW(RC_OK));
    }
    else
        return(RC_THROW(RC_ERR_USE));
}

/************************************************
* scriptDelete(rc_script_t *)                   *
* Destruct a script                             *
************************************************/
rc_return_t scriptDelete(rc_script_t *pScript)
{
    if (*pScript)
        free(*pScript);
    else {
        RC_THROW(RC_WRN_NUL);
    }
    free(pScript);

    return(RC_THROW(RC_OK));
}


CVSTrac 2.0.1