Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / libpam / libpam / pam_delay.c
CommitLineData
984263bc
MD
1/*
2 * pam_delay.c
3 *
4 * Copyright (c) Andrew G. Morgan <morgan@linux.kernel.org> 1996-8
5 * All rights reserved.
6 *
7 * $Id: pam_delay.c,v 1.5 1997/04/05 06:54:19 morgan Exp $
8 * $FreeBSD: src/contrib/libpam/libpam/pam_delay.c,v 1.1.1.1.6.2 2001/06/11 15:28:12 markm Exp $
1de703da 9 * $DragonFly: src/contrib/libpam/libpam/Attic/pam_delay.c,v 1.2 2003/06/17 04:24:03 dillon Exp $
984263bc
MD
10 *
11 * $Log: pam_delay.c,v $
12 */
13
14/*
15 * This is a simple implementation of a delay on failure mechanism; an
16 * attempt to overcome authentication-time attacks in a simple manner.
17 */
18
19#include <unistd.h>
20#include "pam_private.h"
21
22/* **********************************************************************
23 * initialize the time as unset, this is set on the return from the
24 * authenticating pair of of the libpam pam_XXX calls.
25 */
26
27void _pam_reset_timer(pam_handle_t *pamh)
28{
29 D(("setting pamh->fail_delay.set to FALSE"));
30 pamh->fail_delay.set = PAM_FALSE;
31}
32
33/* **********************************************************************
34 * this function sets the start time for possible delayed failing.
35 *
36 * Eventually, it may set the timer so libpam knows how long the program
37 * has already been executing. Currently, this value is used to seed
38 * a pseudo-random number generator...
39 */
40
41void _pam_start_timer(pam_handle_t *pamh)
42{
43 pamh->fail_delay.begin = time(NULL);
44 D(("starting timer..."));
45}
46
47/* *******************************************************************
48 * Compute a pseudo random time. The value is base*(1 +/- 1/5) where
49 * the distribution is pseudo gausian (the sum of three evenly
50 * distributed random numbers -- central limit theorem and all ;^) The
51 * linear random numbers are based on a formulae given in Knuth's
52 * Seminumerical recipies that was reproduced in `Numerical Recipies
53 * in C'. It is *not* a cryptographically strong generator, but it is
54 * probably "good enough" for our purposes here.
55 *
56 * /dev/random might be a better place to look for some numbers...
57 */
58
59static unsigned int _pam_rand(unsigned int seed)
60{
61#define N1 1664525
62#define N2 1013904223
63 return N1*seed + N2;
64}
65
66static unsigned int _pam_compute_delay(unsigned int seed, unsigned int base)
67{
68 int i;
69 double sum;
70 unsigned int ans;
71
72 for (sum=i=0; i<3; ++i) {
73 seed = _pam_rand(seed);
74 sum += (double) ((seed / 10) % 1000000);
75 }
76 sum = (sum/3.)/1e6 - .5; /* rescale */
77 ans = (unsigned int) ( base*(1.+sum) );
78 D(("random number: base=%u -> ans=%u\n", base, ans));
79
80 return ans;
81}
82
83/* **********************************************************************
84 * the following function sleeps for a random time. The actual time
85 * slept is computed above.. It is based on the requested time but will
86 * differ by up to +/- 25%.
87 */
88
89void _pam_await_timer(pam_handle_t *pamh, int status)
90{
91 unsigned int delay;
92 D(("waiting?..."));
93
94 delay = _pam_compute_delay(pamh->fail_delay.begin,
95 pamh->fail_delay.delay);
96 if (pamh->fail_delay.delay_fn_ptr) {
97 union {
98 const void *value;
99 void (*fn)(int, unsigned);
100 } hack_fn_u;
101
102 /* always call the applications delay function, even if
103 the delay is zero - indicate status */
104 hack_fn_u.value = pamh->fail_delay.delay_fn_ptr;
105 hack_fn_u.fn(status, delay);
106
107 } else if (status != PAM_SUCCESS && pamh->fail_delay.set) {
108
109 D(("will wait %u usec", delay));
110
111 if (delay > 0) {
112 struct timeval tval;
113
114 tval.tv_sec = delay / 1000000;
115 tval.tv_usec = delay % 1000000;
116 select(0, NULL, NULL, NULL, &tval);
117 }
118 }
119
120 _pam_reset_timer(pamh);
121 D(("waiting done"));
122}
123
124/* **********************************************************************
125 * this function is known to both the module and the application, it
126 * keeps a running score of the largest-requested delay so far, as
127 * specified by either modules or an application.
128 */
129
130int pam_fail_delay(pam_handle_t *pamh, unsigned int usec)
131{
132 int largest;
133
134 IF_NO_PAMH("pam_fail_delay", pamh, PAM_SYSTEM_ERR);
135
136 D(("setting delay to %u",usec));
137
138 if (pamh->fail_delay.set) {
139 largest = pamh->fail_delay.delay;
140 } else {
141 pamh->fail_delay.set = PAM_TRUE;
142 largest = 0;
143 }
144
145 D(("largest = %u",largest));
146
147 if (largest < usec) {
148 D(("resetting largest delay"));
149 pamh->fail_delay.delay = usec;
150 }
151
152 return PAM_SUCCESS;
153}
154