blob: 9c6240bc4aad5413ff074fd6537ad8014b5562b3 [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?php
2
3namespace LdapRecord\Models\Attributes;
4
5use ReflectionClass;
6
7class AccountControl
8{
9 const SCRIPT = 1;
10
11 const ACCOUNTDISABLE = 2;
12
13 const HOMEDIR_REQUIRED = 8;
14
15 const LOCKOUT = 16;
16
17 const PASSWD_NOTREQD = 32;
18
19 const PASSWD_CANT_CHANGE = 64;
20
21 const ENCRYPTED_TEXT_PWD_ALLOWED = 128;
22
23 const TEMP_DUPLICATE_ACCOUNT = 256;
24
25 const NORMAL_ACCOUNT = 512;
26
27 const INTERDOMAIN_TRUST_ACCOUNT = 2048;
28
29 const WORKSTATION_TRUST_ACCOUNT = 4096;
30
31 const SERVER_TRUST_ACCOUNT = 8192;
32
33 const DONT_EXPIRE_PASSWORD = 65536;
34
35 const MNS_LOGON_ACCOUNT = 131072;
36
37 const SMARTCARD_REQUIRED = 262144;
38
39 const TRUSTED_FOR_DELEGATION = 524288;
40
41 const NOT_DELEGATED = 1048576;
42
43 const USE_DES_KEY_ONLY = 2097152;
44
45 const DONT_REQ_PREAUTH = 4194304;
46
47 const PASSWORD_EXPIRED = 8388608;
48
49 const TRUSTED_TO_AUTH_FOR_DELEGATION = 16777216;
50
51 const PARTIAL_SECRETS_ACCOUNT = 67108864;
52
53 /**
54 * The account control flag values.
55 *
56 * @var array
57 */
58 protected $values = [];
59
60 /**
61 * Constructor.
62 *
63 * @param int $flag
64 */
65 public function __construct($flag = null)
66 {
67 if (! is_null($flag)) {
68 $this->apply($flag);
69 }
70 }
71
72 /**
73 * Get the value when casted to string.
74 *
75 * @return string
76 */
77 public function __toString()
78 {
79 return (string) $this->getValue();
80 }
81
82 /**
83 * Get the value when casted to int.
84 *
85 * @return int
86 */
87 public function __toInt()
88 {
89 return $this->getValue();
90 }
91
92 /**
93 * Add the flag to the account control values.
94 *
95 * @param int $flag
96 *
97 * @return $this
98 */
99 public function add($flag)
100 {
101 // Use the value as a key so if the same value
102 // is used, it will always be overwritten
103 $this->values[$flag] = $flag;
104
105 return $this;
106 }
107
108 /**
109 * Remove the flag from the account control.
110 *
111 * @param int $flag
112 *
113 * @return $this
114 */
115 public function remove($flag)
116 {
117 unset($this->values[$flag]);
118
119 return $this;
120 }
121
122 /**
123 * Extract and apply the flag.
124 *
125 * @param int $flag
126 *
127 * @return void
128 */
129 public function apply($flag)
130 {
131 $this->setValues($this->extractFlags($flag));
132 }
133
134 /**
135 * Determine if the account control contains the given UAC flag(s).
136 *
137 * @param int $flag
138 *
139 * @return bool
140 */
141 public function has($flag)
142 {
143 // Here we will extract the given flag into an array
144 // of possible flags. This will allow us to see if
145 // our AccountControl object contains any of them.
146 $flagsUsed = array_intersect(
147 $this->extractFlags($flag),
148 $this->values
149 );
150
151 return in_array($flag, $flagsUsed);
152 }
153
154 /**
155 * Determine if the account control does not contain the given UAC flag(s).
156 *
157 * @param int $flag
158 *
159 * @return bool
160 */
161 public function doesntHave($flag)
162 {
163 return ! $this->has($flag);
164 }
165
166 /**
167 * Generate an LDAP filter based on the current value.
168 *
169 * @return string
170 */
171 public function filter()
172 {
173 return sprintf('(UserAccountControl:1.2.840.113556.1.4.803:=%s)', $this->getValue());
174 }
175
176 /**
177 * The logon script will be run.
178 *
179 * @return $this
180 */
181 public function runLoginScript()
182 {
183 return $this->add(static::SCRIPT);
184 }
185
186 /**
187 * The user account is locked.
188 *
189 * @return $this
190 */
191 public function accountIsLocked()
192 {
193 return $this->add(static::LOCKOUT);
194 }
195
196 /**
197 * The user account is disabled.
198 *
199 * @return $this
200 */
201 public function accountIsDisabled()
202 {
203 return $this->add(static::ACCOUNTDISABLE);
204 }
205
206 /**
207 * This is an account for users whose primary account is in another domain.
208 *
209 * This account provides user access to this domain, but not to any domain that
210 * trusts this domain. This is sometimes referred to as a local user account.
211 *
212 * @return $this
213 */
214 public function accountIsTemporary()
215 {
216 return $this->add(static::TEMP_DUPLICATE_ACCOUNT);
217 }
218
219 /**
220 * This is a default account type that represents a typical user.
221 *
222 * @return $this
223 */
224 public function accountIsNormal()
225 {
226 return $this->add(static::NORMAL_ACCOUNT);
227 }
228
229 /**
230 * This is a permit to trust an account for a system domain that trusts other domains.
231 *
232 * @return $this
233 */
234 public function accountIsForInterdomain()
235 {
236 return $this->add(static::INTERDOMAIN_TRUST_ACCOUNT);
237 }
238
239 /**
240 * This is a computer account for a computer that is running Microsoft
241 * Windows NT 4.0 Workstation, Microsoft Windows NT 4.0 Server, Microsoft
242 * Windows 2000 Professional, or Windows 2000 Server and is a member of this domain.
243 *
244 * @return $this
245 */
246 public function accountIsForWorkstation()
247 {
248 return $this->add(static::WORKSTATION_TRUST_ACCOUNT);
249 }
250
251 /**
252 * This is a computer account for a domain controller that is a member of this domain.
253 *
254 * @return $this
255 */
256 public function accountIsForServer()
257 {
258 return $this->add(static::SERVER_TRUST_ACCOUNT);
259 }
260
261 /**
262 * This is an MNS logon account.
263 *
264 * @return $this
265 */
266 public function accountIsMnsLogon()
267 {
268 return $this->add(static::MNS_LOGON_ACCOUNT);
269 }
270
271 /**
272 * (Windows 2000/Windows Server 2003) This account does
273 * not require Kerberos pre-authentication for logging on.
274 *
275 * @return $this
276 */
277 public function accountDoesNotRequirePreAuth()
278 {
279 return $this->add(static::DONT_REQ_PREAUTH);
280 }
281
282 /**
283 * When this flag is set, it forces the user to log on by using a smart card.
284 *
285 * @return $this
286 */
287 public function accountRequiresSmartCard()
288 {
289 return $this->add(static::SMARTCARD_REQUIRED);
290 }
291
292 /**
293 * (Windows Server 2008/Windows Server 2008 R2) The account is a read-only domain controller (RODC).
294 *
295 * This is a security-sensitive setting. Removing this setting from an RODC compromises security on that server.
296 *
297 * @return $this
298 */
299 public function accountIsReadOnly()
300 {
301 return $this->add(static::PARTIAL_SECRETS_ACCOUNT);
302 }
303
304 /**
305 * The home folder is required.
306 *
307 * @return $this
308 */
309 public function homeFolderIsRequired()
310 {
311 return $this->add(static::HOMEDIR_REQUIRED);
312 }
313
314 /**
315 * No password is required.
316 *
317 * @return $this
318 */
319 public function passwordIsNotRequired()
320 {
321 return $this->add(static::PASSWD_NOTREQD);
322 }
323
324 /**
325 * The user cannot change the password. This is a permission on the user's object.
326 *
327 * For information about how to programmatically set this permission, visit the following link:
328 *
329 * @see http://msdn2.microsoft.com/en-us/library/aa746398.aspx
330 *
331 * @return $this
332 */
333 public function passwordCannotBeChanged()
334 {
335 return $this->add(static::PASSWD_CANT_CHANGE);
336 }
337
338 /**
339 * Represents the password, which should never expire on the account.
340 *
341 * @return $this
342 */
343 public function passwordDoesNotExpire()
344 {
345 return $this->add(static::DONT_EXPIRE_PASSWORD);
346 }
347
348 /**
349 * (Windows 2000/Windows Server 2003) The user's password has expired.
350 *
351 * @return $this
352 */
353 public function passwordIsExpired()
354 {
355 return $this->add(static::PASSWORD_EXPIRED);
356 }
357
358 /**
359 * The user can send an encrypted password.
360 *
361 * @return $this
362 */
363 public function allowEncryptedTextPassword()
364 {
365 return $this->add(static::ENCRYPTED_TEXT_PWD_ALLOWED);
366 }
367
368 /**
369 * When this flag is set, the service account (the user or computer account)
370 * under which a service runs is trusted for Kerberos delegation.
371 *
372 * Any such service can impersonate a client requesting the service.
373 *
374 * To enable a service for Kerberos delegation, you must set this
375 * flag on the userAccountControl property of the service account.
376 *
377 * @return $this
378 */
379 public function trustForDelegation()
380 {
381 return $this->add(static::TRUSTED_FOR_DELEGATION);
382 }
383
384 /**
385 * (Windows 2000/Windows Server 2003) The account is enabled for delegation.
386 *
387 * This is a security-sensitive setting. Accounts that have this option enabled
388 * should be tightly controlled. This setting lets a service that runs under the
389 * account assume a client's identity and authenticate as that user to other remote
390 * servers on the network.
391 *
392 * @return $this
393 */
394 public function trustToAuthForDelegation()
395 {
396 return $this->add(static::TRUSTED_TO_AUTH_FOR_DELEGATION);
397 }
398
399 /**
400 * When this flag is set, the security context of the user is not delegated to a
401 * service even if the service account is set as trusted for Kerberos delegation.
402 *
403 * @return $this
404 */
405 public function doNotTrustForDelegation()
406 {
407 return $this->add(static::NOT_DELEGATED);
408 }
409
410 /**
411 * (Windows 2000/Windows Server 2003) Restrict this principal to
412 * use only Data Encryption Standard (DES) encryption types for keys.
413 *
414 * @return $this
415 */
416 public function useDesKeyOnly()
417 {
418 return $this->add(static::USE_DES_KEY_ONLY);
419 }
420
421 /**
422 * Get the account control value.
423 *
424 * @return int
425 */
426 public function getValue()
427 {
428 return array_sum($this->values);
429 }
430
431 /**
432 * Get the account control flag values.
433 *
434 * @return array
435 */
436 public function getValues()
437 {
438 return $this->values;
439 }
440
441 /**
442 * Set the account control values.
443 *
444 * @param array $flags
445 *
446 * @return void
447 */
448 public function setValues(array $flags)
449 {
450 $this->values = $flags;
451 }
452
453 /**
454 * Get all flags that are currently applied to the value.
455 *
456 * @return array
457 */
458 public function getAppliedFlags()
459 {
460 $flags = $this->getAllFlags();
461
462 $exists = [];
463
464 foreach ($flags as $name => $flag) {
465 if ($this->has($flag)) {
466 $exists[$name] = $flag;
467 }
468 }
469
470 return $exists;
471 }
472
473 /**
474 * Get all possible account control flags.
475 *
476 * @return array
477 */
478 public function getAllFlags()
479 {
480 return (new ReflectionClass(__CLASS__))->getConstants();
481 }
482
483 /**
484 * Extracts the given flag into an array of flags used.
485 *
486 * @param int $flag
487 *
488 * @return array
489 */
490 public function extractFlags($flag)
491 {
492 $flags = [];
493
494 for ($i = 0; $i <= 26; $i++) {
495 if ((int) $flag & (1 << $i)) {
496 $flags[1 << $i] = 1 << $i;
497 }
498 }
499
500 return $flags;
501 }
502}