Changeset 108
- Timestamp:
- 06/02/05 11:36:55 (4 years ago)
- Files:
-
- trunk/frameworkcc.sh (added)
- trunk/src/com/tresys/framework/policy/Domain.java (modified) (4 diffs)
- trunk/src/com/tresys/framework/policy/PolicyParser.jj (modified) (43 diffs)
- trunk/test/dictionary (modified) (21 diffs)
- trunk/test/policy (modified) (1 diff)
- trunk/test/testcases (added)
- trunk/test/testcases/constraint1 (added)
- trunk/test/testcases/constraint2 (added)
- trunk/test/testcases/constraint3 (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/src/com/tresys/framework/policy/Domain.java
r85 r108 10 10 package com.tresys.framework.policy; 11 11 12 import java.util. Set;12 import java.util.*; 13 13 14 14 import com.tresys.framework.dictionary.Verb; … … 23 23 */ 24 24 public final class Domain extends ComponentWithFobjects{ 25 public List<Component> Children; 26 25 27 /** 26 28 * Default domain constructor. … … 32 34 { 33 35 super(n, verbSet); 36 Children = new LinkedList<Component>(); 34 37 } 35 38 … … 45 48 super(n, par, verbSet); 46 49 } 50 51 /** 52 * Add a child component to this domain. 53 * 54 * @param child Child component 55 */ 56 public void AddChild(Component child){ 57 Children.add(child); 58 } 47 59 } trunk/src/com/tresys/framework/policy/PolicyParser.jj
r107 r108 52 52 * @param errmsg Error message to display on stdout 53 53 */ 54 static void ErrorGenerate (Token tok, String errmsg) {54 static void ErrorGenerate (Token tok, String errmsg) { 55 55 Config.Error("Line "+ tok.beginLine + 56 56 " Column " + tok.beginColumn); … … 67 67 * @param errmsg Error message to display on stdout 68 68 */ 69 static void WarnGenerate ( Token tok, String errmsg ) {69 static void WarnGenerate ( Token tok, String errmsg ) { 70 70 Config.Warn("Line "+ tok.beginLine + 71 71 " Column " + tok.beginColumn ); … … 79 79 * @param errmsg Error message to display on stdout 80 80 */ 81 static void ErrorGenerate (String errmsg) {81 static void ErrorGenerate (String errmsg) { 82 82 Config.Error(errmsg); 83 83 had_error = true; … … 90 90 * Error message to display on stdout 91 91 */ 92 static void WarnGenerate ( String errmsg ) {92 static void WarnGenerate ( String errmsg ) { 93 93 Config.Warn( errmsg ); 94 94 had_warning = true; … … 146 146 } 147 147 148 if ( had_warning ) {148 if ( had_warning ) { 149 149 Config.Warn("Policy parsed but warnings were generated! " + 150 150 "Generated policy may be erroneous.\n"); 151 151 } 152 152 153 if ( had_error ) {153 if ( had_error ) { 154 154 System.out.println("Errors were generated!\n" + 155 155 "The policy will NOT be translated. Please fix the errors and try again."); … … 268 268 { 269 269 // construct domain w/ parent reference 270 if ((parentStr != "") && (parentStr != null)) {270 if ((parentStr != "") && (parentStr != null)) { 271 271 // get parent domain 272 272 parent = genPolicy.Domains.get(parentStr); … … 274 274 // due to checks in the Parent() production that _should_ always 275 275 // succeed but just in case... 276 if (parent == null) {276 if (parent == null) { 277 277 ErrorGenerate(tokDomainName, "A domain \"" 278 278 + parentStr + "\" does not appear to be " … … 285 285 } 286 286 // construct domain w/out parent 287 } else if ( parentStr == "" ) {287 } else if ( parentStr == "" ) { 288 288 domain = new Domain(tokDomainName.image, dictionary.Verbs); 289 289 Config.Debug("Domain created: " + tokDomainName.image); … … 301 301 { 302 302 if (domain != null) { 303 if (genPolicy.Add(domain)){ 303 if (genPolicy.Add(domain)) { 304 if (domain.Parent != null) { 305 domain.Parent.AddChild(domain); 306 } 304 307 Config.Debug("Domain added to policy: " + domain.Name); 305 308 } else { … … 328 331 { 329 332 // construct resource w/ parent reference 330 if ((parentStr != "") && (parentStr != null)) {333 if ((parentStr != "") && (parentStr != null)) { 331 334 // get parent domain 332 335 parent = genPolicy.Domains.get(parentStr); … … 334 337 // due to checks in the Parent() production that _should_ always 335 338 // succeed but just in case... 336 if (parent == null) {339 if (parent == null) { 337 340 ErrorGenerate(tokResourceName, "A domain \"" 338 341 + parentStr + "\" does not appear to be " … … 345 348 } 346 349 // construct resource w/out parent 347 } else if ( parentStr == "" ) {350 } else if ( parentStr == "" ) { 348 351 resource = new Resource(tokResourceName.image, dictionary.Verbs); 349 352 Config.Debug("Resource created: " + tokResourceName.image); … … 362 365 { 363 366 if (resource != null) { 364 if (genPolicy.Add(resource)) {367 if (genPolicy.Add(resource)) { 365 368 Config.Debug("Resource added to policy: " + resource.Name); 369 if (resource.Parent != null) { 370 resource.Parent.AddChild(resource); 371 } 366 372 } else { 367 373 WarnGenerate(tokResourceName, "Failed attempt to insert resource \"" … … 389 395 { 390 396 // construct entrypoint w/ parent reference 391 if ((parentStr != "") && (parentStr != null)) {397 if ((parentStr != "") && (parentStr != null)) { 392 398 // get parent domain 393 399 parent = genPolicy.Domains.get(parentStr); … … 395 401 // due to checks in the Parent() production that _should_ always 396 402 // succeed but just in case... 397 if (parent == null) {403 if (parent == null) { 398 404 ErrorGenerate(tokEntrypointName, "A domain \"" 399 405 + parentStr + "\" does not appear to be " … … 406 412 } 407 413 // construct entrypoint w/out parent 408 } else if ( parentStr == "" ) {414 } else if ( parentStr == "" ) { 409 415 entrypoint = new Entrypoint(tokEntrypointName.image, dictionary.entrypoint); 410 416 Config.Debug("Entrypoint created: " + tokEntrypointName.image); … … 420 426 { 421 427 if (entrypoint != null) { 422 if (genPolicy.Add(entrypoint)){ 428 if (genPolicy.Add(entrypoint)) { 429 if (entrypoint.Parent != null) { 430 entrypoint.Parent.AddChild(entrypoint); 431 } 423 432 Config.Debug("Entrypoint added to policy: " + entrypoint.Name); 424 433 } else { … … 458 467 { 459 468 // remove trailing "." 460 if ( ancestors.length() > 0 ) {469 if ( ancestors.length() > 0 ) { 461 470 ancestors.deleteCharAt(ancestors.length() - 1); 462 471 return ancestors.toString(); … … 489 498 490 499 // control fobjects require special treatment (creation of control resources) 491 if (tokAt != null) {500 if (tokAt != null) { 492 501 fobject = dictionary.GetFobject(tokFobjName.image + tokAt.image); 493 if (fobject != null) {502 if (fobject != null) { 494 503 // check constraint (parent associated w/ same fobject) then add 495 504 if ((domain.Parent != null) && 496 (!domain.Parent.GetFobjects().containsKey(fobject.Name))) {505 (!domain.Parent.GetFobjects().containsKey(fobject.Name))) { 497 506 ErrorGenerate(tokFobjName, "Constraint check failed in Fobject association: " 498 507 + fobject.Name + " -- Children can only be associated with a subset of " 499 508 + "the parent's Fobjects."); 500 509 } 501 else if (domain.AddFobject(fobject)) {510 else if (domain.AddFobject(fobject)) { 502 511 Config.Debug("\tControl Fobject \"" + fobject.Name 503 512 + "\" added to domain \"" + domain.Name + "\"."); 504 513 // create a control resource 505 514 ControlResource conRes = new ControlResource(fobject.Name + domain.Name, dictionary.Verbs); 506 if (genPolicy.Add(conRes)) {515 if (genPolicy.Add(conRes)) { 507 516 Config.Debug("\tControl resource created: " + conRes.Name ); 508 517 } else { … … 519 528 } else { 520 529 fobject = dictionary.GetFobject(tokFobjName.image); 521 if (fobject != null) {530 if (fobject != null) { 522 531 // check constraint (parent associated w/ same fobject) then add 523 532 if ((domain.Parent != null) && 524 (!domain.Parent.GetFobjects().containsKey(fobject.Name))) {533 (!domain.Parent.GetFobjects().containsKey(fobject.Name))) { 525 534 ErrorGenerate(tokFobjName, "Constraint check failed in Fobject association: " 526 535 + fobject.Name + " -- Children can only be associated with a subset of " 527 536 + "the parent's Fobjects."); 528 } else if (domain.AddFobject(fobject)) {537 } else if (domain.AddFobject(fobject)) { 529 538 Config.Debug("\tFobject \"" + fobject.Name 530 539 + "\" added to domain " + domain.Name + "."); … … 555 564 tokFobjName=<ID>{ 556 565 fobject = dictionary.GetFobject(tokFobjName.image); 557 if (fobject != null) {566 if (fobject != null) { 558 567 // check constraint (parent associated w/ same fobject) then add 559 568 if ((resource.Parent != null) && 560 (!resource.Parent.GetFobjects().containsKey(fobject.Name))) {569 (!resource.Parent.GetFobjects().containsKey(fobject.Name))) { 561 570 ErrorGenerate(tokFobjName, "Constraint check failed in Fobject association: " 562 571 + fobject.Name + " -- Children can only be associated with a subset of " 563 572 + "the parent's Fobjects."); 564 } else if (resource.AddFobject(fobject)) {573 } else if (resource.AddFobject(fobject)) { 565 574 Config.Debug("\tFobject \"" + fobject.Name 566 575 + "\" added to domain " + resource.Name + "."); … … 599 608 // verify verb 600 609 verb = dictionary.GetVerb(tokVerbName.image); 601 if (verb != null) {610 if (verb != null) { 602 611 // if all if kopasetic create an access 603 if ((domain != null) && (resource != null)) {612 if ((domain != null) && (resource != null)) { 604 613 access = new Access(domain, resource, verb); 605 614 }else { … … 632 641 * domain can only access resources at the same level or higher. 633 642 */ 634 if (resource.Parent != null) {643 if (resource.Parent != null) { 635 644 // if the domain has a parent then the resource's parent must be a 636 645 //superset of the domain's parent 637 646 if ( (domain.Parent == null ) || 638 (!domain.Name.startsWith(resource.Parent.Name + "."))) {647 (!domain.Name.startsWith(resource.Parent.Name + "."))) { 639 648 ErrorGenerate(tokAccess, 640 649 "Constraint violation! Domain \"" + domain.Name … … 650 659 * constraints). 651 660 */ 652 if ((domain.Parent != null) && (resource.Parent != domain.Parent)) {661 if ((domain.Parent != null) && (resource.Parent != domain.Parent)) { 653 662 /* 654 663 * if no access defined for this verb in parent … … 656 665 */ 657 666 if ((domain.Parent.Accesses.get(verb) == null) || 658 (domain.Parent.Accesses.get(verb).get(resource) == null)) {667 (domain.Parent.Accesses.get(verb).get(resource) == null)) { 659 668 ErrorGenerate(tokAccess, 660 669 "Constraint violation! Access must be defined " … … 663 672 return; 664 673 // if valid parent and verb access but not a correct subset 665 } else if (!access.IsSubsetOf(domain.Parent.Accesses.get(verb).get(resource))) {674 } else if (!access.IsSubsetOf(domain.Parent.Accesses.get(verb).get(resource))) { 666 675 ErrorGenerate(tokAccess, 667 676 "Constraint violation! Must use subset of parent's access."); … … 672 681 } 673 682 } 674 if (genPolicy.Add(access)) {683 if (genPolicy.Add(access)) { 675 684 // update graph links for information flow 676 685 domain.Accesses.get(verb).put(resource, access); … … 701 710 AccessDefnEP axxDefnEP = null; 702 711 String key; 712 String keyParent; 703 713 LinkedList<Enter> list; 714 LinkedList<Enter> listParent; 704 715 } 705 716 { … … 714 725 { 715 726 // tweak or choose default 716 if (tokTweakName != null) {727 if (tokTweakName != null) { 717 728 axxDefnEP = dictionary.entrypoint.GetAccessDefnEP(tokTweakName.image); 718 729 } else { … … 721 732 } 722 733 723 if (axxDefnEP == null) {724 if (tokTweakName != null) {734 if (axxDefnEP == null) { 735 if (tokTweakName != null) { 725 736 ErrorGenerate(tokTweakName, "Invalid entrypoint access: " 726 737 + tokTweakName.image); … … 737 748 * domain can only access entrypoints at the same level or higher. 738 749 */ 739 if (entrypoint.Parent != null) {750 if (entrypoint.Parent != null) { 740 751 // if the domain has a parent then the resource's parent must be a 741 752 //superset of the domain's parent 742 if ( (domainSrc.Parent == null ) || 743 (!domainSrc.Name.startsWith(entrypoint.Parent.Name + "."))){ 753 if (domainSrc.Parent == null || 754 !domainSrc.Name.startsWith(entrypoint.Parent.Name + ".")) 755 { 744 756 ErrorGenerate(tokEntry, 745 757 "Constraint violation! Domain \"" + domainSrc.Name … … 747 759 + "\" which is hidden inside of another domain."); 748 760 return; 749 }else if ( (domainDest.Parent == null ) || 750 (!domainDest.Name.startsWith(entrypoint.Parent.Name + "."))){ 761 } 762 else if ( (domainDest.Parent == null ) || 763 (!domainDest.Name.startsWith(entrypoint.Parent.Name + "."))) 764 { 751 765 ErrorGenerate(tokEntry, 752 766 "Constraint violation! Domain \"" + domainDest.Name … … 760 774 key = domainSrc.toString() + Config.DELIM 761 775 + entrypoint.toString(); 776 762 777 // pull list if already created 763 778 list = genPolicy.Entries.get(key); 764 779 765 780 /* 766 *767 781 * TODO: clean this mess up 768 782 */ 769 if (list != null) {770 // no need to check if parent is null... null in list is impossible771 if (list.getLast().DomainEnd == domainDest.Parent) {783 if (list != null) { 784 // no need to check if domain dest. parent is null... null in list is impossible 785 if (list.getLast().DomainEnd == domainDest.Parent) { 772 786 list.add(enter); 773 } else {787 } else { 774 788 ErrorGenerate(tokEntry, 775 789 "Constraint violation! Parent domain of \"" + domainDest.Name … … 777 791 return; 778 792 } 779 } else if (domainSrc.Parent != null){ 780 ErrorGenerate(tokEntry, 793 // if the source domain has a parent 794 } else if (domainSrc.Parent != null) { 795 keyParent = domainSrc.Parent.toString() + Config.DELIM 796 + entrypoint.toString(); 797 listParent = genPolicy.Entries.get(keyParent); 798 799 // if the entry has already been defined for the parent 800 if (listParent != null || domainSrc.Parent == domainDest.Parent) { 801 list = new LinkedList<Enter>(); 802 list.add(enter); 803 } else { 804 ErrorGenerate(tokEntry, 781 805 "Constraint violation! Parent domain \"" + domainSrc.Parent.Name 782 806 + "\" must enter domain \"" + domainDest.Name 783 807 + "\" before its child \"" + domainSrc.SubName + "\"."); 784 return; 808 return; 809 } 785 810 // if we don't have a list then create one w/ no other constraint checks 786 811 } else { … … 810 835 { 811 836 // domain w/ parent reference 812 if ((domParentStr != "") && (domParentStr != null)) {837 if ((domParentStr != "") && (domParentStr != null)) { 813 838 // retrieve domain 814 839 domain = genPolicy.Domains.get(domParentStr 815 840 + "." + tokDomainName.image); 816 841 817 if (domain == null) {842 if (domain == null) { 818 843 ErrorGenerate(tokDomainName, "The domain \"" 819 844 + domParentStr + "." + tokDomainName.image … … 824 849 } 825 850 // domain w/out parent 826 } else if ( domParentStr == "" ) {851 } else if ( domParentStr == "" ) { 827 852 domain = genPolicy.Domains.get(tokDomainName.image); 828 853 829 if (domain == null) {854 if (domain == null) { 830 855 ErrorGenerate(tokDomainName, "The domain \"" + tokDomainName.image 831 856 + "\" does not appear to be defined before use."); … … 876 901 { 877 902 // if this is a control resource 878 if (tokAt != null) {903 if (tokAt != null) { 879 904 /* 880 905 * Parent() doesn't recognize a single domain w/ no "." 881 906 * which is only possible in a control resource attached to a TLD 882 907 */ 883 if (tokNoParent != null) {908 if (tokNoParent != null) { 884 909 resParentStr = tokNoParent.image; 885 910 } … … 889 914 + tokAt.image + resParentStr); 890 915 891 if (resource == null) {916 if (resource == null) { 892 917 ErrorGenerate(tokResourceName, "The control resource \"" 893 918 + tokResourceName.image + tokAt.image + resParentStr … … 898 923 } 899 924 // resource w/ parent reference 900 }else if ((resParentStr != "") && (resParentStr != null)) {925 }else if ((resParentStr != "") && (resParentStr != null)) { 901 926 // get resource from policy 902 927 resource = genPolicy.Resources.get(resParentStr 903 928 + "." + tokResourceName.image); 904 929 905 if (resource == null) {930 if (resource == null) { 906 931 ErrorGenerate(tokResourceName, "The resource \"" 907 932 + resParentStr + "." + tokResourceName.image … … 912 937 } 913 938 // domain w/out parent 914 } else if ( resParentStr == "" ) {939 } else if ( resParentStr == "" ) { 915 940 resource = genPolicy.Resources.get(tokResourceName.image); 916 941 917 if (resource == null) {942 if (resource == null) { 918 943 ErrorGenerate(tokResourceName, "The resource \"" + tokResourceName.image 919 944 + "\" does not appear to be defined before use."); … … 946 971 { 947 972 // domain w/ parent reference 948 if ((domParentStr != "") && (domParentStr != null)) {973 if ((domParentStr != "") && (domParentStr != null)) { 949 974 // retrieve domain 950 975 entrypoint = genPolicy.Entrypoints.get(domParentStr 951 976 + "." + tokEPName.image); 952 977 953 if (entrypoint == null) {978 if (entrypoint == null) { 954 979 ErrorGenerate(tokEPName, "The domain \"" 955 980 + domParentStr + "." + tokEPName.image … … 960 985 } 961 986 // domain w/out parent 962 } else if ( domParentStr == "" ) {987 } else if ( domParentStr == "" ) { 963 988 entrypoint = genPolicy.Entrypoints.get(tokEPName.image); 964 989 965 if (entrypoint == null) {990 if (entrypoint == null) { 966 991 ErrorGenerate(tokEPName, "The entrypoint \"" + tokEPName.image 967 992 + "\" does not appear to be defined before use in an enter statement."); … … 994 1019 return; 995 1020 996 if (access.TweakAccess(tokFobjName.image, tokAccessName.image)) {1021 if (access.TweakAccess(tokFobjName.image, tokAccessName.image)) { 997 1022 Config.Debug("\tAccess tweaked (Fobject Access): " 998 1023 + tokFobjName.image + " " + tokAccessName.image); trunk/test/dictionary
r105 r108 2 2 verbs { read write } 3 3 fobject dirFiles { 4 [desc: a directory full of files]4 [desc: "a directory full of files"] 5 5 all { 6 6 file { append create execute getattr ioctl link lock read rename setattr unlink write } … … 10 10 read { 11 11 default { 12 [desc: default read access]12 [desc: "default read access"] 13 13 [flow: 9] 14 14 resource { … … 21 21 write { 22 22 default { 23 [desc: default write access]23 [desc: "default write access"] 24 24 [flow: 9] 25 25 resource { … … 30 30 } 31 31 append { 32 [desc: limited write that only allows append]32 [desc: "limited write that only allows append"] 33 33 [flow: 8] 34 34 resource { … … 39 39 } 40 40 delete { 41 [desc: delete a file]41 [desc: "delete a file"] 42 42 [flow: 2] 43 43 resource { … … 51 51 52 52 fobject namedPipes { 53 [desc: named pipe and the directory it lives in]53 [desc: "named pipe and the directory it lives in"] 54 54 all { 55 55 dir { add_name append create execute getattr ioctl link lock read remove_name rename reparent rmdir search setattr unlink write } … … 58 58 read { 59 59 default { 60 [desc: default read access]60 [desc: "default read access"] 61 61 [flow: 9] 62 62 resource { … … 68 68 write { 69 69 default { 70 [desc: default write access]70 [desc: "default write access"] 71 71 [flow: 9] 72 72 resource { … … 79 79 80 80 fobject unixStreamSockets { 81 [desc: unix stream sockets with sockfiles and the directory they live in]81 [desc: "unix stream sockets with sockfiles and the directory they live in"] 82 82 all { 83 83 dir { add_name read remove_name search write } … … 87 87 read { 88 88 default { 89 [desc: create sockfile, bind to socket, listen, and read socket]89 [desc: "create sockfile, bind to socket, listen, and read socket"] 90 90 [flow: 9] 91 91 resource { … … 100 100 write { 101 101 default { 102 [desc: connect to and write to a socket]102 [desc: "connect to and write to a socket"] 103 103 [flow: 9] 104 104 resource { … … 117 117 118 118 fobject tcpNetwork { 119 [desc: tcp network interface, including interface, node, and socket permissions]119 [desc: "tcp network interface, including interface, node, and socket permissions"] 120 120 all { 121 121 netif { tcp_recv tcp_send } … … 125 125 read { 126 126 default { 127 [desc: read from a tcp socket]127 [desc: "read from a tcp socket"] 128 128 [flow: 9] 129 129 resource { … … 137 137 } 138 138 serverRead { 139 [desc: bind, listen, accept, and read from a tcp socket]139 [desc: "bind, listen, accept, and read from a tcp socket"] 140 140 resource { 141 141 netif { tcp_recv tcp_send } … … 150 150 write { 151 151 default { 152 [desc: connect and write to a tcp socket]152 [desc:" connect and write to a tcp socket"] 153 153 resource { 154 154 netif { tcp_recv tcp_send } … … 161 161 } 162 162 serverWrite { 163 [desc: bind, listen, accept, and write to a tcp socket]163 [desc: "bind, listen, accept, and write to a tcp socket"] 164 164 resource { 165 165 netif { tcp_recv tcp_send } … … 176 176 #this is a test fobject to exercise the parsers ability to understand control fobjects and resources 177 177 fobject mqueues@ { 178 [desc: "message queues control fobject"] 178 179 all { 179 180 msgq { enqueue create destroy } … … 182 183 read { 183 184 default { 184 resource { 185 msgq { enqueue create destroy } 186 ipc { write destroy } 187 } 188 } 189 } 190 write { 191 default { 185 [desc: "default message queue read access"] 186 resource { 187 msgq { enqueue create destroy } 188 ipc { write destroy } 189 } 190 } 191 } 192 write { 193 default { 194 [desc: "default message queue write access"] 192 195 resource { 193 196 msgq { enqueue create destroy } … … 200 203 #this is a test fobject to exercise the parsers ability to understand control fobjects and resources 201 204 fobject mqueues { 205 [desc: "message queues control fobject"] 202 206 all { 203 207 msgq { enqueue create destroy } … … 206 210 read { 207 211 default { 208 resource { 209 msgq { enqueue create destroy } 210 ipc { write destroy } 211 } 212 } 213 } 214 write { 215 default { 212 [desc: "default message queue read access"] 213 resource { 214 msgq { enqueue create destroy } 215 ipc { write destroy } 216 } 217 } 218 } 219 write { 220 default { 221 [desc: "default message queue read access"] 216 222 resource { 217 223 msgq { enqueue create destroy } … … 224 230 225 231 entrypoint { 226 [desc:"resource that is executed to enter a domain"]232 [desc:"resource that is executed to enter a domain"] 227 233 default { 228 234 start resource { trunk/test/policy
r107 r108 3 3 domain out; 4 4 domain guard { namedPipes unixStreamSockets dirFiles }; 5 6 # TEST: entry constraint checking7 domain in.test1;8 domain out.test2;9 entrypoint exec;10 enter in out exec {test};11 enter in.test1 out.test2 exec;12 13 # TEST: for domain accessing a hidden resource14 #domain foo;15 #domain fob {dirFiles};16 #resource fob.bar {dirFiles};17 #access foo fob.bar write;18 19 # TEST: for exceeding permissions granted to the parent (PermVector fails subset test)20 #domain foo;21 #domain foo.bar;22 #resource baz {dirFiles};23 #access foo baz write { dirFiles:append };24 #access foo.bar baz write;25 5 26 6 resource eth1 { tcpNetwork };
