Browse Source

First version

Johan 6 years ago
parent
commit
562fe9a5e9
3 changed files with 148 additions and 1 deletions
  1. 33
    1
      README.md
  2. 36
    0
      gaps.py
  3. 79
    0
      gapslib.py

+ 33
- 1
README.md View File

@@ -1,4 +1,36 @@
1 1
 samba4-gaps
2 2
 ===========
3 3
 
4
-Google Apps Password Sync for Samba4
4
+Google Apps Password Sync for Samba4
5
+
6
+Reads from you'r Samba4 AD and updates changes password to Google Apps in SHA1 format. Note that this solution requires you to run:
7
+samba-tool domain passwordsettings set --store-plaintext=on
8
+
9
+And requires you to use "Store passwords using reversible encryption" for each users. Can be enabled with MS Active Directory snap in tool.
10
+
11
+Python Dependencies
12
+===========
13
+
14
+- daemon
15
+- gdata
16
+- hashlib
17
+- syslog
18
+- samba
19
+
20
+gdata can be downloaded from https://code.google.com/p/gdata-python-client/downloads/detail?name=gdata-2.0.17.zip&can=2&q=
21
+
22
+
23
+Install notes
24
+===========
25
+
26
+1. Copy gaps.py and gapslib.py to desired locations.
27
+2. Run gaps.py in cron or at startup from rc.local, or both (if you wan't to schedule a restart). Change your settings in gapslib.py to fit your setup.
28
+3. Change syslog to desired local and add it to your syslog config for custom log file
29
+4. Start the daemon and watch log file for updates
30
+
31
+
32
+If you are having trouble loading samba python modules please copy or symlink files and dirs in "/usr/local/samba/lib/python2.7/site-packages/" to "/usr/lib/python2.7/"
33
+
34
+Debug
35
+===========
36
+If the daemon don't start change /dev/null to dev/tty in gaps.py and watch for error messages.

+ 36
- 0
gaps.py View File

@@ -0,0 +1,36 @@
1
+#!/usr/bin/python
2
+
3
+# Google Apps Passwords Sync for Samba4
4
+# author Johan Johansson johan@baboons.se
5
+# Free to use!
6
+
7
+import time
8
+import gapslib
9
+import os.path
10
+import sys
11
+
12
+from daemon import runner
13
+
14
+class App():
15
+    def __init__(self):
16
+        self.stdin_path = '/dev/null'
17
+        self.stdout_path = '/dev/null'
18
+        self.stderr_path = '/dev/null'
19
+        self.pidfile_path =  '/var/run/gaps.pid'
20
+        self.pidfile_timeout = 60
21
+
22
+        if len(sys.argv) >= 2:
23
+          if sys.argv[1] == "start":
24
+            if(os.path.exists(self.pidfile_path)):
25
+              print "GAPS is already running. stop|start|restart"
26
+              sys.exit()
27
+
28
+
29
+    def run(self):
30
+        while True:
31
+            gapslib.run()
32
+            time.sleep(60)
33
+
34
+app = App()
35
+daemon_runner = runner.DaemonRunner(app)
36
+daemon_runner.do_action()

+ 79
- 0
gapslib.py View File

@@ -0,0 +1,79 @@
1
+#!/usr/bin/env python
2
+import binascii
3
+import quopri
4
+import sys
5
+import textwrap
6
+import hashlib
7
+import syslog
8
+import gdata.apps.multidomain.client;
9
+
10
+from samba.credentials import Credentials
11
+from samba.auth import system_session
12
+from samba.dcerpc import drsblobs
13
+from samba.ndr import ndr_unpack
14
+from samba.samdb import SamDB
15
+
16
+### Custom Settings ###
17
+gaDomain = "yourdomain.com"
18
+gaEmail = "adminuser@yourdomain.com"
19
+gaPassword = "yourpassword"
20
+sambaPrivate = "/usr/local/samba/private"
21
+sambaPath = "DC=YOURDOMAIN,DC=COM"
22
+adBase = "ou=Domain Users,dc=yourdomain,dc=com"
23
+
24
+## Open connection to Syslog ##
25
+syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_LOCAL3)
26
+
27
+## Cached SHA 1 Passwords ##
28
+passwords = {}
29
+
30
+## Connect to Google ##
31
+client = gdata.apps.multidomain.client.MultiDomainProvisioningClient(domain=gaDomain)
32
+client.ssl = True
33
+client.ClientLogin(email=gaEmail, password=gaPassword, source='apps')
34
+
35
+
36
+def esc(s):
37
+    return quopri.encodestring(s, quotetabs=True)
38
+
39
+def print_entry(dn, user, mail, pwd):
40
+    print '%s\t%s\t%s\t%s' % tuple([esc(p) for p in [dn, user, mail, pwd]])
41
+
42
+def update_password(mail, pwd):
43
+    password = hashlib.sha1(pwd).hexdigest()
44
+
45
+    if passwords.has_key(mail):
46
+        if passwords[mail] == password:
47
+            return 0
48
+    try:
49
+        user = client.RetrieveUser(mail)
50
+    except:
51
+        syslog.syslog(syslog.LOG_WARNING, '[WARNING] Account %s not found' % mail)
52
+        return 0
53
+
54
+    user.password = password
55
+    user.hash_function="SHA-1"
56
+    try:
57
+        client.UpdateUser(mail, user)
58
+        syslog.syslog(syslog.LOG_WARNING, '[NOTICE] Updated password for %s' % mail)
59
+        passwords[mail] = password
60
+    except:
61
+        syslog.syslog(syslog.LOG_WARNING, '[ERROR] Could not update password for %s ' % mail)
62
+
63
+def run():
64
+    creds = Credentials()
65
+    samdb = SamDB(url=(sambaPrivate + "/sam.ldb.d/" + sambaPath + ".ldb"), session_info=system_session(), credentials=creds.guess())
66
+    res = samdb.search(base="adBase", expression="(objectClass=user)", attrs=["supplementalCredentials", "sAMAccountName", "mail"])
67
+
68
+    for r in res:
69
+         if not "supplementalCredentials" in r:
70
+             sys.stderr.write("%s: no supplementalCredentials\n" % str(r["dn"]))
71
+             continue
72
+         scb = ndr_unpack(drsblobs.supplementalCredentialsBlob, str(r["supplementalCredentials"]))
73
+         for p in scb.sub.packages:
74
+             if p.name == "Primary:CLEARTEXT":
75
+                 update_password(str(r["mail"]), binascii.unhexlify(p.data).decode("utf16"))
76
+
77
+
78
+
79
+

Loading…
Cancel
Save