Defined functions and added comments. No functional change.
authorPhilipp Spitzer <philipp@spitzer.priv.at>
Tue, 29 May 2012 19:46:44 +0000 (21:46 +0200)
committerPhilipp Spitzer <philipp@spitzer.priv.at>
Tue, 29 May 2012 19:46:44 +0000 (21:46 +0200)
findwwwritable.py

index 346dc90..bcbb917 100755 (executable)
@@ -1,39 +1,72 @@
 #!/usr/bin/python
+# python 2.x is used
+
 import os
 import stat
 from os.path import join
 
-wwwdata_uid = 33
-wwwdata_gids = [33, 42, 121, 127]
 
-# collect bad files
-bad_dirs = [] # wwwdata has write permissions
+def collect_writable_dirs(rootdir, uid, gids):
+    """Returns a list of directories below rootdir (including rootdir) that are writeable 
+    by the user with the given uid or gids or that are world writeable.
+    Normally, uid is the user id of the apache user (e.g. www-data) and gids is a list
+    of group ids this user is member of.
+    
+    :param rootdir: string. directory where the search should start at
+    :param uid: integer user id
+    :param gids: list of integer group ids"""
+    assert isinstance(rootdir, str)
+    assert isinstance(uid, int)
+    assert isinstance(gids, list)
+    for gid in gids: assert isinstance(gid, int)
+
+    writable_dirs = [] # dirs with write permissions - this list is filled by this function
+
+    for root, dirs, files in os.walk(rootdir):
+        for d in dirs:
+            dp = join(root, d) # dp is the dir with path
+            s = os.lstat(dp)
+            if (s.st_mode & stat.S_IFLNK) == stat.S_IFLNK: continue # skip symlinks
+            if s.st_uid == uid and (s.st_mode & stat.S_IWUSR) > 0:
+                writable_dirs.append(dp)
+            elif s.st_gid in gids and (s.st_mode & stat.S_IWGRP) > 0:
+                writable_dirs.append(dp)
+            elif (s.st_mode & stat.S_IWOTH) > 0:
+                writable_dirs.append(dp)
+
+    return writable_dirs
+
+
+
+def summarize_dirs(writable_dirs):
+    """Takes a list of directories and omits each subdirectory if its parent directory
+    is also included in the list. This list is modified "in place" (nothing is returned).
+
+    :param writeable_dirs: List of directories (strings)."""
+    writable_dirs = sorted(writable_dirs)
 
-for root, dirs, files in os.walk('/home'):
-       for f in dirs:
-               fp = join(root, f) # fp is the dir with path
-               s = os.lstat(fp)
-               if (s.st_mode & stat.S_IFLNK) == stat.S_IFLNK: continue # skip symlinks
-               if s.st_uid == wwwdata_uid and (s.st_mode & stat.S_IWUSR) > 0:
-                       bad_dirs.append(fp)
-               elif s.st_gid in wwwdata_gids and (s.st_mode & stat.S_IWGRP) > 0:
-                       bad_dirs.append(fp)
-               elif (s.st_mode & stat.S_IWOTH) > 0:
-                       bad_dirs.append(fp)
+    i = 0
+    while i < len(writable_dirs)-1:
+        if writable_dirs[i+1].startswith(writable_dirs[i] + '/'):
+            del writable_dirs[i+1]
+        else:
+            i += 1
 
 
-bad_dirs = sorted(bad_dirs)
 
+if __name__ == '__main__':
 
-i = 0
-while i < len(bad_dirs)-1:
-       if bad_dirs[i+1].startswith(bad_dirs[i] + '/'):
-               del bad_dirs[i+1]
-       else:
-               i += 1
+    # variables
+    uid = 33                   # user id of the user whos write permissions should be found
+    gids = [33, 42, 121, 127]  # group ids of the user whos write permissions should be found
+    rootdir = '/home'          # directory where the seach is started
 
+    # collect and summarize writeable directories
+    writable_dirs = collect_writable_dirs(rootdir, uid, gids)
+    summarize_dirs(writable_dirs)
 
-for fp in bad_dirs:
-       print fp
+    # print writeable directories
+    for d in writable_dirs:
+        print d