| 1 |
/* makeweb.c - let a user create a web subdirectory |
| 2 |
** |
| 3 |
** Copyright © 1995 by Jef Poskanzer <jef@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 <stdio.h> |
| 38 |
#include <string.h> |
| 39 |
#include <pwd.h> |
| 40 |
#include <errno.h> |
| 41 |
#include <unistd.h> |
| 42 |
#include <sys/types.h> |
| 43 |
#include <sys/stat.h> |
| 44 |
|
| 45 |
|
| 46 |
#define LINK "public_html" |
| 47 |
|
| 48 |
static char* argv0; |
| 49 |
|
| 50 |
|
| 51 |
static void |
| 52 |
check_room( int size, int len ) |
| 53 |
{ |
| 54 |
if ( len > size ) |
| 55 |
{ |
| 56 |
(void) fprintf( stderr, "%s: internal error, out of room\n", argv0 ); |
| 57 |
exit( 1 ); |
| 58 |
} |
| 59 |
} |
| 60 |
|
| 61 |
|
| 62 |
static void |
| 63 |
end_with_slash( char* str ) |
| 64 |
{ |
| 65 |
if ( str[strlen( str ) - 1] != '/' ) |
| 66 |
(void) strcat( str, "/" ); |
| 67 |
} |
| 68 |
|
| 69 |
|
| 70 |
static void |
| 71 |
check_dir( char* dirname, uid_t uid, gid_t gid ) |
| 72 |
{ |
| 73 |
struct stat sb; |
| 74 |
|
| 75 |
/* Check the directory. */ |
| 76 |
if ( stat( dirname, &sb ) < 0 ) |
| 77 |
{ |
| 78 |
if ( errno != ENOENT ) |
| 79 |
{ |
| 80 |
perror( dirname ); |
| 81 |
exit( 1 ); |
| 82 |
} |
| 83 |
/* Doesn't exist. Try to make it. */ |
| 84 |
if ( mkdir( dirname, 0755 ) < 0 ) |
| 85 |
{ |
| 86 |
if ( errno == ENOENT ) |
| 87 |
(void) printf( "\ |
| 88 |
Some part of the path %s does not exist.\n\ |
| 89 |
This is probably a configuration error.\n", dirname ); |
| 90 |
else |
| 91 |
perror( dirname ); |
| 92 |
exit( 1 ); |
| 93 |
} |
| 94 |
(void) printf( "Created web directory %s\n", dirname ); |
| 95 |
/* Try to change the group of the new dir to the user's group. */ |
| 96 |
(void) chown( dirname, -1, gid ); |
| 97 |
} |
| 98 |
else |
| 99 |
{ |
| 100 |
/* The directory already exists. Well, check that it is in |
| 101 |
** fact a directory. |
| 102 |
*/ |
| 103 |
if ( ! S_ISDIR( sb.st_mode ) ) |
| 104 |
{ |
| 105 |
(void) printf( |
| 106 |
"%s already exists but is not a directory!\n", dirname ); |
| 107 |
exit( 1 ); |
| 108 |
} |
| 109 |
if ( sb.st_uid != uid ) |
| 110 |
{ |
| 111 |
(void) printf( |
| 112 |
"%s already exists but you don't own it!\n", dirname ); |
| 113 |
exit( 1 ); |
| 114 |
} |
| 115 |
(void) printf( "Web directory %s already existed.\n", dirname ); |
| 116 |
} |
| 117 |
} |
| 118 |
|
| 119 |
|
| 120 |
int |
| 121 |
main( int argc, char** argv ) |
| 122 |
{ |
| 123 |
char* webdir; |
| 124 |
char* prefix; |
| 125 |
struct passwd* pwd; |
| 126 |
char* username; |
| 127 |
char* homedir; |
| 128 |
char dirname[5000]; |
| 129 |
char linkname[5000]; |
| 130 |
char linkbuf[5000]; |
| 131 |
struct stat sb; |
| 132 |
|
| 133 |
argv0 = argv[0]; |
| 134 |
if ( argc != 1 ) |
| 135 |
{ |
| 136 |
(void) fprintf( stderr, "usage: %s\n", argv0 ); |
| 137 |
exit( 1 ); |
| 138 |
} |
| 139 |
|
| 140 |
pwd = getpwuid( getuid() ); |
| 141 |
if ( pwd == (struct passwd*) 0 ) |
| 142 |
{ |
| 143 |
(void) fprintf( stderr, "%s: can't find your username\n", argv0 ); |
| 144 |
exit( 1 ); |
| 145 |
} |
| 146 |
username = pwd->pw_name; |
| 147 |
homedir = pwd->pw_dir; |
| 148 |
|
| 149 |
#ifdef TILDE_MAP_2 |
| 150 |
|
| 151 |
/* All we have to do for the TILDE_MAP_2 case is make sure there's |
| 152 |
** a public_html subdirectory. |
| 153 |
*/ |
| 154 |
check_room( |
| 155 |
sizeof(dirname), strlen( homedir ) + strlen( TILDE_MAP_2 ) + 2 ); |
| 156 |
(void) strcpy( dirname, homedir ); |
| 157 |
end_with_slash( dirname ); |
| 158 |
(void) strcat( dirname, TILDE_MAP_2 ); |
| 159 |
|
| 160 |
check_dir( dirname, pwd->pw_uid, pwd->pw_gid ); |
| 161 |
|
| 162 |
#else /* TILDE_MAP_2 */ |
| 163 |
|
| 164 |
/* Gather the pieces. */ |
| 165 |
webdir = WEBDIR; |
| 166 |
#ifdef TILDE_MAP_1 |
| 167 |
prefix = TILDE_MAP_1; |
| 168 |
#else /* TILDE_MAP_1 */ |
| 169 |
prefix = ""; |
| 170 |
#endif /* TILDE_MAP_1 */ |
| 171 |
|
| 172 |
/* Assemble the directory name. Be paranoid cause we're sgid. */ |
| 173 |
check_room( |
| 174 |
sizeof(dirname), |
| 175 |
strlen( webdir ) + strlen( prefix ) + strlen( username ) + 3 ); |
| 176 |
(void) strcpy( dirname, webdir ); |
| 177 |
end_with_slash( dirname ); |
| 178 |
if ( strlen( prefix ) != 0 ) |
| 179 |
{ |
| 180 |
(void) strcat( dirname, prefix ); |
| 181 |
end_with_slash( dirname ); |
| 182 |
} |
| 183 |
(void) strcat( dirname, username ); |
| 184 |
|
| 185 |
/* Assemble the link name. */ |
| 186 |
check_room( sizeof(linkname), strlen( homedir ) + strlen( LINK ) + 2 ); |
| 187 |
(void) strcpy( linkname, homedir ); |
| 188 |
end_with_slash( linkname ); |
| 189 |
(void) strcat( linkname, LINK ); |
| 190 |
|
| 191 |
check_dir( dirname, pwd->pw_uid, pwd->pw_gid ); |
| 192 |
|
| 193 |
/* Check the symlink. */ |
| 194 |
try_link_again: ; |
| 195 |
if ( lstat( linkname, &sb ) < 0 ) |
| 196 |
{ |
| 197 |
if ( errno != ENOENT ) |
| 198 |
{ |
| 199 |
perror( linkname ); |
| 200 |
exit( 1 ); |
| 201 |
} |
| 202 |
/* Doesn't exist. Try to make it. */ |
| 203 |
if ( symlink( dirname, linkname ) < 0 ) |
| 204 |
{ |
| 205 |
if ( errno == ENOENT ) |
| 206 |
(void) printf( "\ |
| 207 |
Some part of the path %s does not exist.\n\ |
| 208 |
This is probably a configuration error.\n", linkname ); |
| 209 |
else |
| 210 |
perror( linkname ); |
| 211 |
exit( 1 ); |
| 212 |
} |
| 213 |
(void) printf( "Created symbolic link %s\n", linkname ); |
| 214 |
} |
| 215 |
else |
| 216 |
{ |
| 217 |
/* The link already exists. Well, check that it is in |
| 218 |
** fact a link. |
| 219 |
*/ |
| 220 |
if ( ! S_ISLNK( sb.st_mode ) ) |
| 221 |
{ |
| 222 |
(void) printf( "\ |
| 223 |
%s already exists but is not a\n\ |
| 224 |
symbolic link! Perhaps you have a real web subdirectory in your\n\ |
| 225 |
home dir from a previous web server configuration? You may have\n\ |
| 226 |
to rename it, run %s again, and then copy in the old\n\ |
| 227 |
contents.\n", linkname, argv0 ); |
| 228 |
exit( 1 ); |
| 229 |
} |
| 230 |
/* Check the existing link's contents. */ |
| 231 |
if ( readlink( linkname, linkbuf, sizeof(linkbuf) ) < 0 ) |
| 232 |
{ |
| 233 |
perror( linkname ); |
| 234 |
exit( 1 ); |
| 235 |
} |
| 236 |
if ( strcmp( dirname, linkbuf ) == 0 ) |
| 237 |
(void) printf( "Symbolic link %s already existed.\n", linkname ); |
| 238 |
else |
| 239 |
{ |
| 240 |
(void) printf( "\ |
| 241 |
Symbolic link %s already existed\n\ |
| 242 |
but it points to the wrong place! Attempting to remove and\n\ |
| 243 |
recreate it.\n", linkname ); |
| 244 |
if ( unlink( linkname ) < 0 ) |
| 245 |
{ |
| 246 |
perror( linkname ); |
| 247 |
exit( 1 ); |
| 248 |
} |
| 249 |
goto try_link_again; |
| 250 |
} |
| 251 |
} |
| 252 |
#endif /* TILDE_MAP_2 */ |
| 253 |
|
| 254 |
exit( 0 ); |
| 255 |
} |