]> granicus.if.org Git - apache/blob - support/htdigest.c
d1fc41800fd35810ed06568de301477f1b4b5e6b
[apache] / support / htdigest.c
1 /* ====================================================================
2  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the Apache Group
19  *    for use in the Apache HTTP server project (http://www.apache.org/)."
20  *
21  * 4. The names "Apache Server" and "Apache Group" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    apache@apache.org.
25  *
26  * 5. Products derived from this software may not be called "Apache"
27  *    nor may "Apache" appear in their names without prior written
28  *    permission of the Apache Group.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the Apache Group
33  *    for use in the Apache HTTP server project (http://www.apache.org/)."
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Group and was originally based
51  * on public domain software written at the National Center for
52  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
53  * For more information on the Apache Group and the Apache HTTP server
54  * project, please see <http://www.apache.org/>.
55  *
56  */
57 /******************************************************************************
58  ******************************************************************************
59  * NOTE! This program is not safe as a setuid executable!  Do not make it
60  * setuid!
61  ******************************************************************************
62  *****************************************************************************/
63 /*
64  * htdigest.c: simple program for manipulating digest passwd file for Apache
65  *
66  * by Alexei Kosut, based on htpasswd.c, by Rob McCool
67  */
68
69 #include "ap_config.h"
70 #include <sys/types.h>
71 #include "ap.h"
72 #include "ap_md5.h"
73 #if defined(MPE) || defined(QNX) || defined(WIN32) || defined(__TANDEM)
74 #include <signal.h>
75 #else
76 #include <sys/signal.h>
77 #endif
78
79 #ifdef WIN32
80 #include <conio.h>
81 #define unlink _unlink
82 #endif
83
84 #ifdef CHARSET_EBCDIC
85 #define LF '\n'
86 #define CR '\r'
87 #else
88 #define LF 10
89 #define CR 13
90 #endif /* CHARSET_EBCDIC */
91
92 #define MAX_STRING_LEN 256
93
94 char *tn;
95
96 static void getword(char *word, char *line, char stop)
97 {
98     int x = 0, y;
99
100     for (x = 0; ((line[x]) && (line[x] != stop)); x++)
101         word[x] = line[x];
102
103     word[x] = '\0';
104     if (line[x])
105         ++x;
106     y = 0;
107
108     while ((line[y++] = line[x++]));
109 }
110
111 static int getline(char *s, int n, FILE *f)
112 {
113     register int i = 0;
114
115     while (1) {
116         s[i] = (char) fgetc(f);
117
118         if (s[i] == CR)
119             s[i] = fgetc(f);
120
121         if ((s[i] == 0x4) || (s[i] == LF) || (i == (n - 1))) {
122             s[i] = '\0';
123             return (feof(f) ? 1 : 0);
124         }
125         ++i;
126     }
127 }
128
129 static void putline(FILE *f, char *l)
130 {
131     int x;
132
133     for (x = 0; l[x]; x++)
134         fputc(l[x], f);
135     fputc('\n', f);
136 }
137
138
139 static void add_password(char *user, char *realm, FILE *f)
140 {
141     char *pw;
142     AP_MD5_CTX context;
143     unsigned char digest[16];
144     char string[MAX_STRING_LEN];
145     char pwin[MAX_STRING_LEN];
146     char pwv[MAX_STRING_LEN];
147     unsigned int i;
148
149     if (ap_getpass("New password: ", pwin, sizeof(pwin)) != 0) {
150         fprintf(stderr, "password too long");
151         exit(5);
152     }
153     ap_getpass("Re-type new password: ", pwv, sizeof(pwv));
154     if (strcmp(pwin, pwv) != 0) {
155         fprintf(stderr, "They don't match, sorry.\n");
156         if (tn) {
157             unlink(tn);
158         }
159         exit(1);
160     }
161     pw = pwin;
162     fprintf(f, "%s:%s:", user, realm);
163
164     /* Do MD5 stuff */
165     sprintf(string, "%s:%s:%s", user, realm, pw);
166
167     ap_MD5Init(&context);
168     ap_MD5Update(&context, (unsigned char *) string, strlen(string));
169     ap_MD5Final(digest, &context);
170
171     for (i = 0; i < 16; i++)
172         fprintf(f, "%02x", digest[i]);
173
174     fprintf(f, "\n");
175 }
176
177 static void usage(void)
178 {
179     fprintf(stderr, "Usage: htdigest [-c] passwordfile realm username\n");
180     fprintf(stderr, "The -c flag creates a new file.\n");
181     exit(1);
182 }
183
184 static void interrupted(void)
185 {
186     fprintf(stderr, "Interrupted.\n");
187     if (tn)
188         unlink(tn);
189     exit(1);
190 }
191
192 int main(int argc, char *argv[])
193 {
194     FILE *tfp, *f;
195     char user[MAX_STRING_LEN];
196     char realm[MAX_STRING_LEN];
197     char line[MAX_STRING_LEN];
198     char l[MAX_STRING_LEN];
199     char w[MAX_STRING_LEN];
200     char x[MAX_STRING_LEN];
201     char command[MAX_STRING_LEN];
202     int found;
203
204     tn = NULL;
205     signal(SIGINT, (void (*)(int)) interrupted);
206     if (argc == 5) {
207         if (strcmp(argv[1], "-c"))
208             usage();
209         if (!(tfp = fopen(argv[2], "w"))) {
210             fprintf(stderr, "Could not open passwd file %s for writing.\n",
211                     argv[2]);
212             perror("fopen");
213             exit(1);
214         }
215         printf("Adding password for %s in realm %s.\n", argv[4], argv[3]);
216         add_password(argv[4], argv[3], tfp);
217         fclose(tfp);
218         exit(0);
219     }
220     else if (argc != 4)
221         usage();
222
223     tn = tmpnam(NULL);
224     if (!(tfp = fopen(tn, "w"))) {
225         fprintf(stderr, "Could not open temp file.\n");
226         exit(1);
227     }
228
229     if (!(f = fopen(argv[1], "r"))) {
230         fprintf(stderr,
231                 "Could not open passwd file %s for reading.\n", argv[1]);
232         fprintf(stderr, "Use -c option to create new one.\n");
233         exit(1);
234     }
235     strcpy(user, argv[3]);
236     strcpy(realm, argv[2]);
237
238     found = 0;
239     while (!(getline(line, MAX_STRING_LEN, f))) {
240         if (found || (line[0] == '#') || (!line[0])) {
241             putline(tfp, line);
242             continue;
243         }
244         strcpy(l, line);
245         getword(w, l, ':');
246         getword(x, l, ':');
247         if (strcmp(user, w) || strcmp(realm, x)) {
248             putline(tfp, line);
249             continue;
250         }
251         else {
252             printf("Changing password for user %s in realm %s\n", user, realm);
253             add_password(user, realm, tfp);
254             found = 1;
255         }
256     }
257     if (!found) {
258         printf("Adding user %s in realm %s\n", user, realm);
259         add_password(user, realm, tfp);
260     }
261     fclose(f);
262     fclose(tfp);
263 #if defined(OS2) || defined(WIN32)
264     sprintf(command, "copy \"%s\" \"%s\"", tn, argv[1]);
265 #else
266     sprintf(command, "cp %s %s", tn, argv[1]);
267 #endif
268     system(command);
269     unlink(tn);
270     return 0;
271 }