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