xref: /openbsd-src/libexec/login_token/tokendb.c (revision df69c215c7c66baf660f3f65414fd34796c96152)
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