/* $CoreSDI: ia_list.c,v 1.22 2001/08/28 23:06:08 claudio Exp $ */ /* * Copyright (c) 2000, 2001, Core SDI S.A., Argentina * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither name of the Core SDI S.A. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 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 AUTHOR 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. */ /* * Information Accessing support functions * Author: Claudio Castiglia */ #ifndef WIN32 #include #endif #ifdef __linux__ #include /* in_addr_t */ #endif #include #include #include #include #include #include "sysdep.h" #include "packet.h" #include "resource.h" #include "modtypes.h" #include "modules.h" #include "ia_list.h" #include "ia_perm.h" #include "iaargs.h" #include "log.h" #define WHITE_SPACE " \f\n\r\t\v" static ATTR * _create_attr (ATTR *, ATTRCON *); static void _release_attr (ATTR *); static int _logset_set_name (LOGSET_INFO *, const char *); static unsigned int _resperm2uint (const char *, ssize_t); static void _logset_set_perms (LOGSET_INFO *, RESLIST *, unsigned int *); static int _compare_cmd_line (CMD_LINE *, CMD_LINE *); static void _remove_raw_logset (RAW_LOGSET *); /* * _create_attr(): * Create ATTR entry and add it into the list. * on success return a pointer to the newly created entry, * on error NULL is returned and errno set. */ static ATTR * _create_attr(ATTR *prev, ATTRCON *context) { ATTR *attr; if (context == NULL) return (NULL); if ( (attr = (ATTR *) malloc(sizeof(ATTR))) == NULL) return (NULL); if (prev != NULL) prev->next = attr; attr->atcon = context; attr->next = NULL; return (attr); } /* * _release_attr(): * Release ATTR list. */ static void _release_attr(ATTR *list) { ATTR *i; if (list != NULL) { for (i = list; i != NULL; i = i->next) release_module((void *) i->atcon); free(list); } } /* * _logset_set_name(): * Add a name into the logset; * return 0 on success or -1 on error and set errno. */ static int _logset_set_name(LOGSET_INFO *list, const char *name) { const char **tmp; if (name != NULL) { tmp = (const char **) realloc((void *) list->names_str, sizeof(const char *) * (list->names + 1)); if (tmp == NULL) return (-1); list->names_str = tmp; list->names_str[list->names++] = name; } return (0); } /* * _resperm2uint(): * Convert a resource string indicating logset_info * perms to unsigned int and return it. */ static unsigned int _resperm2uint(const char *string, ssize_t size) { unsigned int perms, i; static struct { char code; unsigned int perm; } permcodes[PERM_IA_COMMANDS] = { { 'L', PERM_LIST }, { 'I', PERM_INFO }, { 'G', PERM_GET }, { 'R', PERM_ROTATE }, { 'Z', PERM_ZAP }, { 'S', PERM_SIGN } }; perms = 0; for (size--; size >= 0; size--) for (i = 0; i < PERM_IA_COMMANDS; i++) if (toupper(string[size]) == permcodes[i].code) { perms |= permcodes[i].perm; break; } return (perms); } /* * _logset_set_perms(): * Set logset permissions for current user. */ static void _logset_set_perms(LOGSET_INFO *list, RESLIST *reslist, unsigned int *generic_perms) { int i; unsigned int perms; char resname[MAXPATHLEN]; RESOURCE *rperms; /* Get generic permissions */ if (*generic_perms == PERM_INVALID) { if ( (rperms = res_find(reslist, IAPERMS_RNAME)) == NULL) *generic_perms = 0; else *generic_perms = _resperm2uint(rperms->data, rperms->dsize); } /* * Search permissions for all names for each * logset and generate perms based on all of them. */ perms = PERM_INVALID; for (i = 0; i < list->names; i++) { snprintf(resname, sizeof(resname), IAPERMS_RNAME "_%s", list->names_str[i]); if ( (rperms = res_find(reslist, resname)) != NULL) { if (perms == PERM_INVALID) perms = 0; perms |= _resperm2uint(rperms->data, rperms->dsize); } } /* Set permissions */ list->perms = (perms == PERM_INVALID) ? *generic_perms : perms; } /* * _compare_cmd_line(): * Compare two cmd_line variables and return 0 if they are equals. * NOTE: If both variables have identical data but differ in order, * they are equal. */ static int _compare_cmd_line(CMD_LINE *a, CMD_LINE *b) { int collisions, i, j; if (a->argc != b->argc) return (1); collisions = 0; for (i = 0; i < a->argc; i++) for (j = 0; j < b->argc; j++) if (!strcmp(a->argv[i], b->argv[j])) { collisions++; break; } return ((collisions == a->argc) ? 0 : 1); } /* * _remove_raw_logset(): * Remove and release a single RAW_LOGSET from the list. */ static void _remove_raw_logset(RAW_LOGSET *rawset) { if (rawset->prev != NULL) rawset->prev->next = rawset->next; if (rawset->next != NULL) rawset->next->prev = rawset->prev; rawset->prev = rawset->next = NULL; release_raw_logset(rawset); } /* * create_cmd_line(): * Create CMD_LINE entry and add it into the list. * on success return a pointer to the newly created entry, * on error NULL is returned and errno set. * NOTE: double and simple quotes are detected (" and '). */ CMD_LINE * create_cmd_line(CMD_LINE *prev, char *line) { CMD_LINE *cmd; char *p, *w, **tmp, quote; if (line == NULL) return (NULL); if ( (cmd = (CMD_LINE *) malloc(sizeof(CMD_LINE))) == NULL) return (NULL); if ( (cmd->data = strdup(line)) == NULL) { free(cmd); return (NULL); } cmd->argc = 0; cmd->argv = NULL; cmd->next = NULL; p = cmd->data; while (p != NULL) { p += strspn(p, WHITE_SPACE); if (*p == '\0') break; w = p; if (*p == '\"' || *p == '\'') { quote = *p; p++; w++; for (; *p != quote && *p != '\0'; p++); if (*p == quote) *p++ = '\0'; } tmp = (char **) realloc(cmd->argv, sizeof(char **) * (cmd->argc + 1)); if (tmp == NULL) { release_cmd_line(cmd); return (NULL); } cmd->argv = tmp; cmd->argv[cmd->argc++] = w; strsep(&p, WHITE_SPACE); } if (prev != NULL) prev->next = cmd; return (cmd); } /* * release_cmd_line(): * Release a CMD_LINE list. */ void release_cmd_line(CMD_LINE *list) { CMD_LINE *i; if (list != NULL) { for (i = list; i != NULL; i = i->next) { if (i->argv != NULL) free(i->argv); if (i->data != NULL) free(i->data); } free(list); } } /* * create_raw_logset(): * Create a RAW_LOGSET entry and add it into the list. * on success return a pointer to the new entry, * on error NULL is returned and errno set. */ RAW_LOGSET * create_raw_logset(RAW_LOGSET *prev, CMD_LINE *cmd) { RAW_LOGSET *rawset; if (cmd == NULL) return (NULL); if ( (rawset = (RAW_LOGSET *) calloc(1, sizeof(RAW_LOGSET))) == NULL) return (NULL); rawset->cmd = cmd; rawset->prev = prev; if (prev != NULL) prev->next = rawset; return (rawset); } /* * release_raw_logset(): * Release a RAW_LOGSET list. */ void release_raw_logset(RAW_LOGSET *list) { RAW_LOGSET *i; if (list != NULL) { for (i = list; i != NULL; i = i->next) release_cmd_line(i->cmd); free(list); } } /* * remove_raw_logset_dups(): * Remove duplicated data in the raw_logset list. */ void remove_raw_logset_dups(RAW_LOGSET *rawlist) { RAW_LOGSET *p, *n; if (rawlist != NULL) for (p = rawlist; p != NULL; p = p->next) for (n = p->next; n != NULL; n = n->next) if (!_compare_cmd_line(p->cmd, n->cmd)) { _remove_raw_logset(n); break; } } /* * create_logset_info(): * Create a LOGSET_INFO item and return it into 'ret_logset' pointer; * return 0 on success or -1 on error and set errno. * NOTE: If user has not permissions the item is not created * (this is not considered an error). */ int create_logset_info(LOGSET_INFO *prev, RAW_LOGSET *rawdata, SESSION *s, unsigned int *generic_perms, LOGSET_INFO **ret_logset) { LOGSET_INFO *litem; CMD_LINE *cmd; ATTR *attr; ATTRCON *atcon; struct attrargs_init init_args; struct attrargs_ret proc_args; /* Create LOGSET_INFO item */ if (rawdata == NULL || generic_perms == NULL) { errno = EINVAL; return (-1); } if ( (litem = (LOGSET_INFO *) calloc(1, sizeof(LOGSET_INFO))) == NULL) return (-1); /* Load and initialize all ATTRIBUTE modules */ attr = NULL; for (cmd = rawdata->cmd; cmd != NULL; cmd = cmd->next) if (cmd->argc > 0) { /* Load and initialize attribute module */ init_args.argc = cmd->argc; init_args.argv = cmd->argv; atcon = load_attr(cmd->argv[0], s, &init_args); if (atcon == NULL) { release_logset_info(litem); return (-1); } /* Add it into the attribute list */ if ( (attr = _create_attr(attr, atcon)) == NULL) { release_module((void *) atcon); release_logset_info(litem); return (-1); } if (litem->attr == NULL) litem->attr = attr; /* Get another name for this logset */ atcon->mod.proc_entry(ATTR_GET_LOGSET_NAME, atcon, &proc_args); if (proc_args.size != 0) if (_logset_set_name(litem, proc_args.data) < 0) { release_logset_info(litem); return (-1); } } _logset_set_perms(litem, s->s_rlist, generic_perms); /* If user can't work with this logset, do not add it into the list */ if (litem->perms == 0) release_logset_info(litem); else { if (prev != NULL) prev->next = litem; if (ret_logset != NULL) *ret_logset = litem; } return (0); } /* * release_logset_info(): * Release a LOGSET_INFO list. */ void release_logset_info(LOGSET_INFO *list) { LOGSET_INFO *i; if (list != NULL) { for (i = list; i != NULL; i = i->next) { if (i->names_str != NULL) free((void *) i->names_str); _release_attr(i->attr); } free(list); } } /* * find_logset_info(): * Search for a logset and return it or NULL if not found. */ LOGSET_INFO * find_logset_info(LOGSET_INFO *list, const char *logset_name) { LOGSET_INFO *l; int i; /* Scan all lists */ for (l = list; l != NULL; l = l->next) { for (i = 0; i < l->names; i++) if (!strcmp(l->names_str[i], logset_name)) break; if (i < l->names) break; } return (l); }