1/* db_ndbm.c--SASL ndbm interface 2 * Rob Siemborski 3 * Rob Earhart 4 * $Id: db_ndbm.c,v 1.6 2005/01/10 19:01:34 snsimon Exp $ 5 */ 6/* 7 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The name "Carnegie Mellon University" must not be used to 22 * endorse or promote products derived from this software without 23 * prior written permission. For permission or any other legal 24 * details, please contact 25 * Office of Technology Transfer 26 * Carnegie Mellon University 27 * 5000 Forbes Avenue 28 * Pittsburgh, PA 15213-3890 29 * (412) 268-4387, fax: (412) 268-7395 30 * tech-transfer@andrew.cmu.edu 31 * 32 * 4. Redistributions of any form whatsoever must retain the following 33 * acknowledgment: 34 * "This product includes software developed by Computing Services 35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 36 * 37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 44 */ 45 46#include <config.h> 47#include <stdio.h> 48#include <ndbm.h> 49#include <fcntl.h> 50#include <sys/stat.h> 51#include <stdlib.h> 52#include <assert.h> 53#include "sasldb.h" 54 55static int db_ok = 0; 56 57/* This provides a version of _sasl_db_getsecret and 58 * _sasl_db_putsecret which work with ndbm. */ 59int _sasldb_getdata(const sasl_utils_t *utils, 60 sasl_conn_t *conn, 61 const char *authid, 62 const char *realm, 63 const char *propName, 64 char *out, const size_t max_out, size_t *out_len) 65{ 66 int result = SASL_OK; 67 char *key; 68 size_t key_len; 69 DBM *db; 70 datum dkey, dvalue; 71 void *cntxt; 72 sasl_getopt_t *getopt; 73 const char *path = SASL_DB_PATH; 74 75 if (!utils) return SASL_BADPARAM; 76 if (!authid || !propName || !realm || !out || !max_out) { 77 utils->seterror(conn, 0, 78 "Bad parameter in db_ndbm.c: _sasldb_getdata"); 79 return SASL_BADPARAM; 80 } 81 if (!db_ok) { 82 utils->seterror(conn, 0, "Database not checked"); 83 return SASL_FAIL; 84 } 85 86 result = _sasldb_alloc_key(utils, authid, realm, propName, 87 &key, &key_len); 88 if (result != SASL_OK) { 89 utils->seterror(conn, 0, 90 "Could not allocate key in _sasldb_getdata"); 91 return result; 92 } 93 94 if (utils->getcallback(conn, SASL_CB_GETOPT, 95 (sasl_callback_ft *)&getopt, &cntxt) == SASL_OK) { /* APPLE: cast */ 96 const char *p; 97 if (getopt(cntxt, NULL, "sasldb_path", &p, NULL) == SASL_OK 98 && p != NULL && *p != 0) { 99 path = p; 100 } 101 } 102 db = dbm_open(path, O_RDONLY, S_IRUSR | S_IWUSR); 103 if (! db) { 104 utils->seterror(cntxt, 0, "Could not open db"); 105 result = SASL_FAIL; 106 goto cleanup; 107 } 108 dkey.dptr = key; 109 dkey.dsize = key_len; 110 dvalue = dbm_fetch(db, dkey); 111 if (! dvalue.dptr) { 112 utils->seterror(cntxt, 0, "no user in db"); 113 result = SASL_NOUSER; 114 goto cleanup; 115 } 116 117 if((size_t)dvalue.dsize > max_out + 1) { 118 utils->seterror(cntxt, 0, "buffer overflow"); 119 return SASL_BUFOVER; 120 } 121 122 if(out_len) *out_len = dvalue.dsize; 123 memcpy(out, dvalue.dptr, dvalue.dsize); 124 out[dvalue.dsize] = '\0'; 125 126#if NDBM_FREE 127 /* Note: not sasl_FREE! This is memory allocated by ndbm, 128 * which is using libc malloc/free. */ 129 free(dvalue.dptr); 130#endif 131 132 cleanup: 133 utils->free(key); 134 if(db) 135 dbm_close(db); 136 137 return result; 138} 139 140int _sasldb_putdata(const sasl_utils_t *utils, 141 sasl_conn_t *conn, 142 const char *authid, 143 const char *realm, 144 const char *propName, 145 const char *data, size_t data_len) 146{ 147 int result = SASL_OK; 148 char *key; 149 size_t key_len; 150 DBM *db; 151 datum dkey; 152 void *cntxt; 153 sasl_getopt_t *getopt; 154 const char *path = SASL_DB_PATH; 155 156 if (!utils) return SASL_BADPARAM; 157 158 if (!authid || !realm || !propName) { 159 utils->seterror(conn, 0, 160 "Bad parameter in db_ndbm.c: _sasldb_putdata"); 161 return SASL_BADPARAM; 162 } 163 164 result = _sasldb_alloc_key(utils, authid, realm, propName, 165 &key, &key_len); 166 if (result != SASL_OK) { 167 utils->seterror(conn, 0, 168 "Could not allocate key in _sasldb_putdata"); 169 return result; 170 } 171 172 if (utils->getcallback(conn, SASL_CB_GETOPT, 173 (sasl_callback_ft *)&getopt, &cntxt) == SASL_OK) { /* APPLE: cast */ 174 const char *p; 175 if (getopt(cntxt, NULL, "sasldb_path", &p, NULL) == SASL_OK 176 && p != NULL && *p != 0) { 177 path = p; 178 } 179 } 180 181 db = dbm_open(path, 182 O_RDWR | O_CREAT, 183 S_IRUSR | S_IWUSR); 184 if (! db) { 185 utils->log(conn, SASL_LOG_ERR, 186 "SASL error opening password file. " 187 "Do you have write permissions?\n"); 188 utils->seterror(conn, 0, "Could not open db for write"); 189 goto cleanup; 190 } 191 dkey.dptr = key; 192 dkey.dsize = key_len; 193 if (data) { 194 datum dvalue; 195 dvalue.dptr = (void *)data; 196 if(!data_len) data_len = strlen(data); 197 dvalue.dsize = data_len; 198 if (dbm_store(db, dkey, dvalue, DBM_REPLACE)) { 199 utils->seterror(conn, 0, 200 "Couldn't update db"); 201 result = SASL_FAIL; 202 } 203 } else { 204 if (dbm_delete(db, dkey)) { 205 utils->seterror(conn, 0, 206 "Couldn't update db"); 207 result = SASL_NOUSER; 208 } 209 } 210 dbm_close(db); 211 212 cleanup: 213 utils->free(key); 214 215 return result; 216} 217 218#ifdef DBM_SUFFIX 219#define SUFLEN (strlen(DBM_SUFFIX) + 1) 220#else 221#define SUFLEN 5 222#endif 223 224int _sasl_check_db(const sasl_utils_t *utils, 225 sasl_conn_t *conn) 226{ 227 const char *path = SASL_DB_PATH; 228 void *cntxt; 229 sasl_getopt_t *getopt; 230 sasl_verifyfile_t *vf; 231 int ret = SASL_OK; 232 char *db; 233 234 if(!utils) return SASL_BADPARAM; 235 236 if (utils->getcallback(conn, SASL_CB_GETOPT, 237 (sasl_callback_ft *)&getopt, &cntxt) == SASL_OK) { /* APPLE: cast */ 238 const char *p; 239 if (getopt(cntxt, NULL, "sasldb_path", &p, NULL) == SASL_OK 240 && p != NULL && *p != 0) { 241 path = p; 242 } 243 } 244 245 db = utils->malloc(strlen(path) + SUFLEN); 246 247 if (db == NULL) { 248 ret = SASL_NOMEM; 249 } 250 251 ret = utils->getcallback(NULL, SASL_CB_VERIFYFILE, 252 (sasl_callback_ft *)&vf, &cntxt); /* APPLE: cast */ 253 if(ret != SASL_OK) { 254 utils->seterror(conn, 0, 255 "No verifyfile callback"); 256 return ret; 257 } 258 259#ifdef DBM_SUFFIX 260 if (ret == SASL_OK) { 261 sprintf(db, "%s%s", path, DBM_SUFFIX); 262 ret = vf(cntxt, db, SASL_VRFY_PASSWD); 263 } 264#else 265 if (ret == SASL_OK) { 266 sprintf(db, "%s.dir", path); 267 ret = vf(cntxt, db, SASL_VRFY_PASSWD); 268 } 269 if (ret == SASL_OK) { 270 sprintf(db, "%s.pag", path); 271 ret = vf(cntxt, db, SASL_VRFY_PASSWD); 272 } 273#endif 274 if (db) { 275 utils->free(db); 276 } 277 if (ret == SASL_OK) { 278 db_ok = 1; 279 } 280 281 if (ret == SASL_OK || ret == SASL_CONTINUE) { 282 return SASL_OK; 283 } else { 284 utils->seterror(conn, 0, 285 "Verifyfile failed"); 286 return ret; 287 } 288} 289 290typedef struct ndbm_handle 291{ 292 DBM *db; 293 datum dkey; 294 int first; 295} handle_t; 296 297sasldb_handle _sasldb_getkeyhandle(const sasl_utils_t *utils, 298 sasl_conn_t *conn) 299{ 300 const char *path = SASL_DB_PATH; 301 sasl_getopt_t *getopt; 302 void *cntxt; 303 DBM *db; 304 handle_t *handle; 305 306 if(!utils || !conn) return NULL; 307 308 if(!db_ok) { 309 utils->seterror(conn, 0, "Database not OK in _sasldb_getkeyhandle"); 310 return NULL; 311 } 312 313 if (utils->getcallback(conn, SASL_CB_GETOPT, 314 (sasl_callback_ft *)&getopt, &cntxt) == SASL_OK) { /* APPLE: cast */ 315 const char *p; 316 if (getopt(cntxt, NULL, "sasldb_path", &p, NULL) == SASL_OK 317 && p != NULL && *p != 0) { 318 path = p; 319 } 320 } 321 322 db = dbm_open(path, O_RDONLY, S_IRUSR | S_IWUSR); 323 324 if(!db) { 325 utils->seterror(conn, 0, "Could not open db"); 326 return NULL; 327 } 328 329 handle = utils->malloc(sizeof(handle_t)); 330 if(!handle) { 331 utils->seterror(conn, 0, "no memory in _sasldb_getkeyhandle"); 332 dbm_close(db); 333 return NULL; 334 } 335 336 handle->db = db; 337 handle->first = 1; 338 339 return (sasldb_handle)handle; 340} 341 342int _sasldb_getnextkey(const sasl_utils_t *utils __attribute__((unused)), 343 sasldb_handle handle, char *out, 344 const size_t max_out, size_t *out_len) 345{ 346 handle_t *dbh = (handle_t *)handle; 347 datum nextkey; 348 349 if(!utils || !handle || !out || !max_out) 350 return SASL_BADPARAM; 351 352 if(dbh->first) { 353 dbh->dkey = dbm_firstkey(dbh->db); 354 dbh->first = 0; 355 } else { 356 nextkey = dbm_nextkey(dbh->db); 357 dbh->dkey = nextkey; 358 } 359 360 if(dbh->dkey.dptr == NULL) 361 return SASL_OK; 362 363 if((unsigned)dbh->dkey.dsize > max_out) 364 return SASL_BUFOVER; 365 366 memcpy(out, dbh->dkey.dptr, dbh->dkey.dsize); 367 if(out_len) *out_len = dbh->dkey.dsize; 368 369 return SASL_CONTINUE; 370} 371 372int _sasldb_releasekeyhandle(const sasl_utils_t *utils, 373 sasldb_handle handle) 374{ 375 handle_t *dbh = (handle_t *)handle; 376 377 if(!utils || !dbh) return SASL_BADPARAM; 378 379 if(dbh->db) dbm_close(dbh->db); 380 381 utils->free(dbh); 382 383 return SASL_OK; 384} 385