1 # Adds a new user to a Samba4 server
2 # Copyright Jelmer Vernooij 2008
4 # Based on the original in EJS:
5 # Copyright Andrew Tridgell 2005
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 import samba.getopt as options
21 from samba.netcmd import Command, SuperCommand, CommandError, Option
23 from samba.ndr import ndr_unpack
24 from samba.dcerpc import security
26 from getpass import getpass
27 from samba.auth import system_session
28 from samba.samdb import SamDB
29 from samba.dsdb import (
30 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
31 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
32 GTYPE_SECURITY_GLOBAL_GROUP,
33 GTYPE_SECURITY_UNIVERSAL_GROUP,
34 GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP,
35 GTYPE_DISTRIBUTION_GLOBAL_GROUP,
36 GTYPE_DISTRIBUTION_UNIVERSAL_GROUP,
39 security_group = dict({"Builtin": GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
40 "Domain": GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
41 "Global": GTYPE_SECURITY_GLOBAL_GROUP,
42 "Universal": GTYPE_SECURITY_UNIVERSAL_GROUP})
43 distribution_group = dict({"Domain": GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP,
44 "Global": GTYPE_DISTRIBUTION_GLOBAL_GROUP,
45 "Universal": GTYPE_DISTRIBUTION_UNIVERSAL_GROUP})
48 class cmd_group_add(Command):
49 """Creates a new AD group.
51 This command creates a new Active Directory group. The groupname specified on the command is a unique sAMAccountName.
53 An Active Directory group may contain user and computer accounts as well as other groups. An administrator creates a group and adds members to that group so they can be managed as a single entity. This helps to simplify security and system administration.
55 Groups may also be used to establish email distribution lists, using --group-type=Distribution.
57 Groups are located in domains in organizational units (OUs). The group's scope is a characteristic of the group that designates the extent to which the group is applied within the domain tree or forest.
59 The group location (OU), type (security or distribution) and scope may all be specified on the samba-tool command when the group is created.
61 The command may be run from the root userid or another authorized userid. The
62 -H or --URL= option can be used to execute the command on a remote server.
65 samba-tool group add Group1 -H ldap://samba.samdom.example.com --description='Simple group'
67 Example1 adds a new group with the name Group1 added to the Users container on a remote LDAP server. The -U parameter is used to pass the userid and password of a user that exists on the remote server and is authorized to issue the command on that server. It defaults to the security type and global scope.
70 sudo samba-tool group add Group2 --group-type=Distribution
72 Example2 adds a new distribution group to the local server. The command is run under root using the sudo command.
75 synopsis = "%prog <groupname> [options]"
77 takes_optiongroups = {
78 "sambaopts": options.SambaOptions,
79 "versionopts": options.VersionOptions,
80 "credopts": options.CredentialsOptions,
84 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
85 metavar="URL", dest="H"),
87 help="Alternative location (without domainDN counterpart) to default CN=Users in which new user object will be created",
89 Option("--group-scope", type="choice", choices=["Domain", "Global", "Universal"],
90 help="Group scope (Domain | Global | Universal)"),
91 Option("--group-type", type="choice", choices=["Security", "Distribution"],
92 help="Group type (Security | Distribution)"),
93 Option("--description", help="Group's description", type=str),
94 Option("--mail-address", help="Group's email address", type=str),
95 Option("--notes", help="Groups's notes", type=str),
98 takes_args = ["groupname"]
100 def run(self, groupname, credopts=None, sambaopts=None,
101 versionopts=None, H=None, groupou=None, group_scope=None,
102 group_type=None, description=None, mail_address=None, notes=None):
104 if (group_type or "Security") == "Security":
105 gtype = security_group.get(group_scope, GTYPE_SECURITY_GLOBAL_GROUP)
107 gtype = distribution_group.get(group_scope, GTYPE_DISTRIBUTION_GLOBAL_GROUP)
109 lp = sambaopts.get_loadparm()
110 creds = credopts.get_credentials(lp, fallback_machine=True)
113 samdb = SamDB(url=H, session_info=system_session(),
114 credentials=creds, lp=lp)
115 samdb.newgroup(groupname, groupou=groupou, grouptype = gtype,
116 description=description, mailaddress=mail_address, notes=notes)
118 # FIXME: catch more specific exception
119 raise CommandError('Failed to create group "%s"' % groupname, e)
120 self.outf.write("Added group %s\n" % groupname)
123 class cmd_group_delete(Command):
124 """Deletes an AD group.
126 The command deletes an existing AD group from the Active Directory domain. The groupname specified on the command is the sAMAccountName.
128 Deleting a group is a permanent operation. When a group is deleted, all permissions and rights that users in the group had inherited from the group account are deleted as well.
130 The command may be run from the root userid or another authorized userid. The -H or --URL option can be used to execute the command on a remote server.
133 samba-tool group delete Group1 -H ldap://samba.samdom.example.com -Uadministrator%passw0rd
135 Example1 shows how to delete an AD group from a remote LDAP server. The -U parameter is used to pass the userid and password of a user that exists on the remote server and is authorized to issue the command on that server.
138 sudo samba-tool group delete Group2
140 Example2 deletes group Group2 from the local server. The command is run under root using the sudo command.
143 synopsis = "%prog <groupname> [options]"
145 takes_optiongroups = {
146 "sambaopts": options.SambaOptions,
147 "versionopts": options.VersionOptions,
148 "credopts": options.CredentialsOptions,
152 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
153 metavar="URL", dest="H"),
156 takes_args = ["groupname"]
158 def run(self, groupname, credopts=None, sambaopts=None, versionopts=None, H=None):
160 lp = sambaopts.get_loadparm()
161 creds = credopts.get_credentials(lp, fallback_machine=True)
164 samdb = SamDB(url=H, session_info=system_session(),
165 credentials=creds, lp=lp)
166 samdb.deletegroup(groupname)
168 # FIXME: catch more specific exception
169 raise CommandError('Failed to remove group "%s"' % groupname, e)
170 self.outf.write("Deleted group %s\n" % groupname)
173 class cmd_group_add_members(Command):
174 """Add members to an AD group.
176 This command adds one or more members to an existing Active Directory group. The command accepts one or more group member names seperated by commas. A group member may be a user or computer account or another Active Directory group.
178 When a member is added to a group the member may inherit permissions and rights from the group. Likewise, when permission or rights of a group are changed, the changes may reflect in the members through inheritance.
181 samba-tool group addmembers supergroup Group1,Group2,User1 -H ldap://samba.samdom.example.com -Uadministrator%passw0rd
183 Example1 shows how to add two groups, Group1 and Group2 and one user account, User1, to the existing AD group named supergroup. The command will be run on a remote server specified with the -H. The -U parameter is used to pass the userid and password of a user authorized to issue the command on the remote server.
186 sudo samba-tool group addmembers supergroup User2
188 Example2 shows how to add a single user account, User2, to the supergroup AD group. It uses the sudo command to run as root when issuing the command.
191 synopsis = "%prog <groupname> <listofmembers> [options]"
193 takes_optiongroups = {
194 "sambaopts": options.SambaOptions,
195 "versionopts": options.VersionOptions,
196 "credopts": options.CredentialsOptions,
200 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
201 metavar="URL", dest="H"),
204 takes_args = ["groupname", "listofmembers"]
206 def run(self, groupname, listofmembers, credopts=None, sambaopts=None,
207 versionopts=None, H=None):
209 lp = sambaopts.get_loadparm()
210 creds = credopts.get_credentials(lp, fallback_machine=True)
213 samdb = SamDB(url=H, session_info=system_session(),
214 credentials=creds, lp=lp)
215 groupmembers = listofmembers.split(',')
216 samdb.add_remove_group_members(groupname, groupmembers,
217 add_members_operation=True)
219 # FIXME: catch more specific exception
220 raise CommandError('Failed to add members "%s" to group "%s"' % (
221 listofmembers, groupname), e)
222 self.outf.write("Added members to group %s\n" % groupname)
225 class cmd_group_remove_members(Command):
226 """Remove members from an AD group.
228 This command removes one or more members from an existing Active Directory group. The command accepts one or more group member names seperated by commas. A group member may be a user or computer account or another Active Directory group that is a member of the group specified on the command.
230 When a member is removed from a group, inherited permissions and rights will no longer apply to the member.
233 samba-tool group removemembers supergroup Group1 -H ldap://samba.samdom.example.com -Uadministrator%passw0rd
235 Example1 shows how to remove Group1 from supergroup. The command will run on the remote server specified on the -H parameter. The -U parameter is used to pass the userid and password of a user authorized to issue the command on the remote server.
238 sudo samba-tool group removemembers supergroup User1
240 Example2 shows how to remove a single user account, User2, from the supergroup AD group. It uses the sudo command to run as root when issuing the command.
243 synopsis = "%prog <groupname> <listofmembers> [options]"
245 takes_optiongroups = {
246 "sambaopts": options.SambaOptions,
247 "versionopts": options.VersionOptions,
248 "credopts": options.CredentialsOptions,
252 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
253 metavar="URL", dest="H"),
256 takes_args = ["groupname", "listofmembers"]
258 def run(self, groupname, listofmembers, credopts=None, sambaopts=None,
259 versionopts=None, H=None):
261 lp = sambaopts.get_loadparm()
262 creds = credopts.get_credentials(lp, fallback_machine=True)
265 samdb = SamDB(url=H, session_info=system_session(),
266 credentials=creds, lp=lp)
267 samdb.add_remove_group_members(groupname, listofmembers.split(","),
268 add_members_operation=False)
270 # FIXME: Catch more specific exception
271 raise CommandError('Failed to remove members "%s" from group "%s"' % (listofmembers, groupname), e)
272 self.outf.write("Removed members from group %s\n" % groupname)
275 class cmd_group_list(Command):
276 """List all groups."""
278 synopsis = "%prog [options]"
281 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
282 metavar="URL", dest="H"),
283 Option("-v", "--verbose",
284 help="Verbose output, showing group type and group scope.",
285 action="store_true"),
289 takes_optiongroups = {
290 "sambaopts": options.SambaOptions,
291 "credopts": options.CredentialsOptions,
292 "versionopts": options.VersionOptions,
295 def run(self, sambaopts=None, credopts=None, versionopts=None, H=None,
297 lp = sambaopts.get_loadparm()
298 creds = credopts.get_credentials(lp, fallback_machine=True)
300 samdb = SamDB(url=H, session_info=system_session(),
301 credentials=creds, lp=lp)
303 domain_dn = samdb.domain_dn()
304 res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE,
305 expression=("(objectClass=group)"),
306 attrs=["samaccountname", "grouptype"])
311 self.outf.write("Group Name Group Type Group Scope\n")
312 self.outf.write("-----------------------------------------------------------------------------\n")
315 self.outf.write("%-44s" % msg.get("samaccountname", idx=0))
316 hgtype = hex(int("%s" % msg["grouptype"]) & 0x00000000FFFFFFFF)
317 if (hgtype == hex(int(security_group.get("Builtin")))):
318 self.outf.write("Security Builtin\n")
319 elif (hgtype == hex(int(security_group.get("Domain")))):
320 self.outf.write("Security Domain\n")
321 elif (hgtype == hex(int(security_group.get("Global")))):
322 self.outf.write("Security Global\n")
323 elif (hgtype == hex(int(security_group.get("Universal")))):
324 self.outf.write("Security Universal\n")
325 elif (hgtype == hex(int(distribution_group.get("Global")))):
326 self.outf.write("Distribution Global\n")
327 elif (hgtype == hex(int(distribution_group.get("Domain")))):
328 self.outf.write("Distribution Domain\n")
329 elif (hgtype == hex(int(distribution_group.get("Universal")))):
330 self.outf.write("Distribution Universal\n")
332 self.outf.write("\n")
335 self.outf.write("%s\n" % msg.get("samaccountname", idx=0))
337 class cmd_group_list_members(Command):
338 """List all members of an AD group.
340 This command lists members from an existing Active Directory group. The command accepts one group name.
343 samba-tool group listmembers \"Domain Users\" -H ldap://samba.samdom.example.com -Uadministrator%passw0rd
346 synopsis = "%prog <groupname> [options]"
349 Option("-H", "--URL", help="LDB URL for database or target server", type=str,
350 metavar="URL", dest="H"),
353 takes_optiongroups = {
354 "sambaopts": options.SambaOptions,
355 "credopts": options.CredentialsOptions,
356 "versionopts": options.VersionOptions,
359 takes_args = ["groupname"]
361 def run(self, groupname, credopts=None, sambaopts=None, versionopts=None, H=None):
362 lp = sambaopts.get_loadparm()
363 creds = credopts.get_credentials(lp, fallback_machine=True)
366 samdb = SamDB(url=H, session_info=system_session(),
367 credentials=creds, lp=lp)
369 search_filter = "(&(objectClass=group)(samaccountname=%s))" % groupname
370 res = samdb.search(samdb.domain_dn(), scope=ldb.SCOPE_SUBTREE,
371 expression=(search_filter),
377 group_dn = res[0].get('dn', idx=0)
378 object_sid = res[0].get('objectSid', idx=0)
380 object_sid = ndr_unpack(security.dom_sid, object_sid)
381 (group_dom_sid, rid) = object_sid.split()
383 search_filter = "(|(primaryGroupID=%s)(memberOf=%s))" % (rid, group_dn)
384 res = samdb.search(samdb.domain_dn(), scope=ldb.SCOPE_SUBTREE,
385 expression=(search_filter),
386 attrs=["samAccountName", "cn"])
392 member_name = msg.get("samAccountName", idx=0)
393 if member_name is None:
394 member_name = msg.get("cn", idx=0)
395 self.outf.write("%s\n" % member_name)
398 raise CommandError('Failed to list members of "%s" group ' % groupname, e)
401 class cmd_group(SuperCommand):
402 """Group management."""
405 subcommands["add"] = cmd_group_add()
406 subcommands["delete"] = cmd_group_delete()
407 subcommands["addmembers"] = cmd_group_add_members()
408 subcommands["removemembers"] = cmd_group_remove_members()
409 subcommands["list"] = cmd_group_list()
410 subcommands["listmembers"] = cmd_group_list_members()