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