""" ldif - generate and parse LDIF data (see RFC 2849) See https://www.python-ldap.org/ for details. """ from __future__ import unicode_literals __version__ = '3.1.0' __all__ = [ # constants 'ldif_pattern', # functions 'CreateLDIF','ParseLDIF', # classes 'LDIFWriter', 'LDIFParser', 'LDIFRecordList', 'LDIFCopy', ] import re from base64 import b64encode, b64decode from io import StringIO import warnings from ldap.compat import urlparse, urlopen attrtype_pattern = r'[\w;.-]+(;[\w_-]+)*' attrvalue_pattern = r'(([^,]|\\,)+|".*?")' attrtypeandvalue_pattern = attrtype_pattern + r'[ ]*=[ ]*' + attrvalue_pattern rdn_pattern = attrtypeandvalue_pattern + r'([ ]*\+[ ]*' + attrtypeandvalue_pattern + r')*[ ]*' dn_pattern = rdn_pattern + r'([ ]*,[ ]*' + rdn_pattern + r')*[ ]*' dn_regex = re.compile('^%s$' % dn_pattern) ldif_pattern = '^((dn(:|::) %(dn_pattern)s)|(%(attrtype_pattern)s(:|::) .*)$)+' % vars() MOD_OP_INTEGER = { 'add':0, # ldap.MOD_ADD 'delete':1, # ldap.MOD_DELETE 'replace':2, # ldap.MOD_REPLACE 'increment':3, # ldap.MOD_INCREMENT } MOD_OP_STR = { 0:'add',1:'delete',2:'replace',3:'increment' } CHANGE_TYPES = ['add','delete','modify','modrdn'] valid_changetype_dict = {} for c in CHANGE_TYPES: valid_changetype_dict[c]=None def is_dn(s): """ returns 1 if s is a LDAP DN """ if s=='': return 1 rm = dn_regex.match(s) return rm!=None and rm.group(0)==s SAFE_STRING_PATTERN = b'(^(\000|\n|\r| |:|<)|[\000\n\r\200-\377]+|[ ]+$)' safe_string_re = re.compile(SAFE_STRING_PATTERN) def list_dict(l): """ return a dictionary with all items of l being the keys of the dictionary """ return {i: None for i in l} class LDIFWriter: """ Write LDIF entry or change records to file object Copy LDIF input to a file output object containing all data retrieved via URLs """ def __init__(self,output_file,base64_attrs=None,cols=76,line_sep='\n'): """ output_file file object for output; should be opened in *text* mode base64_attrs list of attribute types to be base64-encoded in any case cols Specifies how many columns a line may have before it's folded into many lines. line_sep String used as line separator """ self._output_file = output_file self._base64_attrs = list_dict([a.lower() for a in (base64_attrs or [])]) self._cols = cols self._last_line_sep = line_sep self.records_written = 0 def _unfold_lines(self,line): """ Write string line as one or more folded lines """ # Check maximum line length line_len = len(line) if line_len<=self._cols: self._output_file.write(line) self._output_file.write(self._last_line_sep) else: # Fold line pos = self._cols self._output_file.write(line[0:min(line_len,self._cols)]) self._output_file.write(self._last_line_sep) while pos