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