ossp-pkg/rc/rc_sect.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_sect.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 <unistd.h> /* For mktemp(3) */
#include <fcntl.h> /* For open(2) */
#include "rc.h" /* Public Rc interface */
/************************************************
* sectionNew(const char *) *
* Construct a section *
************************************************/
rc_section_t *sectionNew(const char *szName)
{
rc_section_t *pSec = NULL;
/* Among other things, they make great coffee at Cable & Wireless */
/* This code would probably have more bugs if the coffee was not as good */
pSec = (rc_section_t *)calloc(1, sizeof(rc_section_t));
if (pSec == NULL)
RC_THROW(RC_ERR_MEM);
pSec->m_szName = malloc((strlen(szName) + 1) * sizeof(char));
strcpy(pSec->m_szName, szName);
pSec->m_pData = scriptNew();
return(pSec);
}
/************************************************
* sectionCopy(rc_section_t *) *
* Opaque copy constructor *
************************************************/
rc_section_t *sectionCopy(rc_section_t *pOrigsec)
{
rc_section_t *pSec = NULL;
/* Today is a rain and no coffee day */
pSec = (rc_section_t *)calloc(1, sizeof(rc_section_t));
pSec->m_nPri = pOrigsec->m_nPri;
pSec->m_nUid = pOrigsec->m_nUid;
/* Deep copy of section name */
if (pOrigsec->m_szName) {
pSec->m_szName = malloc((strlen(pOrigsec->m_szName) + 1)\
* sizeof(char));
strcpy(pSec->m_szName, pOrigsec->m_szName);
}
/* Deep copy of parent name */
if (pOrigsec->m_szParent) {
pSec->m_szParent = malloc((strlen(pOrigsec->m_szParent) + 1)\
* sizeof(char));
strcpy(pSec->m_szParent, pOrigsec->m_szParent);
}
/* Deep copy of user name */
if (pOrigsec->m_szLogin) {
pSec->m_szLogin = malloc((strlen(pOrigsec->m_szLogin) + 1)\
* sizeof(char));
strcpy(pSec->m_szLogin, pOrigsec->m_szLogin);
}
/* Deep copy of section text */
if (scriptGetdata(pOrigsec->m_pData)) {
if (!pSec->m_pData)
pSec->m_pData = scriptNew();
scriptSetdata(pSec->m_pData, scriptGetdata(pOrigsec->m_pData));
}
if (!pSec)
RC_THROW(RC_ERR_MEM);
return(pSec);
}
/************************************************
* sectionGetXXX(rc_section_t *) *
* Accessor methods *
************************************************/
const int sectionGetpri(rc_section_t *pSec)
{ /* Priority of section, used to order sections during exec|eval|print */
if (pSec)
return(pSec->m_nPri);
else
RC_THROW(RC_ERR_USE);
return(0); /* Not reached */
}
const int sectionGetuid(rc_section_t *pSec)
{ /* Userid of section, used with setuid during exec or eval */
if (pSec)
return(pSec->m_nUid);
else
RC_THROW(RC_ERR_USE);
return(0); /* Not reached */
}
const char *sectionGetname(rc_section_t *pSec)
{ /* Name of section, used for display during verbose */
if (pSec)
return(pSec->m_szName);
else
RC_THROW(RC_ERR_USE);
return(0); /* Not reached */
}
const char *sectionGetparent(rc_section_t *pSec)
{ /* Parent rcfile name of section, used for display during verbose */
if (pSec)
return(pSec->m_szParent);
else
RC_THROW(RC_ERR_USE);
return(0); /* Not reached */
}
const char *sectionGetlogin(rc_section_t *pSec)
{ /* User name of section, used for display during print */
if (pSec)
return(pSec->m_szLogin);
else
RC_THROW(RC_ERR_USE);
return(0); /* Not reached */
}
rc_script_t *sectionGetscript(rc_section_t *pSec)
{
if (pSec)
return(pSec->m_pData);
else
RC_THROW(RC_ERR_USE);
return(0); /* Not reached */
}
const char *sectionGetdata(rc_section_t *pSec)
{ /* Data of section, this is the script body of the particular section */
/* ATTENTION: data section may be NULL */
if (pSec) {
const char *kszScriptdata = scriptGetdata(pSec->m_pData);
/* FIXME mlelstv -- why is an empty section NULL ? */
if (kszScriptdata && strlen(kszScriptdata) > 0)
return(kszScriptdata);
else
return NULL;
}
else
RC_THROW(RC_ERR_USE);
return(0); /* Not reached */
}
/************************************************
* sectionSetXXX(rc_section_t *) *
* Accessor methods *
************************************************/
rc_return_t sectionSetpri(rc_section_t *pSec, long nPriority)
{ /* Priority of section, used to order sections during exec|eval|print */
if (pSec) {
pSec->m_nPri = nPriority;
return(RC_THROW(RC_OK));
}
return(RC_THROW(RC_ERR_USE));
}
rc_return_t sectionSetuid(rc_section_t *pSec, long nUserid)
{ /* Userid of section, used with setuid during exec or eval */
if (pSec) {
pSec->m_nUid = nUserid;
return(RC_THROW(RC_OK));
}
return(RC_THROW(RC_ERR_USE));
}
rc_return_t sectionSetname(rc_section_t *pSec, const char *szName)
{ /* Name of section, used for display during verbose */
if (pSec) {
pSec->m_szName = malloc((strlen(szName) + 1) * sizeof (char));
strcpy(pSec->m_szName, szName);
return(RC_THROW(RC_OK));
}
return(RC_THROW(RC_ERR_USE));
}
rc_return_t sectionSetparent(rc_section_t *pSec, const char *szName)
{ /* Parent rcfile name of section, used for display during verbose */
if (pSec) {
pSec->m_szParent = malloc((strlen(szName) + 1) * sizeof (char));
strcpy(pSec->m_szParent, szName);
return(RC_THROW(RC_OK));
}
return(RC_THROW(RC_ERR_USE));
}
rc_return_t sectionSetlogin(rc_section_t *pSec, const char *szLogin)
{ /* User name of section, used for display during print */
if (pSec) {
pSec->m_szLogin = malloc((strlen(szLogin) + 1) * sizeof (char));
strcpy(pSec->m_szLogin, szLogin);
return(RC_THROW(RC_OK));
}
return(RC_THROW(RC_ERR_USE));
}
rc_return_t sectionSetdata(rc_section_t *pSec, const char *kszIn)
{ /* Data of section, this is the script body of the particular section */
assert(pSec && kszIn);
if (scriptGetdata(pSec->m_pData)) { /* The section data is already in use */
scriptDelete(pSec->m_pData);
pSec->m_pData = scriptNew();
}
scriptSetdata(pSec->m_pData, kszIn);
return(RC_THROW(RC_OK));
}
rc_return_t sectionSetndata(rc_section_t *pSec, const char *kszIn, size_t Len)
{ /* Data of section, this is the script body of the particular section */
char *szTemp = NULL;
size_t nBytes = (Len + 1) * sizeof(char); /* Set size */
/* copy data with terminating NUL character */
szTemp = malloc(nBytes);
strncpy(szTemp, kszIn, Len);
*(szTemp + Len) = '\0'; /* Terminate outgoing */
/* FIXME mlelstv -- how to do exception handling ?? */
sectionSetdata(pSec, szTemp); /* Finish the job */
free(szTemp); /* Deallocate */
szTemp = NULL;
return(RC_THROW(RC_OK));
}
/************************************************
* sectionDump(rc_section_t *) *
* Print a section to standard out *
************************************************/
rc_return_t sectionDump(rc_section_t *pSec)
{
const char *szLogin = NULL;
if (pSec) {
if ((szLogin = sectionGetlogin(pSec)) != NULL)
fprintf(stdout, "#su %s\n", szLogin);
fprintf(stdout, "%s", sectionGetdata(pSec));
return(RC_THROW(RC_OK));
}
else
return(RC_THROW(RC_ERR_USE));
}
/************************************************
* sectionWrite(rc_section_t *, const char *) *
* Print a section to a file *
************************************************/
rc_return_t sectionWrite(rc_section_t *pSec, const char *szPath)
{
int nFdtmp = -1;
FILE *pStream = NULL;
/* Parameter sanity checks */
if (!pSec)
return(RC_THROW(RC_ERR_USE));
/* open file with restricted mode 0600 to preserve privacy */
nFdtmp = open(szPath, O_WRONLY | O_CREAT, 0600);
if (nFdtmp < 0)
return(RC_THROW(RC_ERR_USE));
pStream = fdopen(nFdtmp, "w");
if (pStream == NULL) {
close(nFdtmp);
unlink(szPath);
return(RC_THROW(RC_ERR_USE));
}
fprintf(pStream, "#su %s\n", sectionGetlogin(pSec));
fprintf(pStream, "%s", sectionGetdata(pSec));
fclose(pStream);
/* this file is deleted by user, no cleanup necessary */
return(RC_THROW(RC_OK));
}
/************************************************
* sectionDelete(rc_section_t *) *
* Destruct a section *
************************************************/
rc_return_t sectionDelete(rc_section_t *pSec)
{
/* Cleanup our junk */
if (pSec) {
if (pSec->m_pData) {
scriptDelete(pSec->m_pData);
pSec->m_pData = NULL;
}
if (pSec->m_szName) {
free(pSec->m_szName);
pSec->m_szName = NULL;
}
if (pSec->m_szLogin) {
free(pSec->m_szLogin);
pSec->m_szLogin = NULL;
}
free(pSec);
}
else /* Dumbass passed an empty section object */
return(RC_THROW(RC_ERR_USE));
return(RC_THROW(RC_OK));
}