initial capture of my stuff
[rrq/thttpd.git] / extras / makeweb.c
1 /* makeweb.c - let a user create a web subdirectory
2 **
3 ** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
4 ** All rights reserved.
5 **
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions
8 ** are met:
9 ** 1. Redistributions of source code must retain the above copyright
10 **    notice, this list of conditions and the following disclaimer.
11 ** 2. Redistributions in binary form must reproduce the above copyright
12 **    notice, this list of conditions and the following disclaimer in the
13 **    documentation and/or other materials provided with the distribution.
14 ** 
15 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 ** SUCH DAMAGE.
26 */
27
28 /* This is intended to be installed setgid to a group that has
29 ** write access to the system web directory.  It allows any user
30 ** to create a subdirectory there.  It also makes a symbolic link
31 ** in the user's home directory pointing at the new web subdir.
32 */
33
34
35 #include "../config.h"
36
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <pwd.h>
42 #include <errno.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45
46
47 #define LINK "public_html"
48
49 static char* argv0;
50
51
52 static void
53 check_room( int size, int len )
54     {
55     if ( len > size )
56         {
57         (void) fprintf( stderr, "%s: internal error, out of room\n", argv0 );
58         exit( 1 );
59         }
60     }
61
62
63 static void
64 end_with_slash( char* str )
65     {
66     if ( str[strlen( str ) - 1] != '/' )
67         (void) strcat( str, "/" );
68     }
69
70
71 static void
72 check_dir( char* dirname, uid_t uid, gid_t gid )
73     {
74     struct stat sb;
75
76     /* Check the directory. */
77     if ( stat( dirname, &sb ) < 0 )
78         {
79         if ( errno != ENOENT )
80             {
81             perror( dirname );
82             exit( 1 );
83             }
84         /* Doesn't exist.  Try to make it. */
85         if ( mkdir( dirname, 0755 ) < 0 )
86             {
87             if ( errno == ENOENT )
88                 (void) printf( "\
89 Some part of the path %s does not exist.\n\
90 This is probably a configuration error.\n", dirname );
91             else
92                 perror( dirname );
93             exit( 1 );
94             }
95         (void) printf( "Created web directory %s\n", dirname );
96         /* Try to change the group of the new dir to the user's group. */
97         (void) chown( dirname, -1, gid );
98         }
99     else
100         {
101         /* The directory already exists.  Well, check that it is in
102         ** fact a directory.
103         */
104         if ( ! S_ISDIR( sb.st_mode ) )
105             {
106             (void) printf(
107                 "%s already exists but is not a directory!\n", dirname );
108             exit( 1 );
109             }
110         if ( sb.st_uid != uid )
111             {
112             (void) printf(
113                 "%s already exists but you don't own it!\n", dirname );
114             exit( 1 );
115             }
116         (void) printf( "Web directory %s already existed.\n", dirname );
117         }
118     }
119
120
121 int
122 main( int argc, char** argv )
123     {
124     char* webdir;
125     char* prefix;
126     struct passwd* pwd;
127     char* username;
128     char* homedir;
129     char dirname[5000];
130     char linkname[5000];
131     char linkbuf[5000];
132     struct stat sb;
133
134     argv0 = argv[0];
135     if ( argc != 1 )
136         {
137         (void) fprintf( stderr, "usage:  %s\n", argv0 );
138         exit( 1 );
139         }
140
141     pwd = getpwuid( getuid() );
142     if ( pwd == (struct passwd*) 0 )
143         {
144         (void) fprintf( stderr, "%s: can't find your username\n", argv0 );
145         exit( 1 );
146         }
147     username = pwd->pw_name;
148     homedir = pwd->pw_dir;
149
150 #ifdef TILDE_MAP_2
151
152     /* All we have to do for the TILDE_MAP_2 case is make sure there's
153     ** a public_html subdirectory.
154     */
155     check_room(
156         sizeof(dirname), strlen( homedir ) + strlen( TILDE_MAP_2 ) + 2 );
157     (void) strcpy( dirname, homedir );
158     end_with_slash( dirname );
159     (void) strcat( dirname, TILDE_MAP_2 );
160
161     check_dir( dirname, pwd->pw_uid, pwd->pw_gid );
162
163 #else /* TILDE_MAP_2 */
164
165     /* Gather the pieces. */
166     webdir = WEBDIR;
167 #ifdef TILDE_MAP_1
168     prefix = TILDE_MAP_1;
169 #else /* TILDE_MAP_1 */
170     prefix = "";
171 #endif /* TILDE_MAP_1 */
172
173     /* Assemble the directory name.  Be paranoid cause we're sgid. */
174     check_room(
175         sizeof(dirname),
176         strlen( webdir ) + strlen( prefix ) + strlen( username ) + 3 );
177     (void) strcpy( dirname, webdir );
178     end_with_slash( dirname );
179     if ( strlen( prefix ) != 0 )
180         {
181         (void) strcat( dirname, prefix );
182         end_with_slash( dirname );
183         }
184     (void) strcat( dirname, username );
185
186     /* Assemble the link name. */
187     check_room( sizeof(linkname), strlen( homedir ) + strlen( LINK ) + 2 );
188     (void) strcpy( linkname, homedir );
189     end_with_slash( linkname );
190     (void) strcat( linkname, LINK );
191
192     check_dir( dirname, pwd->pw_uid, pwd->pw_gid );
193
194     /* Check the symlink. */
195     try_link_again: ;
196     if ( lstat( linkname, &sb ) < 0 )
197         {
198         if ( errno != ENOENT )
199             {
200             perror( linkname );
201             exit( 1 );
202             }
203         /* Doesn't exist.  Try to make it. */
204         if ( symlink( dirname, linkname ) < 0 )
205             {
206             if ( errno == ENOENT )
207                 (void) printf( "\
208 Some part of the path %s does not exist.\n\
209 This is probably a configuration error.\n", linkname );
210             else
211                 perror( linkname );
212             exit( 1 );
213             }
214         (void) printf( "Created symbolic link %s\n", linkname );
215         }
216     else
217         {
218         /* The link already exists.  Well, check that it is in
219         ** fact a link.
220         */
221         if ( ! S_ISLNK( sb.st_mode ) )
222             {
223             (void) printf( "\
224 %s already exists but is not a\n\
225 symbolic link!  Perhaps you have a real web subdirectory in your\n\
226 home dir from a previous web server configuration?  You may have\n\
227 to rename it, run %s again, and then copy in the old\n\
228 contents.\n", linkname, argv0 );
229             exit( 1 );
230             }
231         /* Check the existing link's contents. */
232         if ( readlink( linkname, linkbuf, sizeof(linkbuf) ) < 0 )
233             {
234             perror( linkname );
235             exit( 1 );
236             }
237         if ( strcmp( dirname, linkbuf ) == 0 )
238             (void) printf( "Symbolic link %s already existed.\n", linkname );
239         else
240             {
241             (void) printf( "\
242 Symbolic link %s already existed\n\
243 but it points to the wrong place!  Attempting to remove and\n\
244 recreate it.\n", linkname );
245             if ( unlink( linkname ) < 0 )
246                 {
247                 perror( linkname );
248                 exit( 1 );
249                 }
250             goto try_link_again;
251             }
252         }
253 #endif /* TILDE_MAP_2 */
254
255     exit( 0 );
256     }