OSSP CVS Repository

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

ossp-pkg/rc/rc_proc.c 1.42
/*  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_proc.c: Run-command processor ISO C source file
*/

#include <stdlib.h>     /* Standard system headers    */
#include <fcntl.h>      /* For reading rc files       */
#include <unistd.h>     /* For reading rc files       */
#include <string.h>     /* For string manipulation    */
#include <signal.h>     /* For signal(3)              */
#include <sys/wait.h>   /* For waitpid(2) and fork(2) */

#include "rc.h"         /* Public interfaces          */
#include "rc_const.h"   /* String and value const     */
#include "rc_config.h"  /* Option definitions         */


/************************************************
* procNew(void)                                 *
* Construct a processor                         *
************************************************/
rc_proc_t *procNew(void)
{
    rc_proc_t *pNewrc = NULL;

    pNewrc = malloc(sizeof(rc_proc_t));
    pNewrc->m_pAnal = analNew();        /* Construct a configuration analyser */
    analParse(pNewrc->m_pAnal);         /* Preprocess the anal configuration  */
    pNewrc->m_pScriptcom = scriptNew(); /* Construct a run-command script     */
    pNewrc->m_ppLabvec = calloc(pNewrc->m_pAnal->m_nRcs, sizeof(rc_label_t *));

    return(pNewrc);
}

/************************************************
* procReadtmp(rc_proc_t *, const char *)        *
* Open and store a temp file                    *
************************************************/
rc_return_t procReadtmp(rc_proc_t *pRc, const char *szTmpname)
{
    fprintf(stderr, "%s!!!\n", szTmpname);

    return(RC_THROW(RC_OK));
}

/************************************************
* procPopulate(rc_proc_t *)                     *
* Populate the processor with run commands      *
************************************************/
rc_return_t procPopulate(rc_proc_t *pRc)
{
    int nSect   = 0;
    int nFdrc   = -1;
    int nFdfunc = -1;
    int nRet    = 0;
    int nRc     = 0;
    ex_t Except;

    char         *sBuf        = NULL;
    rc_section_t *pSec        = NULL;
    char         *szLocex     = NULL;
    rc_script_t  *pTempscript = NULL;

    assert(*pRc->m_pAnal->m_pszRcs);
    sBuf = (char *)calloc(1, RC_READ_BUFSIZE);

    /* Stick on the starting shell id line */
    scriptAppend(pRc->m_pScriptcom, "#! /bin/sh\n", strlen("#! /bin/sh\n"));

    /* Open the func file if it exists in the configuration */
    if (pRc->m_pAnal->m_szFuncs) {
        if ((nFdfunc = open(pRc->m_pAnal->m_szFuncs, O_RDONLY)) >= 0) {
            /* Read data from the func file */
            while ((nRet = read(nFdfunc, sBuf, RC_READ_BUFSIZE)) > 0) {
                scriptAppend(pRc->m_pScriptcom, sBuf, nRet);
            }
            if (nRet == -1) /* Handle read errors */
                RC_THROW(RC_ERR_IO);
            scriptAppend(pRc->m_pScriptcom, "\n", sizeof(char));
        }
        else
            RC_THROW(RC_ERR_FNC);
    }

    /* Iteratively read possibly globbed rc files */
    for (nRc = 0; nRc < pRc->m_pAnal->m_nRcs; nRc++)
    {
        assert(*pRc->m_pAnal->m_pszRcs);
        assert(pRc->m_pAnal->m_szLocs);

        /* Construct a new label */
        pRc->m_ppLabvec[nRc] = labelNew(pRc->m_pAnal->m_pszRcs[nRc]);

        /* Build the path name */
        szLocex = (char *)malloc(strlen(pRc->m_pAnal->m_szLocs) + \
                                 strlen(pRc->m_pAnal->m_pszRcs[nRc]) + \
                                 strlen("rc.") + 1);
        strcpy(szLocex, pRc->m_pAnal->m_szLocs);
        strcat(szLocex, "rc."); /* FIXME: Make the prefix configurable */
        strcat(szLocex, pRc->m_pAnal->m_pszRcs[nRc]);

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

        /* Read data from the rc file into a temporary script */
        pTempscript = scriptNew();
        while ((nRet = read(nFdrc, sBuf, RC_READ_BUFSIZE)) > 0)
            scriptAppend(pTempscript, sBuf, nRet);

        if (nRet == -1) /* Handle read errors */
            RC_THROW(RC_ERR_IO);

        try {
            /* Append config section if it exists */
            pSec = scriptSection(pTempscript, configGetval(RC_NCF_VAL));
            if (pSec) { /* Only operate if the section lookup succeeds */
                scriptAppend(pRc->m_pScriptcom, sectionGetdata(pSec), strlen(sectionGetdata(pSec)));
                scriptAppend(pRc->m_pScriptcom, "\n", sizeof(char));
                sectionDelete(pSec);    /* Cleanup */
                pSec = NULL;            /* Cleanup */
            }

            for (nSect = 0; nSect < pRc->m_pAnal->m_nSecs; nSect++) { /* Iterate over */
                /* Extract a section from the temp script, and append it */
                pSec = scriptSection(pTempscript, pRc->m_pAnal->m_pszSecs[nSect]);

                if (pSec) /* Only copy if the section lookup succeeds */
                    labelAppendsec(pRc->m_ppLabvec[nRc], pSec);
                else if (configGetval(RC_DBG_VAL)) /* Only show if debug set */
                    fprintf(stderr, "#Warning: Missing section '%s' in %s!\n",\
                        pRc->m_pAnal->m_pszSecs[nSect],\
                        pRc->m_pAnal->m_pszRcs[nRc]);

                if (pSec) { /* Cleanup iterative section string */
                    sectionDelete(pSec);
                    pSec = NULL;
                }
            }
        }
        catch(Except)
            rethrow;

        /* Clean up our crap */
        scriptDelete(pTempscript); /* Temp script */
        pTempscript = NULL;
        free(szLocex);  /* Temp Location + Rcfile */
        szLocex = NULL;
        close(nFdrc);   /* Close Rc file handle */
    }

    close(nFdfunc);     /* Close Func file handle */

    /* Memory cleanups */
    if (sBuf) {
        free(sBuf);
        sBuf = NULL;
    }

    return(RC_THROW(RC_OK));
}

/************************************************
* procRun(rc_proc_t *)                          *
* Run the processed run-command script          *
************************************************/
rc_return_t procRun(rc_proc_t *pRc)
{
    int   nTmp      = 0;              /* Generic index       */
    int   nTmpname  = 0;              /* Temp file name size */
    int   nRcs      = 0;              /* Rc index            */
    int   nSecs     = 0;              /* Section index       */
    int   nSectuid  = -1;             /* The section's user id           */
    int   nRunuid   = -1;             /* The current user id             */
    pid_t Pidexec   = -1;             /* When spawning before execv(3)   */
    char *szTmpfile = NULL;           /* Path of temporary file          */
    char *szTmp     = NULL;           /* Generic temporary string        */
    char *szCom     = NULL;           /* Stores common script text       */
    char *szExec    = NULL;           /* Used only during exec mode      */
    char *pszVec[RC_EXEC_MAXARGS];    /* For passing in to execv(3)      */
    rc_script_t   *pFatscript = NULL; /* To build a comprehensive script */
    rc_section_t **ppSectmp   = NULL; /* Used with priority scheduling   */

    /****************************************************/
    /* This will execute, evaluate, or print the script */
    /* Exec  - Fork and execute each command            */
    /* Eval  - Print machine evaluatable format         */
    /* Print - Print human readable format              */
    /****************************************************/
    if (configGetval(RC_EVL_VAL)) {                             /* Evaluate */
        /* Allocate a block of section pointers to use temporarily */
        ppSectmp = calloc(pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *));
        /* Allocate the command chain string to execute with execv(3) */
        pFatscript = scriptCopy(pRc->m_pScriptcom);
        for (nSecs = 0; nSecs < pRc->m_pAnal->m_nSecs; nSecs++) {
            for (nRcs = 0; nRcs < pRc->m_pAnal->m_nRcs; nRcs++) {
                nTmp = 0;
                while (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs && \
                    strcmp(pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp]->m_szName, \
                                pRc->m_pAnal->m_pszSecs[nSecs]))
                    nTmp++;
                if (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs)
                    ppSectmp[nRcs] = pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp];
                else
                    ppSectmp[nRcs] = NULL;
            }
            qsort((void *)ppSectmp, (size_t)pRc->m_pAnal->m_nRcs, \
                sizeof(rc_section_t *), priCompare);
            nTmp = 0;
            while (nTmp < pRc->m_pAnal->m_nRcs && ppSectmp[nTmp]) {
                if (configGetval(RC_VRB_VAL)) {
                    size_t nBytes = 0;
                    char *szVerbose = NULL;
                    szTmp = (char *)sectionGetname(ppSectmp[nTmp]);
                    nBytes = (strlen(RC_EVN_TEXT) + strlen(szTmp) + 1) * sizeof (char);
                    szVerbose = malloc (nBytes);
                    sprintf(szVerbose, RC_EVN_TEXT, szTmp, szTmp);
                    scriptAppend(pFatscript, szVerbose, strlen(szVerbose));
                    free(szVerbose);
                }
                if ((szTmp = (char *)sectionGetlogin(ppSectmp[nTmp])) != NULL) {
                    scriptAppend(pFatscript, "#su ", strlen("#su "));
                    scriptAppend(pFatscript, szTmp, strlen(szTmp));
                    scriptAppend(pFatscript, "\n", strlen("\n") + 1);
                }
                szTmp = (char *)sectionGetdata(ppSectmp[nTmp]);
                scriptAppend(pFatscript, szTmp, strlen(szTmp) + 1);
                nTmp++;
            }
        }
        free(ppSectmp);
        ppSectmp = NULL;

        szTmpfile = (char *)configGetval(RC_TMP_VAL);
        nTmpname = (strlen(szTmpfile) + strlen(RC_EVL_TMP) + \
                    strlen(RC_EVL_SUF) + 1) * sizeof(char);
        if (*(szTmpfile + (strlen(szTmpfile) - 1) * sizeof(char)) != '/')
            nTmpname += sizeof(char);
        szTmpfile = malloc(nTmpname);
        strcpy(szTmpfile, configGetval(RC_TMP_VAL));
        if (*(szTmpfile + (strlen(szTmpfile) - 1) * sizeof(char)) != '/')
            strcat(szTmpfile, "/");
        strcat(szTmpfile, RC_EVL_TMP);
        mktemp(szTmpfile);
        strcat(szTmpfile, RC_EVL_SUF);
        scriptWrite(pFatscript, szTmpfile); /* Write the whole script out */
        fprintf(stdout, RC_EVL_OUT, szTmpfile, szTmpfile);
        free(szTmpfile);
        szTmpfile = NULL;
        scriptDelete(pFatscript);
        pFatscript = NULL;
    }
    else if (configGetval(RC_EXC_VAL)) {                        /* Execute  */
        /* This block does nothing more than implement the feature,         */
        /* that allows rc to run unprivileged (as long as no privileged     */
        /* code is used in the script sections to be executed               */
        for (nSecs = 0; nSecs < pRc->m_pAnal->m_nSecs; nSecs++) {
            for (nTmp = 0; nTmp < pRc->m_pAnal->m_nRcs; nTmp++) {
                if (pRc->m_ppLabvec[nTmp]->m_ppSecvec && \
                    pRc->m_ppLabvec[nTmp]->m_ppSecvec[nSecs]) {
                    nRunuid = getuid();
                    nSectuid = pRc->m_ppLabvec[nTmp]->m_ppSecvec[nSecs]->m_nUid;
                    /* See if root user status is needed, and bail out if so */
                    if (nRunuid != 0 && nSectuid != -1 && nRunuid != nSectuid) {
                        fprintf(stderr, RC_RUT_TEXT);
                        return(RC_THROW(RC_ERR_USE));
                    }
                }
            }
        }
        /* Allocate a block of section pointers to use temporarily */
        ppSectmp = calloc(pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *));
        szCom = (char *)scriptTostring(pRc->m_pScriptcom);
        for (nSecs = 0; nSecs < pRc->m_pAnal->m_nSecs; nSecs++) {
            for (nRcs = 0; nRcs < pRc->m_pAnal->m_nRcs; nRcs++) {
                nTmp = 0;
                while (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs && \
                    strcmp(pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp]->m_szName, \
                                pRc->m_pAnal->m_pszSecs[nSecs]))
                    nTmp++;
                if (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs)
                    ppSectmp[nRcs] = pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp];
                else
                    ppSectmp[nRcs] = NULL;
            }
            qsort((void *)ppSectmp, (size_t)pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *), priCompare);
            pszVec[0] = "/bin/sh";  /* Run the bourne shell over the following */
            pszVec[1] = "-c";       /* Append script code of the sections */
            pszVec[3] = NULL;       /* Add a NULL to mark the end of the chain */
            nTmp = 0; /* Count from zero until however many sections we have */
            while (nTmp < pRc->m_pAnal->m_nRcs && ppSectmp[nTmp]) {
                szTmp = (char *)sectionGetdata(ppSectmp[nTmp]);
                szExec = malloc(strlen(szCom) * sizeof(char) + \
                               (strlen(szTmp) + 1) * sizeof(char));
                strcpy(szExec, szCom); /* Start out with just the common script code */
                strcat(szExec, szTmp); /* And build a section onto the command chain */
                pszVec[2] = szExec;    /* Actually launch the new process image now  */

                /* Spawn the section shell code */
                switch (Pidexec = fork()){
                    case -1:    /* Broken */
                        return(RC_THROW(RC_ERR_INT));
                        break;  /* Huh? */
                    case 0:     /* Child, runs script code through bourne shell */
                        nSectuid = sectionGetuid(ppSectmp[nTmp]);
                        if (nSectuid >= 0 && getuid() != nSectuid)
                            if (setuid(nSectuid) != 0)
                                return(RC_THROW(RC_ERR_INT));
                        if (execvp(*pszVec, pszVec) == -1)
                            return(RC_THROW(RC_ERR_INT));
                        break;
                    default: /* Parent, blocks until child returns */
                        waitpid(Pidexec, NULL, WUNTRACED);
                        break;
                }

                free(szExec); /* Cleanup after exec */
                szExec = NULL;
                nTmp++;
            }
        }
        free(ppSectmp);
        ppSectmp = NULL;
    }
    else if (configGetval(RC_PRN_VAL)) {                        /* Print  */
        /* Allocate a block of section pointers to use as a temporary */
        ppSectmp = calloc(pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *));
        scriptDump(pRc->m_pScriptcom); /* Dump the common script */
        for (nSecs = 0; nSecs < pRc->m_pAnal->m_nSecs; nSecs++) {
            for (nRcs = 0; nRcs < pRc->m_pAnal->m_nRcs; nRcs++) {
                nTmp = 0;
                while (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs && \
                    strcmp(pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp]->m_szName, \
                                pRc->m_pAnal->m_pszSecs[nSecs]))
                    nTmp++;
                if (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs)
                    ppSectmp[nRcs] = pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp];
                else
                    ppSectmp[nRcs] = NULL;
            }
            qsort((void *)ppSectmp, (size_t)pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *), priCompare);
            nTmp = 0;
            while (nTmp < pRc->m_pAnal->m_nRcs && ppSectmp[nTmp]) {
                sectionDump(ppSectmp[nTmp]);
                nTmp++;
            }
        }
        free(ppSectmp);
        ppSectmp = NULL;
    }
    else /* Something is wrong here */
        return(RC_THROW(RC_ERR_INT));

    return(RC_THROW(RC_OK));
}

/************************************************
* procDelete(rc_proc_t *)                       *
* Destruct a processor                          *
************************************************/
rc_return_t procDelete(rc_proc_t *pRc)
{
    int nRcs = pRc->m_pAnal->m_nRcs;

    /* Destroy the label vector */
    while (nRcs-- > 0) {
        if (pRc->m_ppLabvec[nRcs]) {
            labelDelete(pRc->m_ppLabvec[nRcs]);
            pRc->m_ppLabvec[nRcs] = NULL;
        }
    }
    free(pRc->m_ppLabvec);
    pRc->m_ppLabvec = NULL;
    scriptDelete(pRc->m_pScriptcom);    /* Destroy the script        */
    analDelete(pRc->m_pAnal);           /* Destroy the analyser      */
    free(pRc);                          /* Free the processor itself */

    return(RC_THROW(RC_OK));
}


CVSTrac 2.0.1