web2ldap  1.7.7
About: web2ldap is a full-featured web-based LDAPv3 client.
  Fossies Dox: web2ldap-1.7.7.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

activedirectory.py
Go to the documentation of this file.
1# -*- coding: ascii -*-
2"""
3web2ldap plugin classes for Active Directory (for some information see draft-armijo-ldap-syntax)
4"""
5
6import os
7import time
8import uuid
9from typing import Dict
10
11import iso3166
12
13from ldap0.dn import is_dn
14from ldap0.msad import sid2sddl, sddl2sid
15
16from ... import ETC_DIR
17from ...web.forms import Field, Textarea
18from ...utctime import strftimeiso8601
19from ..searchform import SEARCH_OPT_IS_EQUAL
20from .groups import GroupEntryDN
21from ..schema.syntaxes import (
22 Binary,
23 BitArrayInteger,
24 Boolean,
25 DirectoryString,
26 DistinguishedName,
27 DNSDomain,
28 DynamicDNSelectList,
29 DynamicValueSelectList,
30 GeneralizedTime,
31 IA5String,
32 Integer,
33 OctetString,
34 OID,
35 PropertiesSelectList,
36 SelectList,
37 Uri,
38 XmlValue,
39 syntax_registry,
40)
41
42
44 oid: str = 'ObjectCategory-oid'
45 desc: str = 'DN of the class entry'
46 ldap_url = 'ldap:///CN=Schema,CN=Configuration,_?cn?one?(objectClass=classSchema)'
47 ref_attrs = (
48 (None, 'Same category', None, None),
49 )
50
51syntax_registry.reg_at(
52 ObjectCategory.oid, [
53 '1.2.840.113556.1.4.782', # objectCategory
54 '1.2.840.113556.1.4.783', # defaultObjectCategory
55 ]
56)
57
58
60 oid: str = 'ObjectVersion-oid'
61 desc: str = 'Object version in MS AD (see [MS-ADTS])'
62 attr_value_dict: Dict[str, str] = {
63 '13': 'Windows 2000 Server operating system',
64 '30': 'Windows Server 2003 operating system or Windows Server 2008 (AD LDS)',
65 '31': 'Windows Server 2003 R2 operating system or Windows Server 2008 R2 (AD LDS)',
66 '44': 'Windows Server 2008 operating system (AD DS)',
67 '47': 'Windows Server 2008 R2 (AD DS)',
68 '11221': 'Exchange 2007 SP1',
69 '11222': 'Exchange 2007 SP2',
70 '12639': 'Exchange 2010',
71 '12640': 'Exchange 2010',
72 '13040': 'Exchange 2010 SP1',
73 '13214': 'Exchange 2010 SP1',
74 '14247': 'Exchange 2010 SP2',
75 }
76
77 def display(self, vidx, links) -> str:
78 return SelectList.display(self, vidx, links)
79
80# Register certain attribute types for syntax classes
81syntax_registry.reg_at(
82 ObjectVersion.oid, [
83 '1.2.840.113556.1.2.76', # objectVersion
84 ]
85)
86
87
89 oid: str = 'ObjectSID-oid'
90 desc: str = 'Base class for Windows Security Identifiers'
91 """
92 SID anatomy:
93 Byte Position
94 0 : SID Structure Revision Level (SRL)
95 1 : Number of Subauthority/Relative Identifier
96 2-7 : Identifier Authority Value (IAV) [48 bits]
97 8-x : Variable number of Subauthority or Relative Identifier (RID)
98 [32 bits]
99 """
100
101 def _validate(self, attr_value: bytes) -> bool:
102 return OctetString._validate(self, attr_value)
103
104 def sanitize(self, attr_value: bytes) -> bytes:
105 if not attr_value:
106 return b''
107 return sddl2sid(attr_value.decode('ascii'))
108
109 def form_value(self) -> str:
110 if not self._av:
111 return ''
112 return sid2sddl(self._av)
113
114 def input_field(self) -> Field:
115 return IA5String.input_field(self)
116
117 def display(self, vidx, links) -> str:
118 return '%s<br>%s' % (
119 self._app.form.s2d(sid2sddl(self._av)),
120 OctetString.display(self, vidx, links),
121 )
122
123syntax_registry.reg_at(
124 ObjectSID.oid, [
125 '1.2.840.113556.1.4.146', # objectSID
126 '1.2.840.113556.1.4.609', # sIDHistory
127 ]
128)
129
130
132 oid: str = 'OtherSID-oid'
133 desc: str = 'SID in MS AD which points to another object'
134 editable: bool = False
135 well_known_sids = {
136 # see also http://msdn.microsoft.com/en-us/library/aa379649(VS.85).aspx
137 'S-1-0-0': 'NULL',
138 'S-1-1': 'WORLD_DOMAIN',
139 'S-1-1-0': 'WORLD',
140 'S-1-3': 'CREATOR_OWNER_DOMAIN',
141 'S-1-3-0': 'CREATOR_OWNER',
142 'S-1-3-1': 'CREATOR_GROUP',
143 'S-1-3-4': 'OWNER_RIGHTS',
144 'S-1-5': 'NT_AUTHORITY',
145 'S-1-5-1': 'NT_DIALUP',
146 'S-1-5-2': 'NT_NETWORK',
147 'S-1-5-3': 'NT_BATCH',
148 'S-1-5-4': 'NT_INTERACTIVE',
149 'S-1-5-6': 'NT_SERVICE',
150 'S-1-5-7': 'NT_ANONYMOUS',
151 'S-1-5-8': 'NT_PROXY',
152 'S-1-5-9': 'NT_ENTERPRISE_DCS',
153 'S-1-5-10': 'NT_SELF',
154 'S-1-5-11': 'NT_AUTHENTICATED_USERS',
155 'S-1-5-12': 'NT_RESTRICTED',
156 'S-1-5-13': 'NT_TERMINAL_SERVER_USERS',
157 'S-1-5-14': 'NT_REMOTE_INTERACTIVE',
158 'S-1-5-15': 'NT_THIS_ORGANISATION',
159 'S-1-5-17': 'NT_IUSR',
160 'S-1-5-18': 'NT_SYSTEM',
161 'S-1-5-19': 'NT_LOCAL_SERVICE',
162 'S-1-5-20': 'NT_NETWORK_SERVICE',
163 'S-1-5-64-21': 'NT_DIGEST_AUTHENTICATION',
164 'S-1-5-64-10': 'NT_NTLM_AUTHENTICATION',
165 'S-1-5-64-14': 'NT_SCHANNEL_AUTHENTICATION',
166 'S-1-5-1000': 'NT_OTHER_ORGANISATION',
167 'S-1-5-32': 'BUILTIN',
168 'S-1-5-32-544': 'BUILTIN_ADMINISTRATORS',
169 'S-1-5-32-545': 'BUILTIN_USERS',
170 'S-1-5-32-546': 'BUILTIN_GUESTS',
171 'S-1-5-32-547': 'BUILTIN_POWER_USERS',
172 'S-1-5-32-548': 'BUILTIN_ACCOUNT_OPERATORS',
173 'S-1-5-32-549': 'BUILTIN_SERVER_OPERATORS',
174 'S-1-5-32-550': 'BUILTIN_PRINT_OPERATORS',
175 'S-1-5-32-551': 'BUILTIN_BACKUP_OPERATORS',
176 'S-1-5-32-552': 'BUILTIN_REPLICATOR',
177 'S-1-5-32-553': 'BUILTIN_RAS_SERVERS',
178 'S-1-5-32-554': 'BUILTIN_PREW2K',
179 'S-1-5-32-555': 'BUILTIN_REMOTE_DESKTOP_USERS',
180 'S-1-5-32-556': 'BUILTIN_NETWORK_CONF_OPERATORS',
181 }
182
183 def display(self, vidx, links) -> str:
184 sddl_str = sid2sddl(self._av)
185 search_anchor = self.well_known_sids.get(sddl_str, '')
186 if links and sddl_str not in self.well_known_sids:
187 search_anchor = self._app.anchor(
188 'searchform', '&raquo;',
189 [
190 ('dn', self._dn),
191 ('searchform_mode', 'adv'),
192 ('search_attr', 'objectSid'),
193 ('search_option', SEARCH_OPT_IS_EQUAL),
194 ('search_string', sddl_str),
195 ],
196 title='Search by SID',
197 )
198 return '%s %s<br>%s' % (
199 self._app.form.s2d(sddl_str),
200 search_anchor,
201 OctetString.display(self, vidx, links),
202 )
203
204syntax_registry.reg_at(
205 OtherSID.oid, [
206 '1.2.840.113556.1.4.1301', # tokenGroups
207 '1.2.840.113556.1.4.1418', # tokenGroupsGlobalAndUniversal
208 '1.2.840.113556.1.4.1303', # tokenGroupsNoGCAcceptable
209 '1.2.840.113556.1.4.667', # syncWithSID
210 '1.2.840.113556.1.4.1410', # mS-DS-CreatorSID
211 ]
212)
213
214
216 oid: str = 'SAMAccountName-oid'
217 desc: str = 'SAM-Account-Name in MS AD'
218 max_len: int = 20
219
220# Register certain attribute types for syntax classes
221syntax_registry.reg_at(
222 SAMAccountName.oid, [
223 '1.2.840.113556.1.4.221', # sAMAccountName
224 ]
225)
226
227
229 """
230 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adschema/adschema/a_samaccounttype.asp
231 """
232 oid: str = 'SAMAccountType-oid'
233 desc: str = 'SAM-Account-Type in MS AD'
234 attr_value_dict: Dict[str, str] = {
235 '268435456': 'SAM_GROUP_OBJECT',
236 '268435457': 'SAM_NON_SECURITY_GROUP_OBJECT',
237 '536870912': 'SAM_ALIAS_OBJECT',
238 '536870913': 'SAM_NON_SECURITY_ALIAS_OBJECT',
239 '805306368': 'SAM_NORMAL_USER_ACCOUNT',
240 '805306369': 'SAM_MACHINE_ACCOUNT',
241 '805306370': 'SAM_TRUST_ACCOUNT',
242 '1073741824': 'SAM_APP_BASIC_GROUP',
243 '1073741825': 'SAM_APP_QUERY_GROUP',
244 '2147483647': 'SAM_ACCOUNT_TYPE_MAX',
245 }
246
247# Register certain attribute types for syntax classes
248syntax_registry.reg_at(
249 SAMAccountType.oid, [
250 '1.2.840.113556.1.4.302', # sAMAccountType
251 ]
252)
253
254
256 """
257 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adschema/adschema/a_samaccounttype.asp
258 """
259 oid: str = 'GroupType-oid'
260 desc: str = 'Group-Type in MS AD'
261 flag_desc_table = (
262 ('Group created by system', 0x00000001),
263 ('Group with global scope', 0x00000002),
264 ('Group with domain local scope', 0x00000004),
265 ('Group with universal scope', 0x00000008),
266 ('APP_BASIC group Authz Mgr', 0x00000010),
267 ('APP_QUERY group Authz Mgr.', 0x00000020),
268 ('Security group', 0x80000000),
269 )
270
271syntax_registry.reg_at(
272 GroupType.oid, [
273 '1.2.840.113556.1.4.750', # groupType
274 ]
275)
276
277
279 oid: str = 'DomainRID-oid'
280 desc: str = 'Domain RID in MS AD'
281 attr_value_dict: Dict[str, str] = {
282 '9': 'DOMAIN_RID_LOGON',
283 '500': 'DOMAIN_RID_ADMINISTRATOR',
284 '501': 'DOMAIN_RID_GUEST',
285 '502': 'DOMAIN_RID_KRBTGT',
286 '512': 'DOMAIN_RID_ADMINS',
287 '513': 'DOMAIN_RID_USERS',
288 '514': 'DOMAIN_RID_GUESTS',
289 '515': 'DOMAIN_RID_DOMAIN_MEMBERS',
290 '516': 'DOMAIN_RID_DCS',
291 '517': 'DOMAIN_RID_CERT_ADMINS',
292 '518': 'DOMAIN_RID_SCHEMA_ADMINS',
293 '519': 'DOMAIN_RID_ENTERPRISE_ADMINS',
294 '520': 'DOMAIN_RID_POLICY_ADMINS',
295 }
296
297syntax_registry.reg_at(
298 DomainRID.oid, [
299 '1.2.840.113556.1.4.98', # primaryGroupID
300 ]
301)
302
303
305 """
306 See knowledge base article 305144:
307 http://support.microsoft.com/default.aspx?scid=kb;en-us;Q305144
308 """
309 oid: str = 'UserAccountControl-oid'
310 flag_desc_table = (
311 ('SCRIPT', 0x0001),
312 ('ACCOUNTDISABLE', 0x0002),
313 ('HOMEDIR_REQUIRED', 0x0008),
314 ('LOCKOUT', 0x0010),
315 ('PASSWD_NOTREQD', 0x0020),
316 ('PASSWD_CANT_CHANGE', 0x0040),
317 ('ENCRYPTED_TEXT_PWD_ALLOWED', 0x0080),
318 ('TEMP_DUPLICATE_ACCOUNT', 0x0100),
319 ('NORMAL_ACCOUNT', 0x0200),
320 ('INTERDOMAIN_TRUST_ACCOUNT', 0x0800),
321 ('WORKSTATION_TRUST_ACCOUNT', 0x1000),
322 ('SERVER_TRUST_ACCOUNT', 0x2000),
323 ('DONT_EXPIRE_PASSWORD', 0x10000),
324 ('MNS_LOGON_ACCOUNT', 0x20000),
325 ('SMARTCARD_REQUIRED', 0x40000),
326 ('TRUSTED_FOR_DELEGATION', 0x80000),
327 ('NOT_DELEGATED', 0x100000),
328 ('USE_DES_KEY_ONLY', 0x200000),
329 ('DONT_REQ_PREAUTH', 0x400000),
330 ('PASSWORD_EXPIRED', 0x800000),
331 ('TRUSTED_TO_AUTH_FOR_DELEGATION', 0x1000000),
332 ('NO_AUTH_DATA_REQUIRED', 0x2000000),
333 ('PARTIAL_SECRETS_ACCOUNT', 0x4000000),
334 )
335
336syntax_registry.reg_at(
337 UserAccountControl.oid, [
338 '1.2.840.113556.1.4.8', # userAccountControl
339 ]
340)
341
342
344 """
345 See
346 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adschema/adschema/a_systemflags.asp
347 and
348 http://msdn2.microsoft.com/en-us/library/aa772297.aspx
349 """
350 oid: str = 'SystemFlags-oid'
351 flag_desc_table = (
352 ('ADS_SYSTEMFLAG_DISALLOW_DELETE', 0x80000000),
353 ('ADS_SYSTEMFLAG_CONFIG_ALLOW_RENAME', 0x40000000),
354 ('ADS_SYSTEMFLAG_CONFIG_ALLOW_MOVE', 0x20000000),
355 ('ADS_SYSTEMFLAG_CONFIG_ALLOW_LIMITED_MOVE', 0x10000000),
356 ('ADS_SYSTEMFLAG_DOMAIN_DISALLOW_RENAME', 0x08000000),
357 ('ADS_SYSTEMFLAG_DOMAIN_DISALLOW_MOVE', 0x04000000),
358 ('ADS_SYSTEMFLAG_CR_NTDS_NC', 0x00000001),
359 ('ADS_SYSTEMFLAG_CR_NTDS_DOMAIN', 0x00000002),
360 ('ADS_SYSTEMFLAG_ATTR_NOT_REPLICATED', 0x00000001),
361 ('ADS_SYSTEMFLAG_ATTR_IS_CONSTRUCTED', 0x00000004),
362 ('IS_CATEGORY_1_OBJECT', 0x00000010),
363 ('IS_NOT_MOVED_TO_THE_DELETED_OBJECTS', 0x02000000),
364 )
365
366syntax_registry.reg_at(
367 SystemFlags.oid, [
368 '1.2.840.113556.1.4.375', # systemFlags
369 ]
370)
371
372
374 """
375 http://msdn.microsoft.com/en-us/library/ms679765(VS.85).aspx
376
377 1 (0x00000001) Create an index for the attribute.
378 2 (0x00000002) Create an index for the attribute in each container.
379 4 (0x00000004) Add this attribute to the Ambiguous Name Resolution (ANR) set.
380 8 (0x00000008) Preserve this attribute in the tombstone object for deleted objects.
381 16 (0x00000010) Copy the value for this attribute when the object is copied.
382 32 (0x00000020) Create a tuple index for the attribute (since Windows Server 2003).
383 64 (0x00000040) Creates an index to greatly help VLV performance on arbitrary attributes (ADAM).
384 """
385 oid: str = 'SearchFlags-oid'
386 flag_desc_table = (
387 ('Indexed', 0x0001),
388 ('Indexed in each container', 0x0002),
389 ('Ambiguous Name Resolution (ANR)', 0x0004),
390 ('Preserve in tombstone object', 0x0008),
391 ('Copy value when object copied', 0x0010),
392 ('tuple index', 0x0020),
393 ('VLV index (Subtree Index in ADAM)', 0x0040),
394 ('CONFIDENTIAL', 0x0080),
395 ('NEVER_AUDIT_VALUE', 0x0100),
396 ('RODC_FILTERED', 0x0200),
397 ('', 0x0400),
398 ('', 0x0800),
399 )
400
401syntax_registry.reg_at(
402 SearchFlags.oid, [
403 '1.2.840.113556.1.2.334', # searchFlags
404 ]
405)
406
407
409 oid: str = 'LogonHours-oid'
410 desc: str = 'Logon hours'
411 dayofweek = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
412
413 @staticmethod
414 def _extract_hours(value):
415 if not value or len(value) != 21:
416 return []
417 hour_flags = []
418 for eight_hours in value:
419 for i in range(8):
420 hour_flags.append({0:'-', 1:'X'}[(eight_hours>>i)&1])
421 return hour_flags
422
423 def sanitize(self, attr_value: bytes) -> bytes:
424 if not attr_value:
425 return b''
426 attr_value = attr_value.replace(b'\r', b'').replace(b'\n', b'')
427 hour_flags = [
428 int(attr_value[i:i+1] == b'X')<<i%8
429 for i in range(len(attr_value))
430 ]
431 res = [
432 sum(hour_flags[i*8:(i+1)*8])
433 for i in range(21)
434 ]
435 return bytes(res)
436
437 def _validate(self, attr_value: bytes) -> bool:
438 return len(attr_value) == 21
439
440 def form_value(self) -> str:
441 hour_flags = self._extract_hours(self._av)
442 if hour_flags:
443 day_bits = [
444 ''.join(hour_flags[24*day:24*day+24])
445 for day in range(7)
446 ]
447 else:
448 day_bits = []
449 return '\r\n'.join(day_bits)
450
451 def input_field(self) -> Field:
452 return Textarea(
453 self._at,
454 ': '.join([self._at, self.desc]),
455 self.max_len,
456 1,
457 None,
458 default=self.form_valueform_valueform_value(),
459 rows=7,
460 cols=24,
461 )
462
463 def display(self, vidx, links) -> str:
464 hour_flags = self._extract_hours(self._av)
465 result_lines = [
466 """<tr>
467 <th width="10%%">Day</th>
468 <th colspan="3" width="8%%">0</th>
469 <th colspan="3" width="8%%">3</th>
470 <th colspan="3" width="8%%">6</th>
471 <th colspan="3" width="8%%">9</th>
472 <th colspan="3" width="8%%">12</th>
473 <th colspan="3" width="8%%">15</th>
474 <th colspan="3" width="8%%">18</th>
475 <th colspan="3" width="8%%">21</th>
476 </tr>""",
477 ]
478 for day in range(7):
479 day_bits = hour_flags[24*day:24*day+24]
480 result_lines.append(
481 '<tr><td>%s</td><td>%s</td></tr>' % (
482 self.dayofweek[day],
483 '</td><td>'.join(day_bits)
484 )
485 )
486 return '<p>%s</p><table>%s</table>' % (
487 OctetString.display(self, vidx, links),
488 '\n'.join(result_lines)
489 )
490
491
492syntax_registry.reg_at(
493 LogonHours.oid, [
494 '1.2.840.113556.1.4.64', # logonHours
495 ]
496)
497
498
500 oid: str = 'CountryCode-oid'
501 desc: str = 'Numerical country code'
502 sani_funcs = (
503 bytes.strip,
504 )
505
506 def get_attr_value_dict(self) -> Dict[str, str]:
507 # Enable empty value in any case
508 attr_value_dict: Dict[str, str] = {'0': '-/-'}
509 attr_value_dict.update({
510 str(int(num)): cty.name for num, cty in iso3166.countries_by_numeric.items()
511 })
512 attr_value_dict.pop('', None)
513 return attr_value_dict
514
515
516syntax_registry.reg_at(
517 CountryCode.oid, [
518 '1.2.840.113556.1.4.25', # countryCode
519 ]
520)
521
522
524 """
525 http://msdn.microsoft.com/library/en-us/adschema/adschema/a_instancetype.asp
526 """
527 oid: str = 'InstanceType-oid'
528 flag_desc_table = (
529 ('The head of naming context.', 0x00000001),
530 ('This replica is not instantiated.', 0x00000002),
531 ('The object is writable on this directory.', 0x00000004),
532 ('The naming context above this one on this directory is held.', 0x00000008),
533 (
534 'The naming context is in the process of being '
535 'constructed for the first time via replication.',
536 0x00000010
537 ),
538 ('The naming context is in the process of being removed from the local DSA.', 0x00000020),
539 )
540
541syntax_registry.reg_at(
542 InstanceType.oid, [
543 '1.2.840.113556.1.2.1', # instanceType
544 ]
545)
546
547
549 oid: str = '1.2.840.113556.1.4.903'
550 desc: str = 'DNWithOctetString'
551 octetTag = 'B'
552
553 def _validate(self, attr_value: bytes) -> bool:
554 try:
555 octet_tag, count, octet_string, dn = self._app.ls.uc_decode(attr_value)[0].split(':')
556 except ValueError:
557 return False
558 try:
559 count = int(count)
560 except ValueError:
561 return False
562 return len(octet_string) == count and octet_tag.upper() == self.octetTag and is_dn(dn)
563
564 def display(self, vidx, links) -> str:
565 try:
566 octet_tag, count, octet_string, dn = self.av_u.split(':')
567 except ValueError:
568 return self._app.form.s2d(self.av_u)
569 return ':'.join([
570 self._app.form.s2d(octet_tag),
571 self._app.form.s2d(count),
572 self._app.form.s2d(octet_string),
573 self._app.display_dn(dn, links=links),
574 ])
575
576
578 oid: str = '1.2.840.113556.1.4.904'
579 desc: str = 'DNWithString'
580 octetTag = 'S'
581
582
584 oid: str = '1.2.840.113556.1.4.906'
585 desc: str = 'Integer guaranteed to support 64 bit numbers'
586
587
589 oid: str = '1.2.840.113556.1.4.907'
590 desc: str = 'Object-Security-Descriptor'
591
592
594 oid: str = 'MsAdGUID-oid'
595 desc: str = 'GUID in Active Directory'
596
597 def sanitize(self, attr_value: bytes) -> bytes:
598 try:
599 object_guid_uuid = uuid.UUID(attr_value.decode('ascii').replace(':', ''))
600 except ValueError:
601 return OctetString.sanitize(self, attr_value)
602 return object_guid_uuid.bytes
603
604 def display(self, vidx, links) -> str:
605 object_guid_uuid = uuid.UUID(bytes=self._av)
606 return '{%s}<br>%s' % (
607 str(object_guid_uuid),
608 OctetString.display(self, vidx, links),
609 )
610
611syntax_registry.reg_at(
612 MsAdGUID.oid, [
613 '1.2.840.113556.1.4.2', # objectGUID
614 '1.2.840.113556.1.4.1224', # parentGUID
615 '1.2.840.113556.1.4.340', # rightsGuid
616 '1.2.840.113556.1.4.362', # siteGUID
617 ]
618)
619
620
622 oid: str = 'Interval-oid'
623 desc: str = 'Large integer with timestamp expressed as 100 nanoseconds since 1601-01-01 00:00'
624
625 @staticmethod
626 def _delta(attr_value):
627 return (int(attr_value)-116444736000000000)/10000000
628
629 def display(self, vidx, links) -> str:
630 if self.av_uav_u == '9223372036854775807':
631 return '-1: unlimited/off'
632 delta = self._delta(self.av_uav_u)
633 if delta >= 0:
634 return '%s (%s)' % (
635 MicrosoftLargeInteger.display(self, vidx, links),
636 self._app.form.s2d(str(strftimeiso8601(time.gmtime(delta)))),
637 )
638 return self.av_uav_u
639
640
642 oid: str = 'LockoutTime-oid'
643 desc: str = 'Timestamp of password failure lockout'
644
645 def display(self, vidx, links) -> str:
646 delta = self._delta(self._av)
647 if delta == 0:
648 return '%s (not locked)' % (
649 MicrosoftLargeInteger.display(self, vidx, links)
650 )
651 if delta < 0:
652 return MicrosoftLargeInteger.display(self, vidx, links)
653 return '%s (locked since %s)' % (
654 MicrosoftLargeInteger.display(self, vidx, links),
655 self._app.form.s2d(str(strftimeiso8601(time.gmtime(delta)))),
656 )
657
658syntax_registry.reg_at(
659 LockoutTime.oid, [
660 '1.2.840.113556.1.4.662', # lockoutTime
661 ]
662)
663
664
666 oid: str = 'DomainFunctionality-oid'
667 desc: str = 'Functional level of domain/forest'
668
669 attr_value_dict: Dict[str, str] = {
670 '': '',
671 '0': 'Windows 2000',
672 '1': 'Windows 2003 Mixed',
673 '2': 'Windows 2003',
674 '3': 'Windows 2008',
675 '4': 'Windows 2008R2',
676 '5': 'Windows 2012',
677 '6': 'Windows 2012R2',
678 '7': 'Windows 2016',
679 }
680
681syntax_registry.reg_at(
682 DomainFunctionality.oid, [
683 'domainFunctionality', # no schema information available
684 'forestFunctionality', # no schema information available
685 ]
686)
687
688
690 oid: str = 'DomainControllerFunctionality-oid'
691 desc: str = 'Functional level of domain controller'
692
693 attr_value_dict: Dict[str, str] = {
694 '': '',
695 '0': 'Windows 2000',
696 '2': 'Windows 2003',
697 '3': 'Windows 2008',
698 '4': 'Windows 2008R2',
699 '5': 'Windows 2012',
700 '6': 'Windows 2012R2',
701 '7': 'Windows 2016',
702 }
703
704syntax_registry.reg_at(
705 DomainControllerFunctionality.oid, [
706 'domainControllerFunctionality', # no schema information available
707 ]
708)
709
710
711# Register certain attribute types for Interval
712syntax_registry.reg_at(
713 Interval.oid, [
714 '1.2.840.113556.1.4.159', # accountExpires
715 '1.2.840.113556.1.4.49', # badPasswordTime
716 '1.2.840.113556.1.4.52', # lastLogon
717 '1.2.840.113556.1.4.1696', # lastLogonTimestamp
718 '1.2.840.113556.1.4.51', # lastLogoff
719 '1.2.840.113556.1.4.96', # pwdLastSet
720 ]
721)
722
723
725 oid: str = 'ServerStatus-oid'
726 desc: str = 'Specifies whether the server is enabled or disabled.'
727 attr_value_dict: Dict[str, str] = {
728 '': '',
729 '1': 'enabled',
730 '2': 'disabled',
731 }
732
733syntax_registry.reg_at(
734 ServerStatus.oid, [
735 '1.2.840.113556.1.4.154', # serverStatus
736 ]
737)
738
739
741 oid: str = 'ObjectClassCategory-oid'
742 desc: str = 'Category for object class'
743 attr_value_dict: Dict[str, str] = {
744 '1': 'STRUCTURAL',
745 '2': 'ABSTRACT',
746 '3': 'AUXILIARY',
747 }
748
749syntax_registry.reg_at(
750 ObjectClassCategory.oid, [
751 '1.2.840.113556.1.2.370', # objectClassCategory
752 ]
753)
754
755
757 oid: str = 'ClassSchema-oid'
758 desc: str = 'lDAPDisplayName of the classSchema entry'
759 ldap_url = 'ldap:///_?lDAPDisplayName,lDAPDisplayName?one?(objectClass=classSchema)'
760
761 def display(self, vidx, links) -> str:
762 return OID.display(self, vidx, links)
763
764syntax_registry.reg_at(
765 ClassSchemaLDAPName.oid, [
766 '1.2.840.113556.1.2.351', # auxiliaryClass
767 '1.2.840.113556.1.4.198', # systemAuxiliaryClass
768 '1.2.840.113556.1.2.8', # possSuperiors
769 '1.2.840.113556.1.4.195', # systemPossSuperiors
770 ]
771)
772
773
775 oid: str = 'AttributeSchema-oid'
776 desc: str = 'lDAPDisplayName of the classSchema entry'
777 ldap_url = 'ldap:///_?lDAPDisplayName,lDAPDisplayName?one?(objectClass=attributeSchema)'
778
779 def display(self, vidx, links) -> str:
780 return OID.display(self, vidx, links)
781
782syntax_registry.reg_at(
783 AttributeSchemaLDAPName.oid, [
784 '1.2.840.113556.1.2.25', # mayContain
785 '1.2.840.113556.1.4.196', # systemMayContain
786 '1.2.840.113556.1.2.24', # mustContain
787 '1.2.840.113556.1.4.197', # systemMustContain
788 ]
789)
790
791
793 """
794 http://msdn.microsoft.com/en-us/library/ms679431(VS.85).aspx
795 """
796 oid: str = 'PwdProperties-oid'
797 flag_desc_table = (
798 ('DOMAIN_PASSWORD_COMPLEX', 1),
799 ('DOMAIN_PASSWORD_NO_ANON_CHANGE', 2),
800 ('DOMAIN_PASSWORD_NO_CLEAR_CHANGE', 4),
801 ('DOMAIN_LOCKOUT_ADMINS', 8),
802 ('DOMAIN_PASSWORD_STORE_CLEARTEXT', 16),
803 ('DOMAIN_REFUSE_PASSWORD_CHANGE', 32)
804 )
805
806syntax_registry.reg_at(
807 PwdProperties.oid, [
808 '1.2.840.113556.1.4.93', # pwdProperties
809 ]
810)
811
812
814 oid: str = 'MsDSSupportedEncryptionTypes-oid'
815 flag_desc_table = (
816 ('KERB_ENCTYPE_DES_CBC_CRC', 0x00000001),
817 ('KERB_ENCTYPE_DES_CBC_MD5', 0x00000002),
818 ('KERB_ENCTYPE_RC4_HMAC_MD5', 0x00000004),
819 ('KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96', 0x00000008),
820 ('KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96', 0x00000010),
821 )
822
823syntax_registry.reg_at(
824 MsDSSupportedEncryptionTypes.oid, [
825 '1.2.840.113556.1.4.1963', # msDS-SupportedEncryptionTypes
826 ]
827)
828
829
831 oid: str = 'ShowInAddressBook-oid'
832 desc: str = 'DN of the addressbook container entry'
833 ldap_url = 'ldap:///_?cn?sub?(objectClass=addressBookContainer)'
834
835syntax_registry.reg_at(
836 ShowInAddressBook.oid, [
837 '1.2.840.113556.1.4.644', # showInAddressBook
838 ]
839)
840
841
843 oid: str = 'MsDSReplAttributeMetaData-oid'
844 editable: bool = False
845
846 def _validate(self, attr_value: bytes) -> bool:
847 return attr_value.endswith(b'\n\x00') and XmlValue._validate(self, attr_value[:-1])
848
849syntax_registry.reg_at(
850 MsDSReplAttributeMetaData.oid, [
851 '1.2.840.113556.1.4.1707', # msDS-ReplAttributeMetaData
852 ]
853)
854
855
857 oid: str = 'MsSFU30NisDomain-oid'
858 desc: str = 'Name of NIS domain controlled by MS SFU'
859 ldap_url = 'ldap:///_?cn,cn?sub?(objectClass=msSFU30DomainInfo)'
860
861syntax_registry.reg_at(
862 MsSFU30NisDomain.oid, [
863 '1.2.840.113556.1.6.18.1.339', # msSFU30NisDomain
864 ]
865)
866
867
868syntax_registry.reg_at(
869 GroupEntryDN.oid, [
870 '2.5.4.49', # distinguishedName
871 ],
872 structural_oc_oids=[
873 '1.2.840.113556.1.5.8', # group
874 ],
875)
876
877
878# Work around for Active Directory of Windows 2000:
879# Register syntaxes by odd names
880syntax_registry.oid2syntax['Boolean'] = Boolean
881syntax_registry.oid2syntax['DN'] = DistinguishedName
882syntax_registry.oid2syntax['Integer'] = Integer
883syntax_registry.oid2syntax['DirectoryString'] = DirectoryString
884syntax_registry.oid2syntax['GeneralizedTime'] = GeneralizedTime
885
886syntax_registry.reg_at(
887 DistinguishedName.oid, [
888 'configurationNamingContext',
889 'defaultNamingContext',
890 'dsServiceName',
891 'rootDomainNamingContext',
892 'schemaNamingContext',
893 '1.2.840.113556.1.4.223', # serverName
894 ]
895)
896
897# MS AD declares these attributes with OctetString
898# syntax but Binary syntax is more suitable
899syntax_registry.reg_at(
900 Binary.oid, [
901 '1.2.840.113556.1.4.645', # userCert
902 '1.2.840.113556.1.4.4', # replUpToDateVector
903 '1.2.840.113556.1.2.91', # repsFrom
904 '1.2.840.113556.1.2.83', # repsTo
905 '1.2.840.113556.1.2.281', # nTSecurityDescriptor
906 '2.16.840.1.113730.3.1.35', # thumbnailPhoto
907 ]
908)
909
910# MS AD declares these attributes with DirectoryString
911# syntax but OctetString syntax is more suitable
912syntax_registry.reg_at(
913 OctetString.oid, [
914 '1.2.840.113556.1.4.138', # userParameters
915 ]
916)
917
918syntax_registry.reg_at(
919 Uri.oid, [
920 '1.2.840.113556.1.4.583', # meetingURL
921 '1.2.840.113556.1.2.464', # wWWHomePage
922 '1.2.840.113556.1.4.749', # url
923 ]
924)
925
926syntax_registry.reg_at(
927 DirectoryString.oid, [
928 'supportedLDAPPolicies',
929 'ldapServiceName',
930 ]
931)
932
933syntax_registry.reg_at(
934 DNSDomain.oid, [
935 '1.2.840.113556.1.4.619', # dNSHostName
936 ]
937)
938
939syntax_registry.reg_at(
940 Boolean.oid, [
941 'isGlobalCatalogReady',
942 'isSynchronized',
943 ]
944)
945
946syntax_registry.reg_at(
947 Integer.oid, [
948 'highestCommittedUSN',
949 ]
950)
951
952syntax_registry.reg_at(
953 GeneralizedTime.oid, [
954 'currentTime',
955 ]
956)
957
958
959# Register all syntax classes in this module
960syntax_registry.reg_syntaxes(__name__)
def strftimeiso8601(t)
Definition: utctime.py:65