Skip to content

feat: Add newgrp command (#94)#117

Open
Niloyyy wants to merge 2 commits into
microsoft:mainfrom
Niloyyy:feature/add-newgrp
Open

feat: Add newgrp command (#94)#117
Niloyyy wants to merge 2 commits into
microsoft:mainfrom
Niloyyy:feature/add-newgrp

Conversation

@Niloyyy

@Niloyyy Niloyyy commented Jun 9, 2026

Copy link
Copy Markdown

-This PR implements the newgrp command requested in #94.

-It uses LookupAccountNameW and SetTokenInformation to modify the primary group of the process token, then spawns a new shell (%SHELL% or cmd.exe), conforming to standard POSIX-like expectations on Windows.

-It is implemented as a local workspace crate (uu_newgrp) since GNU coreutils does not natively provide it.

@Niloyyy

Niloyyy commented Jun 9, 2026

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

lionelconswork

This comment was marked as off-topic.

@lionelconswork

This comment was marked as off-topic.

@lhecker

This comment was marked as off-topic.

@lionelconswork

This comment was marked as off-topic.

@lhecker

This comment was marked as off-topic.

Comment thread deps/newgrp/src/lib.rs
Comment on lines +15 to +24
pub fn uu_app() -> Command {
Command::new("newgrp")
.about("Log in to a new group")
.arg(
Arg::new("group")
.help("The group to log into")
.index(1)
.required(false),
)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The -c/--command arg is missing.

Comment thread deps/newgrp/src/lib.rs Outdated
}

// Spawn the shell
let shell = std::env::var("SHELL").unwrap_or_else(|_| "cmd.exe".to_string());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The original newgrp command does not respect a SHELL environment variable. Where did you find this behavior?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The original newgrp command does not respect a SHELL environment variable. Where did you find this behavior?

Cygwin/MSYS2

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm a bit conflicted on whether we should port that behavior. Other tools so far have generally followed the GNU coreutils behavior, so I would assume that newgrp would follow the util-linux behavior. But we don't have login(1), so...

Comment thread deps/newgrp/src/lib.rs Outdated
Comment on lines +94 to +97
let mut token: HANDLE = std::ptr::null_mut();
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &mut token) == 0 {
return Err(format!("OpenProcessToken failed: {}", GetLastError()));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't want to change the token of newgrp but the token of the created process. I believe CreateProcessAsUserW would be the appropriate API for that.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You don't want to change the token of newgrp but the token of the created process. I believe CreateProcessAsUserW would be the appropriate API for that.

That should be fine, because the token is then inherited by the new process.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You're right, but I prefer the suggested approach because it expresses the intent better. I think it's a good idea if we treat this like Microsoft reference code to at least a certain extent. And at least conceptually speaking, newgrp does not really modify its own group, right?

I.e.:

duplicate = DuplicateTokenEx(TokenPrimary)
SetTokenInformation(duplicate, TokenPrimaryGroup)
CreateProcessAsUserW(duplicate, shell + command)

Comment thread deps/newgrp/src/lib.rs Outdated
)
}

pub fn uumain(args: impl uucore::Args) -> i32 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Check how grep handles this. You're missing #[uucore::main(no_signals)] and should be returning an UResult<()>. Same for the function below. You can use an io::Error to GetLastError.

@lionelconswork

This comment was marked as off-topic.

@lhecker

This comment was marked as off-topic.

@mlwege

mlwege commented Jun 16, 2026

Copy link
Copy Markdown

Security: The newgrp/sg tools should ONLY allow switching to a group which is listed in TOKEN_GROUPS (read https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_groups) and has the SE_GROUP_ENABLED flag set.

This is what https://github.com/kofemann/ms-nfs41-client/blob/master/tests/winsg/winsg.c , SFU newgrp.exe, Cygwin newgrp.exe are doing. This prevents users from switching to a "random" group for which the admin or system didn't give them access to.

@mlwege

mlwege commented Jun 16, 2026

Copy link
Copy Markdown

IMO the tool should be aliased to sg.exe too:

SG(1)                     User Commands                     SG(1)

NAME
       sg - execute command as different group ID

SYNOPSIS
       sg [-] [group [-c ] command]

DESCRIPTION
       The sg command works similar to newgrp but accepts a
       command. The command will be executed with the /bin/sh
       shell. With most shells you may run sg from, you need to
       enclose multi-word commands in quotes. Another difference
       between newgrp and sg is that some shells treat newgrp
       specially, replacing themselves with a new instance of a
       shell that newgrp creates. This doesn't happen with sg, so
       upon exit from a sg command you are returned to your
       previous group ID.

@mlwege

mlwege commented Jun 16, 2026

Copy link
Copy Markdown

IMO also useful:
SFU newgrp.exe and winsg.exe (https://github.com/kofemann/ms-nfs41-client/blob/master/tests/winsg/winsg.c) have a -L option to list all groups from TOKEN_GROUPS which have the SE_GROUP_ENABLED flag set.
That is IMO useful in the absence of a id.exe tool.

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.

4 participants