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 57static DB *tokendb; 58 59/* 60 * Static function prototypes 61 */ 62 63static int tokendb_open(void); 64static void tokendb_close(void); 65 66/* 67 * Retrieve a user record from the token database file 68 */ 69 70int 71tokendb_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 104int 105tokendb_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 134int 135tokendb_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 161static int 162tokendb_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 233static void 234tokendb_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 250int 251tokendb_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 283int 284tokendb_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 314int 315tokendb_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