[BACK]Return to htpasswd.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / htpasswd

Annotation of src/usr.bin/htpasswd/htpasswd.c, Revision 1.4

1.4     ! benno       1: /*     $OpenBSD: htpasswd.c,v 1.3 2014/03/17 13:54:58 florian Exp $ */
1.1       florian     2: /*
                      3:  * Copyright (c) 2014 Florian Obser <florian@openbsd.org>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17:
                     18: #include <sys/stat.h>
                     19:
                     20: #include <err.h>
                     21: #include <errno.h>
                     22: #include <limits.h>
                     23: #include <pwd.h>
                     24: #include <readpassphrase.h>
                     25: #include <stdio.h>
                     26: #include <stdlib.h>
                     27: #include <string.h>
                     28: #include <unistd.h>
                     29:
                     30: __dead void    usage(void);
                     31: void           nag(char*);
                     32:
                     33: extern char *__progname;
                     34:
                     35: __dead void
                     36: usage(void)
                     37: {
1.3       florian    38:        fprintf(stderr, "usage: %s [file] login\n", __progname);
1.1       florian    39:        exit(1);
                     40: }
                     41:
                     42: int
                     43: main(int argc, char** argv)
                     44: {
                     45:        FILE *in, *out;
                     46:        size_t linesize;
                     47:        ssize_t linelen;
1.2       florian    48:        mode_t old_umask;
1.1       florian    49:        int fd, loginlen;
                     50:        char hash[_PASSWORD_LEN], *file, *line, *login, pass[1024], pass2[1024];
                     51:        char salt[_PASSWORD_LEN], tmpl[sizeof("/tmp/htpasswd-XXXXXXXXXX")];
                     52:
                     53:        file = NULL;
                     54:        login = NULL;
                     55:        in = NULL;
                     56:        out = NULL;
                     57:        line = NULL;
                     58:        linesize = 0;
                     59:
                     60:        switch (argc) {
                     61:        case 2:
                     62:                if ((loginlen = asprintf(&login, "%s:", argv[1])) == -1)
                     63:                        err(1, "asprintf");
                     64:                break;
                     65:        case 3:
                     66:                file = argv[1];
                     67:                if ((loginlen = asprintf(&login, "%s:", argv[2])) == -1)
                     68:                        err(1, "asprintf");
                     69:                break;
                     70:        default:
                     71:                usage();
                     72:                /* NOT REACHED */
                     73:                break;
                     74:        }
                     75:
                     76:        if (!readpassphrase("Password: ", pass, sizeof(pass), RPP_ECHO_OFF))
                     77:                err(1, "unable to read password");
                     78:        if (!readpassphrase("Retype Password: ", pass2, sizeof(pass2),
                     79:            RPP_ECHO_OFF)) {
                     80:                explicit_bzero(pass, sizeof(pass));
                     81:                err(1, "unable to read password");
                     82:        }
                     83:        if (strcmp(pass, pass2) != 0) {
                     84:                explicit_bzero(pass, sizeof(pass));
                     85:                explicit_bzero(pass2, sizeof(pass2));
                     86:                errx(1, "passwords don't match");
                     87:        }
                     88:
                     89:        explicit_bzero(pass2, sizeof(pass2));
                     90:        if (strlcpy(salt, bcrypt_gensalt(8), sizeof(salt)) >= sizeof(salt))
                     91:                err(1, "salt too long");
                     92:        if (strlcpy(hash, bcrypt(pass, salt), sizeof(hash)) >= sizeof(hash))
                     93:                err(1, "hash too long");
                     94:        explicit_bzero(pass, sizeof(pass));
                     95:
                     96:        if (file == NULL)
                     97:                printf("%s%s\n", login, hash);
                     98:        else {
                     99:                if ((in = fopen(file, "r+")) == NULL) {
                    100:                        if (errno == ENOENT) {
1.2       florian   101:                                old_umask = umask(S_IXUSR|
                    102:                                    S_IWGRP|S_IRGRP|S_IXGRP|
                    103:                                    S_IWOTH|S_IROTH|S_IXOTH);
1.1       florian   104:                                if ((out = fopen(file, "w")) == NULL)
                    105:                                        err(1, "cannot open password file for"
                    106:                                            " reading or writing");
1.2       florian   107:                                umask(old_umask);
1.1       florian   108:                        } else
1.4     ! benno     109:                                err(1, "cannot open password file for"
        !           110:                                        " reading or writing");
1.1       florian   111:                }
                    112:                /* file already exits, copy content and filter login out */
                    113:                if (out == NULL) {
                    114:                        strlcpy(tmpl, "/tmp/htpasswd-XXXXXXXXXX", sizeof(tmpl));
                    115:                        if ((fd = mkstemp(tmpl)) == -1)
                    116:                                err(1, "mkstemp");
                    117:
                    118:                        if ((out = fdopen(fd, "w+")) == NULL)
                    119:                                err(1, "cannot open tempfile");
                    120:
                    121:                        while ((linelen = getline(&line, &linesize, in))
                    122:                            != -1) {
                    123:                                if (strncmp(line, login, loginlen) != 0) {
                    124:                                        if (fprintf(out, "%s", line) == -1)
                    125:                                                err(1, "cannot write to temp "
                    126:                                                    "file");
                    127:                                        nag(line);
                    128:                                }
                    129:                        }
                    130:                }
                    131:                if (fprintf(out, "%s%s\n", login, hash) == -1)
                    132:                        err(1, "cannot write new password hash");
                    133:
                    134:                /* file already exists, overwrite it */
                    135:                if (in != NULL) {
                    136:                        if (fseek(in, 0, SEEK_SET) == -1)
                    137:                                err(1, "cannot seek in password file");
1.4     ! benno     138:                        if (fseek(out, 0, SEEK_SET) == -1)
        !           139:                                err(1, "cannot seek in temp file");
1.1       florian   140:                        if (ftruncate(fileno(in), 0) == -1)
                    141:                                err(1, "cannot truncate password file");
                    142:                        while ((linelen = getline(&line, &linesize, out))
                    143:                            != -1)
                    144:                                if (fprintf(in, "%s", line) == -1)
                    145:                                        err(1, "cannot write to password file");
                    146:                        if (fclose(in) == EOF)
                    147:                                err(1, "cannot close password file");
                    148:                }
                    149:                if (fclose(out) == EOF) {
                    150:                        if (in != NULL)
                    151:                                err(1, "cannot close temp file");
                    152:                        else
                    153:                                err(1, "cannot close password file");
                    154:                }
                    155:                if (in != NULL && unlink(tmpl) == -1)
                    156:                        err(1, "cannot delete temp file (%s)", tmpl);
                    157:        }
                    158:        exit(0);
                    159: }
                    160:
                    161: void
                    162: nag(char* line)
                    163: {
                    164:        char *tok;
                    165:        if (strtok(line, ":") != NULL)
                    166:                if ((tok = strtok(NULL, ":")) != NULL)
                    167:                        if (strncmp(tok, "$2a$", 4) != 0 &&
                    168:                             strncmp(tok, "$2b$", 4) != 0)
                    169:                                fprintf(stderr, "%s doesn't use bcrypt."
                    170:                                    " Update the password.\n", line);
                    171: }