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