/* 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 ** ** 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 /* For string copy and such data ops */ #include /* For memory ops */ #include /* For mktemp(3) */ #include /* 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)); }