Skip to content

Commit 6cf9094

Browse files
committed
Make sure permissions on cookie files are set sanely
Signed-off-by: Patrick Uiterwijk <puiterwijk@redhat.com>
1 parent e9b17d3 commit 6cf9094

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

fedora/client/__init__.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
.. moduleauthor:: Luke Macken <lmacken@redhat.com>
2929
.. moduleauthor:: Toshio Kuratomi <tkuratom@redhat.com>
3030
'''
31+
import errno
32+
import os
3133
import warnings
3234

3335
from munch import Munch
@@ -113,6 +115,16 @@ def __repr__(self):
113115
self.name, self.message, self.extras)
114116

115117

118+
class UnsafeFileError(Exception):
119+
def __init__(self, filename, message):
120+
super(UnsafeFileError, self).__init__(message)
121+
self.message = message
122+
self.filename = filename
123+
124+
def __str__(self):
125+
return 'Unsafe file permissions! {}: {}'.format(self.filename,
126+
self.message)
127+
116128

117129
# Backwards compatibility
118130
class DictContainer(Munch):
@@ -123,6 +135,23 @@ def __init__(self, *args, **kwargs):
123135
Munch.__init__(self, *args, **kwargs)
124136

125137

138+
def check_file_permissions(filename, allow_notexists=False):
139+
if os.path.islink(filename):
140+
raise UnsafeFileError(filename, 'File is a symlink')
141+
try:
142+
stat = os.stat(filename)
143+
except OSError as e:
144+
if e.errno == errno.ENOENT and allow_notexists:
145+
return
146+
raise
147+
if stat.st_uid != os.getuid():
148+
raise UnsafeFileError(filename, 'File not owned by current user')
149+
if stat.st_gid != os.getgid():
150+
raise UnsafeFileError(filename, 'File not owner by primary group')
151+
if stat.st_mode & 0o007:
152+
raise UnsafeFileError(filename, 'File is world-readable')
153+
154+
126155
# We want people to be able to import fedora.client.*Client directly
127156
# pylint: disable-msg=W0611
128157
from fedora.client.proxyclient import ProxyClient

fedora/client/openidbaseclient.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@
4747
from kitchen.text.converters import to_bytes
4848

4949
from fedora import __version__
50-
from fedora.client import AuthError, LoginRequiredError, ServerError
50+
from fedora.client import (AuthError,
51+
LoginRequiredError,
52+
ServerError,
53+
UnsafeFileError,
54+
check_file_permissions)
5155
from fedora.client.openidproxyclient import (
5256
OpenIdProxyClient, absolute_url, openid_login)
5357

@@ -182,7 +186,7 @@ def _initialize_session_cache(self):
182186
# for their password over and over.
183187
if not os.path.isdir(b_SESSION_DIR):
184188
try:
185-
os.makedirs(b_SESSION_DIR, mode=0o755)
189+
os.makedirs(b_SESSION_DIR, mode=0o750)
186190
except OSError as err:
187191
log.warning('Unable to create {file}: {error}'.format(
188192
file=b_SESSION_DIR, error=err))
@@ -301,6 +305,12 @@ def _load_cookies(self):
301305
if not self.cache_session:
302306
return
303307

308+
try:
309+
check_file_permissions(b_SESSION_FILE, True)
310+
except UnsafeFileError as e:
311+
log.debug('Current sessions ignored: {}'.format(str(e)))
312+
return
313+
304314
try:
305315
with self.cache_lock:
306316
with open(b_SESSION_FILE, 'rb') as f:
@@ -312,24 +322,33 @@ def _load_cookies(self):
312322
except IOError:
313323
# The file doesn't exist, so create it.
314324
log.debug("Creating %s", b_SESSION_FILE)
325+
oldmask = os.umask(0o027)
315326
with open(b_SESSION_FILE, 'wb') as f:
316327
f.write(json.dumps({}).encode('utf-8'))
328+
os.umask(oldmask)
317329

318330
def _save_cookies(self):
319331
if not self.cache_session:
320332
return
321333

322334
with self.cache_lock:
323335
try:
336+
check_file_permissions(b_SESSION_FILE, True)
324337
with open(b_SESSION_FILE, 'rb') as f:
325338
data = json.loads(f.read().decode('utf-8'))
339+
except UnsafeFileError as e:
340+
log.debug('Clearing sessions: {}'.format(str(e)))
341+
os.unlink(b_SESSION_FILE)
342+
data = {}
326343
except Exception:
327344
log.warn("Failed to open cookie cache before saving.")
328345
data = {}
329346

347+
oldmask = os.umask(0o027)
330348
data[self.session_key] = self._session.cookies.items()
331349
with open(b_SESSION_FILE, 'wb') as f:
332350
f.write(json.dumps(data).encode('utf-8'))
351+
os.umask(oldmask)
333352

334353

335354
__all__ = ('OpenIdBaseClient', 'requires_login')

0 commit comments

Comments
 (0)