Bug 56309 - udm users/user create doesn't update univentionLastUsedValue of cn=uidNumber if allocated SID is taken
udm users/user create doesn't update univentionLastUsedValue of cn=uidNumber ...
Status: CLOSED FIXED
Product: UCS
Classification: Unclassified
Component: UDM (Generic)
UCS 5.0
Other Linux
: P5 normal (vote)
: UCS 5.0-4-errata
Assigned To: Arvid Requate
Florian Best
https://git.knut.univention.de/univen...
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2023-07-12 17:38 CEST by Arvid Requate
Modified: 2023-07-19 17:15 CEST (History)
1 user (show)

See Also:
What kind of report is it?: Bug Report
What type of bug is this?: 5: Major Usability: Impairs usability in key scenarios
Who will be affected by this bug?: 1: Will affect a very few installed domains
How will those affected feel about the bug?: 5: Blocking further progress on the daily work
User Pain: 0.143
Enterprise Customer affected?:
School Customer affected?: Yes
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number: 2023070621000206
Bug group (optional):
Max CVSS v3 score:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Arvid Requate univentionstaff 2023-07-12 17:38:22 CEST
In a UCS@school domain with a UCS 5.0-4 errata726 primary a customer experienced that the S4-Connector repeatedly generated rejects due to SID values already occupied in Samba/AD.

connector-s4.log had:
===
ldap.CONSTRAINT_VIOLATION: {'desc': 'Constraint violation', 'info': '0000202F: ../../lib/ldb/ldb_key_value/ldb_kv_index.c:3065: Failed to re-index objectSid in CN=someuser,CN=schueler,CN=users,OU=foo,DC=school,DC=domain - ../../lib/ldb/ldb_key_value/ldb_kv_index.c:2910: unique index violation on objectSid in CN=someuser,CN=schueler,CN=users,OU=foo,DC=school,DC=domain'}
===

Support found that the SIDs where blocked by deleted objects under "CN=Deleted Objects" and the "tombstone reanimation" procedure was not initiated by the S4-Connector because the new user didn't match the name of the deleted object.

In UCS@school, the udm allocator is responsible to allocate SIDs and the allocation starts the search for a free RID at the value of (1000 + uidNumber*2). This in turn depends on the allocated uidNumber and that starts at the value that is stored in univentionLastUsedValue and the object cn=uidNumber,cn=temporary,cn=univention,$ldap_base.

We checked the customer environment and found that that value univentionLastUsedValue had not changed since 20221212074241Z and creating a new user with udm also didn't update the value. So udm always started at some lower value of uidNumber and in turn allocated some arbitrary sambaSID that it found to be free, in this case that of a deleted object.

Debugging showed that the request_lock('sid+user', uidNum) call from __generate_user_sid() calls self._release_locks() in case the initial guess for the sambaSID cannot be locked. This can happen, if the naive (1000+uidNumber*2) formula suggests a sambaSID that happens to be already taken. The __generate_user_sid() call then catches the noLock exception and suggests a new sambaSID until it succeeds. So far so good, and the user is created successfully. But: Since _release_locks() flushed all memory about the allocated uidNumber, it will never again be updated in the univentionLastUsedValue.
Comment 1 Arvid Requate univentionstaff 2023-07-12 17:47:37 CEST
See URL field above for a naive untested patch proposal.
Comment 2 Arvid Requate univentionstaff 2023-07-12 17:49:08 CEST
Stacktrace from the _release_locks() call: https://pastebin.knut.univention.de/vKFzEyYp
Comment 3 Arvid Requate univentionstaff 2023-07-12 17:51:23 CEST
Workaround: manually update the univentionLastUsedValue of cn=uidNumber to the currently highest uidNumber in the domain (via ldapmodify) and check that the (1000+2*(uidNumber+1)) is still free.
Comment 4 Florian Best univentionstaff 2023-07-13 10:53:04 CEST
(In reply to Arvid Requate from comment #2)
> Stacktrace from the _release_locks() call:
> https://pastebin.knut.univention.de/vKFzEyYp

_release_locks called
  File "/usr/share/univention-directory-manager-tools/univention-cli-server", line 302, in <module>
    main()
  File "/usr/share/univention-directory-manager-tools/univention-cli-server", line 293, in main
    server_main(args)
  File "/usr/share/univention-directory-manager-tools/univention-cli-server", line 167, in server_main
    handler.handle_request()
  File "/usr/lib/python3.7/socketserver.py", line 296, in handle_request
    return self._handle_request_noblock()
  File "/usr/lib/python3.7/socketserver.py", line 316, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python3.7/socketserver.py", line 616, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python3.7/socketserver.py", line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python3.7/socketserver.py", line 720, in __init__
    self.handle()
  File "/usr/share/univention-directory-manager-tools/univention-cli-server", line 93, in handle
    doit(sarglist, self.request, stdout, stderr)
  File "/usr/share/univention-directory-manager-tools/univention-cli-server", line 238, in doit
    univention.admincli.admin.main(arglist, stdout, stderr)
  File "/usr/lib/python3/dist-packages/univention/admincli/admin.py", line 351, in main
    _doit(arglist, stdout=stdout, stderr=stderr)
  File "/usr/lib/python3/dist-packages/univention/admincli/admin.py", line 600, in _doit
    cli.create(input, append, ignore_exists, parsed_options, parsed_append_options, parsed_remove_options, policy_reference)
  File "/usr/lib/python3/dist-packages/univention/admincli/admin.py", line 628, in create
    return self._create(self.module_name, self.module, self.dn, self.lo, self.position, self.superordinate, *args, **kwargs)
  File "/usr/lib/python3/dist-packages/univention/admincli/admin.py", line 679, in _create
    dn = object.create()
  File "/usr/lib/python3/dist-packages/univention/admin/handlers/__init__.py", line 557, in create
    dn = self._create(response=response, serverctrls=serverctrls)
  File "/usr/lib/python3/dist-packages/univention/admin/handlers/__init__.py", line 1268, in _create
    al.extend(self._ldap_modlist())
  File "/usr/lib/python3/dist-packages/univention/admin/handlers/users/user.py", line 1583, in _ldap_modlist
    ml = self._modlist_samba_sid(ml)
  File "/usr/lib/python3/dist-packages/univention/admin/handlers/users/user.py", line 1942, in _modlist_samba_sid
    sid = self.__generate_user_sid(self['uidNumber'])
  File "/usr/lib/python3/dist-packages/univention/admin/handlers/users/user.py", line 2062, in __generate_user_sid
    return self.request_lock('sid+user', uidNum)
  File "/usr/lib/python3/dist-packages/univention/admin/handlers/__init__.py", line 1711, in request_lock
    self._release_locks()
  File "/usr/lib/python3/dist-packages/univention/admin/handlers/__init__.py", line 1680, in _release_locks
    f.write("%s\n" % ''.join(traceback.format_stack()))
Comment 6 Arvid Requate univentionstaff 2023-07-18 07:13:32 CEST
25b40c47b2 | release only specific locks when locking fails

Built in errata5.0-4 as version 15.0.24-13.
Comment 7 Florian Best univentionstaff 2023-07-18 11:24:02 CEST
OK: functional test
OK: Code review
FYI: as the values aren't added to self.alloc yet the release_lock(name) is a NO-OP (I don't think a lock is requested twice). but ok for me, as the new function signature might be usefull in the future and the code line represents the idea.
OK: Code review that if this case happens afterwards at the very end on operations like create/modify/etc the requested locks during that operation are cleaned up/released.
OK: Jenkins tests ok
OK: YAML