1/* dbconverter-2.c -- convert libsasl v1 sasldb's to SASLv2 format 2 * $Id: dbconverter-2.c,v 1.8 2003/02/13 19:56:17 rjs3 Exp $ 3 * Rob Siemborski 4 * based on SASLv1 sasldblistusers 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 48#include <stdio.h> 49#include <stdlib.h> 50 51#include <sasl.h> 52#include <saslplug.h> 53#include "../sasldb/sasldb.h" 54 55/* Cheating to make the utils work out right */ 56extern const sasl_utils_t *sasl_global_utils; 57sasl_conn_t *globalconn; 58 59typedef void *listcb_t(const char *, const char *, const char *, 60 const char *, unsigned); 61 62void listusers_cb(const char *authid, const char *realm, 63 const char *mechanism, const char *secret, 64 unsigned seclen) 65{ 66 char newPropBuffer[8192]; 67 68 if (!authid || !mechanism || !realm) { 69 fprintf(stderr,"userlist callback has bad param"); 70 return; 71 } 72 73 /* the entries that just say the mechanism exists */ 74 if (strlen(authid)==0) return; 75 76 printf("Converting: %s@%s (%s)...",authid,realm,mechanism); 77 78 /* Maybe we have a plaintext password? */ 79 if(!strcmp(mechanism,"PLAIN-APOP")) { 80 sprintf(newPropBuffer, "userPassword"); 81 /* Skip salt + NULL */ 82 secret = secret + 17; 83 seclen -= 17; 84 } else { 85 sprintf(newPropBuffer, "cmusaslsecret%s", mechanism); 86 } 87 88 _sasldb_putdata(sasl_global_utils, globalconn, 89 authid, realm, newPropBuffer, 90 secret, seclen); 91 92 printf("ok\n"); 93} 94 95/* 96 * List all users in database 97 */ 98 99#if defined(SASL_GDBM) 100 101#include <gdbm.h> 102#include <fcntl.h> 103#include <sys/stat.h> 104 105int listusers(const char *path, listcb_t *cb) 106{ 107 GDBM_FILE indb; 108 datum dkey, nextkey, dvalue; 109 110 indb = gdbm_open((char *)path, 0, GDBM_READER, S_IRUSR | S_IWUSR, NULL); 111 112 if (!indb) { 113 fprintf(stderr, "can't open %s\n", path); 114 return 1; 115 } 116 117 memset(&dkey, 0, sizeof(datum)); 118 119 dkey = gdbm_firstkey(indb); 120 121 while (dkey.dptr != NULL) { 122 char *authid = dkey.dptr; 123 char *realm = dkey.dptr+strlen(authid)+1; 124 char *tmp = realm + strlen(realm)+1; 125 char mech[1024]; 126 int len = dkey.dsize - (tmp - ((char *)dkey.dptr)); 127 128 if (len >= (int) sizeof mech) { 129 fprintf(stderr, "malformed database entry\n"); 130 break; 131 } 132 memcpy(mech, tmp, len); 133 mech[dkey.dsize - (tmp - dkey.dptr)] = '\0'; 134 135 dvalue = gdbm_fetch(indb, dkey); 136 137 if (*authid && dvalue.dptr) { 138 /* don't check return values */ 139 cb(authid,realm,mech,dvalue.dptr,dvalue.dsize); 140 } 141 142 nextkey=gdbm_nextkey(indb, dkey); 143 dkey=nextkey; 144 } 145 146 gdbm_close(indb); 147 return 0; 148} 149 150#elif defined(SASL_NDBM) 151 152#include <ndbm.h> 153#include <fcntl.h> 154#include <sys/stat.h> 155 156int listusers(const char *path, listcb_t *cb) 157{ 158 DBM *indb; 159 datum dkey, nextkey, dvalue; 160 161 indb = dbm_open(path, O_RDONLY, S_IRUSR | S_IWUSR); 162 163 if (!indb) { 164 fprintf(stderr, "can't open %s\n", path); 165 return 1; 166 } 167 168 dkey = dbm_firstkey(indb); 169 170 while (dkey.dptr != NULL) { 171 char *authid = dkey.dptr; 172 char *realm = dkey.dptr+strlen(authid)+1; 173 char *tmp = realm + strlen(realm)+1; 174 char mech[1024]; 175 int len = dkey.dsize - (tmp - ((char *)dkey.dptr)); 176 177 if (len >= (int) sizeof mech) { 178 fprintf(stderr, "malformed database entry\n"); 179 break; 180 } 181 memcpy(mech, tmp, len); 182 mech[dkey.dsize - (tmp - ((char *)dkey.dptr))] = '\0'; 183 184 dvalue = dbm_fetch(indb, dkey); 185 186 if (*authid && dvalue.dptr) { 187 /* don't check return values */ 188 cb(authid,realm,mech,dvalue.dptr,dvalue.dsize); 189 } 190 191 nextkey=dbm_nextkey(indb); 192 dkey=nextkey; 193 } 194 195 dbm_close(indb); 196 return 0; 197} 198 199#elif defined(SASL_BERKELEYDB) 200 201#include <db.h> 202 203#define DB_VERSION_FULL ((DB_VERSION_MAJOR << 24) | (DB_VERSION_MINOR << 16) | DB_VERSION_PATCH) 204/* 205 * Open the database 206 * 207 */ 208static int berkeleydb_open(const char *path,DB **mbdb) 209{ 210 int ret; 211 212#if DB_VERSION_FULL < 0x03000000 213 ret = db_open(path, DB_HASH, DB_CREATE, 0664, NULL, NULL, mbdb); 214#else /* DB_VERSION_FULL < 0x03000000 */ 215 ret = db_create(mbdb, NULL, 0); 216 if (ret == 0 && *mbdb != NULL) 217 { 218#if DB_VERSION_FULL >= 0x04010000 219 ret = (*mbdb)->open(*mbdb, NULL, path, NULL, DB_HASH, DB_CREATE, 0664); 220#else 221 ret = (*mbdb)->open(*mbdb, path, NULL, DB_HASH, DB_CREATE, 0664); 222#endif 223 if (ret != 0) 224 { 225 (void) (*mbdb)->close(*mbdb, 0); 226 *mbdb = NULL; 227 } 228 } 229#endif /* DB_VERSION_FULL < 0x03000000 */ 230 231 if (ret != 0) { 232 fprintf(stderr,"Error opening password file %s\n", path); 233 return SASL_FAIL; 234 } 235 236 return SASL_OK; 237} 238 239/* 240 * Close the database 241 * 242 */ 243 244static void berkeleydb_close(DB *mbdb) 245{ 246 int ret; 247 248 ret = mbdb->close(mbdb, 0); 249 if (ret!=0) { 250 fprintf(stderr,"error closing sasldb: %s", 251 db_strerror(ret)); 252 } 253} 254 255int listusers(const char *path, listcb_t *cb) 256{ 257 int result; 258 DB *mbdb = NULL; 259 DBC *cursor; 260 DBT key, data; 261 262 /* open the db */ 263 result=berkeleydb_open(path, &mbdb); 264 if (result!=SASL_OK) goto cleanup; 265 266 /* make cursor */ 267#if DB_VERSION_FULL < 0x03060000 268 result = mbdb->cursor(mbdb, NULL,&cursor); 269#else 270 result = mbdb->cursor(mbdb, NULL,&cursor, 0); 271#endif /* DB_VERSION_FULL < 0x03060000 */ 272 273 if (result!=0) { 274 fprintf(stderr,"Making cursor failure: %s\n",db_strerror(result)); 275 result = SASL_FAIL; 276 goto cleanup; 277 } 278 279 memset(&key,0, sizeof(key)); 280 memset(&data,0,sizeof(data)); 281 282 /* loop thru */ 283 result = cursor->c_get(cursor, &key, &data, 284 DB_FIRST); 285 286 while (result != DB_NOTFOUND) 287 { 288 char *authid; 289 char *realm; 290 char *tmp; 291 unsigned int len; 292 char mech[1024]; 293 int numnulls = 0; 294 unsigned int lup; 295 296 /* make sure there are exactly 2 null's */ 297 for (lup=0;lup<key.size;lup++) 298 if (((char *)key.data)[lup]=='\0') 299 numnulls++; 300 301 if (numnulls != 2) { 302 fprintf(stderr,"warning: probable database corruption\n"); 303 result = cursor->c_get(cursor, &key, &data, DB_NEXT); 304 continue; 305 } 306 307 authid = key.data; 308 realm = authid + strlen(authid)+1; 309 tmp = realm + strlen(realm)+1; 310 len = key.size - (tmp - authid); 311 312 /* make sure we have enough space of mech */ 313 if (len >=sizeof(mech)) { 314 fprintf(stderr,"warning: absurdly long mech name\n"); 315 result = cursor->c_get(cursor, &key, &data, DB_NEXT); 316 continue; 317 } 318 319 memcpy(mech, tmp, key.size - (tmp - ((char *)key.data))); 320 mech[key.size - (tmp - ((char *)key.data))] = '\0'; 321 322 if (*authid) { 323 /* don't check return values */ 324 cb(authid,realm,mech,data.data,data.size); 325 } 326 327 result = cursor->c_get(cursor, &key, &data, DB_NEXT); 328 } 329 330 if (result != DB_NOTFOUND) { 331 fprintf(stderr,"failure: %s\n",db_strerror(result)); 332 result = SASL_FAIL; 333 goto cleanup; 334 } 335 336 result = cursor->c_close(cursor); 337 if (result!=0) result = SASL_FAIL; 338 339 result = SASL_OK; 340 341 cleanup: 342 343 if (mbdb != NULL) berkeleydb_close(mbdb); 344 return result; 345} 346 347#else 348 349/* ARGSUSED */ 350 351int listusers(const char *path __attribute__((unused)), 352 listcb_t *cb __attribute__((unused))) 353{ 354 fprintf(stderr,"Unsupported DB format"); 355 exit(1); 356} 357 358#endif 359 360char *db_new=SASL_DB_PATH; 361 362int good_getopt(void *context __attribute__((unused)), 363 const char *plugin_name __attribute__((unused)), 364 const char *option, 365 const char **result, 366 unsigned *len) 367{ 368 if (db_new && !strcmp(option, "sasldb_path")) { 369 *result = db_new; 370 if (len) 371 *len = strlen(db_new); 372 return SASL_OK; 373 } 374 375 return SASL_FAIL; 376} 377 378static struct sasl_callback goodsasl_cb[] = { 379 { SASL_CB_GETOPT, &good_getopt, NULL }, 380 { SASL_CB_LIST_END, NULL, NULL } 381}; 382 383int main(int argc, char **argv) 384{ 385 const char *db="/etc/sasldb"; 386 int result; 387 388 if (argc > 1) { 389 db = argv[1]; 390 if(argc > 2) { 391 db_new = argv[2]; 392 } 393 } 394 395 result = sasl_server_init(goodsasl_cb, "dbconverter"); 396 if (result != SASL_OK) { 397 printf("couldn't init saslv2\n"); 398 return 1; 399 } 400 401 result = sasl_server_new("sasldb", 402 "localhost", 403 NULL, 404 NULL, 405 NULL, 406 NULL, 407 0, 408 &globalconn); 409 if (result != SASL_OK) { 410 printf("couldn't create globalconn\n"); 411 return 1; 412 } 413 414 if(_sasl_check_db(sasl_global_utils,globalconn) != SASL_OK) { 415 printf("target DB %s is not OK\n", db_new); 416 return 1; 417 } 418 419 printf("\nThis program will take the sasldb file specified on the\n" 420 "command line and convert it to a new sasldb file in the default\n" 421 "location (usually /etc/sasldb). It is STRONGLY RECOMMENDED that you\n" 422 "backup sasldb before allowing this program to run\n\n" 423 "We are going to convert %s and our output will be in %s\n\n" 424 "Press return to continue\n", db, db_new); 425 426 getchar(); 427 428 listusers(db, (listcb_t *) &listusers_cb); 429 430 sasl_dispose(&globalconn); 431 sasl_done(); 432 433 exit(0); 434} 435