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