1 /*
2 * htpasswd.c: simple program for manipulating password file for NCSA httpd
3 *
4 * Rob McCool
5 */
6
7 /* Modified 29aug97 by Jef Poskanzer to accept new password on stdin,
8 ** if stdin is a pipe or file. This is necessary for use from CGI.
9 */
10
11 #include <sys/types.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <signal.h>
15 #include <stdlib.h>
16 #include <time.h>
17 #include <unistd.h>
18
19 #include <openssl/ssl.h>
20 #include <openssl/err.h>
21 #include <openssl/des.h>
22 #define crypt(pw,salt) DES_crypt((pw),(salt))
23
24 #define LF 10
25 #define CR 13
26
27 #define MAX_STRING_LEN 256
28
29 int tfd;
30 char temp_template[] = "/tmp/htp.XXXXXX";
31
32 void interrupted(int);
33
34 /* Called by: add_password */
strd(char * s)35 static char * strd(char *s) {
36 char *d;
37
38 d=(char *)malloc(strlen(s) + 1);
39 strcpy(d,s);
40 return(d);
41 }
42
43 /* Called by: main */
getword(char * word,char * line,char stop)44 static void getword(char *word, char *line, char stop) {
45 int x = 0,y;
46
47 for(x=0;((line[x]) && (line[x] != stop));x++)
48 word[x] = line[x];
49
50 word[x] = '\0';
51 if(line[x]) ++x;
52 y=0;
53
54 while((line[y++] = line[x++]));
55 }
56
57 /* Called by: main */
htpasswd_getline(char * s,int n,FILE * f)58 static int htpasswd_getline(char *s, int n, FILE *f) {
59 register int i=0;
60
61 while(1) {
62 s[i] = (char)fgetc(f);
63
64 if(s[i] == CR)
65 s[i] = fgetc(f);
66
67 if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
68 s[i] = '\0';
69 return (feof(f) ? 1 : 0);
70 }
71 ++i;
72 }
73 }
74
75 /* Called by: main x2 */
putline(FILE * f,char * l)76 static void putline(FILE *f,char *l) {
77 int x;
78
79 for(x=0;l[x];x++) fputc(l[x],f);
80 fputc('\n',f);
81 }
82
83
84 /* From local_passwd.c (C) Regents of Univ. of California blah blah */
85 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
86 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
87
88 /* Called by: add_password, zx_md5_crypt x6 */
to64(register char * s,register long v,register int n)89 static void to64(register char *s, register long v, register int n) {
90 while (--n >= 0) {
91 *s++ = itoa64[v&0x3f];
92 v >>= 6;
93 }
94 }
95
96 #ifdef MPE
97 /* MPE lacks getpass() and a way to suppress stdin echo. So for now, just
98 issue the prompt and read the results with echo. (Ugh). */
99
getpass(const char * prompt)100 char *getpass(const char *prompt) {
101
102 static char password[81];
103
104 fputs(prompt,stderr);
105 gets((char *)&password);
106
107 if (strlen((char *)&password) > 8) {
108 password[8]='\0';
109 }
110
111 return (char *)&password;
112 }
113 #endif
114
115 /* Called by: main x3 */
116 static void
add_password(char * user,FILE * f)117 add_password( char* user, FILE* f )
118 {
119 char pass[100];
120 char* pw;
121 char* cpw;
122 char salt[3];
123
124 if ( ! isatty( fileno( stdin ) ) )
125 {
126 (void) fgets( pass, sizeof(pass), stdin );
127 if ( pass[strlen(pass) - 1] == '\n' )
128 pass[strlen(pass) - 1] = '\0';
129 pw = pass;
130 }
131 else
132 {
133 pw = strd( (char*) getpass( "New password:" ) );
134 if ( strcmp( pw, (char*) getpass( "Re-type new password:" ) ) != 0 )
135 {
136 (void) fprintf( stderr, "They don't match, sorry.\n" );
137 if ( tfd != -1 )
138 unlink( temp_template );
139 exit( 1 );
140 }
141 }
142 (void) srandom( (int) time( (time_t*) 0 ) );
143 to64( &salt[0], random(), 2 );
144 cpw = crypt( pw, salt );
145 (void) fprintf( f, "%s:%s\n", user, cpw );
146 }
147
usage(void)148 static void usage(void) {
149 fprintf(stderr,"Usage: htpasswd [-c] passwordfile username\n");
150 fprintf(stderr,"The -c flag creates a new file.\n");
151 exit(1);
152 }
153
154 /* Called by: */
interrupted(int signo)155 void interrupted(int signo) {
156 fprintf(stderr,"Interrupted.\n");
157 if(tfd != -1) unlink(temp_template);
158 exit(1);
159 }
160
161 /* Called by: */
main(int argc,char * argv[])162 int main(int argc, char *argv[]) {
163 FILE *tfp,*f;
164 char user[MAX_STRING_LEN];
165 char line[MAX_STRING_LEN];
166 char l[MAX_STRING_LEN];
167 char w[MAX_STRING_LEN];
168 char command[MAX_STRING_LEN];
169 int found;
170
171 tfd = -1;
172 signal(SIGINT,(void (*)(int))interrupted);
173 if(argc == 4) {
174 if(strcmp(argv[1],"-c"))
175 usage();
176 if(!(tfp = fopen(argv[2],"w"))) {
177 fprintf(stderr,"Could not open passwd file %s for writing.\n",
178 argv[2]);
179 perror("fopen");
180 exit(1);
181 }
182 printf("Adding password for %s.\n",argv[3]);
183 add_password(argv[3],tfp);
184 fclose(tfp);
185 exit(0);
186 } else if(argc != 3) usage();
187
188 tfd = mkstemp(temp_template);
189 if(!(tfp = fdopen(tfd,"w"))) {
190 fprintf(stderr,"Could not open temp file.\n");
191 exit(1);
192 }
193
194 if(!(f = fopen(argv[1],"r"))) {
195 fprintf(stderr,
196 "Could not open passwd file %s for reading.\n",argv[1]);
197 fprintf(stderr,"Use -c option to create new one.\n");
198 exit(1);
199 }
200 strcpy(user,argv[2]);
201
202 found = 0;
203 while(!(htpasswd_getline(line,MAX_STRING_LEN,f))) {
204 if(found || (line[0] == '#') || (!line[0])) {
205 putline(tfp,line);
206 continue;
207 }
208 strcpy(l,line);
209 getword(w,l,':');
210 if(strcmp(user,w)) {
211 putline(tfp,line);
212 continue;
213 }
214 else {
215 printf("Changing password for user %s\n",user);
216 add_password(user,tfp);
217 found = 1;
218 }
219 }
220 if(!found) {
221 printf("Adding user %s\n",user);
222 add_password(user,tfp);
223 }
224 fclose(f);
225 fclose(tfp);
226 sprintf(command,"cp %s %s",temp_template,argv[1]);
227 system(command);
228 unlink(temp_template);
229 exit(0);
230 }
231