This is util.c in view mode; [Download] [Up]
/* ====================================================================
* Copyright (c) 1995-1997 The Apache Group. 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.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 5. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED 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 APACHE GROUP OR
* ITS 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 software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
/*
* util.c: string utility things
*
* 3/21/93 Rob McCool
* 1995-96 Many changes by the Apache Group
*
*/
#include "httpd.h"
#include "http_conf_globals.h" /* for user_id & group_id */
const char month_snames[12][4] = {
"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};
API_EXPORT(char *) get_time() {
time_t t;
char *time_string;
t=time(NULL);
time_string = ctime(&t);
time_string[strlen(time_string) - 1] = '\0';
return (time_string);
}
API_EXPORT(char *) ht_time(pool *p, time_t t, const char *fmt, int gmt) {
char ts[MAX_STRING_LEN];
struct tm *tms;
tms = (gmt ? gmtime(&t) : localtime(&t));
/* check return code? */
strftime(ts,MAX_STRING_LEN,fmt,tms);
return pstrdup (p, ts);
}
API_EXPORT(char *) gm_timestr_822(pool *p, time_t sec) {
static const char *const days[7]=
{"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
char ts[50];
struct tm *tms;
tms = gmtime(&sec);
/* RFC date format; as strftime '%a, %d %b %Y %T GMT' */
ap_snprintf(ts, sizeof(ts),
"%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday],
tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900,
tms->tm_hour, tms->tm_min, tms->tm_sec);
return pstrdup (p, ts);
}
/* What a pain in the ass. */
#if defined(HAVE_GMTOFF)
API_EXPORT(struct tm *) get_gmtoff(int *tz) {
time_t tt = time(NULL);
struct tm *t;
t = localtime(&tt);
*tz = (int) (t->tm_gmtoff / 60);
return t;
}
#else
API_EXPORT(struct tm *) get_gmtoff(int *tz) {
time_t tt = time(NULL);
struct tm gmt;
struct tm *t;
int days, hours, minutes;
/* Assume we are never more than 24 hours away. */
gmt = *gmtime(&tt); /* remember gmtime/localtime return ptr to static */
t = localtime(&tt); /* buffer... so be careful */
days = t->tm_yday - gmt.tm_yday;
hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
+ t->tm_hour - gmt.tm_hour);
minutes = hours * 60 + t->tm_min - gmt.tm_min;
*tz = minutes;
return t;
}
#endif
/* Match = 0, NoMatch = 1, Abort = -1 */
/* Based loosely on sections of wildmat.c by Rich Salz
* Hmmm... shouldn't this really go component by component?
*/
API_EXPORT(int) strcmp_match(const char *str, const char *exp) {
int x,y;
for(x=0,y=0;exp[y];++y,++x) {
if((!str[x]) && (exp[y] != '*'))
return -1;
if(exp[y] == '*') {
while(exp[++y] == '*');
if(!exp[y])
return 0;
while(str[x]) {
int ret;
if((ret = strcmp_match(&str[x++],&exp[y])) != 1)
return ret;
}
return -1;
} else
if((exp[y] != '?') && (str[x] != exp[y]))
return 1;
}
return (str[x] != '\0');
}
API_EXPORT(int) strcasecmp_match(const char *str, const char *exp) {
int x,y;
for(x=0,y=0;exp[y];++y,++x) {
if((!str[x]) && (exp[y] != '*'))
return -1;
if(exp[y] == '*') {
while(exp[++y] == '*');
if(!exp[y])
return 0;
while(str[x]) {
int ret;
if((ret = strcasecmp_match(&str[x++],&exp[y])) != 1)
return ret;
}
return -1;
} else
if((exp[y] != '?') && (tolower(str[x]) != tolower(exp[y])))
return 1;
}
return (str[x] != '\0');
}
API_EXPORT(int) is_matchexp(const char *str) {
register int x;
for(x=0;str[x];x++)
if((str[x] == '*') || (str[x] == '?'))
return 1;
return 0;
}
/* This function substitutes for $0-$9, filling in regular expression
* submatches. Pass it the same nmatch and pmatch arguments that you
* passed regexec(). pmatch should not be greater than the maximum number
* of subexpressions - i.e. one more than the re_nsub member of regex_t.
*
* input should be the string with the $-expressions, source should be the
* string that was matched against.
*
* It returns the substituted string, or NULL on error.
*
* Parts of this code are based on Henry Spencer's regsub(), from his
* AT&T V8 regexp package.
*/
API_EXPORT(char *) pregsub(pool *p, const char *input, const char *source,
size_t nmatch, regmatch_t pmatch[]) {
const char *src = input;
char *dest, *dst;
char c;
size_t no;
int len;
if (!source) return NULL;
if (!nmatch) return pstrdup(p, src);
/* First pass, find the size */
len = 0;
while ((c = *src++) != '\0') {
if (c == '&')
no = 0;
else if (c == '$' && isdigit(*src))
no = *src++ - '0';
else
no = 10;
if (no > 9) { /* Ordinary character. */
if (c == '\\' && (*src == '$' || *src == '&'))
c = *src++;
len++;
} else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
len += pmatch[no].rm_eo - pmatch[no].rm_so;
}
}
dest = dst = pcalloc(p, len + 1);
/* Now actually fill in the string */
src = input;
while ((c = *src++) != '\0') {
if (c == '&')
no = 0;
else if (c == '$' && isdigit(*src))
no = *src++ - '0';
else
no = 10;
if (no > 9) { /* Ordinary character. */
if (c == '\\' && (*src == '$' || *src == '&'))
c = *src++;
*dst++ = c;
} else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
len = pmatch[no].rm_eo - pmatch[no].rm_so;
strncpy(dst, source + pmatch[no].rm_so, len);
dst += len;
if (*(dst-1) == '\0') /* strncpy hit NULL. */
return NULL;
}
}
*dst = '\0';
return dest;
}
/*
* Parse .. so we don't compromise security
*/
API_EXPORT(void) getparents(char *name)
{
int l, w;
/* Four paseses, as per RFC 1808 */
/* a) remove ./ path segments */
for (l=0, w=0; name[l] != '\0';)
{
if (name[l] == '.' && name[l+1] == '/' && (l == 0 || name[l-1] == '/'))
l += 2;
else
name[w++] = name[l++];
}
/* b) remove trailing . path, segment */
if (w == 1 && name[0] == '.') w--;
else if (w > 1 && name[w-1] == '.' && name[w-2] == '/') w--;
name[w] = '\0';
/* c) remove all xx/../ segments. (including leading ../ and /../) */
l = 0;
while(name[l]!='\0') {
if(name[l] == '.' && name[l+1] == '.' && name[l+2] == '/' &&
(l == 0 || name[l-1] == '/')) {
register int m=l+3,n;
l=l-2;
if(l>=0) {
while(l >= 0 && name[l] != '/') l--;
l++;
}
else l=0;
n=l;
while((name[n]=name[m])) (++n,++m);
}
else ++l;
}
/* d) remove trailing xx/.. segment. */
if (l == 2 && name[0] == '.' && name[1] == '.') name[0] = '\0';
else if (l > 2 && name[l-1] == '.' && name[l-2] == '.' && name[l-3] == '/')
{
l = l - 4;
if (l >= 0)
{
while (l >= 0 && name[l] != '/') l--;
l++;
}
else l = 0;
name[l] = '\0';
}
}
API_EXPORT(void) no2slash(char *name) {
register int x,y;
for(x=0; name[x];)
if(x && (name[x-1] == '/') && (name[x] == '/'))
for(y=x+1;name[y-1];y++)
name[y-1] = name[y];
else x++;
}
/*
* copy at most n leading directories of s into d
* d should be at least as large as s plus 1 extra byte
* assumes n > 0
* the return value is the ever useful pointer to the trailing \0 of d
*
* examples:
* /a/b, 1 ==> /
* /a/b, 2 ==> /a/
* /a/b, 3 ==> /a/b/
* /a/b, 4 ==> /a/b/
*/
API_EXPORT(char *) make_dirstr_prefix (char *d, const char *s, int n)
{
for(;;) {
*d = *s;
if (*d == '\0') {
*d = '/';
break;
}
if (*d == '/' && (--n) == 0 ) break;
++d;
++s;
}
*++d = 0;
return (d);
}
/*
* return the parent directory name including trailing / of the file s
*/
API_EXPORT(char *) make_dirstr_parent (pool *p, const char *s)
{
char *last_slash = strrchr (s, '/');
char *d;
int l;
if (last_slash == NULL) {
/* XXX: well this is really broken if this happens */
return (pstrdup (p,"/"));
}
l = (last_slash-s)+1;
d = palloc (p, l+1);
memcpy (d, s, l);
d[l] = 0;
return (d);
}
/*
* This function is deprecated. Use one of the preceeding two functions
* which are faster.
*/
API_EXPORT(char *) make_dirstr(pool *p, const char *s, int n) {
register int x,f;
char *res;
for(x=0,f=0;s[x];x++) {
if(s[x] == '/')
if((++f) == n) {
res = palloc(p, x + 2);
strncpy (res, s, x);
res[x] = '/';
res[x+1] = '\0';
return res;
}
}
if (s[strlen(s) - 1] == '/')
return pstrdup (p, s);
else
return pstrcat (p, s, "/", NULL);
}
API_EXPORT(int) count_dirs(const char *path) {
register int x,n;
for(x=0,n=0;path[x];x++)
if(path[x] == '/') n++;
return n;
}
API_EXPORT(void) chdir_file(const char *file) {
int i;
if((i = rind(file,'/')) == -1)
return;
((char *)file)[i] = '\0';
chdir(file);
((char *)file)[i] = '/';
}
API_EXPORT(char *) getword_nc(pool* atrans, char **line, char stop)
{
return getword(atrans,(const char **)line,stop);
}
API_EXPORT(char *) getword(pool* atrans, const char **line, char stop) {
int pos = ind(*line, stop);
char *res;
if (pos == -1) {
res = pstrdup (atrans, *line);
*line += strlen (*line);
return res;
}
res = palloc(atrans, pos + 1);
strncpy (res, *line, pos);
res[pos] = '\0';
while ((*line)[pos] == stop) ++pos;
*line += pos;
return res;
}
API_EXPORT(char *) getword_white_nc(pool* atrans, char **line)
{
return getword_white(atrans,(const char **)line);
}
API_EXPORT(char *) getword_white(pool* atrans, const char **line) {
int pos = -1, x;
char *res;
for(x=0;(*line)[x];x++) {
if (isspace((*line)[x])) {
pos=x;
break;
}
}
if (pos == -1) {
res = pstrdup (atrans, *line);
*line += strlen (*line);
return res;
}
res = palloc(atrans, pos + 1);
strncpy (res, *line, pos);
res[pos] = '\0';
while (isspace((*line)[pos])) ++pos;
*line += pos;
return res;
}
API_EXPORT(char *) getword_nulls_nc(pool* atrans, char **line, char stop)
{
return getword_nulls(atrans,(const char **)line,stop);
}
API_EXPORT(char *) getword_nulls(pool* atrans, const char **line, char stop) {
int pos = ind(*line, stop);
char *res;
if (pos == -1) {
res = pstrdup (atrans, *line);
*line += strlen (*line);
return res;
}
res = palloc(atrans, pos + 1);
strncpy (res, *line, pos);
res[pos] = '\0';
++pos;
*line += pos;
return res;
}
/* Get a word, (new) config-file style --- quoted strings and backslashes
* all honored
*/
static char *substring_conf (pool *p, const char *start, int len, char quote)
{
char *result = palloc (p, len + 2);
char *resp = result;
int i;
for (i = 0; i < len; ++i) {
if (start[i] == '\\' && (start[i+1] == '/'
|| (quote && start[i+1] == quote)))
*resp++ = start[++i];
else
*resp++ = start[i];
}
*resp++ = '\0';
return result;
}
API_EXPORT(char *) getword_conf_nc(pool* p, char **line) {
return getword_conf(p,(const char **)line);
}
API_EXPORT(char *) getword_conf(pool* p, const char **line) {
const char *str = *line, *strend;
char *res;
char quote;
while (*str && isspace (*str))
++str;
if (!*str) {
*line = str;
return "";
}
if ((quote = *str) == '"' || quote == '\'') {
strend = str + 1;
while (*strend && *strend != quote) {
if (*strend == '\\' && strend[1] && strend[1] == quote)
strend += 2;
else ++strend;
}
res = substring_conf (p, str + 1, strend - str - 1, quote);
if (*strend == quote) ++strend;
} else {
strend = str;
while (*strend && !isspace (*strend))
++strend;
res = substring_conf (p, str, strend - str, 0);
}
while (*strend && isspace(*strend)) ++ strend;
*line = strend;
return res;
}
#ifdef UNDEF
/* this function is dangerous, and superceded by getword_white, so don't use it
*/
void cfg_getword(char *word, char *line) {
int x=0,y;
for(x=0;line[x] && isspace(line[x]);x++);
y=0;
while(1) {
if(!(word[y] = line[x]))
break;
if(isspace(line[x]))
if((!x) || (line[x-1] != '\\'))
break;
if(line[x] != '\\') ++y;
++x;
}
word[y] = '\0';
while(line[x] && isspace(line[x])) ++x;
for(y=0;(line[y] = line[x]);++x,++y);
}
#endif
API_EXPORT(int) cfg_getline(char *s, int n, FILE *f) {
register int i=0, c;
s[0] = '\0';
/* skip leading whitespace */
do {
c = getc(f);
} while (c == '\t' || c == ' ');
if(c == EOF)
return 1;
while(1) {
if((c == '\t') || (c == ' ')) {
s[i++] = ' ';
while((c == '\t') || (c == ' '))
c = getc(f);
}
if(c == CR) {
c = getc(f);
}
if(c == EOF || c == 0x4 || c == LF || i == (n-1)) {
/* blast trailing whitespace */
while(i && (s[i-1] == ' ')) --i;
s[i] = '\0';
return 0;
}
s[i] = c;
++i;
c = getc(f);
}
}
/* Retrieve a token, spacing over it and returning a pointer to
* the first non-white byte afterwards. Note that these tokens
* are delimited by semis and commas; and can also be delimited
* by whitespace at the caller's option.
*/
API_EXPORT(char *) get_token (pool *p, char **accept_line, int accept_white)
{
char *ptr = *accept_line;
char *tok_start;
char *token;
int tok_len;
/* Find first non-white byte */
while (*ptr && isspace(*ptr))
++ptr;
tok_start = ptr;
/* find token end, skipping over quoted strings.
* (comments are already gone).
*/
while (*ptr && (accept_white || !isspace(*ptr))
&& *ptr != ';' && *ptr != ',')
{
if (*ptr++ == '"')
while (*ptr)
if (*ptr++ == '"') break;
}
tok_len = ptr - tok_start;
token = palloc (p, tok_len + 1);
strncpy (token, tok_start, tok_len);
token[tok_len] = '\0';
/* Advance accept_line pointer to the next non-white byte */
while (*ptr && isspace(*ptr))
++ptr;
*accept_line = ptr;
return token;
}
static char* tspecials = " \t()<>@,;:\\/[]?={}";
/* Next HTTP token from a header line. Warning --- destructive!
* Use only with a copy!
*/
static char *next_token (char **toks) {
char *cp = *toks;
char *ret;
while (*cp && (iscntrl (*cp) || strchr (tspecials, *cp))) {
if (*cp == '"')
while (*cp && (*cp != '"')) ++cp;
else
++cp;
}
if (!*cp) ret = NULL;
else {
ret = cp;
while (*cp && !iscntrl(*cp) && !strchr (tspecials, *cp))
++cp;
if (*cp) {
*toks = cp + 1;
*cp = '\0';
}
else *toks = cp;
}
return ret;
}
API_EXPORT(int) find_token (pool *p, const char *line, const char *tok) {
char *ltok;
char *lcopy;
if (!line) return 0;
lcopy = pstrdup (p, line);
while ((ltok = next_token (&lcopy)))
if (!strcasecmp (ltok, tok))
return 1;
return 0;
}
API_EXPORT(int) find_last_token (pool *p, const char *line, const char *tok)
{
int llen, tlen, lidx;
if (!line) return 0;
llen = strlen(line);
tlen = strlen(tok);
lidx = llen - tlen;
if ((lidx < 0) ||
((lidx > 0) && !(isspace(line[lidx-1]) || line[lidx-1] == ',')))
return 0;
return (strncasecmp(&line[lidx], tok, tlen) == 0);
}
API_EXPORT(char *) escape_shell_cmd(pool *p, const char *s) {
register int x,y,l;
char *cmd;
l=strlen(s);
cmd = palloc (p, 2 * l + 1); /* Be safe */
strcpy (cmd, s);
for(x=0;cmd[x];x++) {
#if defined(__EMX__) || defined(WIN32)
/* Don't allow '&' in parameters under OS/2. */
/* This can be used to send commands to the shell. */
if (cmd[x] == '&') {
cmd[x] = ' ';
}
#endif
if(ind("&;`'\"|*?~<>^()[]{}$\\\n",cmd[x]) != -1){
for(y=l+1;y>x;y--)
cmd[y] = cmd[y-1];
l++; /* length has been increased */
cmd[x] = '\\';
x++; /* skip the character */
}
}
return cmd;
}
void plustospace(char *str) {
register int x;
for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
}
void spacetoplus(char *str) {
register int x;
for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
}
static char x2c(const char *what) {
register char digit;
digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
digit *= 16;
digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
return(digit);
}
/*
* Unescapes a URL.
* Returns 0 on success, non-zero on error
* Failure is due to
* bad % escape returns BAD_REQUEST
*
* decoding %00 -> \0
* decoding %2f -> / (a special character)
* returns NOT_FOUND
*/
API_EXPORT(int) unescape_url(char *url) {
register int x,y, badesc, badpath;
badesc = 0;
badpath = 0;
for(x=0,y=0;url[y];++x,++y) {
if (url[y] != '%') url[x] = url[y];
else
{
if (!isxdigit(url[y+1]) || !isxdigit(url[y+2]))
{
badesc = 1;
url[x] = '%';
} else
{
url[x] = x2c(&url[y+1]);
y += 2;
if (url[x] == '/' || url[x] == '\0') badpath = 1;
}
}
}
url[x] = '\0';
if (badesc) return BAD_REQUEST;
else if (badpath) return NOT_FOUND;
else return OK;
}
API_EXPORT(char *) construct_server(pool *p, const char *hostname,
unsigned port) {
char portnum[22];
/* Long enough, even if port > 16 bits for some reason */
if (port == DEFAULT_PORT)
return pstrdup (p, hostname);
else {
ap_snprintf (portnum, sizeof(portnum), "%u", port);
return pstrcat (p, hostname, ":", portnum, NULL);
}
}
API_EXPORT(char *) construct_url(pool *p, const char *uri, const server_rec *s) {
return pstrcat (p, "http://",
construct_server(p, s->server_hostname, s->port),
uri, NULL);
}
#define c2x(what,where) sprintf(where,"%%%02x",(unsigned char)what)
/*
escape_path_segment() escapes a path segment, as defined in RFC 1808. This
routine is (should be) OS independent.
os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
cases if a ':' occurs before the first '/' in the URL, the URL should be
prefixed with "./" (or the ':' escaped). In the case of Unix, this means
leaving '/' alone, but otherwise doing what escape_path_segment() does. For
efficiency reasons, we don't use escape_path_segment(), which is provided for
reference. Again, RFC 1808 is where this stuff is defined.
If partial is set, os_escape_path() assumes that the path will be appended to
something with a '/' in it (and thus does not prefix "./").
*/
API_EXPORT(char *) escape_path_segment(pool *p, const char *segment) {
register int x,y;
char *copy = palloc (p, 3 * strlen (segment) + 1);
for(x=0,y=0; segment[x]; x++,y++) {
char c=segment[x];
if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9')
&& ind("$-_.+!*'(),:@&=~",c) == -1)
{
c2x(c,©[y]);
y+=2;
}
else
copy[y]=c;
}
copy[y] = '\0';
return copy;
}
API_EXPORT(char *) os_escape_path(pool *p,const char *path,int partial) {
char *copy=palloc(p,3*strlen(path)+3);
char *s=copy;
if(!partial)
{
int colon=ind(path,':');
int slash=ind(path,'/');
if(colon >= 0 && (colon < slash || slash < 0))
{
*s++='.';
*s++='/';
}
}
for( ; *path ; ++path)
{
char c=*path;
if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9')
&& ind("$-_.+!*'(),:@&=/~",c) == -1)
{
c2x(c,s);
s+=3;
}
else
*s++=c;
}
*s='\0';
return copy;
}
/* escape_uri is now a macro for os_escape_path */
API_EXPORT(char *) escape_html(pool *p, const char *s)
{
int i, j;
char *x;
/* first, count the number of extra characters */
for (i=0, j=0; s[i] != '\0'; i++)
if (s[i] == '<' || s[i] == '>') j += 3;
else if (s[i] == '&') j += 4;
if (j == 0) return pstrdup(p, s);
x = palloc(p, i + j + 1);
for (i=0, j=0; s[i] != '\0'; i++, j++)
if (s[i] == '<')
{
memcpy(&x[j], "<", 4);
j += 3;
} else if (s[i] == '>')
{
memcpy(&x[j], ">", 4);
j += 3;
} else if (s[i] == '&')
{
memcpy(&x[j], "&", 5);
j += 4;
} else
x[j] = s[i];
x[j] = '\0';
return x;
}
API_EXPORT(int) is_directory(const char *path) {
struct stat finfo;
if(stat(path,&finfo) == -1)
return 0; /* in error condition, just return no */
return(S_ISDIR(finfo.st_mode));
}
API_EXPORT(char *) make_full_path(pool *a, const char *src1,
const char *src2) {
register int x;
x = strlen(src1);
if (x == 0) return pstrcat (a, "/", src2, NULL);
if (src1[x - 1] != '/') return pstrcat (a, src1, "/", src2, NULL);
else return pstrcat (a, src1, src2, NULL);
}
/*
* Check for an absoluteURI syntax (see section 3.2 in RFC2068).
*/
API_EXPORT(int) is_url(const char *u) {
register int x;
for (x = 0; u[x] != ':'; x++) {
if ((! u[x]) ||
((! isalpha(u[x])) && (! isdigit(u[x])) &&
(u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
return 0;
}
}
return (x ? 1 : 0); /* If the first character is ':', it's broken, too */
}
API_EXPORT(int) can_exec(const struct stat *finfo) {
#ifdef MULTIPLE_GROUPS
int cnt;
#endif
#if defined(__EMX__) || defined(WIN32)
/* OS/2 dosen't have Users and Groups */
return 1;
#else
if(user_id == finfo->st_uid)
if(finfo->st_mode & S_IXUSR)
return 1;
if(group_id == finfo->st_gid)
if(finfo->st_mode & S_IXGRP)
return 1;
#ifdef MULTIPLE_GROUPS
for(cnt=0; cnt < NGROUPS_MAX; cnt++) {
if(group_id_list[cnt] == finfo->st_gid)
if(finfo->st_mode & S_IXGRP)
return 1;
}
#endif
return (finfo->st_mode & S_IXOTH);
#endif
}
#ifdef NEED_STRDUP
char *strdup (const char *str)
{
char *dup;
if(!(dup = (char *)malloc (strlen (str) + 1)))
return NULL;
dup = strcpy (dup, str);
return dup;
}
#endif
/* The following two routines were donated for SVR4 by Andreas Vogel */
#ifdef NEED_STRCASECMP
int strcasecmp (const char *a, const char *b)
{
const char *p = a;
const char *q = b;
for (p = a, q = b; *p && *q; p++, q++)
{
int diff = tolower(*p) - tolower(*q);
if (diff) return diff;
}
if (*p) return 1; /* p was longer than q */
if (*q) return -1; /* p was shorter than q */
return 0; /* Exact match */
}
#endif
#ifdef NEED_STRNCASECMP
int strncasecmp (const char *a, const char *b, int n)
{
const char *p = a;
const char *q = b;
for (p = a, q = b; /*NOTHING*/; p++, q++)
{
int diff;
if (p == a + n) return 0; /* Match up to n characters */
if (!(*p && *q)) return *p - *q;
diff = tolower(*p) - tolower(*q);
if (diff) return diff;
}
/*NOTREACHED*/
}
#endif
#ifdef NEED_INITGROUPS
int initgroups(const char *name, gid_t basegid)
{
#if defined(QNX) || defined(MPE)
/* QNX and MPE do not appear to support supplementary groups. */
return 0;
#else /* ndef QNX */
gid_t groups[NGROUPS_MAX];
struct group *g;
int index = 0;
setgrent();
groups[index++] = basegid;
while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
if (g->gr_gid != basegid)
{
char **names;
for (names = g->gr_mem; *names != NULL; ++names)
if (!strcmp(*names, name))
groups[index++] = g->gr_gid;
}
endgrent();
return setgroups(index, groups);
#endif /* def QNX */
}
#endif /* def NEED_INITGROUPS */
#ifdef NEED_WAITPID
/* From ikluft@amdahl.com */
/* this is not ideal but it works for SVR3 variants */
/* httpd does not use the options so this doesn't implement them */
int waitpid(pid_t pid, int *statusp, int options)
{
int tmp_pid;
if ( kill ( pid,0 ) == -1) {
errno=ECHILD;
return -1;
}
while ((( tmp_pid = wait(statusp)) != pid) && ( tmp_pid != -1 ));
return tmp_pid;
}
#endif
API_EXPORT(int) ind(const char *s, char c) {
register int x;
for(x=0;s[x];x++)
if(s[x] == c) return x;
return -1;
}
API_EXPORT(int) rind(const char *s, char c) {
register int x;
for(x=strlen(s)-1;x != -1;x--)
if(s[x] == c) return x;
return -1;
}
API_EXPORT(void) str_tolower(char *str) {
while(*str) {
*str = tolower(*str);
++str;
}
}
API_EXPORT(uid_t) uname2id(const char *name) {
#ifdef WIN32
return(1);
#else
struct passwd *ent;
if(name[0] == '#')
return(atoi(&name[1]));
if(!(ent = getpwnam(name))) {
fprintf(stderr,"httpd: bad user name %s\n",name);
exit(1);
}
return(ent->pw_uid);
#endif
}
API_EXPORT(gid_t) gname2id(const char *name) {
#ifdef WIN32
return(1);
#else
struct group *ent;
if(name[0] == '#')
return(atoi(&name[1]));
if(!(ent = getgrnam(name))) {
fprintf(stderr,"httpd: bad group name %s\n",name);
exit(1);
}
return(ent->gr_gid);
#endif
}
#if 0
int get_portnum(int sd) {
struct sockaddr addr;
int len;
len = sizeof(struct sockaddr);
if(getsockname(sd,&addr,&len) < 0)
return -1;
return ntohs(((struct sockaddr_in *)&addr)->sin_port);
}
struct in_addr get_local_addr(int sd) {
struct sockaddr addr;
int len;
len = sizeof(struct sockaddr);
if(getsockname(sd,&addr,&len) < 0) {
perror ("getsockname");
fprintf (stderr, "Can't get local host address!\n");
exit(1);
}
return ((struct sockaddr_in *)&addr)->sin_addr;
}
#endif
/*
* Parses a host of the form <address>[:port]
* :port is permitted if 'port' is not NULL
*/
unsigned long get_virthost_addr (const char *w, unsigned short *ports) {
struct hostent *hep;
unsigned long my_addr;
char *p;
p = strchr(w, ':');
if (ports != NULL)
{
*ports = 0;
if (p != NULL && strcmp(p+1, "*") != 0) *ports = atoi(p+1);
}
if (p != NULL) *p = '\0';
if (strcmp(w, "*") == 0)
{
if (p != NULL) *p = ':';
return htonl(INADDR_ANY);
}
#ifdef DGUX
my_addr = inet_network(w);
#else
my_addr = inet_addr(w);
#endif
if (my_addr != INADDR_NONE)
{
if (p != NULL) *p = ':';
return my_addr;
}
hep = gethostbyname(w);
if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
fprintf (stderr, "Cannot resolve host name %s --- exiting!\n", w);
exit(1);
}
if (hep->h_addr_list[1]) {
fprintf(stderr, "Host %s has multiple addresses ---\n", w);
fprintf(stderr, "you must choose one explicitly for use as\n");
fprintf(stderr, "a virtual host. Exiting!!!\n");
exit(1);
}
if (p != NULL) *p = ':';
return ((struct in_addr *)(hep->h_addr))->s_addr;
}
static char *find_fqdn(pool *a, struct hostent *p) {
int x;
if(ind(p->h_name,'.') == -1) {
for(x=0;p->h_aliases[x];++x) {
if((ind(p->h_aliases[x],'.') != -1) &&
(!strncmp(p->h_aliases[x],p->h_name,strlen(p->h_name))))
return pstrdup(a, p->h_aliases[x]);
}
return NULL;
}
return pstrdup(a, (void *)p->h_name);
}
char *get_local_host(pool *a)
{
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
char str[MAXHOSTNAMELEN+1];
char *server_hostname;
struct hostent *p;
if( gethostname( str, sizeof( str ) - 1 ) != 0 ) {
perror( "Unable to gethostname" );
exit(1);
}
str[MAXHOSTNAMELEN] = '\0';
if((!(p=gethostbyname(str))) || (!(server_hostname = find_fqdn(a, p)))) {
fprintf(stderr,"httpd: cannot determine local host name.\n");
fprintf(stderr,"Use ServerName to set it manually.\n");
exit(1);
}
return server_hostname;
}
/* aaaack but it's fast and const should make it shared text page. */
const int pr2six[256]={
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64
};
API_EXPORT(char *) uudecode(pool *p, const char *bufcoded) {
int nbytesdecoded;
register const unsigned char *bufin;
register char *bufplain;
register unsigned char *bufout;
register int nprbytes;
/* Strip leading whitespace. */
while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
/* Figure out how many characters are in the input buffer.
* Allocate this many from the per-transaction pool for the result.
*/
bufin = (const unsigned char *)bufcoded;
while(pr2six[*(bufin++)] <= 63);
nprbytes = (bufin - (const unsigned char *)bufcoded) - 1;
nbytesdecoded = ((nprbytes+3)/4) * 3;
bufplain = palloc(p, nbytesdecoded + 1);
bufout = (unsigned char *)bufplain;
bufin = (const unsigned char *)bufcoded;
while (nprbytes > 0) {
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
bufin += 4;
nprbytes -= 4;
}
if(nprbytes & 03) {
if(pr2six[bufin[-2]] > 63)
nbytesdecoded -= 2;
else
nbytesdecoded -= 1;
}
bufplain[nbytesdecoded] = '\0';
return bufplain;
}
#ifdef __EMX__
void os2pathname(char *path) {
char newpath[MAX_STRING_LEN];
int loop;
int offset;
offset = 0;
for (loop=0; loop < (strlen(path) + 1) && loop < sizeof(newpath)-1; loop++) {
if (path[loop] == '/') {
newpath[offset] = '\\';
/*
offset = offset + 1;
newpath[offset] = '\\';
*/
} else
newpath[offset] = path[loop];
offset = offset + 1;
};
/* Debugging code */
/* fprintf(stderr, "%s \n", newpath); */
strcpy(path, newpath);
};
#endif
#ifdef NEED_STRERROR
char *
strerror (int err) {
char *p;
extern char *const sys_errlist[];
p = sys_errlist[err];
return (p);
}
#endif
#ifndef NO_SLACK
int ap_slack (int fd, int line)
{
#if !defined(F_DUPFD)
return fd;
#else
int new_fd;
#ifdef HIGH_SLACK_LINE
if (line == AP_SLACK_HIGH && fd < HIGH_SLACK_LINE) {
new_fd = fcntl (fd, F_DUPFD, HIGH_SLACK_LINE);
if (new_fd != -1) {
close (fd);
return new_fd;
}
}
#endif
/* otherwise just assume line == AP_SLACK_LOW */
if (fd >= LOW_SLACK_LINE) {
return fd;
}
new_fd = fcntl (fd, F_DUPFD, LOW_SLACK_LINE);
if (new_fd == -1) {
return fd;
}
close (fd);
return new_fd;
#endif
}
#endif /* NO_SLACK */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.