ftp.nice.ch/pub/next/unix/network/www/httpd.1.5-export.NIHS.bs.gnutar.gz#/httpd_1.5-export/src/util.c

This is util.c in view mode; [Download] [Up]

/************************************************************************
 * NCSA HTTPd Server
 * Software Development Group
 * National Center for Supercomputing Applications
 * University of Illinois at Urbana-Champaign
 * 605 E. Springfield, Champaign, IL 61820
 * httpd@ncsa.uiuc.edu
 *
 * Copyright  (C)  1995, Board of Trustees of the University of Illinois
 *
 ************************************************************************
 *
 * util.c,v 1.105 1995/11/06 20:58:22 blong Exp
 *
 ************************************************************************
 *
 * util.c: string utility things, and other utilities
 * 
 * 03-23-93  Rob McCool
 * 	Original code up to version 1.3 from Rob McCool
 *
 * 02-16-95  cvarela
 *	Fixed stack hole in strsubfirst
 *
 * 03-06-95  blong
 *	Added inststr from bdflush-1.5 for Linux to set the name of
 *	the running processes
 *
 * 03-10-95  blong
 *	Added buffered getline for all but POST requests as suggested by
 *	Robert S. Thau (rst@ai.mit.edu)
 *
 * 03-20-95  blong & cvarela
 *	Fixed make_env_str so that it doesn't modify the pointers
 *
 * 04-03-95  blong
 *	May have fixed problems (esp. under Solaris 2.3) with playing
 *	with library memory in get_remote_name
 *
 * 04-13-95  guillory
 *	added strncpy_dir that limits the length of a directory copy
 *	also added strncpy for same reason
 *
 * 04-29-95  blong
 *      added patch by Kevin Steves (stevesk@mayfield.hp.com) for inststr
 *      under HPUX which uses the pstat command
 *
 * 06-01-95  blong
 *    added patch by Vince Skahan (vds7789@aw101.iasl.ca.boeing.com)
 *    to fix Apollo DomainOS timezone handling
 *
 * 09-02-95  blong
 *    added patch by Gioacchino La Vecchia (gio@di.unipi.it) to make
 *    full host name in get_local_host() to keep from needing to use
 *    the ServerName configuration directive
 *
 * 09-11-95  mshapiro
 *    replaced atoi() in uname2id() and gname2id with scan_long() to
 *    convert user_id and group_id from #n to uid_t, gid_t.
 *    If the config file had contained #non-digit then atoi() would
 *    have returned 0 and the server would have been run as root.
 *
 * 09-12-95  blong
 *    removed get_local_host() patch, because its the wrong thing to
 *    do.  Use the ServerName directive, thats what its there for.
 *
 * 11-02-95  mshapiro
 *    recoded no2slash() to perform the following replacecments
 *      sequences of / (//, ///, etc) with a single /
 *      all occurenences of /./ with a single /
 *      remove ./ at the beginning of the name
 *      replace /. at the end of the name with a single /
 *
 *    added a call to no2slash() at the beginning of getparents()
 *
 */


#include "config.h"
#include "portability.h"

#ifndef NO_STDLIB_H
# include <stdlib.h>
#endif /* NO_STDLIB_H */
#ifndef NO_MALLOC_H
# ifdef NEED_SYS_MALLOC_H
#  include <sys/malloc.h>
# else
#  include <malloc.h>
# endif /* NEED_SYS_MALLOC_H */
#endif /* NO_MALLOC_H */
#include <setjmp.h>
#include <signal.h>
#include <string.h>
#include <grp.h>
#include <pwd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#ifdef HPUX
# include <sys/pstat.h>
#endif
#ifdef APOLLO
# include <sys/time.h>
#endif
#include "constants.h"
#include "util.h"
#include "http_request.h"
#include "http_config.h"
#include "host_config.h"
#include "http_log.h"
#include "httpd.h"


#undef DONTCOMPILEIN
#ifdef DONTCOMPILEIN

/* Superseded by setproctitle (next function) */

extern char** environ;

/* modified from bdflush-1.5 for Linux source code
   This is used to set the name of the running process */
void inststr(char *dst[], int argc, char *src)
{
#ifdef HPUX
    /*
     * 4/29/95 Kevin Steves <stevesk@mayfield.hp.com>
     * Use pstat(PSTAT_SETCMD) on HP-UX.
     */
    union pstun pst;

    pst.pst_command = src;
    pstat(PSTAT_SETCMD, pst, 0, 0, 0);
#else
    if (strlen(src) <= strlen(dst[0])) {
        char *ptr; /*= dst[0];*/

	for (ptr = dst[0]; *ptr; *(ptr++) = '\0');
	/*while (*ptr)
	    *ptr++ = '\0';*/

        strcpy(dst[0], src);
    } 
    else {
        /* stolen from the source to perl 4.036 (assigning to $0) */
        char *ptr, *ptr2;
        int count;
        ptr = dst[0] + strlen(dst[0]);
        for (count = 1; count < argc; count++) {
            if (dst[count] == ptr + 1)
                ptr += strlen(++ptr);
        }
        if (environ[0] == ptr + 1) {
            for (count = 0; environ[count]; count++)
                if (environ[count] == ptr + 1)
                    ptr += strlen(++ptr);
        }
        count = 0;
        for (ptr2 = dst[0]; ptr2 <= ptr; ptr2++) {
            *ptr2 = '\0';
            count++;
        }
        strncpy(dst[0], src, count);
    }
#endif
}

#endif /* 0 */

/*
 * initproctitle(),setproctitle() as given by 
 *    Kevin Ruddy (smiles@powerdog.com) 
 *
 * initproctitle() initializes variables and sets the prefix for the name
 * setproctitle() sets the title given by ps
 *
 * This is known to work under SunOS and AIX3.  There is a specific 
 * command under HPUX to make this work according to 
 * Kevin Steves <stevesk@mayfield.hp.com> which uses 
 * pstat(PSTAT_SETCMD) on HP-UX.  I think BSDI also has a setproctitle()
 * in its libc, but I don't know the interface to add it (from sendmail)
 *
 */

#ifdef SETPROCTITLE

static char     *procstart = NULL,
                *proctitle = NULL;
static int      procstartn = 0,
                proctitlen = 0;
 
void
initproctitle(char *start, int argc, char **argv, char **envp)
{
#ifndef HPUX
        char    *p;
        int     i;

        if (procstart != NULL)
                (void) free(procstart);
        procstart = (char *) malloc(strlen(start) + 3);
        (void) strcpy(procstart, start);
        (void) strcat(procstart, ": ");
        procstartn = strlen(procstart);

        if (argv != 0) {
                proctitle = argv[0];
                for (i = 0; envp[i] != 0; i++)
                        ;
                if (i > 0)
                        p = envp[i - 1] + strlen(envp[i - 1]);
                else
                        p = argv[argc - 1] + strlen(argv[argc - 1]);
                proctitlen = p - proctitle;
        }
#endif /* HPUX */
}

#ifndef HAVE_SETPROCTITLE
void setproctitle(char *title)
{
#ifdef HPUX
    /*
     * 4/29/95 Kevin Steves <stevesk@mayfield.hp.com>
     * Use pstat(PSTAT_SETCMD) on HP-UX.
     */
    union pstun pst;
    char tmp[HUGE_STRING_LEN];

    
    strcpy(tmp,process_name);
    strcat(tmp,": ");
    strncat(tmp,title,HUGE_STRING_LEN-strlen(tmp));
    pst.pst_command = tmp;
    pstat(PSTAT_SETCMD, pst, 0, 0, 0);
#else
        int     len;

        if (proctitle == 0 || proctitlen < procstartn)
                return;

        (void) memset(proctitle, ' ', proctitlen);
        (void) strncpy(proctitle, procstart, procstartn);
        len = strlen(title);
        if (len > proctitlen - procstartn)
                len = proctitlen - procstartn;
        (void) strncpy(proctitle + procstartn, title, len);
#endif /* HPUX */
}
#endif /* HAVE_SETPROCTITLE */

#endif /* SETPROCTITLE */

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);
}

char *gm_timestr_822(time_t sec) {
    return ht_time(sec,HTTP_TIME_FORMAT, 1);
}

char *ht_time(time_t t, char *fmt, int gmt) {
    static 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 ts;
}

/* What a pain in the ass. */
struct tm *get_gmtoff(long *tz) {
    time_t tt;
    struct tm *t;
#ifdef APOLLO
    struct timeval tp;        /* see gettimeofday(2) */
    struct timezone tzp;
#endif

    tt = time(NULL);
    t = localtime(&tt);
#if defined(BSD) && !defined(AUX) && !defined(APOLLO) && !defined(__QNX__) && !defined(CONVEXOS)
    *tz = t->tm_gmtoff;
#elif defined(CONVEXOS)
    {
        struct timeval tp;
        struct timezone tzp;
        gettimeofday(&tp, &tzp);
        *tz = tzp.tz_minuteswest * 60;
    }
#else
# ifdef APOLLO
    gettimeofday(&tp,&tzp);
    *tz = (60 * tzp.tz_minuteswest);
# else
      *tz = - timezone;
# endif
    if(t->tm_isdst)
        *tz += 3600;
#endif
    return t;
}


static char *months[] = {
    "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};


int find_month(char *mon) {
    register int x;

    for(x=0;x<12;x++)
        if(!strcmp(months[x],mon))
            return x;
    return -1;
}

/* Roy owes Rob beer. */
/* This would be considerably easier if strptime or timegm were portable */

int later_than(struct tm *lms, char *ims) {
    char *ip;
    char mname[MAX_STRING_LEN];
    int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, x;

    /* Whatever format we're looking at, it will start with weekday. */
    /* Skip to first space. */
    if(!(ip = strchr(ims,' ')))
        return 0;
    else
        while(isspace(*ip))
            ++ip;

    if(isalpha(*ip)) {
        /* ctime */
        sscanf(ip,"%s %d %d:%d:%d %d",mname,&day,&hour,&min,&sec,&year);
    }
    else if(ip[2] == '-') {
        /* RFC 850 (normal HTTP) */
        char t[MAX_STRING_LEN];
        sscanf(ip,"%s %d:%d:%d",t,&hour,&min,&sec);
        t[2] = '\0';
        day = atoi(t);
        t[6] = '\0';
        strcpy(mname,&t[3]);
        x = atoi(&t[7]);
        /* Prevent wraparound from ambiguity */
        if(x < 70)
            x += 100;
        year = 1900 + x;
    }
    else {
        /* RFC 822 */
        sscanf(ip,"%d %s %d %d:%d:%d",&day,mname,&year,&hour,&min,&sec);
    }
    month = find_month(mname);

    if((x = (1900+lms->tm_year) - year))
        return x < 0;
    if((x = lms->tm_mon - month))
        return x < 0;
    if((x = lms->tm_mday - day))
        return x < 0;
    if((x = lms->tm_hour - hour))
        return x < 0;
    if((x = lms->tm_min - min))
        return x < 0;
    if((x = lms->tm_sec - sec))
        return x < 0;

    return 1;
}


/* Match = 0, NoMatch = 1, Abort = -1 */
/* Based loosely on sections of wildmat.c by Rich Salz */
int strcmp_match(char *str, 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');
}

int is_matchexp(char *str) {
    register int x;

    for(x=0;str[x];x++)
        if((str[x] == '*') || (str[x] == '?'))
            return 1;
    return 0;
}

void strsubfirst(int start,char *dest, char *src)
{
  int src_len, dest_len, i;

  if ((src_len=strlen(src))<start){  /** src "fits" in dest **/
    for (i=0;(dest[i]=src[i]);i++);
    for (i=src_len;(dest[i]=dest[i-src_len+start]);i++);
  }
  else {                             /** src doesn't fit in dest **/
    for (dest_len=strlen(dest),i=dest_len+src_len-start;i>=src_len;i--)
      dest[i] = dest[i-src_len+start];
    for (i=0;i<src_len;i++) dest[i]=src[i];
  }
}

/*
 * Parse .. so we don't compromise security
 */
void getparents(char *name)
{
    int l=0,w=0;
    const char *lookfor="..";

    no2slash(name);

    while(name[l]!='\0') {
        if(name[l]!=lookfor[w]) (w>0 ? (l-=(w-1),w=0) : l++);
        else {
            if(lookfor[++w]=='\0') {
                if(((name[l+1]=='\0') || (name[l+1]=='/')) &&
                   (((l > 3) && (name[l-2] == '/')) || (l<=3))) {
                    register int m=l+1,n;

                    l=l-3;
                    if(l>=0) {
                        while((l!=0) && (name[l]!='/')) --l;
                    }
                    else l=0;
                    n=l;
                    while((name[n]=name[m])) (++n,++m);
                    w=0;
                }
                else w=0;
            }
            else ++l;
        }
    }
}

void no2slash(char *name)
{
    register char *s;
    register char *p;

/* collapse //, ///, etc. into /
 */
    for (s = name; *s; s++)
	while (s[0] == '/' && s[1] == '/')
	{
	    p = s;
	    while (p[0] = p[1])
		p++;
	}

/* collapse /./ into /
 */
    for (s = name; *s; s++)
	while (s[0] =='/' && s[1] == '.' && s[2] == '/')
	{
	    p = s;
	    while (p[0] = p[2])
		p++;
	}

/* remove ./ at the beginning of the name */
    if (name[0] == '.' && name[1] == '/')
    {
	p = name;
	while (p[0] = p[2])
	    p++;
    }

/* change /. at the end of the name to /
 */
    if (name[0] && name[1])
	while (name[2])
	    name++;
    if (name[0] == '/' && name[1] == '.' && name[2] == '\0')
	name[1] = 0;
}

void make_dirstr(char *s, int n, char *d) {
    register int x,f;

    for(x=0,f=0;s[x];x++) {
        if((d[x] = s[x]) == '/')
            if((++f) == n) {
                d[x] = '\0';
                return;
            }
    }
    d[x] = '\0';
}

int count_dirs(char *path) {
    register int x,n;

    for(x=0,n=0;path[x];x++)
        if(path[x] == '/') n++;
    return n;
}


void strcpy_dir(char *d, char *s) {
    register int x;

    for(x=0;s[x];x++)
        d[x] = s[x];

    if(s[x-1] != '/') d[x++] = '/';
    d[x] = '\0';
}

/*
 * A version of strcpy_dir that limits the number of characters
 * that will be copied to n - 1. If s is of length n or greater,
 * that portion is not copied and d is null-terminated at position
 * n. This fixes potential security hole in evaluate_acess.
 * SSG 4/15/95
 */
void strncpy_dir(char *d, char *s, int n) {
    register int x;
    
    for(x=0;s[x] && x < (n - 1);x++)
        d[x] = s[x];

    if(x && s[x-1] != '/' && x < (n - 1)) d[x++] = '/';
    d[x] = '\0';
}

/*
 * My version of strncpy. This will null terminate d if
 * s is n characters or longer. It also will only copy
 * n - 1 characters to d. SSG 4/13/95
 */
void lim_strcpy(char *d, char *s, int n) 
{
    while (--n && (*d++ = *s++))
     ;

    if (!n) 
      *d = '\0';
}

void chdir_file(char *file) {
    int i;

    if((i = rind(file,'/')) == -1)
        return;
    file[i] = '\0';
    chdir(file);
    file[i] = '/';
}

void http2cgi(char* h, char *w) {

    strncpy(h,"HTTP_",5);
    h += 5;
    while ((*h++ = (*w == '-') ? '_' : toupper(*w))) 
	w++;
}

void getline_timed_out(int sig) 
{
    char errstr[MAX_STRING_LEN];

    sprintf(errstr,"timed out waiting for %s", gCurrentRequest->remote_name);
    log_error(errstr,gCurrentRequest->hostInfo->error_log);
    if (!standalone) {
	fclose(stdin);
	fclose(stdout);
	exit(0);
    } else {
#ifdef NO_SIGLONGJMP
	longjmp(jmpbuffer,1);
#else
        siglongjmp(jmpbuffer,1);
#endif
    }
}

int getline(int sd, char *s, int n, int reset, unsigned int timeout)
{
    char *endp = s + n - 1;
    int have_alarmed = 0;
    static int buf_posn, buf_good;
    int buf_start;
    static char buffer[HUGE_STRING_LEN];
    int c;
    int ret;

    buf_start = buf_posn;
    if (reset == 1) {
	buf_start = buf_posn = buf_good = 0;
	buffer[0] = '\0';
    }
    else if (reset == 2) {
	while (buf_posn < buf_good) 
	    *s++ = buffer[buf_posn++];
	*s = '\0';
	return buf_posn - buf_start;
    }

    do {
	if (buf_posn == buf_good) {
	    have_alarmed = 1;
	    signal(SIGALRM,getline_timed_out);
	    alarm(timeout);
      
	    if ((ret=read(sd, buffer, HUGE_STRING_LEN)) <= 0) {
		if (ret == -1 && errno == EINTR) 
		    continue; /* Solaris... */
		else {
                    if (have_alarmed) { alarm(0); signal(SIGALRM,SIG_IGN); }
		    /* just always return -1, instead of 0 */
		    return -1;
		}
	    }

	    buf_good = ret;
	    buf_start -= buf_posn;
	    buf_posn = 0;
	}
	
	c = buffer[buf_posn++];

	if (c == LF) break;
	if (c != CR) *s++ = c;
    } while (s < endp);
  
    if (have_alarmed) { alarm(0); signal(SIGALRM,SIG_IGN); }
  
    *s = '\0';
  
    return buf_posn - buf_start;
}

void splitURL(char *line, char *url, char *args) {
  int x,y;
  int inURL = TRUE;

  for (x=0,y=0 ; ((line[x]) && (line[x] != ' ')); x++) {
    if (inURL) {
      if ((url[x] = line[x]) == '?') {
	url[x] = '\0';
	inURL = FALSE;
      }
    } else {
      args[y] = line[x];
      y++;
    }
  }
  args[y] = '\0';
}

void getword(char *word, char *line, char stop) {
    int x = 0,y;

    for(x=0;((line[x]) && (line[x] != stop));x++)
        word[x] = line[x];

    word[x] = '\0';
    if(line[x]) ++x;
    y=0;

    while((line[y++] = line[x++]));
}

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);
}

int eat_ws (FILE* fp)
{
    int ch;

    while ((ch = fgetc (fp)) != EOF) {
        if (ch != ' ' && ch != '\t')
            return ch;
    }
    return ch;
}
         
int cfg_getline (char* s, int n, FILE* fp)
{
    int   len = 0, ch;

    ch = eat_ws(fp);
    while (1) {
        if (ch == EOF || ch == '\n' || (len == n-1)) {
            if (len && s[len - 1] == ' ') s[len - 1] = '\0';
            else s[len] = '\0';
            return feof(fp) ? 1 : 0;
        }
        s[len++] = ch;
        ch = fgetc (fp);
        if (ch == '\t' || ch == ' ') {
            s[len++] = ch;
            ch = eat_ws (fp);
        }
    }
}

void escape_shell_cmd(char *cmd) {
    register int x,y,l;

    l=strlen(cmd);
    for(x=0;cmd[x];x++) {
        if(ind("&;`'\"|*?~<>^()[]{}$\\",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 */
        }
    }
}

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] = '+';
}

char x2c(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);
}

void unescape_url(char *url) {
    register int x,y;

    for(x=0,y=0;url[y];++x,++y) {
        if((url[x] = url[y]) == '%') {
            url[x] = x2c(&url[y+1]);
            y+=2;
        }
    }
    url[x] = '\0';
}

#define c2x(what,where) sprintf(where,"%%%2x",what)

void escape_url(char *url) {
    register int x,y;
    char copy[HUGE_STRING_LEN];

    strncpy(copy,url,HUGE_STRING_LEN);
            
    for(x=0,y=0;copy[x];x++,y++) {
        if(ind("% ?+&",url[y] = copy[x]) != -1) {
            c2x(copy[x],&url[y]);
            y+=2;
        }
    }
    url[y] = '\0';
}

void escape_uri(char *url) {
    register int x,y;
    char copy[HUGE_STRING_LEN];

    strncpy(copy,url,HUGE_STRING_LEN);
            
    for(x=0,y=0;copy[x];x++,y++) {
        if(ind(":% ?+&",url[y] = copy[x]) != -1) {
            c2x(copy[x],&url[y]);
            y+=2;
        }
    }
    url[y] = '\0';
}

void add_file_to_dir(char *dir,char *file) {

    if (dir[strlen(dir)-1] == '/') {
      if (file[0] == '/') strcat(dir,file+1);
	else strcat(dir,file);
    } else {
      if (file[0] == '/') strcat(dir,file);
	else sprintf(dir,"%s/%s",dir,file);
    }
}

void make_full_path(char *src1,char *src2,char *dst) {
    register int x,y;

    for(x=0;(dst[x] = src1[x]);x++);

    if(!x) dst[x++] = '/';
    else if((dst[x-1] != '/'))
        dst[x++] = '/';

    for(y=0;(dst[x] = src2[y]);x++,y++);
}

int is_directory(char *path) {
    struct stat finfo;

    if(stat(path,&finfo) == -1)
        return 0; /* in error condition, just return no */

    return(S_ISDIR(finfo.st_mode));
}

int is_url(char *u) {
    register int x;

    for(x=0;u[x] != ':';x++)
        if((!u[x]) || (!isalpha(u[x])))
            return 0;

    if((u[x+1] == '/') && (u[x+2] == '/'))
        return 1;
    else return 0;
}

int can_exec(struct stat *finfo) {
    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;
    return (finfo->st_mode & S_IXOTH);
}

#ifdef NEED_STRDUP
char *strdup (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)
{
  gid_t groups[NGROUPS_MAX];
  struct group *g;
  int index = 0;

  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;
    }

  return setgroups(index, groups);
}
#endif

#ifdef __QNX__
int setgroups(int index, gid_t *groups) {
   index = index;
   groups = groups;
   return 0;
}
#endif

#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

int ind(char *s, char c) {
    register int x;

    for(x=0;s[x];x++)
        if(s[x] == c) return x;

    return -1;
}

/*
 * Return the position of character c in string s. Return -1 if c does
 * not occur in s.
 */

int rind(char *s, char c) {
    register int x;

    for(x=strlen(s)-1;x != -1;x--)
        if(s[x] == c) return x;

    return -1;
}

void str_tolower(char *str) {
    while(*str) {
        *str = tolower(*str);
        ++str;
    }
}

static
long
scan_long (char *s, long *n)
{
    char extra[2];

    *extra = 0;
    return (sscanf (s, "%ld%1s", n, extra) == 1 && *extra == 0);
}

uid_t uname2id(char *name) {
    struct passwd *ent;
    long id;

    if(name[0] == '#') 
    {
	if (!scan_long (&name[1], &id))
	{
	    fprintf(stderr,"httpd: bad user id %s\n",name);
	    exit(1);
	}
	return (uid_t) id ;
    }

    if(!(ent = getpwnam(name))) {
        fprintf(stderr,"httpd: bad user name %s\n",name);
        exit(1);
    }
    return(ent->pw_uid);
}

gid_t gname2id(char *name) {
    struct group *ent;
    long id;

    if(name[0] == '#') 
    {
	if (!scan_long (&name[1], &id))
	{
	    fprintf(stderr,"httpd: bad group id %s\n",name);
	    exit(1);
	}
	return (gid_t) id ;
    }

    if(!(ent = getgrnam(name))) {
        fprintf(stderr,"httpd: bad group name %s\n",name);
        exit(1);
    }
    return(ent->gr_gid);
}

int get_portnum(per_request *reqInfo, int sd) {
    struct sockaddr addr;
    int len;

    len = sizeof(struct sockaddr);
    if(getsockname(sd,&addr,&len) < 0)
        die(reqInfo, SC_SERVER_ERROR,"could not get port number");
    return ntohs(((struct sockaddr_in *)&addr)->sin_port);
}

char *find_fqdn(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 strdup(p->h_aliases[x]);
        }
        return NULL;
    } else return strdup(p->h_name);
}

int get_remote_host_min(per_request *reqInfo) {
    struct sockaddr addr;
    int len;
    struct in_addr *iaddr;
    struct hostent *hptr;

    reqInfo->ownDNS = TRUE;

    len = sizeof(struct sockaddr);

    if ((getpeername(reqInfo->connection_socket, &addr, &len)) < 0) {
	return -1;
    }

    iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
    hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
    if(hptr) {
      if (reqInfo->remote_host) free(reqInfo->remote_host);
      reqInfo->remote_host = strdup(hptr->h_name);
      str_tolower(reqInfo->remote_host);
      if (reqInfo->remote_name) free(reqInfo->remote_name);
      reqInfo->remote_name = strdup(reqInfo->remote_host);
    } else {
  	/* shouldn't be necessary, but just in case */
	if (reqInfo->remote_host) free(reqInfo->remote_host);
	reqInfo->remote_host = NULL;
    }
    reqInfo->dns_host_lookup = TRUE;
    return 0;
}

void get_remote_host(per_request *reqInfo) 
{
    struct sockaddr addr;
    int len;
    struct in_addr *iaddr;
    struct hostent *hptr;

    reqInfo->ownDNS = TRUE;

    len = sizeof(struct sockaddr);
    
    if ((getpeername(reqInfo->connection_socket, &addr, &len)) < 0) {
	reqInfo->remote_name = strdup("UNKNOWN_HOST");
	reqInfo->remote_ip = strdup("UNKNOWN_IP");
	reqInfo->remote_host = strdup("UNKNOWN_HOST");
        return;
    }

    iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
    if ((reqInfo->hostInfo->dns_mode != DNS_MIN) &&
	(reqInfo->hostInfo->dns_mode != DNS_NONE))
    {
      hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
      if(hptr) {
        reqInfo->remote_host = strdup(hptr->h_name);
        str_tolower(reqInfo->remote_host);
	if (reqInfo->remote_name) free(reqInfo->remote_name);
        reqInfo->remote_name = strdup(reqInfo->remote_host);
      } else reqInfo->remote_host = NULL;
      reqInfo->dns_host_lookup = TRUE;
    } else 
        reqInfo->remote_host = NULL;
    
    if (reqInfo->hostInfo->dns_mode == DNS_MAX) {
    /* Grrr. Check THAT name to make sure it's really the name of the addr. */
    /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
      if(reqInfo->remote_host) {
        char **haddr;

        hptr = gethostbyname(reqInfo->remote_host);
        if (hptr) {
            for(haddr=hptr->h_addr_list;*haddr;haddr++) {
                if(((struct in_addr *)(*haddr))->s_addr == iaddr->s_addr)
                    break;
            }
        }
        if((!hptr) || (!(*haddr)))
	    if (reqInfo->remote_host) {
		free(reqInfo->remote_host);
            	reqInfo->remote_host = NULL;
	    }
      }
    }
    reqInfo->remote_ip = strdup(inet_ntoa(*iaddr));
    if(!reqInfo->remote_host){
	if (reqInfo->remote_name) free(reqInfo->remote_name);
        reqInfo->remote_name = strdup(reqInfo->remote_ip);
    }
    if (!reqInfo->remote_name){
	reqInfo->remote_name = strdup("UNKNOWN_HOST");
    }
}

char *get_remote_logname(FILE *fd) {
    int len;
    char *result;
#ifdef MIX_SOCKADDR
    struct sockaddr sa_server, sa_client;
#else
    struct sockaddr_in sa_server,sa_client;
#endif

    len = sizeof(sa_client);
    if(getpeername(fileno(fd),(struct sockaddr *)&sa_client,&len) != -1) {
        len = sizeof(sa_server);
        if(getsockname(fileno(fd),(struct sockaddr *)&sa_server,&len) == -1){
	    result = (char *) malloc(sizeof(char)*8);
            strcpy(result, "unknown");
	}
        else
            result = rfc931((struct sockaddr_in *) & sa_client,
                                    (struct sockaddr_in *) & sa_server);
    }
    else {
	result = (char *) malloc(sizeof(char)*8);
        strcpy(result, "unknown");
    }

    return result; /* robm=pinhead */
}

void get_local_host()
{
    char str[128];
    int len = 128;

    if(!(gConfiguration->httpd_conf & HC_SERVER_HOSTNAME)) {
        struct hostent *p;
        gethostname(str, len);
        if((!(p=gethostbyname(str))) || 
	   (!(gConfiguration->server_hostname = find_fqdn(p)))) {
            fprintf(stderr,"httpd: cannot determine local host name.\n");
            fprintf(stderr,"Use ServerName to set it manually.\n");
            exit(1);
        }
    }
}

void get_local_addr(per_request *reqInfo) {
  struct sockaddr addr;
  int len;

  len = sizeof(struct sockaddr);
  if (getsockname(reqInfo->connection_socket, &addr, &len) < 0) {
    char error_msg[100];
    reqInfo->hostInfo = gConfiguration;
    sprintf(error_msg,"get_local_addr: could not get local address, errno is %d",
    		errno);
    die(reqInfo,SC_SERVER_ERROR,error_msg);
  }
  memcpy(&(reqInfo->address_info),&((struct sockaddr_in *)&addr)->sin_addr,
	 sizeof(struct in_addr));
}

void construct_url(char *full_url, per_host *host, char *url) {
/* Since 80 is default port */
  if (port == 80) {
    sprintf(full_url,"http://%s%s",host->server_hostname,url);
  } else {
    sprintf(full_url,"http://%s:%d%s",host->server_hostname,port,url);
  }
}

/* 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
};

void uudecode(char *bufcoded, unsigned char *bufplain, int outbufsize) {
    int nbytesdecoded;
    register char *bufin = bufcoded;
    register unsigned char *bufout = bufplain;
    register int nprbytes;
    
    /* Strip leading whitespace. */
    
    while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
    
    /* Figure out how many characters are in the input buffer.
     * If this would decode into more bytes than would fit into
     * the output buffer, adjust the number of input bytes downwards.
     */
    bufin = bufcoded;
    while(pr2six[(int) *(bufin++)] <= 63);
    nprbytes = bufin - bufcoded - 1;
    nbytesdecoded = ((nprbytes+3)/4) * 3;
    if(nbytesdecoded > outbufsize) {
        nprbytes = (outbufsize*4)/3;
    }
    
    bufin = bufcoded;
    
    while (nprbytes > 0) {
        *(bufout++) = 
            (unsigned char) (pr2six[(int) *bufin] << 2 | pr2six[(int) bufin[1]] >> 4);
        *(bufout++) = 
            (unsigned char) (pr2six[(int) bufin[1]] << 4 | pr2six[(int) bufin[2]] >> 2);
        *(bufout++) = 
            (unsigned char) (pr2six[(int) bufin[2]] << 6 | pr2six[(int) bufin[3]]);
        bufin += 4;
        nprbytes -= 4;
    }
    
    if(nprbytes & 03) {
        if(pr2six[(int) bufin[-2]] > 63)
            nbytesdecoded -= 2;
        else
            nbytesdecoded -= 1;
    }
    bufplain[nbytesdecoded] = '\0';
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.