⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libhttpd.c

📁 修改后的thttp
💻 C
📖 第 1 页 / 共 5 页
字号:
    {    char buf[1000];    send_mime( hc, status, title, "", extrahead, "text/html", -1, 0 );    (void) sprintf(	buf, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n<BODY><H2>%d %s</H2>\n",	status, title, status, title );    add_response( hc, buf );    (void) sprintf( buf, form, arg );    add_response( hc, buf );    (void) sprintf( buf,	"<HR>\n<ADDRESS><A HREF=\"%s\">%s</A></ADDRESS>\n</BODY></HTML>\n",	SERVER_ADDRESS, SERVER_SOFTWARE );    add_response( hc, buf );    }voidhttpd_send_err( httpd_conn* hc, int status, char* title, char* form, char* arg )    {    send_response( hc, status, title, "", form, arg );    }#ifdef AUTH_FILEstatic voidsend_authenticate( httpd_conn* hc, char* realm )    {    static char* header;    static int maxheader = 0;    static char headstr[] = "WWW-Authenticate: Basic realm=\"";    realloc_str( &header, &maxheader, sizeof(headstr) + strlen( realm ) + 1 );    (void) sprintf( header, "%s%s\"", headstr, realm );    send_response( hc, 401, err401title, header, err401form, hc->encodedurl );    /* If the request was a POST then there might still be data to be read,    ** so we need to do a lingering close.    */    if ( hc->method == METHOD_POST )	hc->should_linger = 1;    }/* Base-64 decoding.  This represents binary data as printable ASCII** characters.  Three 8-bit binary bytes are turned into four 6-bit** values, like so:****   [11111111]  [22222222]  [33333333]****   [111111] [112222] [222233] [333333]**** Then the 6-bit values are represented using the characters "A-Za-z0-9+/".*/static int b64_decode_table[256] = {    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */    52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */    15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */    -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */    41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */    };/* Do base-64 decoding on a string.  Ignore any non-base64 bytes.** Return the actual number of bytes generated.  The decoded size will** be at most 3/4 the size of the encoded, and may be smaller if there** are padding characters (blanks, newlines).*/static intb64_decode( const char* str, unsigned char* space, int size )    {    const char* cp;    int space_idx, phase;    int d, prev_d;    unsigned char c;    space_idx = 0;    phase = 0;    for ( cp = str; *cp != '\0'; ++cp )	{	d = b64_decode_table[*cp];	if ( d != -1 )	    {	    switch ( phase )		{		case 0:		++phase;		break;		case 1:		c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) );		if ( space_idx < size )		    space[space_idx++] = c;		++phase;		break;		case 2:		c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) );		if ( space_idx < size )		    space[space_idx++] = c;		++phase;		break;		case 3:		c = ( ( ( prev_d & 0x03 ) << 6 ) | d );		if ( space_idx < size )		    space[space_idx++] = c;		phase = 0;		break;		}	    prev_d = d;	    }	}    return space_idx;    }static intauth_check( httpd_conn* hc, char* dirname  )    {    static char* authpath;    static int maxauthpath = 0;    struct stat sb;    char authinfo[500];    char* authpass;    int l;    FILE* fp;    char line[500];    char* cryp;    static char* prevauthpath;    static int maxprevauthpath = 0;    static time_t prevmtime;    static char* prevuser;    static int maxprevuser = 0;    static char* prevcryp;    static int maxprevcryp = 0;    /* Construct auth filename. */    realloc_str(	&authpath, &maxauthpath, strlen( dirname ) + 1 + sizeof(AUTH_FILE) );    (void) sprintf( authpath, "%s/%s", dirname, AUTH_FILE );    /* Does this directory have an auth file? */    if ( stat( authpath, &sb ) < 0 )	/* Nope, let the request go through. */	return 0;    /* Does this request contain authorization info? */    if ( hc->authorization[0] == '\0' )	{	/* Nope, return a 401 Unauthorized. */	send_authenticate( hc, dirname );	return -1;	}    /* Basic authorization info? */    if ( strncmp( hc->authorization, "Basic ", 6 ) != 0 )	{	send_authenticate( hc, dirname );	return -1;	}    /* Decode it. */    l = b64_decode( &(hc->authorization[6]), authinfo, sizeof(authinfo) );    authinfo[l] = '\0';    /* Split into user and password. */    authpass = strchr( authinfo, ':' );    if ( authpass == (char*) 0 )	{	/* No colon?  Bogus auth info. */	send_authenticate( hc, dirname );	return -1;	}    *authpass++ = '\0';    /* See if we have a cached entry and can use it. */    if ( maxprevauthpath != 0 &&	 strcmp( authpath, prevauthpath ) == 0 &&	 sb.st_mtime == prevmtime &&	 strcmp( authinfo, prevuser ) == 0 )	{	/* Yes.  Check against the cached encrypted password. */	if ( strcmp( crypt( authpass, prevcryp ), prevcryp ) == 0 )	    {	    /* Ok! */	    realloc_str( &hc->remoteuser, &hc->maxremoteuser, strlen( line ) );	    (void) strcpy( hc->remoteuser, line );	    return 0;	    }	else	    {	    /* No. */	    send_authenticate( hc, dirname );	    return -1;	    }	}    /* Open the password file. */    fp = fopen( authpath, "r" );    if ( fp == (FILE*) 0 )	{	/* The file exists but we can't open it?  Disallow access. */	syslog( LOG_ERR, "fopen auth file %.80s - %m", authpath );	httpd_send_err( hc, 403, err403title, err403form, hc->encodedurl );	return -1;	}    /* Read it. */    while ( fgets( line, sizeof(line), fp ) != (char*) 0 )	{	/* Nuke newline. */	l = strlen( line );	if ( line[l - 1] == '\n' )	    line[l - 1] = '\0';	/* Split into user and encrypted password. */	cryp = strchr( line, ':' );	if ( cryp == (char*) 0 )	    continue;	*cryp++ = '\0';	/* Is this the right user? */	if ( strcmp( line, authinfo ) == 0 )	    {	    /* Yes. */	    (void) fclose( fp );	    /* So is the password right? */	    if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )		{		/* Ok! */		realloc_str( &hc->remoteuser, &hc->maxremoteuser, strlen( line ) );		(void) strcpy( hc->remoteuser, line );		/* And cache this user's info for next time. */		realloc_str(		    &prevauthpath, &maxprevauthpath, strlen( authpath ) );		(void) strcpy( prevauthpath, authpath );		prevmtime = sb.st_mtime;		realloc_str( &prevuser, &maxprevuser, strlen( authinfo ) );		(void) strcpy( prevuser, authinfo );		realloc_str( &prevcryp, &maxprevcryp, strlen( cryp ) );		(void) strcpy( prevcryp, cryp );		return 0;		}	    else		{		/* No. */		send_authenticate( hc, dirname );		return -1;		}	    }	}    /* Didn't find that user.  Access denied. */    (void) fclose( fp );    send_authenticate( hc, dirname );    return -1;    }#endif /* AUTH_FILE */static voidsend_dirredirect( httpd_conn* hc )    {    static char* location;    static char* header;    static int maxlocation = 0, maxheader = 0;    static char headstr[] = "Location: ";    realloc_str( &location, &maxlocation, strlen( hc->encodedurl ) + 1 );    (void) sprintf( location, "%s/", hc->encodedurl );    realloc_str( &header, &maxheader, sizeof(headstr) + strlen( location ) );    (void) sprintf( header, "%s%s", headstr, location );    send_response( hc, 302, err302title, header, err302form, location );    }char*httpd_method_str( int method )    {    switch ( method )	{	case METHOD_GET: return "GET";	case METHOD_HEAD: return "HEAD";	case METHOD_POST: return "POST";	default: return (char*) 0;	}    }static intis_hexit( char c )    {    if ( strchr( "0123456789abcdefABCDEF", c ) != (char*) 0 )	return 1;    return 0;    }static inthexit( char c )    {    if ( c >= '0' && c <= '9' )	return c - '0';    if ( c >= 'a' && c <= 'f' )	return c - 'a' + 10;    if ( c >= 'A' && c <= 'F' )	return c - 'A' + 10;    return 0;		/* shouldn't happen, we're guarded by is_hexit() */    }/* Copies and decodes a string.  It's ok for from and to to be the** same string.*/static voidstrdecode( char* to, char* from )    {    for ( ; *from != '\0'; ++to, ++from )	{	if ( from[0] == '%' && is_hexit( from[1] ) && is_hexit( from[2] ) )	    {	    *to = hexit( from[1] ) * 16 + hexit( from[2] );	    from += 2;	    }	else	    *to = *from;	}    *to = '\0';    }inthttpd_get_nfiles( void )    {#ifdef EMBED    return(8);#else    static int inited = 0;    static int n;    if ( ! inited )	{#ifdef RLIMIT_NOFILE	struct rlimit rl;	if ( getrlimit( RLIMIT_NOFILE, &rl ) < 0 )	    {	    syslog( LOG_ERR, "getrlimit - %m" );	    exit( 1 );	    }	if ( rl.rlim_max == RLIM_INFINITY )	    rl.rlim_cur = 4096;		/* arbitrary */	else	    rl.rlim_cur = rl.rlim_max;	if ( setrlimit( RLIMIT_NOFILE, &rl ) < 0 )	    {	    syslog( LOG_ERR, "setrlimit - %m" );	    exit( 1 );	    }	n = rl.rlim_cur;#else /* RLIMIT_NOFILE */	n = getdtablesize();#endif /* RLIMIT_NOFILE */	inited = 1;	}    return n;#endif    }/* Map a ~username/whatever URL into something else.  Two different ways. */static inttilde_map( httpd_conn* hc )    {#if defined(TILDE_MAP_1) || defined(TILDE_MAP_2)    static char* temp;    static int maxtemp = 0;#endif#ifdef TILDE_MAP_1    /* Map ~username to <prefix>/username. */    int len;    static char* prefix = TILDE_MAP_1;    len = strlen( hc->expnfilename ) - 1;    realloc_str( &temp, &maxtemp, len );    (void) strcpy( temp, &hc->expnfilename[1] );    realloc_str(	&hc->expnfilename, &hc->maxexpnfilename, strlen( prefix ) + 1 + len );    (void) strcpy( hc->expnfilename, prefix );    if ( prefix[0] != '\0' )	(void) strcat( hc->expnfilename, "/" );    (void) strcat( hc->expnfilename, temp );#endif /* TILDE_MAP_1 */#ifdef TILDE_MAP_2    /* Map ~username to <user's homedir>/<postfix>. */    static char* postfix = TILDE_MAP_2;    char* cp;    struct passwd* pw;    /* Get the username. */    realloc_str( &temp, &maxtemp, strlen( hc->expnfilename ) - 1 );    (void) strcpy( temp, &hc->expnfilename[1] );    cp = strchr( temp, '/' );    if ( cp != (char*) 0 )	*cp++ = '\0';    else	cp = "";        /* Get the passwd entry. */    pw = getpwnam( temp );    if ( pw == (struct passwd*) 0 )	return 0;        /* Set up altdir. */    realloc_str(	&hc->altdir, &hc->maxaltdir,	strlen( pw->pw_dir ) + 1 + strlen( postfix ) );    (void) strcpy( hc->altdir, pw->pw_dir );    if ( postfix[0] != '\0' )	{	(void) strcat( hc->altdir, "/" );	(void) strcat( hc->altdir, postfix );	}    /* And the filename becomes altdir plus the post-~ part of the original. */    realloc_str(	&hc->expnfilename, &hc->maxexpnfilename,	strlen( hc->altdir ) + 1 + strlen( cp ) );    (void) sprintf( hc->expnfilename, "%s/%s", hc->altdir, cp );#endif /* TILDE_MAP_2 */    return 1;    }/* Expands all symlinks in the given filename, eliding ..'s and leading /'s.** Returns the expanded path (pointer to static string), or (char*) 0 on** errors.  Also returns, in the string pointed to by restP, any trailing** parts of the path that don't exist.**** This is a fairly nice little routine.  It handles any size filenames** without excessive mallocs.*/static char*expand_symlinks( char* path, char** restP, int chrooted )    {    static char* checked;    static char* rest;#ifdef EMBED    char link[2048];#else    char link[5000];#endif    static int maxchecked = 0, maxrest = 0;    int checkedlen, restlen, linklen, prevcheckedlen, prevrestlen, nlinks, i;    char* r;    char* cp1;    char* cp2;    if ( chrooted )	{	/* If we are chrooted, we can actually skip the symlink-expansion,	** since it's impossible to get out of the tree.  However, we still	** need to do the pathinfo check, and the existing symlink expansion	** code is a pretty reasonable way to do this.  So, what we do is	** a single stat() of the whole filename - if it exists, then we	** return it as is with nothing in restP.  If it doesn't exist, we	** fall through to the existing code.	**	** One side-effect of this is that users can't symlink to central	** approved CGIs any more.  The workaround is to use the central	** URL for the CGI instead of a local symlinked one.	*/	struct stat sb;	if ( stat( path, &sb ) != -1 )	    {	    realloc_str( &checked, &maxchecked, strlen( path ) );	    (void) strcpy( checked, path );	    realloc_str( &rest, &maxrest, 0 );	    rest[0] = '\0';	    *restP = rest;	    return checked;	    }	}    /* Start out with nothing in checked and the whole filename in rest. */    realloc_str( &checked, &maxchecked, 1 );    checked[0] = '\0';    checkedlen = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -