On 02/24/2010 02:24 PM, Daniel J Walsh wrote:
>
Ignore the first patch it was missing pc.in files.
Acked-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
Signed-off-by: Joshua Brindle <method@manicmethod.com>
Email: dwalsh@redhat.com
Subject: Fix memory leak on disabled selinux machines.
Date: Wed, 24 Feb 2010 14:15:31 -0500
I think this patch originally came from Eric Paris and was updated by
others but has not been adopted yet. Not sure why.
Always free buf on exit.
Signed-off-by: Joshua Brindle <method@manicmethod.com>
I want to change the default of libsemanage to not look for home
directories in getpwent. This patch allows you to set the flag
usepasswd=false in the semanage.conf file. and genhomedircon will only
setup the labeling of /home, /export/home and any confined users homedirs.
If this patch is not acceptable because libsemanage is being rewritten,
I would like the functionality to be added to the new libsemanage.
On Mon, 2010-02-15 at 14:19 -0800, Justin Mattock wrote:
> this is new:
>
>
> make[2]: Leaving directory `/home/kernel/selinux/libselinux/include'
> make -C src install
> make[2]: Entering directory `/home/kernel/selinux/libselinux/src'
> cc -Werror -Wall -W -Wundef -Wshadow -Wmissing-noreturn
> -Wmissing-format-attribute -I../include -I/usr/include -D_GNU_SOURCE
> -D_FILE_OFFSET_BITS=64 -c -o label_file.o label_file.c
> cc1: warnings being treated as errors
> label_file.c: In function 'init':
> label_file.c:434: error: implicit declaration of function 'fstat'
> label_file.c:436: error: implicit declaration of function 'S_ISREG'
> make[2]: *** [label_file.o] Error 1
> make[2]: Leaving directory `/home/kernel/selinux/libselinux/src'
> make[1]: *** [install] Error 2
> make[1]: Leaving directory `/home/kernel/selinux/libselinux'
> make: *** [install] Error 1
>
> three areas where this could of been created
> update glibc
> updated kernel
> update userspace(altohugh there was not vary many commits in the pull).
Newer glibc headers expose a failure to #include the required headers
for stat(2). Also exposes a conflict in redefining close() in that
file. Patch below should fix.
Only audit the permissions specified by the policy, excluding any
permissions specified via dontaudit or not specified via auditallow.
This only shows up when a single avc_has_perm() call is made with
multiple permissions where some of those permissions are dontaudit'd or
auditallow'd while others are not. The corresponding kernel patch has
already been applied, see:
http://git.kernel.org/?p=linux/kernel/git/jmorris/security-testing-2.6.git;a=commit;h=b6cac5a30b325e14cda425670bb3568d3cad0aa8
Signed-off-by: Stephen D. Smalley <sds@tycho.nsa.gov>
On Sun, 2010-01-24 at 21:29 +0100, Guido Trentalancia wrote:
> Hi !
>
> Has anybody had any time to look at this ticket:
> http://userspace.selinuxproject.org/trac/ticket/7 ?
>
> I have experienced the same issue and verified that the problem is actually triggered by the bzip support (as pointed out by Stephen Smalley back in August). In fact, if I use bzip-blocksize=0 in semanage.conf then the problem disappears...
>
> Otherwise with a default semanage.conf and bzip enabled, I get:
>
> libsepol.module_package_read_offsets: offset greater than file size (at 4, offset 200478 -> 8192 (No such file or directory).
> libsemanage.semanage_load_module: Error while reading from module file /etc/selinux/refpolicy/modules/tmp/base.pp. (No such file or directory).
> semodule: Failed!
>
> I am using libsepol-2.0.41 and libsemanage-2.0.42.
Looking into this more closely, I believe this is another manifestation
of:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=543915#17
which was ultimately traced down to two issues:
1) A missing offset check in libsepol (fixed in libsepol 2.0.38), and
2) A bug / lack of binary mode support in the fmemopen implementation in
glibc that was later fixed, see:
http://sourceware.org/bugzilla/show_bug.cgi?id=6544
Maybe you have the older glibc still?
Looking at the libsemanage code though, I think we could in fact avoid
any dependency on fmemopen by using the native libsepol support for
operating on a memory region via sepol_policy_file_set_mem(), ala:
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Hi folks,
The script, src/exception.sh, contains so called bashisms
(constructs not supported by POSIX, but present as bash
extensions). This means when trying to build on systems where /bin/sh
is not bash, the build fails with an error. This patch uses bash to
run exception.sh. This bug affects a significant subset of Debian and
Debian derivative machines.
manoj
Signed-off-by: Manoj Srivastava <srivasta@debian.org>
Signed-off-by: Joshua Brindle <method@manicmethod.com>
Email: guido@trentalancia.com
Subject: Contributed manual pages for libselinux
Date: Sat, 21 Nov 2009 20:51:17 +0100
Hello Eamon !
On Fri, 2009-11-20 at 21:42 -0500, Eamon Walsh wrote:
> Hi, thanks for doing this. Some quick review below.
You are welcome, I suppose it was a boring task for many...
Thanks very much for reviewing the changes. And please accept my
apologies for not placing "[PATCH]" in the subject of the original post.
I had just subscribed to the list.
I left you cc address intact here...
> There is too much in matchpathcon(3) now. It's going to need to be
> split up into different pages, perhaps the init/fini/teardown stuff in
> one page, the lookup calls in another, and the non-matchpathcon prefixed
> calls in a third page.
>
> Also, .so manpage links are needed for all the calls here.
Yes, matchpathcon is a mess. Following your guidelines, I have now
splitted the huge and messy page in several different man pages. It's
easier to consult and easier to maintain.
The first part (page) is strictly related to _init, its variant
_init_index, _fini, matchpathcon and its variant matchpathcon_index.
Nice and concise. References are provided in the "SEE ALSO" section to
the rest.
The second page describes the auxiliary lookup calls
(matchpathcon_checkmatches) and the inode associations functions
(matchpathcon_filespec_{add,destroy,eval}). The reference section points
to the main matchpathcon page.
A third page has been created for the functions that are used to set the
flags (set_matchpathcon_flags) or to configure the behaviour of the main
matchpathcon functions (set_matchpathcon_invalidcon and
set_matchpathcon_printf).
A fourth and fifth page is devoted to functions that should never had
ended up in matchpathcon (selinux_file_context_cmp and
selinux_file_context_verify in one page and selinux_lsetfilecon_default
in another one): we do not really need to save electrons needed for new
pages...
>
>
> > * print_access_vector
> >
>
> Looks good.
No modifications.
> > * security_disable
> >
>
> See the selinux.h comments for this. It needs to be documented that
> this function can only be called at startup time.
Ok. I have stressed that now and also mentioned that after the policy
has been loaded at startup, then only "setenforce" can be used to alter
(not disable) the mode of the SELinux kernel code (for example by
placing it into "permissive" mode).
> > * security_set_boolean_list
> >
>
> a RETURN VALUE section is needed in this page, documenting at least this
> call if not the others in that page.
I have now added a "RETURN VALUE" section.
Also, to avoid confusion, I have rephrased the word "returns" in
"provides" when not strictly referring the to the return value of the
function (take for example security_get_boolean_names(), strictly
speaking the function returns an integer representing 0=success or
-1=failure, although from a conceptual point of view it also returns a
list trough modification of one of its parameters passed by reference).
Usually when an application developer looks at the "RETURN VALUE"
section it is because he/she has already planned/coded the call to the
function (and thus also the handling to parameters passed by reference)
and only needs to check for the function exit status so that it can be
handled properly at the call point.
> > * selinux_check_passwd_access
> >
>
> This is a replacement for the inconsistently named "checkPasswdAccess"
> function. So, the existing description of checkPasswdAccess should be
> moved to this function, and checkPasswdAccess should be changed to "this
> is a deprecated alias for selinux_check_passwd_access".
Yes, I have now mentioned that checkPasswdAccess is deprecated. We are
referring to file security_compute_av.3 as the description of these two
functions lives there...
By the way, it has been pointed out that this function should not
hard-code a string. I also agree with him, there is a generic constant
for such "passwd" object class, it is defined in flask.h could be used
instead of the string, thus avoiding hard-coding and also allowing to
save a few cycles and be theoretically future-proof (if ever the name
would change, say to "password", "auth-token" or anything else).
libselinux/src/checkAccess.c.orig 2009-11-21 20:07:21.000000000
libselinux/src/checkAccess.c 2009-11-21 20:08:36.000000000
@@ -13,17 +13,12 @@ int selinux_check_passwd_access(access_v
if (is_selinux_enabled() == 0)
return 0;
if (getprevcon_raw(&user_context) == 0) {
- security_class_t passwd_class;
struct av_decision avd;
int retval;
- passwd_class = string_to_security_class("passwd");
- if (passwd_class == 0)
- return 0;
-
retval = security_compute_av_raw(user_context,
user_context,
- passwd_class,
+ SECCLASS_PASSWD,
requested,
&avd);
Note that the above code, should really live in the application and not
in the selinux library. It used to be like that, then for some reason it
has been introduced. Redhat's passwd and cronie are calling the library
function and thus at the moment they rely on it. But for example,
util-linux-ng has the code in it and does not call this function, as I
believe it should be. A very minor issue anyway...
> > * selinux_init_load_policy
> >
>
> A paragraph break is needed in the DESCRIPTION section before this function.
Done. I have also added a note to the already mentioned fact that after
initial policy load, SELinux cannot be anymore disabled using calls to
security_disable(3).
> > * selinux_lsetfilecon_default
> >
>
> See notes above about the matchpathcon manpage.
Yes, separate man page now.
> > * selinux_mkload_policy
> >
>
> Looks good.
No modifications.
> > * set_selinuxmnt
> >
>
> This manpage includes two static functions that are not part of the
> libselinux API (at least, not anymore) and should be removed.
>
> Also, I'm not comfortable with the description given. Instead, use the
> comments in selinux.h, which are more accurate and verbose.
>
Please let me know if things are any better now.
I did also provide on the same day a patch for beautifying and improving
the command-line option parsing of a few utilities (a ticket had been
created by somebody). That patch provides those improvement according to
GNU-style parsing of "help" and "version" options (including long-option
variants). I think it also fixes a couple of typos here and there. Feel
free to include that patch too if you like it, so that the ticket can be
closed ! I will attach it again in another separate message: it has been
slightly modified in order to apply cleanly to the latest git snapshot.
More important, I was also thinking about fingerprinting (and
subsequently checking) the libraries with some cryptographic hash
function such as the NIST-recommended SHA2. It is beginning to be done
for security-related projects like OpenSSL, so I believe it is even more
essential for SELinux. Ever thought about anything like that ?
Best regards,
Guido
Signed-off-By: Joshua Brindle <method@manicmethod.com>
This patch is proposed to solve Ticket #1 [1672486] (command line
binaries should support --version and --help).
It adds handling of -h, -V and the long formats --help and --version to
all binaries (checkpolicy/checkmodule).
It also adds handling of long options for some of the available options.
Manual pages have also been updated accordingly (and a few undocumented
options have been documented).
Guido Trentalancia
Signed-off-by: Joshua Brindle <method@manicmethod.com>
On Mon, 2009-08-24 at 23:37 +1000, Russell Coker wrote:
> On Mon, 24 Aug 2009, Daniel J Walsh <dwalsh@redhat.com> wrote:
> > >>> http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=503252
> > >>
> > >> audit2allow -l is looking for the load_policy message which does not go
> > >> to the dmesg, /var/log/messages. Therefore the tool has no idea when
> > >> policy was last loaded.
> > >
> > > That would be a kernel bug then.
> >
> > Well I believe the messages that are intercepted by the audit.log do not go
> > into dmesg, by design. Although Steve, James or Eric could probably say for
> > sure.
>
> When auditd is not running on a Debian system with CentOS kernel
> 2.6.18-92.1.13.el5xen or Debian/Lenny kernel 2.6.26-2-xen-686 then nothing
> goes to the kernel message log which is interpreted by audit2allow as a
> candidate for the "-l" functionality.
>
> It's OK if all the AVC messages go to the audit log and "dmesg|audit2allow -l"
> gives no output. But if all AVC messages other than the load_policy message
> go to the kernel message log then it's a bug.
Originally audit2allow used the avc: allowed message generated by
auditallow statement for load_policy to identify policy reloads. Later
it was switched to use the MAC_POLICY_LOAD events generated by the audit
framework. Those events should still get logged via printk if auditd is
not running, but it appears that the code (audit_printk_skb) will then
log the type= field as an integer rather than a string, and
audit2allow/sepolgen only looks for the string MAC_POLICY_LOAD.
So I suspect that this would be resolved by modifying sepolgen/audit.py
to also match on type=1403 for load messages. Try this:
Signed-off-by: Joshua Brindle <method@manicmethod.com>
Each manual page should start with a "NAME" section, which lists the
name and a brief description of the page separated by "\-". These
sections are parsed by "mandb" and stored in a database for the use of
"apropos" and "whatis", so they must be in a certain format. These
manual pages apparently use the wrong format and cannot be parsed by
"mandb". This commit fixes that.
Signed-off-by: Manoj Srivastava <srivasta@debian.org>
Signed-off-by: Joshua Brindle <method@manicmethod.com>
Manoj Srivastava wrote:
> Hi,
>
> As demonstrated by
>
> $ ldd /lib/libsemanage.so.1
> linux-gate.so.1 => (0xb8092000)
> libsepol.so.1 => /lib/libsepol.so.1 (0xb8015000)
> libselinux.so.1 => /lib/libselinux.so.1 (0xb7ffa000)
> libbz2.so.1.0 => /lib/libbz2.so.1.0 (0xb7fe9000)
> libustr-1.0.so.1 => /usr/lib/libustr-1.0.so.1 (0xb7fbf000)
> libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7e60000)
> libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7e5c000)
> /lib/ld-linux.so.2 (0xb8093000)
>
> libsemanage1 links to libustr which is located under the,
> possible separate or external, /usr partition, which would render
> libsemanage unusable in such setups. (This dependency has been around
> since 2.0.9).
>
> Should we move libsemanage1 to /usr/lib? The only reason for it
> to be in /lib would be for early boot, where /usr might not be
> available, but at this point, it is likely not usable without /usr
> anyway.
>
> manoj
Yes, I'm not sure why you'd need libsemanage during early boot, we
probably should apply this:
Signed-off-by: Joshua Brindle <method@manicmethod.com>
Apparently I failed to split out the whitespace changes from a
previous patchset, and a bit of the equivalence patch of the
day snuck in. This causes a stack trace when you execute
semanage fcontext -l. This patch reverts the accidentally
included code.
Signed-off-by: Chad Sellers <csellers@tresys.com>
This patch fixes a bug that causes semanage node -a to not work
(failing with a python traceback). You can test the bug with any
semanage node -a command, such as:
semanage node -a -t node_t -p ipv4 -M 255.255.255.0 192.168.1.0
Signed-off-by: Chad Sellers <csellers@tresys.com>
Email: dwalsh@redhat.com
Subject: Add modules support to semanage
Date: Thu, 12 Nov 2009 11:23:15 -0500
On 11/11/2009 01:52 PM, Chad Sellers wrote:
> On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote:
>
>> Includes enable and disable.
>>
> I presume I should hold off on this patch until you have a chance to
> resubmit the libsemanage support that it relies on. Let me know if that's
> not the case.
>
> Thanks,
> Chad
>
Lets do this patch.
Moves load_policy from /usr/sbin to /sbin
Removed cruft.
Signed-off-by: Chad Sellers <csellers@tresys.com>
Email: srivasta@debian.org
Subject: cannnot -> cannot and suport -> support
Date: Tue, 17 Nov 2009 10:27:57 -0600
This was reported after a lintian check found this on any package
linked with libsepol. Closes: #556390
Signed-off-by: Manoj Srivastava <srivasta@debian.org>
Signed-off-by: Chad Sellers <csellers@tresys.com>
Email: dwalsh@redhat.com
Subject: Remove setrans management from semanage
Date: Wed, 30 Sep 2009 14:07:49 -0400
This will not work correctly using the current mcstrans code base. I believe an admin has to edit this code directly and probably should have never been added to semanage.
Signed-off-by: Chad Sellers <csellers@tresys.com>
Email: tliu@redhat.com
Subject: policycoreutils: share setfiles restore function with restorecond
Date: Wed, 19 Aug 2009 15:51:44 -0400
This is the first of two patches.
This patch splits all of the restore functionality in setfiles
into another two files, restore.c and restore.h.
The reason for this is shown in the next patch, which patches
restorecond to share this code.
To use it, instantiate a restore_opts struct with the proper options
and then pass a pointer to it into restore_init, and call restore_destroy
later.
Signed-off-by: Thomas Liu <tliu@redhat.com>
Signed-off-by: Dan Walsh <dwalsh@redhat.com>
I've rebased this so that it will apply to current trunk.
Signed-off-by: Chad Sellers <csellers@tresys.com>
Having a pkgconfig files allows the pkg-config tool to be used to
query the presence of the library (or a particular version of it),
and to obtain the C flags and linker arguments to build with it.
Based on Debian patches by Manoj Srivastava <srivasta@debian.org>.
Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
This patch adds a function to turn off file contexts validation.
We need this for cross-installs in rpm, where we install policy
into a chroot that has binaries of a different architecture which
cannot be executed on the build system. So, we would like to use
this function to disable executing setfiles. This of course means
the file contexts could be invalid, but we're willing to take
that risk.
Signed-off-by: Chad Sellers <csellers@tresys.com>
In integrating SELinux policy into rpm, we have a need to be
able to reset the configuration data (e.g. policy type) loaded
into libselinux. These values are currently loaded lazily by a
number of different functions (e.g. matchpatchcon_init()).
Since we are changing rpm to install policy, including initial
base policy, we need to be able to reload these configuration
items after the policy has been installed.
reset_selinux_config() already exists and is used by
selinux_init_load_policy() for a similar reason, but it is not
exported. This was probably intentionaly since it is not thread
safe at all. That said, rpm needs to do the same thing. This
patch makes the function public, and places a warning in the
header comment that it is not thread safe.
Signed-off-by: Chad Sellers <csellers@tresys.com>
Email: method@manicmethod.com
Subject: libsepol: Add support for multiple target OSes
Date: Tue, 13 Oct 2009 15:56:39 -0400
Paul Nuzzi wrote:
> On Wed, 2009-09-16 at 09:58 -0400, Joshua Brindle wrote:
>> I'd rather have separate ocontext structs for each system. That way it
>> is very easy to understand which ones apply to which system and you
>> don't get a crazy out of context ocontext struct.
>>
>
> I looked into having separate ocontext structs but that would involve
> changing a lot of files making the patch much larger and more intrusive.
>
>>> } u;
>>> union {
>>> uint32_t sclass; /* security class for genfs */
>>> @@ -313,6 +323,17 @@ typedef struct genfs {
>>> #define OCON_NODE6 6 /* IPv6 nodes */
>>> #define OCON_NUM 7
>>>
>>> +/* object context array indices for Xen */
>>> +#define OCON_ISID 0 /* initial SIDs */
>>> +#define OCON_PIRQ 1 /* physical irqs */
>>> +#define OCON_IOPORT 2 /* io ports */
>>> +#define OCON_IOMEM 3 /* io memory */
>>> +#define OCON_DEVICE 4 /* pci devices */
>>> +#define OCON_DUMMY1 5 /* reserved */
>>> +#define OCON_DUMMY2 6 /* reserved */
>>> +#define OCON_NUM 7
>>> +
>>> +
>>>
>> Should these be namespaced? What if<random other system> has io port
>> objects? You'd have to align them with each other and you have a mess of
>> keeping the numbers the same (you already do this with OCON_ISID)
>
> Variables have been namespaced and there is no more overlap with
> OCON_ISID.
>
>> Also we are relying on having the same number of OCON's which isn't good
>> I don't think. As much as I hate the policydb_compat_info (read: alot)
>> why aren't we using that to say how many ocons a xen policy really has?
>
> OCON_NUM is now dynamically read through policydb_compat_info.
>
>
>> This is messy, why not an ocontext_selinux_free() and
>> ocontext_xen_free() (note: I realize the xen_free() one won't do
>> anything except freep the ocontext_t)
>>
>
> done.
>
>>> len = buf[1];
>>> - if (len != strlen(target_str)&&
>>> - (!alt_target_str || len != strlen(alt_target_str))) {
>>> - ERR(fp->handle, "policydb string length %zu does not match "
>>> - "expected length %zu", len, strlen(target_str));
>>> + if (len> 32) {
>>>
>> magic number 32?
>
> #defined.
>
> Thanks for your input. Below is the updated patch for libsepol.
>
Acked-by: Joshua Brindle <method@manicmethod.com>
for the entire patchset with the following diff on top:
diff --git a/checkpolicy/checkpolicy.c b/checkpolicy/checkpolicy.c
index 76d8ed3..e76bb1a 100644
--- a/checkpolicy/checkpolicy.c
+++ b/checkpolicy/checkpolicy.c
@@ -100,8 +100,8 @@ unsigned int policyvers = POLICYDB_VERSION_MAX;
void usage(char *progname)
{
printf
- ("usage: %s [-b] [-d] [-U handle_unknown (allow,deny,reject) [-M]"
- "[-c policyvers (%d-%d)] [-o output_file] [-t platform]"
+ ("usage: %s [-b] [-d] [-U handle_unknown (allow,deny,reject)] [-M]"
+ "[-c policyvers (%d-%d)] [-o output_file] [-t target_platform (selinux,xen)]"
"[input_file]\n",
progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
exit(1);
Signed-off-by: Joshua Brindle <method@manicmethod.com>
Add support to sepolgen for new Xen ocontext identifiers.
Signed-off-by: Paul Nuzzi <pjnuzzi@tycho.ncsc.mil>
Signed-off-by: Joshua Brindle <method@manicmethod.com>
On Wed, 2009-09-16 at 09:58 -0400, Joshua Brindle wrote:
> I'd rather have separate ocontext structs for each system. That way it
> is very easy to understand which ones apply to which system and you
> don't get a crazy out of context ocontext struct.
>
I looked into having separate ocontext structs but that would involve
changing a lot of files making the patch much larger and more intrusive.
> > } u;
> > union {
> > uint32_t sclass; /* security class for genfs */
> > @@ -313,6 +323,17 @@ typedef struct genfs {
> > #define OCON_NODE6 6 /* IPv6 nodes */
> > #define OCON_NUM 7
> >
> > +/* object context array indices for Xen */
> > +#define OCON_ISID 0 /* initial SIDs */
> > +#define OCON_PIRQ 1 /* physical irqs */
> > +#define OCON_IOPORT 2 /* io ports */
> > +#define OCON_IOMEM 3 /* io memory */
> > +#define OCON_DEVICE 4 /* pci devices */
> > +#define OCON_DUMMY1 5 /* reserved */
> > +#define OCON_DUMMY2 6 /* reserved */
> > +#define OCON_NUM 7
> > +
> > +
> >
> Should these be namespaced? What if <random other system> has io port
> objects? You'd have to align them with each other and you have a mess of
> keeping the numbers the same (you already do this with OCON_ISID)
Variables have been namespaced and there is no more overlap with
OCON_ISID.
> Also we are relying on having the same number of OCON's which isn't good
> I don't think. As much as I hate the policydb_compat_info (read: alot)
> why aren't we using that to say how many ocons a xen policy really has?
OCON_NUM is now dynamically read through policydb_compat_info.
> This is messy, why not an ocontext_selinux_free() and
> ocontext_xen_free() (note: I realize the xen_free() one won't do
> anything except freep the ocontext_t)
>
done.
> >
> > len = buf[1];
> > - if (len != strlen(target_str)&&
> > - (!alt_target_str || len != strlen(alt_target_str))) {
> > - ERR(fp->handle, "policydb string length %zu does not match "
> > - "expected length %zu", len, strlen(target_str));
> > + if (len> 32) {
> >
>
> magic number 32?
#defined.
Thanks for your input. Below is the updated patch for libsepol.
----
libsepol/include/sepol/policydb/policydb.h | 28 ++
libsepol/src/expand.c | 85 +++++++-
libsepol/src/policydb.c | 295
+++++++++++++++++++++++------
libsepol/src/policydb_internal.h | 1
libsepol/src/private.h | 4
libsepol/src/write.c | 93 ++++++++-
6 files changed, 443 insertions(+), 63 deletions(-)
Signed-off-by: Joshua Brindle <method@manicmethod.com>