aef045dfe5091ebe813eb8c41cd74557e20cb61e
[openafs.git] / src / kauth / kaauxdb.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * ALL RIGHTS RESERVED
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 RCSID
18     ("$Header$");
19
20 #ifdef AFS_NT40_ENV
21 #include <io.h>
22 #else
23 #include <sys/file.h>
24 #endif
25 #ifdef HAVE_FCNTL_H
26 #include <fcntl.h>
27 #endif
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #else
31 #ifdef HAVE_STRINGS_H
32 #include <strings.h>
33 #endif
34 #endif
35 #include <rx/rxkad.h>
36 #include "ubik_int.h"
37 #include "kauth.h"
38 #include "kaserver.h"
39
40
41 static int fd = 0;
42
43 /* Open the auxiliary database file containing failed authentication
44  * counters, and the times at which the last failures occurred.
45  * Nothing fancy.
46  */
47 int
48 kaux_opendb(char *path)
49 {
50     char dbpathname[1024];
51     static char dbname[] = "auxdb";
52
53     if (strlen(path) < 1024 - strlen(dbname)) { /* bullet-proofing */
54
55         strcpy(dbpathname, path);
56         strcat(dbpathname, dbname);
57
58         fd = open(dbpathname, O_CREAT | O_RDWR, 0600);
59         if (fd < 0)
60             perror(dbpathname);
61     }
62
63     return fd;
64 }
65
66 /* close that auxiliary database.  Unneccessary, but here for symmetry.
67  */
68 void
69 kaux_closedb(void)
70 {
71
72     if (fd > 0)
73         close(fd);
74     return;
75 }
76
77
78 /* 
79  * The read and write routines take as a parameter, the offset into
80  * the main database at which a particular user's entry resides.  They
81  * then convert that into an offset into the auxiliary database.  This
82  * makes the main code a little simpler, though it obscures a small
83  * detail.
84  */
85 int
86 kaux_read(afs_int32 to,         /* this is the offset of the user id in the main database. 
87                                  * we do the conversion here - probably a bad idea. */
88           unsigned int *nfailures, afs_uint32 * lasttime)
89 {
90     unsigned int offset;
91
92     *nfailures = *lasttime = 0;
93
94     if (fd <= 0 || !to)
95         return 0;
96
97     offset =
98         ((to - sizeof(struct kaheader)) / ENTRYSIZE) * (sizeof(int) +
99                                                         sizeof(afs_int32));
100     /* can't get there from here */
101     if (offset > lseek(fd, offset, SEEK_SET))
102         return 0;
103
104     /* we should just end up with 0 for nfailures and lasttime if EOF is 
105      * encountered here, I hope */
106     if ((0 > read(fd, nfailures, sizeof(int)))
107         || (0 > read(fd, lasttime, sizeof(afs_int32)))) {
108         *nfailures = *lasttime = 0;
109         perror("kaux_read()");
110     }
111
112     return 0;
113 }
114
115 int
116 kaux_write(afs_int32 to, unsigned int nfailures, afs_uint32 lasttime)
117 {
118     unsigned int offset;
119
120     if (fd <= 0 || !to)
121         return 0;
122
123     offset =
124         ((to - sizeof(struct kaheader)) / ENTRYSIZE) * (sizeof(int) +
125                                                         sizeof(afs_int32));
126     /* can't get there from here */
127     if (offset > lseek(fd, offset, SEEK_SET))
128         return 0;
129
130     if ((write(fd, &nfailures, sizeof(int)) != sizeof(int))
131         || (write(fd, &lasttime, sizeof(afs_int32)) != sizeof(afs_int32)))
132         perror("kaux_write()");
133     return 0;
134 }
135
136
137 /* adjust this user's records to reflect a failure.
138  * locktime is the value stored in the main database that specifies
139  * how long a user's ID should be locked once the attempts limit has
140  * been exceeded.  It also functions as the interval during which the
141  * permitted N-1 authentication failures plus the forbidden Nth
142  * failure must occur, in order for the ID to actually be locked.  Ie,
143  * all failures which occurred more than _locktime_ seconds ago are
144  * forgiven.
145  * locktime == 0 signifies that the ID should be locked indefinitely
146  */
147 void
148 kaux_inc(afs_int32 to, afs_uint32 locktime)
149 {
150     int nfailures;
151     afs_uint32 lasttime, now;
152
153     now = time(0);
154
155     kaux_read(to, &nfailures, &lasttime);
156
157     if (locktime && lasttime + locktime < now)
158         nfailures = 1;
159     else
160         nfailures++;
161
162     kaux_write(to, nfailures, now);
163
164 }
165
166 /* 
167  * report on whether a particular id is locked or not...
168  * has to get some dirt from ubik.
169  * We multiply the actual number of permitted attempts by two because
170  * klog tries to authenticate twice when the password is bogus: once
171  * with the ka_string_to_key, and once with des_string_to_key, for
172  * Kerberos compatibility.  It's easier to frob here than to explain
173  * to users/admins.
174  * RETURNS: time when the ID will be unlocked, or 0 if it's not locked. 
175  */
176 int
177 kaux_islocked(afs_int32 to, u_int attempts, u_int locktime)
178 {
179     extern int ubeacon_Debug(), ubeacon_AmSyncSite();
180     unsigned int nfailures, myshare;
181     afs_uint32 lasttime;
182     struct ubik_debug beaconinfo;
183
184     /* if attempts is 0, that means there's no limit, so the id
185      * can't ever be locked...
186      */
187     if (!attempts)
188         return 0;
189
190     kaux_read(to, &nfailures, &lasttime);
191
192     ubeacon_Debug(&beaconinfo);
193     attempts = attempts * 2;
194
195     myshare = attempts / beaconinfo.nServers;
196     if (ubeacon_AmSyncSite())
197         myshare += attempts % beaconinfo.nServers;
198
199     if (!myshare) {
200         return -1;
201     } else if ((nfailures < myshare)
202                || (locktime && lasttime + locktime < time(0))) {
203         return 0;
204     } else if (locktime == 0) { /* infinite */
205         return -1;
206     } else {
207         return (lasttime + locktime);
208     }
209 }