33 static const char copyright[] =
34 "Copyright (c) 2003-2012\n\
35 Distributed Systems Software. All rights reserved.";
36 static const char revid[] =
37 "$Id: transform.c 2594 2012-10-19 17:28:49Z brachman $";
43 #include <sys/utsname.h>
45 #ifndef DACS_TRANSFORM_ACLS
46 #define DACS_TRANSFORM_ACLS "[transform-acls]dacs-fs:"DACS_HOME"/dacs_transform/acls"
49 #ifndef DACS_TRANSFORM_DOCS
50 #define DACS_TRANSFORM_DOCS DACS_HOME"/dacs_transform/docs"
53 #define DEFAULT_SGML_DIRECTIVE_PREFIX "<!--DACS "
54 #define DEFAULT_SGML_DIRECTIVE_SUFFIX "-->"
56 #ifndef DEFAULT_HTML_ANNOTATION
57 #define DEFAULT_HTML_ANNOTATION "<b>*** Content elided ***</b>"
60 static MAYBE_UNUSED const char *log_module_name =
"dacs_transform";
86 get_directive(
Kwv *kwv,
char **value,
char **errmsg)
95 for (i = 0; directive_tab[i].
name != NULL; i++) {
99 *errmsg =
"Only one directive is allowed";
111 eval(
char *expr,
Kwv *kwv_attrs,
Var_ns **namespaces,
char **result_str)
121 if (st ==
ACS_EXPR_TRUE && result_str != NULL && *result_str != NULL)
144 if (pair->
val != NULL) {
146 if (pair->
val[0] ==
'`') {
147 if (eval(p, kwv, namespaces, &newval) < 0)
164 char *e, *s, *suffix, *suffix_crlf;
173 if ((e =
strsuffix(s, slen, suffix)) == NULL
174 && (e =
strsuffix(s, slen, suffix_crlf)) == NULL)
185 is_regex_directive(
char *line, regex_t *regex,
char **startp,
char **endp,
191 if ((st = regexec(regex, line, 4, m, 0)) == 0) {
192 if (m[0].rm_so == -1 || m[1].rm_so == -1 || m[2].rm_so == -1
196 *startp = line + m[1].rm_eo;
197 *endp = line + m[2].rm_so;
200 else if (st != REG_NOMATCH) {
203 if (errmsg != NULL) {
205 regerror(st, regex, errbuf,
sizeof(errbuf));
206 *errmsg =
ds_xprintf(
"bad regular expression: \"%s\": %s",
229 Kwv *kwv_dacs,
char *op,
int invert,
char *acls,
230 char *object_name,
char *idents,
char **errmsg)
233 char **constraints, *expr, *object;
244 if (acs_expr_error_occurred(rc)) {
246 *errmsg =
ds_xprintf(
"Line %d: expansion error: \"%s\"",
261 if (strcaseeq(pair->
name, op))
263 (nargs == 0) ?
"" :
"&",
264 invert ? region + 1 : region);
267 (nargs == 0) ?
"" :
"&", pair->
name, pair->
val);
272 object =
ds_xprintf(
"%s?%s", object_name, ds_buf(&args));
274 kwv_conf, kwv_dacs, NULL, &constraints);
335 "transform_annotation");
377 Kwv *attrs,
int skip,
int expand,
char *expr)
383 stack_el->
region = region;
386 stack_el->
expr = expr;
447 if (
transform(tc,
"", NULL, errmsg) == -1)
459 if ((fp = fopen(path,
"r")) == NULL) {
461 *errmsg =
ds_xprintf(
"Cannot read \"%s\": %s", path, strerror(errno));
480 if (
transform(tc,
"", NULL, errmsg) == -1)
487 test_transform_simple(FILE *fp_out,
char *filename)
495 kwv_add(kwv,
"dog1",
"Auggie");
496 kwv_add(kwv,
"dog2",
"Harley");
497 kwv_add(kwv,
"dog3",
"Bandito");
500 if (ds_out == NULL) {
502 fprintf(stderr,
"%s\n", errmsg);
506 if ((fp = fp_out) == NULL)
508 if (ds_len(ds_out) > 0)
509 fprintf(fp,
"%s", ds_buf(ds_out));
522 int dcount, elided, expand, granted, invert, recurse, st;
523 char *buf, *e, *regex_str, *region, *line, *s, *suffix, *username;
524 char *opname, *expr_attr, *filename_attr, *uri_attr, *p;
530 Kwv *kwv_attrs, *kwv_conf, *kwv_dacs;
547 current_stackp = tc->
stackp;
563 regex_str =
ds_xprintf(
"^\\(%s\\).*\\(%s\\)\n$",
568 regex =
ALLOC(regex_t);
569 if (regcomp(regex, regex_str, 0) != 0) {
571 *errmsg =
"Invalid regular expression";
586 if (regex_str == NULL) {
587 if ((st = is_directive(tc, line, &s, &e)) == -1) {
593 else if ((st = is_regex_directive(line, regex, &s, &e, errmsg)) == -1)
608 =
ds_xprintf(
"Line %d: invalid attribute specification: \"%s\"",
613 if ((kwv_attrs = attrs(kwv, &tc->
env->
namespaces)) == NULL) {
615 *errmsg =
ds_xprintf(
"Line %d: expression evaluation error",
620 directive = get_directive(kwv_attrs, ®ion, errmsg);
627 && !strcaseeq(p,
"yes"))
645 *errmsg =
ds_xprintf(
"Line %d: DACS tag stack overflow",
650 stack_el = push_stack(tc, directive, region, kwv_attrs, 1,
656 st = region_test(tc, region, kwv_attrs, kwv_conf, kwv_dacs,
"begin",
657 invert, tc->
acls, object_name, idents, errmsg);
659 if (invert == 0 && st == 1) {
663 else if (invert == 0 && st == 0)
665 else if (invert == 1 && st == 0) {
669 else if (invert == 1 && st == 1)
673 *errmsg =
ds_xprintf(
"Line %d: access control test error",
687 *errmsg =
ds_xprintf(
"Line %d: DACS tag stack underflow",
694 *errmsg =
ds_xprintf(
"Line %d: DACS tag end mismatch",
710 if (acs_expr_error_occurred(rc)) {
713 =
ds_xprintf(
"Line %d: expression evaluation error: \"%s\"",
741 if (buf != NULL && *buf !=
'\0') {
746 *errmsg =
ds_xprintf(
"Line %d: expansion error: \"%s\"",
785 *errmsg =
ds_xprintf(
"Line %d: unrecognized HTTP method",
794 if (directive ==
D_EXPAND && dcount == 0) {
797 else if (dcount != 1) {
803 if (uri_attr != NULL) {
806 if ((uri =
uri_parse(uri_attr)) == NULL) {
808 *errmsg =
ds_xprintf(
"Line %d: invalid URI: %s",
812 if (streq(uri->
scheme,
"file")) {
815 *errmsg =
ds_xprintf(
"Line %d: invalid URI: %s",
820 filename_attr = uri->
path;
823 else if (!streq(uri->
scheme,
"http") &&
824 !streq(uri->
scheme,
"https")) {
826 *errmsg =
ds_xprintf(
"Line %d: invalid URI scheme: %s",
832 if (filename_attr != NULL) {
833 if (*filename_attr !=
'/' && *tc->
docs !=
'\0') {
842 *errmsg =
ds_xprintf(
"Line %d: DACS tag stack overflow",
848 = push_stack(tc, directive, region, kwv_attrs, 1, expand, NULL);
858 opname, username, region));
860 st = region_test(tc, region, kwv_attrs, kwv_conf, kwv_dacs, opname,
861 invert, tc->
acls, object_name, idents, errmsg);
864 if (invert == 0 && st == 1) {
868 else if (invert == 0 && st == 0)
870 else if (invert == 1 && st == 0) {
874 else if (invert == 1 && st == 1)
878 *errmsg =
ds_xprintf(
"Line %d: access control test error",
883 if (directive ==
D_EXPAND && dcount == 0 && granted)
886 if (dcount && granted) {
890 if (filename_attr != NULL) {
893 if (*filename_attr ==
'/' || tc->
insert_dir == NULL)
900 *errmsg =
ds_xprintf(
"Line %d: cannot load file: %s",
905 else if (uri_attr != NULL) {
906 int argnum, reply_len;
910 argnum, NULL, NULL, NULL, &buf, &reply_len,
917 else if (expr_attr != NULL) {
919 if (acs_expr_error_occurred(rc)) {
922 =
ds_xprintf(
"Line %d: expression evaluation error: \"%s\"",
931 if (recurse && buf != NULL) {
936 dsio_set(ds_in, NULL, buf, strlen(buf), 1);
938 ntc = transform_reconfig(tc, ds_in, ds_out);
940 if ((st =
transform(ntc, object_name, idents, errmsg)) != 0)
956 *errmsg =
ds_xprintf(
"Line %d: expansion error: \"%s\"",
975 buf, (directive ==
D_INSERT) ?
"\n" :
"");
987 st = region_test(tc, region, kwv_attrs, kwv_conf, kwv_dacs,
"id",
988 invert, tc->
acls, object_name, idents, errmsg);
991 if (invert == 0 && st == 1) {
995 else if (invert == 0 && st == 0)
997 else if (invert == 1 && st == 0) {
1001 else if (invert == 1 && st == 1)
1005 *errmsg =
ds_xprintf(
"Line %d: access control test error",
1011 struct utsname utsname;
1019 ds_asprintf(out,
"%sGenerated %s by %s %s on %s %s",
1032 st = region_test(tc, region, kwv_attrs, kwv_conf, kwv_dacs,
"debug",
1033 invert, tc->
acls, object_name, idents, errmsg);
1036 if (invert == 0 && st == 1) {
1040 else if (invert == 0 && st == 0)
1042 else if (invert == 1 && st == 0) {
1046 else if (invert == 1 && st == 1)
1050 *errmsg =
ds_xprintf(
"Line %d: access control test error",
1056 int show_attrs, show_dacs, show_conf;
1059 show_attrs = show_dacs = show_conf = 1;
1061 show_attrs = show_dacs = show_conf = 0;
1062 if (strcaseeq(p,
"Attrs"))
1064 else if (strcaseeq(p,
"DACS"))
1066 else if (strcaseeq(p,
"Conf"))
1068 else if (strcaseeq(p,
"all"))
1069 show_attrs = show_dacs = show_conf = 1;
1072 if (strcaseeq(p,
"no"))
1078 if (strcaseeq(p,
"no"))
1084 if (strcaseeq(p,
"no"))
1096 if (show_attrs &&
kwv_count(kwv_attrs, NULL) > 0)
1098 kwv_buf(kwv_attrs, (
int)
'=', (
int)
'"'));
1099 if (show_dacs &&
kwv_count(kwv_dacs, NULL) > 0)
1101 kwv_buf(kwv_dacs, (
int)
'=', (
int)
'"'));
1102 if (show_conf &&
kwv_count(kwv_conf, NULL) > 0)
1104 kwv_buf(kwv_conf, (
int)
'=', (
int)
'"'));
1128 *errmsg =
ds_xprintf(
"Line %d: DACS tag stack overflow",
1134 = push_stack(tc, directive, region, kwv_attrs, 1, expand, NULL);
1139 st = region_test(tc, region, kwv_attrs, kwv_conf, kwv_dacs,
"eval",
1140 invert, tc->
acls, object_name, idents, errmsg);
1142 if (invert == 0 && st == 1) {
1146 else if (invert == 0 && st == 0)
1148 else if (invert == 1 && st == 0) {
1152 else if (invert == 1 && st == 1)
1156 *errmsg =
ds_xprintf(
"Line %d: access control test error",
1166 st = region_test(tc, region, kwv_attrs, kwv_conf, kwv_dacs,
"set",
1167 invert, tc->
acls, object_name, idents, errmsg);
1170 if (invert == 0 && st == 1) {
1174 else if (invert == 0 && st == 0)
1176 else if (invert == 1 && st == 0) {
1180 else if (invert == 1 && st == 1)
1184 *errmsg =
ds_xprintf(
"Line %d: access control test error",
1211 *errmsg =
ds_xprintf(
"Line %d: unrecognized HTTP method",
1226 if (uri_attr != NULL) {
1228 *errmsg =
ds_xprintf(
"Line %d: unimplemented directive",
1235 *errmsg =
ds_xprintf(
"Line %d: DACS tag stack overflow",
1241 = push_stack(tc, directive, region, kwv_attrs, 1, expand, NULL);
1251 st = region_test(tc, region, kwv_attrs, kwv_conf, kwv_dacs, opname,
1252 invert, tc->
acls, object_name, idents, errmsg);
1254 if (invert == 0 && st == 1) {
1258 else if (invert == 0 && st == 0)
1260 else if (invert == 1 && st == 0) {
1264 else if (invert == 1 && st == 1)
1268 *errmsg =
ds_xprintf(
"Line %d: access control test error",
1325 if (tc->
stackp != current_stackp) {
1327 *errmsg =
"Directive tags are unbalanced";
1359 do_transform(
Transform_config *tc,
char *docname,
char *docuri,
char *name,
1360 char *idents,
char *content_type,
char **errmsg)
1363 char *doctype, *ext, *object_name;
1372 if (docname != NULL) {
1374 if (
strstr(docname,
"/../")
1375 ||
strsuffix(docname, strlen(docname),
"/") != NULL) {
1377 *errmsg =
"Invalid DOC name";
1380 if (*tc->
docs ==
'\0')
1384 if ((fp = fopen(path,
"r")) == NULL) {
1386 *errmsg =
ds_xprintf(
"Cannot load \"%s\"", path);
1393 int argnum, reply_len;
1397 if ((uri =
uri_parse(docuri)) == NULL) {
1399 *errmsg =
ds_xprintf(
"Invalid URI: %s", docuri);
1406 argnum, NULL, NULL, NULL, &reply, &reply_len,
1407 NULL, NULL) == -1) {
1416 if (docname != NULL)
1417 object_name = docname;
1424 if (object_name == NULL) {
1426 *errmsg =
"No name is available for the input document";
1429 if (*object_name !=
'/')
1430 object_name =
ds_xprintf(
"/%s", object_name);
1433 if (content_type != NULL) {
1434 if (*content_type ==
'\0')
1437 doctype = content_type;
1444 doctype =
"text/html";
1448 APACHE_HOME))) != NULL) {
1454 if (strcaseeq(ext,
".xml"))
1455 doctype =
"text/xml";
1456 else if (strcaseeq(ext,
".txt"))
1457 doctype =
"text/plain";
1463 if (doctype != NULL)
1464 printf(
"Content-Type: %s\n\n", doctype);
1466 st =
transform(tc, object_name, idents, errmsg);
1470 if (ds_len(tc->
ds_out) > 0)
1471 printf(
"%s", ds_buf(tc->
ds_out));
1486 fprintf(stderr,
"Usage: dacstransform [dacsoptions] [flags] [- | file]\n");
1487 fprintf(stderr,
"flags are composed from:\n");
1488 fprintf(stderr,
"-admin: following idents are DACS admins\n");
1489 fprintf(stderr,
"-ct str: the MIME content type string\n");
1490 fprintf(stderr,
"-docs dir: directory containing the documents\n");
1491 fprintf(stderr,
"-f: don't map the file's location\n");
1492 fprintf(stderr,
"-F sep: use sep as the field separator for roles\n");
1493 fprintf(stderr,
"-fd domain: the federation domain\n");
1494 fprintf(stderr,
"-fh hostname: the hostname\n");
1495 fprintf(stderr,
"-fj jurname: the jurisdiction name\n");
1496 fprintf(stderr,
"-fn fedname: the federation name\n");
1497 fprintf(stderr,
"-h|-help: show this help blurb\n");
1498 fprintf(stderr,
"-i ident: use ident\n");
1499 fprintf(stderr,
"-icgi: use REMOTE_USER for username\n");
1500 fprintf(stderr,
"-icgig: like -icgi but also add roles\n");
1501 fprintf(stderr,
"-ieuid: add the euid to set of identities\n");
1502 fprintf(stderr,
"-ieuidg: like -ieuid but also add its groups\n");
1503 fprintf(stderr,
"-il ident: use ident, a local name\n");
1504 fprintf(stderr,
"-ilg ident: use local ident with its Unix groups\n");
1505 fprintf(stderr,
"-insert dir: directory containing inserted documents\n");
1506 fprintf(stderr,
"-iuid: add the uid to set of identities\n");
1507 fprintf(stderr,
"-iuidg: like -iuid but also add its groups\n");
1508 fprintf(stderr,
"-lg: add Unix groups to roles of locals\n");
1509 fprintf(stderr,
"-name str: the name of the input document\n");
1510 fprintf(stderr,
"-prefix str: the directive prefix string\n");
1511 fprintf(stderr,
"-r|-rules rules_uri: where to look for rules\n");
1512 fprintf(stderr,
"-roles roles_vfs: where to look for roles\n");
1513 fprintf(stderr,
"-rprefix regex: the directive prefix, as a regex\n");
1514 fprintf(stderr,
"-rsuffix regex: the directive suffix, as a regex\n");
1515 fprintf(stderr,
"-suffix str: the directive suffix string\n");
1516 fprintf(stderr,
"-var name=value: set name to value in DACS namespace\n");
1517 fprintf(stderr,
"-x: run as an app, not a web service\n");
1518 fprintf(stderr,
"--: end of flag arguments\n");
1519 fprintf(stderr,
"\n");
1520 fprintf(stderr,
"The standard input is read if no file is specified or\n");
1521 fprintf(stderr,
"if '-' is specified. This implies the -f flag.\n");
1522 fprintf(stderr,
"Unless the -f flag appears, a file argument is mapped\n");
1523 fprintf(stderr,
"to the document directory.\n");
1524 fprintf(stderr,
"The default document directory is \"%s\"\n",
1526 fprintf(stderr,
"The default ACL URI is \"%s\"\n",
1535 int exec_run, i, st;
1536 char *content_type, *doc, *errmsg, *idents, *name, *p, *remote_addr, *uri;
1537 char *acls, *annotation, *directive_prefix, *directive_suffix, *docs;
1538 char *insert_dir, *regex_prefix, *regex_suffix;
1540 Kwv *kwv, *kwv_conf, *kwv_dacs;
1544 errmsg =
"Internal error";
1550 content_type = NULL;
1551 directive_prefix = NULL;
1552 directive_suffix = NULL;
1554 regex_prefix = NULL;
1555 regex_suffix = NULL;
1562 if ((remote_addr = getenv(
"REMOTE_ADDR")) == NULL)
1568 for (i = 0; i < argc; i++)
1569 fprintf(stderr,
"%d: \"%s\"\n", i, argv[i]);
1581 if (streq(argv[0],
"dacstransform") || streq(argv[0],
"transform")
1582 ||
strsuffix(argv[0], strlen(argv[0]),
"/dacstransform") != NULL
1583 ||
strsuffix(argv[0], strlen(argv[0]),
"/transform") != NULL) {
1584 if ((argc == 2 && argv[1][0] !=
'-')
1585 || (argc == 3 && argv[1][0] ==
'-')) {
1596 argc = dsvec_len(av) - 1;
1597 argv = (
char **) dsvec_base(av);
1604 for (i = 0; i < argc; i++)
1605 fprintf(stderr,
"%d: \"%s\"\n", i, argv[i]);
1608 for (i = 1; argv[i] != NULL; i++) {
1609 if (streq(argv[i],
"-x")) {
1616 log_module_name =
"dacstransform";
1618 log_module_name =
"dacs_transform";
1620 if (
dacs_init(app_type, &argc, &argv, &kwv, &errmsg) == -1) {
1624 fprintf(stderr,
"Error: %s\n", errmsg);
1626 fprintf(stderr,
"An error occurred\n");
1635 printf(
"<p>An error occurred during the service request.\n");
1637 printf(
"<p>Reason: %s.\n", errmsg);
1649 for (i = 1; i < argc; i++) {
1650 if (argv[i][0] !=
'-')
1660 else if (streq(argv[i],
"-docs")) {
1662 errmsg =
ds_xprintf(
"Document VFS expected after %s", argv[i - 1]);
1666 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1671 else if (streq(argv[i],
"-insert")) {
1673 errmsg =
ds_xprintf(
"Document VFS expected after %s", argv[i - 1]);
1676 if (insert_dir != NULL) {
1677 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1680 insert_dir = argv[i];
1682 else if (streq(argv[i],
"-f"))
1684 else if (streq(argv[i],
"-x")) {
1687 else if (streq(argv[i],
"-h") || streq(argv[i],
"-help")) {
1691 else if (streq(argv[i],
"-name")) {
1693 errmsg =
ds_xprintf(
"Name string expected after %s", argv[i - 1]);
1697 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1702 else if (streq(argv[i],
"-prefix")) {
1704 errmsg =
ds_xprintf(
"Prefix string expected after %s", argv[i - 1]);
1707 if (directive_prefix != NULL) {
1708 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1711 directive_prefix = argv[i];
1713 else if (streq(argv[i],
"-rprefix")) {
1715 errmsg =
ds_xprintf(
"Regex prefix string expected after %s",
1719 if (regex_prefix != NULL) {
1720 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1723 regex_prefix = argv[i];
1725 else if (streq(argv[i],
"-rsuffix")) {
1727 errmsg =
ds_xprintf(
"Regex suffix string expected after %s",
1731 if (regex_suffix != NULL) {
1732 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1735 regex_suffix = argv[i];
1737 else if (streq(argv[i],
"-suffix")) {
1739 errmsg =
ds_xprintf(
"Suffix string expected after %s", argv[i - 1]);
1742 if (directive_suffix != NULL) {
1743 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1746 directive_suffix = argv[i];
1748 else if (streq(argv[i],
"-ct")) {
1750 errmsg =
ds_xprintf(
"Content type string expected after %s",
1754 if (content_type != NULL) {
1755 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1758 content_type = argv[i];
1760 else if (streq(argv[i],
"-r") || streq(argv[i],
"-rules")) {
1764 errmsg =
ds_xprintf(
"Ruleset VFS expected after %s", argv[i - 1]);
1768 errmsg =
ds_xprintf(
"Duplicate %s specification", argv[i - 1]);
1772 if (argv[i][0] !=
'/') {
1773 errmsg =
"Invalid ruleset VFS";
1776 acls =
ds_xprintf(
"[transform-acls]dacs-fs:%s", argv[i]);
1781 else if (streq(argv[i],
"-var")) {
1782 char *def, *varname, *varvalue;
1785 errmsg =
"Variable name=value required after -var";
1792 errmsg =
"Usage: -var name=value";
1797 errmsg =
ds_xprintf(
"Can't initialize: %s", def);
1801 else if (streq(argv[i],
"--")) {
1809 if (argv[i] == NULL || streq(argv[i],
"-")) {
1813 else if (argv[i + 1] != NULL) {
1814 errmsg =
"Only one document may be specified";
1827 if (content_type == NULL)
1834 if ((p =
kwv_lookup_value(kwv,
"ANNOTATE")) != NULL && strcaseeq(p,
"yes"))
1840 if (doc == NULL && uri == NULL) {
1841 errmsg =
"DOC or DOCURI argument is required";
1847 errmsg =
"Only one of DOC or DOCURI can be specified";
1851 errmsg =
"DOC must be an absolute path";
1858 errmsg =
"Unrecognized URI scheme";
1867 if (directive_prefix != NULL)
1869 if (directive_suffix != NULL)
1871 if (regex_prefix != NULL)
1873 if (regex_suffix != NULL)
1889 if (idents == NULL) {
1892 if ((user = getenv(
"REMOTE_USER")) != NULL
1893 && *user !=
'\0' && !streq(user,
"unauth")) {
1896 roles = getenv(
"DACS_ROLES");
1897 idents =
make_ident(user, roles, NULL, 0, remote_addr);
1909 if (do_transform(tc, doc, uri, name, idents, content_type, &errmsg) == -1)
1918 main(
int argc,
char **argv)