• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/scripting/python/samba/
1#!/usr/bin/python
2
3# Unix SMB/CIFS implementation.
4# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
5# Copyright (C) Matthias Dieter Wallnoefer 2009
6#
7# Based on the original in EJS:
8# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 3 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22#
23
24"""Convenience functions for using the SAM."""
25
26import samba
27import glue
28import ldb
29from samba.idmap import IDmapDB
30import pwd
31import time
32import base64
33
34__docformat__ = "restructuredText"
35
36class SamDB(samba.Ldb):
37    """The SAM database."""
38
39    def __init__(self, url=None, lp=None, modules_dir=None, session_info=None,
40                 credentials=None, flags=0, options=None):
41        """Opens the SAM Database
42        For parameter meanings see the super class (samba.Ldb)
43        """
44
45        self.lp = lp
46        if url is None:
47                url = lp.get("sam database")
48
49        super(SamDB, self).__init__(url=url, lp=lp, modules_dir=modules_dir,
50                session_info=session_info, credentials=credentials, flags=flags,
51                options=options)
52
53        glue.dsdb_set_global_schema(self)
54
55    def connect(self, url=None, flags=0, options=None):
56        super(SamDB, self).connect(url=self.lp.private_path(url), flags=flags,
57                options=options)
58
59    def domain_dn(self):
60        # find the DNs for the domain
61        res = self.search(base="",
62                          scope=ldb.SCOPE_BASE,
63                          expression="(defaultNamingContext=*)",
64                          attrs=["defaultNamingContext"])
65        assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None)
66        return res[0]["defaultNamingContext"][0]
67
68    def enable_account(self, filter):
69        """Enables an account
70
71        :param filter: LDAP filter to find the user (eg samccountname=name)
72        """
73        res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
74                          expression=filter, attrs=["userAccountControl"])
75        assert(len(res) == 1)
76        user_dn = res[0].dn
77
78        userAccountControl = int(res[0]["userAccountControl"][0])
79        if (userAccountControl & 0x2):
80            userAccountControl = userAccountControl & ~0x2 # remove disabled bit
81        if (userAccountControl & 0x20):
82            userAccountControl = userAccountControl & ~0x20 # remove 'no password required' bit
83
84        mod = """
85dn: %s
86changetype: modify
87replace: userAccountControl
88userAccountControl: %u
89""" % (user_dn, userAccountControl)
90        self.modify_ldif(mod)
91
92    def force_password_change_at_next_login(self, filter):
93        """Forces a password change at next login
94
95        :param filter: LDAP filter to find the user (eg samccountname=name)
96        """
97        res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
98                          expression=filter, attrs=[])
99        assert(len(res) == 1)
100        user_dn = res[0].dn
101
102        mod = """
103dn: %s
104changetype: modify
105replace: pwdLastSet
106pwdLastSet: 0
107""" % (user_dn)
108        self.modify_ldif(mod)
109
110    def newuser(self, username, unixname, password, force_password_change_at_next_login_req=False):
111        """Adds a new user
112
113        Note: This call adds also the ID mapping for winbind; therefore it works
114        *only* on SAMBA 4.
115
116        :param username: Name of the new user
117        :param unixname: Name of the unix user to map to
118        :param password: Password for the new user
119        :param force_password_change_at_next_login_req: Force password change
120        """
121        self.transaction_start()
122        try:
123            user_dn = "CN=%s,CN=Users,%s" % (username, self.domain_dn())
124
125            # The new user record. Note the reliance on the SAMLDB module which
126            # fills in the default informations
127            self.add({"dn": user_dn,
128                "sAMAccountName": username,
129                "objectClass": "user"})
130
131            # Sets the password for it
132            self.setpassword("(dn=" + user_dn + ")", password,
133              force_password_change_at_next_login_req)
134
135            # Gets the user SID (for the account mapping setup)
136            res = self.search(user_dn, scope=ldb.SCOPE_BASE,
137                              expression="objectclass=*",
138                              attrs=["objectSid"])
139            assert len(res) == 1
140            user_sid = self.schema_format_value("objectSid", res[0]["objectSid"][0])
141
142            try:
143                idmap = IDmapDB(lp=self.lp)
144
145                user = pwd.getpwnam(unixname)
146
147                # setup ID mapping for this UID
148                idmap.setup_name_mapping(user_sid, idmap.TYPE_UID, user[2])
149
150            except KeyError:
151                pass
152        except:
153            self.transaction_cancel()
154            raise
155        self.transaction_commit()
156
157    def setpassword(self, filter, password, force_password_change_at_next_login_req=False):
158        """Sets the password for a user
159
160        Note: This call uses the "userPassword" attribute to set the password.
161        This works correctly on SAMBA 4 and on Windows DCs with
162        "2003 Native" or higer domain function level.
163
164        :param filter: LDAP filter to find the user (eg samccountname=name)
165        :param password: Password for the user
166        :param force_password_change_at_next_login_req: Force password change
167        """
168        self.transaction_start()
169        try:
170            res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
171                              expression=filter, attrs=[])
172            assert(len(res) == 1)
173            user_dn = res[0].dn
174
175            setpw = """
176dn: %s
177changetype: modify
178replace: userPassword
179userPassword:: %s
180""" % (user_dn, base64.b64encode(password))
181
182            self.modify_ldif(setpw)
183
184            if force_password_change_at_next_login_req:
185                self.force_password_change_at_next_login(
186                  "(dn=" + str(user_dn) + ")")
187
188            #  modify the userAccountControl to remove the disabled bit
189            self.enable_account(filter)
190        except:
191            self.transaction_cancel()
192            raise
193        self.transaction_commit()
194
195    def setexpiry(self, filter, expiry_seconds, no_expiry_req=False):
196        """Sets the account expiry for a user
197
198        :param filter: LDAP filter to find the user (eg samccountname=name)
199        :param expiry_seconds: expiry time from now in seconds
200        :param no_expiry_req: if set, then don't expire password
201        """
202        self.transaction_start()
203        try:
204            res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
205                          expression=filter,
206                          attrs=["userAccountControl", "accountExpires"])
207            assert(len(res) == 1)
208            user_dn = res[0].dn
209
210            userAccountControl = int(res[0]["userAccountControl"][0])
211            accountExpires     = int(res[0]["accountExpires"][0])
212            if no_expiry_req:
213                userAccountControl = userAccountControl | 0x10000
214                accountExpires = 0
215            else:
216                userAccountControl = userAccountControl & ~0x10000
217                accountExpires = glue.unix2nttime(expiry_seconds + int(time.time()))
218
219            setexp = """
220dn: %s
221changetype: modify
222replace: userAccountControl
223userAccountControl: %u
224replace: accountExpires
225accountExpires: %u
226""" % (user_dn, userAccountControl, accountExpires)
227
228            self.modify_ldif(setexp)
229        except:
230            self.transaction_cancel()
231            raise
232        self.transaction_commit();
233
234