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