
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
3
hj5                 @   s  d Z ddlZddlZddlZddlmZ ddlmZ G dd deZ	G dd	 d	eZ
G d
d de	ZG dd de	ZG dd de	ZG dd de	ZG dd de	ZG dd de	ZG dd de	ZG dd de	ZG dd de	ZG dd de	ZG dd de	ZG d d! d!e	ZG d"d# d#e	ZG d$d% d%e	Zd&d' Zd(d) ZG d*d+ d+eZG d,d- d-eZG d.d/ d/eZG d0d1 d1eZG d2d3 d3eZ dS )4z,
Created on Sep 18, 2009

@author: sgallagh
    N   )SSSDOptions)SSSDChangeConfc               @   s   e Zd ZdS )SSSDConfigExceptionN)__name__
__module____qualname__ r	   r	   /usr/lib/python3.6/__init__.pyr      s    r   c               @   s   e Zd ZdS )ParsingErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )AlreadyInitializedErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )NotInitializedErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )NoOutputFileErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )NoServiceErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )NoSectionErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )NoOptionErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )ServiceNotRecognizedErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )ServiceAlreadyExistsN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )NoDomainErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )DomainNotRecognizedN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )DomainAlreadyExistsErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )NoSuchProviderErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )NoSuchProviderSubtypeErrorN)r   r   r   r	   r	   r	   r
   r      s    r   c               @   s   e Zd ZdS )ProviderSubtypeInUseN)r   r   r   r	   r	   r	   r
   r      s    r   c             C   s   dd | D S )Nc             S   s   g | ]}|j  qS r	   )strip).0xr	   r	   r
   
<listcomp>    s    zstriplist.<locals>.<listcomp>r	   )lr	   r	   r
   	striplist   s    r   c             C   s(   g }x| D ]}||kr
|j | q
W |S )N)append)Zoptions1Zoptions2overlapoptionr	   r	   r
   options_overlap"   s
    
r#   c               @   s<   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd ZdS )SSSDConfigSchemac             C   s   t j|  |sd}|sd}yht|d}| j| W d Q R X xBtdd tj|D ]*}t|d | }| j| W d Q R X qRW W n, tk
r    Y n tk
r   t	Y nX t
ttjd dkrtnttttd d	| _d
dd| _d S )Nz/usr/share/sssd/sssd.api.confz/usr/share/sssd/sssd.api.drc             S   s   t jd| S )Nz^sssd-.*\.conf$)research)fr	   r	   r
   <lambda>7   s    z+SSSDConfigSchema.__init__.<locals>.<lambda>/r      )boolintlongfloatstrlistNoneFT)falsetrue)r   __init__openreadfpfilteroslistdirIOErrorSyntaxErrorr   r,   r-   sysversion_infor.   r/   r0   r1   type_lookupbool_lookup)self
schemafileschemaplugindirfdfiler	   r	   r
   r5   *   s2    



zSSSDConfigSchema.__init__c             C   s  | j |st| j|}d}d}d}d}i }x| j|D ]}|d }	t|	jd}
t|
}| j|
|  }| j|
|  }| j|
|  }|d t	j
krt	j
|d  }nd }|dkr||||d f||d < q:|dkrFt|
| |kr|||||
| f||d < q|tkrt|
| |kr>|||||
| gf||d < nyh|tkrt|
| tkr||||| j|
| j  gf||d < n ||||||
| gf||d < W n tk
r   tY nX nyd|tkrt|
| tkr||||| j|
| j  f||d < n||||||
| f||d < W n tk
rB   tY nX q:|dkr
|tkr^tg }x|
|d  D ]~}t||kry@|tkrt|tkr| j|j  }n||}|j|g W n tk
r   tY nX n|j|g qpW |||||f||d < q:tq:W |S )	Nr   r   r+      value,name   )has_sectionr   optionsstrip_comments_emptyr   splitlenr?   r@   r   Zoption_stringstyper1   r,   r0   lower
ValueErrorr   extend)rA   sectionrL   ZPRIMARY_TYPEZSUBTYPEZ	MANDATORYZDEFAULTZparsed_optionsr"   Zunparsed_optionZsplit_optionZ	optionlenZprimarytypesubtypeZ	mandatoryZdescZfixed_optionsr   newvaluer	   r	   r
   get_optionsQ   s    




 


zSSSDConfigSchema.get_optionsc             C   s<   | j |st|| j||s.td||f | j|| S )NzSection [%s] has no option [%s])rK   r   
has_optionr   rW   )rA   rT   r"   r	   r	   r
   
get_option   s    
zSSSDConfigSchema.get_optionc                s:   | j |st|| j| t fdd j D }|S )Nc                s,   g | ]$} | d  dkr| | d  fqS )rJ   Nr	   )r   r   )schema_optionsr	   r
   r      s   z1SSSDConfigSchema.get_defaults.<locals>.<listcomp>)rK   r   rW   dictkeys)rA   rT   Zdefaultsr	   )rZ   r
   get_defaults   s    

zSSSDConfigSchema.get_defaultsc             C   s   dd | j  D }|S )Nc             S   s@   g | ]8}|d  dkr|d  j d r|d  j d r|d  qS )rI   servicedomainprovider)
startswith)r   r   r	   r	   r
   r      s    z1SSSDConfigSchema.get_services.<locals>.<listcomp>)sections)rA   service_listr	   r	   r
   get_services   s    zSSSDConfigSchema.get_servicesc             C   s   i }xf| j  D ]Z}|d jd}|d dkrt|dkr|d |krPg ||d < ||d  j|d g qW x |j D ]}t|| ||< qvW |S )NrI   r*   r   r`   rF   r   r+   )rb   rN   rO   rS   r\   tuple)rA   	providersrT   Zsplitsectionkeyr	   r	   r
   get_providers   s    zSSSDConfigSchema.get_providersN)	r   r   r   r5   rW   rY   r]   rd   rh   r	   r	   r	   r
   r$   )   s   'v	r$   c               @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )SSSDConfigObjectc             C   s   d | _ i | _d S )N)rI   rL   )rA   r	   r	   r
   r5      s    zSSSDConfigObject.__init__c             C   s   | j S )z
        Return the name of the object

        === Returns ===
        The domain name

        === Errors ===
        No errors
        )rI   )rA   r	   r	   r
   get_name   s    
zSSSDConfigObject.get_namec             C   s$   || j j kr| j | S t|dS )a  
        Return the value of an service option

        optionname:
          The option to get.

        === Returns ===
        The value for the requested option.

        === Errors ===
        NoOptionError:
          The specified option was not listed in the service
        N)rL   r\   r   )rA   
optionnamer	   r	   r
   rY      s    
zSSSDConfigObject.get_optionc             C   s   | j S )z
        Return a dictionary of name/value pairs for this object

        === Returns ===
        A dictionary of name/value pairs currently in use for this object

        === Errors ===
        No errors
        )rL   )rA   r	   r	   r
   get_all_options  s    
z SSSDConfigObject.get_all_optionsc             C   s   || j kr| j |= dS )z
        Remove an option from the object. If the option does not exist, it is ignored.

        === Returns ===
        No return value.

        === Errors ===
        No errors
        N)rL   )rA   rk   r	   r	   r
   remove_option  s    

zSSSDConfigObject.remove_optionN)r   r   r   r5   rj   rY   rl   rm   r	   r	   r	   r
   ri      s
   ri   c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )SSSDServicez3
    Object to manipulate SSSD service options
    c             C   s~   t j|  t|t s"t|tkr&t|j|s8t||| _	|| _
i | _g | _| jj| j
jd | jj| j
j| j	 dS )a\  
        Create a new SSSDService, setting its defaults to those found in the
        schema. This constructor should not be used directly. Use
        SSSDConfig.new_service() instead.

        name:
          The service name
        apischema:
          An SSSDConfigSchema? object created by SSSDConfig.__init__()

        === Returns ===
        The newly-created SSSDService object.

        === Errors ===
        TypeError:
          The API schema passed in was unusable or the name was not a string.
        ServiceNotRecognizedError:
          The service was not listed in the schema
        r^   N)ri   r5   
isinstancer$   rP   r0   	TypeErrorrK   r   rI   schemarL   hidden_optionsupdater]   )rA   servicename	apischemar	   r	   r
   r5   0  s    

zSSSDService.__init__c             C   s6   i }| j jd}|j| | j j| j}|j| |S )aI  
        List options for the service, including the mandatory flag.

        === Returns ===
        A dictionary of configurable options. This dictionary is keyed on the
        option name with a tuple of the variable type, subtype ('None' if the
        type is not  a collection type), whether it is mandatory, the
        translated option description, and the default value (or 'None') as
        the value.

        Example:
        { 'enumerate' :
          (bool, None, False, u'Enable enumerating all users/groups', True) }

        === Errors ===
        No errors
        r^   )rq   rW   rs   rI   )rA   rL   rZ   r	   r	   r
   list_options_with_mandatory[  s    

z'SSSDService.list_options_with_mandatoryc             C   sR   | j  }i }x@|j D ]4}|| d || d || d || d f||< qW |S )a  
        List all options that apply to this service

        === Returns ===
        A dictionary of configurable options. This dictionary is keyed on the
        option name with a tuple of the variable type, subtype ('None' if the
        type is not  a collection type), the translated option description, and
        the default value (or 'None') as the value.

        Example:
        { 'services' :
          (list, str, u'SSSD Services to start', ['nss', 'pam']) }

        === Errors ===
        No Errors
        r   r   rF   rJ   )rv   r\   )rA   rL   filtered_optionsrg   r	   r	   r
   list_optionsx  s
    4zSSSDService.list_optionsc             C   s^   | j  }i }xL|j D ]@}|| d r|| d || d || d || d f||< qW |S )a  
        List all mandatory options that apply to this service

        === Returns ===
        A dictionary of configurable options. This dictionary is keyed on the
        option name with a tuple of the variable type, subtype ('None' if the
        type is not  a collection type), the translated option description, and
        the default value (or 'None') as the value.

        Example:
        { 'services' :
          (list, str, u'SSSD Services to start', ['nss', 'pam']) }

        === Errors ===
        No Errors
        r+   r   r   rF   rJ   )rv   r\   )rA   rL   rw   rg   r	   r	   r
   list_mandatory_options  s    4z"SSSDService.list_mandatory_optionsc             C   sR  | j j| j|r"| j j| j|}nH| j jd|r@| j jd|}n*|| jkrX|| j|< dS td| j|f |dkr| j| dS d}|d tkrt	|tkrt	|t
krt|jd}n|g}t	||d kryb|d tkrt	|t
kr| j j|j  }n4|d tkr$t	|t
kr$t|d}n|d |}W n2 tk
rL   d}Y n tk
rd   d}Y nX |rtd|d |t	|f t	|tkrDybg }xX|D ]P}|d	 tkrt	|t
kr|j| j j|j  g n|j|d	 |g qW W n2 tk
r   d}Y n tk
r(   d}Y nX |r@td
|d	  |}|| j|< dS )a  
        Set a service option to the specified value (or values)

        optionname:
          The option to change
        value:
          The value to set. This may be a single value or a list of values. If
          it is set to None, it resets the option to its default.

        === Returns ===
        No return value

        === Errors ===
        NoOptionError:
          The specified option is not listed in the schema
        TypeError:
          The value specified was not of the expected type
        r^   NzSection [%s] has no option [%s]Fr   rH   TzExpected %s for %s, received %sr   zExpected %s)rq   rX   rI   rY   rr   rL   r   rm   r1   rP   r0   r   rN   r,   r@   rQ   r-   rR   KeyErrorrp   rS   )rA   rk   rG   option_schemaraise_errorrV   r   r	   r	   r
   
set_option  s\    





zSSSDService.set_optionN)	r   r   r   __doc__r5   rv   rx   ry   r}   r	   r	   r	   r
   rn   +  s   +rn   c               @   sj   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdddZ	dd Z
dd Zdd Zdd Zdd ZdS )
SSSDDomainz2
    Object to manipulate SSSD domain options
    c             C   sv   t j|  t|t s"t|tkr&t|| _|| _d| _	d| _
g | _i | _| jj| jjd | jj| jjd dS )a  
        Creates a new, empty SSSDDomain. This domain is inactive by default.
        This constructor should not be used directly. Use
        SSSDConfig.new_domain() instead.

        name:
          The domain name.
        apischema:
          An SSSDConfigSchema object created by SSSDConfig.__init__()

        === Returns ===
        The newly-created SSSDDomain object.

        === Errors ===
        TypeError:
          apischema was not an SSSDConfigSchema object or domainname was not
         a string
        FNr`   r_   )ri   r5   ro   r$   rP   r0   rp   rI   rq   activeoldnamerf   rL   rs   r]   )rA   Z
domainnameru   r	   r	   r
   r5   
  s    
zSSSDDomain.__init__c             C   s   t || _dS )ad  
        Enable or disable this domain

        active:
          Boolean value. If True, this domain will be added to the active
          domains list when it is saved. If False, it will be removed from the
          active domains list when it is saved.

        === Returns ===
        No return value

        === Errors ===
        No errors
        N)r,   r   )rA   r   r	   r	   r
   
set_active/  s    zSSSDDomain.set_activec             C   sx   i }|j | jjd |j | jjd xJ| jD ]@\}}| jjd| }|j | | jjd||f }|j | q0W |S )ag  
        List options for the currently-configured providers, including the
        mandatory flag

        === Returns ===
        A dictionary of configurable options. This dictionary is keyed on the
        option name with a tuple of the variable type, subtype ('None' if the
        type is not  a collection type), whether it is mandatory, the
        translated option description, and the default value (or 'None') as
        the value.

        Example:
        { 'enumerate' :
          (bool, None, False, u'Enable enumerating all users/groups', True) }

        === Errors ===
        No errors
        r`   r_   zprovider/%szprovider/%s/%s)rs   rq   rW   rf   )rA   rL   r`   ZprovidertyperZ   r	   r	   r
   rv   @  s    
z&SSSDDomain.list_options_with_mandatoryc             C   sR   | j  }i }x@|j D ]4}|| d || d || d || d f||< qW |S )a$  
        List options available for the currently-configured providers.

        === Returns ===
        A dictionary of configurable options. This dictionary is keyed on the
        option name with a tuple of the variable type, subtype ('None' if the
        type is not  a collection type), the translated option description, and
        the default value (or 'None') as the value.

        Example:
        { 'enumerate' :
          (bool, None, u'Enable enumerating all users/groups', True) }

        === Errors ===
        No errors
        r   r   rF   rJ   )rv   r\   )rA   rL   rw   rg   r	   r	   r
   rx   d  s
    4zSSSDDomain.list_optionsc             C   s^   | j  }i }xL|j D ]@}|| d r|| d || d || d || d f||< qW |S )a$  
        List mandatory options for the currently-configured providers.

        === Returns ===
        A dictionary of configurable options. This dictionary is keyed on the
        option name with a tuple of the variable type, subtype ('None' if the
        type is not  a collection type), the translated option description, and
        the default value (or 'None') as the value.

        Example:
        { 'enumerate' :
          (bool, None, u'Enable enumerating all users/groups', True) }

        === Errors ===
        No errors
        r+   r   r   rF   rJ   )rv   r\   )rA   rL   rw   rg   r	   r	   r
   ry     s    4z!SSSDDomain.list_mandatory_optionsNc             C   s`   | j jd| }|r0|j| j jd||f  n,| j }x"|| D ]}|j| j|| qBW |S )a  
        If provider_type is specified, list all options applicable to that
        target, otherwise list all possible options available for a provider.

        type:
            Provider backend type. (e.g. local, ldap, krb5, etc.)
        provider_type:
            Subtype of the backend type. (e.g. id, auth, access, chpass)

        === Returns ===

        A dictionary of configurable options for the specified provider type.
        This dictionary is keyed on the option name with a tuple of the
        variable type, subtype ('None' if the type is not  a collection type),
        the translated option description, and the default value (or 'None')
        as the value.

        === Errors ===

        NoSuchProviderError:
            The specified provider is not listed in the schema or plugins
        NoSuchProviderSubtypeError:
            The specified provider subtype is not listed in the schema
        zprovider/%szprovider/%s/%s)rq   rW   rs   list_providerslist_provider_options)rA   r`   provider_typerL   Zknown_providersr	   r	   r
   r     s    
z SSSDDomain.list_provider_optionsc             C   s
   | j j S )a>  
        Return a dictionary of providers.

        === Returns ===
        Returns a dictionary of providers, keyed on the primary type, with the
        value being a tuple of the subtypes it supports.

        Example:
        { 'ldap' : ('id', 'auth', 'chpass') }

        === Errors ===
        No Errors
        )rq   rh   )rA   r	   r	   r
   r     s    zSSSDDomain.list_providersc       
      C   s`  | j  }||j kr&td| j|f |dkr<| j| dS || }d}|d tkrt|tkrt|tkr|t|j	d}n|g}t||d krFy^|d t
krt|tkr| jj|j  }n0|d tkrt|tkrt|d}n|d |}W n2 tk
r   d}Y n tk
r$   d}Y nX |rFtd|d |t|f t|tkrybg }xX|D ]P}|d t
krt|tkr|j| jj|j  g n|j|d |g q`W W n2 tk
r   d}Y n tk
r   d}Y nX |r td	|d  |}|jd
}|dkrR|d| }	y| j||	 W n tk
rN   tY nX n
|| j|< dS )a  
        Set a domain option to the specified value (or values)

        option:
          The option to change.
        value:
          The value to set. This may be a single value or a list of values.
          If it is set to None, it resets the option to its default.

        === Returns ===
        No return value.

        === Errors ===
        NoOptionError:
            The specified option is not listed in the schema
        TypeError:
            The value specified was not of the expected type
        zSection [%s] has no option [%s]NFr   rH   TzExpected %s for %s, received %sr   zExpected %s	_provider)rx   r\   r   rI   rm   r1   rP   r0   r   rN   r,   rq   r@   rQ   r-   rR   rz   rp   rS   rfindadd_providerr   rL   )
rA   r"   rG   rL   r{   r|   rV   r   Zis_providerr`   r	   r	   r
   r}     sf    





zSSSDDomain.set_optionc             C   s(   t |tkrt| js| j| _|| _dS )z
        Change the name of the domain

        newname:
          New name for this domain

        === Returns ===
        No return value.

        === Errors ===
        TypeError:
          newname was not a string
        N)rP   r0   rp   r   rI   )rA   Znewnamer	   r	   r
   set_name-  s
    zSSSDDomain.set_namec                s   | j  }||j kr* || kr.t nt fdd| jD }t|dkrRtt|dkr|d d |krt|d d n| jj| fg d  }|| j|< | jj	| j
jd|  | jj	| j
jd| f  dS )	aH  
        Add a new provider type to the domain

        type:
          Provider backend type. (e.g. local, ldap, krb5, etc.)
        subtype:
          Subtype of the backend type. (e.g. id, auth, chpass)

        === Returns ===
        No return value.

        === Errors ===
        ProviderSubtypeInUse:
          Another backend is already providing this subtype
        NoSuchProviderError:
          The specified provider is not listed in the schema or plugins
        NoSuchProviderSubtypeError:
          The specified provider subtype is not listed in the schema
        c                s   g | ]}|d   kr|qS )r   r	   )r   r   )r   r	   r
   r   a  s    z+SSSDDomain.add_provider.<locals>.<listcomp>r   r   z%s_providerzprovider/%szprovider/%s/%sN)r   r\   r   r   rf   rO   r   rS   rL   rs   rq   r]   )rA   r`   r   configured_providersZwith_this_typeZoption_namer	   )r   r
   r   D  s&    


zSSSDDomain.add_providerc       
      C   s   d}x | j D ]\}}||krP d}qW |s.dS | j||}xV| j D ]L\}}||f||fkr\qB| j||}t|j |j }x|D ]
}||= qW qBW x|D ]}	|	| jkr| j|	= qW d| }	|	| jkr| j|	= | j j||f dS )a  
        Remove a provider from the domain. If the provider is not present, it
        is ignored.

        provider_type:
          Subtype of the backend type. (e.g. id, auth, chpass)

        === Returns ===
        No return value.

        === Errors ===
        No Errors
        Nz%s_provider)rf   r   r#   r\   rL   remove)
rA   r   r`   ZptyperL   ZprovZprovider_optionsr!   optr"   r	   r	   r
   remove_provideru  s,    



zSSSDDomain.remove_provider)N)r   r   r   r~   r5   r   rv   rx   ry   r   r   r}   r   r   r   r	   r	   r	   r
   r     s   %$
'[1r   c               @   s   e Zd ZdZd1ddZd2ddZdd Zd3d	d
Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 ZdS )4
SSSDConfigzQ
    class SSSDConfig
    Primary class for operating on SSSD configurations
    Nc             C   s,   t j|  t||| _d| _d| _d| _dS )a+  
        Initialize the SSSD config parser/editor. This constructor does not
        open or create a config file. If the schemafile and schemaplugindir
        are not passed, it will use the system defaults.

        schemafile:
          The path to the API schema config file. Usually
          /usr/share/sssd/sssd.api.conf
        schemaplugindir:
          The path the directory containing the provider schema config files.
          Usually /usr/share/sssd/sssd.api.d

        === Returns ===
        The newly-created SSSDConfig object.

        === Errors ===
        IOError:
          Exception raised when the schema file could not be opened for
          reading.
        ParsingError:
          The main schema file or one of those in the plugin directory could
          not be parsed.
        NFr+   )r   r5   r$   rq   
configfileinitializedAPI_VERSION)rA   rB   rC   r	   r	   r
   r5     s
    
zSSSDConfig.__init__c             C   s   | j r
t|sd}t|d.}y| j| W n tk
rD   tY nX W dQ R X || _d| _ y"t| jdd| j	kr|tdW n t
k
r   Y nX dS )a  
        Read in a config file, populating all of the service and domain
        objects with the read values.

        configfile:
          The path to the SSSD config file. If not specified, use the system
          default, usually /etc/sssd.conf

        === Returns ===
        No return value

        === Errors ===
        IOError:
          Exception raised when the file could not be opened for reading
        ParsingError:
          Exception raised when errors occur attempting to parse a file.
        AlreadyInitializedError:
          This SSSDConfig object was already initialized by a call to
          import_config() or new_config()
        z/etc/sssd/sssd.confr%   NTsssdZconfig_file_versionzWrong config_file_version)r   r   r6   r7   	Exceptionr   r   r-   getr   rp   )rA   r   rD   r	   r	   r
   import_config  s     zSSSDConfig.import_configc             C   s2   | j r
td| _ x| jj D ]}| j|}qW dS )a/  
        Initialize the SSSDConfig object with the defaults from the schema.

        === Returns ===
        No return value

        === Errors ===
        AlreadyInitializedError:
          This SSSDConfig object was already initialized by a call to
          import_config() or new_config()
        TN)r   r   rq   rd   new_service)rA   rt   r^   r	   r	   r
   
new_config  s
    zSSSDConfig.new_configc          	   C   sj   | j s
t|dkr&| jdkr t| j}tjd}t|d}| j| j}|j	| W dQ R X tj| dS )a  
        Write out the configuration to a file.

        outputfile:
          The path to write the new config file. If it is not specified, it
          will use the path specified by the import() call.
        === Returns ===
        No return value

        === Errors ===
        IOError:
          Exception raised when the file could not be opened for writing
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        NoOutputFileError:
          No outputfile was specified and this SSSDConfig object was not
          initialized by import()
        N   w)
r   r   r   r   r9   umaskr6   dumpoptswrite)rA   Z
outputfileZ	old_umaskZofoutputr	   r	   r
   r     s    

zSSSDConfig.writec             C   s~   | j s
t| jddrvt| jddjd}tj|}d|krD|d= | j }xt	|D ]}||krV||= qVW t	|}ng }|S )a  
        Return a list of all active services.

        === Returns ===
        The list of active services.

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        r   servicesrH    )
r   r   rX   r   r   rN   r[   fromkeyslist_servicesr1   )rA   active_servicesservice_dictZconfigured_servicesZsrvr	   r	   r
   list_active_services3  s    


zSSSDConfig.list_active_servicesc                sL   | j s
t| jddr.t| jddjd ng   fdd| j D }|S )a  
        Return a list of all disabled services.

        === Returns ===
        The list of inactive services.

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        r   r   rH   c                s   g | ]}| kr|qS r	   r	   )r   r   )r   r	   r
   r   i  s    z5SSSDConfig.list_inactive_services.<locals>.<listcomp>)r   r   rX   r   r   rN   r   )rA   r   r	   )r   r
   list_inactive_servicesU  s    z!SSSDConfig.list_inactive_servicesc             C   s    | j s
tdd | j D }|S )a  
        Retrieve a list of known services.

        === Returns ===
        The list of known services.

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        c             S   s"   g | ]}|d  j ds|d  qS )rI   r_   )ra   )r   r   r	   r	   r
   r   |  s    z,SSSDConfig.list_services.<locals>.<listcomp>)r   r   rb   )rA   rc   r	   r	   r
   r   m  s    zSSSDConfig.list_servicesc             C   sp   | j s
t| j|stt|| j}xF| j| j|D ]2}y|j|d |d  W q6 t	k
rf   Y q6X q6W |S )a  
        Get an SSSDService object to edit a service.

        name:
          The name of the service to return.

        === Returns ===
        An SSSDService instance containing the current state of a service in
        the SSSDConfig

        === Errors ===
        NoServiceError:
          There is no such service with the specified name in the SSSDConfig.
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        rI   rG   )
r   r   rK   r   rn   rq   rM   rL   r}   r   )rA   rI   r^   r   r	   r	   r
   get_service  s    

zSSSDConfig.get_servicec             C   s6   | j s
t| j|rt|t|| j}| j| |S )a  
        Create a new service from the defaults and return the SSSDService
        object for it. This function will also add this service to the list of
        active services in the [SSSD] section.

        name:
          The name of the service to create and return.

        === Returns ===
        The newly-created SSSDService object

        === Errors ===
        ServiceNotRecognizedError:
          There is no such service in the schema.
        ServiceAlreadyExistsError:
          The service being created already exists in the SSSDConfig object.
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        )r   r   rK   r   rn   rq   save_service)rA   rI   r^   r	   r	   r
   r     s    

zSSSDConfig.new_servicec             C   s   | j s
t|| j krt| jddd }|s@| jdd| dS tjt|d j	d}d|krf|d= d||< | jdddj
|j  dS )	a  
        Activate a service

        name:
          The name of the service to activate

        === Returns ===
        No return value

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        NoServiceError:
          There is no such service with the specified name in the SSSDConfig.
        r   r   r   NrG   rH   r   z, )r   r   r   r   get_option_indexsetr[   r   r   rN   joinr\   )rA   rI   itemr   r	   r	   r
   activate_service  s    zSSSDConfig.activate_servicec             C   s   | j s
t|| j krt| jddd }|s@| jddd dS tjt|d j	d}d|krf|d= ||krt||= | jdddj
|j  dS )	a  
        Deactivate a service

        name:
          The name of the service to deactivate

        === Returns ===
        No return value

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        NoServiceError:
          There is no such service with the specified name in the SSSDConfig.
        r   r   r   r   NrG   rH   z, )r   r   r   r   r   r   r[   r   r   rN   r   r\   )rA   rI   r   r   r	   r	   r
   deactivate_service  s    zSSSDConfig.deactivate_servicec             C   s   | j s
t| jd| dS )a  
        Remove a service from the SSSDConfig object. This function will also
        remove this service from the list of active services in the [SSSD]
        section. Has no effect if the service does not exist.

        === Returns ===
        No return value

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        rT   N)r   r   delete_option)rA   rI   r	   r	   r
   delete_service  s    zSSSDConfig.delete_servicec             C   s   | j s
tt|tst|j }| jd|}g }xV|j j D ]F\}}t	|t
kr\dj|}|dkrn| j|}|jd|t|d q>W | j||| dS )a  
        Save the changes made to the service object back to the SSSDConfig
        object.

        service_object:
          The SSSDService object to save to the configuration.

        === Returns ===
        No return value
        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        TypeError:
          service_object was not of the type SSSDService
        rT   z, debug_levelr"   )rP   rI   rG   N)r   r   ro   rn   rp   rj   r   rl   itemsrP   r1   r   _get_debug_level_valr    r0   add_section)rA   r^   rI   indexZaddkwr"   rG   r	   r	   r
   r   &  s     


zSSSDConfig.save_servicec             C   s   | j s
t| jddrNt| jddjd}tj|}d|krD|d= t|}ng }| j	 }xd| j	 D ]X}| jd| dr| jd| ddkr|j
| ||kr|j
| qd||krd|j
| qdW |S )a  
        Return a list of all active domains.

        === Returns ===
        The list of configured, active domains.

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        r   domainsrH   r   z	domain/%senabledr3   )r   r   rX   r   r   rN   r[   r   r1   list_domainsr   )rA   sssd_domainsdomain_dictr   domr	   r	   r
   list_active_domainsP  s&    


zSSSDConfig.list_active_domainsc             C   s   | j s
t| jddrNt| jddjd}tj|}d|krD|d= t|}ng }| j	 }xR| j	 D ]F}| jd| dr| jd| ddkr|j
| qd||krd|j
| qdW |S )a.  
        Return a list of all configured, but disabled domains.

        === Returns ===
        The list of configured, inactive domains.

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        r   r   rH   r   z	domain/%sr   r4   )r   r   rX   r   r   rN   r[   r   r1   r   r   )rA   r   r   r   r   r	   r	   r
   list_inactive_domainsv  s"    

z SSSDConfig.list_inactive_domainsc             C   s    | j s
tdd | j D }|S )aL  
        Return a list of all configured domains, including inactive domains.

        === Returns ===
        The list of configured domains, both active and inactive.

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        c             S   s*   g | ]"}|d  j dr|d  dd qS )rI   zdomain/   N)ra   )r   r   r	   r	   r
   r     s    z+SSSDConfig.list_domains.<locals>.<listcomp>)r   r   rb   )rA   r   r	   r	   r
   r     s    zSSSDConfig.list_domainsc             C   s  | j s
t| jd| s t|t|| j}dd | j| jd| D }ddddddddddd
}|j }dd |D }d	|kr|j	d xt|j
 D ]h\}}||krq||kr||j| }	|	d |j kr|d|jd ||	d  kr|j	||	d f qW x:|D ]2\}
}y|j|
| W n tk
r6   Y nX qW xd| j| jd| D ]L}|d |d f|krTy|j|d |d  W n tk
r   Y nX qTW | j||_|S )a  
        Get an SSSDDomain object to edit a domain.

        name:
          The name of the domain to return.

        === Returns ===
        An SSSDDomain instance containing the current state of a domain in the
        SSSDConfig

        === Errors ===
        NoDomainError:
          There is no such domain with the specified name in the SSSDConfig.
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        z	domain/%sc             S   s.   g | ]&}|d  j ddkr|d  |d fqS )rI   r   r   rG   )r   )r   r   r	   r	   r
   r     s    z)SSSDConfig.get_domain.<locals>.<listcomp>Nid_providerauth_provider)
r   Zsudo_providerr   Zchpass_providerZautofs_providerZselinux_providerZsubdomains_providerZsession_providerZhostid_providerZresolver_providerc             S   s   g | ]}|d  qS )r   r	   )r   r   r	   r	   r
   r     s    access_providerpermitr   r   rI   rG   )r   r   )r   r   rK   r   r   rq   rM   rL   r   r    r   r   r\   r   r}   r   is_domain_activer   )rA   rI   r_   rf   Zdefault_providersr   Zproviders_listr`   Zdefault_providerZdefault_provider_valuer"   rG   r   r	   r	   r
   
get_domain  sR    
zSSSDConfig.get_domainc             C   s6   | j s
t| jd| rtt|| j}| j| |S )a  
        Create a new, empty domain and return the SSSDDomain object for it.

        name:
          The name of the domain to create and return.

        === Returns ===
        The newly-created SSSDDomain object

        === Errors ===
        DomainAlreadyExistsError:
          The service being created already exists in the SSSDConfig object.
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        z	domain/%s)r   r   rK   r   r   rq   save_domain)rA   rI   r_   r	   r	   r
   
new_domain  s    
zSSSDConfig.new_domainc             C   s&   | j s
t|| j krt|| j kS )a  
        Is a particular domain set active

        name:
          The name of the configured domain to check

        === Returns ===
        True if the domain is active, False if it is inactive

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        NoDomainError:
          No domain by this name is configured
        )r   r   r   r   r   )rA   rI   r	   r	   r
   r     s
    zSSSDConfig.is_domain_activec             C   s   | j s
t|| j krt| jddd }|s@| jdd| dS tjt|d j	d}d|krf|d= d||< | jdddj
|j  dS )	a  
        Activate a configured domain

        name:
          The name of the configured domain to activate

        === Returns ===
        No return value

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        NoDomainError:
          No domain by this name is configured
        r   r   r   NrG   rH   r   z, )r   r   r   r   r   r   r[   r   r   rN   r   r\   )rA   rI   r   r   r	   r	   r
   activate_domain2  s    zSSSDConfig.activate_domainc             C   s   | j s
t|| j krt| jddd }|s@| jddd dS tjt|d j	d}d|krf|d= ||krt||= | jdddj
|j  dS )	a  
        Deactivate a configured domain

        name:
          The name of the configured domain to deactivate

        === Returns ===
        No return value

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        NoDomainError:
          No domain by this name is configured
        r   r   r   r   NrG   rH   z, )r   r   r   r   r   r   r[   r   r   rN   r   r\   )rA   rI   r   r   r	   r	   r
   deactivate_domain\  s    zSSSDConfig.deactivate_domainc             C   s(   | j s
t| j| | jdd|  dS )a  
        Remove a domain from the SSSDConfig object. This function will also
        remove this domain from the list of active domains in the [SSSD]
        section, if it is there.

        === Returns ===
        No return value

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        rT   z	domain/%sN)r   r   r   r   )rA   rI   r	   r	   r
   delete_domain  s    
zSSSDConfig.delete_domainc       
      C   sZ  | j s
tt|tst|j }d}|jrX|j|krX| j|j | jdd|j }d|_d| }| j	| j
d|\}}|| j kr| j|g  | j|dd }x@|D ]8}|d dkr|d |j kr| j|d d|d d qW xV|j j D ]F\}}	t|	tkrd	j|	}	|d
kr"| j|	}	| j||t|	 qW |jrL| j| n
| j| dS )a9  
        Save the changes made to the domain object back to the SSSDConfig
        object. If this domain is marked active, ensure it is present in the
        active domain list in the [SSSD] section

        domain_object:
          The SSSDDomain object to save to the configuration.

        === Returns ===
        No return value

        === Errors ===
        NotInitializedError:
          This SSSDConfig object has not had import_config() or new_config()
          run on it yet.
        TypeError:
          domain_object was not of type SSSDDomain
        NrT   z	domain/%srP   r"   rI   rG   Tz, r   )r   r   ro   r   rp   rj   r   r   r   ZfindOptsr   r   r   rL   rl   Zdelete_option_subtreer   rP   r1   r   r   r   r0   r   r   )
rA   r_   rI   ZoldindexZsectionnamenoZsection_subtreeZsection_optionsr"   rG   r	   r	   r
   r     s:    





zSSSDConfig.save_domain)NN)N)N)r   r   r   r~   r5   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r	   r	   r	   r
   r     s0   

-
$""***&$S**r   )!r~   r9   r&   r=   Zsssdoptionsr   Zipachangeconfr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r#   r$   objectri   rn   r   r   r	   r	   r	   r
   <module>   sB    G< \   '