Hello oops-users,

1096976240.000 2246 192.168.1.25 TCP_MISS/200 5602 GET http://zadorno.com/ kot 
DIRECT/zadorno.com text/html
1096976242.000 414 192.168.1.25 TCP_MISS/200 2407 GET 
http://zadorno.com/archives/dance.gif kot DIRECT/zadorno.com image/gif
1096976242.000 496 192.168.1.25 TCP_MISS/200 5857 GET 
http://zadorno.com/archives/Edos_05-10-012-1.jpg kot DIRECT/zadorno.com image/jpeg
1096976242.000 2800 192.168.1.25 TCP_ERROR/200 4027 GET http://zadorno.com/zadorno.css 
kot DIRECT/zadorno.com text/css

и всё, дальше не отдаёт :( почему так может случаться? В логах совсем
пусто :((( код ошибки не при делах - обрывается и просто так :(

NTLM, т.е. IE работает прекрасно, а вот опера... Может я чего
проглядел?

-- 
Best regards,
 Konstantin Nikonenko        http://www.kot.dp.ua/

P.S. Теперь как отдельный модуль ;)

В IIS разрешить внутреннюю проверку и обычным текстом, анонимус
запретить ;)

/usr/local/src/oops# grep -Ri win_http * | grep -v "win_http.c"
src/modules.c:    insert_module(&win_http.general, (struct general_module 
**)&auth_first);
src/modules.h:extern    struct  auth_module     win_http;
src/modules/Makefile.in:        [EMAIL PROTECTED]@ \
src/modules/Makefile:   win_http.so \

module pam {
        # This line is string in client's auth request header
        realm           Enter You Login and Password to access.

        scheme          Basic
        service         oops

        template        /usr/local/oops/auth_template.html
}

module win_http {
        # This line is string in client's auth request header
        realm           Enter You Login and Password to access.

        # Possible are 'Basic' or 'NTLM' only
        # If basic is set - we never request to client other scheme
        # If NTLM auth is fails proxy request Basic Auth and only after there denied
        scheme          NTLM

        # NT server IP (only), where all users are live.
        nt_server       192.168.1.6

        # Now we are supported only HTTP service helper
        nt_port         HTTP

        template        /usr/local/oops/auth_template.html
}
/*
Copyright (C) 1999 Igor Khasilev, [EMAIL PROTECTED]
Copyright (C) 2003,2004 Konstantin Nikonenko, <[EMAIL PROTECTED]>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
/* From Kostya:
to setup Win IIS Server remove flag from anonymous login to main page, 
allow Plain text auth and internal mechanism.
You can manupalete allow user or deny from real time ;)
*/

#include        "../oops.h"
#include        "../modules.h"

#define MODULE_NAME     "win_http"
#define MODULE_INFO     "Auth using NTLM or Basic on Win2k HTTP server"
#define MODULE_BR14     "Auth using Win2k HTTP server"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#if     defined(MODULES)
#define MODPREF
#else
#define MODPREF  static
#endif

MODPREF char            module_type             = MODULE_AUTH;
MODPREF char            module_name[]           = MODULE_NAME;
MODPREF char            module_info[MODINFOLEN] = MODULE_BR14;

MODPREF int             mod_load(void);
MODPREF int             mod_unload(void);
MODPREF int             mod_config_beg(int), mod_config_end(int), 
mod_config(char*,int), mod_run(void);
MODPREF int             auth(int so, struct group *group, struct request* rq, int 
*flags);

struct  auth_module     win_http = {
        {
        NULL, NULL,
        MODULE_NAME,
        mod_load,
        mod_unload,
        mod_config_beg,
        mod_config_end,
        mod_config,
        NULL,
        MODULE_AUTH,
        MODULE_INFO,
        mod_run
        },
        auth
};


static  pthread_rwlock_t        pwf_lock;
static  char    *pwds = NULL;
static  char    *template = NULL;
static  time_t  pwf_mtime, pwf_check_time;
static  time_t  pwf_template_mtime, pwf_template_check_time;
static  int     pwf_template_len;
static  char    pwf_name[MAXPATHLEN];
static  char    pwf_template[MAXPATHLEN];
static  char    pwf_charset[64];
static  char    realm[64];
static  enum    {Basic,NTLM} scheme = Basic;

static  char    *authreq = NULL;
static  int      authreqlen;
static  char    *authreqfmt = "%s\nProxy-Authenticate: Basic realm=\"%s\"";
static  char    *authreqfmt_b = "%s\n realm=\"%s\"";
static  char    *std_template = "\n<body>Authorization to proxy-server 
failed.<p><hr>\n\
<i><font size=-1>by \'win_http\' module to Oops.";
static  int     std_template_len;
static  int     pwf_charset_len;
static  int     badschlen;
static  char    *badsch=NULL;
static  char    *badschfmt = "HTTP/1.0 407 Proxy Authentication required\n\
Proxy-Authenticate: %s realm=\"%s\"\n\n\
<body>Authorization to proxy-server failed.<p>\n\
Your browser proposed unsupported scheme\n\
<hr>\n\
<i><font size=-1>by \'Win-http\' module to Oops.";

#define RDLOCK_PWF_CONFIG       pthread_rwlock_rdlock(&pwf_lock)
#define WRLOCK_PWF_CONFIG       pthread_rwlock_wrlock(&pwf_lock)
#define UNLOCK_PWF_CONFIG       pthread_rwlock_unlock(&pwf_lock)

static  void    reload_pwf_template(void);
static  void    check_pwf_template_age(void);
static  void    send_auth_req(int, struct request *);

static int read_from(int , char *, int type);           // Functions to make dialog 
with NT HTTP 
static int send_to(int, char *, int type);              // service about NTLM auth. 
types: 0 - server, 1-client, 2-Basic

static char nt_server[16];              // NT Server IP, not name
static unsigned int nt_port=80;                 // port, where we send NTLM structures

static struct servent    *sp;
static struct sockaddr_in hin;
static int unit, s;
static char client_data[2047];

#if     !defined(SOLARIS)
pthread_mutex_t crypt_lock;
#endif

int
mod_run(void)
{
    return(MOD_CODE_OK);
}

int
mod_load(void)
{
    snprintf(module_info, sizeof(module_info)-1, MODULE_INFO);

    pthread_rwlock_init(&pwf_lock, NULL);
#if     !defined(SOLARIS)
    pthread_mutex_init(&crypt_lock, NULL);
#endif
    std_template_len = strlen(std_template);

    printf("WIN_HTTP started\n");

    return(MOD_CODE_OK);
}

int
mod_unload(void)
{
    printf("Win_http stopped\n");
    pthread_rwlock_destroy(&pwf_lock);
    return(MOD_CODE_OK);
}

int
mod_config_beg(int i)
{
    WRLOCK_PWF_CONFIG ;
    if ( pwds ) free(pwds); pwds = 0;
    if ( authreq ) free(authreq); authreq = 0;
    if ( badsch ) free(badsch); badsch = 0;
    if ( template ) free(template); template = 0;
    pwf_name[0]         = 0;
    pwf_template[0]     = 0;
    pwf_charset[0]      = 0;
    pwf_mtime = pwf_template_mtime = 0;
    strcpy(realm, "oops") ;
    nt_server[0]        = 0;
    scheme = Basic;
    pwf_check_time = 0 ;
    pwf_mtime      = 0 ;
    UNLOCK_PWF_CONFIG ;
    return(MOD_CODE_OK);
}

int
mod_config_end(int i)
{
char    *sch="None";

    WRLOCK_PWF_CONFIG ;
    if ( scheme == Basic ) {
        sch = "Basic";
        // If basic is set - we never request to client other scheme
        authreqfmt = authreqfmt_b;      
    } else {
      if ( scheme == NTLM  ){
         sch = "NTLM";
      } else {
        my_xlog(OOPS_LOG_NOTICE|OOPS_LOG_DBG|OOPS_LOG_INFORM, "Win_http: Unsupported 
scheme\n");
        UNLOCK_PWF_CONFIG ;
        return(MOD_CODE_ERR);
      }
    }        
    authreqlen = 0;
    authreq = malloc(strlen(authreqfmt)+1+strlen(realm)+strlen(sch));
    if ( authreq ) {
        sprintf(authreq, authreqfmt, sch, realm);
        authreqlen = strlen(authreq);
    }

    badschlen = 0;
    badsch = malloc(strlen(badschfmt)+1+strlen(realm)+strlen(sch));
    if ( badsch ) {
        sprintf(badsch, badschfmt, sch, realm);
        badschlen = strlen(badsch);
    }

    if ( pwf_template[0] )
        reload_pwf_template();
    UNLOCK_PWF_CONFIG ;
    return(MOD_CODE_OK);
}

int
mod_config(char *config, int i)
{

char    *p = config;

    WRLOCK_PWF_CONFIG ;

    while( *p && IS_SPACE(*p) ) p++;
    if ( !strncasecmp(p, "realm", 5) ) {
        p += 5;
        while (*p && IS_SPACE(*p) ) p++;
        strncpy(realm, p, sizeof(realm) -1 );
    } else
    if ( !strncasecmp(p, "template", 8) ) {
        p += 8;
        while (*p && IS_SPACE(*p) ) p++;
        strncpy(pwf_template, p, sizeof(pwf_template) -1 );
    } else
    if ( !strncasecmp(p, "charset", 7) ) {
        p += 7;
        while (*p && IS_SPACE(*p) ) p++;
        sprintf(pwf_charset, "Content-Type: text/html; charset=%.20s\n", p);
        pwf_charset_len = strlen(pwf_charset);
    } else
    if ( !strncasecmp(p, "scheme", 6) ) {
        p += 6;
        while (*p && IS_SPACE(*p) ) p++;
        if ( !strcasecmp(p, "basic") )  scheme = Basic;
        if ( !strcasecmp(p, "NTLM") ) scheme = NTLM;
    }
    if ( !strncasecmp(p, "nt_server", 9) ) {
        p += 9;
        while (*p && IS_SPACE(*p) ) p++;
        strncpy(nt_server, p, sizeof(nt_server) -1);
    }

    if ( !strncasecmp(p, "nt_port", 7) ) {
        p += 7;
        while (*p && IS_SPACE(*p) ) p++;
        if ( !strcasecmp(p, "HTTP") )  nt_port = 80;
    }

    UNLOCK_PWF_CONFIG ;
    return(MOD_CODE_OK);
}

int
auth(int so, struct group *group, struct request* rq, int *flags) {
char    *authorization = NULL;
struct  output_object   *reply_obj = NULL;

    if ( !authreq ) {
        my_xlog(OOPS_LOG_NOTICE|OOPS_LOG_DBG|OOPS_LOG_INFORM, "auth(): Something wrong 
with Win_http module.\n");
        return(MOD_CODE_OK);
    }
    WRLOCK_PWF_CONFIG ;
    if ( rq->av_pairs)
        authorization = attr_value(rq->av_pairs, "Proxy-Authorization");
    if ( !authorization ) {
        /* send 407 Proxy Authentication Required */
        send_auth_req(so, rq);
        SET(*flags, MOD_AFLAG_OUT);
        UNLOCK_PWF_CONFIG;
        return(MOD_CODE_ERR);
    } else {
        char *data;
        if ( !strncasecmp(authorization, "Basic", 5 ) ) {
          int    rc;
          char  *up=NULL, *p;
            data = authorization + 5;
            while ( *data && IS_SPACE(*data) ) data++;
          send_to_ntlm(unit, client_data, 0);
            if ( *data ) up = base64_decode(data);
            if ( up ) {
                /* up = username:password */
                p = strchr(up, ':');
                if ( p ) { *p=0; p++; }

                hin.sin_family = AF_INET;           // host byte order
                hin.sin_port = htons(nt_port);      // short, network byte order
                hin.sin_addr.s_addr = inet_addr(nt_server);
                memset(&(hin.sin_zero), '\0', 8);   // zero the rest of the struct
                memcpy(client_data, data, 2047);
                if ((unit=socket(AF_INET,SOCK_STREAM,0)) > 0)
                {
                 if (connect(unit,(struct sockaddr *)&hin,sizeof(hin)) != -1)
                 {
                        send_to_ntlm(unit, client_data, 2);
                        rc = recv_from_ntlm(unit, client_data, 2);
                 // end if connect
                 } else 
                   my_xlog(OOPS_LOG_NOTICE|OOPS_LOG_DBG|OOPS_LOG_INFORM, "Can't 
connect to server %s\n", nt_server);
                 close(unit);
                } // end if create socket unit

                if ( rc != 2 ) {
                    /*failed*/
                    free(up);
                    send_auth_req(so, rq);
                    SET(*flags, MOD_AFLAG_OUT);
                    UNLOCK_PWF_CONFIG;
                    return(MOD_CODE_ERR);
                  } else {
                    IF_STRDUP(rq->proxy_user, up);
                    free(up);
                    SET(*flags, MOD_AFLAG_CKACC);
                    UNLOCK_PWF_CONFIG;
                    return(MOD_CODE_OK);
                  }
            } /* up != NULL */
        } else {
            if ( !strncasecmp(authorization, "NTLM", 4 ) ) {
                data = authorization + 4;
                while ( *data && IS_SPACE(*data) ) data++;
                if ( *data ) {
                 hin.sin_family = AF_INET;           // host byte order
                 hin.sin_port = htons(nt_port);      // short, network byte order
                 hin.sin_addr.s_addr = inet_addr(nt_server);
                 memset(&(hin.sin_zero), '\0', 8);   // zero the rest of the struct
                 memcpy(client_data, data, 2047);
                 if ((unit=socket(AF_INET,SOCK_STREAM,0)) > 0)
                 {
                  if (connect(unit,(struct sockaddr *)&hin,sizeof(hin)) != -1)
                  {
                     // Step 2
                     // We are received first NTLN hash from client and now send to 
HTTP
// Client  -> Server NTLM 1 hash
                     send_to_ntlm(unit, client_data, 0);
                     if(recv_from_ntlm(unit, client_data,0))
                     {
// Server -> Client NTLM 2 hash

                        // Reply to client second hash, who was received from NT HTTP
                        send_to_ntlm(so, client_data, 1);
                        if( recv_from_ntlm(so, client_data, 1) ) {
                                  // Step 3
// Client -> Server NTLM 3 hash
                                  // Client encode server unswer and we send it ti HTTP
                                  send_to_ntlm(unit, client_data, 0);
                                  if(recv_from_ntlm(unit, client_data,0) == 2){
                                        // Server -> Got HTTP 200 Ok
                                        close(unit);
                                        IF_STRDUP(rq->proxy_user, client_data);
                                        SET(*flags, MOD_AFLAG_CKACC);
                                        UNLOCK_PWF_CONFIG;
                                        return(MOD_CODE_OK);
                                  } else {
                                        
my_xlog(OOPS_LOG_NOTICE|OOPS_LOG_DBG|OOPS_LOG_INFORM, "Code NTLM is not 200\nReturn to 
Basic scheme\n");
                                  }
                        }

                     }  // end if receive_from_ntlm
                  // end if connect
                  } else my_xlog(OOPS_LOG_NOTICE|OOPS_LOG_DBG|OOPS_LOG_INFORM, "Can't 
connect to server %s\n", nt_server);
                  close(unit);
                 } // end if create socket unit
                } // end if NTLM have data
                // Begin proposal Basic scheme
                sprintf(client_data, "\
HTTP/1.1 407 Proxy Authentication Required\n\
Proxy-Authenticate: Basic realm %s\n\
Connection: Keep-Alive\n\
Content-Type: text/html\n\n", realm);
                send(so, client_data, sizeof(client_data), 0);
                SET(*flags, MOD_AFLAG_OUT);
                UNLOCK_PWF_CONFIG;
                return(MOD_CODE_ERR);                   
            } else {
                /* we do not support any schemes except Basic or NTLM */
                writet(so, badsch, badschlen, 30);
                SET(*flags, MOD_AFLAG_OUT);
            }
        }
    UNLOCK_PWF_CONFIG;
    return(MOD_CODE_ERR);
    }
}

int send_to_ntlm(int server, char *cl_data, int type)
{
        char serv_request[2047];
        const char *my_content="<HTML><HEAD>Unauthorized<p></HEAD>\n<BODY>Unauthorized 
access</BODY></HTML>\n";
        memset(serv_request, '\0', 2047);
        if(type == 1){
          // Type is 1 - To Client
          sprintf( serv_request,"\
HTTP/1.1 407 Proxy Authentication Required\n\
Proxy-Authenticate: NTLM %s\
Connection: Keep-Alive\n\
Content-Length: %d\n\
Content-Type: text/html\n\n%s", cl_data, strlen(my_content), my_content);
        } else {
                if(type == 0){
                  // Type is 0 - To Server
                  sprintf( serv_request,"\
HEAD / HTTP/1.1\n\
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, 
application/msword, application/vnd.ms-powerpoint, */*\n\
Accept-Language: ru\n\
Accept-Encoding: gzip, deflate\n\
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)\n\
Host: %s\n\
Connection: Keep-Alive\n\
Authorization: NTLM %s\n\n",nt_server,cl_data);
                } else {
                // type is 2 - Basic
                  sprintf( serv_request,"\
HEAD / HTTP/1.1\n\
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, 
application/msword, application/vnd.ms-powerpoint, */*\n\
Accept-Language: ru\n\
Accept-Encoding: gzip, deflate\n\
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)\n\
Host: %s\n\
Connection: Keep-Alive\n\
Authorization: Basic %s\n\n",nt_server,cl_data);
                }
        }
        send(server, serv_request, strlen(serv_request),0);
        return 1;
}

int recv_from_ntlm(int client, char *cl_data, int type)
{
     char cl_str[1], *str_str, *where, end_str[2047];
     int data_size, r;
     const char *ntlm_string=" NTLM ";
     char *w_str=cl_data;
     struct pollarg polling;

     memcpy(end_str,cl_data,2047);
     memset(cl_data,'\0', 2047);
     if( type ){
     forever() {
        polling.fd = client;
        polling.request = FD_POLL_RD;
        r = poll_descriptors(1, &polling, READ_ANSW_TIMEOUT*8);
        if ( r < 0  ) {
            my_xlog(OOPS_LOG_SEVERE, "recv_from_ntlm(): select: error.\n");
            return 0;
        }
        if ( r == 0 ) {
            my_xlog(OOPS_LOG_SEVERE, "recv_from_ntlm(): select: timed out.\n");
            return 0;
        }
        if ( IS_HUPED(&polling) ) {
            my_xlog(OOPS_LOG_SEVERE, "recv_from_ntlm(): Client closed connection too 
early.\n");
            return 0;
        }
        if ( IS_READABLE(&polling) )
                break;
      }
     }

     while((data_size=recv(client,cl_str,1,0)) != -1){
           if(*cl_str == '\n' && *(w_str-2) == '\n') break;
           *(w_str++) = *cl_str;
     }

     if ( type ){
        polling.fd = client;
        polling.request = FD_POLL_WR;
        poll_descriptors(1, &polling, READ_ANSW_TIMEOUT*8);
     }

     // Search NTLM string
        if( (where=strstr(cl_data, ntlm_string)) != NULL){
            w_str = where;
            while( *where++ != '\n' );
                *where = '\0';
            strcpy(cl_data, w_str+strlen(ntlm_string));
            return 1;
        } else {
            if( (where=strstr(cl_data, "200 OK")) != NULL ){
                if (type == 2) return 2;

                char *temp = base64_decode(end_str), username[255];
                int user_offset, user_len, i;
                user_offset=*(temp+40);
                user_len   =*(temp+36);
                memset(cl_data, '\0', user_len);
                for(i=0;i<user_len;i+=2){
                  *(cl_data++) = *(temp+user_offset+i);
                }
                free(temp);
                return 2;
            }
        }
      if(data_size == -1) perror("recv()");
      my_xlog(OOPS_LOG_NOTICE|OOPS_LOG_DBG|OOPS_LOG_INFORM, "Unknown NTLM reply\n"); 
 return 0;
}


/*
static void
check_pwf_template_age(void)
{
    if ( global_sec_timer - pwf_template_check_time < 60 ) return;
    reload_pwf_template();
}
*/

static void
reload_pwf_template(void)
{
struct  stat    sb;
int             rc, size, fd;

    if ( !pwf_template[0] ) return;

        my_xlog(OOPS_LOG_NOTICE|OOPS_LOG_DBG|OOPS_LOG_INFORM, "Win_http: reload pwf 
template\n");

    rc = stat(pwf_template, &sb);
    if ( rc != -1 ) {
        if ( sb.st_mtime <= pwf_template_mtime ) return;
        size = sb.st_size;
        if ( size <= 0 ) return;
        if ( template ) free(template); template = NULL;
        template = xmalloc(size,"reload_pwf_template(): 1");
        if ( template ) {
            fd = open(pwf_template, O_RDONLY);
            if ( fd != -1 ) {
                rc = read(fd, template, size);
                if ( rc != size ) {
                    free(template);template = NULL;
                } else {
                    pwf_template_mtime = sb.st_mtime;
                    pwf_template_check_time = global_sec_timer;
                    pwf_template_len = size;
                }
                close(fd);
            } else {
                free(template); template = NULL;
            }
        }
    }
}

static void
send_auth_req(int so, struct request *rq)
{
struct  output_object   *obj;
struct  buff            *body;
int                     rc;

    obj = xmalloc(sizeof(*obj),"send_auth_req(): obj");
    if ( !obj )
        return;

    bzero(obj, sizeof(*obj));

    put_av_pair(&obj->headers,"HTTP/1.0", "407 Proxy Authentication Required");
    put_av_pair(&obj->headers,"Proxy-Authenticate:", authreq);
    put_av_pair(&obj->headers,"Content-Type:", "text/html");

    if ( !template ) body = alloc_buff(std_template_len);
        else         body = alloc_buff(pwf_template_len);
    if ( body ) {
        obj->body = body;
        if ( !template )
                rc = attach_data(std_template, std_template_len, body);
            else
                rc = attach_data(template, pwf_template_len, body);
        if ( !rc )
                process_output_object(so, obj, rq);
    }

    free_output_obj(obj);
    return;
}

Дати відповідь електронним листом