@@ -24,7 +24,11 @@ class UnityLDAP extends ldapConn
2424 "top "
2525 );
2626
27- private $ custom_mappings_path = __DIR__ . "/../../deployment/custom_user_mappings " ;
27+ private $ custom_mappings_path = CONFIG ["ldap " ]["custom_user_mappings_dir " ];
28+ private $ def_user_shell = CONFIG ["ldap " ]["def_user_shell " ];
29+ private $ offset_UIDGID = CONFIG ["ldap " ]["offset_UIDGID " ];
30+ private $ offset_PIGID = CONFIG ["ldap " ]["offset_PIGID " ];
31+ private $ offset_ORGGID = CONFIG ["ldap " ]["offset_ORGGID " ];
2832
2933 // Instance vars for various ldapEntry objects
3034 private $ baseOU ;
@@ -34,7 +38,6 @@ class UnityLDAP extends ldapConn
3438 private $ org_groupOU ;
3539 private $ adminGroup ;
3640 private $ userGroup ;
37- private $ def_user_shell ;
3841
3942 public function __construct ()
4043 {
@@ -46,7 +49,6 @@ public function __construct()
4649 $ this ->org_groupOU = $ this ->getEntry (CONFIG ["ldap " ]["orggroup_ou " ]);
4750 $ this ->adminGroup = $ this ->getEntry (CONFIG ["ldap " ]["admin_group " ]);
4851 $ this ->userGroup = $ this ->getEntry (CONFIG ["ldap " ]["user_group " ]);
49- $ this ->def_user_shell = CONFIG ["ldap " ]["def_user_shell " ];
5052 }
5153
5254 public function getUserOU ()
@@ -84,104 +86,100 @@ public function getDefUserShell()
8486 return $ this ->def_user_shell ;
8587 }
8688
87- public function getNextUIDNumber ( $ UnitySQL )
89+ public function getNextUIDGIDNumber ( $ uid )
8890 {
89- $ max_uid = $ UnitySQL ->getSiteVar ('MAX_UID ' );
90- $ new_uid = $ max_uid + 1 ;
91-
92- while ($ this ->IDNumInUse ($ new_uid )) {
93- $ new_uid ++;
91+ $ IDNumsInUse = array_merge ($ this ->getAllUIDNumbersInUse (), $ this ->getAllGIDNumbersInUse ());
92+ $ start = $ this ->offset_UIDGID ;
93+ $ customIDMappings = $ this ->getCustomIDMappings ();
94+ $ customMappedID = $ customIDMappings [$ uid ] ?? null ;
95+ if (!is_null ($ customMappedID ) && !in_array ($ customMappedID , $ IDNumsInUse )) {
96+ return $ customMappedID ;
9497 }
95-
96- $ UnitySQL ->updateSiteVar ('MAX_UID ' , $ new_uid );
97-
98- return $ new_uid ;
98+ if (!is_null ($ customMappedID ) && in_array ($ customMappedID , $ IDNumsInUse )) {
99+ UnitySite::errorLog (
100+ "warning " ,
101+ "user ' $ uid' has a custom mapped IDNumber $ customMappedID but it's already in use! " ,
102+ );
103+ }
104+ return $ this ->getNextIDNumber ($ start , $ IDNumsInUse );
99105 }
100106
101- public function getNextPiGIDNumber ( $ UnitySQL )
107+ public function getNextPIGIDNumber ( )
102108 {
103- $ max_pigid = $ UnitySQL ->getSiteVar ('MAX_PIGID ' );
104- $ new_pigid = $ max_pigid + 1 ;
105-
106- while ($ this ->IDNumInUse ($ new_pigid )) {
107- $ new_pigid ++;
108- }
109-
110- $ UnitySQL ->updateSiteVar ('MAX_PIGID ' , $ new_pigid );
111-
112- return $ new_pigid ;
109+ $ IDNumsInUse = $ this ->getAllGIDNumbersInUse ();
110+ $ start = $ this ->offset_PIGID ;
111+ return $ this ->getNextIDNumber ($ start , $ IDNumsInUse );
113112 }
114113
115- public function getNextOrgGIDNumber ($ UnitySQL )
114+ public function getNextOrgGIDNumber ()
116115 {
117- $ max_gid = $ UnitySQL ->getSiteVar ('MAX_GID ' );
118- $ new_gid = $ max_gid + 1 ;
119-
120- while ($ this ->IDNumInUse ($ new_gid )) {
121- $ new_gid ++;
122- }
123-
124- $ UnitySQL ->updateSiteVar ('MAX_GID ' , $ new_gid );
125-
126- return $ new_gid ;
116+ $ IDNumsInUse = array_values ($ this ->getCustomIDMappings ());
117+ $ start = $ this ->offset_ORGGID ;
118+ return $ this ->getNextIDNumber ($ start , $ IDNumsInUse );
127119 }
128120
129- private function IDNumInUse ($ id )
121+ private function isIDNumberForbidden ($ id )
130122 {
131123 // 0-99 are probably going to be used for local system accounts instead of LDAP accounts
132124 // 100-999, 60000-64999 are reserved for debian packages
133- if (($ id <= 999 ) || ($ id >= 60000 && $ id <= 64999 )) {
134- return true ;
135- }
136- $ users = $ this ->userOU ->getChildrenArray ([], true );
137- foreach ($ users as $ user ) {
138- if ($ user ["uidnumber " ][0 ] == $ id ) {
139- return true ;
140- }
141- }
142- $ pi_groups = $ this ->pi_groupOU ->getChildrenArray (["gidnumber " ], true );
143- foreach ($ pi_groups as $ pi_group ) {
144- if ($ pi_group ["gidnumber " ][0 ] == $ id ) {
145- return true ;
146- }
147- }
148- $ groups = $ this ->groupOU ->getChildrenArray (["gidnumber " ], true );
149- foreach ($ groups as $ group ) {
150- if ($ group ["gidnumber " ][0 ] == $ id ) {
151- return true ;
152- }
153- }
125+ return (($ id <= 999 ) || ($ id >= 60000 && $ id <= 64999 ));
126+ }
154127
155- return false ;
128+ private function getNextIDNumber ($ start , $ IDNumsInUse )
129+ {
130+ // custom ID mappings are considered both UIDs and GIDs
131+ $ IDNumsInUse = array_merge ($ IDNumsInUse , array_values ($ this ->getCustomIDMappings ()));
132+ $ new_id = $ start ;
133+ while ($ this ->isIDNumberForbidden ($ new_id ) || in_array ($ new_id , $ IDNumsInUse )) {
134+ $ new_id ++;
135+ }
136+ return $ new_id ;
156137 }
157138
158- public function getUnassignedID ( $ uid , $ UnitySQL )
139+ private function getCustomIDMappings ( )
159140 {
160- $ netid = strtok ($ uid , "_ " ); // extract netid
161- // scrape all files in custom folder
141+ $ output = [];
162142 $ dir = new \DirectoryIterator ($ this ->custom_mappings_path );
163143 foreach ($ dir as $ fileinfo ) {
144+ $ filename = $ fileinfo ->getFilename ();
145+ if ($ fileinfo ->isDot () || ($ filename == "README.md " )) {
146+ continue ;
147+ }
164148 if ($ fileinfo ->getExtension () == "csv " ) {
165- // found csv file
166149 $ handle = fopen ($ fileinfo ->getPathname (), "r " );
167- while (($ data = fgetcsv ($ handle , 1000 , ", " )) !== false ) {
168- $ netid_match = $ data [0 ];
169- $ uid_match = $ data [1 ];
170-
171- if ($ uid == $ netid_match || $ netid == $ netid_match ) {
172- // found a match
173- if (!$ this ->IDNumInUse ($ uid_match )) {
174- return $ uid_match ;
175- }
176- }
150+ while (($ row = fgetcsv ($ handle , null , ", " )) !== false ) {
151+ array_push ($ output , $ row );
177152 }
153+ } else {
154+ UnitySite::errorLog (
155+ "warning " ,
156+ "custom ID mapping file ' $ filename' ignored, extension != .csv " ,
157+ );
178158 }
179159 }
160+ $ output_map = [];
161+ foreach ($ output as [$ uid , $ uidNumber_str ]) {
162+ $ output_map [$ uid ] = intval ($ uidNumber_str );
163+ }
164+ return $ output_map ;
165+ }
180166
181- // didn't find anything from existing mappings, use next available
182- $ next_uid = $ this ->getNextUIDNumber ($ UnitySQL );
167+ private function getAllUIDNumbersInUse ()
168+ {
169+ // use baseOU for awareness of externally managed entries
170+ return array_map (
171+ fn ($ x ) => $ x ["uidnumber " ][0 ],
172+ $ this ->baseOU ->getChildrenArray (["uidNumber " ], true , "(objectClass=posixAccount) " ),
173+ );
174+ }
183175
184- return $ next_uid ;
176+ private function getAllGIDNumbersInUse ()
177+ {
178+ // use baseOU for awareness of externally managed entries
179+ return array_map (
180+ fn ($ x ) => $ x ["gidnumber " ][0 ],
181+ $ this ->baseOU ->getChildrenArray (["gidNumber " ], true , "(objectClass=posixGroup) " ),
182+ );
185183 }
186184
187185 public function getAllUsersUIDs ()
@@ -235,7 +233,7 @@ public function getAllUsersAttributes($attributes)
235233 $ user_attributes = $ this ->baseOU ->getChildrenArray (
236234 $ attributes ,
237235 true , // recursive
238- "objectClass=posixAccount "
236+ "( objectClass=posixAccount) "
239237 );
240238 foreach ($ user_attributes as $ i => $ attributes ) {
241239 if (!in_array ($ attributes ["uid " ][0 ], $ include_uids )) {
0 commit comments