.. Reminder for header structure:        
  Parts (H1)          : #################### with overline
  Chapters (H2)       : ******************** with overline
  Sections (H3)       : ====================
  Subsections (H4)    : --------------------
  Subsubsections (H5) : ^^^^^^^^^^^^^^^^^^^^
  Paragraphs (H6)     : """""""""""""""""""""

.. |date| date::

.. meta::
  :description: Using Python to administer Samba-AD
  :keywords: Security, Samba-AD, documentation, python, python-samdb

.. _samba_python_samdb:

###################################
Using Python to administer Samba-AD
###################################

You can find the official documentation of the api on the `Samba website <https://www.samba.org/~jelmer/samba4/pydoctor/samba.samdb.SamDB.html>`_.

.. note::

  Samba Python API are based on Python 3.6 or higher.

****************************************
Importing the necessary Python libraries
****************************************

.. code-block:: python

  #!/usr/bin/python
  # -*- coding: utf-8 -*-
  import getpass
  import ldb
  from samba.auth import system_session
  from samba.credentials import Credentials
  from samba.dcerpc import security
  from samba.dcerpc.security import dom_sid
  from samba.ndr import ndr_pack, ndr_unpack
  from samba.param import LoadParm
  from samba.samdb import SamDB

**********************************************
Creating the Python classes that will help you
**********************************************

* For opening a connection in LDAP mode (with a network access):

  .. code-block:: python

    lp = LoadParm()
    creds = Credentials()
    creds.guess(lp)
    creds.set_username('user_account_name')
    creds.set_password('my_super_password')
    samdb = SamDB(url='ldap://127.0.0.1:389', session_info=system_session(),credentials=creds, lp=lp)

* For opening a live connection on the LDB database (direct access to the LDB database files):

  .. code-block:: python

    lp = LoadParm()
    creds = Credentials()
    creds.guess(lp)
    samdb = SamDB(url='/var/lib/samba/private/sam.ldb', session_info=system_session(),credentials=creds, lp=lp)

**********************************
Acting on the Organizational Units
**********************************

Deleting an Organizational Unit
===============================

.. code-block:: python

  def delete_ou(samdb, dn):
      samdb.transaction_start()
      try:
          samdb.delete(dn)
      except:
          samdb.transaction_cancel()
          raise
      else:
          samdb.transaction_commit()

  delete_ou(samdb,'OU=department,OU=city,DC=mydomain,DC=lan')

Creating an Organizational Unit
===============================

.. code-block:: python

  samdb.create_ou('OU=department,OU=city,DC=mydomain,DC=lan')

***************
Acting on users
***************

Creating a user
===============

.. code-block:: python

  samdb.newuser(username="test-toto",password='password')

Deleting a user
===============

.. code-block:: python

  samdb.deleteuser(username="jpdrole")

Setting a user’s password
=========================

.. code-block:: python

  samdb.setpassword("(sAMAccountName=test-toto)", "123456", force_change_at_next_login=False, username=None)

Moving a user to another Organizational Unit
============================================

.. code-block:: python

  samdb.rename('CN=test-toto,CN=Users,DC=mydomain,DC=lan','CN=test-toto,OU=tata,OU=tranquilit,DC=mydomain,DC=lan')

****************
Acting on groups
****************

Creating a group
================

.. code-block:: python

  samdb.newgroup(groupname='waptselfservice')

Adding a user or machine to a group
===================================

.. code-block:: python

  samdb.add_remove_group_members(groupname='waptselfservice', members=['test-toto','dcardon','vcardon'], add_members_operation=True)

Deleting a user or machine from a group
=======================================

.. code-block:: python

  samdb.add_remove_group_members(groupname='waptselfservice', members=['test-toto','dcardon','vcardon'], add_members_operation=False)

*********************************************************
Searching for objects in an Active Directory Samba Forest
*********************************************************

Displaying all user, group, computer objects
============================================

.. code-block:: python

  query = "(|(objectclass=user)(objectclass=computer)(objectclass=group))"
  result = samdb.search('DC=mydomain,DC=lan', expression=query, scope=ldb.SCOPE_SUBTREE)
  for item in result:
      if 'sAMAccountName' in item:
          print(item['distinguishedName'])
          print(item['sAMAccountName'])

Searching for an object by its sAMAccountName
=============================================

.. code-block:: python

  query = ("(sAMAccountName=test-toto)")
  result = samdb.search('DC=mydomain,DC=lan', expression=query, scope=ldb.SCOPE_SUBTREE)

********************
Acting on attributes
********************

Modifying an attribute
======================

.. warning::

  **Watch the indentation**.
  The second line of the :abbr:`LDIF (LDAP Data Interchange Format)` string (here *changetype*) and all subsequent lines must not be indented as is usually done in Python, because LDIF parsers do not accept spaces at the beginning of lines.

.. code-block:: python

  ldif_data = """dn: %s
  changetype: modify
  replace: mail
  mail: test-toto@tranquil.it
  """ % dn
  samdb.modify_ldif(ldif_data)

Adding an attribute
===================

.. warning::

  **Watch the indentation**.
  The second line of the :abbr:`LDIF (LDAP Data Interchange Format)` string (here *changetype*) and all subsequent lines must not be indented as is usually done in Python, because LDIF parsers do not accept spaces at the beginning of lines.

.. code-block:: python

  ldif_data = """dn: CN=test-toto,OU=tata,OU=tranquilit,DC=mydomain,DC=lan
  changetype: modify
  add: telephoneNumber
  telephoneNumber: 0102030405
  """
  samdb.modify_ldif(ldif_data)
