Skip to content

Commit f8e4237

Browse files
committed
_crypt: fix implicit declaration of crypt(), use crypt_r() if available.
The '_crypt' module provides a binding to the C crypt(3) function. It is used by the crypt.crypt() function. Looking at the C code, there are a couple of things we can improve: - Because crypt() only depends on primitive C types, we currently get away with calling it without it being declared. Ensure that we include <unistd.h>, which is the POSIX header file declaring this. - The disadvantage of crypt() is that it's thread-unsafe. Systems like Linux and recent versions of FreeBSD nowadays provide crypt_r() as a replacement. This function allows you to pass in a 'crypt_data' object that will hold the resulting string for you. Extend the code to use this function when available. This patch is actually needed to make this module build on CloudABI (https://mail.python.org/pipermail/python-dev/2016-July/145708.html). CloudABI's C library doesn't provide any thread-unsafe functions, meaning that crypt_r() is the only way you can crypt passwords.
1 parent 29ba688 commit f8e4237

File tree

5 files changed

+73
-6
lines changed

5 files changed

+73
-6
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Let the `_crypt` module use `crypt_r()` when available for thread safety.

Modules/_cryptmodule.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
#include <sys/types.h>
77

8+
#ifdef HAVE_CRYPT_H
9+
#include <crypt.h>
10+
#endif
11+
#include <unistd.h>
12+
813
/* Module crypt */
914

1015
/*[clinic input]
@@ -34,7 +39,13 @@ static PyObject *
3439
crypt_crypt_impl(PyObject *module, const char *word, const char *salt)
3540
/*[clinic end generated code: output=0512284a03d2803c input=0e8edec9c364352b]*/
3641
{
42+
#ifdef HAVE_CRYPT_R
43+
struct crypt_data data;
44+
data.initialized = 0;
45+
return Py_BuildValue("s", crypt_r(word, salt, &data));
46+
#else
3747
return Py_BuildValue("s", crypt(word, salt));
48+
#endif
3849
}
3950

4051

configure

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7681,7 +7681,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h
76817681

76827682
fi
76837683

7684-
for ac_header in asm/types.h conio.h direct.h dlfcn.h errno.h \
7684+
for ac_header in asm/types.h conio.h crypt.h direct.h dlfcn.h errno.h \
76857685
fcntl.h grp.h \
76867686
ieeefp.h io.h langinfo.h libintl.h process.h pthread.h \
76877687
sched.h shadow.h signal.h stropts.h termios.h \
@@ -9502,6 +9502,51 @@ _ACEOF
95029502

95039503
fi
95049504
# Dynamic linking for HP-UX
9505+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
9506+
$as_echo_n "checking for crypt in -lcrypt... " >&6; }
9507+
if ${ac_cv_lib_crypt_crypt+:} false; then :
9508+
$as_echo_n "(cached) " >&6
9509+
else
9510+
ac_check_lib_save_LIBS=$LIBS
9511+
LIBS="-lcrypt $LIBS"
9512+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
9513+
/* end confdefs.h. */
9514+
9515+
/* Override any GCC internal prototype to avoid an error.
9516+
Use char because int might match the return type of a GCC
9517+
builtin and then its argument prototype would still apply. */
9518+
#ifdef __cplusplus
9519+
extern "C"
9520+
#endif
9521+
char crypt ();
9522+
int
9523+
main ()
9524+
{
9525+
return crypt ();
9526+
;
9527+
return 0;
9528+
}
9529+
_ACEOF
9530+
if ac_fn_c_try_link "$LINENO"; then :
9531+
ac_cv_lib_crypt_crypt=yes
9532+
else
9533+
ac_cv_lib_crypt_crypt=no
9534+
fi
9535+
rm -f core conftest.err conftest.$ac_objext \
9536+
conftest$ac_exeext conftest.$ac_ext
9537+
LIBS=$ac_check_lib_save_LIBS
9538+
fi
9539+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
9540+
$as_echo "$ac_cv_lib_crypt_crypt" >&6; }
9541+
if test "x$ac_cv_lib_crypt_crypt" = xyes; then :
9542+
cat >>confdefs.h <<_ACEOF
9543+
#define HAVE_LIBCRYPT 1
9544+
_ACEOF
9545+
9546+
LIBS="-lcrypt $LIBS"
9547+
9548+
fi
9549+
# crypt() on Linux
95059550

95069551
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time_safe" >&5
95079552
$as_echo_n "checking for uuid_generate_time_safe... " >&6; }
@@ -11141,8 +11186,8 @@ fi
1114111186

1114211187
# checks for library functions
1114311188
for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
11144-
clock confstr ctermid dup3 execv faccessat fchmod fchmodat fchown fchownat \
11145-
fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
11189+
clock confstr crypt_r ctermid dup3 execv faccessat fchmod fchmodat fchown \
11190+
fchownat fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
1114611191
futimens futimes gai_strerror getentropy \
1114711192
getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \
1114811193
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \

configure.ac

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,7 +2043,7 @@ dnl AC_MSG_RESULT($cpp_type)
20432043

20442044
# checks for header files
20452045
AC_HEADER_STDC
2046-
AC_CHECK_HEADERS(asm/types.h conio.h direct.h dlfcn.h errno.h \
2046+
AC_CHECK_HEADERS(asm/types.h conio.h crypt.h direct.h dlfcn.h errno.h \
20472047
fcntl.h grp.h \
20482048
ieeefp.h io.h langinfo.h libintl.h process.h pthread.h \
20492049
sched.h shadow.h signal.h stropts.h termios.h \
@@ -2679,6 +2679,7 @@ AC_MSG_RESULT($SHLIBS)
26792679
AC_CHECK_LIB(sendfile, sendfile)
26802680
AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV
26812681
AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
2682+
AC_CHECK_LIB(crypt, crypt) # crypt() on Linux
26822683

26832684
AC_MSG_CHECKING(for uuid_generate_time_safe)
26842685
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <uuid/uuid.h>]], [[
@@ -3409,8 +3410,8 @@ fi
34093410

34103411
# checks for library functions
34113412
AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
3412-
clock confstr ctermid dup3 execv faccessat fchmod fchmodat fchown fchownat \
3413-
fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
3413+
clock confstr crypt_r ctermid dup3 execv faccessat fchmod fchmodat fchown \
3414+
fchownat fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
34143415
futimens futimes gai_strerror getentropy \
34153416
getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \
34163417
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \

pyconfig.h.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@
140140
/* Define to 1 if you have the `copysign' function. */
141141
#undef HAVE_COPYSIGN
142142

143+
/* Define to 1 if you have the <crypt.h> header file. */
144+
#undef HAVE_CRYPT_H
145+
146+
/* Define to 1 if you have the `crypt_r' function. */
147+
#undef HAVE_CRYPT_R
148+
143149
/* Define to 1 if you have the `ctermid' function. */
144150
#undef HAVE_CTERMID
145151

@@ -547,6 +553,9 @@
547553
/* Define to 1 if you have the `lgamma' function. */
548554
#undef HAVE_LGAMMA
549555

556+
/* Define to 1 if you have the `crypt' library (-lcrypt). */
557+
#undef HAVE_LIBCRYPT
558+
550559
/* Define to 1 if you have the `dl' library (-ldl). */
551560
#undef HAVE_LIBDL
552561

0 commit comments

Comments
 (0)