google / google-authenticator-libpam

Apache License 2.0
1.76k stars 281 forks source link

error : Failed to update secret file "/home/testuser1/.google_authenticator": Permission denied #101

Open tagorenathv opened 6 years ago

tagorenathv commented 6 years ago

log in /var/log/secure : sshd(pam_google_authenticator)[6902]: Accepted google_authenticator for testuser1 sshd(pam_google_authenticator)[6902]: Failed to delete tempfile “/home/testuser1/.google_authenticator~Q6SNiK”: No such file or directory sshd(pam_google_authenticator)[6902]: Failed to update secret file “/home/testuser1/.google_authenticator”: Permission denied sshd[6900]: error: PAM: Authentication failure for testuser1 from XXX.XXX.XX.XX

.google_authenticator have 600 permission. Followed all steps as mentioned, still not able to login. Using RHEL 7.5 AMI.

ThomasHabets commented 6 years ago

Sounds like it's related to SELinux. Do you run it, and could you try turning it off to test?

tagorenathv commented 6 years ago

You mean SELinux = disabled? Tried that too. Still no luck.!

ThomasHabets commented 6 years ago

What does your pam config file look like?

Who owns /home/testuser1/.google_authenticator?

What are the ownerships and permissions on /home/testuser1?

tagorenathv commented 6 years ago

for .google_authenticator: -rw-------. 1 testuser1 testuser1 136 Jul 18 03:37 .google_authenticator

/etc/pam.d conf: auth required pam_sepermit.so

auth substack password-auth

auth required /usr/local/lib/security/pam_google_authenticator.so echo_verification_code auth include postlogin

/etc/ssh/sshd_config conf: ChallengeResponseAuthentication yes AuthenticationMethods publickey,keyboard-interactive

tried almost all module options.

ThomasHabets commented 6 years ago

So getenforce says Disabled, verifying that SELinux is off?

What are the permissions and ownerships on /home/testuser1? ls -ld /home/testuser1

(I've improved the error message a bit in https://github.com/google/google-authenticator-libpam/commit/a48e6492d3a8a15c88002c6959e9de8dba5b0bbc, but won't help us here)

tagorenathv commented 6 years ago

these are my complete details:

/var/log/secure : debug log => sshd(pam_google_authenticator)[4498]: debug: no scratch code used from "/home/testuser1/.google_authenticator" sshd(pam_google_authenticator)[4498]: Accepted google_authenticator for testuser1 sshd(pam_google_authenticator)[4498]: Failed to create tempfile "/home/testuser1/.google_authenticator~1lqc2M": Permission denied sshd(pam_google_authenticator)[4498]: Failed to update secret file "/home/testuser1/.google_authenticator": Permission denied sshd(pam_google_authenticator)[4498]: debug: end of google_authenticator for "testuser1". Result: Authentication failure sshd[4493]: error: PAM: Authentication failure for testuser1 from x.x.x.x sshd(pam_google_authenticator)[4499]: debug: start of google_authenticator for "testuser1" sshd(pam_google_authenticator)[4499]: debug: Secret file permissions are 0600. Allowed permissions are 0600 sshd(pam_google_authenticator)[4499]: debug: "/home/testuser1/.google_authenticator" read sshd(pam_google_authenticator)[4499]: debug: shared secret in "/home/testuser1/.google_authenticator" processed sshd[4493]: Postponed keyboard-interactive for testuser1 from x.x.x.x port 54109 ssh2 [preauth]

ls -ld /home/testuser1/ => drwx------. 3 testuser1 testuser1 124 Jul 18 09:54 /home/testuser1/

ls -ld /home/testuser1/.google_authenticator => -rw-------. 1 testuser1 testuser1 136 Jul 18 09:54 /home/testuser1/.google_authenticator

/etc/selinux/config => SELINUX=disabled

/etc/pam.d/sshd =>

%PAM-1.0

auth required pam_sepermit.so

auth substack password-auth

auth required /usr/local/lib/security/pam_google_authenticator.so debug echo_verification_code auth include postlogin

/etc/ssh/sshd_config => ChallengeResponseAuthentication yes AuthenticationMethods publickey,keyboard-interactive

with debug logs it seems perm issues, but with other prems for .google_authenticator or for home folder m getting Server refused our key

ThomasHabets commented 6 years ago

Yeah the problem is the Permission denied. Permissions on home directory and file look good, so it should wotrk.

Again, does running getenforce say Disabled, verifying that SELinux is off?

tagorenathv commented 6 years ago

[testuser1@ip-x-x-x-x~]$ getenforce Enforcing

But at /etc/selinux/config: => SELINUX=disabled

ThomasHabets commented 6 years ago

Did you reboot after setting that?

I've not done anything with SELinux, nor do I run RHEL, so don't know what else to check.

tagorenathv commented 6 years ago

I havent and i dont think its possible (prod instances) . Do we have any other procedure to make SELINUX disable change got reflected without reboot? With this I think it will work. Please suggest. Thankyou.

ThomasHabets commented 6 years ago

I think by design it's not possible to turn it off on a running system. E.g. see this manpage.

You could place the .google_authenticator somewhere other than the user's home directory using secret=/etc/ga/$USER/.google_authenticator and create one new directory there per user.

I'm not sure if SELinux would block that, but you could try it.

tagorenathv commented 6 years ago

still same.

sshd(pam_google_authenticator)[18140]: Failed to create tempfile "/etc/ga/testuser1/.google_authenticator~BqkkJ9": Permission denied sshd(pam_google_authenticator)[18140]: Failed to update secret file "/etc/ga/testuser1/.google_authenticator": Permission denied

folder permissions and .google_authenticator are good. I think only way to make this work is to disable SELINUX.

ThomasHabets commented 6 years ago

You could make root own all the directories and files under /etc/ga/ and run with user=root. That at least should work. But users won't be able to manage their own configs then.

loa-in- commented 6 years ago

Try setting proper SELinux context. SELinux is not something to be avoided. I know it's a confusing (at first) world, but it pays off. Look for tutorials or ask me privately.

DPStokesNZ commented 4 years ago

You definitely don't want to disable SELinux. The issue here is that later versions of this software create temporary files in the user home directory (by default) before (presumably) copying the contents into the overarching configuration file then removing them. Thus, the SSH process needs to have permission to perform this task.

One solution to allowing the GA software to operate under SELinux is to move the Google Authenticator configuration file to a folder that both SSH and the user can access, e.g.:

  1. Add a local SELinux file context for a new home subdirectory: sudo semanage fcontext -a -t auth_home_t "/home/[^/]+/\.ga(/.*)?"
  2. Create the new subdirectory: mkdir -p ~\.ga
  3. Restore the SELinux context restorecon -Rv ~\.ga; and/or import SELinux module which transforms the context of any directory called .ga created in a user home directory using the template:
    policy_module(google_authenticator_transfrom, 1.0)
    gen_require(`
    type unconfined_t, user_home_dir_t, auth_home_t;
    ')
    filetrans_pattern(unconfined_t, user_home_dir_t, auth_home_t, dir, ".ga")
  4. "Move" your existing .google_authenticator file: cat ~/.google_authenticator > ~/.ga/.google_authenticator && chmod 0400 ~/.ga/.google_authenticator
  5. Configure PAM to use new location by appending secret=${HOME}/.ga/.google_authenticator to the end of the auth required pam_google_authenticator.so line in /etc/pam.d/sshd
  6. Restart SSH daemon.
jdbarnes-isi commented 4 years ago

This policy, created by audit2allow, fixed the problem, but it seems a bit clunky to allow ssh_t do all it does... the authenticator lib writes a temp file, deletes a temp file, and requires some kind of renaming as well.

--- begin avrule block ---
decl 1:
commons: <empty>
classes: file{  create  open  read  rename  setattr  unlink  write }
roles  : <empty>
types  : sshd_t user_home_dir_t
users  : <empty>
bools  : <empty>
levels : <empty>
cats   : <empty>

log entries from denials:

Failed to read "/home/$USER/.google_authenticator"
Failed to create tempfile "/home/$USER/.google_authenticator~pNn1dA": Permission denied
Failed to update secret file "/home/$USER/.google_authenticator": Permission denied
Failed to delete tempfile "/home/$USER/.google_authenticator~TuINiX": Permission denied
jdbarnes-isi commented 4 years ago

I ran into another AVC denial for getattr... so, my conclusion is that it seems like the cleanest solution on Fedora is to use the existing permissions from the ssh selinux module to work around this. From my limited testing yesterday and today, this should solve the problem without having to create a custom selinux policy.

1. Verify that you have the module enabled and the context exists

$ sudo semodule -l | grep ^ssh
$ sudo semanage fcontext -l | grep 'unconfined_u:object_r:ssh_home_t'

the line from the selinux module looks like this

/home/[^/]+/\.ssh(/.*)?        all files        unconfined_u:object_r:ssh_home_t:s0

2. Move the file into a location with the correct context, and update it's context

~]$ mv .google_authenticator .ssh/
~]$ restorecon -Rv .ssh/
Relabeled /home/user1/.ssh/.google_authenticator from unconfined_u:object_r:auth_home_t:s0 to unconfined_u:object_r:ssh_home_t:s0

3. Set the library parameter to use the new location

And in your pam.d/[service] file, set the file location to $HOME/.ssh/.google_authenticator pam_google_authenticator.so secret=~/.ssh/.google_authenticator


It looks like the rpm creates contexts as auth_home_t, so sshd_t must operate on auth_home_t files for the defaults to work. There is probably a way to better label these or to include a policy in the rpm that makes this work with sshd.

/home/[^/]+/\.google_authenticator                 all files          unconfined_u:object_r:auth_home_t:s0
/home/[^/]+/\.google_authenticator~                all files          unconfined_u:object_r:auth_home_t:s0
jhmartin commented 4 years ago

@jdbarnes-isi Your changed fixed it for CentOS 8.1.1911 as well.

H20-17 commented 3 years ago

I prefer the fix suggested by @DPStokesNZ over that of @jdbarnes-isi. AFAICS the fix suggested by @jdbarnes-isi will only work for ssh, but not for other servies, whereas the solution proposed by @DPStokesNZ will work for other things besides, such as Cockpit.

duritong commented 3 years ago

There needs to be some coordination to fix that properly and it is not yet fully clear what the best approach is.

Fact: We can't keep the secret file in ~/.google-authenticator on SELinux enabled systems, since the file trans can't work with regexp and thus files will be wrongly labeled all the time.

Suggestion is to have to secret in something like: ~/.config/google-authentictor/secret or ~/.config/ga/secret

Once we agreed on a different location (in a directory), we could add the path to the selinux-policy and then integrate it in the package.

Only doing that over a simply default config file for Fedora systems that points to the new location raises likely issues of the secret not be found, as the google-authenticator bin also expects the file in the standard location and you can't define another default it without patching. Also patching would mean, that we would likely need to check for the directory to exist and create otherwise and so the patch gets larger than what I would want to simply carry on in the package.

I would love to have thoughts by the owners of that repo, what they would be happy to go further. BUT we can't fix it for SELinux enabled systems as it behaves at the moment.

ThomasHabets commented 3 years ago

@duritong you're saying you want to patch it here, upstream, to not be a file directly in the home directory?

Seems reasonable. Is there a standards doc for how ~/.config/ is laid out?

Also it'd need to be backwards compatible, so it's not as simple as just changing the default. And if ~/.config doesn't exist then it needs to be mkdir'd. Same with any subdirs.

zpytela commented 3 years ago

@ThomasHabets This is the XDG specification: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html

jdbarnes-isi commented 3 years ago

Would someone want the authenticator secret to be the same across multiple services? I personally only use the secret for sshd, not sddm (nor have I tried to see if it integrates with sddm or any other auth stack).

Do services that might want to accept g.a. in the pam stack tolerate using their own existing config directories for this kind of file transformation that is done by g.a.-libpam?

Existing functionality works as long as it's documented that generating a single secret once won't be sufficient for all services, and that on SELinux-enabled sysems, you simply have to copy/move the secret somewhere that your service tolerates and restorecon -r.

duritong commented 3 years ago

@duritong you're saying you want to patch it here, upstream, to not be a file directly in the home directory?

Exactly. I think it make sense, instead of carrying a half-baked patch for Fedora/RHEL distros.

Seems reasonable. Is there a standards doc for how ~/.config/ is laid out?

based on @zpytela link, I would suggest to put the files into ~/.config/google-authenticator

Also it'd need to be backwards compatible, so it's not as simple as just changing the default. And if ~/.config doesn't exist then it needs to be mkdir'd. Same with any subdirs.

Yes and this is why it won't be a simple patch and I would be glad to have it integrated here. Thank you!

ThomasHabets commented 3 years ago

I'll accept a well-written pull request for this, but realistically I won't be implementing it myself.

Note that I will be picky about e.g. how to create the needed directories if they don't already exist.

antonio-antonucci commented 3 years ago

Hi @DPStokesNZ, I have tried your procedure, however I am still getting the following errors:

Failed to create tempfile "/root/.ga/.google_authenticator~s8p3zH": Permission denied Failed to update secret file "/root/.ga/.google_authenticator": Permission denied

Any hint?

duritong commented 3 years ago

Failed to create tempfile "/root/.ga/.google_authenticator~s8p3zH": Permission denied Failed to update secret file "/root/.ga/.google_authenticator": Permission denied

Did you add the filecontexts to your policy and apply the right context?

duritong commented 3 years ago

I'll accept a well-written pull request for this, but realistically I won't be implementing it myself.

Note that I will be picky about e.g. how to create the needed directories if they don't already exist.

I can not really commit to write such a patch and glad to have anybody picking that task up, with better C knowledge than me.

antonio-antonucci commented 3 years ago

@duritong, I guess so ... I created the .te file used "make -f" to get a .pp and finally used semodule -i to load the policy

DPStokesNZ commented 3 years ago

Hi @DPStokesNZ, I have tried your procedure, however I am still getting the following errors:

Failed to create tempfile "/root/.ga/.google_authenticator~s8p3zH": Permission denied Failed to update secret file "/root/.ga/.google_authenticator": Permission denied

Any hint?

Given that you are trying to use /root I would imagine that the semanage fcontext command won't match given that it is /home folder centric. You can check this with a simple ls -laZ ~ | grep ga and note that the context is probably still admin_home_t rather than auth_home_t.

I would suggest adding the following context then perform the restorecon command: sudo semanage fcontext -a -t auth_home_t "/root/\.ga(/.*)?"

FelixSchwarz commented 3 years ago

Also it'd need to be backwards compatible, so it's not as simple as just changing the default.

I quickly glanced over the current code on how to implement this. My initial idea was to tackle authentication first. For example google_authenticator() could try to use ~/.config/google-authenticator/secret first and then (if that file does not exist) fall back to the previous location (~/.google_authenticator). The assumption is that we still want hard-coded default filename(s) in the code and not a config file containing a default filename which has to be parsed at runtime.

Ideally we would only fall back if the path does not exist at all (but not in case of insecure file permissions) but looking at open_secret_file() it seems that it would be easier to fall back whenever the new path is not suitable. However we should not log Failed to read ... for the first try to avoid misleading (error) log messages.

Is that a reasonable approach? I did not write any pam modules before so I might be blissfully unaware of some security constraints. I'd be glad for any criticism before any code is written so I don't waste time.

Please note I can't really ensure I will come up with some usable code. Real life tends to insert itself at the worst possible moments...

ThomasHabets commented 3 years ago

What I'm thinking is that it may be best to create a new function open_first_secret_file() or something that tries one, then the other. You can extend the return value of open_secret_file() to be 0 on success, 1 on fail-but-continue, and 2 for final-fail?

The Failed to read message is deceptive anyway, it actually failed to open.

But if you wrap it in a function, and only that function calles open_secret_file, then you can do the logging from the caller depending on the return value, thus prevent double error logging. Also if both fail on open() you probably want to log just one line saying failed to open either of these two.

Maybe something like that?

FelixSchwarz commented 3 years ago

You can extend the return value of open_secret_file() to be 0 on success, 1 on fail-but-continue, and 2 for final-fail?

Currently open_secret_file() returns fd on success (so the code comment above that function is wrong/misleading) so I guess you mean -1 for fail-but-continue and -2 for final fail?

Otherwise I agree that this might be a good way to implement the feature.

ThomasHabets commented 3 years ago

Doh, I was fooled by my own incorrect comment on top of the function. :-(

FelixSchwarz commented 3 years ago

No worries, I can add a commit to a potential PR which fixes that (unless you want to fix that first - feel free to do so ofc).

ThomasHabets commented 3 years ago

I fixed the comment

FelixSchwarz commented 3 years ago

Currently get_secret_filename() is called within the privileged part of google_authenticator() while open_secret_file() is only called after unnecessary privileges were dropped.

(Sorry if all these detail questions are too much noise and I can understand if you don't want to spend so much time on that little feature you are not interested in. Please drop me a note and I'll try to come up with some working code without guidance - might be more hassle in the review though ;-).

ThomasHabets commented 3 years ago

I understand not wanting to waste time implementing something only to be asked to do the other way. :-)

Hmm… I don't see why get_secret_filename() should not be good, better even, to call after dropping privs. If you want to move things from before to after drop, then probably best to keep that a single commit. One commit, one conceptual change.

Up to you on char* vs char**+int. Whatever makes for cleanest code. I don't foresee a list to be needed in the future, so if it's cleaner to hard code two, then that's fine.

sebdanielsson commented 3 years ago

Any progress on this? Can't use google-authenticator with Cockpit on Fedora 34.

H20-17 commented 2 years ago

Has there been any progress on this?

ThomasHabets commented 2 years ago

None that I know. Note that what's left here is actually just a feature request to change the default secrets filename location. Nothing is preventing anyone using the option to PAM, and to the CLI when provisioning.

Red54 commented 2 years ago

Workaround:

  1. Save .google_authenticator to .yubico/ directory: google-authenticator -s .yubico/.google_authenticator

  2. Add this line to your PAM configuration file: auth required pam_google_authenticator.so secret=~/.yubico/.google_authenticator

SELinux added support for the .yubico/ directory in 2013, so most of the current systems support it: https://github.com/fedora-selinux/selinux-policy/commit/0d81967b8884426951150b126f0e63c294f503ec

Wotisrv commented 2 years ago

My personal workaround is semanage permissive -a cockpit_session_t. I still get the error messages but I can use Cockpit with Google Authenticator on Fedora 36 Server Edition.

EarlRamirez commented 1 year ago

Updating the label to ssh_home_t resolved the issue for me

m666m commented 1 month ago

Workaround:

  1. Save .google_authenticator to .yubico/ directory: google-authenticator -s .yubico/.google_authenticator
  2. Add this line to your PAM configuration file: auth required pam_google_authenticator.so secret=~/.yubico/.google_authenticator

SELinux added support for the .yubico/ directory in 2013, so most of the current systems support it: fedora-selinux/selinux-policy@0d81967

Sam problem on Fedora 40/ Fedora IOT:

$  sudo semanage fcontext -l | grep yubico
/home/[^/]+/\.yubico(/.*)?                         all files          unconfined_u:object_r:auth_home_t:s0 
/root/\.yubico(/.*)?                               all files          system_u:object_r:auth_home_t:s0

$  sudo semanage fcontext -l | grep .google_authenticator
/home/[^/]+/\.google_authenticator                 all files          unconfined_u:object_r:auth_home_t:s0 
/home/[^/]+/\.google_authenticator~                all files          unconfined_u:object_r:auth_home_t:s0 
/root/\.google_authenticator                       all files          system_u:object_r:auth_home_t:s0 
/root/\.google_authenticator~                      all files          system_u:object_r:auth_home_t:s0

Did it missing (/.*)? with install script ?

Resolved this by create a new dir, put the .google_authenticator here,then set the pam:

CFG_DIR=$HOME/.config/Google-authenticator
HOMEBASE=$(dirname $HOME)
mkdir -p $CFG_DIR

sudo semanage fcontext --add --type auth_home_t "$HOMEBASE/[^/]+/\.config/Google-authenticator(/.*)?"

sudo restorecon -Rv $CFG_DIR

cat ~/.google_authenticator |tee $CFGDIR/.google_authenticator && chmod 0400 $CFGDIR/.google_authenticator

sudo vi /etc/pam.d/sshd

    auth required pam_google_authenticator.so secret=${HOME}/.config/Google-authenticator/.google_authenticator

sudo systemctl restart sshd