~ubuntu-branches/ubuntu/vivid/samba/vivid

« back to all changes in this revision

Viewing changes to source4/scripting/python/samba/netcmd/pwsettings.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
#
 
3
# Sets password settings.
 
4
# (Password complexity, history length, minimum password length, the minimum
 
5
# and maximum password age) on a Samba4 server
 
6
#
 
7
# Copyright Matthias Dieter Wallnoefer 2009
 
8
# Copyright Andrew Kroeger 2009
 
9
# Copyright Jelmer Vernooij 2009
 
10
#
 
11
# This program is free software; you can redistribute it and/or modify
 
12
# it under the terms of the GNU General Public License as published by
 
13
# the Free Software Foundation; either version 3 of the License, or
 
14
# (at your option) any later version.
 
15
#
 
16
# This program is distributed in the hope that it will be useful,
 
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
# GNU General Public License for more details.
 
20
#
 
21
# You should have received a copy of the GNU General Public License
 
22
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
23
#
 
24
 
 
25
import samba.getopt as options
 
26
import ldb
 
27
 
 
28
from samba.auth import system_session
 
29
from samba.samdb import SamDB
 
30
from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX, DOMAIN_PASSWORD_STORE_CLEARTEXT
 
31
from samba.netcmd import Command, CommandError, Option
 
32
 
 
33
class cmd_pwsettings(Command):
 
34
    """Sets password settings
 
35
 
 
36
    Password complexity, history length, minimum password length, the minimum 
 
37
    and maximum password age) on a Samba4 server.
 
38
    """
 
39
 
 
40
    synopsis = "(show | set <options>)"
 
41
 
 
42
    takes_optiongroups = {
 
43
        "sambaopts": options.SambaOptions,
 
44
        "versionopts": options.VersionOptions,
 
45
        "credopts": options.CredentialsOptions,
 
46
        }
 
47
 
 
48
    takes_options = [
 
49
        Option("-H", help="LDB URL for database or target server", type=str),
 
50
        Option("--quiet", help="Be quiet", action="store_true"),
 
51
        Option("--complexity", type="choice", choices=["on","off","default"],
 
52
          help="The password complexity (on | off | default). Default is 'on'"),
 
53
        Option("--store-plaintext", type="choice", choices=["on","off","default"],
 
54
          help="Store plaintext passwords where account have 'store passwords with reversible encryption' set (on | off | default). Default is 'off'"),
 
55
        Option("--history-length",
 
56
          help="The password history length (<integer> | default).  Default is 24.", type=str),
 
57
        Option("--min-pwd-length",
 
58
          help="The minimum password length (<integer> | default).  Default is 7.", type=str),
 
59
        Option("--min-pwd-age",
 
60
          help="The minimum password age (<integer in days> | default).  Default is 1.", type=str),
 
61
        Option("--max-pwd-age",
 
62
          help="The maximum password age (<integer in days> | default).  Default is 43.", type=str),
 
63
          ]
 
64
 
 
65
    takes_args = ["subcommand"]
 
66
 
 
67
    def run(self, subcommand, H=None, min_pwd_age=None, max_pwd_age=None,
 
68
            quiet=False, complexity=None, store_plaintext=None, history_length=None,
 
69
            min_pwd_length=None, credopts=None, sambaopts=None,
 
70
            versionopts=None):
 
71
        lp = sambaopts.get_loadparm()
 
72
        creds = credopts.get_credentials(lp)
 
73
 
 
74
        samdb = SamDB(url=H, session_info=system_session(),
 
75
            credentials=creds, lp=lp)
 
76
 
 
77
        domain_dn = samdb.domain_dn()
 
78
        res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
 
79
          attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength",
 
80
                 "minPwdAge", "maxPwdAge"])
 
81
        assert(len(res) == 1)
 
82
        try:
 
83
            pwd_props = int(res[0]["pwdProperties"][0])
 
84
            pwd_hist_len = int(res[0]["pwdHistoryLength"][0])
 
85
            cur_min_pwd_len = int(res[0]["minPwdLength"][0])
 
86
            # ticks -> days
 
87
            cur_min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24))
 
88
            cur_max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24))
 
89
        except Exception, e:
 
90
            raise CommandError("Could not retrieve password properties!", e)
 
91
 
 
92
        if subcommand == "show":
 
93
            self.message("Password informations for domain '%s'" % domain_dn)
 
94
            self.message("")
 
95
            if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0:
 
96
                self.message("Password complexity: on")
 
97
            else:
 
98
                self.message("Password complexity: off")
 
99
            if pwd_props & DOMAIN_PASSWORD_STORE_CLEARTEXT != 0:
 
100
                self.message("Store plaintext passwords: on")
 
101
            else:
 
102
                self.message("Store plaintext passwords: off")
 
103
            self.message("Password history length: %d" % pwd_hist_len)
 
104
            self.message("Minimum password length: %d" % cur_min_pwd_len)
 
105
            self.message("Minimum password age (days): %d" % cur_min_pwd_age)
 
106
            self.message("Maximum password age (days): %d" % cur_max_pwd_age)
 
107
        elif subcommand == "set":
 
108
            msgs = []
 
109
            m = ldb.Message()
 
110
            m.dn = ldb.Dn(samdb, domain_dn)
 
111
 
 
112
            if complexity is not None:
 
113
                if complexity == "on" or complexity == "default":
 
114
                    pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
 
115
                    msgs.append("Password complexity activated!")
 
116
                elif complexity == "off":
 
117
                    pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX)
 
118
                    msgs.append("Password complexity deactivated!")
 
119
 
 
120
            if store_plaintext is not None:
 
121
                if store_plaintext == "on" or store_plaintext == "default":
 
122
                    pwd_props = pwd_props | DOMAIN_PASSWORD_STORE_CLEARTEXT
 
123
                    msgs.append("Plaintext password storage for changed passwords activated!")
 
124
                elif store_plaintext == "off":
 
125
                    pwd_props = pwd_props & (~DOMAIN_PASSWORD_STORE_CLEARTEXT)
 
126
                    msgs.append("Plaintext password storage for changed passwords deactivated!")
 
127
 
 
128
            if complexity is not None or store_plaintext is not None:
 
129
                m["pwdProperties"] = ldb.MessageElement(str(pwd_props),
 
130
                  ldb.FLAG_MOD_REPLACE, "pwdProperties")
 
131
 
 
132
            if history_length is not None:
 
133
                if history_length == "default":
 
134
                    pwd_hist_len = 24
 
135
                else:
 
136
                    pwd_hist_len = int(history_length)
 
137
 
 
138
                if pwd_hist_len < 0 or pwd_hist_len > 24:
 
139
                    raise CommandError("Password history length must be in the range of 0 to 24!")
 
140
 
 
141
                m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len),
 
142
                  ldb.FLAG_MOD_REPLACE, "pwdHistoryLength")
 
143
                msgs.append("Password history length changed!")
 
144
 
 
145
            if min_pwd_length is not None:
 
146
                if min_pwd_length == "default":
 
147
                    min_pwd_len = 7
 
148
                else:
 
149
                    min_pwd_len = int(min_pwd_length)
 
150
 
 
151
                if min_pwd_len < 0 or min_pwd_len > 14:
 
152
                    raise CommandError("Minimum password length must be in the range of 0 to 14!")
 
153
 
 
154
                m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len),
 
155
                  ldb.FLAG_MOD_REPLACE, "minPwdLength")
 
156
                msgs.append("Minimum password length changed!")
 
157
 
 
158
            if min_pwd_age is not None:
 
159
                if min_pwd_age == "default":
 
160
                    min_pwd_age = 1
 
161
                else:
 
162
                    min_pwd_age = int(min_pwd_age)
 
163
 
 
164
                if min_pwd_age < 0 or min_pwd_age > 998:
 
165
                    raise CommandError("Minimum password age must be in the range of 0 to 998!")
 
166
 
 
167
                # days -> ticks
 
168
                min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7))
 
169
 
 
170
                m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks),
 
171
                  ldb.FLAG_MOD_REPLACE, "minPwdAge")
 
172
                msgs.append("Minimum password age changed!")
 
173
 
 
174
            if max_pwd_age is not None:
 
175
                if max_pwd_age == "default":
 
176
                    max_pwd_age = 43
 
177
                else:
 
178
                    max_pwd_age = int(max_pwd_age)
 
179
 
 
180
                if max_pwd_age < 0 or max_pwd_age > 999:
 
181
                    raise CommandError("Maximum password age must be in the range of 0 to 999!")
 
182
 
 
183
                # days -> ticks
 
184
                max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7))
 
185
 
 
186
                m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks),
 
187
                  ldb.FLAG_MOD_REPLACE, "maxPwdAge")
 
188
                msgs.append("Maximum password age changed!")
 
189
 
 
190
            if max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
 
191
                raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age))
 
192
 
 
193
            samdb.modify(m)
 
194
            msgs.append("All changes applied successfully!")
 
195
            self.message("\n".join(msgs))
 
196
        else:
 
197
            raise CommandError("Wrong argument '%s'!" % subcommand)