bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / support / htdbm.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * htdbm.c: simple program for manipulating DBM
19  * password databases for the Apache HTTP server
20  *
21  * Contributed by Mladen Turk <mturk@mappingsoft.com>
22  * 12 Oct 2001
23  */
24
25 #include "apr.h"
26 #include "apr_lib.h"
27 #include "apr_strings.h"
28 #include "apr_file_io.h"
29 #include "apr_file_info.h"
30 #include "apr_pools.h"
31 #include "apr_signal.h"
32 #include "apr_md5.h"
33 #include "apr_sha1.h"
34 #include "apr_dbm.h"
35
36 #if APR_HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 #if APR_HAVE_STRING_H
40 #include <string.h>
41 #endif
42 #if APR_HAVE_STRINGS_H
43 #include <strings.h>
44 #endif
45 #include <time.h>
46
47 #if APR_CHARSET_EBCDIC
48 #include "apr_xlate.h"
49 #endif /*APR_CHARSET_EBCDIC*/
50
51 #if APR_HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54 #if APR_HAVE_CRYPT_H
55 #include <crypt.h>
56 #endif
57
58
59 #if !APR_CHARSET_EBCDIC
60 #define LF 10
61 #define CR 13
62 #else /*APR_CHARSET_EBCDIC*/
63 #define LF '\n'
64 #define CR '\r'
65 #endif /*APR_CHARSET_EBCDIC*/
66
67 #define MAX_STRING_LEN 256
68 #define ALG_PLAIN 0
69 #define ALG_APMD5 1
70 #define ALG_APSHA 2
71  
72 #if APR_HAVE_CRYPT_H
73 #define ALG_CRYPT 3
74 #endif
75
76
77 #define ERR_FILEPERM    1
78 #define ERR_SYNTAX      2
79 #define ERR_PWMISMATCH  3
80 #define ERR_INTERRUPTED 4
81 #define ERR_OVERFLOW    5
82 #define ERR_BADUSER     6
83 #define ERR_EMPTY       7
84
85
86 typedef struct htdbm_t htdbm_t;
87
88 struct htdbm_t {
89     apr_dbm_t               *dbm;
90     apr_pool_t              *pool;
91 #if APR_CHARSET_EBCDIC
92     apr_xlate_t             *to_ascii;
93 #endif
94     char                    *filename;
95     char                    *username;
96     char                    *userpass;
97     char                    *comment;
98     char                    *type;
99     int                     create;
100     int                     rdonly;
101     int                     alg;
102 };
103
104
105 #define HTDBM_MAKE   0
106 #define HTDBM_DELETE 1
107 #define HTDBM_VERIFY 2
108 #define HTDBM_LIST   3
109 #define HTDBM_NOFILE 4
110 #define HTDBM_STDIN  5
111
112 static void terminate(void)
113 {
114     apr_terminate();
115 #ifdef NETWARE
116     pressanykey();
117 #endif
118 }
119
120 static void htdbm_terminate(htdbm_t *htdbm) 
121 {
122     if (htdbm->dbm)
123         apr_dbm_close(htdbm->dbm);
124     htdbm->dbm = NULL;
125 }
126
127 static htdbm_t *h;
128   
129 static void htdbm_interrupted(void) 
130 {
131     htdbm_terminate(h);
132     fprintf(stderr, "htdbm Interrupted !\n");
133     exit(ERR_INTERRUPTED);
134 }
135
136 static apr_status_t htdbm_init(apr_pool_t **pool, htdbm_t **hdbm) 
137 {
138
139 #if APR_CHARSET_EBCDIC
140     apr_status_t rv;
141 #endif
142
143     apr_pool_create( pool, NULL);
144     apr_signal(SIGINT, (void (*)(int)) htdbm_interrupted);
145
146     (*hdbm) = (htdbm_t *)apr_pcalloc(*pool, sizeof(htdbm_t));
147     (*hdbm)->pool = *pool;
148
149 #if APR_CHARSET_EBCDIC
150     rv = apr_xlate_open(&((*hdbm)->to_ascii), "ISO8859-1", APR_DEFAULT_CHARSET, (*hdbm)->pool);
151     if (rv) {
152         fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", rv);
153         return APR_EGENERAL;
154     }
155     rv = apr_SHA1InitEBCDIC((*hdbm)->to_ascii);
156     if (rv) {
157         fprintf(stderr, "apr_SHA1InitEBCDIC()->%d\n", rv);
158         return APR_EGENERAL;
159     }
160     rv = apr_MD5InitEBCDIC((*hdbm)->to_ascii);
161     if (rv) {
162         fprintf(stderr, "apr_MD5InitEBCDIC()->%d\n", rv);
163         return APR_EGENERAL;
164     }
165 #endif /*APR_CHARSET_EBCDIC*/
166
167     /* Set MD5 as default */
168     (*hdbm)->alg = ALG_APMD5;
169     (*hdbm)->type = "default";
170     return APR_SUCCESS;
171 }
172
173 static apr_status_t htdbm_open(htdbm_t *htdbm) 
174 {
175     if (htdbm->create)
176         return apr_dbm_open_ex(&htdbm->dbm, htdbm->type, htdbm->filename, APR_DBM_RWCREATE, 
177                             APR_OS_DEFAULT, htdbm->pool);
178     else
179         return apr_dbm_open_ex(&htdbm->dbm, htdbm->type, htdbm->filename, 
180                             htdbm->rdonly ? APR_DBM_READONLY : APR_DBM_READWRITE, 
181                             APR_OS_DEFAULT, htdbm->pool);
182 }
183
184 static apr_status_t htdbm_save(htdbm_t *htdbm, int *changed) 
185 {
186     apr_datum_t key, val;
187
188     if (!htdbm->username)
189         return APR_SUCCESS;
190
191     key.dptr = htdbm->username;
192     key.dsize = strlen(htdbm->username);
193     if (apr_dbm_exists(htdbm->dbm, key))
194         *changed = 1;
195
196     val.dsize = strlen(htdbm->userpass);
197     if (!htdbm->comment)
198         val.dptr  = htdbm->userpass;
199     else {
200         val.dptr = apr_pstrcat(htdbm->pool, htdbm->userpass, ":",
201                                htdbm->comment, NULL);
202         val.dsize += (strlen(htdbm->comment) + 1);
203     }
204     return apr_dbm_store(htdbm->dbm, key, val);
205 }
206
207 static apr_status_t htdbm_del(htdbm_t *htdbm) 
208 {
209     apr_datum_t key;
210
211     key.dptr = htdbm->username;
212     key.dsize = strlen(htdbm->username);
213     if (!apr_dbm_exists(htdbm->dbm, key))
214         return APR_ENOENT;
215
216     return apr_dbm_delete(htdbm->dbm, key);
217 }
218
219 static apr_status_t htdbm_verify(htdbm_t *htdbm) 
220 {
221     apr_datum_t key, val;
222     char pwd[MAX_STRING_LEN] = {0};
223     char *rec, *cmnt;
224
225     key.dptr = htdbm->username;
226     key.dsize = strlen(htdbm->username);
227     if (!apr_dbm_exists(htdbm->dbm, key))
228         return APR_ENOENT;    
229     if (apr_dbm_fetch(htdbm->dbm, key, &val) != APR_SUCCESS)
230         return APR_ENOENT;
231     rec = apr_pstrndup(htdbm->pool, val.dptr, val.dsize);
232     cmnt = strchr(rec, ';');
233     if (cmnt)
234         strncpy(pwd, rec, cmnt - rec);
235     else
236         strcpy(pwd, rec);
237     return apr_password_validate(htdbm->userpass, pwd);
238 }
239
240 static apr_status_t htdbm_list(htdbm_t *htdbm) 
241 {
242     apr_status_t rv;
243     apr_datum_t key, val;
244     char *rec, *cmnt;
245     char kb[MAX_STRING_LEN];
246     int i = 0;
247
248     rv = apr_dbm_firstkey(htdbm->dbm, &key);
249     if (rv != APR_SUCCESS) {
250         fprintf(stderr, "Empty database -- %s\n", htdbm->filename); 
251         return APR_ENOENT;
252     }
253     rec = apr_pcalloc(htdbm->pool, HUGE_STRING_LEN);
254
255     fprintf(stderr, "Dumping records from database -- %s\n", htdbm->filename); 
256     fprintf(stderr, "    %-32sComment\n", "Username");    
257     while (key.dptr != NULL) {
258         rv = apr_dbm_fetch(htdbm->dbm, key, &val);
259         if (rv != APR_SUCCESS) {
260             fprintf(stderr, "Failed getting data from %s\n", htdbm->filename);
261             return APR_EGENERAL;
262         }
263         strncpy(kb, key.dptr, key.dsize);
264         kb[key.dsize] = '\0';
265         fprintf(stderr, "    %-32s", kb);
266         strncpy(rec, val.dptr, val.dsize);
267         rec[val.dsize] = '\0';
268         cmnt = strchr(rec, ':');
269         if (cmnt)
270             fprintf(stderr, cmnt + 1);
271         fprintf(stderr, "\n");
272         rv = apr_dbm_nextkey(htdbm->dbm, &key);
273         if (rv != APR_SUCCESS)
274             fprintf(stderr, "Failed getting NextKey\n");
275         ++i;
276     }
277
278     fprintf(stderr, "Total #records : %d\n", i);
279     return APR_SUCCESS;
280 }
281
282 static void to64(char *s, unsigned long v, int n)
283 {
284     static unsigned char itoa64[] =         /* 0 ... 63 => ASCII - 64 */
285     "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
286
287     while (--n >= 0) {
288         *s++ = itoa64[v&0x3f];
289         v >>= 6;
290     }
291 }
292
293 static apr_status_t htdbm_make(htdbm_t *htdbm) 
294 {
295     char cpw[MAX_STRING_LEN];
296     char salt[9];
297
298     switch (htdbm->alg) {
299         case ALG_APSHA:
300             /* XXX cpw >= 28 + strlen(sha1) chars - fixed len SHA */
301             apr_sha1_base64(htdbm->userpass,strlen(htdbm->userpass),cpw);
302         break;
303
304         case ALG_APMD5: 
305             (void) srand((int) time((time_t *) NULL));
306             to64(&salt[0], rand(), 8);
307             salt[8] = '\0';
308             apr_md5_encode((const char *)htdbm->userpass, (const char *)salt,
309                             cpw, sizeof(cpw));
310         break;
311         case ALG_PLAIN:
312             /* XXX this len limitation is not in sync with any HTTPd len. */
313             apr_cpystrn(cpw,htdbm->userpass,sizeof(cpw));
314         break;
315 #if APR_HAVE_CRYPT_H
316         case ALG_CRYPT:
317             (void) srand((int) time((time_t *) NULL));
318             to64(&salt[0], rand(), 8);
319             salt[8] = '\0';
320             apr_cpystrn(cpw, (char *)crypt(htdbm->userpass, salt), sizeof(cpw) - 1);
321             fprintf(stderr, "CRYPT is now deprecated, use MD5 instead!\n");
322 #endif
323         default:
324         break;
325     }
326     htdbm->userpass = apr_pstrdup(htdbm->pool, cpw);
327     return APR_SUCCESS;
328 }
329
330 static apr_status_t htdbm_valid_username(htdbm_t *htdbm)
331 {
332     if (!htdbm->username || (strlen(htdbm->username) > 64) || (strlen(htdbm->username) < 1)) {
333         fprintf(stderr, "Invalid username length\n");
334         return APR_EINVAL;
335     }
336     if (strchr(htdbm->username, ':')) {
337         fprintf(stderr, "Username contains invalid characters\n");
338         return APR_EINVAL;
339     }
340     return APR_SUCCESS;
341 }
342
343 static void htdbm_usage(void)
344 {
345
346 #if APR_HAVE_CRYPT_H
347 #define CRYPT_OPTION "d"
348 #else
349 #define CRYPT_OPTION ""
350 #endif
351     fprintf(stderr, "htdbm -- program for manipulating DBM password databases.\n\n");
352     fprintf(stderr, "Usage: htdbm    [-cm"CRYPT_OPTION"pstvx] [-TDBTYPE] database username\n");
353     fprintf(stderr, "                -b[cm"CRYPT_OPTION"ptsv] [-TDBTYPE] database username password\n");
354     fprintf(stderr, "                -n[m"CRYPT_OPTION"pst]   username\n");
355     fprintf(stderr, "                -nb[m"CRYPT_OPTION"pst]  username password\n");
356     fprintf(stderr, "                -v[m"CRYPT_OPTION"ps]    [-TDBTYPE] database username\n");
357     fprintf(stderr, "                -vb[m"CRYPT_OPTION"ps]   [-TDBTYPE] database username password\n");
358     fprintf(stderr, "                -x[m"CRYPT_OPTION"ps]    [-TDBTYPE] database username\n");
359     fprintf(stderr, "                -l                       [-TDBTYPE] database\n");
360     fprintf(stderr, "Options:\n");
361     fprintf(stderr, "   -b   Use the password from the command line rather "
362                     "than prompting for it.\n");
363     fprintf(stderr, "   -c   Create a new database.\n");
364     fprintf(stderr, "   -n   Don't update database; display results on stdout.\n");
365     fprintf(stderr, "   -m   Force MD5 encryption of the password (default).\n");
366 #if APR_HAVE_CRYPT_H
367     fprintf(stderr, "   -d   Force CRYPT encryption of the password (now deprecated).\n");
368 #endif
369     fprintf(stderr, "   -p   Do not encrypt the password (plaintext).\n");
370     fprintf(stderr, "   -s   Force SHA encryption of the password.\n");
371     fprintf(stderr, "   -T   DBM Type (SDBM|GDBM|DB|default).\n");
372     fprintf(stderr, "   -l   Display usernames from database on stdout.\n");
373     fprintf(stderr, "   -t   The last param is username comment.\n");
374     fprintf(stderr, "   -v   Verify the username/password.\n");
375     fprintf(stderr, "   -x   Remove the username record from database.\n");
376     exit(ERR_SYNTAX);
377
378 }
379
380
381 int main(int argc, const char * const argv[])
382 {
383     apr_pool_t *pool;
384     apr_status_t rv;
385     apr_size_t l;
386     char pwi[MAX_STRING_LEN];
387     char pwc[MAX_STRING_LEN];
388     char errbuf[MAX_STRING_LEN];
389     const char *arg;
390     int  need_file = 1;
391     int  need_user = 1;
392     int  need_pwd  = 1;
393     int  need_cmnt = 0;
394     int  pwd_supplied = 0;
395     int  changed;
396     int  cmd = HTDBM_MAKE;
397     int  i;
398     int args_left = 2;
399
400     apr_app_initialize(&argc, &argv, NULL);
401     atexit(terminate);
402
403     if ((rv = htdbm_init(&pool, &h)) != APR_SUCCESS) {
404         fprintf(stderr, "Unable to initialize htdbm terminating!\n");
405         apr_strerror(rv, errbuf, sizeof(errbuf));
406         exit(1);
407     }
408     /*
409      * Preliminary check to make sure they provided at least
410      * three arguments, we'll do better argument checking as 
411      * we parse the command line.
412      */
413     if (argc < 3)
414        htdbm_usage();
415     /*
416      * Go through the argument list and pick out any options.  They
417      * have to precede any other arguments.
418      */
419     for (i = 1; i < argc; i++) {
420         arg = argv[i];
421         if (*arg != '-')
422             break;
423         
424         while (*++arg != '\0') {
425             switch (*arg) {
426             case 'b':
427                 pwd_supplied = 1;
428                 need_pwd = 0;
429                 args_left++;
430                 break;
431             case 'c':
432                 h->create = 1;
433                 break;
434             case 'n':
435                 need_file = 0;
436                 cmd = HTDBM_NOFILE;
437                     args_left--;
438                 break;
439             case 'l':
440                 need_pwd = 0;
441                 need_user = 0;
442                 cmd = HTDBM_LIST;
443                 h->rdonly = 1;
444                 args_left--;
445                 break;
446             case 't':
447                 need_cmnt = 1;
448                 args_left++;
449                 break;
450             case 'T':
451                 h->type = apr_pstrdup(h->pool, ++arg);
452                 while (*arg != '\0')
453                     ++arg;
454                 --arg; /* so incrementing this in the loop with find a null */
455                 break;
456             case 'v':
457                 h->rdonly = 1;
458                 cmd = HTDBM_VERIFY;
459                 break;
460             case 'x':
461                 need_pwd = 0;
462                 cmd = HTDBM_DELETE;
463                 break;
464             case 'm':
465                 h->alg = ALG_APMD5;
466                 break;
467             case 'p':
468                 h->alg = ALG_PLAIN;
469                 break;
470             case 's':
471                 h->alg = ALG_APSHA;
472                 break;
473 #if APR_HAVE_CRYPT_H
474             case 'd':
475                 h->alg = ALG_CRYPT;
476                 break;
477 #endif
478             default:
479                 htdbm_usage();
480                 break;
481             }
482         }
483     }
484     /*
485      * Make sure we still have exactly the right number of arguments left
486      * (the filename, the username, and possibly the password if -b was
487      * specified).
488      */
489     if ((argc - i) != args_left)
490         htdbm_usage();
491
492     if (!need_file)
493         i--;
494     else {
495         h->filename = apr_pstrdup(h->pool, argv[i]);
496             if ((rv = htdbm_open(h)) != APR_SUCCESS) {
497             fprintf(stderr, "Error opening database %s\n", argv[i]);
498             apr_strerror(rv, errbuf, sizeof(errbuf));
499             fprintf(stderr,"%s\n",errbuf);
500             exit(ERR_FILEPERM);
501         }
502     }
503     if (need_user) {
504         h->username = apr_pstrdup(pool, argv[i+1]);
505         if (htdbm_valid_username(h) != APR_SUCCESS)
506             exit(ERR_BADUSER);
507     }
508     if (pwd_supplied)
509         h->userpass = apr_pstrdup(pool, argv[i+2]);
510
511     if (need_pwd) {
512         l = sizeof(pwc);
513         if (apr_password_get("Enter password        : ", pwi, &l) != APR_SUCCESS) {
514             fprintf(stderr, "Password too long\n");
515             exit(ERR_OVERFLOW);
516         }
517         l = sizeof(pwc);
518         if (apr_password_get("Re-type password      : ", pwc, &l) != APR_SUCCESS) {
519             fprintf(stderr, "Password too long\n");
520             exit(ERR_OVERFLOW);
521         }
522         if (strcmp(pwi, pwc) != 0) {
523             fprintf(stderr, "Password verification error\n");
524             exit(ERR_PWMISMATCH);
525         }
526             
527         h->userpass = apr_pstrdup(pool,  pwi);
528     }
529     if (need_cmnt && pwd_supplied)
530         h->comment = apr_pstrdup(pool, argv[i+3]);
531     else if (need_cmnt)
532         h->comment = apr_pstrdup(pool, argv[i+2]);
533
534     switch (cmd) {
535         case HTDBM_VERIFY:
536             if ((rv = htdbm_verify(h)) != APR_SUCCESS) {
537                 if(rv == APR_ENOENT) {
538                     fprintf(stderr, "The user '%s' could not be found in database\n", h->username);
539                     exit(ERR_BADUSER);
540                 }
541                 else {
542                     fprintf(stderr, "Password mismatch for user '%s'\n", h->username);
543                     exit(ERR_PWMISMATCH);
544                 }
545             }
546             else
547                 fprintf(stderr, "Password validated for user '%s'\n", h->username);
548             break;
549         case HTDBM_DELETE:
550             if (htdbm_del(h) != APR_SUCCESS) {
551                 fprintf(stderr, "Cannot find user '%s' in database\n", h->username);
552                 exit(ERR_BADUSER);
553             }
554             h->username = NULL;
555             changed = 1;
556             break;
557         case HTDBM_LIST:
558             htdbm_list(h);
559             break;
560         default:
561             htdbm_make(h);
562             break;
563
564     }    
565     if (need_file && !h->rdonly) {
566         if ((rv = htdbm_save(h, &changed)) != APR_SUCCESS) {
567             apr_strerror(rv, errbuf, sizeof(errbuf));
568             exit(ERR_FILEPERM);
569         }
570         fprintf(stdout, "Database %s %s.\n", h->filename, 
571                 h->create ? "created" : (changed ? "modified" : "updated"));
572     }
573     if (cmd == HTDBM_NOFILE) {
574         if (!need_cmnt) {
575             fprintf(stderr, "%s:%s\n", h->username, h->userpass);
576         }
577         else {
578             fprintf(stderr, "%s:%s:%s\n", h->username, h->userpass,
579                     h->comment);
580         }
581     }
582     htdbm_terminate(h);
583     
584     return 0; /* Suppress compiler warning. */
585 }