Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions make/modules/jdk.security.auth/Lib.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ include LibCommon.gmk
## Build libjaas
################################################################################

$(eval $(call SetupJdkLibrary, BUILD_LIBJAAS, \
NAME := jaas, \
OPTIMIZATION := LOW, \
EXTRA_HEADER_DIRS := java.base:libjava, \
LIBS_windows := advapi32.lib mpr.lib netapi32.lib user32.lib, \
))

TARGETS += $(BUILD_LIBJAAS)
ifeq ($(call isTargetOs, windows), true)
$(eval $(call SetupJdkLibrary, BUILD_LIBJAAS, \
NAME := jaas, \
OPTIMIZATION := LOW, \
EXTRA_HEADER_DIRS := java.base:libjava, \
LIBS_windows := advapi32.lib mpr.lib netapi32.lib user32.lib, \
))

TARGETS += $(BUILD_LIBJAAS)
endif
################################################################################
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -26,7 +26,6 @@
package com.sun.security.auth.module;

import java.util.*;
import java.io.IOException;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
Expand Down Expand Up @@ -127,10 +126,14 @@ public boolean login() throws LoginException {
ss = new UnixSystem();
} catch (UnsatisfiedLinkError ule) {
succeeded = false;
throw new FailedLoginException
var error = new FailedLoginException
("Failed in attempt to import " +
"the underlying system identity information" +
" on " + System.getProperty("os.name"));
if (ule.getCause() != null) {
error.initCause(ule.getCause());
}
throw error;
}
userPrincipal = new UnixPrincipal(ss.getUsername());
UIDPrincipal = new UnixNumericUserPrincipal(ss.getUid());
Expand All @@ -150,9 +153,10 @@ public boolean login() throws LoginException {
"succeeded importing info: ");
System.out.println("\t\t\tuid = " + ss.getUid());
System.out.println("\t\t\tgid = " + ss.getGid());
unixGroups = ss.getGroups();
for (int i = 0; i < unixGroups.length; i++) {
System.out.println("\t\t\tsupp gid = " + unixGroups[i]);
if (unixGroups != null) {
for (int i = 0; i < unixGroups.length; i++) {
System.out.println("\t\t\tsupp gid = " + unixGroups[i]);
}
}
}
succeeded = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -25,6 +25,14 @@

package com.sun.security.auth.module;

import jdk.internal.ffi.generated.jaas_unix.passwd;

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;

import static jdk.internal.ffi.generated.jaas_unix.jaas_unix_h.*;

/**
* This class implementation retrieves and makes available Unix
* UID/GID/groups information for the current user.
Expand All @@ -33,10 +41,6 @@
*/
public class UnixSystem {

private native void getUnixInfo();

// Warning: the following 4 fields are used by Unix.c

/** The current username. */
protected String username;

Expand All @@ -53,10 +57,42 @@ public class UnixSystem {
* Instantiate a {@code UnixSystem} and load
* the native library to access the underlying system information.
*/
@SuppressWarnings("restricted")
public UnixSystem() {
System.loadLibrary("jaas");
getUnixInfo();
try (Arena scope = Arena.ofConfined()) {
int groupnum = getgroups(0, MemorySegment.NULL);
if (groupnum == -1) {
throw new RuntimeException("getgroups returns " + groupnum);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a must-have, but would be nice to have a FFM for errno to provide better diagnostics.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. There is a Linker.Option.captureCallState("errno") feature and I'll see how to use it.

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like there has been prior work with this, at least with macos, e.g.: src/java.base/macosx/classes/jdk/internal/ffi/generated/errno/errno_h.java

}

var gs = scope.allocate(gid_t, groupnum);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be the size of gid_t * groupnum as the first argument and the byte alignment as the second?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is MemorySegment allocate(MemoryLayout elementLayout, long count) in SegmentAllocator.java.

groupnum = getgroups(groupnum, gs);
if (groupnum == -1) {
throw new RuntimeException("getgroups returns " + groupnum);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a must-have, but would be nice to have a FFM for errno to provide better diagnostics.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes.

}

groups = new long[groupnum];
for (int i = 0; i < groupnum; i++) {
groups[i] = gs.getAtIndex(gid_t, i);
}

var resbuf = passwd.allocate(scope);
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't this be 1024 as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the MemorySegment allocate(SegmentAllocator allocator) method in the generated passwd.java. If I understand correctly, the 2nd argument to getpwuid_r should be the pointer to a single passwd struct and the 3rd is to a big enough memory to hold contents of extra pointers inside passwd.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, ideally the 3rd argument would be the size of platform's maximum pwd struct buffer size, which at least can found found on linux and macos with _SC_GETPW_R_SIZE_MAX using sysconf. The sysconf FFM would not be a must-have, but would be a nice addition (along with errno) as part of the core libraries in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh no, _SC_GETPW_R_SIZE_MAX itself is 70 on Linux and 71 on macOS. One cross-platform solution I can think of is to set the buffer size to 1K and if not enough double it until enough.

var pwd = scope.allocate(C_POINTER);
var pwd_buf = scope.allocate(1024);
int out = getpwuid_r(getuid(), resbuf, pwd_buf, pwd_buf.byteSize(), pwd);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: resbuf is usually name pwd, which is used to reference the passwd attributes in pwd_buf.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was using the old names in the C code. They could be confusing. I'll fix them.

if (out != 0) {
throw new RuntimeException("getpwuid_r returns " + out);
}
if (pwd.get(ValueLayout.ADDRESS, 0).equals(MemorySegment.NULL)) {
throw new RuntimeException("getpwuid_r returns NULL result");
}
uid = passwd.pw_uid(resbuf);
gid = passwd.pw_gid(resbuf);
username = passwd.pw_name(resbuf).getString(0);
} catch (Throwable t) {
var error = new UnsatisfiedLinkError("FFM calls failed");
error.initCause(t);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you want to check with getCause() here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

getCause of t? I'll just pass the whole t back to the caller.

throw error;
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

// Generated by jextract

package jdk.internal.ffi.generated.jaas_unix;

import java.lang.invoke.*;
import java.lang.foreign.*;
import java.nio.ByteOrder;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

import static java.lang.foreign.ValueLayout.*;
import static java.lang.foreign.MemoryLayout.PathElement.*;

@SuppressWarnings("restricted")
public class jaas_unix_h$shared {

jaas_unix_h$shared() {
// Should not be called directly
}

public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool");
public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char");
public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short");
public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int");
public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long");
public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float");
public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double");
public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*"))
.withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR));
public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long");

static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls");

static void traceDowncall(String name, Object... args) {
String traceArgs = Arrays.stream(args)
.map(Object::toString)
.collect(Collectors.joining(", "));
System.out.printf("%s(%s)\n", name, traceArgs);
}

static MethodHandle upcallHandle(Class<?> fi, String name, FunctionDescriptor fdesc) {
try {
return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType());
} catch (ReflectiveOperationException ex) {
throw new AssertionError(ex);
}
}

static MemoryLayout align(MemoryLayout layout, long align) {
return switch (layout) {
case PaddingLayout p -> p;
case ValueLayout v -> v.withByteAlignment(align);
case GroupLayout g -> {
MemoryLayout[] alignedMembers = g.memberLayouts().stream()
.map(m -> align(m, align)).toArray(MemoryLayout[]::new);
yield g instanceof StructLayout ?
MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers);
}
case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align));
};
}
}
Loading