summaryrefslogtreecommitdiff
path: root/modules/pam_time
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2000-06-20 22:10:38 +0000
committerAndrew G. Morgan <morgan@kernel.org>2000-06-20 22:10:38 +0000
commitea488580c42e8918445a945484de3c8a5addc761 (patch)
treec992f3ba699caafedfadc16af38e6359c3c24698 /modules/pam_time
Initial revision
Diffstat (limited to 'modules/pam_time')
-rw-r--r--modules/pam_time/.cvsignore1
-rw-r--r--modules/pam_time/Makefile98
-rw-r--r--modules/pam_time/README43
-rwxr-xr-xmodules/pam_time/install_conf46
-rw-r--r--modules/pam_time/pam_time.c612
-rw-r--r--modules/pam_time/time.conf64
6 files changed, 864 insertions, 0 deletions
diff --git a/modules/pam_time/.cvsignore b/modules/pam_time/.cvsignore
new file mode 100644
index 00000000..380a834a
--- /dev/null
+++ b/modules/pam_time/.cvsignore
@@ -0,0 +1 @@
+dynamic
diff --git a/modules/pam_time/Makefile b/modules/pam_time/Makefile
new file mode 100644
index 00000000..03105bb1
--- /dev/null
+++ b/modules/pam_time/Makefile
@@ -0,0 +1,98 @@
+#
+# $Id$
+#
+# This Makefile controls a build process of $(TITLE) module for
+# Linux-PAM. You should not modify this Makefile (unless you know
+# what you are doing!).
+#
+# Created by Andrew Morgan <morgan@linux.kernel.org> 1996/6/11
+#
+
+TITLE=pam_time
+CONFD=$(CONFIGED)/security
+export CONFD
+CONFILE=$(CONFD)/time.conf
+export CONFILE
+
+#
+
+LIBSRC = $(TITLE).c
+LIBOBJ = $(TITLE).o
+LIBOBJD = $(addprefix dynamic/,$(LIBOBJ))
+LIBOBJS = $(addprefix static/,$(LIBOBJ))
+
+DEFS=-DCONFILE=\"$(CONFILE)\"
+
+CFLAGS += $(DEFS)
+
+dynamic/%.o : %.c
+ $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+static/%.o : %.c
+ $(CC) $(CFLAGS) $(STATIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+
+ifdef DYNAMIC
+LIBSHARED = $(TITLE).so
+endif
+ifdef STATIC
+LIBSTATIC = lib$(TITLE).o
+endif
+
+####################### don't edit below #######################
+
+dummy:
+ @echo "**** This is not a top-level Makefile "
+ exit
+
+all: dirs $(LIBSHARED) $(LIBSTATIC) register
+
+dirs:
+ifdef DYNAMIC
+ $(MKDIR) ./dynamic
+endif
+ifdef STATIC
+ $(MKDIR) ./static
+endif
+
+register:
+ifdef STATIC
+ ( cd .. ; ./register_static $(TITLE) $(TITLE)/$(LIBSTATIC) )
+endif
+
+ifdef DYNAMIC
+$(LIBOBJD): $(LIBSRC)
+
+$(LIBSHARED): $(LIBOBJD)
+ $(LD_D) -o $@ $(LIBOBJD)
+endif
+
+ifdef STATIC
+$(LIBOBJS): $(LIBSRC)
+
+$(LIBSTATIC): $(LIBOBJS)
+ $(LD) -r -o $@ $(LIBOBJS)
+endif
+
+install: all
+ifdef DYNAMIC
+ $(MKDIR) $(FAKEROOT)$(SECUREDIR)
+ $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR)
+endif
+ $(MKDIR) $(FAKEROOT)$(SCONFIGED)
+ bash -f ./install_conf
+
+remove:
+ rm -f $(FAKEROOT)$(SECUREDIR)/$(TITLE).so
+ rm -f $(FAKEROOT)$(CONFILE)
+
+clean:
+ rm -f $(LIBOBJD) $(LIBOBJS) core *~
+ rm -f ./.ignore_age
+
+extraclean: clean
+ rm -f *.a *.o *.so *.bak
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
diff --git a/modules/pam_time/README b/modules/pam_time/README
new file mode 100644
index 00000000..dcbe35e4
--- /dev/null
+++ b/modules/pam_time/README
@@ -0,0 +1,43 @@
+$Id$
+
+This is a help file for the pam_time module. It explains the need for
+pam_time and also the syntax of the /etc/security/time.conf file.
+[a lot of the syntax is freely adapted from the porttime file of the
+shadow suite.]
+
+1. Introduction
+===============
+
+It is desirable to restrict access to a system and or specific
+applications at various times of the day and on specific days or over
+various terminal lines.
+
+The pam_time module is intended to offer a configurable module that
+satisfies this purpose, within the context of Linux-PAM.
+
+2. the /etc/security/time.conf file
+===================================
+
+This file is the configuration script for defining time/port access
+control to the system/applications.
+
+Its syntax is described in the sample ./time.conf provided in this
+directory.
+
+unrecognised rules are ignored (but an error is logged to syslog(3))
+
+--------------------
+Bugs to Andrew <morgan@parc.power.net> or the list <pam-list@redhat.com>
+
+########################################################################
+# $Log$
+# Revision 1.1 2000/06/20 22:12:00 agmorgan
+# Initial revision
+#
+# Revision 1.1.1.1 1998/07/12 05:17:16 morgan
+# Linux PAM sources pre-0.66
+#
+# Revision 1.3 1997/01/04 20:42:43 morgan
+# I want email on parc now
+#
+# \ No newline at end of file
diff --git a/modules/pam_time/install_conf b/modules/pam_time/install_conf
new file mode 100755
index 00000000..051d8b70
--- /dev/null
+++ b/modules/pam_time/install_conf
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+CONFILE=$FAKEROOT"$CONFILE"
+IGNORE_AGE=./.ignore_age
+QUIET_INSTALL=../../.quiet_install
+CONF=./time.conf
+MODULE=pam_time
+
+echo
+
+if [ -f "$QUIET_INSTALL" ]; then
+ if [ ! -f "$CONFILE" ]; then
+ yes="y"
+ else
+ yes="skip"
+ fi
+elif [ -f "$IGNORE_AGE" ]; then
+ echo "you don't want to be bothered with the age of your $CONFILE file"
+ yes="n"
+elif [ ! -f "$CONFILE" ] || [ "$CONF" -nt "$CONFILE" ]; then
+ if [ -f "$CONFILE" ]; then
+ echo "An older $MODULE configuration file already exists ($CONFILE)"
+ echo "Do you wish to copy the $CONF file in this distribution"
+ echo "to $CONFILE ? (y/n) [skip] "
+ read yes
+ else
+ yes="y"
+ fi
+else
+ yes="skip"
+fi
+
+if [ "$yes" = "y" ]; then
+ mkdir -p $FAKEROOT$CONFD
+ echo " copying $CONF to $CONFILE"
+ cp $CONF $CONFILE
+else
+ echo " Skipping $CONF installation"
+ if [ "$yes" = "n" ]; then
+ touch "$IGNORE_AGE"
+ fi
+fi
+
+echo
+
+exit 0
diff --git a/modules/pam_time/pam_time.c b/modules/pam_time/pam_time.c
new file mode 100644
index 00000000..2ca51859
--- /dev/null
+++ b/modules/pam_time/pam_time.c
@@ -0,0 +1,612 @@
+/* pam_time module */
+
+/*
+ * $Id$
+ *
+ * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/6/22
+ * (File syntax and much other inspiration from the shadow package
+ * shadow-960129)
+ */
+
+const static char rcsid[] =
+"$Id$;\n"
+"\t\tVersion 0.22 for Linux-PAM\n"
+"Copyright (C) Andrew G. Morgan 1996 <morgan@linux.kernel.org>\n";
+
+#ifdef linux
+# define _GNU_SOURCE
+# include <features.h>
+#endif
+
+#include <sys/file.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define PAM_TIME_CONF CONFILE /* from external define */
+#define PAM_TIME_BUFLEN 1000
+#define FIELD_SEPARATOR ';' /* this is new as of .02 */
+
+typedef enum { FALSE, TRUE } boolean;
+typedef enum { AND, OR } operator;
+
+/*
+ * here, we make definitions for the externally accessible functions
+ * in this file (these definitions are required for static modules
+ * but strongly encouraged generally) they are used to instruct the
+ * modules include file to define their prototypes.
+ */
+
+#define PAM_SM_ACCOUNT
+
+#include <security/_pam_macros.h>
+#include <security/pam_modules.h>
+
+/* --- static functions for checking whether the user should be let in --- */
+
+static void _log_err(const char *format, ... )
+{
+ va_list args;
+
+ va_start(args, format);
+ openlog("pam_time", LOG_CONS|LOG_PID, LOG_AUTH);
+ vsyslog(LOG_CRIT, format, args);
+ va_end(args);
+ closelog();
+}
+
+static void shift_bytes(char *mem, int from, int by)
+{
+ while (by-- > 0) {
+ *mem = mem[from];
+ ++mem;
+ }
+}
+
+static int read_field(int fd, char **buf, int *from, int *to)
+{
+ /* is buf set ? */
+
+ if (! *buf) {
+ *buf = (char *) malloc(PAM_TIME_BUFLEN);
+ if (! *buf) {
+ _log_err("out of memory");
+ D(("no memory"));
+ return -1;
+ }
+ *from = *to = 0;
+ fd = open(PAM_TIME_CONF, O_RDONLY);
+ }
+
+ /* do we have a file open ? return error */
+
+ if (fd < 0 && *to <= 0) {
+ _log_err( PAM_TIME_CONF " not opened");
+ memset(*buf, 0, PAM_TIME_BUFLEN);
+ _pam_drop(*buf);
+ return -1;
+ }
+
+ /* check if there was a newline last time */
+
+ if ((*to > *from) && (*to > 0)
+ && ((*buf)[*from] == '\0')) { /* previous line ended */
+ (*from)++;
+ (*buf)[0] = '\0';
+ return fd;
+ }
+
+ /* ready for more data: first shift the buffer's remaining data */
+
+ *to -= *from;
+ shift_bytes(*buf, *from, *to);
+ *from = 0;
+ (*buf)[*to] = '\0';
+
+ while (fd >= 0 && *to < PAM_TIME_BUFLEN) {
+ int i;
+
+ /* now try to fill the remainder of the buffer */
+
+ i = read(fd, *to + *buf, PAM_TIME_BUFLEN - *to);
+ if (i < 0) {
+ _log_err("error reading " PAM_TIME_CONF);
+ return -1;
+ } else if (!i) {
+ close(fd);
+ fd = -1; /* end of file reached */
+ } else
+ *to += i;
+
+ /*
+ * contract the buffer. Delete any comments, and replace all
+ * multiple spaces with single commas
+ */
+
+ i = 0;
+#ifdef DEBUG_DUMP
+ D(("buffer=<%s>",*buf));
+#endif
+ while (i < *to) {
+ if ((*buf)[i] == ',') {
+ int j;
+
+ for (j=++i; j<*to && (*buf)[j] == ','; ++j);
+ if (j!=i) {
+ shift_bytes(i + (*buf), j-i, (*to) - j);
+ *to -= j-i;
+ }
+ }
+ switch ((*buf)[i]) {
+ int j,c;
+ case '#':
+ for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j);
+ if (j >= *to) {
+ (*buf)[*to = ++i] = '\0';
+ } else if (c == '\n') {
+ shift_bytes(i + (*buf), j-i, (*to) - j);
+ *to -= j-i;
+ ++i;
+ } else {
+ _log_err("internal error in " __FILE__
+ " at line %d", __LINE__ );
+ return -1;
+ }
+ break;
+ case '\\':
+ if ((*buf)[i+1] == '\n') {
+ shift_bytes(i + *buf, 2, *to - (i+2));
+ *to -= 2;
+ }
+ break;
+ case '!':
+ case ' ':
+ case '\t':
+ if ((*buf)[i] != '!')
+ (*buf)[i] = ',';
+ /* delete any trailing spaces */
+ for (j=++i; j < *to && ( (c = (*buf)[j]) == ' '
+ || c == '\t' ); ++j);
+ shift_bytes(i + *buf, j-i, (*to)-j );
+ *to -= j-i;
+ break;
+ default:
+ ++i;
+ }
+ }
+ }
+
+ (*buf)[*to] = '\0';
+
+ /* now return the next field (set the from/to markers) */
+ {
+ int i;
+
+ for (i=0; i<*to; ++i) {
+ switch ((*buf)[i]) {
+ case '#':
+ case '\n': /* end of the line/file */
+ (*buf)[i] = '\0';
+ *from = i;
+ return fd;
+ case FIELD_SEPARATOR: /* end of the field */
+ (*buf)[i] = '\0';
+ *from = ++i;
+ return fd;
+ }
+ }
+ *from = i;
+ (*buf)[*from] = '\0';
+ }
+
+ if (*to <= 0) {
+ D(("[end of text]"));
+ *buf = NULL;
+ }
+
+ return fd;
+}
+
+/* read a member from a field */
+
+static int logic_member(const char *string, int *at)
+{
+ int len,c,to;
+ int done=0;
+ int token=0;
+
+ len=0;
+ to=*at;
+ do {
+ c = string[to++];
+
+ switch (c) {
+
+ case '\0':
+ --to;
+ done = 1;
+ break;
+
+ case '&':
+ case '|':
+ case '!':
+ if (token) {
+ --to;
+ }
+ done = 1;
+ break;
+
+ default:
+ if (isalpha(c) || c == '*' || isdigit(c) || c == '_'
+ || c == '-' || c == '.') {
+ token = 1;
+ } else if (token) {
+ --to;
+ done = 1;
+ } else {
+ ++*at;
+ }
+ }
+ } while (!done);
+
+ return to - *at;
+}
+
+typedef enum { VAL, OP } expect;
+
+static boolean logic_field(const void *me, const char *x, int rule,
+ boolean (*agrees)(const void *, const char *
+ , int, int))
+{
+ boolean left=FALSE, right, not=FALSE;
+ operator oper=OR;
+ int at=0, l;
+ expect next=VAL;
+
+ while ((l = logic_member(x,&at))) {
+ int c = x[at];
+
+ if (next == VAL) {
+ if (c == '!')
+ not = !not;
+ else if (isalpha(c) || c == '*') {
+ right = not ^ agrees(me, x+at, l, rule);
+ if (oper == AND)
+ left &= right;
+ else
+ left |= right;
+ next = OP;
+ } else {
+ _log_err("garbled syntax; expected name (rule #%d)", rule);
+ return FALSE;
+ }
+ } else { /* OP */
+ switch (c) {
+ case '&':
+ oper = AND;
+ break;
+ case '|':
+ oper = OR;
+ break;
+ default:
+ _log_err("garbled syntax; expected & or | (rule #%d)"
+ , rule);
+ D(("%c at %d",c,at));
+ return FALSE;
+ }
+ next = VAL;
+ }
+ at += l;
+ }
+
+ return left;
+}
+
+static boolean is_same(const void *A, const char *b, int len, int rule)
+{
+ int i;
+ const char *a;
+
+ a = A;
+ for (i=0; len > 0; ++i, --len) {
+ if (b[i] != a[i]) {
+ if (b[i++] == '*') {
+ return (!--len || !strncmp(b+i,a+strlen(a)-len,len));
+ } else
+ return FALSE;
+ }
+ }
+ return ( !len );
+}
+
+typedef struct {
+ int day; /* array of 7 bits, one set for today */
+ int minute; /* integer, hour*100+minute for now */
+} TIME;
+
+struct day {
+ const char *d;
+ int bit;
+} static const days[11] = {
+ { "su", 01 },
+ { "mo", 02 },
+ { "tu", 04 },
+ { "we", 010 },
+ { "th", 020 },
+ { "fr", 040 },
+ { "sa", 0100 },
+ { "wk", 076 },
+ { "wd", 0101 },
+ { "al", 0177 },
+ { NULL, 0 }
+};
+
+static TIME time_now(void)
+{
+ struct tm *local;
+ time_t the_time;
+ TIME this;
+
+ the_time = time((time_t *)0); /* get the current time */
+ local = localtime(&the_time);
+ this.day = days[local->tm_wday].bit;
+ this.minute = local->tm_hour*100 + local->tm_min;
+
+ D(("day: 0%o, time: %.4d", this.day, this.minute));
+ return this;
+}
+
+/* take the current date and see if the range "date" passes it */
+static boolean check_time(const void *AT, const char *times, int len, int rule)
+{
+ boolean not,pass;
+ int marked_day, time_start, time_end;
+ const TIME *at;
+ int i,j=0;
+
+ at = AT;
+ D(("chcking: 0%o/%.4d vs. %s", at->day, at->minute, times));
+
+ if (times == NULL) {
+ /* this should not happen */
+ _log_err("internal error: " __FILE__ " line %d", __LINE__);
+ return FALSE;
+ }
+
+ if (times[j] == '!') {
+ ++j;
+ not = TRUE;
+ } else {
+ not = FALSE;
+ }
+
+ for (marked_day = 0; len > 0 && isalpha(times[j]); --len) {
+ int this_day=-1;
+
+ D(("%c%c ?", times[j], times[j+1]));
+ for (i=0; days[i].d != NULL; ++i) {
+ if (tolower(times[j]) == days[i].d[0]
+ && tolower(times[j+1]) == days[i].d[1] ) {
+ this_day = days[i].bit;
+ break;
+ }
+ }
+ j += 2;
+ if (this_day == -1) {
+ _log_err("bad day specified (rule #%d)", rule);
+ return FALSE;
+ }
+ marked_day ^= this_day;
+ }
+ if (marked_day == 0) {
+ _log_err("no day specified");
+ return FALSE;
+ }
+ D(("day range = 0%o", marked_day));
+
+ time_start = 0;
+ for (i=0; len > 0 && i < 4 && isdigit(times[i+j]); ++i, --len) {
+ time_start *= 10;
+ time_start += times[i+j]-'0'; /* is this portable? */
+ }
+ j += i;
+
+ if (times[j] == '-') {
+ time_end = 0;
+ for (i=1; len > 0 && i < 5 && isdigit(times[i+j]); ++i, --len) {
+ time_end *= 10;
+ time_end += times[i+j]-'0'; /* is this portable */
+ }
+ j += i;
+ } else
+ time_end = -1;
+
+ D(("i=%d, time_end=%d, times[j]='%c'", i, time_end, times[j]));
+ if (i != 5 || time_end == -1) {
+ _log_err("no/bad times specified (rule #%d)", rule);
+ return TRUE;
+ }
+ D(("times(%d to %d)", time_start,time_end));
+ D(("marked_day = 0%o", marked_day));
+
+ /* compare with the actual time now */
+
+ pass = FALSE;
+ if (time_start < time_end) { /* start < end ? --> same day */
+ if ((at->day & marked_day) && (at->minute >= time_start)
+ && (at->minute < time_end)) {
+ D(("time is listed"));
+ pass = TRUE;
+ }
+ } else { /* spans two days */
+ if ((at->day & marked_day) && (at->minute >= time_start)) {
+ D(("caught on first day"));
+ pass = TRUE;
+ } else {
+ marked_day <<= 1;
+ marked_day |= (marked_day & 0200) ? 1:0;
+ D(("next day = 0%o", marked_day));
+ if ((at->day & marked_day) && (at->minute <= time_end)) {
+ D(("caught on second day"));
+ pass = TRUE;
+ }
+ }
+ }
+
+ return (not ^ pass);
+}
+
+static int check_account(const char *service
+ , const char *tty, const char *user)
+{
+ int from=0,to=0,fd=-1;
+ char *buffer=NULL;
+ int count=0;
+ TIME here_and_now;
+ int retval=PAM_SUCCESS;
+
+ here_and_now = time_now(); /* find current time */
+ do {
+ boolean good=TRUE,intime;
+
+ /* here we get the service name field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+
+ if (!buffer || !buffer[0]) {
+ /* empty line .. ? */
+ continue;
+ }
+ ++count;
+
+ good = logic_field(service, buffer, count, is_same);
+ D(("with service: %s", good ? "passes":"fails" ));
+
+ /* here we get the terminal name field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_TIME_CONF "; no tty entry #%d", count);
+ continue;
+ }
+ good &= logic_field(tty, buffer, count, is_same);
+ D(("with tty: %s", good ? "passes":"fails" ));
+
+ /* here we get the username field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_TIME_CONF "; no user entry #%d", count);
+ continue;
+ }
+ good &= logic_field(user, buffer, count, is_same);
+ D(("with user: %s", good ? "passes":"fails" ));
+
+ /* here we get the time field */
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (!buffer || !buffer[0]) {
+ _log_err(PAM_TIME_CONF "; no time entry #%d", count);
+ continue;
+ }
+
+ intime = logic_field(&here_and_now, buffer, count, check_time);
+ D(("with time: %s", intime ? "passes":"fails" ));
+
+ fd = read_field(fd,&buffer,&from,&to);
+ if (buffer && buffer[0]) {
+ _log_err(PAM_TIME_CONF "; poorly terminated rule #%d", count);
+ continue;
+ }
+
+ if (good && !intime) {
+ /*
+ * for security parse whole file.. also need to ensure
+ * that the buffer is free()'d and the file is closed.
+ */
+ retval = PAM_PERM_DENIED;
+ } else {
+ D(("rule passed"));
+ }
+ } while (buffer);
+
+ return retval;
+}
+
+/* --- public account management functions --- */
+
+PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc
+ ,const char **argv)
+{
+ const char *service=NULL, *tty=NULL;
+ const char *user=NULL;
+
+ /* set service name */
+
+ if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service)
+ != PAM_SUCCESS || service == NULL) {
+ _log_err("cannot find the current service name");
+ return PAM_ABORT;
+ }
+
+ /* set username */
+
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL
+ || *user == '\0') {
+ _log_err("cannot determine the user's name");
+ return PAM_USER_UNKNOWN;
+ }
+
+ /* set tty name */
+
+ if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS
+ || tty == NULL) {
+ D(("PAM_TTY not set, probing stdin"));
+ tty = ttyname(STDIN_FILENO);
+ if (tty == NULL) {
+ _log_err("couldn't get the tty name");
+ return PAM_ABORT;
+ }
+ if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) {
+ _log_err("couldn't set tty name");
+ return PAM_ABORT;
+ }
+ }
+
+ if (strncmp("/dev/",tty,5) == 0) { /* strip leading /dev/ */
+ tty += 5;
+ }
+
+ /* good, now we have the service name, the user and the terminal name */
+
+ D(("service=%s", service));
+ D(("user=%s", user));
+ D(("tty=%s", tty));
+
+ return check_account(service,tty,user);
+}
+
+/* end of module definition */
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_time_modstruct = {
+ "pam_time",
+ NULL,
+ NULL,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
diff --git a/modules/pam_time/time.conf b/modules/pam_time/time.conf
new file mode 100644
index 00000000..d2062fdb
--- /dev/null
+++ b/modules/pam_time/time.conf
@@ -0,0 +1,64 @@
+# this is an example configuration file for the pam_time module. Its syntax
+# was initially based heavily on that of the shadow package (shadow-960129).
+#
+# the syntax of the lines is as follows:
+#
+# services;ttys;users;times
+#
+# white space is ignored and lines maybe extended with '\\n' (escaped
+# newlines). As should be clear from reading these comments,
+# text following a '#' is ignored to the end of the line.
+#
+# the combination of individual users/terminals etc is a logic list
+# namely individual tokens that are optionally prefixed with '!' (logical
+# not) and separated with '&' (logical and) and '|' (logical or).
+#
+# services
+# is a logic list of PAM service names that the rule applies to.
+#
+# ttys
+# is a logic list of terminal names that this rule applies to.
+#
+# users
+# is a logic list of users to whom this rule applies.
+#
+# NB. For these items the simple wildcard '*' may be used only once.
+#
+# times
+# the format here is a logic list of day/time-range
+# entries the days are specified by a sequence of two character
+# entries, MoTuSa for example is Monday Tuesday and Saturday. Note
+# that repeated days are unset MoMo = no day, and MoWk = all weekdays
+# bar Monday. The two character combinations accepted are
+#
+# Mo Tu We Th Fr Sa Su Wk Wd Al
+#
+# the last two being week-end days and all 7 days of the week
+# respectively. As a final example, AlFr means all days except Friday.
+#
+# each day/time-range can be prefixed with a '!' to indicate "anything
+# but"
+#
+# The time-range part is two 24-hour times HHMM separated by a hyphen
+# indicating the start and finish time (if the finish time is smaller
+# than the start time it is deemed to apply on the following day).
+#
+# for a rule to be active, ALL of service+ttys+users must be satisfied
+# by the applying process.
+#
+
+#
+# Here is a simple example: running blank on tty* (any ttyXXX device),
+# the users 'you' and 'me' are denied service all of the time
+#
+
+#blank;tty* & !ttyp*;you|me;!Al0000-2400
+
+# Another silly example, user 'root' is denied xsh access
+# from pseudo terminals at the weekend and on mondays.
+
+#xsh;ttyp*;root;!WdMo0000-2400
+
+#
+# End of example file.
+# \ No newline at end of file