1 /* $OpenBSD: tokendb.c,v 1.11 2019/06/28 13:32:53 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/time.h>
40 #include <sys/resource.h>
41
42 #include <ctype.h>
43 #include <db.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <grp.h>
47 #include <limits.h>
48 #include <stdio.h>
49 #include <syslog.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53
54 #include "token.h"
55 #include "tokendb.h"
56
57 static DB *tokendb;
58
59 /*
60 * Static function prototypes
61 */
62
63 static int tokendb_open(void);
64 static void tokendb_close(void);
65
66 /*
67 * Retrieve a user record from the token database file
68 */
69
70 int
tokendb_getrec(char * username,TOKENDB_Rec * tokenrec)71 tokendb_getrec(char *username, TOKENDB_Rec *tokenrec)
72 {
73 DBT key;
74 DBT data;
75 int status = 0;
76
77 key.data = username;
78 key.size = strlen(username) + 1;
79 memset(&data, 0, sizeof(data));
80
81 if (tokendb_open())
82 return(-1);
83
84 status = (tokendb->get)(tokendb, &key, &data, 0);
85 switch (status) {
86 case 1:
87 tokendb_close();
88 return(ENOENT);
89 case -1:
90 tokendb_close();
91 return(-1);
92 }
93 memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
94 if ((tokenrec->flags & TOKEN_USEMODES) == 0)
95 tokenrec->mode = tt->modes & ~TOKEN_RIM;
96 tokendb_close();
97 return (0);
98 }
99
100 /*
101 * Put a user record to the token database file.
102 */
103
104 int
tokendb_putrec(char * username,TOKENDB_Rec * tokenrec)105 tokendb_putrec(char *username, TOKENDB_Rec *tokenrec)
106 {
107 DBT key;
108 DBT data;
109 int status = 0;
110
111 key.data = username;
112 key.size = strlen(username) + 1;
113
114 if (tokenrec->mode)
115 tokenrec->flags |= TOKEN_USEMODES;
116 data.data = tokenrec;
117 data.size = sizeof(TOKENDB_Rec);
118
119 if (!tokendb_open()) {
120 if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
121 tokendb_close();
122 return (-1);
123 }
124 status = (tokendb->put)(tokendb, &key, &data, 0);
125 }
126 tokendb_close();
127 return (status);
128 }
129
130 /*
131 * Remove a user record from the token database file.
132 */
133
134 int
tokendb_delrec(char * username)135 tokendb_delrec(char *username)
136 {
137 DBT key;
138 int status = 0;
139
140 key.data = username;
141 key.size = strlen(username) + 1;
142
143 if (!tokendb_open()) {
144 if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
145 tokendb_close();
146 return (-1);
147 }
148 status = (tokendb->del)(tokendb, &key, 0);
149 }
150 tokendb_close();
151 return (status);
152 }
153
154 /*
155 * Open the token database. In order to expedite access in
156 * heavily loaded conditions, we employ a N1 lock method.
157 * Updates should be brief, so all locks wait infinitely.
158 * Wait for a read (shared) lock as all updates read first.
159 */
160
161 static int
tokendb_open(void)162 tokendb_open(void)
163 {
164 int must_set_perms = 0;
165 int must_set_mode = 0;
166 struct group *grp;
167 struct stat statb;
168
169 if ((grp = getgrnam(TOKEN_GROUP)) == NULL) {
170 printf("Missing %s group, authentication disabled\n",
171 TOKEN_GROUP);
172 fflush(stdout);
173 syslog(LOG_ALERT,
174 "the %s group is missing, token authentication disabled",
175 TOKEN_GROUP);
176 return (-1);
177 }
178
179 if (stat(tt->db, &statb) == -1) {
180 if (errno != ENOENT)
181 return (-1);
182 must_set_perms++;
183 } else {
184 if (statb.st_uid != 0 || statb.st_gid != grp->gr_gid) {
185 #ifdef PARANOID
186 printf("Authentication disabled\n");
187 fflush(stdout);
188 syslog(LOG_ALERT,
189 "POTENTIAL COMPROMISE of %s. Owner was %u, "
190 "Group was %u", tt->db, statb.st_uid, statb.st_gid);
191 return (-1);
192 #else
193 must_set_perms++;
194 #endif
195 }
196 if ((statb.st_mode & 0777) != 0640) {
197 #ifdef PARANOID
198 printf("Authentication disabled\n");
199 fflush(stdout);
200 syslog(LOG_ALERT,
201 "POTENTIAL COMPROMISE of %s. Mode was %o",
202 tt->db, statb.st_mode);
203 return (-1);
204 #else
205 must_set_mode++;
206 #endif
207 }
208 }
209 if (!(tokendb =
210 dbopen(tt->db, O_CREAT | O_RDWR, 0640, DB_BTREE, 0)) )
211 return (-1);
212
213 if (flock((tokendb->fd)(tokendb), LOCK_SH)) {
214 (tokendb->close)(tokendb);
215 return (-1);
216 }
217 if (must_set_perms && fchown((tokendb->fd)(tokendb), 0, grp->gr_gid))
218 syslog(LOG_INFO,
219 "Can't set owner/group of %s errno=%m", tt->db);
220 if (must_set_mode && fchmod((tokendb->fd)(tokendb), 0640))
221 syslog(LOG_INFO,
222 "Can't set mode of %s errno=%m", tt->db);
223
224 return (0);
225 }
226
227 /*
228 * Close the token database. We are holding an unknown lock.
229 * Release it, then close the db. Since little can be done
230 * about errors, we ignore them.
231 */
232
233 static void
tokendb_close(void)234 tokendb_close(void)
235 {
236 if (tokendb) {
237 (void)flock((tokendb->fd)(tokendb), LOCK_UN);
238 (tokendb->close)(tokendb);
239 tokendb = NULL;
240 }
241 }
242
243 /*
244 * Retrieve the first user record from the database, leaving the
245 * database open for the next retrieval. If the march thru the
246 * the database is aborted before end-of-file, the caller should
247 * call tokendb_close to release the read lock.
248 */
249
250 int
tokendb_firstrec(int reverse_flag,TOKENDB_Rec * tokenrec)251 tokendb_firstrec(int reverse_flag, TOKENDB_Rec *tokenrec)
252 {
253 DBT key;
254 DBT data;
255 int status = 0;
256
257 memset(&data, 0, sizeof(data));
258
259 if (!tokendb_open()) {
260 status = (tokendb->seq)(tokendb, &key, &data,
261 reverse_flag ? R_LAST : R_FIRST);
262 }
263 if (status) {
264 tokendb_close();
265 return (status);
266 }
267 if (!data.data) {
268 tokendb_close();
269 return (ENOENT);
270 }
271 memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
272 if ((tokenrec->flags & TOKEN_USEMODES) == 0)
273 tokenrec->mode = tt->modes & ~TOKEN_RIM;
274 return (0);
275 }
276
277 /*
278 * Retrieve the next sequential user record from the database. Close
279 * the database only on end-of-file or error.
280 */
281
282
283 int
tokendb_nextrec(int reverse_flag,TOKENDB_Rec * tokenrec)284 tokendb_nextrec(int reverse_flag, TOKENDB_Rec *tokenrec)
285 {
286 DBT key;
287 DBT data;
288 int status;
289
290 memset(&data, 0, sizeof(data));
291
292 status = (tokendb->seq)(tokendb, &key, &data,
293 reverse_flag ? R_PREV : R_NEXT);
294
295 if (status) {
296 tokendb_close();
297 return (status);
298 }
299 if (!data.data) {
300 tokendb_close();
301 return (ENOENT);
302 }
303 memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
304 if ((tokenrec->flags & TOKEN_USEMODES) == 0)
305 tokenrec->mode = tt->modes & ~TOKEN_RIM;
306 return (0);
307 }
308
309 /*
310 * Retrieve and lock a user record. Since there are no facilities in
311 * BSD for record locking, we hack a bit lock into the user record.
312 */
313
314 int
tokendb_lockrec(char * username,TOKENDB_Rec * tokenrec,unsigned recflags)315 tokendb_lockrec(char *username, TOKENDB_Rec *tokenrec, unsigned recflags)
316 {
317 DBT key;
318 DBT data;
319 int status;
320
321 key.data = username;
322 key.size = strlen(username) + 1;
323 memset(&data, 0, sizeof(data));
324
325 if (tokendb_open())
326 return(-1);
327
328 if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
329 tokendb_close();
330 return(-1);
331 }
332 switch ((tokendb->get)(tokendb, &key, &data, 0)) {
333 case 1:
334 tokendb_close();
335 return (ENOENT);
336 case -1:
337 tokendb_close();
338 return(-1);
339 }
340 memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
341
342 if ((tokenrec->flags & TOKEN_LOCKED)||(tokenrec->flags & recflags)) {
343 tokendb_close();
344 return(1);
345 }
346 data.data = tokenrec;
347 data.size = sizeof(TOKENDB_Rec);
348
349 time(&tokenrec->lock_time);
350 tokenrec->flags |= recflags;
351 status = (tokendb->put)(tokendb, &key, &data, 0);
352 tokendb_close();
353 if (status)
354 return(-1);
355 if ((tokenrec->flags & TOKEN_USEMODES) == 0)
356 tokenrec->mode = tt->modes & ~TOKEN_RIM;
357
358 return(0);
359 }
360
361