Minor stderr tweak
[mod_fastcgi.git] / fcgi_util.c
blob14cebcfab51a0bce15a978210a9f7edaa6c925bb
1 /*
2 * $Id: fcgi_util.c,v 1.8 1999/10/06 11:42:39 roberts Exp $
3 */
5 #include "fcgi.h"
7 /*******************************************************************************
8 * Compute printable MD5 hash. Pool p is used for scratch as well as for
9 * allocating the hash - use temp storage, and dup it if you need to keep it.
11 char *
12 fcgi_util_socket_hash_filename(pool *p, const char *path,
13 const char *user, const char *group)
15 char *buf = ap_pstrcat(p, path, user, group, NULL);
17 /* Canonicalize the path (remove "//", ".", "..") */
18 ap_getparents(buf);
20 return ap_md5(p, (unsigned char *)buf);
23 /*******************************************************************************
24 * Return absolute path to file in either "regular" FCGI socket directory or
25 * the dynamic directory. Result is allocated in pool p.
27 const char *
28 fcgi_util_socket_make_path_absolute(pool * const p,
29 const char *const file, const int dynamic)
31 return (const char *)ap_pstrcat(p,
32 (dynamic ? fcgi_dynamic_dir : fcgi_socket_dir), "/", file, NULL);
35 /*******************************************************************************
36 * Allocate a new string from pool p with the name of a Unix/Domain socket's
37 * lock file (used by dynamic only).
39 const char *
40 fcgi_util_socket_get_lock_filename(pool *p, const char *socket_path)
42 return ap_pstrcat(p, socket_path, ".lock", NULL);
45 /*******************************************************************************
46 * Build a Domain Socket Address structure, and calculate its size.
47 * The error message is allocated from the pool p. If you don't want the
48 * struct sockaddr_un also allocated from p, pass it preallocated (!=NULL).
50 const char *
51 fcgi_util_socket_make_domain_addr(pool *p, struct sockaddr_un **socket_addr,
52 int *socket_addr_len, const char *socket_path)
54 int socket_pathLen = strlen(socket_path);
56 if (socket_pathLen >= sizeof((*socket_addr)->sun_path)) {
57 return ap_pstrcat(p, "path \"", socket_path,
58 "\" is too long for a Domain socket", NULL);
61 if (*socket_addr == NULL)
62 *socket_addr = ap_pcalloc(p, sizeof(struct sockaddr_un));
63 else
64 memset(*socket_addr, 0, sizeof(struct sockaddr_un));
66 (*socket_addr)->sun_family = AF_UNIX;
67 strcpy((*socket_addr)->sun_path, socket_path);
69 *socket_addr_len = SUN_LEN(*socket_addr);
70 return NULL;
73 /*******************************************************************************
74 * Convert a hostname or IP address string to an in_addr struct.
76 static int
77 convert_string_to_in_addr(const char * const hostname, struct in_addr * const addr)
79 struct hostent *hp;
80 int count;
82 addr->s_addr = inet_addr((char *)hostname);
84 if (addr->s_addr == INADDR_NONE) {
85 if ((hp = gethostbyname((char *)hostname)) == NULL)
86 return -1;
88 memcpy((char *) addr, hp->h_addr, hp->h_length);
89 count = 0;
90 while (hp->h_addr_list[count] != 0)
91 count++;
93 return count;
95 return 1;
99 /*******************************************************************************
100 * Build an Inet Socket Address structure, and calculate its size.
101 * The error message is allocated from the pool p. If you don't want the
102 * struct sockaddr_in also allocated from p, pass it preallocated (!=NULL).
104 const char *
105 fcgi_util_socket_make_inet_addr(pool *p, struct sockaddr_in **socket_addr,
106 int *socket_addr_len, const char *host, int port)
108 if (*socket_addr == NULL)
109 *socket_addr = ap_pcalloc(p, sizeof(struct sockaddr_in));
110 else
111 memset(*socket_addr, 0, sizeof(struct sockaddr_in));
113 (*socket_addr)->sin_family = AF_INET;
114 (*socket_addr)->sin_port = htons(port);
116 /* Get an in_addr represention of the host */
117 if (host != NULL) {
118 if (convert_string_to_in_addr(host, &(*socket_addr)->sin_addr) != 1) {
119 return ap_pstrcat(p, "failed to resolve \"", host,
120 "\" to exactly one IP address", NULL);
122 } else {
123 (*socket_addr)->sin_addr.s_addr = htonl(INADDR_ANY);
126 *socket_addr_len = sizeof(struct sockaddr_in);
127 return NULL;
130 /*******************************************************************************
131 * Determine if a process with uid/gid can access a file with mode permissions.
133 const char *
134 fcgi_util_check_access(pool *tp,
135 const char * const path, const struct stat *statBuf,
136 const int mode, const uid_t uid, const gid_t gid)
138 if (statBuf == NULL) {
139 static struct stat staticStatBuf;
141 if (stat(path, &staticStatBuf) < 0)
142 return ap_psprintf(tp, "stat() failed: %s", strerror(errno));
143 statBuf = &staticStatBuf;
146 /* If the uid owns the file, check the owner bits */
147 if (uid == statBuf->st_uid) {
148 if (mode & R_OK && !(statBuf->st_mode & S_IRUSR))
149 return "read not allowed by owner";
150 if (mode & W_OK && !(statBuf->st_mode & S_IWUSR))
151 return "write not allowed by owner";
152 if (mode & X_OK && !(statBuf->st_mode & S_IXUSR))
153 return "execute not allowed by owner";
154 return NULL;
157 #ifndef __EMX__
158 /* If the gid is same as the file's group, check the group bits */
159 if (gid == statBuf->st_gid) {
160 if (mode & R_OK && !(statBuf->st_mode & S_IRGRP))
161 return "read not allowed by group";
162 if (mode & W_OK && !(statBuf->st_mode & S_IWGRP))
163 return "write not allowed by group";
164 if (mode & X_OK && !(statBuf->st_mode & S_IXGRP))
165 return "execute not allowed by group";
166 return NULL;
169 /* Get the user membership for the file's group. If the
170 * uid is a member, check the group bits. */
172 const struct group * const gr = getgrgid(statBuf->st_gid);
173 const struct passwd * const pw = getpwuid(uid);
175 if (gr != NULL && pw != NULL) {
176 char **user = gr->gr_mem;
177 for ( ; *user != NULL; user++) {
178 if (strcmp(*user, pw->pw_name) == 0) {
179 if (mode & R_OK && !(statBuf->st_mode & S_IRGRP))
180 return "read not allowed by group";
181 if (mode & W_OK && !(statBuf->st_mode & S_IWGRP))
182 return "write not allowed by group";
183 if (mode & X_OK && !(statBuf->st_mode & S_IXGRP))
184 return "execute not allowed by group";
185 return NULL;
191 /* That just leaves the other bits.. */
192 if (mode & R_OK && !(statBuf->st_mode & S_IROTH))
193 return "read not allowed";
194 if (mode & W_OK && !(statBuf->st_mode & S_IWOTH))
195 return "write not allowed";
196 if (mode & X_OK && !(statBuf->st_mode & S_IXOTH))
197 return "execute not allowed";
198 #endif
200 return NULL;
204 /*******************************************************************************
205 * Find a FastCGI server with a matching fs_path, and if fcgi_suexec is
206 * enabled with matching uid and gid.
208 fcgi_server *
209 fcgi_util_fs_get_by_id(const char *ePath, uid_t uid, gid_t gid)
211 char path[FCGI_MAXPATH];
212 fcgi_server *s;
214 /* @@@ This should now be done in the loop below */
215 ap_cpystrn(path, ePath, FCGI_MAXPATH);
216 ap_no2slash(path);
218 for (s = fcgi_servers; s != NULL; s = s->next) {
219 int i;
220 const char *fs_path = s->fs_path;
221 for (i = 0; fs_path[i] && path[i]; ++i) {
222 if (fs_path[i] != path[i]) {
223 break;
226 if (fs_path[i]) {
227 continue;
229 if (path[i] == '\0' || path[i] == '/') {
230 if (fcgi_suexec == NULL || (uid == s->uid && gid == s->gid))
231 return s;
234 return NULL;
237 /*******************************************************************************
238 * Find a FastCGI server with a matching fs_path, and if fcgi_suexec is
239 * enabled with matching user and group.
241 fcgi_server *
242 fcgi_util_fs_get(const char *ePath, const char *user, const char *group)
244 char path[FCGI_MAXPATH];
245 fcgi_server *s;
247 ap_cpystrn(path, ePath, FCGI_MAXPATH);
248 ap_no2slash(path);
250 for (s = fcgi_servers; s != NULL; s = s->next) {
251 if (strcmp(s->fs_path, path) == 0) {
252 if (fcgi_suexec == NULL)
253 return s;
255 if (strcmp(user, s->user) == 0
256 && (user[0] == '~' || strcmp(group, s->group) == 0))
258 return s;
262 return NULL;
265 const char *
266 fcgi_util_fs_is_path_ok(pool * const p, const char * const fs_path,
267 struct stat *finfo, const uid_t uid, const gid_t gid)
269 const char *err;
271 if (finfo == NULL) {
272 finfo = (struct stat *)ap_palloc(p, sizeof(struct stat));
273 if (stat(fs_path, finfo) < 0)
274 return ap_psprintf(p, "stat() failed: %s", strerror(errno));
277 /* No Parse Header scripts aren't allowed.
278 * @@@ Well... we really could quite easily */
279 if (strncmp(strrchr(fs_path, '/'), "/nph-", 5) == 0)
280 return ap_psprintf(p, "NPH scripts cannot be run as FastCGI");
282 if (finfo->st_mode == 0)
283 return ap_psprintf(p, "script not found or unable to stat()");
285 if (S_ISDIR(finfo->st_mode))
286 return ap_psprintf(p, "script is a directory!");
288 if (fcgi_suexec != NULL) {
289 err = fcgi_util_check_access(p, fs_path, finfo, X_OK, uid, gid);
290 if (err) {
291 return ap_psprintf(p,
292 "access for fcgi_suexec (uid %ld, gid %ld) not allowed: %s",
293 (long)uid, (long)gid, err);
296 else {
297 err = fcgi_util_check_access(p, fs_path, finfo, X_OK, fcgi_user_id, fcgi_group_id);
298 if (err) {
299 return ap_psprintf(p,
300 "access for server (uid %ld, gid %ld) not allowed: %s",
301 (long)fcgi_user_id, (long)fcgi_group_id, err);
305 return NULL;
310 /*******************************************************************************
311 * Allocate a new FastCGI server record from pool p with default values.
313 fcgi_server *
314 fcgi_util_fs_new(pool *p)
316 fcgi_server *s = (fcgi_server *) ap_pcalloc(p, sizeof(fcgi_server));
318 /* Initialize anything who's init state is not zeroizzzzed */
319 s->listenQueueDepth = FCGI_DEFAULT_LISTEN_Q;
320 s->appConnectTimeout = FCGI_DEFAULT_APP_CONN_TIMEOUT;
321 s->idle_timeout = FCGI_DEFAULT_IDLE_TIMEOUT;
322 s->initStartDelay = DEFAULT_INIT_START_DELAY;
323 s->restartDelay = FCGI_DEFAULT_RESTART_DELAY;
324 s->restartOnExit = FALSE;
325 s->directive = APP_CLASS_UNKNOWN;
326 s->processPriority = FCGI_DEFAULT_PRIORITY;
327 s->listenFd = -2;
328 s->envp = &fcgi_empty_env;
330 return s;
333 /*******************************************************************************
334 * Add the server to the linked list of FastCGI servers.
336 void
337 fcgi_util_fs_add(fcgi_server *s)
339 s->next = fcgi_servers;
340 fcgi_servers = s;
343 /*******************************************************************************
344 * Configure uid, gid, user, group, username for suexec.
346 const char *
347 fcgi_util_fs_set_uid_n_gid(pool *p, fcgi_server *s, uid_t uid, gid_t gid)
349 struct passwd *pw;
350 struct group *gr;
352 if (fcgi_suexec == NULL)
353 return NULL;
355 s->uid = uid;
356 pw = getpwuid(uid);
357 if (pw == NULL) {
358 return ap_psprintf(p,
359 "getpwuid() couldn't determine the username for uid '%ld', "
360 "you probably need to modify the User directive: %s",
361 (long)uid, strerror(errno));
363 s->user = ap_pstrdup(p, pw->pw_name);
364 s->username = s->user;
366 s->gid = gid;
367 gr = getgrgid(gid);
368 if (gr == NULL) {
369 return ap_psprintf(p,
370 "getgrgid() couldn't determine the group name for gid '%ld', "
371 "you probably need to modify the Group directive: %s",
372 (long)gid, strerror(errno));
374 s->group = ap_pstrdup(p, gr->gr_name);
376 return NULL;
379 /*******************************************************************************
380 * Allocate an array of ServerProcess records.
382 ServerProcess *
383 fcgi_util_fs_create_procs(pool *p, int num)
385 int i;
386 ServerProcess *proc = (ServerProcess *)ap_pcalloc(p, sizeof(ServerProcess) * num);
388 for (i = 0; i < num; i++) {
389 proc[i].pid = 0;
390 proc[i].state = STATE_READY;
392 return proc;
396 *----------------------------------------------------------------------
398 * fcgi_util_lock_fd
400 * Provide file locking via fcntl(2) function call. This
401 * code has been borrowed from Stevens "Advanced Unix
402 * Programming", page 370.
404 * Inputs:
405 * File descriptor to be locked, offsets within the file.
407 * Results:
408 * 0 on successful locking, -1 otherwise
410 * Side effects:
411 * File pointed to by file descriptor is locked or unlocked.
412 * Provided macros allow for both blocking and non-blocking
413 * behavior.
415 *----------------------------------------------------------------------
418 int
419 fcgi_util_lock_fd(int fd, int cmd, int type, off_t offset, int whence, off_t len)
421 struct flock lock;
422 int res;
424 lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
425 lock.l_start = offset; /* byte offset, relative to whence */
426 lock.l_whence = whence; /* SEEK_SET, SEET_CUR, SEEK_END */
427 lock.l_len = len; /* # of bytes, (0 indicates to EOF) */
429 /* Don't be fooled into thinking we've set a lock when we've
430 merely caught a signal. */
432 /* This is OK only if there is a hard_timeout() in effect! */
433 while ((res = fcntl(fd, cmd, &lock)) == -1 && errno == EINTR);
435 return res;