/* makeweb.c - let a user create a web subdirectory ** ** Copyright © 1995 by Jef Poskanzer . ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions ** are met: ** 1. Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. */ /* This is intended to be installed setgid to a group that has ** write access to the system web directory. It allows any user ** to create a subdirectory there. It also makes a symbolic link ** in the user's home directory pointing at the new web subdir. */ #include "../config.h" #include #include #include #include #include #include #include #include #define LINK "public_html" static char* argv0; static void check_room( int size, int len ) { if ( len > size ) { (void) fprintf( stderr, "%s: internal error, out of room\n", argv0 ); exit( 1 ); } } static void end_with_slash( char* str ) { if ( str[strlen( str ) - 1] != '/' ) (void) strcat( str, "/" ); } static void check_dir( char* dirname, uid_t uid, gid_t gid ) { struct stat sb; /* Check the directory. */ if ( stat( dirname, &sb ) < 0 ) { if ( errno != ENOENT ) { perror( dirname ); exit( 1 ); } /* Doesn't exist. Try to make it. */ if ( mkdir( dirname, 0755 ) < 0 ) { if ( errno == ENOENT ) (void) printf( "\ Some part of the path %s does not exist.\n\ This is probably a configuration error.\n", dirname ); else perror( dirname ); exit( 1 ); } (void) printf( "Created web directory %s\n", dirname ); /* Try to change the group of the new dir to the user's group. */ (void) chown( dirname, -1, gid ); } else { /* The directory already exists. Well, check that it is in ** fact a directory. */ if ( ! S_ISDIR( sb.st_mode ) ) { (void) printf( "%s already exists but is not a directory!\n", dirname ); exit( 1 ); } if ( sb.st_uid != uid ) { (void) printf( "%s already exists but you don't own it!\n", dirname ); exit( 1 ); } (void) printf( "Web directory %s already existed.\n", dirname ); } } int main( int argc, char** argv ) { char* webdir; char* prefix; struct passwd* pwd; char* username; char* homedir; char dirname[5000]; char linkname[5000]; char linkbuf[5000]; struct stat sb; argv0 = argv[0]; if ( argc != 1 ) { (void) fprintf( stderr, "usage: %s\n", argv0 ); exit( 1 ); } pwd = getpwuid( getuid() ); if ( pwd == (struct passwd*) 0 ) { (void) fprintf( stderr, "%s: can't find your username\n", argv0 ); exit( 1 ); } username = pwd->pw_name; homedir = pwd->pw_dir; #ifdef TILDE_MAP_2 /* All we have to do for the TILDE_MAP_2 case is make sure there's ** a public_html subdirectory. */ check_room( sizeof(dirname), strlen( homedir ) + strlen( TILDE_MAP_2 ) + 2 ); (void) strcpy( dirname, homedir ); end_with_slash( dirname ); (void) strcat( dirname, TILDE_MAP_2 ); check_dir( dirname, pwd->pw_uid, pwd->pw_gid ); #else /* TILDE_MAP_2 */ /* Gather the pieces. */ webdir = WEBDIR; #ifdef TILDE_MAP_1 prefix = TILDE_MAP_1; #else /* TILDE_MAP_1 */ prefix = ""; #endif /* TILDE_MAP_1 */ /* Assemble the directory name. Be paranoid cause we're sgid. */ check_room( sizeof(dirname), strlen( webdir ) + strlen( prefix ) + strlen( username ) + 3 ); (void) strcpy( dirname, webdir ); end_with_slash( dirname ); if ( strlen( prefix ) != 0 ) { (void) strcat( dirname, prefix ); end_with_slash( dirname ); } (void) strcat( dirname, username ); /* Assemble the link name. */ check_room( sizeof(linkname), strlen( homedir ) + strlen( LINK ) + 2 ); (void) strcpy( linkname, homedir ); end_with_slash( linkname ); (void) strcat( linkname, LINK ); check_dir( dirname, pwd->pw_uid, pwd->pw_gid ); /* Check the symlink. */ try_link_again: ; if ( lstat( linkname, &sb ) < 0 ) { if ( errno != ENOENT ) { perror( linkname ); exit( 1 ); } /* Doesn't exist. Try to make it. */ if ( symlink( dirname, linkname ) < 0 ) { if ( errno == ENOENT ) (void) printf( "\ Some part of the path %s does not exist.\n\ This is probably a configuration error.\n", linkname ); else perror( linkname ); exit( 1 ); } (void) printf( "Created symbolic link %s\n", linkname ); } else { /* The link already exists. Well, check that it is in ** fact a link. */ if ( ! S_ISLNK( sb.st_mode ) ) { (void) printf( "\ %s already exists but is not a\n\ symbolic link! Perhaps you have a real web subdirectory in your\n\ home dir from a previous web server configuration? You may have\n\ to rename it, run %s again, and then copy in the old\n\ contents.\n", linkname, argv0 ); exit( 1 ); } /* Check the existing link's contents. */ if ( readlink( linkname, linkbuf, sizeof(linkbuf) ) < 0 ) { perror( linkname ); exit( 1 ); } if ( strcmp( dirname, linkbuf ) == 0 ) (void) printf( "Symbolic link %s already existed.\n", linkname ); else { (void) printf( "\ Symbolic link %s already existed\n\ but it points to the wrong place! Attempting to remove and\n\ recreate it.\n", linkname ); if ( unlink( linkname ) < 0 ) { perror( linkname ); exit( 1 ); } goto try_link_again; } } #endif /* TILDE_MAP_2 */ exit( 0 ); }