Skip to content

Commit 848f826

Browse files
committed
[GR-28391] Implement crypt module
PullRequest: graalpython/1765
2 parents c39e6b6 + 40b9f8a commit 848f826

File tree

12 files changed

+179
-10
lines changed

12 files changed

+179
-10
lines changed

graalpython/com.oracle.graal.python.cext/posix/posix.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,15 @@ int32_t set_sockaddr_in6_members(int8_t *addr, int32_t port, int8_t *address, in
818818
return sizeof(sa);
819819
}
820820

821+
int64_t call_crypt(const char *word, const char *salt, int32_t *len) {
822+
const char *result = crypt(word, salt);
823+
if (result == NULL) {
824+
return NULL;
825+
}
826+
*len = strlen(result);
827+
return (int64_t)(uintptr_t)result;
828+
}
829+
821830
int32_t get_errno() {
822831
return errno;
823832
}

graalpython/com.oracle.graal.python.cext/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ def build_libposix(capi_home):
471471
files = [os.path.abspath(os.path.join(src_dir, f)) for f in os.listdir(src_dir) if f.endswith(".c")]
472472
module = Extension(libposix_name,
473473
sources=files,
474+
libraries=['crypt'] if not darwin_native else [],
474475
extra_compile_args=cflags_warnings + ['-Wall', '-Werror'])
475476
args = [verbosity, 'build', 'install_lib', '-f', '--install-dir=%s' % capi_home, "clean"]
476477
setup(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*graalpython.lib-python.3.test.test_crypt.CryptTestCase.test_blowfish_rounds
2+
*graalpython.lib-python.3.test.test_crypt.CryptTestCase.test_crypt
3+
*graalpython.lib-python.3.test.test_crypt.CryptTestCase.test_invalid_rounds
4+
*graalpython.lib-python.3.test.test_crypt.CryptTestCase.test_methods
5+
*graalpython.lib-python.3.test.test_crypt.CryptTestCase.test_salt
6+
*graalpython.lib-python.3.test.test_crypt.CryptTestCase.test_saltedcrypt
7+
*graalpython.lib-python.3.test.test_crypt.CryptTestCase.test_sha2_rounds
8+
*graalpython.lib-python.3.test.test_crypt.TestWhyCryptDidNotImport.test_import_failure_message

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_queue.txt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
*graalpython.lib-python.3.test.test_queue.CQueueTest.test_shrinking_queue
2020
*graalpython.lib-python.3.test.test_queue.CSimpleQueueTest.test_basic
2121
*graalpython.lib-python.3.test.test_queue.CSimpleQueueTest.test_is_default
22-
*graalpython.lib-python.3.test.test_queue.CSimpleQueueTest.test_many_threads
23-
*graalpython.lib-python.3.test.test_queue.CSimpleQueueTest.test_many_threads_nonblock
24-
*graalpython.lib-python.3.test.test_queue.CSimpleQueueTest.test_many_threads_timeout
2522
*graalpython.lib-python.3.test.test_queue.CSimpleQueueTest.test_negative_timeout_raises_exception
2623
*graalpython.lib-python.3.test.test_queue.CSimpleQueueTest.test_order
2724
*graalpython.lib-python.3.test.test_queue.CSimpleQueueTest.test_reentrancy
@@ -46,9 +43,6 @@
4643
*graalpython.lib-python.3.test.test_queue.PyQueueTest.test_queue_task_done
4744
*graalpython.lib-python.3.test.test_queue.PyQueueTest.test_shrinking_queue
4845
*graalpython.lib-python.3.test.test_queue.PySimpleQueueTest.test_basic
49-
*graalpython.lib-python.3.test.test_queue.PySimpleQueueTest.test_many_threads
50-
*graalpython.lib-python.3.test.test_queue.PySimpleQueueTest.test_many_threads_nonblock
51-
*graalpython.lib-python.3.test.test_queue.PySimpleQueueTest.test_many_threads_timeout
5246
*graalpython.lib-python.3.test.test_queue.PySimpleQueueTest.test_negative_timeout_raises_exception
5347
*graalpython.lib-python.3.test.test_queue.PySimpleQueueTest.test_order
5448
*graalpython.lib-python.3.test.test_queue.PySimpleQueueTest.test_references

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import com.oracle.graal.python.builtins.modules.CodecsTruffleModuleBuiltins;
5959
import com.oracle.graal.python.builtins.modules.CollectionsModuleBuiltins;
6060
import com.oracle.graal.python.builtins.modules.ContextvarsModuleBuiltins;
61+
import com.oracle.graal.python.builtins.modules.CryptModuleBuiltins;
6162
import com.oracle.graal.python.builtins.modules.CtypesModuleBuiltins;
6263
import com.oracle.graal.python.builtins.modules.ErrnoModuleBuiltins;
6364
import com.oracle.graal.python.builtins.modules.FaulthandlerModuleBuiltins;
@@ -391,6 +392,7 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed)
391392
new PropertyBuiltins(),
392393
new BaseExceptionBuiltins(),
393394
new PosixModuleBuiltins(),
395+
new CryptModuleBuiltins(),
394396
new ScandirIteratorBuiltins(),
395397
new DirEntryBuiltins(),
396398
new ImpModuleBuiltins(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.modules;
42+
43+
import java.util.List;
44+
45+
import com.oracle.graal.python.annotations.ArgumentClinic;
46+
import com.oracle.graal.python.builtins.Builtin;
47+
import com.oracle.graal.python.builtins.CoreFunctions;
48+
import com.oracle.graal.python.builtins.PythonBuiltins;
49+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
50+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryClinicBuiltinNode;
51+
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
52+
import com.oracle.graal.python.runtime.PosixSupportLibrary;
53+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
54+
import com.oracle.truffle.api.dsl.NodeFactory;
55+
import com.oracle.truffle.api.dsl.Specialization;
56+
import com.oracle.truffle.api.frame.VirtualFrame;
57+
import com.oracle.truffle.api.library.CachedLibrary;
58+
59+
@CoreFunctions(defineModule = "_crypt")
60+
public class CryptModuleBuiltins extends PythonBuiltins {
61+
@Override
62+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
63+
return CryptModuleBuiltinsFactory.getFactories();
64+
}
65+
66+
@Builtin(name = "crypt", minNumOfPositionalArgs = 2, numOfPositionalOnlyArgs = 2, parameterNames = {"word", "salt"})
67+
@ArgumentClinic(name = "word", conversion = ArgumentClinic.ClinicConversion.String)
68+
@ArgumentClinic(name = "salt", conversion = ArgumentClinic.ClinicConversion.String)
69+
@GenerateNodeFactory
70+
abstract static class CryptNode extends PythonBinaryClinicBuiltinNode {
71+
@Specialization
72+
Object crypt(VirtualFrame frame, String word, String salt,
73+
@CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib) {
74+
try {
75+
return posixLib.crypt(getPosixSupport(), word, salt);
76+
} catch (PosixSupportLibrary.PosixException e) {
77+
throw raiseOSErrorFromPosixException(frame, e);
78+
}
79+
}
80+
81+
@Override
82+
protected ArgumentClinicProvider getArgumentClinic() {
83+
return CryptModuleBuiltinsClinicProviders.CryptNodeClinicProviderGen.INSTANCE;
84+
}
85+
}
86+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,6 +2376,12 @@ public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int s
23762376
throw shouldNotReachHere("Not implemented");
23772377
}
23782378

2379+
@ExportMessage
2380+
@SuppressWarnings({"unused", "static-method"})
2381+
public String crypt(String word, String salt) throws PosixException {
2382+
throw new UnsupportedPosixFeatureException("crypt not supported");
2383+
}
2384+
23792385
@ExportMessage
23802386
@SuppressWarnings("static-method")
23812387
public UniversalSockAddr createUniversalSockAddr(FamilySpecificSockAddr src) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/ImageBuildtimePosixSupport.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@
4545
import java.util.HashSet;
4646
import java.util.IdentityHashMap;
4747

48-
import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException;
4948
import org.graalvm.nativeimage.ImageInfo;
5049

5150
import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult;
5251
import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor;
5352
import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer;
5453
import com.oracle.graal.python.runtime.PosixSupportLibrary.FamilySpecificSockAddr;
5554
import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException;
55+
import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException;
5656
import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException;
5757
import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult;
5858
import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult;
@@ -824,6 +824,13 @@ final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int so
824824
return nativeLib.getaddrinfo(nativePosixSupport, node, service, family, sockType, protocol, flags);
825825
}
826826

827+
@ExportMessage
828+
final String crypt(String word, String salt,
829+
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException {
830+
checkNotInImageBuildtime();
831+
return nativeLib.crypt(nativePosixSupport, word, salt);
832+
}
833+
827834
@ExportMessage
828835
final UniversalSockAddr createUniversalSockAddr(FamilySpecificSockAddr src,
829836
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,17 @@ final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int so
10821082
}
10831083
}
10841084

1085+
@ExportMessage
1086+
final String crypt(String word, String salt,
1087+
@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException {
1088+
logEnter("crypt", "%s, %s", word, salt);
1089+
try {
1090+
return logExit("crypt", "%s", lib.crypt(delegate, word, salt));
1091+
} catch (PosixException e) {
1092+
throw logException("crypt", e);
1093+
}
1094+
}
1095+
10851096
@ExportMessage
10861097
final UniversalSockAddr createUniversalSockAddr(FamilySpecificSockAddr src,
10871098
@CachedLibrary("this.delegate") PosixSupportLibrary lib) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@
6464
import java.util.concurrent.atomic.AtomicReferenceArray;
6565
import java.util.logging.Level;
6666

67-
import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException;
6867
import org.graalvm.nativeimage.ImageInfo;
6968

7069
import com.oracle.graal.python.PythonLanguage;
@@ -78,6 +77,7 @@
7877
import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException;
7978
import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr;
8079
import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr;
80+
import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException;
8181
import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException;
8282
import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult;
8383
import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult;
@@ -126,6 +126,8 @@ public final class NFIPosixSupport extends PosixSupport {
126126

127127
private static final Unsafe UNSAFE = initUnsafe();
128128

129+
private static final Object CRYPT_LOCK = new Object();
130+
129131
private static Unsafe initUnsafe() {
130132
try {
131133
return Unsafe.getUnsafe();
@@ -240,7 +242,9 @@ private enum PosixNativeFunction {
240242
get_sockaddr_in_members("([sint8], [sint32]):void"),
241243
get_sockaddr_in6_members("([sint8], [sint32], [sint8]):void"),
242244
set_sockaddr_in_members("([sint8], sint32, sint32):sint32"),
243-
set_sockaddr_in6_members("([sint8], sint32, [sint8], sint32, sint32):sint32");
245+
set_sockaddr_in6_members("([sint8], sint32, [sint8], sint32, sint32):sint32"),
246+
247+
call_crypt("([sint8], [sint8], [sint32]):sint64");
244248

245249
private final String signature;
246250

@@ -1589,6 +1593,32 @@ public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int s
15891593
return new AddrInfoCursorImpl(this, ptr[0], invokeNode);
15901594
}
15911595

1596+
@ExportMessage
1597+
public String crypt(String word, String salt,
1598+
@Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException {
1599+
int[] lenArray = new int[1];
1600+
/*
1601+
* From the manpage: Upon successful completion, crypt returns a pointer to a string which
1602+
* encodes both the hashed passphrase, and the settings that were used to encode it. See
1603+
* crypt(5) for more detail on the format of hashed passphrases. crypt places its result in
1604+
* a static storage area, which will be overwritten by subsequent calls to crypt. It is not
1605+
* safe to call crypt from multiple threads simultaneously. Upon error, it may return a NULL
1606+
* pointer or a pointer to an invalid hash, depending on the implementation.
1607+
*/
1608+
// Note GIL is not enough as crypt is using global memory so we need a really global lock
1609+
synchronized (CRYPT_LOCK) {
1610+
long resultPtr = invokeNode.callLong(this, PosixNativeFunction.call_crypt, stringToUTF8CString(word), stringToUTF8CString(salt), wrap(lenArray));
1611+
// CPython doesn't handle the case of "invalid hash" return specially and neither do we
1612+
if (resultPtr == 0) {
1613+
throw getErrnoAndThrowPosixException(invokeNode);
1614+
}
1615+
int len = lenArray[0];
1616+
byte[] resultBytes = new byte[len];
1617+
UNSAFE.copyMemory(null, resultPtr, resultBytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, len);
1618+
return PythonUtils.newString(resultBytes);
1619+
}
1620+
}
1621+
15921622
private String gai_strerror(int errorCode,
15931623
@Shared("invoke") @Cached InvokeNativeFunction invokeNode) {
15941624
byte[] buf = new byte[1024];
@@ -2002,6 +2032,11 @@ private Object bufferToCString(Buffer path) {
20022032
return wrap(nullTerminate(path.data, (int) path.length));
20032033
}
20042034

2035+
private Object stringToUTF8CString(String input) {
2036+
byte[] utf8 = BytesUtils.utf8StringToBytes(input);
2037+
return wrap(nullTerminate(utf8, utf8.length));
2038+
}
2039+
20052040
private static byte[] nullTerminate(byte[] str, int length) {
20062041
byte[] terminated = new byte[length + 1];
20072042
PythonUtils.arraycopy(str, 0, terminated, 0, length);

0 commit comments

Comments
 (0)