GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / utils / dbconverter-2.c
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 */
56 extern const sasl_utils_t *sasl_global_utils;
57 sasl_conn_t *globalconn;
58
59 typedef void *listcb_t(const char *, const char *, const char *,
60                        const char *, unsigned);
61
62 void 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
105 int 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
156 int 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 /*
204  * Open the database
205  *
206  */
207 static int berkeleydb_open(const char *path,DB **mbdb)
208 {
209     int ret;
210
211 #if DB_VERSION_MAJOR < 3
212     ret = db_open(path, DB_HASH, DB_CREATE, 0664, NULL, NULL, mbdb);
213 #else /* DB_VERSION_MAJOR < 3 */
214     ret = db_create(mbdb, NULL, 0);
215     if (ret == 0 && *mbdb != NULL)
216     {
217 #if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1
218         ret = (*mbdb)->open(*mbdb, NULL, path, NULL, DB_HASH, DB_CREATE, 0664);
219 #else
220         ret = (*mbdb)->open(*mbdb, path, NULL, DB_HASH, DB_CREATE, 0664);
221 #endif
222         if (ret != 0)
223         {
224             (void) (*mbdb)->close(*mbdb, 0);
225             *mbdb = NULL;
226         }
227     }
228 #endif /* DB_VERSION_MAJOR < 3 */
229
230     if (ret != 0) {
231         fprintf(stderr,"Error opening password file %s\n", path);
232         return SASL_FAIL;
233     }
234
235     return SASL_OK;
236 }
237
238 /*
239  * Close the database
240  *
241  */
242
243 static void berkeleydb_close(DB *mbdb)
244 {
245     int ret;
246     
247     ret = mbdb->close(mbdb, 0);
248     if (ret!=0) {
249         fprintf(stderr,"error closing sasldb: %s",
250                 db_strerror(ret));
251     }
252 }
253
254 int listusers(const char *path, listcb_t *cb)
255 {
256     int result;
257     DB *mbdb = NULL;
258     DBC *cursor;
259     DBT key, data;
260
261     /* open the db */
262     result=berkeleydb_open(path, &mbdb);
263     if (result!=SASL_OK) goto cleanup;
264
265     /* make cursor */
266 #if DB_VERSION_MAJOR < 3
267 #if DB_VERSION_MINOR < 6
268     result = mbdb->cursor(mbdb, NULL,&cursor); 
269 #else
270     result = mbdb->cursor(mbdb, NULL,&cursor, 0); 
271 #endif /* DB_VERSION_MINOR < 7 */
272 #else /* DB_VERSION_MAJOR < 3 */
273     result = mbdb->cursor(mbdb, NULL,&cursor, 0); 
274 #endif /* DB_VERSION_MAJOR < 3 */
275
276     if (result!=0) {
277         fprintf(stderr,"Making cursor failure: %s\n",db_strerror(result));
278       result = SASL_FAIL;
279       goto cleanup;
280     }
281
282     memset(&key,0, sizeof(key));
283     memset(&data,0,sizeof(data));
284
285     /* loop thru */
286     result = cursor->c_get(cursor, &key, &data,
287                            DB_FIRST);
288
289     while (result != DB_NOTFOUND)
290     {
291         char *authid;
292         char *realm;
293         char *tmp;
294         unsigned int len;
295         char mech[1024];
296         int numnulls = 0;
297         unsigned int lup;
298
299         /* make sure there are exactly 2 null's */
300         for (lup=0;lup<key.size;lup++)
301             if (((char *)key.data)[lup]=='\0')
302                 numnulls++;
303
304         if (numnulls != 2) {
305             fprintf(stderr,"warning: probable database corruption\n");
306             result = cursor->c_get(cursor, &key, &data, DB_NEXT);
307             continue;
308         }
309
310         authid = key.data;
311         realm  = authid + strlen(authid)+1;
312         tmp    = realm + strlen(realm)+1;
313         len = key.size - (tmp - authid);
314
315         /* make sure we have enough space of mech */
316         if (len >=sizeof(mech)) {
317             fprintf(stderr,"warning: absurdly long mech name\n");
318             result = cursor->c_get(cursor, &key, &data, DB_NEXT);
319             continue;
320         }
321
322         memcpy(mech, tmp, key.size - (tmp - ((char *)key.data)));
323         mech[key.size - (tmp - ((char *)key.data))] = '\0';
324
325         if (*authid) {
326             /* don't check return values */
327             cb(authid,realm,mech,data.data,data.size);
328         }
329
330         result = cursor->c_get(cursor, &key, &data, DB_NEXT);
331     }
332
333     if (result != DB_NOTFOUND) {
334         fprintf(stderr,"failure: %s\n",db_strerror(result));
335         result = SASL_FAIL;
336         goto cleanup;
337     }
338
339     result = cursor->c_close(cursor);
340     if (result!=0) result = SASL_FAIL;
341
342     result = SASL_OK;
343
344  cleanup:
345
346     if (mbdb != NULL) berkeleydb_close(mbdb);
347     return result;
348 }
349
350 #else 
351
352 /* ARGSUSED */
353
354 int listusers(const char *path __attribute__((unused)),
355               listcb_t *cb __attribute__((unused)))
356 {
357     fprintf(stderr,"Unsupported DB format");
358     exit(1);
359 }
360
361 #endif
362
363 char *db_new=SASL_DB_PATH;
364
365 int good_getopt(void *context __attribute__((unused)), 
366                 const char *plugin_name __attribute__((unused)), 
367                 const char *option,
368                 const char **result,
369                 unsigned *len)
370 {
371     if (db_new && !strcmp(option, "sasldb_path")) {
372         *result = db_new;
373         if (len)
374             *len = strlen(db_new);
375         return SASL_OK;
376     }
377
378     return SASL_FAIL;
379 }
380
381 static struct sasl_callback goodsasl_cb[] = {
382     { SASL_CB_GETOPT, &good_getopt, NULL },
383     { SASL_CB_LIST_END, NULL, NULL }
384 };
385
386 int main(int argc, char **argv)
387 {
388     const char *db="/etc/sasldb";
389     int result;
390
391     if (argc > 1) {
392         db = argv[1];
393         if(argc > 2) {
394             db_new = argv[2];
395         }
396     }
397
398     result = sasl_server_init(goodsasl_cb, "dbconverter");
399     if (result != SASL_OK) {
400         printf("couldn't init saslv2\n");
401         return 1;
402     }
403
404     result = sasl_server_new("sasldb",
405                              "localhost",
406                              NULL,
407                              NULL,
408                              NULL,
409                              NULL,
410                              0,
411                              &globalconn);
412     if (result != SASL_OK) {
413         printf("couldn't create globalconn\n");
414         return 1;
415     }
416
417     if(_sasl_check_db(sasl_global_utils,globalconn) != SASL_OK) {
418         printf("target DB %s is not OK\n", db_new);
419         return 1;
420     }
421     
422     printf("\nThis program will take the sasldb file specified on the\n"
423            "command line and convert it to a new sasldb file in the default\n"
424            "location (usually /etc/sasldb). It is STRONGLY RECOMMENDED that you\n"
425            "backup sasldb before allowing this program to run\n\n"
426            "We are going to convert %s and our output will be in %s\n\n"
427            "Press return to continue\n", db, db_new);
428
429     getchar();
430
431     listusers(db, (listcb_t *) &listusers_cb);
432
433     sasl_dispose(&globalconn);
434     sasl_done();
435     
436     exit(0);
437 }