]> granicus.if.org Git - apache/blob - support/htdigest.c
fix references / update transformation
[apache] / support / htdigest.c
1 /* Copyright 1999-2004 The Apache Software Foundation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 /******************************************************************************
17  ******************************************************************************
18  * NOTE! This program is not safe as a setuid executable!  Do not make it
19  * setuid!
20  ******************************************************************************
21  *****************************************************************************/
22 /*
23  * htdigest.c: simple program for manipulating digest passwd file for Apache
24  *
25  * by Alexei Kosut, based on htpasswd.c, by Rob McCool
26  */
27
28 #include "apr.h"
29 #include "apr_file_io.h"
30 #include "apr_md5.h"
31 #include "apr_lib.h"            /* for apr_getpass() */
32 #include "apr_general.h"
33 #include "apr_signal.h"
34 #include "apr_strings.h"        /* for apr_pstrdup() */
35
36 #define APR_WANT_STDIO
37 #define APR_WANT_STRFUNC
38 #include "apr_want.h"
39
40 #if APR_HAVE_SYS_TYPES_H
41 #include <sys/types.h>
42 #endif
43 #if APR_HAVE_STDLIB_H
44 #include <stdlib.h>
45 #endif
46
47 #ifdef WIN32
48 #include <conio.h>
49 #endif
50
51
52 #if APR_CHARSET_EBCDIC
53 #define LF '\n'
54 #define CR '\r'
55 #else
56 #define LF 10
57 #define CR 13
58 #endif /* APR_CHARSET_EBCDIC */
59
60 #define MAX_STRING_LEN 256
61
62 apr_file_t *tfp = NULL;
63 apr_file_t *errfile;
64 apr_pool_t *cntxt;
65 #if APR_CHARSET_EBCDIC
66 apr_xlate_t *to_ascii;
67 #endif
68
69 static void cleanup_tempfile_and_exit(int rc)
70 {
71     if (tfp) {
72         apr_file_close(tfp);
73     }
74     exit(rc);
75 }
76
77 static void getword(char *word, char *line, char stop)
78 {
79     int x = 0, y;
80
81     for (x = 0; ((line[x]) && (line[x] != stop)); x++)
82         word[x] = line[x];
83
84     word[x] = '\0';
85     if (line[x])
86         ++x;
87     y = 0;
88
89     while ((line[y++] = line[x++]));
90 }
91
92 static int get_line(char *s, int n, apr_file_t *f)
93 {
94     register int i = 0;
95     char ch;
96     apr_status_t rv = APR_EINVAL;
97
98     while (i < (n - 1) && 
99            ((rv = apr_file_getc(&ch, f)) == APR_SUCCESS) && (ch != '\n')) {
100         s[i++] = ch;
101     }
102     if (ch == '\n')
103         s[i++] = ch;
104     s[i] = '\0';
105
106     if (rv != APR_SUCCESS) 
107         return 1;
108
109     return 0;
110 }
111
112 static void putline(apr_file_t *f, char *l)
113 {
114     int x;
115
116     for (x = 0; l[x]; x++)
117         apr_file_putc(l[x], f);
118 }
119
120
121 static void add_password(const char *user, const char *realm, apr_file_t *f)
122 {
123     char *pw;
124     apr_md5_ctx_t context;
125     unsigned char digest[16];
126     char string[MAX_STRING_LEN];
127     char pwin[MAX_STRING_LEN];
128     char pwv[MAX_STRING_LEN];
129     unsigned int i;
130     apr_size_t len = sizeof(pwin);
131
132     if (apr_password_get("New password: ", pwin, &len) != APR_SUCCESS) {
133         apr_file_printf(errfile, "password too long");
134         cleanup_tempfile_and_exit(5);
135     }
136     len = sizeof(pwin);
137     apr_password_get("Re-type new password: ", pwv, &len);
138     if (strcmp(pwin, pwv) != 0) {
139         apr_file_printf(errfile, "They don't match, sorry.\n");
140         cleanup_tempfile_and_exit(1);
141     }
142     pw = pwin;
143     apr_file_printf(f, "%s:%s:", user, realm);
144
145     /* Do MD5 stuff */
146     sprintf(string, "%s:%s:%s", user, realm, pw);
147
148     apr_md5_init(&context);
149 #if APR_CHARSET_EBCDIC
150     apr_md5_set_xlate(&context, to_ascii);
151 #endif
152     apr_md5_update(&context, (unsigned char *) string, strlen(string));
153     apr_md5_final(digest, &context);
154
155     for (i = 0; i < 16; i++)
156         apr_file_printf(f, "%02x", digest[i]);
157
158     apr_file_printf(f, "\n");
159 }
160
161 static void usage(void)
162 {
163     apr_file_printf(errfile, "Usage: htdigest [-c] passwordfile realm username\n");
164     apr_file_printf(errfile, "The -c flag creates a new file.\n");
165     exit(1);
166 }
167
168 static void interrupted(void)
169 {
170     apr_file_printf(errfile, "Interrupted.\n");
171     cleanup_tempfile_and_exit(1);
172 }
173
174 static void terminate(void)
175 {
176     apr_terminate();
177 #ifdef NETWARE
178     pressanykey();
179 #endif
180 }
181
182 int main(int argc, const char * const argv[])
183 {
184     apr_file_t *f;
185     apr_status_t rv;
186     char tn[] = "htdigest.tmp.XXXXXX";
187     char *dirname;
188     char user[MAX_STRING_LEN];
189     char realm[MAX_STRING_LEN];
190     char line[MAX_STRING_LEN];
191     char l[MAX_STRING_LEN];
192     char w[MAX_STRING_LEN];
193     char x[MAX_STRING_LEN];
194     int found;
195    
196     apr_app_initialize(&argc, &argv, NULL);
197     atexit(terminate); 
198     apr_pool_create(&cntxt, NULL);
199     apr_file_open_stderr(&errfile, cntxt);
200
201 #if APR_CHARSET_EBCDIC
202     rv = apr_xlate_open(&to_ascii, "ISO8859-1", APR_DEFAULT_CHARSET, cntxt);
203     if (rv) {
204         apr_file_printf(errfile, "apr_xlate_open(): %s (%d)\n",
205                 apr_strerror(rv, line, sizeof(line)), rv);
206         exit(1);
207     }
208 #endif
209     
210     apr_signal(SIGINT, (void (*)(int)) interrupted);
211     if (argc == 5) {
212         if (strcmp(argv[1], "-c"))
213             usage();
214         rv = apr_file_open(&f, argv[2], APR_WRITE | APR_CREATE, -1, cntxt);
215         if (rv != APR_SUCCESS) {
216             char errmsg[120];
217
218             apr_file_printf(errfile, "Could not open passwd file %s for writing: %s\n",
219                     argv[2],
220                     apr_strerror(rv, errmsg, sizeof errmsg));
221             exit(1);
222         }
223         apr_file_printf(errfile, "Adding password for %s in realm %s.\n", 
224                     argv[4], argv[3]);
225         add_password(argv[4], argv[3], f);
226         apr_file_close(f);
227         exit(0);
228     }
229     else if (argc != 4)
230         usage();
231
232     if (apr_temp_dir_get((const char**)&dirname, cntxt) != APR_SUCCESS) {
233         apr_file_printf(errfile, "%s: could not determine temp dir\n",
234                         argv[0]);
235         exit(1);
236     }
237     dirname = apr_psprintf(cntxt, "%s/%s", dirname, tn);
238
239     if (apr_file_mktemp(&tfp, dirname, 0, cntxt) != APR_SUCCESS) {
240         apr_file_printf(errfile, "Could not open temp file %s.\n", dirname);
241         exit(1);
242     }
243
244     if (apr_file_open(&f, argv[1], APR_READ, -1, cntxt) != APR_SUCCESS) {
245         apr_file_printf(errfile,
246                 "Could not open passwd file %s for reading.\n", argv[1]);
247         apr_file_printf(errfile, "Use -c option to create new one.\n");
248         cleanup_tempfile_and_exit(1);
249     }
250     apr_cpystrn(user, argv[3], sizeof(user));
251     apr_cpystrn(realm, argv[2], sizeof(realm));
252
253     found = 0;
254     while (!(get_line(line, MAX_STRING_LEN, f))) {
255         if (found || (line[0] == '#') || (!line[0])) {
256             putline(tfp, line);
257             continue;
258         }
259         strcpy(l, line);
260         getword(w, l, ':');
261         getword(x, l, ':');
262         if (strcmp(user, w) || strcmp(realm, x)) {
263             putline(tfp, line);
264             continue;
265         }
266         else {
267             apr_file_printf(errfile, "Changing password for user %s in realm %s\n", 
268                     user, realm);
269             add_password(user, realm, tfp);
270             found = 1;
271         }
272     }
273     if (!found) {
274         apr_file_printf(errfile, "Adding user %s in realm %s\n", user, realm);
275         add_password(user, realm, tfp);
276     }
277     apr_file_close(f);
278
279     /* The temporary file has all the data, just copy it to the new location.
280      */
281     if (apr_file_copy(dirname, argv[1], APR_FILE_SOURCE_PERMS, cntxt) !=
282                 APR_SUCCESS) {
283         apr_file_printf(errfile, "%s: unable to update file %s\n", 
284                         argv[0], argv[1]);
285     }
286     apr_file_close(tfp);
287
288     return 0;
289 }