xref: /openbsd-src/libexec/login_token/tokendb.c (revision df69c215c7c66baf660f3f65414fd34796c96152)
1*df69c215Sderaadt /*	$OpenBSD: tokendb.c,v 1.11 2019/06/28 13:32:53 deraadt Exp $	*/
227b8cbb6Smillert 
327b8cbb6Smillert /*-
4fafad76dSmillert  * Copyright (c) 1995 Migration Associates Corp. All Rights Reserved
527b8cbb6Smillert  *
627b8cbb6Smillert  * Redistribution and use in source and binary forms, with or without
727b8cbb6Smillert  * modification, are permitted provided that the following conditions
827b8cbb6Smillert  * are met:
927b8cbb6Smillert  * 1. Redistributions of source code must retain the above copyright
1027b8cbb6Smillert  *    notice, this list of conditions and the following disclaimer.
1127b8cbb6Smillert  * 2. Redistributions in binary form must reproduce the above copyright
1227b8cbb6Smillert  *    notice, this list of conditions and the following disclaimer in the
1327b8cbb6Smillert  *    documentation and/or other materials provided with the distribution.
1427b8cbb6Smillert  * 3. All advertising materials mentioning features or use of this software
1527b8cbb6Smillert  *    must display the following acknowledgement:
1627b8cbb6Smillert  *      This product includes software developed by Berkeley Software Design,
1727b8cbb6Smillert  *      Inc.
1827b8cbb6Smillert  * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
1927b8cbb6Smillert  *    or promote products derived from this software without specific prior
2027b8cbb6Smillert  *    written permission.
2127b8cbb6Smillert  *
2227b8cbb6Smillert  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
2327b8cbb6Smillert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2427b8cbb6Smillert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2527b8cbb6Smillert  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
2627b8cbb6Smillert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2727b8cbb6Smillert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2827b8cbb6Smillert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2927b8cbb6Smillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3027b8cbb6Smillert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3127b8cbb6Smillert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3227b8cbb6Smillert  * SUCH DAMAGE.
3327b8cbb6Smillert  *
3427b8cbb6Smillert  *	BSDI $From: tokendb.c,v 1.1 1996/08/26 20:13:10 prb Exp $
3527b8cbb6Smillert  */
3627b8cbb6Smillert 
3727b8cbb6Smillert #include <sys/types.h>
3827b8cbb6Smillert #include <sys/stat.h>
3927b8cbb6Smillert #include <sys/time.h>
4027b8cbb6Smillert #include <sys/resource.h>
4127b8cbb6Smillert 
4227b8cbb6Smillert #include <ctype.h>
4327b8cbb6Smillert #include <db.h>
4427b8cbb6Smillert #include <errno.h>
4527b8cbb6Smillert #include <fcntl.h>
4615904bd8Smillert #include <grp.h>
4727b8cbb6Smillert #include <limits.h>
4827b8cbb6Smillert #include <stdio.h>
4927b8cbb6Smillert #include <syslog.h>
5027b8cbb6Smillert #include <stdlib.h>
5127b8cbb6Smillert #include <string.h>
5227b8cbb6Smillert #include <unistd.h>
5327b8cbb6Smillert 
5427b8cbb6Smillert #include "token.h"
5527b8cbb6Smillert #include "tokendb.h"
5627b8cbb6Smillert 
5727b8cbb6Smillert static	DB	*tokendb;
5827b8cbb6Smillert 
5927b8cbb6Smillert /*
6027b8cbb6Smillert  * Static function prototypes
6127b8cbb6Smillert  */
6227b8cbb6Smillert 
6327b8cbb6Smillert static	int	tokendb_open(void);
6427b8cbb6Smillert static	void	tokendb_close(void);
6527b8cbb6Smillert 
6627b8cbb6Smillert /*
6727b8cbb6Smillert  * Retrieve a user record from the token database file
6827b8cbb6Smillert  */
6927b8cbb6Smillert 
7027b8cbb6Smillert int
tokendb_getrec(char * username,TOKENDB_Rec * tokenrec)7127b8cbb6Smillert tokendb_getrec(char *username, TOKENDB_Rec *tokenrec)
7227b8cbb6Smillert {
7327b8cbb6Smillert 	DBT	key;
7427b8cbb6Smillert 	DBT	data;
7527b8cbb6Smillert 	int	status = 0;
7627b8cbb6Smillert 
7727b8cbb6Smillert 	key.data = username;
7827b8cbb6Smillert 	key.size = strlen(username) + 1;
7927b8cbb6Smillert 	memset(&data, 0, sizeof(data));
8027b8cbb6Smillert 
8127b8cbb6Smillert 	if (tokendb_open())
8227b8cbb6Smillert 		return(-1);
8327b8cbb6Smillert 
8427b8cbb6Smillert 	status = (tokendb->get)(tokendb, &key, &data, 0);
8527b8cbb6Smillert 	switch (status) {
8627b8cbb6Smillert 	case 1:
87d1dadea4Smarkus 		tokendb_close();
8827b8cbb6Smillert 		return(ENOENT);
8927b8cbb6Smillert 	case -1:
90d1dadea4Smarkus 		tokendb_close();
9127b8cbb6Smillert 		return(-1);
9227b8cbb6Smillert 	}
9327b8cbb6Smillert 	memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
9427b8cbb6Smillert 	if ((tokenrec->flags & TOKEN_USEMODES) == 0)
9527b8cbb6Smillert 		tokenrec->mode = tt->modes & ~TOKEN_RIM;
96d1dadea4Smarkus 	tokendb_close();
9727b8cbb6Smillert 	return (0);
9827b8cbb6Smillert }
9927b8cbb6Smillert 
10027b8cbb6Smillert /*
10127b8cbb6Smillert  * Put a user record to the token database file.
10227b8cbb6Smillert  */
10327b8cbb6Smillert 
10427b8cbb6Smillert int
tokendb_putrec(char * username,TOKENDB_Rec * tokenrec)10527b8cbb6Smillert tokendb_putrec(char *username, TOKENDB_Rec *tokenrec)
10627b8cbb6Smillert {
10727b8cbb6Smillert 	DBT	key;
10827b8cbb6Smillert 	DBT	data;
10927b8cbb6Smillert 	int	status = 0;
11027b8cbb6Smillert 
11127b8cbb6Smillert 	key.data = username;
11227b8cbb6Smillert 	key.size = strlen(username) + 1;
11327b8cbb6Smillert 
11427b8cbb6Smillert 	if (tokenrec->mode)
11527b8cbb6Smillert 		tokenrec->flags |= TOKEN_USEMODES;
11627b8cbb6Smillert 	data.data = tokenrec;
11727b8cbb6Smillert 	data.size = sizeof(TOKENDB_Rec);
11827b8cbb6Smillert 
11927b8cbb6Smillert 	if (!tokendb_open()) {
12027b8cbb6Smillert 		if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
12127b8cbb6Smillert 			tokendb_close();
12227b8cbb6Smillert 			return (-1);
12327b8cbb6Smillert 		}
12427b8cbb6Smillert 		status = (tokendb->put)(tokendb, &key, &data, 0);
12527b8cbb6Smillert 	}
12627b8cbb6Smillert 	tokendb_close();
12727b8cbb6Smillert 	return (status);
12827b8cbb6Smillert }
12927b8cbb6Smillert 
13027b8cbb6Smillert /*
13127b8cbb6Smillert  * Remove a user record from the token database file.
13227b8cbb6Smillert  */
13327b8cbb6Smillert 
13427b8cbb6Smillert int
tokendb_delrec(char * username)13527b8cbb6Smillert tokendb_delrec(char *username)
13627b8cbb6Smillert {
13727b8cbb6Smillert 	DBT	key;
13827b8cbb6Smillert 	int	status = 0;
13927b8cbb6Smillert 
14027b8cbb6Smillert 	key.data = username;
14127b8cbb6Smillert 	key.size = strlen(username) + 1;
14227b8cbb6Smillert 
14327b8cbb6Smillert 	if (!tokendb_open()) {
14427b8cbb6Smillert 		if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
14527b8cbb6Smillert 			tokendb_close();
14627b8cbb6Smillert 			return (-1);
14727b8cbb6Smillert 		}
14827b8cbb6Smillert 		status = (tokendb->del)(tokendb, &key, 0);
14927b8cbb6Smillert 	}
15027b8cbb6Smillert 	tokendb_close();
15127b8cbb6Smillert 	return (status);
15227b8cbb6Smillert }
15327b8cbb6Smillert 
15427b8cbb6Smillert /*
15527b8cbb6Smillert  * Open the token database.  In order to expedite access in
15627b8cbb6Smillert  * heavily loaded conditions, we employ a N1 lock method.
15727b8cbb6Smillert  * Updates should be brief, so all locks wait infinitely.
15827b8cbb6Smillert  * Wait for a read (shared) lock as all updates read first.
15927b8cbb6Smillert  */
16027b8cbb6Smillert 
16127b8cbb6Smillert static	int
tokendb_open(void)16227b8cbb6Smillert tokendb_open(void)
16327b8cbb6Smillert {
16427b8cbb6Smillert 	int	must_set_perms = 0;
16515904bd8Smillert 	int	must_set_mode = 0;
16615904bd8Smillert 	struct	group	*grp;
16727b8cbb6Smillert 	struct	stat	statb;
16827b8cbb6Smillert 
16915904bd8Smillert 	if ((grp = getgrnam(TOKEN_GROUP)) == NULL) {
17015904bd8Smillert 		printf("Missing %s group, authentication disabled\n",
17115904bd8Smillert 		    TOKEN_GROUP);
17215904bd8Smillert 		fflush(stdout);
17315904bd8Smillert 		syslog(LOG_ALERT,
17415904bd8Smillert 		    "the %s group is missing, token authentication disabled",
17515904bd8Smillert 		    TOKEN_GROUP);
17615904bd8Smillert 		return (-1);
17715904bd8Smillert 	}
17815904bd8Smillert 
179*df69c215Sderaadt 	if (stat(tt->db, &statb) == -1) {
18027b8cbb6Smillert 		if (errno != ENOENT)
18127b8cbb6Smillert 			return (-1);
18227b8cbb6Smillert 		must_set_perms++;
18327b8cbb6Smillert 	} else {
18415904bd8Smillert 		if (statb.st_uid != 0 || statb.st_gid != grp->gr_gid) {
18527b8cbb6Smillert #ifdef PARANOID
18627b8cbb6Smillert 			printf("Authentication disabled\n");
18727b8cbb6Smillert 			fflush(stdout);
18827b8cbb6Smillert 			syslog(LOG_ALERT,
1892cc39398Sderaadt 			    "POTENTIAL COMPROMISE of %s. Owner was %u, "
1902cc39398Sderaadt 			    "Group was %u", tt->db, statb.st_uid, statb.st_gid);
19127b8cbb6Smillert 			return (-1);
19227b8cbb6Smillert #else
19327b8cbb6Smillert 			must_set_perms++;
19427b8cbb6Smillert #endif
19527b8cbb6Smillert 		}
196c77bc37eSmillert 		if ((statb.st_mode & 0777) != 0640) {
19727b8cbb6Smillert #ifdef PARANOID
19827b8cbb6Smillert 			printf("Authentication disabled\n");
19927b8cbb6Smillert 			fflush(stdout);
20027b8cbb6Smillert 			syslog(LOG_ALERT,
20127b8cbb6Smillert 			    "POTENTIAL COMPROMISE of %s. Mode was %o",
20227b8cbb6Smillert 			    tt->db, statb.st_mode);
20327b8cbb6Smillert 			return (-1);
20427b8cbb6Smillert #else
20515904bd8Smillert 			must_set_mode++;
20627b8cbb6Smillert #endif
20727b8cbb6Smillert 		}
20827b8cbb6Smillert 	}
20927b8cbb6Smillert 	if (!(tokendb =
210c77bc37eSmillert 	    dbopen(tt->db, O_CREAT | O_RDWR, 0640, DB_BTREE, 0)) )
21127b8cbb6Smillert 		return (-1);
21227b8cbb6Smillert 
21327b8cbb6Smillert 	if (flock((tokendb->fd)(tokendb), LOCK_SH)) {
21427b8cbb6Smillert 		(tokendb->close)(tokendb);
21527b8cbb6Smillert 		return (-1);
21627b8cbb6Smillert 	}
21715904bd8Smillert 	if (must_set_perms && fchown((tokendb->fd)(tokendb), 0, grp->gr_gid))
21827b8cbb6Smillert 		syslog(LOG_INFO,
21927b8cbb6Smillert 		    "Can't set owner/group of %s errno=%m", tt->db);
220c77bc37eSmillert 	if (must_set_mode && fchmod((tokendb->fd)(tokendb), 0640))
22115904bd8Smillert 		syslog(LOG_INFO,
22215904bd8Smillert 		    "Can't set mode of %s errno=%m", tt->db);
22327b8cbb6Smillert 
22427b8cbb6Smillert 	return (0);
22527b8cbb6Smillert }
22627b8cbb6Smillert 
22727b8cbb6Smillert /*
22827b8cbb6Smillert  * Close the token database.  We are holding an unknown lock.
22927b8cbb6Smillert  * Release it, then close the db. Since little can be done
23027b8cbb6Smillert  * about errors, we ignore them.
23127b8cbb6Smillert  */
23227b8cbb6Smillert 
23327b8cbb6Smillert static	void
tokendb_close(void)23427b8cbb6Smillert tokendb_close(void)
23527b8cbb6Smillert {
236aae6ec35Sderaadt 	if (tokendb) {
23727b8cbb6Smillert 		(void)flock((tokendb->fd)(tokendb), LOCK_UN);
23827b8cbb6Smillert 		(tokendb->close)(tokendb);
239aae6ec35Sderaadt 		tokendb = NULL;
240aae6ec35Sderaadt 	}
24127b8cbb6Smillert }
24227b8cbb6Smillert 
24327b8cbb6Smillert /*
24427b8cbb6Smillert  * Retrieve the first user record from the database, leaving the
24527b8cbb6Smillert  * database open for the next retrieval. If the march thru the
24627b8cbb6Smillert  * the database is aborted before end-of-file, the caller should
24727b8cbb6Smillert  * call tokendb_close to release the read lock.
24827b8cbb6Smillert  */
24927b8cbb6Smillert 
25027b8cbb6Smillert int
tokendb_firstrec(int reverse_flag,TOKENDB_Rec * tokenrec)25127b8cbb6Smillert tokendb_firstrec(int reverse_flag, TOKENDB_Rec *tokenrec)
25227b8cbb6Smillert {
25327b8cbb6Smillert 	DBT	key;
25427b8cbb6Smillert 	DBT	data;
25527b8cbb6Smillert 	int	status = 0;
25627b8cbb6Smillert 
25727b8cbb6Smillert 	memset(&data, 0, sizeof(data));
25827b8cbb6Smillert 
25927b8cbb6Smillert 	if (!tokendb_open()) {
26027b8cbb6Smillert 		status = (tokendb->seq)(tokendb, &key, &data,
26127b8cbb6Smillert 				reverse_flag ? R_LAST : R_FIRST);
26227b8cbb6Smillert 	}
26327b8cbb6Smillert 	if (status) {
26427b8cbb6Smillert 		tokendb_close();
26527b8cbb6Smillert 		return (status);
26627b8cbb6Smillert 	}
26727b8cbb6Smillert 	if (!data.data) {
26827b8cbb6Smillert 		tokendb_close();
26927b8cbb6Smillert 		return (ENOENT);
27027b8cbb6Smillert 	}
27127b8cbb6Smillert 	memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
27227b8cbb6Smillert 	if ((tokenrec->flags & TOKEN_USEMODES) == 0)
27327b8cbb6Smillert 		tokenrec->mode = tt->modes & ~TOKEN_RIM;
27427b8cbb6Smillert 	return (0);
27527b8cbb6Smillert }
27627b8cbb6Smillert 
27727b8cbb6Smillert /*
27827b8cbb6Smillert  * Retrieve the next sequential user record from the database. Close
27927b8cbb6Smillert  * the database only on end-of-file or error.
28027b8cbb6Smillert  */
28127b8cbb6Smillert 
28227b8cbb6Smillert 
28327b8cbb6Smillert int
tokendb_nextrec(int reverse_flag,TOKENDB_Rec * tokenrec)28427b8cbb6Smillert tokendb_nextrec(int reverse_flag, TOKENDB_Rec *tokenrec)
28527b8cbb6Smillert {
28627b8cbb6Smillert 	DBT	key;
28727b8cbb6Smillert 	DBT	data;
28827b8cbb6Smillert 	int	status;
28927b8cbb6Smillert 
29027b8cbb6Smillert 	memset(&data, 0, sizeof(data));
29127b8cbb6Smillert 
29227b8cbb6Smillert 	status = (tokendb->seq)(tokendb, &key, &data,
29327b8cbb6Smillert 		reverse_flag ? R_PREV : R_NEXT);
29427b8cbb6Smillert 
29527b8cbb6Smillert 	if (status) {
29627b8cbb6Smillert 		tokendb_close();
29727b8cbb6Smillert 		return (status);
29827b8cbb6Smillert 	}
29927b8cbb6Smillert 	if (!data.data) {
30027b8cbb6Smillert 		tokendb_close();
30127b8cbb6Smillert 		return (ENOENT);
30227b8cbb6Smillert 	}
30327b8cbb6Smillert 	memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
30427b8cbb6Smillert 	if ((tokenrec->flags & TOKEN_USEMODES) == 0)
30527b8cbb6Smillert 		tokenrec->mode = tt->modes & ~TOKEN_RIM;
30627b8cbb6Smillert 	return (0);
30727b8cbb6Smillert }
30827b8cbb6Smillert 
30927b8cbb6Smillert /*
31027b8cbb6Smillert  * Retrieve and lock a user record.  Since there are no facilities in
31127b8cbb6Smillert  * BSD for record locking, we hack a bit lock into the user record.
31227b8cbb6Smillert  */
31327b8cbb6Smillert 
31427b8cbb6Smillert int
tokendb_lockrec(char * username,TOKENDB_Rec * tokenrec,unsigned recflags)31527b8cbb6Smillert tokendb_lockrec(char *username, TOKENDB_Rec *tokenrec, unsigned recflags)
31627b8cbb6Smillert {
31727b8cbb6Smillert 	DBT	key;
31827b8cbb6Smillert 	DBT	data;
31927b8cbb6Smillert 	int	status;
32027b8cbb6Smillert 
32127b8cbb6Smillert 	key.data = username;
32227b8cbb6Smillert 	key.size = strlen(username) + 1;
32327b8cbb6Smillert 	memset(&data, 0, sizeof(data));
32427b8cbb6Smillert 
32527b8cbb6Smillert 	if (tokendb_open())
32627b8cbb6Smillert 		return(-1);
32727b8cbb6Smillert 
32827b8cbb6Smillert 	if (flock((tokendb->fd)(tokendb), LOCK_EX)) {
32927b8cbb6Smillert 		tokendb_close();
33027b8cbb6Smillert 		return(-1);
33127b8cbb6Smillert 	}
33227b8cbb6Smillert 	switch ((tokendb->get)(tokendb, &key, &data, 0)) {
33327b8cbb6Smillert 	case 1:
33427b8cbb6Smillert 		tokendb_close();
33527b8cbb6Smillert 		return (ENOENT);
33627b8cbb6Smillert 	case -1:
33727b8cbb6Smillert 		tokendb_close();
33827b8cbb6Smillert 		return(-1);
33927b8cbb6Smillert 	}
34027b8cbb6Smillert 	memcpy(tokenrec, data.data, sizeof(TOKENDB_Rec));
34127b8cbb6Smillert 
34227b8cbb6Smillert 	if ((tokenrec->flags & TOKEN_LOCKED)||(tokenrec->flags & recflags)) {
34327b8cbb6Smillert 		tokendb_close();
34427b8cbb6Smillert 		return(1);
34527b8cbb6Smillert 	}
34627b8cbb6Smillert 	data.data = tokenrec;
34727b8cbb6Smillert 	data.size = sizeof(TOKENDB_Rec);
34827b8cbb6Smillert 
34927b8cbb6Smillert 	time(&tokenrec->lock_time);
35027b8cbb6Smillert 	tokenrec->flags |= recflags;
35127b8cbb6Smillert 	status = (tokendb->put)(tokendb, &key, &data, 0);
35227b8cbb6Smillert 	tokendb_close();
35327b8cbb6Smillert 	if (status)
35427b8cbb6Smillert 		return(-1);
35527b8cbb6Smillert 	if ((tokenrec->flags & TOKEN_USEMODES) == 0)
35627b8cbb6Smillert 		tokenrec->mode = tt->modes & ~TOKEN_RIM;
35727b8cbb6Smillert 
35827b8cbb6Smillert 	return(0);
35927b8cbb6Smillert }
36027b8cbb6Smillert 
361