Initial checkin.
This commit is contained in:
commit
0e727788cb
|
@ -0,0 +1,15 @@
|
||||||
|
CC=gcc
|
||||||
|
CFLAGS=-O2 -fPIC -Wall
|
||||||
|
LDFLAGS=-shared -lpam -lldap
|
||||||
|
LD=ld
|
||||||
|
|
||||||
|
all: pam_csc.so
|
||||||
|
|
||||||
|
pam_csc.so: pam_csc.o
|
||||||
|
$(LD) -o $@ $(LDFLAGS) $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f pam_csc.so pam_csc.o
|
||||||
|
|
||||||
|
install:
|
||||||
|
cp pam_csc.so /lib/security/
|
|
@ -0,0 +1,6 @@
|
||||||
|
The Debian Package libpam-csc
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Comments regarding the Package
|
||||||
|
|
||||||
|
-- David Bartley <dtbartle@csclub.uwaterloo.ca> Sun, 24 Jun 2007 23:18:22 -0400
|
|
@ -0,0 +1,6 @@
|
||||||
|
libpam-csc for Debian
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
<possible notes regarding this package - if none, delete this file>
|
||||||
|
|
||||||
|
-- David Bartley <dtbartle@csclub.uwaterloo.ca> Sun, 24 Jun 2007 23:18:22 -0400
|
|
@ -0,0 +1,5 @@
|
||||||
|
libpam-csc (1.0) unstable; urgency=low
|
||||||
|
|
||||||
|
* Initial Release.
|
||||||
|
|
||||||
|
-- David Bartley <dtbartle@csclub.uwaterloo.ca> Sun, 24 Jun 2007 23:18:22 -0400
|
|
@ -0,0 +1 @@
|
||||||
|
5
|
|
@ -0,0 +1,12 @@
|
||||||
|
Source: libpam-csc
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: David Bartley <dtbartle@csclub.uwaterloo.ca>
|
||||||
|
Build-Depends: debhelper (>= 4.0.0), libldap-dev, libpam0g-dev
|
||||||
|
Standards-Version: 3.7.2
|
||||||
|
|
||||||
|
Package: libpam-csc
|
||||||
|
Architecture: any
|
||||||
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
|
Description: Custom CSC PAM module to handle account expiration.
|
||||||
|
Custom CSC PAM module to handle account expiration.
|
|
@ -0,0 +1,26 @@
|
||||||
|
This is libpam-csc, written and maintained by David Bartley <dtbartle@csclub.uwaterloo.ca>
|
||||||
|
on Sun, 24 Jun 2007 23:18:22 -0400.
|
||||||
|
|
||||||
|
The original source can always be found at:
|
||||||
|
ftp://ftp.debian.org/dists/unstable/main/source/
|
||||||
|
|
||||||
|
Copyright Holder: David Bartley
|
||||||
|
|
||||||
|
License:
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this package; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
On Debian systems, the complete text of the GNU General
|
||||||
|
Public License can be found in `/usr/share/common-licenses/GPL'.
|
|
@ -0,0 +1 @@
|
||||||
|
lib/security
|
|
@ -0,0 +1 @@
|
||||||
|
TODO
|
|
@ -0,0 +1,99 @@
|
||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
# Sample debian/rules that uses debhelper.
|
||||||
|
# This file was originally written by Joey Hess and Craig Small.
|
||||||
|
# As a special exception, when this file is copied by dh-make into a
|
||||||
|
# dh-make output file, you may use that output file without restriction.
|
||||||
|
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||||
|
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS = -Wall -g
|
||||||
|
|
||||||
|
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||||
|
CFLAGS += -O0
|
||||||
|
else
|
||||||
|
CFLAGS += -O2
|
||||||
|
endif
|
||||||
|
|
||||||
|
configure: configure-stamp
|
||||||
|
configure-stamp:
|
||||||
|
dh_testdir
|
||||||
|
# Add here commands to configure the package.
|
||||||
|
|
||||||
|
touch configure-stamp
|
||||||
|
|
||||||
|
|
||||||
|
build: build-stamp
|
||||||
|
|
||||||
|
build-stamp: configure-stamp
|
||||||
|
dh_testdir
|
||||||
|
|
||||||
|
# Add here commands to compile the package.
|
||||||
|
$(MAKE)
|
||||||
|
#docbook-to-man debian/libpam-csc.sgml > libpam-csc.1
|
||||||
|
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
rm -f build-stamp configure-stamp
|
||||||
|
|
||||||
|
# Add here commands to clean up after the build process.
|
||||||
|
-$(MAKE) clean
|
||||||
|
|
||||||
|
dh_clean
|
||||||
|
|
||||||
|
install: build-stamp
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_clean -k
|
||||||
|
dh_installdirs
|
||||||
|
install -m 644 pam_csc.so $(CURDIR)/debian/libpam-csc/lib/security
|
||||||
|
|
||||||
|
# Add here commands to install the package into debian/libpam-csc.
|
||||||
|
# $(MAKE) DESTDIR=$(CURDIR)/debian/libpam-csc install
|
||||||
|
|
||||||
|
|
||||||
|
# Build architecture-independent files here.
|
||||||
|
binary-indep: build install
|
||||||
|
# We have nothing to do by default.
|
||||||
|
|
||||||
|
# Build architecture-dependent files here.
|
||||||
|
binary-arch: build install
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_installchangelogs
|
||||||
|
dh_installdocs
|
||||||
|
dh_installexamples
|
||||||
|
# dh_install
|
||||||
|
# dh_installmenu
|
||||||
|
# dh_installdebconf
|
||||||
|
# dh_installlogrotate
|
||||||
|
# dh_installemacsen
|
||||||
|
# dh_installpam
|
||||||
|
# dh_installmime
|
||||||
|
# dh_python
|
||||||
|
# dh_installinit
|
||||||
|
# dh_installcron
|
||||||
|
# dh_installinfo
|
||||||
|
dh_installman
|
||||||
|
dh_link
|
||||||
|
dh_strip
|
||||||
|
dh_compress
|
||||||
|
dh_fixperms
|
||||||
|
# dh_perl
|
||||||
|
# dh_makeshlibs
|
||||||
|
dh_installdeb
|
||||||
|
dh_shlibdeps
|
||||||
|
dh_gencontrol
|
||||||
|
dh_md5sums
|
||||||
|
dh_builddeb
|
||||||
|
|
||||||
|
binary: binary-indep binary-arch
|
||||||
|
.PHONY: build clean binary-indep binary-arch binary install configure
|
|
@ -0,0 +1,239 @@
|
||||||
|
#define PAM_SM_ACCOUNT
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <security/pam_modules.h>
|
||||||
|
#include <security/pam_appl.h>
|
||||||
|
#include <ldap.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
|
#define PAM_CSC_LDAP_URI \
|
||||||
|
"ldap://caffeine.csclub.uwaterloo.ca ldap://perpugilliam.csclub.uwaterloo.ca"
|
||||||
|
#define PAM_CSC_LDAP_USER_BASE_DN "ou=People,dc=csclub,dc=uwaterloo,dc=ca"
|
||||||
|
#define PAM_CSC_LDAP_GROUP_BASE_DN "ou=Group,dc=csclub,dc=uwaterloo,dc=ca"
|
||||||
|
#define PAM_CSC_LDAP_TIMEOUT 5
|
||||||
|
#define PAM_CSC_ALLOWED_GROUPS "cn=staff"
|
||||||
|
#define PAM_CSC_MINIMUM_UID 1000
|
||||||
|
#define PAM_CSC_EXPIRED_MSG \
|
||||||
|
"*****************************************************************************\n" \
|
||||||
|
"* *\n" \
|
||||||
|
"* Your account has expired - please contact the Computer Science Club *\n" \
|
||||||
|
"* *\n" \
|
||||||
|
"*****************************************************************************\n"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* User terms are defined as (3 * year + term) where term is:
|
||||||
|
* 0 = Winter, 1 = Spring, 2 = Fall
|
||||||
|
* Term is a string in the form [f|w|s][year]
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum check_user_type_t
|
||||||
|
{
|
||||||
|
check_user_exists,
|
||||||
|
check_user_cur_term,
|
||||||
|
check_user_prev_term,
|
||||||
|
check_user_groups
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HANDLE_WARN \
|
||||||
|
{ \
|
||||||
|
syslog(LOG_AUTHPRIV | LOG_WARNING, "pam_csc generated a warning on line %d of %s\n", __LINE__, __FILE__); \
|
||||||
|
retval = PAM_SUCCESS; \
|
||||||
|
goto cleanup; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WARN_ZERO(x) \
|
||||||
|
if( (x) == 0 ) HANDLE_WARN
|
||||||
|
|
||||||
|
#define WARN_NEG1(x) \
|
||||||
|
if( (x) == -1 ) HANDLE_WARN
|
||||||
|
|
||||||
|
#define WARN_PAM(x) \
|
||||||
|
if( (x) != PAM_SUCCESS ) HANDLE_WARN
|
||||||
|
|
||||||
|
#define WARN_LDAP(x) \
|
||||||
|
if( (x) != LDAP_SUCCESS ) HANDLE_WARN
|
||||||
|
|
||||||
|
char* escape_ldap_string(const char* src)
|
||||||
|
{
|
||||||
|
char *dst, *dstPtr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!(dst = malloc(2 * strlen(src) + 1)))
|
||||||
|
return NULL;
|
||||||
|
dstPtr = dst;
|
||||||
|
|
||||||
|
for(i = 0; i < strlen(src); i++)
|
||||||
|
{
|
||||||
|
if(src[i] == '*' || src[i] == '(' || src[i] == ')' || src[i] == '\\')
|
||||||
|
{
|
||||||
|
dstPtr[0] = '\\';
|
||||||
|
dstPtr++;
|
||||||
|
}
|
||||||
|
dstPtr[0] = src[i];
|
||||||
|
dstPtr++;
|
||||||
|
}
|
||||||
|
dstPtr[0] = '\0';
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_user(const char* username, enum check_user_type_t checkType)
|
||||||
|
{
|
||||||
|
int retval = PAM_SUCCESS;
|
||||||
|
time_t curTime;
|
||||||
|
struct tm* localTime;
|
||||||
|
int longTerm, year, term;
|
||||||
|
LDAP* ld = NULL;
|
||||||
|
static const char termChars[] = {'w', 's', 'f'};
|
||||||
|
char* usernameEscaped = NULL;
|
||||||
|
char* filter = NULL;
|
||||||
|
char* attr[] = {"objectClass", NULL};
|
||||||
|
struct timeval timeout = {PAM_CSC_LDAP_TIMEOUT, 0};
|
||||||
|
LDAPMessage* res = NULL;
|
||||||
|
char* baseDN = NULL;
|
||||||
|
|
||||||
|
/* fail-safe for root */
|
||||||
|
if(strcmp(username, "root") == 0)
|
||||||
|
{
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* connect and bind */
|
||||||
|
WARN_LDAP( ldap_initialize(&ld, PAM_CSC_LDAP_URI) )
|
||||||
|
WARN_NEG1( ldap_simple_bind(ld, NULL, NULL) )
|
||||||
|
|
||||||
|
WARN_ZERO( usernameEscaped = escape_ldap_string(username) );
|
||||||
|
switch(checkType)
|
||||||
|
{
|
||||||
|
case check_user_exists:
|
||||||
|
|
||||||
|
/* format filter */
|
||||||
|
WARN_ZERO( filter = malloc(50 + strlen(usernameEscaped)) )
|
||||||
|
sprintf(filter, "(uid=%s)", usernameEscaped);
|
||||||
|
baseDN = PAM_CSC_LDAP_USER_BASE_DN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case check_user_prev_term:
|
||||||
|
case check_user_cur_term:
|
||||||
|
|
||||||
|
/* get term info and compute current and previous term */
|
||||||
|
WARN_NEG1( curTime = time(NULL) )
|
||||||
|
WARN_ZERO( localTime = localtime(&curTime) )
|
||||||
|
longTerm = 3 * (1900 + localTime->tm_year) + (localTime->tm_mon / 4);
|
||||||
|
if(checkType == check_user_prev_term)
|
||||||
|
longTerm--;
|
||||||
|
term = termChars[longTerm % 3];
|
||||||
|
year = longTerm / 3;
|
||||||
|
|
||||||
|
/* format filter */
|
||||||
|
WARN_ZERO( filter = malloc(100 + strlen(usernameEscaped)) )
|
||||||
|
sprintf(filter, "(&(uid=%s)(|(&(objectClass=member)(term=%c%d))(!(objectClass=member))))",
|
||||||
|
usernameEscaped, term, year);
|
||||||
|
baseDN = PAM_CSC_LDAP_USER_BASE_DN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case check_user_groups:
|
||||||
|
|
||||||
|
/* format filter */
|
||||||
|
WARN_ZERO( filter = malloc(50 + strlen(PAM_CSC_ALLOWED_GROUPS) + strlen(usernameEscaped)) )
|
||||||
|
sprintf(filter, "(&(objectClass=posixGroup)(%s)(memberUid=%s))", PAM_CSC_ALLOWED_GROUPS, usernameEscaped);
|
||||||
|
baseDN = PAM_CSC_LDAP_GROUP_BASE_DN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* search */
|
||||||
|
WARN_LDAP( ldap_search_st(ld, baseDN, LDAP_SCOPE_SUBTREE, filter, attr, 1, &timeout, &res) )
|
||||||
|
if((term = ldap_count_entries(ld, res)) == 0)
|
||||||
|
retval = PAM_AUTH_ERR;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
if(usernameEscaped) free(usernameEscaped);
|
||||||
|
if(res) ldap_msgfree(res);
|
||||||
|
if(filter) free(filter);
|
||||||
|
if(ld) ldap_unbind(ld);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int print_pam_message(pam_handle_t* pamh, char* msg, int style)
|
||||||
|
{
|
||||||
|
int retval = PAM_SUCCESS;
|
||||||
|
struct pam_conv* pamConv;
|
||||||
|
struct pam_message pamMessage;
|
||||||
|
struct pam_message* pamMessages[1];
|
||||||
|
struct pam_response* pamResponse;
|
||||||
|
|
||||||
|
/* output message */
|
||||||
|
WARN_PAM( pam_get_item(pamh, PAM_CONV, (const void**)&pamConv) )
|
||||||
|
pamMessages[0] = &pamMessage;
|
||||||
|
pamMessage.msg_style = style;
|
||||||
|
pamMessage.msg = msg;
|
||||||
|
WARN_PAM( pamConv->conv(1, (const struct pam_message**)pamMessages,
|
||||||
|
&pamResponse, pamConv->appdata_ptr) )
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char* argv[])
|
||||||
|
{
|
||||||
|
const char* username;
|
||||||
|
struct passwd* pwd;
|
||||||
|
|
||||||
|
/* determine username */
|
||||||
|
if((pam_get_user(pamh, &username, NULL) != PAM_SUCCESS) || !username)
|
||||||
|
{
|
||||||
|
return PAM_USER_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check uid */
|
||||||
|
pwd = getpwnam(username);
|
||||||
|
if(pwd && pwd->pw_uid < PAM_CSC_MINIMUM_UID)
|
||||||
|
{
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if user exists in ldap */
|
||||||
|
if(check_user(username, check_user_exists) == PAM_AUTH_ERR)
|
||||||
|
{
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if user is registered for the current term */
|
||||||
|
if(check_user(username, check_user_cur_term) == PAM_SUCCESS)
|
||||||
|
{
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if user is registered for the previous term */
|
||||||
|
if(check_user(username, check_user_prev_term) == PAM_SUCCESS)
|
||||||
|
{
|
||||||
|
/* show warning */
|
||||||
|
syslog(LOG_AUTHPRIV | LOG_NOTICE, "(pam_csc): %s was not registered for current term but was registered for previous term - permitting login\n", username);
|
||||||
|
print_pam_message(pamh, PAM_CSC_EXPIRED_MSG, PAM_TEXT_INFO);
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if user is in allowed groups */
|
||||||
|
if(check_user(username, check_user_groups) == PAM_SUCCESS)
|
||||||
|
{
|
||||||
|
/* show warning */
|
||||||
|
print_pam_message(pamh, PAM_CSC_EXPIRED_MSG, PAM_TEXT_INFO);
|
||||||
|
syslog(LOG_AUTHPRIV | LOG_NOTICE, "(pam_csc): %s was not registered but was in allowed groups - permitting login\n", username);
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* account has expired - show prompt */
|
||||||
|
print_pam_message(pamh, PAM_CSC_EXPIRED_MSG, PAM_ERROR_MSG);
|
||||||
|
syslog(LOG_AUTHPRIV | LOG_NOTICE, "(pam_csc): %s was not registered and was not in allowed groups - denying login\n", username);
|
||||||
|
|
||||||
|
return PAM_AUTH_ERR;
|
||||||
|
}
|
Loading…
Reference in New Issue