1 /* $OpenBSD: tokendb.c,v 1.8 2005/09/16 23:47:00 deraadt Exp $ */
2
3 /*-
4 * Copyright (c) 1995 Migration Associates Corp. All Rights Reserved
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Berkeley Software Design,
17 * Inc.
18 * 4. The name of Berkeley Software Design, Inc. may not be used to endorse
19 * or promote products derived from this software without specific prior
20 * written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * BSDI $From: tokendb.c,v 1.1 1996/08/26 20:13:10 prb Exp $
35 */
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/param.h>
40 #include <sys/time.h>
41 #include <sys/resource.h>
42
43 #include <ctype.h>
44 #include <db.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <grp.h>
48 #include <limits.h>
49 #include <stdio.h>
50 #include <syslog.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54
55 #include "token.h"
56 #include "tokendb.h"
57
58 static DB *tokendb;
59
60 /*
61 * Static function prototypes
62 */
63
64 static int tokendb_open(void);
65 static void tokendb_close(void);
66
67 /*
68 * Retrieve a user record from the token database file
69 */
70
71 int
tokendb_getrec(char * username,TOKENDB_Rec * tokenrec)72 tokendb_getrec(char *username, TOKENDB_Rec *tokenrec)
73 {
74 DBT key;
75 DBT data;
76 int status = 0;
77
78 key.data = username;
79 key.size = strlen(username) + 1;
80 memset(&data, 0, sizeof(data));
81
82 if (tokendb_open())
83 return(-1);
84
85 status = (tokendb->get)(tokendb, &key, &data, 0);
86 switch (status) {
87 case 1:
88 tokendb_close();
89 return(ENOENT);
90 case -1:
91 tokendb_close();
92 return(-1);
93 }
94 memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
95 if ((tokenrec->flags & TOKEN_USEMODES) == 0)
96 tokenrec->mode = tt->modes & ~TOKEN_RIM;
97 tokendb_close();
98 return (0);
99 }
100
101 /*
102 * Put a user record to the token database file.
103 */
104
105 int
tokendb_putrec(char * username,TOKENDB_Rec * tokenrec)106 tokendb_putrec(char *username, TOKENDB_Rec *tokenrec)
107 {
108 DBT key;
109 DBT data;
110 int status = 0;
111
112 key.data = username;
113 key.size = strlen(username) + 1;
114
115 if (tokenrec->mode)
116 tokenrec->flags |= TOKEN_USEMODES;
117 data.data = tokenrec;
118 data.size = sizeof(TOKENDB_Rec);
119
120 if (!tokendb_open()) {
121 if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
122 tokendb_close();
123 return (-1);
124 }
125 status = (tokendb->put)(tokendb, &key, &data, 0);
126 }
127 tokendb_close();
128 return (status);
129 }
130
131 /*
132 * Remove a user record from the token database file.
133 */
134
135 int
tokendb_delrec(char * username)136 tokendb_delrec(char *username)
137 {
138 DBT key;
139 DBT data;
140 int status = 0;
141
142 key.data = username;
143 key.size = strlen(username) + 1;
144 memset(&data, 0, sizeof(data));
145
146 if (!tokendb_open()) {
147 if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
148 tokendb_close();
149 return (-1);
150 }
151 status = (tokendb->del)(tokendb, &key, 0);
152 }
153 tokendb_close();
154 return (status);
155 }
156
157 /*
158 * Open the token database. In order to expedite access in
159 * heavily loaded conditions, we employ a N1 lock method.
160 * Updates should be brief, so all locks wait infinitely.
161 * Wait for a read (shared) lock as all updates read first.
162 */
163
164 static int
tokendb_open(void)165 tokendb_open(void)
166 {
167 int must_set_perms = 0;
168 int must_set_mode = 0;
169 struct group *grp;
170 struct stat statb;
171
172 if ((grp = getgrnam(TOKEN_GROUP)) == NULL) {
173 printf("Missing %s group, authentication disabled\n",
174 TOKEN_GROUP);
175 fflush(stdout);
176 syslog(LOG_ALERT,
177 "the %s group is missing, token authentication disabled",
178 TOKEN_GROUP);
179 return (-1);
180 }
181
182 if (stat(tt->db, &statb) < 0) {
183 if (errno != ENOENT)
184 return (-1);
185 must_set_perms++;
186 } else {
187 if (statb.st_uid != 0 || statb.st_gid != grp->gr_gid) {
188 #ifdef PARANOID
189 printf("Authentication disabled\n");
190 fflush(stdout);
191 syslog(LOG_ALERT,
192 "POTENTIAL COMPROMISE of %s. Owner was %u, "
193 "Group was %u", tt->db, statb.st_uid, statb.st_gid);
194 return (-1);
195 #else
196 must_set_perms++;
197 #endif
198 }
199 if ((statb.st_mode & 0777) != 0640) {
200 #ifdef PARANOID
201 printf("Authentication disabled\n");
202 fflush(stdout);
203 syslog(LOG_ALERT,
204 "POTENTIAL COMPROMISE of %s. Mode was %o",
205 tt->db, statb.st_mode);
206 return (-1);
207 #else
208 must_set_mode++;
209 #endif
210 }
211 }
212 if (!(tokendb =
213 dbopen(tt->db, O_CREAT | O_RDWR, 0640, DB_BTREE, 0)) )
214 return (-1);
215
216 if (flock((tokendb->fd)(tokendb), LOCK_SH)) {
217 (tokendb->close)(tokendb);
218 return (-1);
219 }
220 if (must_set_perms && fchown((tokendb->fd)(tokendb), 0, grp->gr_gid))
221 syslog(LOG_INFO,
222 "Can't set owner/group of %s errno=%m", tt->db);
223 if (must_set_mode && fchmod((tokendb->fd)(tokendb), 0640))
224 syslog(LOG_INFO,
225 "Can't set mode of %s errno=%m", tt->db);
226
227 return (0);
228 }
229
230 /*
231 * Close the token database. We are holding an unknown lock.
232 * Release it, then close the db. Since little can be done
233 * about errors, we ignore them.
234 */
235
236 static void
tokendb_close(void)237 tokendb_close(void)
238 {
239 if (tokendb) {
240 (void)flock((tokendb->fd)(tokendb), LOCK_UN);
241 (tokendb->close)(tokendb);
242 tokendb = NULL;
243 }
244 }
245
246 /*
247 * Retrieve the first user record from the database, leaving the
248 * database open for the next retrieval. If the march thru the
249 * the database is aborted before end-of-file, the caller should
250 * call tokendb_close to release the read lock.
251 */
252
253 int
tokendb_firstrec(int reverse_flag,TOKENDB_Rec * tokenrec)254 tokendb_firstrec(int reverse_flag, TOKENDB_Rec *tokenrec)
255 {
256 DBT key;
257 DBT data;
258 int status = 0;
259
260 memset(&data, 0, sizeof(data));
261
262 if (!tokendb_open()) {
263 status = (tokendb->seq)(tokendb, &key, &data,
264 reverse_flag ? R_LAST : R_FIRST);
265 }
266 if (status) {
267 tokendb_close();
268 return (status);
269 }
270 if (!data.data) {
271 tokendb_close();
272 return (ENOENT);
273 }
274 memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
275 if ((tokenrec->flags & TOKEN_USEMODES) == 0)
276 tokenrec->mode = tt->modes & ~TOKEN_RIM;
277 return (0);
278 }
279
280 /*
281 * Retrieve the next sequential user record from the database. Close
282 * the database only on end-of-file or error.
283 */
284
285
286 int
tokendb_nextrec(int reverse_flag,TOKENDB_Rec * tokenrec)287 tokendb_nextrec(int reverse_flag, TOKENDB_Rec *tokenrec)
288 {
289 DBT key;
290 DBT data;
291 int status;
292
293 memset(&data, 0, sizeof(data));
294
295 status = (tokendb->seq)(tokendb, &key, &data,
296 reverse_flag ? R_PREV : R_NEXT);
297
298 if (status) {
299 tokendb_close();
300 return (status);
301 }
302 if (!data.data) {
303 tokendb_close();
304 return (ENOENT);
305 }
306 memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
307 if ((tokenrec->flags & TOKEN_USEMODES) == 0)
308 tokenrec->mode = tt->modes & ~TOKEN_RIM;
309 return (0);
310 }
311
312 /*
313 * Retrieve and lock a user record. Since there are no facilities in
314 * BSD for record locking, we hack a bit lock into the user record.
315 */
316
317 int
tokendb_lockrec(char * username,TOKENDB_Rec * tokenrec,unsigned recflags)318 tokendb_lockrec(char *username, TOKENDB_Rec *tokenrec, unsigned recflags)
319 {
320 DBT key;
321 DBT data;
322 int status;
323
324 key.data = username;
325 key.size = strlen(username) + 1;
326 memset(&data, 0, sizeof(data));
327
328 if (tokendb_open())
329 return(-1);
330
331 if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
332 tokendb_close();
333 return(-1);
334 }
335 switch ((tokendb->get)(tokendb, &key, &data, 0)) {
336 case 1:
337 tokendb_close();
338 return (ENOENT);
339 case -1:
340 tokendb_close();
341 return(-1);
342 }
343 memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
344
345 if ((tokenrec->flags & TOKEN_LOCKED)||(tokenrec->flags & recflags)) {
346 tokendb_close();
347 return(1);
348 }
349 data.data = tokenrec;
350 data.size = sizeof(TOKENDB_Rec);
351
352 time(&tokenrec->lock_time);
353 tokenrec->flags |= recflags;
354 status = (tokendb->put)(tokendb, &key, &data, 0);
355 tokendb_close();
356 if (status)
357 return(-1);
358 if ((tokenrec->flags & TOKEN_USEMODES) == 0)
359 tokenrec->mode = tt->modes & ~TOKEN_RIM;
360
361 return(0);
362 }
363
364