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