~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to support/htpasswd.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 ******************************************************************************
 
19
 * NOTE! This program is not safe as a setuid executable!  Do not make it
 
20
 * setuid!
 
21
 ******************************************************************************
 
22
 *****************************************************************************/
 
23
/*
 
24
 * htpasswd.c: simple program for manipulating password file for
 
25
 * the Apache HTTP server
 
26
 *
 
27
 * Originally by Rob McCool
 
28
 *
 
29
 * Exit values:
 
30
 *  0: Success
 
31
 *  1: Failure; file access/permission problem
 
32
 *  2: Failure; command line syntax problem (usage message issued)
 
33
 *  3: Failure; password verification failure
 
34
 *  4: Failure; operation interrupted (such as with CTRL/C)
 
35
 *  5: Failure; buffer would overflow (username, filename, or computed
 
36
 *     record too long)
 
37
 *  6: Failure; username contains illegal or reserved characters
 
38
 *  7: Failure; file is not a valid htpasswd file
 
39
 */
 
40
 
 
41
#include "apr.h"
 
42
#include "apr_lib.h"
 
43
#include "apr_strings.h"
 
44
#include "apr_errno.h"
 
45
#include "apr_file_io.h"
 
46
#include "apr_general.h"
 
47
#include "apr_signal.h"
 
48
 
 
49
#if APR_HAVE_STDIO_H
 
50
#include <stdio.h>
 
51
#endif
 
52
 
 
53
#include "apr_md5.h"
 
54
#include "apr_sha1.h"
 
55
#include <time.h>
 
56
 
 
57
#if APR_HAVE_CRYPT_H
 
58
#include <crypt.h>
 
59
#endif
 
60
#if APR_HAVE_STDLIB_H
 
61
#include <stdlib.h>
 
62
#endif
 
63
#if APR_HAVE_STRING_H
 
64
#include <string.h>
 
65
#endif
 
66
#if APR_HAVE_UNISTD_H
 
67
#include <unistd.h>
 
68
#endif
 
69
 
 
70
#ifdef WIN32
 
71
#include <conio.h>
 
72
#define unlink _unlink
 
73
#endif
 
74
 
 
75
#if !APR_CHARSET_EBCDIC
 
76
#define LF 10
 
77
#define CR 13
 
78
#else /*APR_CHARSET_EBCDIC*/
 
79
#define LF '\n'
 
80
#define CR '\r'
 
81
#endif /*APR_CHARSET_EBCDIC*/
 
82
 
 
83
#define MAX_STRING_LEN 256
 
84
#define ALG_PLAIN 0
 
85
#define ALG_CRYPT 1
 
86
#define ALG_APMD5 2
 
87
#define ALG_APSHA 3
 
88
 
 
89
#define ERR_FILEPERM 1
 
90
#define ERR_SYNTAX 2
 
91
#define ERR_PWMISMATCH 3
 
92
#define ERR_INTERRUPTED 4
 
93
#define ERR_OVERFLOW 5
 
94
#define ERR_BADUSER 6
 
95
#define ERR_INVALID 7
 
96
 
 
97
#define APHTP_NEWFILE        1
 
98
#define APHTP_NOFILE         2
 
99
#define APHTP_NONINTERACTIVE 4
 
100
#define APHTP_DELUSER        8
 
101
 
 
102
apr_file_t *errfile;
 
103
apr_file_t *ftemp = NULL;
 
104
 
 
105
#define NL APR_EOL_STR
 
106
 
 
107
static void to64(char *s, unsigned long v, int n)
 
108
{
 
109
    static unsigned char itoa64[] =         /* 0 ... 63 => ASCII - 64 */
 
110
        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
111
 
 
112
    while (--n >= 0) {
 
113
        *s++ = itoa64[v&0x3f];
 
114
        v >>= 6;
 
115
    }
 
116
}
 
117
 
 
118
static void putline(apr_file_t *f, const char *l)
 
119
{
 
120
    apr_file_puts(l, f);
 
121
}
 
122
 
 
123
/*
 
124
 * Make a password record from the given information.  A zero return
 
125
 * indicates success; failure means that the output buffer contains an
 
126
 * error message instead.
 
127
 */
 
128
static int mkrecord(char *user, char *record, apr_size_t rlen, char *passwd,
 
129
                    int alg)
 
130
{
 
131
    char *pw;
 
132
    char cpw[120];
 
133
    char pwin[MAX_STRING_LEN];
 
134
    char pwv[MAX_STRING_LEN];
 
135
    char salt[9];
 
136
    apr_size_t bufsize;
 
137
 
 
138
    if (passwd != NULL) {
 
139
        pw = passwd;
 
140
    }
 
141
    else {
 
142
        bufsize = sizeof(pwin);
 
143
        if (apr_password_get("New password: ", pwin, &bufsize) != 0) {
 
144
            apr_snprintf(record, (rlen - 1), "password too long (>%"
 
145
                         APR_SIZE_T_FMT ")", sizeof(pwin) - 1);
 
146
            return ERR_OVERFLOW;
 
147
        }
 
148
        bufsize = sizeof(pwv);
 
149
        apr_password_get("Re-type new password: ", pwv, &bufsize);
 
150
        if (strcmp(pwin, pwv) != 0) {
 
151
            apr_cpystrn(record, "password verification error", (rlen - 1));
 
152
            return ERR_PWMISMATCH;
 
153
        }
 
154
        pw = pwin;
 
155
        memset(pwv, '\0', sizeof(pwin));
 
156
    }
 
157
    switch (alg) {
 
158
 
 
159
    case ALG_APSHA:
 
160
        /* XXX cpw >= 28 + strlen(sha1) chars - fixed len SHA */
 
161
        apr_sha1_base64(pw,strlen(pw),cpw);
 
162
        break;
 
163
 
 
164
    case ALG_APMD5:
 
165
        (void) srand((int) time((time_t *) NULL));
 
166
        to64(&salt[0], rand(), 8);
 
167
        salt[8] = '\0';
 
168
 
 
169
        apr_md5_encode((const char *)pw, (const char *)salt,
 
170
                     cpw, sizeof(cpw));
 
171
        break;
 
172
 
 
173
    case ALG_PLAIN:
 
174
        /* XXX this len limitation is not in sync with any HTTPd len. */
 
175
        apr_cpystrn(cpw,pw,sizeof(cpw));
 
176
        break;
 
177
 
 
178
#if !(defined(WIN32) || defined(NETWARE))
 
179
    case ALG_CRYPT:
 
180
    default:
 
181
        (void) srand((int) time((time_t *) NULL));
 
182
        to64(&salt[0], rand(), 8);
 
183
        salt[8] = '\0';
 
184
 
 
185
        apr_cpystrn(cpw, (char *)crypt(pw, salt), sizeof(cpw) - 1);
 
186
        break;
 
187
#endif
 
188
    }
 
189
    memset(pw, '\0', strlen(pw));
 
190
 
 
191
    /*
 
192
     * Check to see if the buffer is large enough to hold the username,
 
193
     * hash, and delimiters.
 
194
     */
 
195
    if ((strlen(user) + 1 + strlen(cpw)) > (rlen - 1)) {
 
196
        apr_cpystrn(record, "resultant record too long", (rlen - 1));
 
197
        return ERR_OVERFLOW;
 
198
    }
 
199
    strcpy(record, user);
 
200
    strcat(record, ":");
 
201
    strcat(record, cpw);
 
202
    strcat(record, "\n");
 
203
    return 0;
 
204
}
 
205
 
 
206
static void usage(void)
 
207
{
 
208
    apr_file_printf(errfile, "Usage:" NL);
 
209
    apr_file_printf(errfile, "\thtpasswd [-cmdpsD] passwordfile username" NL);
 
210
    apr_file_printf(errfile, "\thtpasswd -b[cmdpsD] passwordfile username "
 
211
                    "password" NL NL);
 
212
    apr_file_printf(errfile, "\thtpasswd -n[mdps] username" NL);
 
213
    apr_file_printf(errfile, "\thtpasswd -nb[mdps] username password" NL);
 
214
    apr_file_printf(errfile, " -c  Create a new file." NL);
 
215
    apr_file_printf(errfile, " -n  Don't update file; display results on "
 
216
                    "stdout." NL);
 
217
    apr_file_printf(errfile, " -m  Force MD5 encryption of the password"
 
218
#if defined(WIN32) || defined(TPF) || defined(NETWARE)
 
219
        " (default)"
 
220
#endif
 
221
        "." NL);
 
222
    apr_file_printf(errfile, " -d  Force CRYPT encryption of the password"
 
223
#if (!(defined(WIN32) || defined(TPF) || defined(NETWARE)))
 
224
            " (default)"
 
225
#endif
 
226
            "." NL);
 
227
    apr_file_printf(errfile, " -p  Do not encrypt the password (plaintext)." NL);
 
228
    apr_file_printf(errfile, " -s  Force SHA encryption of the password." NL);
 
229
    apr_file_printf(errfile, " -b  Use the password from the command line "
 
230
            "rather than prompting for it." NL);
 
231
    apr_file_printf(errfile, " -D  Delete the specified user." NL);
 
232
    apr_file_printf(errfile,
 
233
            "On Windows, NetWare and TPF systems the '-m' flag is used by "
 
234
            "default." NL);
 
235
    apr_file_printf(errfile,
 
236
            "On all other systems, the '-p' flag will probably not work." NL);
 
237
    exit(ERR_SYNTAX);
 
238
}
 
239
 
 
240
/*
 
241
 * Check to see if the specified file can be opened for the given
 
242
 * access.
 
243
 */
 
244
static int accessible(apr_pool_t *pool, char *fname, int mode)
 
245
{
 
246
    apr_file_t *f = NULL;
 
247
 
 
248
    if (apr_file_open(&f, fname, mode, APR_OS_DEFAULT, pool) != APR_SUCCESS) {
 
249
        return 0;
 
250
    }
 
251
    apr_file_close(f);
 
252
    return 1;
 
253
}
 
254
 
 
255
/*
 
256
 * Return true if the named file exists, regardless of permissions.
 
257
 */
 
258
static int exists(char *fname, apr_pool_t *pool)
 
259
{
 
260
    apr_finfo_t sbuf;
 
261
    apr_status_t check;
 
262
 
 
263
    check = apr_stat(&sbuf, fname, APR_FINFO_TYPE, pool);
 
264
    return ((check || sbuf.filetype != APR_REG) ? 0 : 1);
 
265
}
 
266
 
 
267
static void terminate(void)
 
268
{
 
269
    apr_terminate();
 
270
#ifdef NETWARE
 
271
    pressanykey();
 
272
#endif
 
273
}
 
274
 
 
275
static void check_args(apr_pool_t *pool, int argc, const char *const argv[],
 
276
                       int *alg, int *mask, char **user, char **pwfilename,
 
277
                       char **password)
 
278
{
 
279
    const char *arg;
 
280
    int args_left = 2;
 
281
    int i;
 
282
 
 
283
    /*
 
284
     * Preliminary check to make sure they provided at least
 
285
     * three arguments, we'll do better argument checking as
 
286
     * we parse the command line.
 
287
     */
 
288
    if (argc < 3) {
 
289
        usage();
 
290
    }
 
291
 
 
292
    /*
 
293
     * Go through the argument list and pick out any options.  They
 
294
     * have to precede any other arguments.
 
295
     */
 
296
    for (i = 1; i < argc; i++) {
 
297
        arg = argv[i];
 
298
        if (*arg != '-') {
 
299
            break;
 
300
        }
 
301
        while (*++arg != '\0') {
 
302
            if (*arg == 'c') {
 
303
                *mask |= APHTP_NEWFILE;
 
304
            }
 
305
            else if (*arg == 'n') {
 
306
                *mask |= APHTP_NOFILE;
 
307
                args_left--;
 
308
            }
 
309
            else if (*arg == 'm') {
 
310
                *alg = ALG_APMD5;
 
311
            }
 
312
            else if (*arg == 's') {
 
313
                *alg = ALG_APSHA;
 
314
            }
 
315
            else if (*arg == 'p') {
 
316
                *alg = ALG_PLAIN;
 
317
            }
 
318
            else if (*arg == 'd') {
 
319
                *alg = ALG_CRYPT;
 
320
            }
 
321
            else if (*arg == 'b') {
 
322
                *mask |= APHTP_NONINTERACTIVE;
 
323
                args_left++;
 
324
            }
 
325
            else if (*arg == 'D') {
 
326
                *mask |= APHTP_DELUSER;
 
327
            }
 
328
            else {
 
329
                usage();
 
330
            }
 
331
        }
 
332
    }
 
333
 
 
334
    if ((*mask & APHTP_NEWFILE) && (*mask & APHTP_NOFILE)) {
 
335
        apr_file_printf(errfile, "%s: -c and -n options conflict" NL, argv[0]);
 
336
        exit(ERR_SYNTAX);
 
337
    }
 
338
    if ((*mask & APHTP_NEWFILE) && (*mask & APHTP_DELUSER)) {
 
339
        apr_file_printf(errfile, "%s: -c and -D options conflict" NL, argv[0]);
 
340
        exit(ERR_SYNTAX);
 
341
    }
 
342
    if ((*mask & APHTP_NOFILE) && (*mask & APHTP_DELUSER)) {
 
343
        apr_file_printf(errfile, "%s: -n and -D options conflict" NL, argv[0]);
 
344
        exit(ERR_SYNTAX);
 
345
    }
 
346
    /*
 
347
     * Make sure we still have exactly the right number of arguments left
 
348
     * (the filename, the username, and possibly the password if -b was
 
349
     * specified).
 
350
     */
 
351
    if ((argc - i) != args_left) {
 
352
        usage();
 
353
    }
 
354
 
 
355
    if (*mask & APHTP_NOFILE) {
 
356
        i--;
 
357
    }
 
358
    else {
 
359
        if (strlen(argv[i]) > (APR_PATH_MAX - 1)) {
 
360
            apr_file_printf(errfile, "%s: filename too long" NL, argv[0]);
 
361
            exit(ERR_OVERFLOW);
 
362
        }
 
363
        *pwfilename = apr_pstrdup(pool, argv[i]);
 
364
        if (strlen(argv[i + 1]) > (MAX_STRING_LEN - 1)) {
 
365
            apr_file_printf(errfile, "%s: username too long (> %d)" NL,
 
366
                argv[0], MAX_STRING_LEN - 1);
 
367
            exit(ERR_OVERFLOW);
 
368
        }
 
369
    }
 
370
    *user = apr_pstrdup(pool, argv[i + 1]);
 
371
    if ((arg = strchr(*user, ':')) != NULL) {
 
372
        apr_file_printf(errfile, "%s: username contains illegal "
 
373
                        "character '%c'" NL, argv[0], *arg);
 
374
        exit(ERR_BADUSER);
 
375
    }
 
376
    if (*mask & APHTP_NONINTERACTIVE) {
 
377
        if (strlen(argv[i + 2]) > (MAX_STRING_LEN - 1)) {
 
378
            apr_file_printf(errfile, "%s: password too long (> %d)" NL,
 
379
                argv[0], MAX_STRING_LEN);
 
380
            exit(ERR_OVERFLOW);
 
381
        }
 
382
        *password = apr_pstrdup(pool, argv[i + 2]);
 
383
    }
 
384
}
 
385
 
 
386
/*
 
387
 * Let's do it.  We end up doing a lot of file opening and closing,
 
388
 * but what do we care?  This application isn't run constantly.
 
389
 */
 
390
int main(int argc, const char * const argv[])
 
391
{
 
392
    apr_file_t *fpw = NULL;
 
393
    char record[MAX_STRING_LEN];
 
394
    char line[MAX_STRING_LEN];
 
395
    char *password = NULL;
 
396
    char *pwfilename = NULL;
 
397
    char *user = NULL;
 
398
    char tn[] = "htpasswd.tmp.XXXXXX";
 
399
    char *dirname;
 
400
    char *scratch, cp[MAX_STRING_LEN];
 
401
    int found = 0;
 
402
    int i;
 
403
    int alg = ALG_CRYPT;
 
404
    int mask = 0;
 
405
    apr_pool_t *pool;
 
406
    int existing_file = 0;
 
407
#if APR_CHARSET_EBCDIC
 
408
    apr_status_t rv;
 
409
    apr_xlate_t *to_ascii;
 
410
#endif
 
411
 
 
412
    apr_app_initialize(&argc, &argv, NULL);
 
413
    atexit(terminate);
 
414
    apr_pool_create(&pool, NULL);
 
415
    apr_file_open_stderr(&errfile, pool);
 
416
 
 
417
#if APR_CHARSET_EBCDIC
 
418
    rv = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, pool);
 
419
    if (rv) {
 
420
        apr_file_printf(errfile, "apr_xlate_open(to ASCII)->%d" NL, rv);
 
421
        exit(1);
 
422
    }
 
423
    rv = apr_SHA1InitEBCDIC(to_ascii);
 
424
    if (rv) {
 
425
        apr_file_printf(errfile, "apr_SHA1InitEBCDIC()->%d" NL, rv);
 
426
        exit(1);
 
427
    }
 
428
    rv = apr_MD5InitEBCDIC(to_ascii);
 
429
    if (rv) {
 
430
        apr_file_printf(errfile, "apr_MD5InitEBCDIC()->%d" NL, rv);
 
431
        exit(1);
 
432
    }
 
433
#endif /*APR_CHARSET_EBCDIC*/
 
434
 
 
435
    check_args(pool, argc, argv, &alg, &mask, &user, &pwfilename, &password);
 
436
 
 
437
 
 
438
#if defined(WIN32) || defined(NETWARE)
 
439
    if (alg == ALG_CRYPT) {
 
440
        alg = ALG_APMD5;
 
441
        apr_file_printf(errfile, "Automatically using MD5 format." NL);
 
442
    }
 
443
#endif
 
444
 
 
445
#if (!(defined(WIN32) || defined(TPF) || defined(NETWARE)))
 
446
    if (alg == ALG_PLAIN) {
 
447
        apr_file_printf(errfile,"Warning: storing passwords as plain text "
 
448
                        "might just not work on this platform." NL);
 
449
    }
 
450
#endif
 
451
 
 
452
    /*
 
453
     * Only do the file checks if we're supposed to frob it.
 
454
     */
 
455
    if (!(mask & APHTP_NOFILE)) {
 
456
        existing_file = exists(pwfilename, pool);
 
457
        if (existing_file) {
 
458
            /*
 
459
             * Check that this existing file is readable and writable.
 
460
             */
 
461
            if (!accessible(pool, pwfilename, APR_READ | APR_APPEND)) {
 
462
                apr_file_printf(errfile, "%s: cannot open file %s for "
 
463
                                "read/write access" NL, argv[0], pwfilename);
 
464
                exit(ERR_FILEPERM);
 
465
            }
 
466
        }
 
467
        else {
 
468
            /*
 
469
             * Error out if -c was omitted for this non-existant file.
 
470
             */
 
471
            if (!(mask & APHTP_NEWFILE)) {
 
472
                apr_file_printf(errfile,
 
473
                        "%s: cannot modify file %s; use '-c' to create it" NL,
 
474
                        argv[0], pwfilename);
 
475
                exit(ERR_FILEPERM);
 
476
            }
 
477
            /*
 
478
             * As it doesn't exist yet, verify that we can create it.
 
479
             */
 
480
            if (!accessible(pool, pwfilename, APR_CREATE | APR_WRITE)) {
 
481
                apr_file_printf(errfile, "%s: cannot create file %s" NL,
 
482
                                argv[0], pwfilename);
 
483
                exit(ERR_FILEPERM);
 
484
            }
 
485
        }
 
486
    }
 
487
 
 
488
    /*
 
489
     * All the file access checks (if any) have been made.  Time to go to work;
 
490
     * try to create the record for the username in question.  If that
 
491
     * fails, there's no need to waste any time on file manipulations.
 
492
     * Any error message text is returned in the record buffer, since
 
493
     * the mkrecord() routine doesn't have access to argv[].
 
494
     */
 
495
    if (!(mask & APHTP_DELUSER)) {
 
496
        i = mkrecord(user, record, sizeof(record) - 1,
 
497
                     password, alg);
 
498
        if (i != 0) {
 
499
            apr_file_printf(errfile, "%s: %s" NL, argv[0], record);
 
500
            exit(i);
 
501
        }
 
502
        if (mask & APHTP_NOFILE) {
 
503
            printf("%s" NL, record);
 
504
            exit(0);
 
505
        }
 
506
    }
 
507
 
 
508
    /*
 
509
     * We can access the files the right way, and we have a record
 
510
     * to add or update.  Let's do it..
 
511
     */
 
512
    if (apr_temp_dir_get((const char**)&dirname, pool) != APR_SUCCESS) {
 
513
        apr_file_printf(errfile, "%s: could not determine temp dir" NL,
 
514
                        argv[0]);
 
515
        exit(ERR_FILEPERM);
 
516
    }
 
517
    dirname = apr_psprintf(pool, "%s/%s", dirname, tn);
 
518
 
 
519
    if (apr_file_mktemp(&ftemp, dirname, 0, pool) != APR_SUCCESS) {
 
520
        apr_file_printf(errfile, "%s: unable to create temporary file %s" NL,
 
521
                        argv[0], dirname);
 
522
        exit(ERR_FILEPERM);
 
523
    }
 
524
 
 
525
    /*
 
526
     * If we're not creating a new file, copy records from the existing
 
527
     * one to the temporary file until we find the specified user.
 
528
     */
 
529
    if (existing_file && !(mask & APHTP_NEWFILE)) {
 
530
        if (apr_file_open(&fpw, pwfilename, APR_READ | APR_BUFFERED,
 
531
                          APR_OS_DEFAULT, pool) != APR_SUCCESS) {
 
532
            apr_file_printf(errfile, "%s: unable to read file %s" NL,
 
533
                            argv[0], pwfilename);
 
534
            exit(ERR_FILEPERM);
 
535
        }
 
536
        while (apr_file_gets(line, sizeof(line), fpw) == APR_SUCCESS) {
 
537
            char *colon;
 
538
 
 
539
            strcpy(cp, line);
 
540
            scratch = cp;
 
541
            while (apr_isspace(*scratch)) {
 
542
                ++scratch;
 
543
            }
 
544
 
 
545
            if (!*scratch || (*scratch == '#')) {
 
546
                putline(ftemp, line);
 
547
                continue;
 
548
            }
 
549
            /*
 
550
             * See if this is our user.
 
551
             */
 
552
            colon = strchr(scratch, ':');
 
553
            if (colon != NULL) {
 
554
                *colon = '\0';
 
555
            }
 
556
            else {
 
557
                /*
 
558
                 * If we've not got a colon on the line, this could well
 
559
                 * not be a valid htpasswd file.
 
560
                 * We should bail at this point.
 
561
                 */
 
562
                apr_file_printf(errfile, "%s: The file %s does not appear "
 
563
                                         "to be a valid htpasswd file." NL,
 
564
                                argv[0], pwfilename);
 
565
                apr_file_close(fpw);
 
566
                exit(ERR_INVALID);
 
567
            }
 
568
            if (strcmp(user, scratch) != 0) {
 
569
                putline(ftemp, line);
 
570
                continue;
 
571
            }
 
572
            else {
 
573
                if (!(mask & APHTP_DELUSER)) {
 
574
                    /* We found the user we were looking for.
 
575
                     * Add him to the file.
 
576
                    */
 
577
                    apr_file_printf(errfile, "Updating ");
 
578
                    putline(ftemp, record);
 
579
                    found++;
 
580
                }
 
581
                else {
 
582
                    /* We found the user we were looking for.
 
583
                     * Delete them from the file.
 
584
                     */
 
585
                    apr_file_printf(errfile, "Deleting ");
 
586
                    found++;
 
587
                }
 
588
            }
 
589
        }
 
590
        apr_file_close(fpw);
 
591
    }
 
592
    if (!found && !(mask & APHTP_DELUSER)) {
 
593
        apr_file_printf(errfile, "Adding ");
 
594
        putline(ftemp, record);
 
595
    }
 
596
    else if (!found && (mask & APHTP_DELUSER)) {
 
597
        apr_file_printf(errfile, "User %s not found" NL, user);
 
598
        exit(0);
 
599
    }
 
600
    apr_file_printf(errfile, "password for user %s" NL, user);
 
601
 
 
602
    /* The temporary file has all the data, just copy it to the new location.
 
603
     */
 
604
    if (apr_file_copy(dirname, pwfilename, APR_FILE_SOURCE_PERMS, pool) !=
 
605
        APR_SUCCESS) {
 
606
        apr_file_printf(errfile, "%s: unable to update file %s" NL,
 
607
                        argv[0], pwfilename);
 
608
        exit(ERR_FILEPERM);
 
609
    }
 
610
    apr_file_close(ftemp);
 
611
    return 0;
 
612
}