General ideas, notes, wishes and other crufty stuff which might be useful. [ last modified end of 1998] Can engine load _all_ rules at the outset, and discard the ones that are not applicable? Perhaps the one-shot rules don't need to be loaded in this fashion. Idea: perhaps the rules should be objects, with a standardised API that the engine uses to run them? In any event, the interface between the rules and the engine has to be very well documented, and standardised. Idea: perhaps the starting points and the goals for the rules can be defined by the rules themselves. e.g the general Unix rulset might list some of the rules below. At a later date, someone could write a rule which might have a goal: ``Open ports below 1024 for writing''. If we could do this, then the engine would be _extremely_ flexible. Someone would have to co-ordinate the list of things, to stop duplicate groups coming up with the same goal, and to ensure that rules from different vendors will work together. Rules will need to get info from the engine too, e.g the type of system, a list of user-ids and details etc. Again, the mechanism to do this should be standardised. Some of this info might be cached by the engine, and loaded before the first rules start up. What goals do we want: become user-id X become user-id 0 become group-id Y read from file alter file append to file truncate file remove file execute file change file's permissions: one, or several rules? change file's timestamps cause user X to run program and what else? Some things, like loading the info for the password & group files, will be different for different systems. So we probably need some pseudo-rules which will do this for us, and work on particular systems. Need to read & parse the full output for uname for several systems. The best way to do this is to create a Perl module Sys::Uname.pm, and then submit it into the Perl group. Must write in Perl 5 code with -w and use strict!!! How can we get Perl to find and auto-load objects? Especially as we won't know their name :-) If the rules ARE objects, mainly a set of methods, then we can probably have an array of rules. One rule method might be init() which would set up any object thingys, and also disqualify itself if the rule is for the wrong system. How to check what network services are running, and identify the actual programs (e.g sendmail and qpopper) and their particular versions? Some combination of netstat, grepping of /etc/inetd.conf and /etc/rc* perhaps. We could use netcat to connect to the port & get info, but can we guarantee that this is accurate? What's a good way to partition rules, so that they can be downloaded from various places? Suggestion: Genunix/ Linux/ Linux/RedHat Linux/Slackware FreeBSD/ Solaris/ Bind/ Sendmail/ We could go Systems/Genunix Systems/Linux etc Programs/Bind Programs/Sendmail etc but would the extra level be useful? In any case, I'm assuming that the end-user can get Sendmail/* rules from one place, Linux/RedHat/* rules fom another place etc. Vendors can create new parts of the namespace as required. There would be a user-configured shell script which would retrieve rules into this namespace, and which could be run by the engine at start-up, if specified by a run-time option. Will we need some way to override rules, e.g a Linux rule which says ``Don't use the rule Genunix/parse_password_file, use me instead''. If so, would be nice to log this overrule and perhaps also print it to the user when it happens. Part of each rule is a description of the rule in a human language: Unique Name Author(s) Date of Last Modification Publisher, i.e who own the PGP key in which the rule is encrypted Description, e.g 2-3 lines of text End users might be able to do # kuang+ --list-rules, to see the details. Would it be a good idea to list the sorts of things that Kuang+ CAN'T help protect against, e.g badly-chosen passwords (use Crack instead), or stuff like that. Of course, someone (not us) could write a rule which read in the output from Crack, and make use of that information, e.g person X's password is guessable -> anybody can become person X Not our problem, though! but we could document it somewhere. Engine Operation ---------------- Idea: Engine runs in two phases. Phase 1: load and run all the applicable rules. If they find anything, they add a structure to an array: init_state => an indication of the initial state, in a form which will be easy to use, perhaps not plain ASCII descript() => pointer to a function in the original rule file which describes the problem found, e.g User X has a writable .login file final_state => an indication of the final state, as above Phase 1a: If the user just wants to see the initial list of system problems, then we can run the descript() function for every node in the array, and this will show the initial list. Phase 2: Attempt to pair up initial & final states in the array elements so as to create all possible chains of nodes. Note that we can remove some nodes, e.g Remove nodes with end state X if no other nodes have start state X. Ditto, remove nodes with start state Y if no other nodes have end state Y. We also have to watch out for loops, e.g nodes 5 -> 12 -> 16 -> 5. I'm not sure if a breadth-first or a depth-first traversal would be best here, but we can work it out. Phase 2a: The chains are sent to the user, e.g 5 -> 12 -> 16 -> 24 -> 13 (init state of 5) can reach (final state of 13) via the following: (init state of 5) can (final state of 5) (init state of 12) can (final state of 12) . . .