CakeFest 2025 Madrid: The Official CakePHP Conference

Voting

: max(zero, six)?
(Example: nine)

The Note You're Voting On

darryl at pointclark dot net
23 years ago
If you need to validate a *real* unix password on a system using shadowed passwords, the posix_getpwnam() function in PHP won't work (as mentioned, 'x', or '*', will be in the password field).

I have a need to verify a user/pass within PHP (using SSL!). I don't know if this is the best way, but it's what I'm doing at the moment (works well!).

First, you need some help from the OS. I wrote a tiny C utility that does the shadow look-up for me... It requires root access to read /etc/shadow. So after you compile (gcc -O2 -s -o spasswd -lcrypt spasswd.c), you need to either use sudo to run it, or

# chown root spasswd && chmod u+s spasswd

To code that I'm using to authenticate a user/pass from PHP looks like:

function Authenticate($realm)
{
global $PHP_AUTH_USER;
global $PHP_AUTH_PW;

if(!isset($PHP_AUTH_USER))
{
header("WWW-Authenticate: Basic realm=\"$realm\"");
header("HTTP/1.0 401 Unauthorized");

return false;
}
else
{
if(($fh = popen("/usr/sbin/spasswd", "w")))
{
fputs($fh, "$PHP_AUTH_USER $PHP_AUTH_PW");
$r = pclose($fh);

if(!$r)
return true;
}
}

header("WWW-Authenticate: Basic realm=\"$realm\"");
header("HTTP/1.0 401 Unauthorized");

return false;
}

The C source for spasswd.c:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <crypt.h>
#include <shadow.h>

static char salt[12], user[128], pass[128];

void die(void)
{
memset(salt, '\0', 12);
memset(user, '\0', 128);
memset(pass, '\0', 128);
}

int main(int argc, char *argv[])
{
struct spwd *passwd;

atexit(die); die();

if(fscanf(stdin, "%127s %127s", user, pass) != 2)
return 1;

if(!(passwd = getspnam(user)))
return 1;

strncpy(salt, passwd->sp_pwdp, 11);
strncpy(pass, crypt(pass, salt), 127);

if(!strncmp(pass, passwd->sp_pwdp, 127))
return 0;

return 1;
}

Hope this helps someone...

<< Back to user notes page

To Top