1/* 2 * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * 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 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifdef HAVE_CONFIG_H 35#include "config.h" 36RCSID("$Id$"); 37#endif 38 39#include "otp_locl.h" 40 41#if !defined(HAVE_NDBM) && !defined(HAVE_DB_NDBM) 42#include "ndbm_wrap.h" 43#endif 44 45#define RETRIES 5 46 47void * 48otp_db_open (void) 49{ 50 int lock; 51 int i; 52 void *ret; 53 54 for(i = 0; i < RETRIES; ++i) { 55 struct stat statbuf; 56 57 lock = open (OTP_DB_LOCK, O_WRONLY | O_CREAT | O_EXCL, 0666); 58 if (lock >= 0) { 59 close(lock); 60 break; 61 } 62 if (stat (OTP_DB_LOCK, &statbuf) == 0) { 63 if (time(NULL) - statbuf.st_mtime > OTP_DB_TIMEOUT) 64 unlink (OTP_DB_LOCK); 65 else 66 sleep (1); 67 } 68 } 69 if (i == RETRIES) 70 return NULL; 71 ret = dbm_open (OTP_DB, O_RDWR | O_CREAT, 0600); 72 if (ret == NULL) 73 unlink (OTP_DB_LOCK); 74 return ret; 75} 76 77void 78otp_db_close (void *dbm) 79{ 80 dbm_close ((DBM *)dbm); 81 unlink (OTP_DB_LOCK); 82} 83 84/* 85 * Remove this entry from the database. 86 * return 0 if ok. 87 */ 88 89int 90otp_delete (void *v, OtpContext *ctx) 91{ 92 DBM *dbm = (DBM *)v; 93 datum key; 94 95 key.dsize = strlen(ctx->user); 96 key.dptr = ctx->user; 97 98 return dbm_delete(dbm, key); 99} 100 101/* 102 * Read this entry from the database and lock it if lockp. 103 */ 104 105static int 106otp_get_internal (void *v, OtpContext *ctx, int lockp) 107{ 108 DBM *dbm = (DBM *)v; 109 datum dat, key; 110 char *p; 111 time_t now, then; 112 113 key.dsize = strlen(ctx->user); 114 key.dptr = ctx->user; 115 116 dat = dbm_fetch (dbm, key); 117 if (dat.dptr == NULL) { 118 ctx->err = "Entry not found"; 119 return -1; 120 } 121 p = dat.dptr; 122 123 memcpy (&then, p, sizeof(then)); 124 ctx->lock_time = then; 125 if (lockp) { 126 time(&now); 127 if (then && now - then < OTP_USER_TIMEOUT) { 128 ctx->err = "Entry locked"; 129 return -1; 130 } 131 memcpy (p, &now, sizeof(now)); 132 } 133 p += sizeof(now); 134 ctx->alg = otp_find_alg (p); 135 if (ctx->alg == NULL) { 136 ctx->err = "Bad algorithm"; 137 return -1; 138 } 139 p += strlen(p) + 1; 140 { 141 unsigned char *up = (unsigned char *)p; 142 ctx->n = (up[0] << 24) | (up[1] << 16) | (up[2] << 8) | up[3]; 143 } 144 p += 4; 145 memcpy (ctx->key, p, OTPKEYSIZE); 146 p += OTPKEYSIZE; 147 strlcpy (ctx->seed, p, sizeof(ctx->seed)); 148 if (lockp) 149 return dbm_store (dbm, key, dat, DBM_REPLACE); 150 else 151 return 0; 152} 153 154/* 155 * Get and lock. 156 */ 157 158int 159otp_get (void *v, OtpContext *ctx) 160{ 161 return otp_get_internal (v, ctx, 1); 162} 163 164/* 165 * Get and don't lock. 166 */ 167 168int 169otp_simple_get (void *v, OtpContext *ctx) 170{ 171 return otp_get_internal (v, ctx, 0); 172} 173 174/* 175 * Write this entry to the database. 176 */ 177 178int 179otp_put (void *v, OtpContext *ctx) 180{ 181 DBM *dbm = (DBM *)v; 182 datum dat, key; 183 char buf[1024], *p; 184 time_t zero = 0; 185 size_t len, rem; 186 187 key.dsize = strlen(ctx->user); 188 key.dptr = ctx->user; 189 190 p = buf; 191 rem = sizeof(buf); 192 193 if (rem < sizeof(zero)) 194 return -1; 195 memcpy (p, &zero, sizeof(zero)); 196 p += sizeof(zero); 197 rem -= sizeof(zero); 198 len = strlen(ctx->alg->name) + 1; 199 200 if (rem < len) 201 return -1; 202 strlcpy (p, ctx->alg->name, rem); 203 p += len; 204 rem -= len; 205 206 if (rem < 4) 207 return -1; 208 { 209 unsigned char *up = (unsigned char *)p; 210 *up++ = (ctx->n >> 24) & 0xFF; 211 *up++ = (ctx->n >> 16) & 0xFF; 212 *up++ = (ctx->n >> 8) & 0xFF; 213 *up++ = (ctx->n >> 0) & 0xFF; 214 } 215 p += 4; 216 rem -= 4; 217 218 if (rem < OTPKEYSIZE) 219 return -1; 220 memcpy (p, ctx->key, OTPKEYSIZE); 221 p += OTPKEYSIZE; 222 rem -= OTPKEYSIZE; 223 224 len = strlen(ctx->seed) + 1; 225 if (rem < len) 226 return -1; 227 strlcpy (p, ctx->seed, rem); 228 p += len; 229 rem -= len; 230 dat.dptr = buf; 231 dat.dsize = p - buf; 232 return dbm_store (dbm, key, dat, DBM_REPLACE); 233} 234