blob: 1c70e8cd0dc3a9c8731c3aacc690aba0277bc00e [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?php
2
3namespace Adldap;
4
5class Utilities
6{
7 /**
8 * Converts a DN string into an array of RDNs.
9 *
10 * This will also decode hex characters into their true
11 * UTF-8 representation embedded inside the DN as well.
12 *
13 * @param string $dn
14 * @param bool $removeAttributePrefixes
15 *
16 * @return array|false
17 */
18 public static function explodeDn($dn, $removeAttributePrefixes = true)
19 {
20 $dn = ldap_explode_dn($dn, ($removeAttributePrefixes ? 1 : 0));
21
22 if (is_array($dn) && array_key_exists('count', $dn)) {
23 foreach ($dn as $rdn => $value) {
24 $dn[$rdn] = self::unescape($value);
25 }
26 }
27
28 return $dn;
29 }
30
31 /**
32 * Un-escapes a hexadecimal string into
33 * its original string representation.
34 *
35 * @param string $value
36 *
37 * @return string
38 */
39 public static function unescape($value)
40 {
41 return preg_replace_callback('/\\\([0-9A-Fa-f]{2})/', function ($matches) {
42 return chr(hexdec($matches[1]));
43 }, $value);
44 }
45
46 /**
47 * Convert a binary SID to a string SID.
48 *
49 * @author Chad Sikorra
50 *
51 * @link https://github.com/ChadSikorra
52 * @link https://stackoverflow.com/questions/39533560/php-ldap-get-user-sid
53 *
54 * @param string $value The Binary SID
55 *
56 * @return string|null
57 */
58 public static function binarySidToString($value)
59 {
60 // Revision - 8bit unsigned int (C1)
61 // Count - 8bit unsigned int (C1)
62 // 2 null bytes
63 // ID - 32bit unsigned long, big-endian order
64 $sid = @unpack('C1rev/C1count/x2/N1id', $value);
65
66 if (!isset($sid['id']) || !isset($sid['rev'])) {
67 return;
68 }
69
70 $revisionLevel = $sid['rev'];
71
72 $identifierAuthority = $sid['id'];
73
74 $subs = isset($sid['count']) ? $sid['count'] : 0;
75
76 $sidHex = $subs ? bin2hex($value) : '';
77
78 $subAuthorities = [];
79
80 // The sub-authorities depend on the count, so only get as
81 // many as the count, regardless of data beyond it.
82 for ($i = 0; $i < $subs; $i++) {
83 $data = implode('', array_reverse(
84 str_split(
85 substr($sidHex, 16 + ($i * 8), 8),
86 2
87 )
88 ));
89
90 $subAuthorities[] = hexdec($data);
91 }
92
93 // Tack on the 'S-' and glue it all together...
94 return 'S-'.$revisionLevel.'-'.$identifierAuthority.implode(
95 preg_filter('/^/', '-', $subAuthorities)
96 );
97 }
98
99 /**
100 * Convert a binary GUID to a string GUID.
101 *
102 * @param string $binGuid
103 *
104 * @return string|null
105 */
106 public static function binaryGuidToString($binGuid)
107 {
108 if (trim($binGuid) == '' || is_null($binGuid)) {
109 return;
110 }
111
112 $hex = unpack('H*hex', $binGuid)['hex'];
113
114 $hex1 = substr($hex, -26, 2).substr($hex, -28, 2).substr($hex, -30, 2).substr($hex, -32, 2);
115 $hex2 = substr($hex, -22, 2).substr($hex, -24, 2);
116 $hex3 = substr($hex, -18, 2).substr($hex, -20, 2);
117 $hex4 = substr($hex, -16, 4);
118 $hex5 = substr($hex, -12, 12);
119
120 $guid = sprintf('%s-%s-%s-%s-%s', $hex1, $hex2, $hex3, $hex4, $hex5);
121
122 return $guid;
123 }
124
125 /**
126 * Converts a string GUID to it's hex variant.
127 *
128 * @param string $string
129 *
130 * @return string
131 */
132 public static function stringGuidToHex($string)
133 {
134 $hex = '\\'.substr($string, 6, 2).'\\'.substr($string, 4, 2).'\\'.substr($string, 2, 2).'\\'.substr($string, 0, 2);
135 $hex = $hex.'\\'.substr($string, 11, 2).'\\'.substr($string, 9, 2);
136 $hex = $hex.'\\'.substr($string, 16, 2).'\\'.substr($string, 14, 2);
137 $hex = $hex.'\\'.substr($string, 19, 2).'\\'.substr($string, 21, 2);
138 $hex = $hex.'\\'.substr($string, 24, 2).'\\'.substr($string, 26, 2).'\\'.substr($string, 28, 2).'\\'.substr($string, 30, 2).'\\'.substr($string, 32, 2).'\\'.substr($string, 34, 2);
139
140 return $hex;
141 }
142
143 /**
144 * Encode a password for transmission over LDAP.
145 *
146 * @param string $password The password to encode
147 *
148 * @return string
149 */
150 public static function encodePassword($password)
151 {
152 return iconv('UTF-8', 'UTF-16LE', '"'.$password.'"');
153 }
154
155 /**
156 * Salt and hash a password to make its SSHA OpenLDAP version.
157 *
158 * @param string $password The password to create
159 *
160 * @return string
161 */
162 public static function makeSSHAPassword($password)
163 {
164 mt_srand((float) microtime() * 1000000);
165 $salt = pack('CCCC', mt_rand(), mt_rand(), mt_rand(), mt_rand());
166
167 return '{SSHA}'.base64_encode(pack('H*', sha1($password.$salt)).$salt);
168 }
169
170 /**
171 * Round a Windows timestamp down to seconds and remove
172 * the seconds between 1601-01-01 and 1970-01-01.
173 *
174 * @param float $windowsTime
175 *
176 * @return float
177 */
178 public static function convertWindowsTimeToUnixTime($windowsTime)
179 {
180 return round($windowsTime / 10000000) - 11644473600;
181 }
182
183 /**
184 * Convert a Unix timestamp to Windows timestamp.
185 *
186 * @param float $unixTime
187 *
188 * @return float
189 */
190 public static function convertUnixTimeToWindowsTime($unixTime)
191 {
192 return ($unixTime + 11644473600) * 10000000;
193 }
194
195 /**
196 * Validates that the inserted string is an object SID.
197 *
198 * @param string $sid
199 *
200 * @return bool
201 */
202 public static function isValidSid($sid)
203 {
204 return (bool) preg_match("/^S-\d(-\d{1,10}){1,16}$/i", $sid);
205 }
206
207 /**
208 * Validates that the inserted string is an object GUID.
209 *
210 * @param string $guid
211 *
212 * @return bool
213 */
214 public static function isValidGuid($guid)
215 {
216 return (bool) preg_match('/^([0-9a-fA-F]){8}(-([0-9a-fA-F]){4}){3}-([0-9a-fA-F]){12}$|^([0-9a-fA-F]{8}-){3}[0-9a-fA-F]{8}$/', $guid);
217 }
218
219 /**
220 * Converts an ignore string into an array.
221 *
222 * @param string $ignore
223 *
224 * @return array
225 */
226 protected static function ignoreStrToArray($ignore)
227 {
228 $ignore = trim($ignore);
229
230 return $ignore ? str_split($ignore) : [];
231 }
232}