| mod_auth_pam.c | mod_auth_pam2.c | |||
|---|---|---|---|---|
|
503 lines 14947 bytes Last modified : Fri Jul 12 08:22:25 2002 |
420 lines 12997 bytes Last modified : Fri Jul 12 08:22:26 2002 |
|||
| 1 | /* Copyright (c) 2000 Ingo Luetkebohle, All rights reserved. | 1 | /* Copyright (c) 2000 Ingo Luetkebohle, All rights reserved. | |
| 2 | * | 2 | * | |
| 3 | * Redistribution and use in source and binary forms, with or without | 3 | * Redistribution and use in source and binary forms, with or without | |
| 4 | * modification, are permitted provided that the following conditions | 4 | * modification, are permitted provided that the following conditions | |
| 5 | * are met: | 5 | * are met: | |
| 6 | * | 6 | * | |
| 7 | * 1. Redistributions of source code must retain the above copyright | 7 | * 1. Redistributions of source code must retain the above copyright | |
| 8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. | |
| 9 | * | 9 | * | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in | 11 | * notice, this list of conditions and the following disclaimer in | |
| 12 | * the documentation and/or other materials provided with the | 12 | * the documentation and/or other materials provided with the | |
| 13 | * distribution. | 13 | * distribution. | |
| 14 | * | 14 | * | |
| 15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | 15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |
| 16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 18 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CODE CONTRIBUTORS | 18 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CODE CONTRIBUTORS | |
| 19 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | 19 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | |
| 20 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT | 20 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT | |
| 21 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | 21 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
| 22 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 22 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
| 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
| 27 | */ | 27 | */ | |
| 28 | 28 | |||
| 29 | /* | 29 | /* $Id$ | |
| 30 | * v 1.1 from 07. July 2002 | 30 | * mod_auth_pam for apache 2.0 | |
| 31 | * | |||
| 32 | * Based on: v 1.1 from 07. July 2002 (for apache 1.3) | |||
| 33 | * | |||
| 31 | * | 34 | * | |
| 32 | * mod_auth_pam: | 35 | * mod_auth_pam: | |
| 33 | * basic authentication against pluggable authentication module lib | 36 | * basic authentication against pluggable authentication module lib | |
| 34 | * | 37 | * | |
| 35 | * The authoritative homepage for this module is at | 38 | * The authoritative homepage for this module is at | |
| 36 | * http://pam.sourceforge.net/ | 39 | * http://pam.sourceforge.net/ | |
| 37 | * | 40 | * | |
| 38 | * For assistance and support, contact the pam-list | 41 | * For assistance and support, contact the pam-list | |
| 39 | * https://listman.redhat.com/mailman/listinfo/pam-list | 42 | * https://listman.redhat.com/mailman/listinfo/pam-list | |
| 40 | * or the Help forum on SourceForge. | 43 | * or the Help forum on SourceForge. | |
| 41 | * | 44 | * | |
| 42 | * Written by Ingo Luetkebohle, based upon mod_auth.c, with contributions | 45 | * Written by Ingo Luetkebohle, based upon mod_auth.c, with contributions | |
| 43 | * from Fredrik Ohrn (group performance), Dirk-Willem van Gulik (licensing | 46 | * from Fredrik Ohrn (group performance), Dirk-Willem van Gulik (licensing | |
| 44 | * consultation) and Michael Johnson (example group implementation). | 47 | * consultation) and Michael Johnson (example group implementation). | |
| 45 | * | 48 | * | |
| 46 | * Thanks to Andrew Morgan and the rest of the Linux-PAM developers who | 49 | * Thanks to Andrew Morgan and the rest of the Linux-PAM developers who | |
| 47 | * provided invaluable development help and ideas. | 50 | * provided invaluable development help and ideas. | |
| 48 | * | 51 | * | |
| 49 | * Changes: | 52 | * Changes: | |
| 53 | * 09-Jul-02: Ported to apache 2.02 (Dirk-Willem van Gulik, | |||
| 54 | * <dirkx@covalent.net>). | |||
| 50 | * 07-Jul-02: License changed to allow redistribution | 55 | * 07-Jul-02: License changed to allow redistribution | |
| 51 | * Performance improvement for group lookup | 56 | * Performance improvement for group lookup | |
| 52 | (many thanks to Fredrik Ohrn for the patch) | 57 | (many thanks to Fredrik Ohrn for the patch) | |
| 53 | * 06-Dec-99: Special casing for Solaris 2.6 added | 58 | * 06-Dec-99: Special casing for Solaris 2.6 added | |
| 54 | * Added versioning message to headers | 59 | * Added versioning message to headers | |
| 55 | * 14-Feb-99: Cleaned up the configuration directives and named them | 60 | * 14-Feb-99: Cleaned up the configuration directives and named them | |
| 56 | * in a more straightforward way | 61 | * in a more straightforward way | |
| 57 | * | 62 | * | |
| 58 | * incorporated getugroups patch from Klaus Wissmann <kw@aw.net> | 63 | * incorporated getugroups patch from Klaus Wissmann <kw@aw.net> | |
| 59 | * to look up supplementary groups from /etc/group | 64 | * to look up supplementary groups from /etc/group | |
| 60 | * | 65 | * | |
| 61 | * 22-Jan-99: incorporated changes from Pavel Kankovsky <kan@dcit.cz> | 66 | * 22-Jan-99: incorporated changes from Pavel Kankovsky <kan@dcit.cz> | |
| 62 | * Enabler configuration directive now called AuthPAM_Enabled | 67 | * Enabler configuration directive now called AuthPAM_Enabled | |
| 63 | * Updated for Apache 1.3.x | 68 | * Updated for Apache 1.3.x | |
| 64 | * 25-Sep-98: replaced pwdb groups routine with standard C | 69 | * 25-Sep-98: replaced pwdb groups routine with standard C | |
| 65 | * 19-Oct-97: made module fall through (if configured to do so), | 70 | * 19-Oct-97: made module fall through (if configured to do so), | |
| 66 | * even when a user of the given name is found in the PAM | 71 | * even when a user of the given name is found in the PAM | |
| 67 | * databases | 72 | * databases | |
| 68 | * 17-Apr-97: fixed segfault that occured when Apache couldn't look | 73 | * 17-Apr-97: fixed segfault that occured when Apache couldn't look | |
| 69 | * up the remote host name | 74 | * up the remote host name | |
| 70 | * removed annoying compiler warnings | 75 | * removed annoying compiler warnings | |
| 71 | * | 76 | * | |
| 72 | * 05-Apr-97: made fall-through configurable with AuthPAM_Authorative | 77 | * 05-Apr-97: made fall-through configurable with AuthPAM_Authorative | |
| 73 | * | 78 | * | |
| 74 | * 25-Mar-97: added support for transparent fall-through to other auth | 79 | * 25-Mar-97: added support for transparent fall-through to other auth | |
| 75 | * modules with configurable fail delays | 80 | * modules with configurable fail delays | |
| 76 | * added acct_mgmt hook | 81 | * added acct_mgmt hook | |
| 77 | * added group support (through libpwdb) | 82 | * added group support (through libpwdb) | |
| 78 | * | 83 | * | |
| 79 | * usage information: | 84 | * usage information: | |
| 80 | * | 85 | * | |
| 81 | * new-style (DSO) | 86 | * new-style (DSO and apache 2.0) | |
| 82 | * | 87 | * | |
| 83 | * compile with | 88 | * compile with | |
| 84 | * apxs -c -lpam mod_auth_pam.c | 89 | * apxs -c -lpam mod_auth_pam.c | |
| 85 | * | 90 | * | |
| 91 | * apxs -I/usr/local/include -L/usr/local/lib -c -lpam mod_auth_pam.c | |||
| 92 | * | |||
| 86 | * install with | 93 | * install with | |
| 87 | * apxs -i -a mod_auth_pam.so | 94 | * apxs -i -a mod_auth_pam.so | |
| 88 | * | 95 | * | |
| 89 | * configure PAM by adding | 96 | * configure PAM by adding | |
| 90 | * /etc/pam.d/httpd | 97 | * /etc/pam.d/httpd | |
| 98 | * | |||
| 91 | * with the appropriate pam modules (for starters, just copy over ftp) | 99 | * with the appropriate pam modules (for starters, just copy over ftp) | |
| 92 | * | 100 | * | |
| 93 | * old-style (from Apache 1.2.x) | 101 | * old-style (from Apache 1.2.x) | |
| 94 | * | 102 | * | |
| 95 | * 1. Configuration: | 103 | * 1. Configuration: | |
| 96 | * Module pam_auth_module mod_auth_pam.o | 104 | * Module pam_auth_module mod_auth_pam.o | |
| 97 | * EXTRA_LIBS+= -lpam -ldl | 105 | * EXTRA_LIBS+= -lpam -ldl | |
| 98 | * | 106 | * | |
| 99 | * 2. Add an auth and an account entry for service type "httpd" | 107 | * 2. Add an auth and an account entry for service type "httpd" | |
| 100 | * to your PAM configuration | 108 | * to your PAM configuration | |
| 101 | * | 109 | * | |
| 102 | * | 110 | * | |
| 103 | * configuration directives: | 111 | * configuration directives: | |
| 104 | * AuthFailDelay <msecs> | 112 | * AuthFailDelay <msecs> | |
| 105 | * number of mili-seconds to wait after a | 113 | * number of mili-seconds to wait after a | |
| 106 | * failed authentication attempt. this is | 114 | * failed authentication attempt. this is | |
| 107 | * a minimum value and may have been | 115 | * a minimum value and may have been | |
| 108 | * increased by other pam apps. | 116 | * increased by other pam apps. | |
| 109 | * defaults to 0 | 117 | * defaults to 0 | |
| 110 | * REQUIRES lib_pam SUPPORT | 118 | * REQUIRES lib_pam SUPPORT | |
| 111 | * | 119 | * | |
| 112 | * AuthPAM_Enabled on|off | 120 | * AuthPAM_Enabled on|off | |
| 113 | * If on, mod_auth_pam will try to authenticate | 121 | * If on, mod_auth_pam will try to authenticate | |
| 114 | * the user. | 122 | * the user. | |
| 115 | * If off, mod_auth_pam will DECLINE immediately | 123 | * If off, mod_auth_pam will DECLINE immediately | |
| 116 | * instead of trying to authenticate the user. | 124 | * instead of trying to authenticate the user. | |
| 117 | * This will make Apache try other modules. | 125 | * This will make Apache try other modules. | |
| 118 | * Defaults to on | 126 | * Defaults to on | |
| 119 | * | 127 | * | |
| 120 | * AuthPAM_FallThrough | 128 | * AuthPAM_FallThrough | |
| 121 | * If on, makes mod_auth_pam DECLINE if it can't | 129 | * If on, makes mod_auth_pam DECLINE if it can't | |
| 122 | * the username, giving other modules a chance. | 130 | * the username, giving other modules a chance. | |
| 123 | * Please note that, if it DOES find the username, | 131 | * Please note that, if it DOES find the username, | |
| 124 | * and the password doesn't match, it will NOT | 132 | * and the password doesn't match, it will NOT | |
| 125 | * fall through but return "access denied" instead | 133 | * fall through but return "access denied" instead | |
| 126 | * Defaults to off | 134 | * Defaults to off | |
| 127 | * | 135 | * | |
| 128 | * AuthPAM_Authorative on|off DEPRECATED | 136 | * AuthPAM_Authorative on|off DEPRECATED | |
| 129 | */ | 137 | */ | |
| 130 | 138 | |||
| 139 | #include <sys/types.h> | |||
| 140 | #include <pwd.h> /* for getpwnam et.al. */ | |||
| 141 | #include <grp.h> /* for getpwnam et.al. */ | |||
| 131 | #include <unistd.h> | 142 | #include <unistd.h> | |
| 132 | 143 | |||
| 144 | #include "ap_config.h" | |||
| 133 | #include "httpd.h" | 145 | #include "httpd.h" | |
| 134 | #include "http_config.h" | 146 | #include "http_config.h" | |
| 135 | #include "http_core.h" | 147 | #include "http_core.h" | |
| 136 | #include "http_log.h" | 148 | #include "http_log.h" | |
| 137 | #include "http_protocol.h" | 149 | #include "http_protocol.h" | |
| 150 | #include "http_request.h" | |||
| 138 | 151 | |||
| 139 | #include <security/pam_appl.h> | 152 | #include <security/pam_appl.h> | |
| 140 | 153 | |||
| 141 | /* change this to 0 on RedHat 4.x */ | 154 | /* change this to 0 on RedHat 4.x */ | |
| 142 | #define PAM_STRE_NEEDS_PAMH 1 | 155 | #define PAM_STRE_NEEDS_PAMH 1 | |
| 143 | #define VERSION "1.0a" | 156 | #define VERSION "1.0a" | |
| 144 | 157 | |||
| 145 | module pam_auth_module; | 158 | module pam_auth_module; | |
| 146 | 159 | |||
| 147 | static const char | 160 | static const char | |
| 148 | *pam_servicename = "httpd", | 161 | *pam_servicename = "httpd", | |
| 149 | *valid_user = "valid-user"; | 162 | *valid_user = "valid-user"; | |
| 150 | 163 | |||
| 151 | typedef struct { | 164 | typedef struct { | |
| 152 | char *name, *pw; | 165 | char *name, *pw; | |
| 153 | } auth_pam_userinfo; | 166 | } auth_pam_userinfo; | |
| 154 | 167 | |||
| 155 | /* | 168 | /* | |
| 156 | * Solaris 2.6.x has a broken conversation function and needs this | 169 | * Solaris 2.6.x has a broken conversation function and needs this | |
| 157 | * as a global variable | 170 | * as a global variable | |
| 158 | * I refused to pollute code for other platforms with this, | 171 | * I refused to pollute code for other platforms with this, | |
| 159 | * so all Solaris 2.6 specific stuff is if'd like the following | 172 | * so all Solaris 2.6 specific stuff is if'd like the following | |
| 160 | */ | 173 | */ | |
| 161 | #if SOLARIS2 == 260 | 174 | #if SOLARIS2 == 260 | |
| 162 | auth_pam_userinfo *global_userinfo; | 175 | auth_pam_userinfo *global_userinfo; | |
| 163 | #endif | 176 | #endif | |
| 164 | 177 | |||
| 165 | /* | 178 | /* | |
| 166 | * the pam_strerror function has different parameters in early PAM | 179 | * the pam_strerror function has different parameters in early PAM | |
| 167 | * versions | 180 | * versions | |
| 168 | */ | 181 | */ | |
| 169 | #ifndef PAM_STRE_NEEDS_PAMH | 182 | #ifndef PAM_STRE_NEEDS_PAMH | |
| 170 | #define compat_pam_strerror(pamh, res) pam_strerror(res) | 183 | #define compat_pam_strerror(pamh, res) pam_strerror(res) | |
| 171 | #else | 184 | #else | |
| 172 | #define compat_pam_strerror(pamh, res) pam_strerror(pamh, res) | 185 | #define compat_pam_strerror(pamh, res) pam_strerror(pamh, res) | |
| 173 | #endif | 186 | #endif | |
| 174 | 187 | |||
| 175 | /* | 188 | /* | |
| 176 | * configuration directive handling | 189 | * configuration directive handling | |
| 177 | */ | 190 | */ | |
| 178 | 191 | |||
| 179 | typedef struct { | 192 | typedef struct { | |
| 180 | int | 193 | int | |
| 181 | fail_delay, /* fail delay in ms -- needs library support */ | 194 | fail_delay, /* fail delay in ms -- needs library support */ | |
| 182 | fall_through, /* 1 to DECLINE instead of AUTH_REQUIRED if we | 195 | fall_through, /* 1 to DECLINE instead of HTTP_UNAUTHORIZEDif we | |
| 183 | can't find the username (defaults to 0) */ | 196 | can't find the username (defaults to 0) */ | |
| 184 | enabled; /* 1 to use mod_auth_pam, 0 otherwise | 197 | enabled; /* 1 to use mod_auth_pam, 0 otherwise | |
| 185 | (defaults to 1) */ | 198 | (defaults to 1) */ | |
| 186 | } auth_pam_dir_config; | 199 | } auth_pam_dir_config; | |
| 187 | 200 | |||
| 188 | void auth_pam_init(server_rec *s, pool *p) | 201 | static | |
| 202 | int auth_pam_init( | |||
| 203 | apr_pool_t *p, | |||
| 204 | apr_pool_t *plog, | |||
| 205 | apr_pool_t *ptemp, | |||
| 206 | server_rec *s | |||
| 207 | ) | |||
| 189 | { | 208 | { | |
| 190 | ap_add_version_component("mod_auth_pam/" VERSION); | 209 | ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,"PAM: mod_auth_pam/" VERSION); | |
| 210 | ||||
| 211 | return OK; | |||
| 191 | } | 212 | } | |
| 192 | 213 | |||
| 193 | static | 214 | static | |
| 194 | void* create_auth_pam_dir_config(pool *p, char *dummy) | 215 | void* create_auth_pam_dir_config(apr_pool_t *p, char *dummy) | |
| 195 | { | 216 | { | |
| 196 | auth_pam_dir_config *new = | 217 | auth_pam_dir_config *new = | |
| 197 | (auth_pam_dir_config*) ap_palloc (p, sizeof(auth_pam_dir_config)); | 218 | (auth_pam_dir_config*) apr_palloc (p, sizeof(auth_pam_dir_config)); | |
| 198 | 219 | |||
| 199 | new->fail_delay = 0; /* 0 ms */ | 220 | new->fail_delay = 0; /* 0 ms */ | |
| 200 | new->fall_through = 0; /* off */ | 221 | new->fall_through = 0; /* off */ | |
| 201 | new->enabled = 1; /* on */ | 222 | new->enabled = 1; /* on */ | |
| 202 | return new; | 223 | return new; | |
| 203 | } | 224 | } | |
| 204 | 225 | |||
| 205 | static | 226 | static command_rec auth_pam_cmds[] = { | |
| 206 | char* auth_fail_delay(cmd_parms *cmd, auth_pam_dir_config *config, char *secs) | |||
| 207 | { | |||
| 208 | if(secs) | |||
| 209 | config->fail_delay = atoi(secs); | |||
| 210 | return NULL; | |||
| 211 | } | |||
| 212 | ||||
| 213 | static | |||
| 214 | char* auth_fall_through(cmd_parms *cmd, auth_pam_dir_config *config, int arg) | |||
| 215 | { | |||
| 216 | config->fall_through = arg; | |||
| 217 | return NULL; | |||
| 218 | } | |||
| 219 | 227 | |||
| 220 | static | 228 | AP_INIT_TAKE1("AuthPAM_FailDelay", | |
| 221 | char* auth_enable(cmd_parms *cmd, auth_pam_dir_config *config, int arg) | 229 | ap_set_string_slot, | |
| 222 | { | 230 | (void *)APR_OFFSETOF(auth_pam_dir_config, fail_delay), | |
| 223 | config->enabled = arg; | 231 | OR_AUTHCFG, | |
| 224 | return NULL; | 232 | "number of micro seconds to wait after failed authentication " | |
| 225 | } | 233 | "attempt. (default is 0.)" ), | |
| 234 | ||||
| 235 | AP_INIT_FLAG("AuthPAM_FallThrough", | |||
| 236 | ap_set_flag_slot, | |||
| 237 | (void *)APR_OFFSETOF(auth_pam_dir_config, fall_through), | |||
| 238 | OR_AUTHCFG, | |||
| 239 | "on|off - determines if other authentication methods are attempted " | |||
| 240 | "if this one fails; (default is off.)"), | |||
| 241 | ||||
| 242 | AP_INIT_FLAG("AuthPAM_Enabled", | |||
| 243 | ap_set_flag_slot, | |||
| 244 | (void *)APR_OFFSETOF(auth_pam_dir_config, enabled), | |||
| 245 | OR_AUTHCFG, | |||
| 246 | "on|off - determines if PAM authentication is enabled; (" | |||
| 247 | "default is on.)" ), | |||
| 226 | 248 | |||
| 227 | static command_rec auth_pam_cmds[] = { | 249 | { NULL } | |
| 228 | { "AuthFailDelay", (const char*(*)())auth_fail_delay, 0, OR_AUTHCFG, TAKE1, | |||
| 229 | "number of micro seconds to wait after failed authentication attempt. defau | |||
| 230 | lt is 0" }, | |||
| 231 | { "AuthPAM_Authorative", (const char*(*)())auth_fall_through, NULL, OR_AUTHCFG, FLAG, | |||
| 232 | "no longer in use -- see AuthPAM_FallThrough instead" }, | |||
| 233 | { "AuthPAM_FallThrough", (const char*(*)())auth_fall_through, NULL, OR_AUTHCFG, FLAG, | |||
| 234 | "on|off - determines if other authentication methods are attempted if this | |||
| 235 | one fails; default is off" }, | |||
| 236 | { "AuthPAM_Enabled", (const char*(*)())auth_enable, NULL, OR_AUTHCFG, FLAG, | |||
| 237 | "on|off - determines if PAM authentication is enabled; default is on" }, | |||
| 238 | { 0 } | |||
| 239 | }; | 250 | }; | |
| 240 | 251 | |||
| 241 | /* | 252 | /* | |
| 242 | * auth_pam_talker: supply authentication information to PAM when asked | 253 | * auth_pam_talker: supply authentication information to PAM when asked | |
| 243 | * | 254 | * | |
| 244 | * Assumptions: | 255 | * Assumptions: | |
| 245 | * A password is asked for by requesting input without echoing | 256 | * A password is asked for by requesting input without echoing | |
| 246 | * A username is asked for by requesting input _with_ echoing | 257 | * A username is asked for by requesting input _with_ echoing | |
| 247 | * | 258 | * | |
| 248 | */ | 259 | */ | |
| 249 | static | 260 | static | |
| 250 | int auth_pam_talker(int num_msg, | 261 | int auth_pam_talker(int num_msg, | |
| 251 | const struct pam_message **msg, | 262 | const struct pam_message **msg, | |
| 252 | struct pam_response **resp, | 263 | struct pam_response **resp, | |
| 253 | void *appdata_ptr) | 264 | void *appdata_ptr) | |
| 254 | { | 265 | { | |
| 255 | unsigned short i = 0; | 266 | unsigned short i = 0; | |
| 256 | auth_pam_userinfo *userinfo = (auth_pam_userinfo*)appdata_ptr; | 267 | auth_pam_userinfo *userinfo = (auth_pam_userinfo*)appdata_ptr; | |
| 257 | struct pam_response *response = 0; | 268 | struct pam_response *response = 0; | |
| 258 | 269 | |||
| 259 | #if SOLARIS2 == 260 | 270 | #if SOLARIS2 == 260 | |
| 260 | if(!userinfo) | 271 | if(!userinfo) | |
| 261 | userinfo = global_userinfo; | 272 | userinfo = global_userinfo; | |
| 262 | /* fprintf(stderr,"%s : %s", userinfo->name, userinfo->pw); */ | 273 | /* fprintf(stderr,"%s : %s", userinfo->name, userinfo->pw); */ | |
| 263 | #endif | 274 | #endif | |
| 264 | 275 | |||
| 265 | /* parameter sanity checking */ | 276 | /* parameter sanity checking */ | |
| 266 | if(!resp || !msg || !userinfo) | 277 | if(!resp || !msg || !userinfo) | |
| 267 | return PAM_CONV_ERR; | 278 | return PAM_CONV_ERR; | |
| 268 | 279 | |||
| 269 | /* allocate memory to store response */ | 280 | /* allocate memory to store response */ | |
| 270 | response = malloc(num_msg * sizeof(struct pam_response)); | 281 | response = malloc(num_msg * sizeof(struct pam_response)); | |
| 271 | if(!response) | 282 | if(!response) | |
| 272 | return PAM_CONV_ERR; | 283 | return PAM_CONV_ERR; | |
| 273 | 284 | |||
| 274 | /* copy values */ | 285 | /* copy values */ | |
| 275 | for(i = 0; i < num_msg; i++) { | 286 | for(i = 0; i < num_msg; i++) { | |
| 276 | /* initialize to safe values */ | 287 | /* initialize to safe values */ | |
| 277 | response[i].resp_retcode = 0; | 288 | response[i].resp_retcode = 0; | |
| 278 | response[i].resp = 0; | 289 | response[i].resp = 0; | |
| 279 | 290 | |||
| 280 | /* select response based on requested output style */ | 291 | /* select response based on requested output style */ | |
| 281 | switch(msg[i]->msg_style) { | 292 | switch(msg[i]->msg_style) { | |
| 282 | case PAM_PROMPT_ECHO_ON: | 293 | case PAM_PROMPT_ECHO_ON: | |
| 283 | /* on memory allocation failure, auth fails */ | 294 | /* on memory allocation failure, auth fails */ | |
| 284 | response[i].resp = strdup(userinfo->name); | 295 | response[i].resp = strdup(userinfo->name); | |
| 285 | break; | 296 | break; | |
| 286 | case PAM_PROMPT_ECHO_OFF: | 297 | case PAM_PROMPT_ECHO_OFF: | |
| 287 | response[i].resp = strdup(userinfo->pw); | 298 | response[i].resp = strdup(userinfo->pw); | |
| 288 | break; | 299 | break; | |
| 289 | default: | 300 | default: | |
| 290 | if(response) | 301 | if(response) | |
| 291 | free(response); | 302 | free(response); | |
| 292 | return PAM_CONV_ERR; | 303 | return PAM_CONV_ERR; | |
| 293 | } | 304 | } | |
| 294 | } | 305 | } | |
| 295 | /* everything okay, set PAM response values */ | 306 | /* everything okay, set PAM response values */ | |
| 296 | *resp = response; | 307 | *resp = response; | |
| 297 | return PAM_SUCCESS; | 308 | return PAM_SUCCESS; | |
| 298 | } | 309 | } | |
| 299 | 310 | |||
| 300 | /* | 311 | /* | |
| 301 | * These functions return 0 if client is OK, and proper error status | 312 | * These functions return 0 if client is OK, and proper error status | |
| 302 | * if not... either AUTH_REQUIRED, if we made a check, and it failed, or | 313 | * if not... either AUTH_REQUIRED, if we made a check, and it failed, or | |
| 303 | * SERVER_ERROR, if things are so totally confused that we couldn't | 314 | * SERVER_ERROR, if things are so totally confused that we couldn't | |
| 304 | * figure out how to tell if the client is authorized or not. | 315 | * figure out how to tell if the client is authorized or not. | |
| 305 | * | 316 | * | |
| 306 | * If they return DECLINED, and all other modules also decline, that's | 317 | * If they return DECLINED, and all other modules also decline, that's | |
| 307 | * treated by the server core as a configuration error, logged and | 318 | * treated by the server core as a configuration error, logged and | |
| 308 | * reported as such. | 319 | * reported as such. | |
| 309 | */ | 320 | */ | |
| 310 | 321 | |||
| 311 | /* | 322 | /* | |
| 312 | * Determine user ID, and check if it really is that user | 323 | * Determine user ID, and check if it really is that user | |
| 313 | */ | 324 | */ | |
| 314 | static | 325 | static | |
| 315 | int pam_auth_basic_user (request_rec *r) | 326 | int pam_auth_basic_user (request_rec *r) | |
| 316 | { | 327 | { | |
| 317 | int res = 0; | 328 | int res = 0; | |
| 318 | /* mod_auth_pam specific */ | 329 | /* mod_auth_pam specific */ | |
| 319 | auth_pam_userinfo userinfo = { NULL, NULL }; | 330 | auth_pam_userinfo userinfo = { NULL, NULL }; | |
| 320 | auth_pam_dir_config *conf = (auth_pam_dir_config*) | 331 | auth_pam_dir_config *conf = (auth_pam_dir_config*) | |
| 321 | ap_get_module_config(r->per_dir_config, &pam_auth_module); | 332 | ap_get_module_config(r->per_dir_config, &pam_auth_module); | |
| 322 | /* PAM specific */ | 333 | /* PAM specific */ | |
| 323 | struct pam_conv conv_info = { &auth_pam_talker, (void*)&userinfo}; | 334 | struct pam_conv conv_info = { &auth_pam_talker, (void*)&userinfo}; | |
| 324 | pam_handle_t *pamh = NULL; | 335 | pam_handle_t *pamh = NULL; | |
| 325 | 336 | |||
| 326 | #if SOLARIS2 == 260 | 337 | #if SOLARIS2 == 260 | |
| 327 | global_userinfo = &userinfo; | 338 | global_userinfo = &userinfo; | |
| 328 | #endif | 339 | #endif | |
| 329 | 340 | |||
| 330 | /* enabled? */ | 341 | /* enabled? */ | |
| 331 | if (!conf->enabled) | 342 | if (!conf->enabled) | |
| 332 | return DECLINED; | 343 | return DECLINED; | |
| 333 | 344 | |||
| 334 | /* read sent pw */ | 345 | /* read sent pw */ | |
| 335 | if ((res = ap_get_basic_auth_pw (r, (const char**)&(userinfo.pw)))) | 346 | if ((res = ap_get_basic_auth_pw (r, (const char**)&(userinfo.pw)))) | |
| 336 | return res; | 347 | return res; | |
| 337 | 348 | |||
| 338 | /* this is only set after get_basic_auth_pw was called */ | 349 | /* this is only set after get_basic_auth_pw was called */ | |
| 339 | userinfo.name = r->connection->user; | 350 | userinfo.name = r->user; | |
| 340 | 351 | |||
| 341 | /* initialize pam */ | 352 | /* initialize pam */ | |
| 342 | if((res = pam_start(pam_servicename, | 353 | if((res = pam_start(pam_servicename, | |
| 343 | userinfo.name, | 354 | userinfo.name, | |
| 344 | &conv_info, | 355 | &conv_info, | |
| 345 | &pamh)) != PAM_SUCCESS) { | 356 | &pamh)) != PAM_SUCCESS) { | |
| 346 | 357 | |||
| 347 | ap_log_reason((char*)compat_pam_strerror(pamh, res), r->uri, r); | 358 | ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "PAM: Could not start pam service: %s",compat_pam_strerror(pamh, res)); | |
| 348 | return DECLINED; | 359 | return DECLINED; | |
| 349 | } | 360 | } | |
| 350 | 361 | |||
| 351 | /* set fail delay */ | 362 | /* set fail delay */ | |
| 352 | #ifdef PAM_FAIL_DELAY | 363 | #ifdef PAM_FAIL_DELAY | |
| 353 | pam_fail_delay(pamh, conf->fail_delay); | 364 | pam_fail_delay(pamh, conf->fail_delay); | |
| 354 | #endif | 365 | #endif | |
| 355 | 366 | |||
| 356 | /* set remote user information */ | 367 | /* set remote user information */ | |
| 357 | /* this seems to cause segfaults in lots of cases -- disabled for now | 368 | /* this seems to cause segfaults in lots of cases -- disabled for now | |
| 358 | pam_set_item(pamh, PAM_USER, userinfo.name); | 369 | pam_set_item(pamh, PAM_USER, userinfo.name); | |
| 359 | pam_set_item(pamh, PAM_RHOST, get_remote_host(r->connection, | 370 | pam_set_item(pamh, PAM_RHOST, get_remote_host(r->connection, | |
| 360 | conf, | 371 | conf, | |
| 361 | REMOTE_NAME)); | 372 | REMOTE_NAME)); | |
| 362 | */ | 373 | */ | |
| 363 | 374 | |||
| 364 | /* try to authenticate user, log error on failure */ | 375 | /* try to authenticate user, log error on failure */ | |
| 365 | if((res = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != | 376 | if((res = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != | |
| 366 | PAM_SUCCESS ) { | 377 | PAM_SUCCESS ) { | |
| 367 | ap_log_reason((char*)compat_pam_strerror(pamh, res), r->uri, r); | 378 | ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, | |
| 379 | "PAM: user '%s' - not authenticated: %s",r->user,compat_pam_strerror(pamh, res)); | |||
| 380 | ||||
| 368 | if(conf->fall_through && (res == PAM_USER_UNKNOWN)) { | 381 | if(conf->fall_through && (res == PAM_USER_UNKNOWN)) { | |
| 369 | /* we don't know about the user, but other auth modules might do */ | 382 | /* we don't know about the user, but other auth modules might do */ | |
| 370 | pam_end(pamh, PAM_SUCCESS); | 383 | pam_end(pamh, PAM_SUCCESS); | |
| 371 | return DECLINED; | 384 | return DECLINED; | |
| 372 | } else { | 385 | } else { | |
| 373 | pam_end(pamh, PAM_SUCCESS); | 386 | pam_end(pamh, PAM_SUCCESS); | |
| 374 | ap_note_basic_auth_failure(r); | 387 | ap_note_basic_auth_failure(r); | |
| 375 | return AUTH_REQUIRED; | 388 | return HTTP_UNAUTHORIZED; | |
| 376 | } /* endif fall_through */ | 389 | } /* endif fall_through */ | |
| 377 | } /* endif authenticate */ | 390 | } /* endif authenticate */ | |
| 378 | 391 | |||
| 379 | /* check that the account is healthy */ | 392 | /* check that the account is healthy */ | |
| 380 | if((res = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { | 393 | if((res = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { | |
| 381 | ap_log_reason((char*)compat_pam_strerror(pamh, res), r->uri, r); | 394 | ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, | |
| 395 | "PAM: user '%s' - invalid account: %s",r->user,compat_pam_strerror(pamh, res)); | |||
| 382 | pam_end(pamh, PAM_SUCCESS); | 396 | pam_end(pamh, PAM_SUCCESS); | |
| 383 | return AUTH_REQUIRED; | 397 | return HTTP_UNAUTHORIZED; | |
| 384 | } | 398 | } | |
| 385 | 399 | |||
| 386 | pam_end(pamh, PAM_SUCCESS); | 400 | pam_end(pamh, PAM_SUCCESS); | |
| 387 | return OK; | 401 | return OK; | |
| 388 | } | 402 | } | |
| 389 | 403 | |||
| 390 | /* | 404 | static void pam_register_hooks(apr_pool_t *p) | |
| 391 | * Look if that user (as authenticated above) is allowed here | 405 | { | |
| 392 | */ | 406 | ap_hook_post_config(auth_pam_init, NULL, NULL, APR_HOOK_MIDDLE); | |
| 393 | 407 | ap_hook_check_user_id(pam_auth_basic_user,NULL,NULL,APR_HOOK_MIDDLE); | ||
| 394 | static | 408 | } | |
| 395 | int pam_check_auth (request_rec *r) | |||
| 396 | { | |||
| 397 | register int i = 0; | |||
| 398 | char method_restricted = 0, *line = 0, *word = 0; | |||
| 399 | auth_pam_dir_config *conf = (auth_pam_dir_config*) | |||
| 400 | ap_get_module_config(r->per_dir_config, &pam_auth_module); | |||
| 401 | ||||
| 402 | char *p_group = NULL; | |||
| 403 | ||||
| 404 | /* check for allowed users/group */ | |||
| 405 | const array_header *reqs_arr = ap_requires (r); | |||
| 406 | require_line *reqs = 0; | |||
| 407 | ||||
| 408 | /* enabled? */ | |||
| 409 | if (!conf->enabled) | |||
| 410 | return DECLINED; | |||
| 411 | ||||
| 412 | /* if any valid user suffices return success */ | |||
| 413 | if (!reqs_arr) | |||
| 414 | return (OK); | |||
| 415 | ||||
| 416 | /* otherwise */ | |||
| 417 | reqs = (require_line*)reqs_arr->elts; | |||
| 418 | ||||
| 419 | /* loop over requirement lines */ | |||
| 420 | for( i = 0; i < reqs_arr->nelts; i++) { | |||
| 421 | /* if method of this requirement matches current method */ | |||
| 422 | if (reqs[i].method_mask & (1 << r->method_number)) { | |||
| 423 | method_restricted = 1; | |||
| 424 | ||||
| 425 | line = reqs[i].requirement; | |||
| 426 | word = ap_getword(r->pool, (const char**)&line, ' '); | |||
| 427 | ||||
| 428 | /* if any user is ok */ | |||
| 429 | if(!strcmp(word, valid_user)) | |||
| 430 | return OK; | |||
| 431 | ||||
| 432 | /* loop over line */ | |||
| 433 | if(!strcmp(word, "user")) { | |||
| 434 | while(*line) { | |||
| 435 | word = ap_getword_conf(r->pool, (const char**)&line); | |||
| 436 | /* if username matches remote username */ | |||
| 437 | if(!strcmp(r->connection->user, word)) | |||
| 438 | /* return success */ | |||
| 439 | return OK; | |||
| 440 | } | |||
| 441 | } /* end if user */ | |||
| 442 | else if(!strcmp(word, "group")) { | |||
| 443 | struct group *grent; | |||
| 444 | char **members; | |||
| 445 | ||||
| 446 | if (!p_group) | |||
| 447 | { | |||
| 448 | struct passwd *pwent; | |||
| 449 | ||||
| 450 | if ((pwent = getpwnam (r->connection->user)) && (grent = getgrgid (pwent->pw_gid))) | |||
| 451 | p_group = grent->gr_name; | |||
| 452 | } | |||
| 453 | ||||
| 454 | while (*line) | |||
| 455 | { | |||
| 456 | word = ap_getword_conf(r->pool, (const char**)&line); | |||
| 457 | ||||
| 458 | if (p_group && !strcmp (p_group, word)) | |||
| 459 | return OK; | |||
| 460 | ||||
| 461 | if ((grent = getgrnam (word)) && grent->gr_mem) | |||
| 462 | { | |||
| 463 | members = grent->gr_mem; | |||
| 464 | ||||
| 465 | while (*members) | |||
| 466 | { | |||
| 467 | if (!strcmp (*members, word)) | |||
| 468 | return OK; | |||
| 469 | ||||
| 470 | members ++; | |||
| 471 | } | |||
| 472 | } | |||
| 473 | } | |||
| 474 | } /* end if group */ | |||
| 475 | } | |||
| 476 | } | |||
| 477 | ||||
| 478 | if (!method_restricted) | |||
| 479 | return OK; | |||
| 480 | ||||
| 481 | ap_note_basic_auth_failure (r); | |||
| 482 | return AUTH_REQUIRED; | |||
| 483 | } | |||
| 484 | 409 | |||
| 485 | module pam_auth_module = { | 410 | module AP_MODULE_DECLARE_DATA pam_auth_module = { | |
| 486 | STANDARD_MODULE_STUFF, | 411 | STANDARD20_MODULE_STUFF, | |
| 487 | auth_pam_init, /* initializer */ | |||
| 488 | create_auth_pam_dir_config, /* dir config creater */ | 412 | create_auth_pam_dir_config, /* dir config creater */ | |
| 489 | NULL, /* dir merger --- default is to override */ | 413 | NULL, /* dir merger --- default is to override */ | |
| 490 | NULL, /* server config */ | 414 | NULL, /* server config */ | |
| 491 | NULL, /* merge server config */ | 415 | NULL, /* merge server config */ | |
| 492 | auth_pam_cmds, /* command table */ | 416 | auth_pam_cmds, /* command table */ | |
| 493 | NULL, /* handlers */ | 417 | pam_register_hooks, /* register hooks */ | |
| 494 | NULL, /* filename translation */ | |||
| 495 | pam_auth_basic_user, /* check_user_id */ | |||
| 496 | pam_check_auth, /* check auth */ | |||
| 497 | NULL, /* check access */ | |||
| 498 | NULL, /* type_checker */ | |||
| 499 | NULL, /* fixups */ | |||
| 500 | NULL /* logger */ | |||
| 501 | }; | 418 | }; | |
| 502 | 419 | |||
| 503 | 420 |