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