(#12457) add users primary group, not Process.gid, in initgroups

The Process.gid (real gid) was always included when initialising supplementary
groups in the initgroups method (called when changing the euid via the
change_user method).  This has been replaced by the primary gid of the user.

This led to a privilege leak, as well as a potential surprise when it came to
file ownership, in both the agent and the master.

Fix and analysis by Dominic Cleal <dcleal@redhat.com>

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
(#12458) default to users primary group, not root, in `asuser`

When only a user (no group) was given to the asuser method, the egid wouldn't
be changed and would remain the privileged gid.  This has been changed to the
primary gid of the user.

Fix and analysis by Dominic Cleal <dcleal@redhat.com>

Contributed: Daniel Pittman <daniel@puppetlabs.com>
Contributed: Deepak Giridharagopal <deepak@puppetlabs.com>
Contributed: Nick Lewis <nick@puppetlabs.com>
(#12459) drop supplementary groups when permanently dropping UID

On certain platforms, Process::UID.change_privilege doesn't handle
changing supplementary groups. In that case, we need to always
explicitly initgroups, regardless of whether we're using
change_privilege, or change_group/change_user.

Analysis by Dominic Cleal <dcleal@redhat.com>

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
(#12463) add secure `replace_file` to Puppet::Util

There is some complex logic around replacing an existing file safely, and it
used to be scattered all over the tree - making the whole system much harder
to use nicely and pleasantly.

It is much better that we provide a central, and easy to use, method for
achieving that specific and common goal in a consistent, secure, and easy to
audit fashion.

Based on code submitted by me on 2010-04-08.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
(#12462) user_role_add: use `replace_file` for /etc/shadow

The user_role_add provider for user management previously open-coded the safe,
atomic replacement of /etc/shadow after in modified it.

Mostly even safely, except that it didn't enforce permissions on the temporary
file, so might have spilled data to third parties, if tempfile isn't
sufficiently secure.  (Ruby makes no promises about tempfile mode.)

We replace that with the standard, central replace_file API, which ensures
that is done in a safe, correct, and standard fashion.

On the way through this removes the window where this could previously have
lost the content of /etc/shadow due to an unfortunately timed crash, by
ensuring we fsync the content of the temporary file.

It also documents, but doesn't eliminate, the lack of locking and other races
around this update to the shadow file.

Finally, some minor code and test updates to make it easier to test this on
fake data, rather than like on your own /etc/shadow file...

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
(#12460) use `replace_file` for the .k5login file

Previously this hand-coded replacing the .k5login file; Replacing that with
the standard API ensures consistent, safe, and atomic updates of the target
file.

It also reduces the cognitive burden of the provider, since the semantics of
the standard method are clearer than the semantics of the type.

Finally, this commit adds some tests for the type, and the inline provider, to
help ensure that the type continues to work into the future.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
(#12463) eliminate `secure_open` in favour of `replace_file`

None of the users of `secure_open` in the codebase actually want to achieve a
result different from `replace_file`, so we might as well eliminate the older
API in favour of one that is easier to use and clearer in intent.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Copy owner/group in replace_file

If the file doesn't exist, this will still use the current user/group as
the uid/gid of the file.
Document uid/gid-related methods in Puppet::Util
Remove unnecessary fallbacks in change_{user,group}

These methods were attempting to call change_privilege, and rescuing
NotImplementedError, to use our own implementation of similar behavior.
As it turns out, the only system on which change_privilege is not
implemented is Windows, which these methods already don't support. So
there's no reason to have a fallback that would only ever fail or not be
reached.
Fix Rails compatibility code to be less stupid.

When the Inventory ActiveRecord node object was implemented, an alias was
created to make the `scope` vs `named_scope` change over the Rails 2.x to 3.x
releases work nicely.

Sadly, this did this by using the older name, and creating an alias on the
modern releases.  That works great until the 3.2.x release, where the
internals changed and the compatibility stuff broke.

Instead, we apply the change so that the modern version works for older
releases, which should be much more robust - not least because they don't
develop on the older versions, so they are not a moving target.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Fix stubbing of ActiveRecord that doesn't work in AR 3.2.*

These tests worked really hard to try and stub out the AR stack and avoid
using a database - which worked, until the AR 3.2 series changed their
internals and so the stubbing stopped working.

Instead, rewrite the tests to actually use a database.  Works much better and
catches way more errors, even if the tests run marginally less often.
Honestly, though, almost everything here is database layer behaviour...

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Make PuppetSpec::Files methods available at module level.

Previously you could only access the `tmpfile` and `tmpdir` helpers by mixing
the module in somewhere, despite them exclusively mutating global state.

This became inconvenient when trying to centralize the database setup, so I
moved them to module functions and made the helpers that mix in defer to the
module level methods.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Clean up and unify scratch database setup logic.

Now that we have a pile of places all trying to do the same setup and
exclusion for SQLite in their tests, it pays to push all that into a central
location and make it uniformly available to all the tests.

This provides a nice, global method that can be invoked by any test suite to
configure the database, and then uses that everywhere that was doing scratch
database setup.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Prior to this commit we hard coded paths in two tests that depended on
our CI system directory structure. This made it hard to use our
acceptance suite without also including the exact same setup. It also
increased the cost of maintaining our CI setup.

This uses a path relative to the test itself (the file that it SCPs
should always be in the same directory as the test itself)

Signed-off-by: Justin Stoller <justin@puppetlabs.com>
Merge pull request #509 from justinstoller/bug/2.6.x/12692-dont_hard_code_paths_in_tests

(#12692) Don't hard code CI paths into tests
Updating CHANGELOG and lib/puppet.rb for 2.6.14
(#4862) Stop using EventLoop in the Puppet daemon.

This eliminates the places in the code that use the EventLoop model directly:
the two timers established to check configuration changes and run the agent,
and the invocation of the main loop in daemon mode.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
(#4862) `returning` is not a standard Ruby method.

The `returning(foo) do ... end` idiom used in this method isn't a standard
part of Ruby; it comes from the event-loop better definers code.  Since this
is the one occurrence in the source tree, might as well open-code it.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
(#4862) define_method is not a public method in Ruby.

The `better-definers` part of the EventLoop library change `define_method` to
be public on all objects, rather than private.  This isn't standard in Ruby,
and we only had one place that wasn't respecting this to start with.

Rather than retaining this divergence we just use `send` to trigger the
behaviour externally in the one place that is needed.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>