├── .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 |
--------------------------------------------------------------------------------