Skip to content

[NEW] GPO - Add Group Policy Objects module - #124

Open
ValverdeVinicius wants to merge 6 commits into
tranquilit:mainfrom
ValverdeVinicius:implement-gpo-module
Open

[NEW] GPO - Add Group Policy Objects module#124
ValverdeVinicius wants to merge 6 commits into
tranquilit:mainfrom
ValverdeVinicius:implement-gpo-module

Conversation

@ValverdeVinicius

Copy link
Copy Markdown

Fixes #120

Group Policy Objects (GPO) module

Adds a Group Policy module to list, view, create, duplicate, rename and delete the Group Policy Objects of a domain, and to edit their content.

GPC (LDAP)

  • TGPO / TGPOLogic (packages/OpenRSATCore/ugpocore.pas): list, create, duplicate, rename and delete GPOs, with staged modifications applied in a single LDAP operation (Add/Replace/Delete per attribute).
  • GPO catalog of the available GPC parameters, with descriptions.

GPT (SYSVOL)

  • TGPTCore (packages/OpenRSATCore/ugptcore.pas): access to the GPT files through smbclient on Linux/macOS and through the native UNC API (with WNetAddConnection2) on Windows.
  • List the GPT files, read/write GPT.INI and Registry.pol files. LastError reports the real failure reason.

Registry.pol (REGF)

  • TGPRegPol (packages/OpenRSATCore/ugpregpol.pas): binary REGF parser and serializer (PRegf header, nested keys, REG_SZ/REG_EXPAND_SZ/REG_DWORD/REG_QWORD/REG_BINARY/REG_MULTI_SZ values).

UI (packages/OpenRSATGUI/ufrmmodulegpo.pas)

  • Toolbar to create, duplicate, rename and delete the selected GPO.
  • GPO list on the left; the selected GPO is shown in the center with tabs:
    • Summary: status, versions, statistics (total/known/unknown parameters, used technologies).
    • Configuration: list of parameters with an editor panel on the right (GPC parameters, or User/Machine Registry.pol key/value editor).
    • Catalog: all available parameters, to easily add a new parameter to the GPO.
    • Technical: GPC path and attributes, GPT path, files and GPT.INI.
  • All changes remain local until the save action (staging model).

Save flow (GPO modification)

  1. Check the staged changes.
  2. Update the files and objects by provider (Registry.pol files of the dirty sides are written on the SYSVOL).
  3. Update the GPT.INI when requested (version, display name, options).
  4. Calculate the new version of User/Machine (a dirty Registry.pol side bumps its version automatically, the checkboxes add manual increments).
  5. Update the versionNumber.

Tests

  • tests/unit/unittest.ugpocore.pas: 149 assertions covering the GPC helpers, the GPT.INI parser, the smbclient output parser and the Registry.pol parser (load, round-trip, edit and save, invalid inputs).
  • tests/integration/integrationtest.ugpocore.pas: integration tests against a real Active Directory (list, create, duplicate, rename, delete, update configuration).

Add a Group Policy module to list, view, create, duplicate, rename and
delete the Group Policy Objects of a domain, and to edit their content.

- LDAP core (GPC): TGPO and TGPOLogic (list, create, duplicate, rename,
  delete, staged modifications applied in a single LDAP operation).
- SYSVOL access (GPT): TGPTCore using smbclient on Linux/macOS and the
  native UNC API on Windows; list files, read and write GPT.INI and
  Registry.pol files.
- Registry.pol (REGF): TGPRegPol parser and serializer (keys, values,
  REG_SZ/REG_DWORD/REG_BINARY/...).
- UI: toolbar actions, GPO list, Summary/Configuration/Catalog/Technical
  tabs, GPC parameter editor and Registry.pol visual editor, with a local
  staging model: nothing is written to the domain until the save action.
- Save flow: write the modified Registry.pol files, update the GPT.INI,
  calculate the new User/Machine versions and update the versionNumber.
- Register the module in the main window and in the packages.

@synopse synopse left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice PR!
I really like that there are so many unit tests.

I made some minor proposals of refactoring, adding some new wrapper functions to mORMot.
I guess the core GPO logic could be part of mormot.net.ldap, to be reusable.

What do you think?

Comment thread packages/OpenRSATCore/ugpocore.pas Outdated
{ TGPO }

function TGPO.GetDisplayName: RawUtf8;
var

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use TLdapAttributeList.GetByName()

Comment thread packages/OpenRSATCore/ugpocore.pas Outdated
i: Integer;
begin
result := '';
if not ParseDN(ADomainDN, Pairs) then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing noraise=true.
simply use the new DNToCN((ADomainDN, true, [dnDC])

Comment thread packages/OpenRSATCore/ugpocore.pas Outdated
constructor TGPOLogic.Create(ALdapClient: TLdapClient);
begin
fLog := TOpenRSATLog;
if Assigned(fLog) then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

anti pattern for sure - no way to disable this logging, which has little interrest

Comment thread packages/OpenRSATCore/ugpocore.pas Outdated
Attributes.Add(GPO_ATTR_DISPLAYNAME, ADisplayName);

DomainName := GetDomainName;
Attributes.Add(GPO_ATTR_FILESYSPATH,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just created TLdapAttributeList.AddFmt for this kind of code

Comment thread packages/OpenRSATCore/ugpocore.pas Outdated
function TGPOLogic.ApplyModifications(AGPO: TGPO;
const AModifications: array of TGPOModification): Boolean;
var
Modifications: array of RawByteString;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use AsnAddItem() and Modifications: TAsnObjects

Comment thread packages/OpenRSATCore/ugpocore.pas Outdated
GPO_MACHINE_VERSION_SHIFT = 16;

// Attributes of the GPC that OpenRSAT knows and can manage.
GPO_KNOWN_ATTRIBUTES: array of RawUtf8 = (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using an enumerate would be much better here

Comment thread packages/OpenRSATCore/ugpocore.pas Outdated
var
i: Integer;
begin
SetLength(result, Length(GPO_KNOWN_ATTRIBUTES));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code would be simplified with an enumerate for GPO_KNOWN_ATTRIBUTES[] index

@ValverdeVinicius

Copy link
Copy Markdown
Author

Very nice PR! I really like that there are so many unit tests.

I made some minor proposals of refactoring, adding some new wrapper functions to mORMot. I guess the core GPO logic could be part of mormot.net.ldap, to be reusable.

What do you think?

I agree with that. I'll do it as soon as possible.

- Keep the GPO core logic in OpenRSAT (ugpocore.pas) and use the LDAP
  helpers added in mORMot 2.4 (GetByName, AddFmt, TAsnObjects/AsnAddItem,
  DNToCN with dnDC filter) instead of reimplementing them.
- Fix the Registry.pol string handling: Windows stores REG_SZ/REG_MULTI_SZ
  values as UTF-16LE, now detected and converted on read/write.
- Sanitize non UTF-8 text coming from smbclient and the SYSVOL files before
  it reaches the UI.
- Fall back to English when a translation resource is missing, and stop
  logging an error when the Options TreeView has no previous selection.
- Rename the GPO creation method to TGPOLogic.Add (avoid shadowing Create).
- Reference the mORMot2 package of the submodule explicitly in the project
  files, and bump the mORMot2 submodule to the official 2.4 helpers.
- Add a UTF-16LE Registry.pol unit test and keep the GPO catalog enum.
- Widen the Stage/Discard and Save/Discard changes buttons so the
  translated captions are not truncated, and enlarge the Configuration
  editor panel.
- Make the GPT files list taller and add two splitters on the Technical
  tab: one between the GPC attributes and the GPT area, and one between
  the GPT files grid and the GPT.INI memo.
Remove the translation entries of the old GPO module strings that no
longer exist in the code, and reorder the catalog around the new
rsGPOCatalog* constants.
@osvegn

osvegn commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Nice work!
I appreciate the work you've done to add a the GPO module. It follows most of the features requested by the initial issue (#120). But this issue only shares some of my ideas, not what is expected in OpenRSAT. It should have been a discussion instead of an issue to implement.
Most of the logical part should be used for the GPO features. Some part could be part of mORMot2, some others can be part of the OpenRSAT project.
However, I do not agree with the UI. It looks like my first idea of creating a new GPO module with everything related to GPO in it, in a flat way. But it should be better to implement the GPO in a similar UI than Microsoft's tool (GPMC), so system administrators wont be lost when they will use OpenRSAT, as with the other modules.
So instead of creating a new module, GPO can be part of the ADUC module, which already shows GPO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Group Policy Objects (GPO) Module

3 participants