├── .gitignore ├── CREDITS ├── LICENSE ├── README ├── config.m4 ├── package.xml ├── pam.c ├── pam.stub.php ├── pam_arginfo.h ├── pam_legacy_arginfo.h └── php_pam.h /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | *.lo 3 | *.la 4 | .libs 5 | acinclude.m4 6 | aclocal.m4 7 | autom4te.cache 8 | build 9 | config.guess 10 | config.h 11 | config.h.in 12 | config.log 13 | config.nice 14 | config.status 15 | config.sub 16 | configure 17 | configure.ac 18 | include 19 | install-sh 20 | libtool 21 | ltmain.sh 22 | Makefile 23 | Makefile.fragments 24 | Makefile.global 25 | Makefile.objects 26 | missing 27 | mkinstalldirs 28 | modules 29 | run-tests.php 30 | tests/*/*.diff 31 | tests/*/*.out 32 | tests/*/*.php 33 | tests/*/*.exp 34 | tests/*/*.log 35 | tests/*/*.sh 36 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | PAM 2 | Mikael Johansson 3 | Chad Cunningham 4 | Amish 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------- 2 | The PHP License, version 3.01 3 | Copyright (c) 1999 - 2019 The PHP Group. All rights reserved. 4 | -------------------------------------------------------------------- 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, is permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | 3. The name "PHP" must not be used to endorse or promote products 19 | derived from this software without prior written permission. For 20 | written permission, please contact group@php.net. 21 | 22 | 4. Products derived from this software may not be called "PHP", nor 23 | may "PHP" appear in their name, without prior written permission 24 | from group@php.net. You may indicate that your software works in 25 | conjunction with PHP by saying "Foo for PHP" instead of calling 26 | it "PHP Foo" or "phpfoo" 27 | 28 | 5. The PHP Group may publish revised and/or new versions of the 29 | license from time to time. Each version will be given a 30 | distinguishing version number. 31 | Once covered code has been published under a particular version 32 | of the license, you may always continue to use it under the terms 33 | of that version. You may also choose to use such covered code 34 | under the terms of any subsequent version of the license 35 | published by the PHP Group. No one other than the PHP Group has 36 | the right to modify the terms applicable to covered code created 37 | under this License. 38 | 39 | 6. Redistributions of any form whatsoever must retain the following 40 | acknowledgment: 41 | "This product includes PHP software, freely available from 42 | ". 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND 45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP 48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55 | OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | -------------------------------------------------------------------- 58 | 59 | This software consists of voluntary contributions made by many 60 | individuals on behalf of the PHP Group. 61 | 62 | The PHP Group can be contacted via Email at group@php.net. 63 | 64 | For more information on the PHP Group and the PHP project, 65 | please see . 66 | 67 | PHP includes the Zend Engine, freely available at 68 | . 69 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | API 2 | 3 | bool pam_auth(string $username, string $password 4 | [, string &$error [, $checkacctmgmt = true [, string $servicename ] ] ]) 5 | bool pam_chpass(string $username, string $oldpassword, string $newpassword 6 | [, string &$error [, string $servicename ] ]) 7 | 8 | The parameters are 9 | 10 | username - Username to check 11 | password - User supplied password 12 | error - Output parameter to put any error messages in 13 | checkacctmgmt - Call pam_acct_mgmt() to check account expiration and access hours (requires root access!) 14 | servicename - PAM service name to use (provided pam.force_servicename is not TRUE) 15 | oldpassword - Current password on account 16 | newpassword - Password to change to 17 | 18 | INSTALLATION 19 | 20 | For pam_auth and pam_chpass to work, module must know about the PAM service to use. 21 | 22 | By default, the PAM service is set to "php". It can be changed by adding the following 23 | to your php.ini: 24 | 25 | pam.servicename = "your-pam-service"; 26 | 27 | Service name can also be, optionally, passed as a parameter to pam_auth OR pam_chpass. 28 | 29 | You can inform the module to ignore the service name passed as a parameter and use 30 | pam.servicename only, by adding the following to your php.ini: 31 | 32 | pam.force_servicename = 1; 33 | 34 | Next, you'll need to create a pam service file for php. If you are on linux, 35 | you'll need to create the file /etc/pam.d/php. You can copy another one to work 36 | off of (/etc/pam.d/login is a good choice). 37 | 38 | Some examples that should work: 39 | 40 | on linux: 41 | 42 | # /etc/pam.d/php 43 | # 44 | # note: both an auth and account entry are required 45 | 46 | auth sufficient /lib/security/pam_pwdb.so shadow nodelay 47 | account sufficient /lib/security/pam_pwdb.so 48 | 49 | on solaris: 50 | 51 | # add to /etc/pam.conf 52 | 53 | php auth requisite /usr/lib/security/pam_authtok_get.so.1 54 | php auth required /usr/lib/security/pam_unix_auth.so.1 55 | php account required /usr/lib/security/pam_unix_account.so.1 56 | 57 | These would authenticate out of the unix password and shadow file. However 58 | please checking other /etc/pam.d/ entries, as the libraries these examples 59 | point to may not be correct. 60 | 61 | 62 | FAQ 63 | 64 | * What is PAM? 65 | 66 | PAM stands for Pluggable Authentication Module. It is a system that abstracts 67 | user authentication to allow arbitrary modules to handle the real work. In this 68 | way, pam enabled services can use a variety of complex authentication schemes 69 | without modifying the applications. For more Information, and available 70 | modules, see http://www.kernel.org/pub/linux/libs/pam/. 71 | 72 | 73 | * Why would I want to use PAM from PHP? 74 | 75 | PAM gives you very flexible control over authentication. As an example, there 76 | are PAM modules that will authenticate against a local shadow or password file, 77 | a Windows NT domain, an SQL database, LDAP, Kerberos, Radius, and more. In 78 | addition, pam modules can give you the ability to have restrictions on the 79 | authentication, such as the pam_tally module which limits the number of login 80 | attempts, and the pam_listfile which let's you restrict access to a list of 81 | users. Please note, using pam does not mean you can securely authenticate 82 | users, it simply gives you the ability to do so with proper configuration and 83 | planning. 84 | 85 | 86 | * How can I get pam? 87 | 88 | If you are running linux or solaris, you already have it! Linux and Solaris 89 | both natively use pam for all authentication, so you're are all set. If you are 90 | on other systems, well, you're on your own. I have no idea what PAM has been 91 | ported too... 92 | 93 | 94 | * I'm getting an Authentication Failure error, why? 95 | 96 | Try setting the $checkacctmgmt parameter to false to skip the pam_acct_mgmt() 97 | call, note that this only checks the password and skips performing account 98 | validation such as account expiration and access. Otherwise see below. 99 | 100 | The most likely reason for this is that you are trying to authenticate via a 101 | local shadow file and you do not have permission to do so. The PAM modules 102 | handling shadow authentication (used on Linux and Solaris) require that the 103 | application have permission to read the shadow file (makes sense, eh?). If you 104 | are running php as a cgi or as a webserver module, it is executed as your 105 | webservers user and group. 106 | 107 | By default, most Linux and Solaris systems are configured to only allow the root 108 | user to read the shadow file. The recommended 109 | way around this is to change permissions on the shadow file so that it is group 110 | readable, and chgrp the file to the a group that the webserver is in. Before 111 | doing this, you should give it some serious thought as allowing your webserver 112 | to read the shadow file gives hackers another way to crack away at your system. 113 | 114 | If you decide to enable this, I stronly suggest usage of the pam_tally module 115 | to limit failed logins to a reasonable number of attempts, and one of the other 116 | modules which will allow you to block root and other system users. 117 | 118 | 119 | * The pam_auth function doesn't return anything, whattup? 120 | 121 | Did you remember to create an entry in the pam configuration for the php 122 | service? 123 | 124 | 125 | * Logs indicate pam authenticated the user, but the function doesn't return 126 | true, what gives? 127 | 128 | Make sure your pam configuration has an entry for both auth and account, if you 129 | do not have both, it will not work. 130 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension pam 3 | 4 | dnl Check PHP version: 5 | AC_MSG_CHECKING(PHP version) 6 | if test ! -z "$phpincludedir"; then 7 | PHP_VERSION=`grep 'PHP_VERSION ' $phpincludedir/main/php_version.h | sed -e 's/.*"\([[0-9\.]]*\)".*/\1/g' 2>/dev/null` 8 | elif test ! -z "$PHP_CONFIG"; then 9 | PHP_VERSION=`$PHP_CONFIG --version 2>/dev/null` 10 | fi 11 | 12 | if test x"$PHP_VERSION" = "x"; then 13 | AC_MSG_WARN([none]) 14 | else 15 | PHP_MAJOR_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/g' 2>/dev/null` 16 | PHP_MINOR_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/g' 2>/dev/null` 17 | PHP_RELEASE_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/g' 2>/dev/null` 18 | AC_MSG_RESULT([$PHP_VERSION]) 19 | fi 20 | 21 | if test $PHP_MAJOR_VERSION -lt 7; then 22 | AC_MSG_ERROR([need at least PHP 7 or newer]) 23 | fi 24 | 25 | PHP_ARG_WITH(pam, for PAM support, 26 | [ --with-pam[=DIR] Include PAM support. DIR is the libpam install prefix]) 27 | 28 | if test "$PHP_PAM" != "no"; then 29 | SEARCH_PATH="/usr/local /usr" # you might want to change this 30 | SEARCH_FOR="/include/security/pam_appl.h" # you most likely want to change this 31 | if test -r $PHP_PAM/$SEARCH_FOR; then # path given as parameter 32 | PAM_DIR=$PHP_PAM 33 | else # search default path list 34 | AC_MSG_CHECKING([for PAM files in default path]) 35 | for i in $SEARCH_PATH ; do 36 | if test -r $i/$SEARCH_FOR; then 37 | PAM_DIR=$i 38 | AC_MSG_RESULT(found in $i) 39 | fi 40 | done 41 | fi 42 | 43 | if test -z "$PAM_DIR"; then 44 | AC_MSG_RESULT([not found]) 45 | AC_MSG_ERROR([install the PAM library or use --with-pam=DIR to specify the location]) 46 | fi 47 | 48 | PHP_ADD_INCLUDE($PAM_DIR/include) 49 | 50 | LIBNAME=pam # you may want to change this 51 | LIBSYMBOL=pam_start # you most likely want to change this 52 | 53 | PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, 54 | [ 55 | PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $PAM_DIR/$PHP_LIBDIR, PAM_SHARED_LIBADD) 56 | AC_DEFINE(HAVE_PAM,1,[ ]) 57 | ],[ 58 | AC_MSG_ERROR([wrong PAM lib version or lib not found]) 59 | ],[ 60 | -L$PAM_DIR/$PHP_LIBDIR -lm 61 | ]) 62 | 63 | PHP_SUBST(PAM_SHARED_LIBADD) 64 | 65 | PHP_NEW_EXTENSION(pam, pam.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) 66 | fi 67 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | pam 4 | pecl.php.net 5 | PAM integration 6 | This extension provides PAM (Pluggable Authentication Modules) integration. PAM is a system of libraries that handle the authentication tasks of applications and services. The library provides a stable API for applications to defer to for authentication tasks. 7 | 8 | Amish M 9 | anonamish 10 | anonamish AT gmail DOT com 11 | yes 12 | 13 | 2023-09-22 14 | 15 | 2.2.5 16 | 2.2.0 17 | 18 | 19 | stable 20 | stable 21 | 22 | PHP 23 | 24 | Remove PAM_DISALLOW_NULL_AUTHTOK from pam_chauthtok() 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 7.3.0 43 | 44 | 45 | 1.10 46 | 47 | 48 | 49 | pam 50 | 51 | 52 | 53 | 2023-09-22 54 | 55 | 56 | 2.2.5 57 | 2.2.5 58 | 59 | 60 | stable 61 | stable 62 | 63 | PHP 64 | 65 | Remove PAM_DISALLOW_NULL_AUTHTOK from pam_chauthtok() 66 | 67 | 68 | 69 | 2022-01-19 70 | 71 | 72 | 2.2.4 73 | 2.2.4 74 | 75 | 76 | stable 77 | stable 78 | 79 | PHP 80 | 81 | Update TSRMLS_CACHE in RINIT_FUNCTION and MINIT_FUNCTION 82 | 83 | 84 | 85 | 2021-06-08 86 | 87 | 88 | 2.2.3 89 | 2.2.3 90 | 91 | 92 | stable 93 | stable 94 | 95 | PHP 96 | 97 | Fix minimum version of php and pear installer 98 | 99 | 100 | 101 | 2021-06-07 102 | 103 | 104 | 2.2.2 105 | 2.2.2 106 | 107 | 108 | stable 109 | stable 110 | 111 | PHP 112 | 113 | Add missing globals init and other minor fixes 114 | 115 | 116 | 117 | 2021-01-30 118 | 119 | 120 | 2.2.1 121 | 2.2.1 122 | 123 | 124 | stable 125 | stable 126 | 127 | PHP 128 | 129 | Allow to call pam_auth() and pam_chpass() with a different PAM service name, at runtime 130 | Introduce new php.ini boolean pam.force_servicename to force to always use pam.servicename 131 | Optimize a bit and fix rare case memory leak 132 | Fix status parameter passing by reference 133 | Remove TSRMLS_* for php 8 134 | Fix PHP_PAM_VERSION 135 | 136 | 137 | 138 | 2009-11-05 139 | 140 | 141 | 1.0.2 142 | 1.0.2 143 | 144 | 145 | stable 146 | stable 147 | 148 | PHP 149 | 150 | Added PAM_RHOST param to facilitate RHOST auth (using $_SERVER['REMOTE_ADDR']) 151 | 152 | 153 | 154 | 155 | 1.0.1 156 | 1.0.1 157 | 158 | 159 | stable 160 | stable 161 | 162 | 2007-09-22 163 | PHP 164 | 165 | Error messages specify which pam_* function failed 166 | Fixed build on lib64 type systems 167 | 168 | 169 | 170 | 171 | 1.0.0 172 | 1.0.0 173 | 174 | 175 | stable 176 | stable 177 | 178 | 2006-11-13 179 | PHP 180 | 181 | Initial PECL release 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /pam.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Copyright (c) The PHP Group | 4 | +----------------------------------------------------------------------+ 5 | | This source file is subject to version 3.01 of the PHP license, | 6 | | that is bundled with this package in the file LICENSE, and is | 7 | | available through the world-wide-web at the following url: | 8 | | http://www.php.net/license/3_01.txt | 9 | | If you did not receive a copy of the PHP license and are unable to | 10 | | obtain it through the world-wide-web, please send a note to | 11 | | license@php.net so we can mail you a copy immediately. | 12 | +----------------------------------------------------------------------+ 13 | | Authors: Amish | 14 | | PHP 4.0: Mikael Johansson | 15 | | Chad Cunningham | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifdef HAVE_CONFIG_H 20 | #include "config.h" 21 | #endif 22 | 23 | #include "php.h" 24 | #include "php_ini.h" 25 | #include "ext/standard/info.h" 26 | #include "php_pam.h" 27 | #include 28 | #include 29 | 30 | #if PHP_VERSION_ID < 80000 31 | #include "pam_legacy_arginfo.h" 32 | #else 33 | #include "pam_arginfo.h" 34 | #endif 35 | 36 | ZEND_DECLARE_MODULE_GLOBALS(pam) 37 | 38 | /* True global resources - no need for thread safety here */ 39 | static int le_pam; 40 | 41 | /* {{{ PHP_INI 42 | */ 43 | PHP_INI_BEGIN() 44 | STD_PHP_INI_ENTRY("pam.servicename", "php", PHP_INI_ALL, OnUpdateString, servicename, zend_pam_globals, pam_globals) 45 | STD_PHP_INI_BOOLEAN("pam.force_servicename", "0", PHP_INI_ALL, OnUpdateBool, force_servicename, zend_pam_globals, pam_globals) 46 | PHP_INI_END() 47 | /* }}} */ 48 | 49 | /* {{{ auth_pam_talker: supply authentication information to PAM when asked 50 | * 51 | * Assumptions: 52 | * A password is asked for by requesting input without echoing 53 | * A username is asked for by requesting input _with_ echoing 54 | * 55 | */ 56 | static 57 | int auth_pam_talker(int num_msg, 58 | const struct pam_message ** msg, 59 | struct pam_response ** resp, 60 | void *appdata_ptr) 61 | { 62 | unsigned short i = 0; 63 | pam_auth_t *userinfo = (pam_auth_t *) appdata_ptr; 64 | struct pam_response *response = NULL; 65 | 66 | /* parameter sanity checking */ 67 | if (!resp || !msg || !userinfo) 68 | return PAM_CONV_ERR; 69 | 70 | /* allocate memory to store response */ 71 | response = malloc(num_msg * sizeof(struct pam_response)); 72 | if (!response) 73 | return PAM_CONV_ERR; 74 | 75 | /* copy values */ 76 | for (i = 0; i < num_msg; ++i) { 77 | /* initialize to safe values */ 78 | response[i].resp_retcode = 0; 79 | response[i].resp = NULL; 80 | 81 | /* select response based on requested output style */ 82 | switch (msg[i]->msg_style) { 83 | case PAM_PROMPT_ECHO_ON: 84 | /* on memory allocation failure, auth fails */ 85 | response[i].resp = strdup(userinfo->name); 86 | break; 87 | case PAM_PROMPT_ECHO_OFF: 88 | response[i].resp = strdup(userinfo->pw); 89 | break; 90 | default: 91 | _pam_drop_reply(response, i); 92 | return PAM_CONV_ERR; 93 | } 94 | } 95 | /* everything okay, set PAM response values */ 96 | *resp = response; 97 | return PAM_SUCCESS; 98 | } 99 | /* }}} */ 100 | 101 | /* {{{ chpass_pam_talker: supply authentication information to PAM when asked 102 | * 103 | * Assumptions: 104 | * A password is asked for by requesting input without echoing 105 | * A username is asked for by requesting input _with_ echoing 106 | * 107 | */ 108 | static 109 | int chpass_pam_talker(int num_msg, 110 | const struct pam_message ** msg, 111 | struct pam_response ** resp, 112 | void *appdata_ptr) 113 | { 114 | unsigned short i = 0; 115 | pam_chpass_t *userinfo = (pam_chpass_t *) appdata_ptr; 116 | struct pam_response *response = NULL; 117 | 118 | /* parameter sanity checking */ 119 | if (!resp || !msg || !userinfo) 120 | return PAM_CONV_ERR; 121 | 122 | /* allocate memory to store response */ 123 | response = malloc(num_msg * sizeof(struct pam_response)); 124 | if (!response) 125 | return PAM_CONV_ERR; 126 | 127 | /* copy values */ 128 | for (i = 0; i < num_msg; ++i) { 129 | /* initialize to safe values */ 130 | response[i].resp_retcode = 0; 131 | response[i].resp = NULL; 132 | 133 | /* select response based on requested output style */ 134 | switch (msg[i]->msg_style) { 135 | case PAM_PROMPT_ECHO_ON: 136 | /* on memory allocation failure, auth fails */ 137 | response[i].resp = strdup(userinfo->name); 138 | break; 139 | case PAM_PROMPT_ECHO_OFF: 140 | response[i].resp = strdup((userinfo->count++) ? userinfo->newpw : userinfo->oldpw); 141 | break; 142 | default: 143 | _pam_drop_reply(response, i); 144 | return PAM_CONV_ERR; 145 | } 146 | } 147 | /* everything okay, set PAM response values */ 148 | *resp = response; 149 | return PAM_SUCCESS; 150 | } 151 | /* }}} */ 152 | 153 | /* {{{ proto bool pam_auth( string username, string password [, string &status [, bool checkacctmgmt = true [, string servicename ] ] ]) 154 | Authenticates a user and returns TRUE on success, FALSE on failure */ 155 | PHP_FUNCTION(pam_auth) 156 | { 157 | char *username, *password, *srvname = NULL; 158 | size_t username_len, password_len, srvname_len = 0; 159 | zval *status = NULL, *server, *remote_addr; 160 | zend_bool checkacctmgmt = 1; 161 | 162 | pam_auth_t userinfo = {NULL, NULL}; 163 | struct pam_conv conv_info = {&auth_pam_talker, (void *) &userinfo}; 164 | pam_handle_t *pamh = NULL; 165 | int result; 166 | char *error_msg; 167 | 168 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|z/bs", &username, &username_len, &password, &password_len, &status, &checkacctmgmt, &srvname, &srvname_len) == FAILURE) { 169 | RETURN_FALSE; 170 | } 171 | 172 | userinfo.name = username; 173 | userinfo.pw = password; 174 | 175 | if ((result = pam_start((PAM_G(force_servicename) || !srvname || srvname_len < 1 || !srvname[0]) ? PAM_G(servicename) : srvname, userinfo.name, &conv_info, &pamh)) != PAM_SUCCESS) { 176 | if (status) { 177 | spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_start"); 178 | zval_dtor(status); 179 | ZVAL_STRING(status, error_msg); 180 | efree(error_msg); 181 | } 182 | RETURN_FALSE; 183 | } 184 | 185 | if ((server = zend_hash_str_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER")-1)) != NULL && Z_TYPE_P(server) == IS_ARRAY) { 186 | if ((remote_addr = zend_hash_str_find(Z_ARRVAL_P(server), "REMOTE_ADDR", sizeof("REMOTE_ADDR")-1)) != NULL && Z_TYPE_P(remote_addr) == IS_STRING) { 187 | pam_set_item(pamh, PAM_RHOST, Z_STRVAL_P(remote_addr)); 188 | } 189 | } 190 | 191 | if ((result = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { 192 | if (status) { 193 | spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_authenticate"); 194 | zval_dtor(status); 195 | ZVAL_STRING(status, error_msg); 196 | efree(error_msg); 197 | } 198 | pam_end(pamh, PAM_SUCCESS); 199 | RETURN_FALSE; 200 | } 201 | 202 | if (checkacctmgmt) { 203 | if ((result = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { 204 | if (status) { 205 | spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_acct_mgmt"); 206 | zval_dtor(status); 207 | ZVAL_STRING(status, error_msg); 208 | efree(error_msg); 209 | } 210 | pam_end(pamh, PAM_SUCCESS); 211 | RETURN_FALSE; 212 | } 213 | } 214 | 215 | pam_end(pamh, PAM_SUCCESS); 216 | RETURN_TRUE; 217 | } 218 | /* }}} */ 219 | 220 | /* {{{ proto bool pam_chpass( string username, string oldpassword, string newpassword [, string &status [, string servicename ] ]) 221 | Changes a users password and returns TRUE on success, FALSE on failure */ 222 | PHP_FUNCTION(pam_chpass) 223 | { 224 | char *username, *oldpass, *newpass, *srvname = NULL; 225 | size_t username_len, oldpass_len, newpass_len, srvname_len = 0; 226 | zval *status = NULL; 227 | 228 | pam_chpass_t userinfo = {NULL, NULL, NULL, 0}; 229 | struct pam_conv conv_info = {&chpass_pam_talker, (void *) &userinfo}; 230 | pam_handle_t *pamh = NULL; 231 | int result; 232 | char *error_msg; 233 | 234 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|z/s", &username, &username_len, &oldpass, &oldpass_len, &newpass, &newpass_len, &status, &srvname, &srvname_len) == FAILURE) { 235 | RETURN_FALSE; 236 | } 237 | 238 | userinfo.name = username; 239 | userinfo.oldpw = oldpass; 240 | userinfo.newpw = newpass; 241 | 242 | if ((result = pam_start((PAM_G(force_servicename) || !srvname || srvname_len < 1 || !srvname[0]) ? PAM_G(servicename) : srvname, userinfo.name, &conv_info, &pamh)) != PAM_SUCCESS) { 243 | if (status) { 244 | spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_start"); 245 | zval_dtor(status); 246 | ZVAL_STRING(status, error_msg); 247 | efree(error_msg); 248 | } 249 | RETURN_FALSE; 250 | } 251 | 252 | if ((result = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { 253 | if (status) { 254 | spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_authenticate"); 255 | zval_dtor(status); 256 | ZVAL_STRING(status, error_msg); 257 | efree(error_msg); 258 | } 259 | pam_end(pamh, PAM_SUCCESS); 260 | RETURN_FALSE; 261 | } 262 | 263 | if ((result = pam_chauthtok(pamh, 0)) != PAM_SUCCESS) { 264 | if (status) { 265 | spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_chauthtok"); 266 | zval_dtor(status); 267 | ZVAL_STRING(status, error_msg); 268 | efree(error_msg); 269 | } 270 | pam_end(pamh, PAM_SUCCESS); 271 | RETURN_FALSE; 272 | } 273 | 274 | pam_end(pamh, PAM_SUCCESS); 275 | RETURN_TRUE; 276 | } 277 | /* }}} */ 278 | 279 | /* {{{ php_pam_init_globals 280 | */ 281 | static void php_pam_init_globals(zend_pam_globals *pam_globals) 282 | { 283 | pam_globals->servicename = NULL; 284 | pam_globals->force_servicename = 0; 285 | } 286 | /* }}} */ 287 | 288 | /* {{{ PHP_MINIT_FUNCTION 289 | */ 290 | PHP_MINIT_FUNCTION(pam) 291 | { 292 | #if defined(ZTS) && defined(COMPILE_DL_PAM) 293 | ZEND_TSRMLS_CACHE_UPDATE(); 294 | #endif 295 | ZEND_INIT_MODULE_GLOBALS(pam, php_pam_init_globals, NULL); 296 | REGISTER_INI_ENTRIES(); 297 | return SUCCESS; 298 | } 299 | /* }}} */ 300 | 301 | /* {{{ PHP_MSHUTDOWN_FUNCTION 302 | */ 303 | PHP_MSHUTDOWN_FUNCTION(pam) 304 | { 305 | UNREGISTER_INI_ENTRIES(); 306 | return SUCCESS; 307 | } 308 | /* }}} */ 309 | 310 | /* {{{ PHP_RINIT_FUNCTION 311 | */ 312 | PHP_RINIT_FUNCTION(pam) 313 | { 314 | #if defined(ZTS) && defined(COMPILE_DL_PAM) 315 | ZEND_TSRMLS_CACHE_UPDATE(); 316 | #endif 317 | return SUCCESS; 318 | } 319 | /* }}} */ 320 | 321 | /* {{{ PHP_MINFO_FUNCTION 322 | */ 323 | PHP_MINFO_FUNCTION(pam) 324 | { 325 | php_info_print_table_start(); 326 | php_info_print_table_header(2, "PAM support", "enabled"); 327 | php_info_print_table_row(2, "Extension version", PHP_PAM_VERSION); 328 | php_info_print_table_end(); 329 | 330 | DISPLAY_INI_ENTRIES(); 331 | } 332 | /* }}} */ 333 | 334 | /* {{{ pam_module_entry 335 | */ 336 | zend_module_entry pam_module_entry = { 337 | STANDARD_MODULE_HEADER, 338 | "pam", 339 | ext_functions, 340 | PHP_MINIT(pam), 341 | PHP_MSHUTDOWN(pam), 342 | PHP_RINIT(pam), 343 | NULL, /* Replace with NULL if there's nothing to do at request end */ 344 | PHP_MINFO(pam), 345 | PHP_PAM_VERSION, 346 | STANDARD_MODULE_PROPERTIES 347 | }; 348 | /* }}} */ 349 | 350 | #ifdef COMPILE_DL_PAM 351 | #ifdef ZTS 352 | ZEND_TSRMLS_CACHE_DEFINE() 353 | #endif 354 | ZEND_GET_MODULE(pam) 355 | #endif 356 | 357 | /* 358 | * Local variables: 359 | * tab-width: 4 360 | * c-basic-offset: 4 361 | * End: 362 | * vim600: noet sw=4 ts=4 fdm=marker 363 | * vim<600: noet sw=4 ts=4 364 | */ 365 | -------------------------------------------------------------------------------- /pam.stub.php: -------------------------------------------------------------------------------- 1 | | 15 | | Chad Cunningham | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef PHP_PAM_H 20 | #define PHP_PAM_H 21 | 22 | extern zend_module_entry pam_module_entry; 23 | #define phpext_pam_ptr &pam_module_entry 24 | 25 | #define PHP_PAM_VERSION "2.2.5" 26 | 27 | #ifdef PHP_WIN32 28 | # define PHP_PAM_API __declspec(dllexport) 29 | #elif defined(__GNUC__) && __GNUC__ >= 4 30 | # define PHP_PAM_API __attribute__ ((visibility("default"))) 31 | #else 32 | # define PHP_PAM_API 33 | #endif 34 | 35 | #ifdef ZTS 36 | #include "TSRM.h" 37 | #endif 38 | 39 | ZEND_BEGIN_MODULE_GLOBALS(pam) 40 | char *servicename; 41 | zend_bool force_servicename; 42 | ZEND_END_MODULE_GLOBALS(pam) 43 | 44 | typedef struct { 45 | char *name, *pw; 46 | } pam_auth_t; 47 | 48 | typedef struct { 49 | char *name, *oldpw, *newpw; 50 | int count; 51 | } pam_chpass_t; 52 | 53 | #define PAM_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(pam, v) 54 | 55 | #if defined(ZTS) && defined(COMPILE_DL_PAM) 56 | ZEND_TSRMLS_CACHE_EXTERN() 57 | #endif 58 | 59 | #endif /* PHP_PAM_H */ 60 | 61 | 62 | /* 63 | * Local variables: 64 | * tab-width: 4 65 | * c-basic-offset: 4 66 | * End: 67 | * vim600: noet sw=4 ts=4 fdm=marker 68 | * vim<600: noet sw=4 ts=4 69 | */ 70 | --------------------------------------------------------------------------------