/*
   cipelib - library routines common to CIPE (user-mode part) and PKCIPE

   Copyright 2000 Olaf Titz <olaf@bigred.inka.de>

   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.
*/
/* $Id: socks5_open.c,v 1.2 2000/11/22 20:23:38 olaf Exp $ */

#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "cipelib.h"
#include "socks5_internal.h"

int socks5_open(struct sockaddr_in *so)
{
    int e;
    char *su=getenv("SOCKS5_USER");
    char *sp=getenv("SOCKS5_PASSWD");
    char buf[520];

    int fd=socket(AF_INET, SOCK_STREAM, 0);
    if (fd<0) {
	cipe_syslog(LOG_ERR, "socks5_open: socket: %m"); return -1;
    }
    if (connect(fd, (struct sockaddr *)so, sizeof(*so))<0) {
	cipe_syslog(LOG_ERR, "socks5_open: connect: %m");
	goto error;
    }
    if (su)
	e=writen(fd, "\005\002\000\002", 4, "socks5_open: winit");
    else
	e=writen(fd, "\005\001\000", 3, "socks5_open: winit");
    if (e<0)
	goto error;
    if (readn(fd, buf, 2, "socks5_open: rinit")<2)
	goto error;

    switch (buf[1]) {
    case '\000':
	break;
    case '\002':
    {
	unsigned char l;
	int lu, lp;

	if (!su) su="";
	if (!sp) sp="";
	lu=strlen(su); lu=MIN(lu, 255);
	lp=strlen(sp); lp=MIN(lp, 255);
	if ((writen(fd, "\001", 1, "socks5_open: wauth1")<0) ||
	    (l=lu, writen(fd, &l, 1, "socks5_open: wauth2")<0) ||
	    (writen(fd, su, lu, "socks5_open: wauth3")<0) ||
	    (l=lp, writen(fd, &l, 1, "socks5_open: wauth4")<0) ||
	    (writen(fd, sp, lp, "socks5_open: wauth5")<0))
	    goto error;
	if (readn(fd, buf, 2, "socks5_open: rauth")<0)
	    goto error;
	if (buf[1]!=0) {
	    cipe_syslog(LOG_ERR, "socks5_open: authentication failed");
	    goto error;
	}
	break;
    }
    default:
	cipe_syslog(LOG_ERR, "socks5_open: authentication required");
	goto error;
    }
    return fd;

 error:
    close(fd);
    return -1;
}
