#ifdef I_SHADOW
/* Shadow password support for solaris - pdo@cs.umd.edu
* Not just Solaris: at least HP-UX, IRIX, Linux.
- * the API is from SysV. --jhi */
-#ifdef __hpux__
+ * The API is from SysV.
+ *
+ * There are at least two more shadow interfaces,
+ * see the comments in pp_gpwent().
+ *
+ * --jhi */
+# ifdef __hpux__
/* There is a MAXINT coming from <shadow.h> <- <hpsecurity.h> <- <values.h>
* and another MAXINT from "perl.h" <- <sys/param.h>. */
-#undef MAXINT
-#endif
-#include <shadow.h>
+# undef MAXINT
+# endif
+# include <shadow.h>
#endif
/* XXX If this causes problems, set i_unistd=undef in the hint file. */
#endif
#if !defined(PERL_EFF_ACCESS_R_OK) && defined(HAS_EACCESS)
-# if defined(I_SYS_SECURITY)
+# ifdef I_SYS_SECURITY
# include <sys/security.h>
# endif
# ifdef ACC_SELF
EXTEND(SP, 1);
PERL_FLUSHALL_FOR_CHILD;
childpid = PerlProc_fork();
+ if (childpid == -1)
+ RETSETUNDEF;
PUSHi(childpid);
RETURN;
# else
}
}
PERL_FLUSHALL_FOR_CHILD;
-#if (defined(HAS_FORK) || defined(AMIGAOS)) && !defined(VMS) && !defined(OS2)
+#if (defined(HAS_FORK) || defined(AMIGAOS)) && !defined(VMS) && !defined(OS2) && !defined(__CYGWIN__)
if (PerlProc_pipe(pp) >= 0)
did_pipes = 1;
while ((childpid = vfork()) == -1) {
register SV *sv;
STRLEN n_a;
struct passwd *pwent = NULL;
-/* We do not use HAS_GETSPENT in pp_gpwent() but leave it here in the case
- * somebody wants to write an XS to access the shadow passwords. --jhi */
-# ifdef HAS_GETSPNAM
- struct spwd *spwent = NULL;
-# endif
+ /*
+ * We currently support only the SysV getsp* shadow password interface.
+ * The interface is declared in <shadow.h> and often one needs to link
+ * with -lsecurity or some such.
+ * This interface is used at least by Solaris, HP-UX, IRIX, and Linux.
+ * (and SCO?)
+ *
+ * AIX getpwnam() is clever enough to return the encrypted password
+ * only if the caller (euid?) is root.
+ *
+ * There are at least two other shadow password APIs. Many platforms
+ * seem to contain more than one interface for accessing the shadow
+ * password databases, possibly for compatibility reasons.
+ * The getsp*() is by far he simplest one, the other two interfaces
+ * are much more complicated, but also very similar to each other.
+ *
+ * <sys/types.h>
+ * <sys/security.h>
+ * <prot.h>
+ * struct pr_passwd *getprpw*();
+ * The password is in
+ * char getprpw*(...).ufld.fd_encrypt[]
+ * Mention HAS_GETPRPWNAM here so that Configure probes for it.
+ *
+ * <sys/types.h>
+ * <sys/security.h>
+ * <prot.h>
+ * struct es_passwd *getespw*();
+ * The password is in
+ * char *(getespw*(...).ufld.fd_encrypt)
+ * Mention HAS_GETESPWNAM here so that Configure probes for it.
+ *
+ * Mention I_PROT here so that Configure probes for it.
+ *
+ * In HP-UX for getprpw*() the manual page claims that one should include
+ * <hpsecurity.h> instead of <sys/security.h>, but that is not needed
+ * if one includes <shadow.h> as that includes <hpsecurity.h>,
+ * and pp_sys.c already includes <shadow.h> if there is such.
+ *
+ * Note that <sys/security.h> is already probed for, but currently
+ * it is only included in special cases.
+ *
+ * In Digital UNIX/Tru64 if using the getespw*() (which seems to be
+ * be preferred interface, even though also the getprpw*() interface
+ * is available) one needs to link with -lsecurity -ldb -laud -lm.
+ * One also needs to call set_auth_parameters() in main() before
+ * doing anything else, whether one is using getespw*() or getprpw*().
+ *
+ * Note that accessing the shadow databases can be magnitudes
+ * slower than accessing the standard databases.
+ *
+ * --jhi
+ */
switch (which) {
case OP_GPWNAM:
sv_setpv(sv, pwent->pw_name);
PUSHs(sv = sv_mortalcopy(&PL_sv_no));
+ SvPOK_off(sv);
+ /* If we have getspnam(), we try to dig up the shadow
+ * password. If we are underprivileged, the shadow
+ * interface will set the errno to EACCES or similar,
+ * and return a null pointer. If this happens, we will
+ * use the dummy password (usually "*" or "x") from the
+ * standard password database.
+ *
+ * In theory we could skip the shadow call completely
+ * if euid != 0 but in practice we cannot know which
+ * security measures are guarding the shadow databases
+ * on a random platform.
+ *
+ * Resist the urge to use additional shadow interfaces.
+ * Divert the urge to writing an extension instead.
+ *
+ * --jhi */
# ifdef HAS_GETSPNAM
- spwent = getspnam(pwent->pw_name);
- if (spwent)
- sv_setpv(sv, spwent->sp_pwdp);
- else
- sv_setpv(sv, pwent->pw_passwd);
-# else
- sv_setpv(sv, pwent->pw_passwd);
+ {
+ struct spwd *spwent;
+ int saverrno; /* Save and restore errno so that
+ * underprivileged attempts seem
+ * to have never made the unsccessful
+ * attempt to retrieve the shadow password. */
+
+ saverrno = errno;
+ spwent = getspnam(pwent->pw_name);
+ errno = saverrno;
+ if (spwent && spwent->sp_pwdp)
+ sv_setpv(sv, spwent->sp_pwdp);
+ }
# endif
+ if (!SvPOK(sv)) /* Use the standard password, then. */
+ sv_setpv(sv, pwent->pw_passwd);
+
# ifndef INCOMPLETE_TAINTS
- /* passwd is tainted because user himself can diddle with it. */
+ /* passwd is tainted because user himself can diddle with it.
+ * admittedly not much and in a very limited way, but nevertheless. */
SvTAINTED_on(sv);
# endif
# else
sv_setuv(sv, (UV)pwent->pw_gid);
# endif
- /* pw_change, pw_quota, and pw_age are mutually exclusive. */
+ /* pw_change, pw_quota, and pw_age are mutually exclusive--
+ * because of the poor interface of the Perl getpw*(),
+ * not because there's some standard/convention saying so.
+ * A better interface would have been to return a hash,
+ * but we are accursed by our history, alas. --jhi. */
PUSHs(sv = sv_mortalcopy(&PL_sv_no));
# ifdef PWCHANGE
sv_setiv(sv, (IV)pwent->pw_change);
# endif
# endif
- /* pw_class and pw_comment are mutually exclusive. */
+ /* pw_class and pw_comment are mutually exclusive--.
+ * see the above note for pw_change, pw_quota, and pw_age. */
PUSHs(sv = sv_mortalcopy(&PL_sv_no));
# ifdef PWCLASS
sv_setpv(sv, pwent->pw_class);
djSP;
#if defined(HAS_PASSWD) && defined(HAS_SETPWENT)
setpwent();
-# ifdef HAS_SETSPENT
- setspent();
-# endif
RETPUSHYES;
#else
DIE(aTHX_ PL_no_func, "setpwent");
djSP;
#if defined(HAS_PASSWD) && defined(HAS_ENDPWENT)
endpwent();
-# ifdef HAS_ENDSPENT
- endspent();
-# endif
RETPUSHYES;
#else
DIE(aTHX_ PL_no_func, "endpwent");