From 8972c51811e39f35bbce70fdd07bb7dbd3e51bf9 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 13 Nov 2008 13:30:49 +0100 Subject: finished with ipaaction, time for some cleanup --- ipaaction/ipaaction_example_policy.xml | 14 +- worker/Makefile | 4 +- worker/worker.c | 424 ++++++++++++++++++++++++++++++--- 3 files changed, 400 insertions(+), 42 deletions(-) diff --git a/ipaaction/ipaaction_example_policy.xml b/ipaaction/ipaaction_example_policy.xml index 3ca7e51..d2b9045 100644 --- a/ipaaction/ipaaction_example_policy.xml +++ b/ipaaction/ipaaction_example_policy.xml @@ -11,13 +11,14 @@ - test -e /etc/redhat-release + /usr/bin/test -e /etc/redhat-release + nobody http://my.server.org/something.txt /tmp/something.txt nobody - nogroup + nobody 0444 unconfined_u:object_r:user_home_t:s0 user:dummy:rw- @@ -26,15 +27,8 @@ /bin/rm /tmp/something.txt - admin + adm - - VGhpcyBpcyBhIHRlc3QK - /tmp/something_other.txt - nobody - nogroup - 0444 - diff --git a/worker/Makefile b/worker/Makefile index 17a9c8c..f1d6808 100644 --- a/worker/Makefile +++ b/worker/Makefile @@ -1,6 +1,6 @@ -CFLAGS=-Wall -Werror `xml2-config --cflags` `xslt-config --cflags` -g -LDFLAGS=`xml2-config --libs` `xslt-config --libs` -g +CFLAGS=-Wall -Werror `xml2-config --cflags` `xslt-config --cflags` `curl-config --cflags` -g +LDFLAGS=`xml2-config --libs` `xslt-config --libs` `curl-config --libs` -g INDENTFLAGS=-kr -nut -l80 SRCS = worker.c debug.c diff --git a/worker/worker.c b/worker/worker.c index 6bfc069..efd7706 100644 --- a/worker/worker.c +++ b/worker/worker.c @@ -26,6 +26,12 @@ #include #include +#include + +#include +#include + + #include "util.h" #define XMLCHARLEN 255 @@ -43,7 +49,33 @@ xmlChar *default_namespace_prefix = (xmlChar *) "def"; #define XSLT_METADATA_NAMESPACE (xmlChar *) "http://freeipa.org/xsl/metadata/1.0" #define XSLT_METADATA_NAMESPACE_PREFIX (xmlChar *) "md" -#define XPATH_OUTPUT_HANDLER (xmlChar *) "//md:output_handler/*" +#define XPATH_OUTPUT_HANDLER (xmlChar *) "//md:output_handler/md:*" + +int open_temporary_file(char *name, const char *permission, const uid_t uid, const gid_t gid, const char *selinux_context_string) { + int fd; + int ret; + + fd=mkstemp(name); + if (fd==-1) { + DEBUG(0,("mkstemp failed with template %s: %s\n",name, strerror(errno))); + return -1; + } + + ret=fchmod(fd, (mode_t) strtol(permission, NULL, 8)); + CHECK(ret, -1, ("Cannot chmod temporary file to %s: %s\n", permission, strerror(errno)), return -1); + + ret=fchown(fd, uid, gid); + CHECK(ret, -1, ("Cannot chown temporary file to uid %d and gid %d: %s\n", uid, gid, strerror(errno)), return -1); + + if (selinux_context_string != NULL ) { + + ret=fsetfilecon(fd, (security_context_t ) selinux_context_string); + CHECK(ret, -1, ("fsetfilecon failed: %s\n",strerror(errno)), return -1); + + } + + return fd; +} int exec_command(const char *command, const uid_t uid, const gid_t gid, char *arguments, char *extra_args) { char *argv[10]; /* FIXME */ @@ -82,12 +114,12 @@ int exec_command(const char *command, const uid_t uid, const gid_t gid, char *ar } ret=pipe(stdout_pipe); - CHECK(ret, -1, ("pipe failed: %s\n",strerror(errno)), return(-1)); + CHECK(ret, -1, ("pipe failed: %s\n",strerror(errno)), return -1); ret=pipe(stderr_pipe); - CHECK(ret, -1, ("pipe failed: %s\n",strerror(errno)), return(-1)); + CHECK(ret, -1, ("pipe failed: %s\n",strerror(errno)), return -1); pid=fork(); - CHECK(pid, -1, ("fork failed: %s",strerror(errno)), return(-1)); + CHECK(pid, -1, ("fork failed: %s",strerror(errno)), return -1); if (!pid) { /* FIXME: missing error checking */ close(stdout_pipe[0]); @@ -97,11 +129,14 @@ int exec_command(const char *command, const uid_t uid, const gid_t gid, char *ar CHECK(ret, -1, ("dup2 failed: %s\n",strerror(errno)), exit(1)); ret=dup2(stderr_pipe[1], STDERR_FILENO); CHECK(ret, -1, ("dup2 failed: %s\n",strerror(errno)), exit(1)); + close(STDIN_FILENO); - ret=setuid(uid); - CHECK(ret, -1, ("setuid failed: %s\n",strerror(errno)), exit(1)); + ret=chdir("/"); + CHECK(ret, -1, ("chdir to / failed: %s\n",strerror(errno)), exit(1)); ret=setgid(gid); CHECK(ret, -1, ("setgid failed: %s\n",strerror(errno)), exit(1)); + ret=setuid(uid); + CHECK(ret, -1, ("setuid failed: %s\n",strerror(errno)), exit(1)); execv(command, argv); } @@ -129,7 +164,7 @@ int exec_command(const char *command, const uid_t uid, const gid_t gid, char *ar for(i=0;ipw_uid, grp_info->gr_gid, NULL); + /* fd=mkstemp(tmp_file_name); if (fd==-1) { DEBUG(0,("mkstemp failed with template %s: %s\n",tmp_file_name, strerror(errno))); free(name); - return(-1); + return -1; } ret=fchmod(fd, (mode_t) strtol(permission, NULL, 8)); @@ -230,6 +267,7 @@ int output_handler_file(xmlNode *node, const xmlDocPtr doc, const char *xslt_fil ret=fchown(fd, pwd_info->pw_uid, grp_info->gr_gid); CHECK_MINUS_ONE_RETURN(ret, ("Cannot chown temporary file to %s:%s: %s\n", owner, group, strerror(errno))); + */ parsed_stylesheet = xsltParseStylesheetFile((xmlChar *) xslt_file_name); CHECK_NULL_FATAL(parsed_stylesheet, ("Cannot parse stylesheet!\n")); @@ -256,7 +294,7 @@ int output_handler_file(xmlNode *node, const xmlDocPtr doc, const char *xslt_fil free(permission); free(param_name); free(param_value); - return(0); + return 0; } int output_handler_exec_with_args(xmlNode *node, const xmlDocPtr doc, const char *xslt_file_name) { @@ -282,7 +320,7 @@ int output_handler_exec_with_args(xmlNode *node, const xmlDocPtr doc, const char if( (ret=stat(command, &stat_buffer)) == -1) { DEBUG(0,("stat on %s failed: %s\n",command, strerror(errno))); free(command); - return(-1); + return -1; } @@ -292,7 +330,7 @@ int output_handler_exec_with_args(xmlNode *node, const xmlDocPtr doc, const char pwd_info=getpwnam(user); CHECK_NULL_RETURN(pwd_info, ("Cannot find user %s.\n", user)); - group=get_output_handler_parameter(node, "group", "nogroup", 0); + group=get_output_handler_parameter(node, "group", "nobody", 0); grp_info=getgrnam(group); CHECK_NULL_RETURN(grp_info, ("Cannot find group %s.\n", group)); @@ -329,7 +367,7 @@ int output_handler_exec_with_args(xmlNode *node, const xmlDocPtr doc, const char free(group); free(param_name); free(param_value); - return(0); + return 0; } int print_all_attributes(xmlNode *node) { @@ -340,7 +378,7 @@ int print_all_attributes(xmlNode *node) { DEBUG(3, ("found attribute '%s' with value '%s'.\n", cur->name, XML_GET_CONTENT(cur->children))); cur=cur->next; } - return(0); + return 0; } int find_output_handler(const xmlDocPtr doc, const char *xslt_file_name) { @@ -400,7 +438,7 @@ int find_output_handler(const xmlDocPtr doc, const char *xslt_file_name) { return 0; } -char *find_value_by_xpath(xmlDocPtr doc, xmlChar * xpath_expr, xmlChar * prefix, +char *find_name_by_xpath(xmlDocPtr doc, xmlChar * xpath_expr, xmlChar * prefix, xmlChar * namespace) { @@ -430,6 +468,57 @@ char *find_value_by_xpath(xmlDocPtr doc, xmlChar * xpath_expr, xmlChar * prefix, return (NULL); } + if (xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) { + DEBUG(0, ("Nothing found for %s\n", xpath_expr)); + xmlXPathFreeObject(xpath_obj); + xmlXPathFreeContext(xpath_context); + return (NULL); + } else if (xmlXPathNodeSetGetLength(xpath_obj->nodesetval) != 1) { + DEBUG(0, ("More than one node found for %s!", xpath_expr)); + xmlXPathFreeObject(xpath_obj); + xmlXPathFreeContext(xpath_context); + return (NULL); + } else { + result = strdup((char *) xpath_obj->nodesetval->nodeTab[0]->name); + } + + + xmlXPathFreeObject(xpath_obj); + xmlXPathFreeContext(xpath_context); + return result; + +} + +char *find_value_by_xpath(const xmlDocPtr doc, const xmlChar * xpath_expr, const xmlChar * prefix, + const xmlChar * namespace) +{ + + xmlXPathContextPtr xpath_context; + xmlXPathObjectPtr xpath_obj; + char *result = NULL; + + /* Create xpath evaluation context */ + xpath_context = xmlXPathNewContext(doc); + CHECK_NULL_FATAL(xpath_context, + ("Error: unable to create new XPath context\n")); + /* Register a namespace */ + if (xmlXPathRegisterNs(xpath_context, prefix, namespace) != 0) { + DEBUG(0, + ("Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", + prefix , namespace)); + xmlXPathFreeContext(xpath_context); + return (NULL); + } + /* Evaluate xpath expression */ + xpath_obj = xmlXPathEvalExpression(xpath_expr, xpath_context); + if (xpath_obj == NULL) { + DEBUG(0, + ("Error: unable to evaluate xpath expression \"%s\"\n", + xpath_expr)); + xmlXPathFreeContext(xpath_context); + return (NULL); + } + if (xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) { DEBUG(0, ("Nothing found for %s\n", xpath_expr)); xmlXPathFreeObject(xpath_obj); @@ -454,6 +543,264 @@ char *find_value_by_xpath(xmlDocPtr doc, xmlChar * xpath_expr, xmlChar * prefix, } +int check_ipaaction_condition(const xmlDocPtr doc, const xmlChar *default_namespace) { + char *condition; + char *user; + char *group; + struct passwd *pwd_info; + struct group *grp_info; + int ret; + char *arguments; + + condition = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:condition/def:command", + default_namespace_prefix, default_namespace); + if ( condition==NULL ) { + DEBUG(3, ("No condition found for current ipaaction.\n")); + return 0; + } + DEBUG(3, ("Found condition for current ipaaction: |%s|\n", condition)); + + user = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:condition/def:user", + default_namespace_prefix, default_namespace); + if (user==NULL) { + DEBUG(3, ("User for condition not found, using default")); + user=strdup("nobody"); + } + DEBUG(3, ("Found user for condition: %s\n", user)); + pwd_info=getpwnam(user); + CHECK(pwd_info, NULL, ("Cannot find user %s.\n", user), return -1); + + group = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:condition/def:group", + default_namespace_prefix, default_namespace); + if (group==NULL) { + DEBUG(3, ("Group for condition not found, using default\n")); + group=strdup("nobody"); + } + DEBUG(3, ("Found group for condition: %s\n", group)); + grp_info=getgrnam(group); + CHECK(grp_info, NULL, ("Cannot find group %s.\n", group), return -1); + + arguments=strchr(condition,' '); + if (arguments!=NULL) { + *arguments++='\0'; + } + + ret=exec_command(condition, pwd_info->pw_uid, grp_info->gr_gid, arguments, NULL); + + free(group); + free(user); + free(condition); + + return ret; +} + +int ipaaction_file(const xmlDocPtr doc, const xmlChar *default_namespace) { + char *url; + char *data; + char *path; + char *owner; + char *group; + char *access; + char *selinux_context; + //char **acl; + char *cleanup; + struct passwd *pwd_info; + struct group *grp_info; + CURL *curl_context; + CURLcode curl_result; + char *tmp_file_name; + FILE *output_file; + int fd; + int ret; + struct stat stat_buffer; + + url = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:file/def:url", + default_namespace_prefix, default_namespace); + DEBUG(3, ("Found the following ipaaction file url: |%s|\n", url)); + data = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:file/def:data", + default_namespace_prefix, default_namespace); + DEBUG(3, ("Found the following ipaaction file data: |%s|\n", data)); + if (url==NULL && data==NULL) { + DEBUG(0,("Found no url or data element for ipaaction file. This should never happen.\n")); + return -1; + } + if (url!=NULL && data!=NULL) { + DEBUG(0,("Only url or data element are allowed for ipaaction file, not both. This should never happen.\n")); + return -1; + } + + path = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:file/def:path", + default_namespace_prefix, default_namespace); + CHECK(path, NULL, ("Path for ipaaction file not found.\n"), return -1); + DEBUG(3, ("Found path for ipaaction file: %s\n", path)); + ret=stat(path, &stat_buffer); + CHECK(ret, 0, ("Destination file %s alread exists.\n", path), return -1); + + owner = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:file/def:owner", + default_namespace_prefix, default_namespace); + if (owner==NULL) { + DEBUG(3, ("Owner for ipaaction file not found, using default\n")); + owner=strdup("root"); + } + DEBUG(3, ("Found owner for ipaaction file: %s\n", owner)); + pwd_info=getpwnam(owner); + CHECK(pwd_info, NULL, ("Cannot find user %s.\n", owner), return -1); + + group = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:file/def:group", + default_namespace_prefix, default_namespace); + if (group==NULL) { + DEBUG(3, ("Group for ipaaction file not found, using default\n")); + group=strdup("root"); + } + DEBUG(3, ("Found group for ipaaction file: %s\n", group)); + grp_info=getgrnam(group); + CHECK(grp_info, NULL, ("Cannot find group %s.\n", group), return -1); + + access = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:file/def:access", + default_namespace_prefix, default_namespace); + if (access==NULL) { + DEBUG(3, ("Access permissions for ipaaction file not found, using default\n")); + group=strdup("0400"); + } + DEBUG(3, ("Found access permissions for ipaaction file: %s\n", access)); + + selinux_context = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:file/def:selinux_context", + default_namespace_prefix, default_namespace); + if (selinux_context==NULL) { + DEBUG(3, ("SELinux file context for ipaaction file not found, using none\n")); + selinux_context=NULL; + } + DEBUG(3, ("Found SELinux file context for ipaaction file: %s\n", selinux_context)); + + cleanup = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:file/def:cleanup", + default_namespace_prefix, default_namespace); + if (cleanup==NULL) { + DEBUG(3, ("No cleanup information for ipaaction file not found, assuming no\n")); + cleanup=strdup("no"); + } + DEBUG(3, ("Found cleanup information for ipaaction file: %s\n", cleanup)); + + + tmp_file_name=(char *) malloc(strlen(path)+7); + CHECK(tmp_file_name,NULL, ("malloc failed."), return -1); + strcpy(tmp_file_name, path); + strcat(tmp_file_name, ".XXXXXX"); + fd=open_temporary_file(tmp_file_name, access, pwd_info->pw_uid, grp_info->gr_gid, selinux_context); + CHECK(fd, -1, ("Failed to open temporary file.\n"), return -1); + output_file=fdopen(fd,"w"); + CHECK(output_file, NULL, ("fdopen failed: %s\n", strerror(errno)), return -1); + if (url!=NULL) { + curl_context=curl_easy_init(); + CHECK(curl_context, NULL, ("curl_easy_init failed.\n"), return -1); + curl_result=curl_easy_setopt(curl_context, CURLOPT_URL, url); + DEBUG(3,("curl result: %d\n",curl_result)); + curl_result=curl_easy_setopt(curl_context, CURLOPT_WRITEDATA, output_file); + DEBUG(3,("curl result: %d\n",curl_result)); + + curl_result=curl_easy_perform(curl_context); + DEBUG(3,("curl result: %d\n",curl_result)); + + curl_easy_cleanup(curl_context); + } + + fclose(output_file); /* this should close fd, too */ + ret=rename(tmp_file_name, path); + CHECK_MINUS_ONE_RETURN(ret, ("Cannot rename %s to %s: %s\n", tmp_file_name, path, strerror(errno) )); + free(tmp_file_name); + + return 0; +} + +int ipaaction_run(const xmlDocPtr doc, const xmlChar *default_namespace) { + char *command; + char *user; + char *group; + struct passwd *pwd_info; + struct group *grp_info; + int ret; + char *arguments; + + command = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:run/def:command", + default_namespace_prefix, default_namespace); + CHECK(command, NULL, + ("No command in ipaaction run section found, this should neven happen.\n"), + return -1); + DEBUG(3, ("Found command for current ipaaction: |%s|\n", command)); + + user = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:run/def:user", + default_namespace_prefix, default_namespace); + if (user==NULL) { + DEBUG(3, ("User for ipaaction run command not found, using default")); + user=strdup("nobody"); + } + DEBUG(3, ("Found user for ipaaction run command: %s\n", user)); + pwd_info=getpwnam(user); + CHECK(pwd_info, NULL, ("Cannot find user %s.\n", user), return -1); + + group = find_value_by_xpath(doc, + (xmlChar *) "//def:ipa/def:ipaaction/def:run/def:group", + default_namespace_prefix, default_namespace); + if (group==NULL) { + DEBUG(3, ("Group for ipaaction run command not found, using default\n")); + group=strdup("nobody"); + } + DEBUG(3, ("Found group for ipaaction run command: %s\n", group)); + grp_info=getgrnam(group); + CHECK(grp_info, NULL, ("Cannot find group %s.\n", group), return -1); + + arguments=strchr(command,' '); + if (arguments!=NULL) { + *arguments++='\0'; + } + + ret=exec_command(command, pwd_info->pw_uid, grp_info->gr_gid, arguments, NULL); + + free(group); + free(user); + free(command); + + return ret; + + return 0; +} + +int handle_ipaaction(const xmlDocPtr doc, const xmlChar *default_namespace) { + int ret; + + ret=check_ipaaction_condition(doc, default_namespace); + if (ret!=0) { + DEBUG(0,("IPA action condition failed\n")); + return -1; + } + + ret=ipaaction_file(doc, default_namespace); + if (ret!=0) { + DEBUG(0,("IPA action file failed\n")); + return -1; + } + + ret=ipaaction_run(doc, default_namespace); + if (ret!=0) { + DEBUG(0,("IPA action run failed\n")); + return -1; + } + + return 0; +} + int main(int argc, char **argv) { @@ -465,6 +812,7 @@ int main(int argc, char **argv) char *xslt_file_name; xmlRelaxNGValidCtxtPtr rng_context; xmlDocPtr xslt_doc; + char *ipa_policy_type; if (argc != 2) { DEBUG(0, @@ -491,14 +839,18 @@ int main(int argc, char **argv) CHECK_NULL_FATAL(default_namespace, ("Cannot copy namespace!\n")); DEBUG(3, ("Default namespace of %s is %s\n", argv[1], default_namespace)); - /* extract XSTLfile and RNGfile from document using XPath */ - xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:XSLTfile", + + xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:ipa/*[2]", default_namespace_prefix); - xslt_file_name = - find_value_by_xpath(doc, xpath_expr, default_namespace_prefix, - default_namespace); - CHECK_NULL_FATAL(xslt_file_name, ("Name of XSLT file not found.\n")); - DEBUG(3, ("Found name of XSLT file: %s\n", xslt_file_name)); + ipa_policy_type = find_name_by_xpath(doc, xpath_expr, default_namespace_prefix, default_namespace); + CHECK_NULL_FATAL(ipa_policy_type, ("Type of IPA policy not found.\n")); + DEBUG(3, ("Found IPA policy type: %s\n", ipa_policy_type)); + if ( strncmp(ipa_policy_type, "ipaconfig",9) != 0 && + strncmp(ipa_policy_type, "iparole",7) != 0 && + strncmp(ipa_policy_type, "ipaaction",9) != 0) { + DEBUG(0,("unknown IPA ploicy type\n")); + exit(1); + } xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:RNGfile", default_namespace_prefix); @@ -527,13 +879,25 @@ int main(int argc, char **argv) free(rng_file_name); - /* read the xslt file */ - xslt_doc = xmlParseFile(xslt_file_name); - CHECK_NULL_FATAL(xslt_doc, ("Cannot parse file %s!\n", xslt_file_name)); + if ( strncmp( ipa_policy_type, "ipaaction", 9)==0) { + handle_ipaaction(doc, default_namespace); + } else { + xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:XSLTfile", + default_namespace_prefix); + xslt_file_name = + find_value_by_xpath(doc, xpath_expr, default_namespace_prefix, + default_namespace); + CHECK_NULL_FATAL(xslt_file_name, ("Name of XSLT file not found.\n")); + DEBUG(3, ("Found name of XSLT file: %s\n", xslt_file_name)); - find_output_handler(doc, xslt_file_name); + /* read the xslt file */ + xslt_doc = xmlParseFile(xslt_file_name); + CHECK_NULL_FATAL(xslt_doc, ("Cannot parse file %s!\n", xslt_file_name)); - free(xslt_file_name); + find_output_handler(doc, xslt_file_name); + + free(xslt_file_name); + } xmlFreeDoc(doc); -- cgit