From: hno <> Date: Mon, 20 May 2002 05:42:39 +0000 (+0000) Subject: Samba Winbind ntlm and basic authentication helpers by Francesco Chemolli X-Git-Tag: SQUID_3_0_PRE1~1015 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ff84874ee573cd235b37bde2d5d9f97a38074e6d;p=thirdparty%2Fsquid.git Samba Winbind ntlm and basic authentication helpers by Francesco Chemolli --- diff --git a/configure.in b/configure.in index f2b12a99f3..c7b5e7f20d 100644 --- a/configure.in +++ b/configure.in @@ -3,15 +3,15 @@ dnl Configuration input file for Squid dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.269 2002/05/19 15:07:55 hno Exp $ +dnl $Id: configure.in,v 1.270 2002/05/19 23:42:39 hno Exp $ dnl dnl dnl AC_INIT(src/main.c) AC_CONFIG_AUX_DIR(cfgaux) -AM_INIT_AUTOMAKE(squid, 2.6-DEVEL) +AM_INIT_AUTOMAKE(Squid, 2.6-DEVEL) AM_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.269 $)dnl +AC_REVISION($Revision: 1.270 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -2254,6 +2254,7 @@ AC_OUTPUT([\ src/auth/ntlm/helpers/no_check/Makefile \ src/auth/ntlm/helpers/SMB/Makefile \ src/auth/ntlm/helpers/SMB/smbval/Makefile \ + src/auth/ntlm/helpers/winbind/Makefile \ contrib/Makefile \ snmplib/Makefile \ icons/Makefile \ diff --git a/helpers/basic_auth/winbind/Makefile.am b/helpers/basic_auth/winbind/Makefile.am new file mode 100644 index 0000000000..dd8c4984b6 --- /dev/null +++ b/helpers/basic_auth/winbind/Makefile.am @@ -0,0 +1,11 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: Makefile.am,v 1.1 2002/05/19 23:42:40 hno Exp $ +# + +libexec_PROGRAMS = wb_auth +wb_auth_SOURCES = wb_basic_auth.c wb_common.c +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src +LDADD = -L$(top_builddir)/lib -lmiscutil -lntlmauth diff --git a/helpers/basic_auth/winbind/samba_nss.h b/helpers/basic_auth/winbind/samba_nss.h new file mode 100644 index 0000000000..6165e0b24a --- /dev/null +++ b/helpers/basic_auth/winbind/samba_nss.h @@ -0,0 +1,105 @@ +#ifndef _NSSWITCH_NSS_H +#define _NSSWITCH_NSS_H +/* + Unix SMB/Netbios implementation. + Version 2.0 + + a common place to work out how to define NSS_STATUS on various + platforms + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_NSS_COMMON_H + +/* Sun Solaris */ + +#include +#include +#include + +typedef nss_status_t NSS_STATUS; + +#define NSS_STATUS_SUCCESS NSS_SUCCESS +#define NSS_STATUS_NOTFOUND NSS_NOTFOUND +#define NSS_STATUS_UNAVAIL NSS_UNAVAIL +#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN + +#elif HAVE_NSS_H + +/* GNU */ + +#include + +typedef enum nss_status NSS_STATUS; + +#elif HAVE_NS_API_H + +/* SGI IRIX */ + +/* following required to prevent warnings of double definition + * of datum from ns_api.h +*/ +#ifdef DATUM +#define _DATUM_DEFINED +#endif + +#include + +typedef enum +{ + NSS_STATUS_SUCCESS=NS_SUCCESS, + NSS_STATUS_NOTFOUND=NS_NOTFOUND, + NSS_STATUS_UNAVAIL=NS_UNAVAIL, + NSS_STATUS_TRYAGAIN=NS_TRYAGAIN +} NSS_STATUS; + +#define NSD_MEM_STATIC 0 +#define NSD_MEM_VOLATILE 1 +#define NSD_MEM_DYNAMIC 2 + +#elif defined(HPUX) +/* HP-UX 11 */ + +#include "nsswitch/hp_nss_common.h" +#include "nsswitch/hp_nss_dbdefs.h" +#include + +#ifndef _HAVE_TYPEDEF_NSS_STATUS +#define _HAVE_TYPEDEF_NSS_STATUS +typedef nss_status_t NSS_STATUS; + +#define NSS_STATUS_SUCCESS NSS_SUCCESS +#define NSS_STATUS_NOTFOUND NSS_NOTFOUND +#define NSS_STATUS_UNAVAIL NSS_UNAVAIL +#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN +#endif /* HPUX */ + +#else /* Nothing's defined. Neither gnu nor sun nor hp */ + +typedef enum +{ + NSS_STATUS_SUCCESS=0, + NSS_STATUS_NOTFOUND=1, + NSS_STATUS_UNAVAIL=2, + NSS_STATUS_TRYAGAIN=3 +} NSS_STATUS; + +#endif + +#endif /* _NSSWITCH_NSS_H */ diff --git a/helpers/basic_auth/winbind/wb_basic_auth.c b/helpers/basic_auth/winbind/wb_basic_auth.c new file mode 100644 index 0000000000..ff9db92fcb --- /dev/null +++ b/helpers/basic_auth/winbind/wb_basic_auth.c @@ -0,0 +1,121 @@ +/* + * (C) 2000 Francesco Chemolli + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * 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, USA. + * + */ + + +#include "wbntlm.h" +#include "util.h" +/* stdio.h is included in wbntlm.h */ +#include +#include +#include +#include /* for gettimeofday */ +#include /* BUG: is this portable? */ + +#include "winbind_nss_config.h" +#include "winbindd_nss.h" + +char debug_enabled=1; +char *myname; +pid_t mypid; + +NSS_STATUS winbindd_request(int req_type, + struct winbindd_request *request, + struct winbindd_response *response); + + +void do_authenticate(char *user, char *pass) { + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS winbindd_result; + + memset(&request,0,sizeof(struct winbindd_request)); + memset(&response,0,sizeof(struct winbindd_response)); + + + strncpy(request.data.auth.user,user,sizeof(fstring)-1); + strncpy(request.data.auth.pass,pass,sizeof(fstring)-1); + + winbindd_result = winbindd_request(WINBINDD_PAM_AUTH, + &request, &response); + debug("winbindd result: %d\n",winbindd_result); + + if (winbindd_result==WINBINDD_OK) { + SEND("OK"); + } else { + SEND("ERR"); + } + + return; /* useless */ +} + +void manage_request(void) { + char buf[BUFFER_SIZE+1]; + int length; + char *c, *user, *pass; + + if (fgets(buf, BUFFER_SIZE, stdin) == NULL) { + warn("fgets() failed! dying..... errno=%d (%s)\n", errno, + strerror(errno)); + exit(1); /* BIIG buffer */ + } + + c=memchr(buf,'\n',BUFFER_SIZE); + if (c) { + *c='\0'; + length=c-buf; + } + else { + warn("No newline in '%s'. Dying.\n",buf); + exit(1); + } + + debug("Got '%s' from squid (length: %d).\n",buf,length); + user=buf; + + pass=memchr(buf,' ',length); + if (!pass) { + warn("Password not found. Denying access\n"); + SEND("ERR"); + return; + } + *pass='\0'; + pass++; + + do_authenticate(user,pass); + +} + +int main (int argc, char ** argv) { + if (argc > 0) { /* should always be true */ + myname=strrchr(argv[0],'/'); + if (myname==NULL) + myname=argv[0]; + } else { + myname="(unknown)"; + } + mypid=getpid(); + debug("ntlm winbindd auth helper build " __DATE__ ", " __TIME__ + " starting up...\n"); + /* initialize FDescs */ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + while(1) { + manage_request(); + } + return 0; +} diff --git a/helpers/basic_auth/winbind/wb_common.c b/helpers/basic_auth/winbind/wb_common.c new file mode 100644 index 0000000000..1049529452 --- /dev/null +++ b/helpers/basic_auth/winbind/wb_common.c @@ -0,0 +1,398 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + winbind client common code + + Copyright (C) Tim Potter 2000 + Copyright (C) Andrew Tridgell 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "winbind_nss_config.h" +#include "winbindd_nss.h" +#include "config.h" + + +/* Global variables. These are effectively the client state information */ + +int winbindd_fd = -1; /* fd for winbindd socket */ +static char *excluded_domain; + +/* Free a response structure */ + +void free_response(struct winbindd_response *response) +{ + /* Free any allocated extra_data */ + + if (response) + SAFE_FREE(response->extra_data); +} + +/* + smbd needs to be able to exclude lookups for its own domain +*/ +void winbind_exclude_domain(const char *domain) +{ + SAFE_FREE(excluded_domain); + excluded_domain = strdup(domain); +} + + +/* Initialise a request structure */ + +void init_request(struct winbindd_request *request, int request_type) +{ + static char *domain_env; + static BOOL initialised; + + request->length = sizeof(struct winbindd_request); + + request->cmd = (enum winbindd_cmd)request_type; + request->pid = getpid(); + request->domain[0] = '\0'; + + if (!initialised) { + initialised = True; + domain_env = getenv(WINBINDD_DOMAIN_ENV); + } + + if (domain_env) { + strncpy(request->domain, domain_env, + sizeof(request->domain) - 1); + request->domain[sizeof(request->domain) - 1] = '\0'; + } +} + +/* Initialise a response structure */ + +void init_response(struct winbindd_response *response) +{ + /* Initialise return value */ + + response->result = WINBINDD_ERROR; +} + +/* Close established socket */ + +void close_sock(void) +{ + if (winbindd_fd != -1) { + close(winbindd_fd); + winbindd_fd = -1; + } +} + +/* Connect to winbindd socket */ + +int winbind_open_pipe_sock(void) +{ + struct sockaddr_un sunaddr; + static pid_t our_pid; + struct stat st; + pstring path; + + if (our_pid != getpid()) { + close_sock(); + our_pid = getpid(); + } + + if (winbindd_fd != -1) { + return winbindd_fd; + } + + /* Check permissions on unix socket directory */ + + if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) { + return -1; + } + + if (!S_ISDIR(st.st_mode) || + (st.st_uid != 0 && st.st_uid != geteuid())) { + return -1; + } + + /* Connect to socket */ + + strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + strncat(path, "/", sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + ZERO_STRUCT(sunaddr); + sunaddr.sun_family = AF_UNIX; + strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1); + + /* If socket file doesn't exist, don't bother trying to connect + with retry. This is an attempt to make the system usable when + the winbindd daemon is not running. */ + + if (lstat(path, &st) == -1) { + return -1; + } + + /* Check permissions on unix socket file */ + + if (!S_ISSOCK(st.st_mode) || + (st.st_uid != 0 && st.st_uid != geteuid())) { + return -1; + } + + /* Connect to socket */ + + if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + return -1; + } + + if (connect(winbindd_fd, (struct sockaddr *)&sunaddr, + sizeof(sunaddr)) == -1) { + close_sock(); + return -1; + } + + return winbindd_fd; +} + +/* Write data to winbindd socket with timeout */ + +int write_sock(void *buffer, int count) +{ + int result, nwritten; + + /* Open connection to winbind daemon */ + + restart: + + if (winbind_open_pipe_sock() == -1) { + return -1; + } + + /* Write data to socket */ + + nwritten = 0; + + while(nwritten < count) { + struct timeval tv; + fd_set r_fds; + + /* Catch pipe close on other end by checking if a read() + call would not block by calling select(). */ + + FD_ZERO(&r_fds); + FD_SET(winbindd_fd, &r_fds); + ZERO_STRUCT(tv); + + if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) { + close_sock(); + return -1; /* Select error */ + } + + /* Write should be OK if fd not available for reading */ + + if (!FD_ISSET(winbindd_fd, &r_fds)) { + + /* Do the write */ + + result = write(winbindd_fd, + (char *)buffer + nwritten, + count - nwritten); + + if ((result == -1) || (result == 0)) { + + /* Write failed */ + + close_sock(); + return -1; + } + + nwritten += result; + + } else { + + /* Pipe has closed on remote end */ + + close_sock(); + goto restart; + } + } + + return nwritten; +} + +/* Read data from winbindd socket with timeout */ + +static int read_sock(void *buffer, int count) +{ + int result = 0, nread = 0; + + /* Read data from socket */ + + while(nread < count) { + + result = read(winbindd_fd, (char *)buffer + nread, + count - nread); + + if ((result == -1) || (result == 0)) { + + /* Read failed. I think the only useful thing we + can do here is just return -1 and fail since the + transaction has failed half way through. */ + + close_sock(); + return -1; + } + + nread += result; + } + + return result; +} + +/* Read reply */ + +int read_reply(struct winbindd_response *response) +{ + int result1, result2 = 0; + + if (!response) { + return -1; + } + + /* Read fixed length response */ + + if ((result1 = read_sock(response, sizeof(struct winbindd_response))) + == -1) { + + return -1; + } + + /* We actually send the pointer value of the extra_data field from + the server. This has no meaning in the client's address space + so we clear it out. */ + + response->extra_data = NULL; + + /* Read variable length response */ + + if (response->length > sizeof(struct winbindd_response)) { + int extra_data_len = response->length - + sizeof(struct winbindd_response); + + /* Mallocate memory for extra data */ + + if (!(response->extra_data = malloc(extra_data_len))) { + return -1; + } + + if ((result2 = read_sock(response->extra_data, extra_data_len)) + == -1) { + free_response(response); + return -1; + } + } + + /* Return total amount of data read */ + + return result1 + result2; +} + +/* + * send simple types of requests + */ + +NSS_STATUS winbindd_send_request(int req_type, struct winbindd_request *request) +{ + struct winbindd_request lrequest; + + /* Check for our tricky environment variable */ + + if (getenv(WINBINDD_DONT_ENV)) { + return NSS_STATUS_NOTFOUND; + } + + /* smbd may have excluded this domain */ + if (excluded_domain && + strcasecmp(excluded_domain, request->domain) == 0) { + return NSS_STATUS_NOTFOUND; + } + + if (!request) { + ZERO_STRUCT(lrequest); + request = &lrequest; + } + + /* Fill in request and send down pipe */ + + init_request(request, req_type); + + if (write_sock(request, sizeof(*request)) == -1) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +/* + * Get results from winbindd request + */ + +NSS_STATUS winbindd_get_response(struct winbindd_response *response) +{ + struct winbindd_response lresponse; + + if (!response) { + ZERO_STRUCT(lresponse); + response = &lresponse; + } + + init_response(response); + + /* Wait for reply */ + if (read_reply(response) == -1) { + return NSS_STATUS_UNAVAIL; + } + + /* Throw away extra data if client didn't request it */ + if (response == &lresponse) { + free_response(response); + } + + /* Copy reply data from socket */ + if (response->result != WINBINDD_OK) { + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} + +/* Handle simple types of requests */ + +NSS_STATUS winbindd_request(int req_type, + struct winbindd_request *request, + struct winbindd_response *response) +{ + NSS_STATUS status; + + status = winbindd_send_request(req_type, request); + if (status != NSS_STATUS_SUCCESS) + return(status); + return winbindd_get_response(response); +} diff --git a/helpers/basic_auth/winbind/wbntlm.h b/helpers/basic_auth/winbind/wbntlm.h new file mode 100644 index 0000000000..1b01f47095 --- /dev/null +++ b/helpers/basic_auth/winbind/wbntlm.h @@ -0,0 +1,90 @@ +/* + * (C) 2000 Francesco Chemolli , + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * 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, USA. + */ + +#ifndef _WBNTLM_H_ +#define _WBNTLM_H_ + +#include "config.h" +#include "ntlmauth.h" +#include +#include +#include +#include + + +/*************** CONFIGURATION ***************/ +#ifndef DEBUG +#define DEBUG +#endif + +/* the attempted entropy source. If it doesn't exist, random() is uesed */ +#define ENTROPY_SOURCE "/dev/urandom" + +#define DOMAIN "GCSINT" /* TODO: fix ntlm_make_challenge */ + +/************* END CONFIGURATION *************/ + +/* Debugging stuff */ +extern char *myname; +static char *__foo; +extern pid_t mypid; +extern char debug_enabled; + +#ifdef DEBUG +#define __DO_DEBUG 1 +#else +#define __DO_DEBUG 0 +#endif + +#ifdef __GNUC__ /* this is really a gcc-ism */ +#define warn(X...) fprintf(stderr,"%s[%d](%s:%d): ", myname, mypid, \ + ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\ + __LINE__);\ + fprintf(stderr,X) +#define debug(X...) if(__DO_DEBUG && debug_enabled) { warn(X); } +#else /* __GNUC__ */ +static void +debug(char *format,...) +{ +} +static void +warn(char *format,...) +{ +} +#endif /* __GNUC__ */ + + + +/* A couple of harmless helper macros */ +#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n"); +#ifdef __GNUC__ +#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); \ + printf(X "\n",Y) +#else +/* no gcc, no debugging. varargs macros are a gcc extension */ +#define SEND2 printf +#endif + +typedef enum { + YES, + NO, + DONTKNOW +} tristate; + +#define CHALLENGE_LEN 8 +#define BUFFER_SIZE 2010 + +#endif /* _WBNTLM_H_ */ diff --git a/helpers/basic_auth/winbind/winbind_nss_config.h b/helpers/basic_auth/winbind/winbind_nss_config.h new file mode 100644 index 0000000000..ac80f4adc2 --- /dev/null +++ b/helpers/basic_auth/winbind/winbind_nss_config.h @@ -0,0 +1,148 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Winbind daemon for ntdom nss module + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _WINBIND_NSS_CONFIG_H +#define _WINBIND_NSS_CONFIG_H + +/* Include header files from data in config.h file */ + +#include "config.h" + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_UNIXSOCKET +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include +#include +#include "samba_nss.h" + +/* Declarations for functions in winbind_nss.c + needed in winbind_nss_solaris.c (solaris wrapper to nss) */ + +NSS_STATUS _nss_winbind_setpwent(void); +NSS_STATUS _nss_winbind_endpwent(void); +NSS_STATUS _nss_winbind_getpwent_r(struct passwd* result, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getpwuid_r(uid_t, struct passwd*, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getpwnam_r(const char* name, struct passwd* result, + char* buffer, size_t buflen, int* errnop); + +NSS_STATUS _nss_winbind_setgrent(void); +NSS_STATUS _nss_winbind_endgrent(void); +NSS_STATUS _nss_winbind_getgrent_r(struct group* result, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getgrnam_r(const char *name, + struct group *result, char *buffer, + size_t buflen, int *errnop); +NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, + struct group *result, char *buffer, + size_t buflen, int *errnop); + +/* I'm trying really hard not to include anything from smb.h with the + result of some silly looking redeclaration of structures. */ + +#ifndef _PSTRING +#define _PSTRING +#define PSTRING_LEN 1024 +#define FSTRING_LEN 256 +typedef char pstring[PSTRING_LEN]; +typedef char fstring[FSTRING_LEN]; +#endif + +#ifndef _BOOL +#define _BOOL /* So we don't typedef BOOL again in vfs.h */ +#define False (0) +#define True (1) +#define Auto (2) +typedef int BOOL; +#endif + +#if !defined(uint32) +#if (SIZEOF_INT == 4) +#define uint32 unsigned int +#elif (SIZEOF_LONG == 4) +#define uint32 unsigned long +#elif (SIZEOF_SHORT == 4) +#define uint32 unsigned short +#endif +#endif + +#if !defined(uint16) +#if (SIZEOF_SHORT == 4) +#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16; +#else /* SIZEOF_SHORT != 4 */ +#define uint16 unsigned short +#endif /* SIZEOF_SHORT != 4 */ +#endif + +#ifndef uint8 +#define uint8 unsigned char +#endif + +/* zero a structure */ +#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) + +/* zero a structure given a pointer to the structure */ +#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } + +/* Some systems (SCO) treat UNIX domain sockets as FIFOs */ + +#ifndef S_IFSOCK +#define S_IFSOCK S_IFIFO +#endif + +#ifndef S_ISSOCK +#define S_ISSOCK(mode) ((mode & S_IFSOCK) == S_IFSOCK) +#endif + +#endif diff --git a/helpers/basic_auth/winbind/winbindd_nss.h b/helpers/basic_auth/winbind/winbindd_nss.h new file mode 100644 index 0000000000..a88b1209ab --- /dev/null +++ b/helpers/basic_auth/winbind/winbindd_nss.h @@ -0,0 +1,202 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Winbind daemon for ntdom nss module + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef SAFE_FREE +#define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0) +#endif + +#ifndef _WINBINDD_NTDOM_H +#define _WINBINDD_NTDOM_H + +#define WINBINDD_SOCKET_NAME "pipe" /* Name of PF_UNIX socket */ +#define WINBINDD_SOCKET_DIR "/tmp/.winbindd" /* Name of PF_UNIX dir */ + +#define WINBINDD_DOMAIN_ENV "WINBINDD_DOMAIN" /* Environment variables */ +#define WINBINDD_DONT_ENV "_NO_WINBINDD" + +/* Update this when you change the interface. */ + +#define WINBIND_INTERFACE_VERSION 2 + +/* Socket commands */ + +enum winbindd_cmd { + + WINBINDD_INTERFACE_VERSION, /* Always a well known value */ + + /* Get users and groups */ + + WINBINDD_GETPWNAM, + WINBINDD_GETPWUID, + WINBINDD_GETGRNAM, + WINBINDD_GETGRGID, + WINBINDD_GETGROUPS, + + /* Enumerate users and groups */ + + WINBINDD_SETPWENT, + WINBINDD_ENDPWENT, + WINBINDD_GETPWENT, + WINBINDD_SETGRENT, + WINBINDD_ENDGRENT, + WINBINDD_GETGRENT, + + /* PAM authenticate and password change */ + + WINBINDD_PAM_AUTH, + WINBINDD_PAM_AUTH_CRAP, + WINBINDD_PAM_CHAUTHTOK, + + /* List various things */ + + WINBINDD_LIST_USERS, /* List w/o rid->id mapping */ + WINBINDD_LIST_GROUPS, /* Ditto */ + WINBINDD_LIST_TRUSTDOM, + + /* SID conversion */ + + WINBINDD_LOOKUPSID, + WINBINDD_LOOKUPNAME, + + /* Lookup functions */ + + WINBINDD_SID_TO_UID, + WINBINDD_SID_TO_GID, + WINBINDD_UID_TO_SID, + WINBINDD_GID_TO_SID, + + /* Miscellaneous other stuff */ + + WINBINDD_CHECK_MACHACC, /* Check machine account pw works */ + WINBINDD_PING, /* Just tell me winbind is running */ + WINBINDD_INFO, /* Various bit of info. Currently just tidbits */ + + /* Placeholder for end of cmd list */ + + WINBINDD_NUM_CMDS +}; + +/* Winbind request structure */ + +struct winbindd_request { + uint32 length; + enum winbindd_cmd cmd; /* Winbindd command to execute */ + pid_t pid; /* pid of calling process */ + + union { + fstring username; /* getpwnam */ + fstring groupname; /* getgrnam */ + uid_t uid; /* getpwuid, uid_to_sid */ + gid_t gid; /* getgrgid, gid_to_sid */ + struct { + fstring user; + fstring pass; + } auth; /* pam_winbind auth module */ + struct { + unsigned char chal[8]; + fstring user; + fstring domain; + fstring lm_resp; + uint16 lm_resp_len; + fstring nt_resp; + uint16 nt_resp_len; + } auth_crap; + struct { + fstring user; + fstring oldpass; + fstring newpass; + } chauthtok; /* pam_winbind passwd module */ + fstring sid; /* lookupsid, sid_to_[ug]id */ + fstring name; /* lookupname */ + uint32 num_entries; /* getpwent, getgrent */ + } data; + fstring domain; /* {set,get,end}{pw,gr}ent() */ +}; + +/* Response values */ + +enum winbindd_result { + WINBINDD_ERROR, + WINBINDD_OK +}; + +/* Winbind response structure */ + +struct winbindd_response { + + /* Header information */ + + uint32 length; /* Length of response */ + enum winbindd_result result; /* Result code */ + + /* Fixed length return data */ + + union { + int interface_version; /* Try to ensure this is always in the same spot... */ + + /* getpwnam, getpwuid */ + + struct winbindd_pw { + fstring pw_name; + fstring pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + fstring pw_gecos; + fstring pw_dir; + fstring pw_shell; + } pw; + + /* getgrnam, getgrgid */ + + struct winbindd_gr { + fstring gr_name; + fstring gr_passwd; + gid_t gr_gid; + int num_gr_mem; + int gr_mem_ofs; /* offset to group membership */ + } gr; + + uint32 num_entries; /* getpwent, getgrent */ + struct winbindd_sid { + fstring sid; /* lookupname, [ug]id_to_sid */ + int type; + } sid; + struct winbindd_name { + fstring name; /* lookupsid */ + int type; + } name; + uid_t uid; /* sid_to_uid */ + gid_t gid; /* sid_to_gid */ + struct winbindd_info { + char winbind_separator; + fstring samba_version; + } info; + } data; + + /* Variable length return data */ + + void *extra_data; /* getgrnam, getgrgid, getgrent */ +}; + +#endif diff --git a/helpers/ntlm_auth/Makefile.am b/helpers/ntlm_auth/Makefile.am index 249fbd2622..131b350771 100644 --- a/helpers/ntlm_auth/Makefile.am +++ b/helpers/ntlm_auth/Makefile.am @@ -1,7 +1,7 @@ # Makefile for storage modules in the Squid Object Cache server # -# $Id: Makefile.am,v 1.4 2002/05/19 15:07:55 hno Exp $ +# $Id: Makefile.am,v 1.5 2002/05/19 23:42:42 hno Exp $ # -DIST_SUBDIRS = fakeauth no_check SMB +DIST_SUBDIRS = fakeauth no_check SMB winbind SUBDIRS = @NTLM_AUTH_HELPERS@ diff --git a/helpers/ntlm_auth/winbind/Makefile.am b/helpers/ntlm_auth/winbind/Makefile.am new file mode 100644 index 0000000000..2bfd30f901 --- /dev/null +++ b/helpers/ntlm_auth/winbind/Makefile.am @@ -0,0 +1,11 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: Makefile.am,v 1.1 2002/05/19 23:42:42 hno Exp $ +# + +libexec_PROGRAMS = wb_ntlmauth +wb_ntlmauth_SOURCES = wb_ntlm_auth.c wb_common.c +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src +LDADD = -L$(top_builddir)/lib -lmiscutil -lntlmauth -lm diff --git a/helpers/ntlm_auth/winbind/patches/wb_common.patch b/helpers/ntlm_auth/winbind/patches/wb_common.patch new file mode 100644 index 0000000000..09771207f2 --- /dev/null +++ b/helpers/ntlm_auth/winbind/patches/wb_common.patch @@ -0,0 +1,11 @@ +--- samba-HEAD/source/nsswitch/wb_common.c Sat Jan 12 23:12:11 2002 ++++ squid-ntlm/src/auth/ntlm/helpers/winbind/wb_common.c Sat Jan 12 23:45:03 2002 +@@ -25,6 +25,8 @@ + + #include "winbind_nss_config.h" + #include "winbindd_nss.h" ++#include "config.h" ++ + + /* Global variables. These are effectively the client state information */ + diff --git a/helpers/ntlm_auth/winbind/patches/winbind_nss_config.patch b/helpers/ntlm_auth/winbind/patches/winbind_nss_config.patch new file mode 100644 index 0000000000..209d4f1c1a --- /dev/null +++ b/helpers/ntlm_auth/winbind/patches/winbind_nss_config.patch @@ -0,0 +1,20 @@ +--- samba-HEAD/source/nsswitch/winbind_nss_config.h Wed Sep 5 10:11:16 2001 ++++ squid-ntlm/src/auth/ntlm/helpers/winbind/winbind_nss_config.h Sat Nov 24 00:32:05 2001 +@@ -27,7 +27,7 @@ + + /* Include header files from data in config.h file */ + +-#include ++#include "config.h" + + #include + +@@ -63,7 +63,7 @@ + #include + #include + #include +-#include "nsswitch/nss.h" ++#include "samba_nss.h" + + /* Declarations for functions in winbind_nss.c + needed in winbind_nss_solaris.c (solaris wrapper to nss) */ diff --git a/helpers/ntlm_auth/winbind/samba_nss.h b/helpers/ntlm_auth/winbind/samba_nss.h new file mode 100644 index 0000000000..6165e0b24a --- /dev/null +++ b/helpers/ntlm_auth/winbind/samba_nss.h @@ -0,0 +1,105 @@ +#ifndef _NSSWITCH_NSS_H +#define _NSSWITCH_NSS_H +/* + Unix SMB/Netbios implementation. + Version 2.0 + + a common place to work out how to define NSS_STATUS on various + platforms + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_NSS_COMMON_H + +/* Sun Solaris */ + +#include +#include +#include + +typedef nss_status_t NSS_STATUS; + +#define NSS_STATUS_SUCCESS NSS_SUCCESS +#define NSS_STATUS_NOTFOUND NSS_NOTFOUND +#define NSS_STATUS_UNAVAIL NSS_UNAVAIL +#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN + +#elif HAVE_NSS_H + +/* GNU */ + +#include + +typedef enum nss_status NSS_STATUS; + +#elif HAVE_NS_API_H + +/* SGI IRIX */ + +/* following required to prevent warnings of double definition + * of datum from ns_api.h +*/ +#ifdef DATUM +#define _DATUM_DEFINED +#endif + +#include + +typedef enum +{ + NSS_STATUS_SUCCESS=NS_SUCCESS, + NSS_STATUS_NOTFOUND=NS_NOTFOUND, + NSS_STATUS_UNAVAIL=NS_UNAVAIL, + NSS_STATUS_TRYAGAIN=NS_TRYAGAIN +} NSS_STATUS; + +#define NSD_MEM_STATIC 0 +#define NSD_MEM_VOLATILE 1 +#define NSD_MEM_DYNAMIC 2 + +#elif defined(HPUX) +/* HP-UX 11 */ + +#include "nsswitch/hp_nss_common.h" +#include "nsswitch/hp_nss_dbdefs.h" +#include + +#ifndef _HAVE_TYPEDEF_NSS_STATUS +#define _HAVE_TYPEDEF_NSS_STATUS +typedef nss_status_t NSS_STATUS; + +#define NSS_STATUS_SUCCESS NSS_SUCCESS +#define NSS_STATUS_NOTFOUND NSS_NOTFOUND +#define NSS_STATUS_UNAVAIL NSS_UNAVAIL +#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN +#endif /* HPUX */ + +#else /* Nothing's defined. Neither gnu nor sun nor hp */ + +typedef enum +{ + NSS_STATUS_SUCCESS=0, + NSS_STATUS_NOTFOUND=1, + NSS_STATUS_UNAVAIL=2, + NSS_STATUS_TRYAGAIN=3 +} NSS_STATUS; + +#endif + +#endif /* _NSSWITCH_NSS_H */ diff --git a/helpers/ntlm_auth/winbind/wb_common.c b/helpers/ntlm_auth/winbind/wb_common.c new file mode 100644 index 0000000000..1a1f5c0252 --- /dev/null +++ b/helpers/ntlm_auth/winbind/wb_common.c @@ -0,0 +1,403 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + winbind client common code + + Copyright (C) Tim Potter 2000 + Copyright (C) Andrew Tridgell 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "winbind_nss_config.h" +#include "winbindd_nss.h" +#include "config.h" + + +/* Global variables. These are effectively the client state information */ + +int winbindd_fd = -1; /* fd for winbindd socket */ +static char *excluded_domain; + +/* Free a response structure */ + +void +free_response(struct winbindd_response *response) +{ + /* Free any allocated extra_data */ + + if (response) + SAFE_FREE(response->extra_data); +} + +/* + smbd needs to be able to exclude lookups for its own domain +*/ +void +winbind_exclude_domain(const char *domain) +{ + SAFE_FREE(excluded_domain); + excluded_domain = strdup(domain); +} + + +/* Initialise a request structure */ + +void +init_request(struct winbindd_request *request, int request_type) +{ + static char *domain_env; + static BOOL initialised; + + request->length = sizeof(struct winbindd_request); + + request->cmd = (enum winbindd_cmd) request_type; + request->pid = getpid(); + request->domain[0] = '\0'; + + if (!initialised) { + initialised = True; + domain_env = getenv(WINBINDD_DOMAIN_ENV); + } + + if (domain_env) { + strncpy(request->domain, domain_env, sizeof(request->domain) - 1); + request->domain[sizeof(request->domain) - 1] = '\0'; + } +} + +/* Initialise a response structure */ + +void +init_response(struct winbindd_response *response) +{ + /* Initialise return value */ + + response->result = WINBINDD_ERROR; +} + +/* Close established socket */ + +void +close_sock(void) +{ + if (winbindd_fd != -1) { + close(winbindd_fd); + winbindd_fd = -1; + } +} + +/* Connect to winbindd socket */ + +int +winbind_open_pipe_sock(void) +{ + struct sockaddr_un sunaddr; + static pid_t our_pid; + struct stat st; + pstring path; + + if (our_pid != getpid()) { + close_sock(); + our_pid = getpid(); + } + + if (winbindd_fd != -1) { + return winbindd_fd; + } + + /* Check permissions on unix socket directory */ + + if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) { + return -1; + } + + if (!S_ISDIR(st.st_mode) || (st.st_uid != 0 && st.st_uid != geteuid())) { + return -1; + } + + /* Connect to socket */ + + strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + strncat(path, "/", sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + ZERO_STRUCT(sunaddr); + sunaddr.sun_family = AF_UNIX; + strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1); + + /* If socket file doesn't exist, don't bother trying to connect + * with retry. This is an attempt to make the system usable when + * the winbindd daemon is not running. */ + + if (lstat(path, &st) == -1) { + return -1; + } + + /* Check permissions on unix socket file */ + + if (!S_ISSOCK(st.st_mode) || (st.st_uid != 0 && st.st_uid != geteuid())) { + return -1; + } + + /* Connect to socket */ + + if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + return -1; + } + + if (connect(winbindd_fd, (struct sockaddr *) &sunaddr, + sizeof(sunaddr)) == -1) { + close_sock(); + return -1; + } + + return winbindd_fd; +} + +/* Write data to winbindd socket with timeout */ + +int +write_sock(void *buffer, int count) +{ + int result, nwritten; + + /* Open connection to winbind daemon */ + + restart: + + if (winbind_open_pipe_sock() == -1) { + return -1; + } + + /* Write data to socket */ + + nwritten = 0; + + while (nwritten < count) { + struct timeval tv; + fd_set r_fds; + + /* Catch pipe close on other end by checking if a read() + * call would not block by calling select(). */ + + FD_ZERO(&r_fds); + FD_SET(winbindd_fd, &r_fds); + ZERO_STRUCT(tv); + + if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) { + close_sock(); + return -1; /* Select error */ + } + + /* Write should be OK if fd not available for reading */ + + if (!FD_ISSET(winbindd_fd, &r_fds)) { + + /* Do the write */ + + result = write(winbindd_fd, + (char *) buffer + nwritten, count - nwritten); + + if ((result == -1) || (result == 0)) { + + /* Write failed */ + + close_sock(); + return -1; + } + + nwritten += result; + + } else { + + /* Pipe has closed on remote end */ + + close_sock(); + goto restart; + } + } + + return nwritten; +} + +/* Read data from winbindd socket with timeout */ + +static int +read_sock(void *buffer, int count) +{ + int result = 0, nread = 0; + + /* Read data from socket */ + + while (nread < count) { + + result = read(winbindd_fd, (char *) buffer + nread, count - nread); + + if ((result == -1) || (result == 0)) { + + /* Read failed. I think the only useful thing we + * can do here is just return -1 and fail since the + * transaction has failed half way through. */ + + close_sock(); + return -1; + } + + nread += result; + } + + return result; +} + +/* Read reply */ + +int +read_reply(struct winbindd_response *response) +{ + int result1, result2 = 0; + + if (!response) { + return -1; + } + + /* Read fixed length response */ + + if ((result1 = read_sock(response, sizeof(struct winbindd_response))) + == -1) { + + return -1; + } + + /* We actually send the pointer value of the extra_data field from + * the server. This has no meaning in the client's address space + * so we clear it out. */ + + response->extra_data = NULL; + + /* Read variable length response */ + + if (response->length > sizeof(struct winbindd_response)) { + int extra_data_len = response->length - + sizeof(struct winbindd_response); + + /* Mallocate memory for extra data */ + + if (!(response->extra_data = malloc(extra_data_len))) { + return -1; + } + + if ((result2 = read_sock(response->extra_data, extra_data_len)) + == -1) { + free_response(response); + return -1; + } + } + + /* Return total amount of data read */ + + return result1 + result2; +} + +/* + * send simple types of requests + */ + +NSS_STATUS +winbindd_send_request(int req_type, struct winbindd_request * request) +{ + struct winbindd_request lrequest; + + /* Check for our tricky environment variable */ + + if (getenv(WINBINDD_DONT_ENV)) { + return NSS_STATUS_NOTFOUND; + } + + /* smbd may have excluded this domain */ + if (excluded_domain && strcasecmp(excluded_domain, request->domain) == 0) { + return NSS_STATUS_NOTFOUND; + } + + if (!request) { + ZERO_STRUCT(lrequest); + request = &lrequest; + } + + /* Fill in request and send down pipe */ + + init_request(request, req_type); + + if (write_sock(request, sizeof(*request)) == -1) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +/* + * Get results from winbindd request + */ + +NSS_STATUS +winbindd_get_response(struct winbindd_response * response) +{ + struct winbindd_response lresponse; + + if (!response) { + ZERO_STRUCT(lresponse); + response = &lresponse; + } + + init_response(response); + + /* Wait for reply */ + if (read_reply(response) == -1) { + return NSS_STATUS_UNAVAIL; + } + + /* Throw away extra data if client didn't request it */ + if (response == &lresponse) { + free_response(response); + } + + /* Copy reply data from socket */ + if (response->result != WINBINDD_OK) { + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} + +/* Handle simple types of requests */ + +NSS_STATUS +winbindd_request(int req_type, + struct winbindd_request * request, struct winbindd_response * response) +{ + NSS_STATUS status; + + status = winbindd_send_request(req_type, request); + if (status != NSS_STATUS_SUCCESS) + return (status); + return winbindd_get_response(response); +} diff --git a/helpers/ntlm_auth/winbind/wb_ntlm_auth.c b/helpers/ntlm_auth/winbind/wb_ntlm_auth.c new file mode 100644 index 0000000000..247c824fe2 --- /dev/null +++ b/helpers/ntlm_auth/winbind/wb_ntlm_auth.c @@ -0,0 +1,425 @@ +/* + * (C) 2000 Francesco Chemolli + * (C) 2002 Andrew Bartlett + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * 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, USA. + * + */ +/* + * TODO: + * -add handling of the -d flag + * -move all squid-helper-protocol-related operations to helper functions + * -remove the hard-coded target NT domain name + * + * - MAYBE move squid-helper-protocol-related opetations to an external + * library? + */ + + +#include "wbntlm.h" +#include "util.h" +/* stdio.h is included in wbntlm.h */ +#include +#include +#include +#include /* for gettimeofday */ +#include /* BUG: is this portable? */ + +#ifdef HAVE_CTYPE_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#if HAVE_GETOPT_H +#include +#endif + +#include "winbind_nss_config.h" +#include "winbindd_nss.h" + +#ifndef min +#define min(x,y) ((x)<(y)?(x):(y)) +#endif + +void +authfail(char *domain, char *user, char *reason) +{ + /* TODO: -move away from SEND-type gcc-isms + * -prepare for protocol extension as soon as rbcollins is ready + */ + SEND2("NA %s\\%s auth failure because: %s", domain, user, reason); +} + +void +authok(const char *domain, const char *user) +{ + SEND2("AF %s\\%s", domain, user); +} + +void +sendchallenge(const char *challenge) +{ + SEND2("TT %s", challenge); +} + +void +helperfail(const char *reason) +{ + SEND2("BH %s", reason); +} + +char debug_enabled = 0; +char *myname; +pid_t mypid; + +static void +lc(char *string) +{ + char *p = string, c; + while ((c = *p)) { + *p = tolower(c); + p++; + } +} + +static void +uc(char *string) +{ + char *p = string, c; + while ((c = *p)) { + *p = toupper(c); + p++; + } +} + + + +NSS_STATUS winbindd_request(int req_type, + struct winbindd_request *request, struct winbindd_response *response); + + +static tristate have_urandom = DONTKNOW; +FILE *urandom_file = NULL; + +void +init_random() +{ + if (have_urandom == DONTKNOW) { + int result = 0; + struct stat st; + result = stat(ENTROPY_SOURCE, &st); + if (result != 0 || !(S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { + debug("Entropy source " ENTROPY_SOURCE " is unavailable\n"); + have_urandom = NO; + } + if ((urandom_file = fopen(ENTROPY_SOURCE, "r")) == NULL) { + unsigned int seed; + struct timeval t; + warn("Can't open entropy source " ENTROPY_SOURCE "\n"); + have_urandom = NO; + gettimeofday(&t, NULL); + seed = squid_random() * getpid() * t.tv_sec * t.tv_usec; + squid_srandom(seed); + } else { + have_urandom = YES; + } + } +} + +static unsigned char challenge[CHALLENGE_LEN + 1]; +static char * +build_challenge(void) +{ + size_t gotchars; + unsigned char j; + switch (have_urandom) { + case YES: + if ((gotchars = fread(&challenge, CHALLENGE_LEN, 1, urandom_file)) == 0) { + /* couldn't get a challenge. Fall back to random() and friends. + * notice that even a single changed byte is good enough for us */ + have_urandom = NO; + return build_challenge(); + } + return challenge; + case NO: + if (!(squid_random() % 100)) { /* sometimes */ + init_random(); + } + for (j = 0; j < CHALLENGE_LEN; j++) + challenge[j] = (unsigned char) (squid_random() % 256); + return challenge; + default: + warn("Critical internal error. Somebody forgot to initialize " + "the random system. Exiting.\n"); + exit(1); + } +} + +lstring lmhash, nthash; +static char have_nthash = 0; /* simple flag. A tad dirty.. */ + +void +do_authenticate(ntlm_authenticate * auth, int auth_length) +{ + lstring tmp; + int tocopy; + NSS_STATUS winbindd_result; + struct winbindd_request request; + struct winbindd_response response; + char *domain, *user; + + memset(&request, 0, sizeof(struct winbindd_request)); + + memset(&response, 0, sizeof(struct winbindd_response)); + + /* domain */ + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain); + if (tmp.str == NULL || tmp.l == 0) { /* no domain supplied */ + request.data.auth_crap.domain[0] = 0; + } else { + tocopy = min(tmp.l + 1, sizeof(fstring)); + xstrncpy(request.data.auth_crap.domain, tmp.str, tocopy); + } + + domain = request.data.auth_crap.domain; /* just a shortcut */ + + /* username */ + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user); + if (tmp.str == NULL || tmp.l == 0) { + authfail(domain, "-", "No username in request"); + return; + } + + tocopy = min(sizeof(fstring), tmp.l + 1); + xstrncpy(request.data.auth_crap.user, tmp.str, tocopy); + user = request.data.auth_crap.user; + + /* now the LM hash */ + lmhash = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse); + switch (lmhash.l) { + case 0: + warn("No lm hash provided by user %s\\%s\n", domain, user); + request.data.auth_crap.lm_resp_len = 0; + break; + case 24: + memcpy(request.data.auth_crap.lm_resp, lmhash.str, 24); + request.data.auth_crap.lm_resp_len = 24; + break; + default: + authfail(domain, user, "Broken LM hash response"); + return; + } + + nthash = ntlm_fetch_string((char *) auth, auth_length, &auth->ntresponse); + switch (nthash.l) { + case 0: + debug("no nthash\n"); + request.data.auth_crap.nt_resp_len = 0; + break; + case 24: + memcpy(request.data.auth_crap.nt_resp, nthash.str, 24); + request.data.auth_crap.nt_resp_len = 24; + break; + default: + debug("nthash len = %d\n", nthash.l); + authfail(domain, user, "Broken NT hash response"); + return; + } + + debug("Checking user '%s\\%s' lmhash len =%d, have_nthash=%d, " + "nthash len=%d\n", domain, user, lmhash.l, have_nthash, nthash.l); + + memcpy(request.data.auth_crap.chal, challenge, CHALLENGE_LEN); + + winbindd_result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, + &request, &response); + debug("winbindd result: %d\n", winbindd_result); + + if (winbindd_result == WINBINDD_OK) { + lc(domain); + lc(user); + authok(domain, user); + } else { + char error_buf[200]; + snprintf(error_buf, sizeof(error_buf), "Authentication Failure (%s)", + response.data.auth.error_string); + authfail(domain, user, error_buf); + } + return; /* useless */ +} + +void +manage_request(char *target_domain) +{ + char buf[BUFFER_SIZE + 1]; + char *c, *decoded; + ntlmhdr *fast_header; + + + if (fgets(buf, BUFFER_SIZE, stdin) == NULL) { + warn("fgets() failed! dying..... errno=%d (%s)\n", errno, + strerror(errno)); + exit(1); /* BIIG buffer */ + } + + c = memchr(buf, '\n', BUFFER_SIZE); + if (c) + *c = '\0'; + else { + warn("No newline in '%s'. Dying.\n", buf); + exit(1); + } + + debug("Got '%s' from squid.\n", buf); + if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */ + sendchallenge(ntlm_make_challenge(target_domain, NULL, + build_challenge(), CHALLENGE_LEN)); + return; + } + if (strncmp(buf, "KK ", 3) != 0) { /* not an auth-request */ + helperfail("illegal request received"); + warn("Illegal request received: '%s'\n", buf); + return; + } + /* At this point I'm sure it's a KK */ + decoded = base64_decode(buf + 3); + if (!decoded) { /* decoding failure, return error */ + authfail("-", "-", "Auth-format error, base64-decoding error"); + return; + } + fast_header = (struct _ntlmhdr *) decoded; + + /* sanity-check: it IS a NTLMSSP packet, isn't it? */ + if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { + authfail("-", "-", "Broken NTLM packet, missing NTLMSSP signature"); + return; + } + /* Understand what we got */ + switch (fast_header->type) { + case NTLM_NEGOTIATE: + authfail("-", "-", "Received neg-request while expecting auth packet"); + return; + case NTLM_CHALLENGE: + authfail("-", "-", "Received challenge. Refusing to abide"); + return; + case NTLM_AUTHENTICATE: + do_authenticate((ntlm_authenticate *) decoded, + (strlen(buf) - 3) * 3 / 4); + return; + default: + helperfail("Unknown authentication packet type"); + return; + } + /* notreached */ + return; +} + +static char * +get_winbind_domain(void) +{ + struct winbindd_response response; + char *domain; + + ZERO_STRUCT(response); + + /* Send off request */ + + if (winbindd_request(WINBINDD_DOMAIN_NAME, NULL, &response) != + NSS_STATUS_SUCCESS) { + warn("could not obtain winbind domain name!\n"); + exit(1); + } + + domain = strdup(response.data.domain_name); + uc(domain); + + warn("target domain is %s\n", domain); + return domain; +} + +char * +process_options(int argc, char *argv[]) +{ + int opt; + char *target_domain = NULL; + + while (-1 != (opt = getopt(argc, argv, "d"))) { + switch (opt) { + case 'd': + debug_enabled = 1; + break; + default: + warn("Unknown option: -%c. Exiting\n", opt); + exit(1); + break; /* not reached */ + } + if (optind >= argc - 1) { + target_domain = argv[optind]; + warn("target domain is %s\n", target_domain); + } + } + return target_domain; +} + +void +check_winbindd() +{ + NSS_STATUS r; + struct winbindd_request request; + struct winbindd_response response; + r = winbindd_request(WINBINDD_INTERFACE_VERSION, &request, &response); + if (r != WINBINDD_OK) { + warn("Can't contact winbindd. Dying\n"); + exit(1); + } + if (response.data.interface_version != WINBIND_INTERFACE_VERSION) { + warn("Winbind protocol mismatch. Align squid and samba. Dying\n"); + exit(1); + } +} + +int +main(int argc, char **argv) +{ + char *target_domain; + if (argc > 0) { /* should always be true */ + myname = strrchr(argv[0], '/'); + if (myname == NULL) + myname = argv[0]; + else + myname++; + } else { + myname = "(unknown)"; + } + mypid = getpid(); + target_domain = process_options(argc, argv); + debug("ntlm winbindd auth helper build " __DATE__ ", " __TIME__ + " starting up...\n"); + + check_winbindd(); + + if (target_domain == NULL) { + target_domain = get_winbind_domain(); + } + + /* initialize FDescs */ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + init_random(); + while (1) { + manage_request(target_domain); + } + return 0; +} diff --git a/helpers/ntlm_auth/winbind/wbntlm.h b/helpers/ntlm_auth/winbind/wbntlm.h new file mode 100644 index 0000000000..7edccbcbac --- /dev/null +++ b/helpers/ntlm_auth/winbind/wbntlm.h @@ -0,0 +1,88 @@ +/* + * (C) 2000 Francesco Chemolli , + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * 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, USA. + */ + +#ifndef _WBNTLM_H_ +#define _WBNTLM_H_ + +#include "config.h" +#include "ntlmauth.h" +#include +#include +#include +#include + + +/*************** CONFIGURATION ***************/ +#ifndef DEBUG +#define DEBUG +#endif + +/* the attempted entropy source. If it doesn't exist, random() is uesed */ +#define ENTROPY_SOURCE "/dev/urandom" + +/************* END CONFIGURATION *************/ + +/* Debugging stuff */ +extern char *myname; +static char *__foo; +extern pid_t mypid; +extern char debug_enabled; + +#ifdef DEBUG +#define __DO_DEBUG 1 +#else +#define __DO_DEBUG 0 +#endif + +#if defined(__GNUC__) || defined(__ICC) /* this is really a gcc-ism */ +#define warn(X...) fprintf(stderr,"%s[%d](%s:%d): ", myname, mypid, \ + ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\ + __LINE__);\ + fprintf(stderr,X) +#define debug(X...) if(__DO_DEBUG && debug_enabled) { warn(X); } +#else /* __GNUC__ */ +static void +debug(char *format,...) +{ +} +static void +warn(char *format,...) +{ +} +#endif /* __GNUC__ */ + + + +/* A couple of harmless helper macros */ +#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n"); +#if defined(__GNUC__) || defined (__ICC) +#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); \ + printf(X "\n",Y) +#else +/* no gcc, no debugging. varargs macros are a gcc extension */ +#define SEND2 printf +#endif + +typedef enum { + YES, + NO, + DONTKNOW +} tristate; + +#define CHALLENGE_LEN 8 +#define BUFFER_SIZE 2010 + +#endif /* _WBNTLM_H_ */ diff --git a/helpers/ntlm_auth/winbind/winbind_nss_config.h b/helpers/ntlm_auth/winbind/winbind_nss_config.h new file mode 100644 index 0000000000..ac80f4adc2 --- /dev/null +++ b/helpers/ntlm_auth/winbind/winbind_nss_config.h @@ -0,0 +1,148 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Winbind daemon for ntdom nss module + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _WINBIND_NSS_CONFIG_H +#define _WINBIND_NSS_CONFIG_H + +/* Include header files from data in config.h file */ + +#include "config.h" + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_UNIXSOCKET +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include +#include +#include "samba_nss.h" + +/* Declarations for functions in winbind_nss.c + needed in winbind_nss_solaris.c (solaris wrapper to nss) */ + +NSS_STATUS _nss_winbind_setpwent(void); +NSS_STATUS _nss_winbind_endpwent(void); +NSS_STATUS _nss_winbind_getpwent_r(struct passwd* result, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getpwuid_r(uid_t, struct passwd*, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getpwnam_r(const char* name, struct passwd* result, + char* buffer, size_t buflen, int* errnop); + +NSS_STATUS _nss_winbind_setgrent(void); +NSS_STATUS _nss_winbind_endgrent(void); +NSS_STATUS _nss_winbind_getgrent_r(struct group* result, char* buffer, + size_t buflen, int* errnop); +NSS_STATUS _nss_winbind_getgrnam_r(const char *name, + struct group *result, char *buffer, + size_t buflen, int *errnop); +NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, + struct group *result, char *buffer, + size_t buflen, int *errnop); + +/* I'm trying really hard not to include anything from smb.h with the + result of some silly looking redeclaration of structures. */ + +#ifndef _PSTRING +#define _PSTRING +#define PSTRING_LEN 1024 +#define FSTRING_LEN 256 +typedef char pstring[PSTRING_LEN]; +typedef char fstring[FSTRING_LEN]; +#endif + +#ifndef _BOOL +#define _BOOL /* So we don't typedef BOOL again in vfs.h */ +#define False (0) +#define True (1) +#define Auto (2) +typedef int BOOL; +#endif + +#if !defined(uint32) +#if (SIZEOF_INT == 4) +#define uint32 unsigned int +#elif (SIZEOF_LONG == 4) +#define uint32 unsigned long +#elif (SIZEOF_SHORT == 4) +#define uint32 unsigned short +#endif +#endif + +#if !defined(uint16) +#if (SIZEOF_SHORT == 4) +#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16; +#else /* SIZEOF_SHORT != 4 */ +#define uint16 unsigned short +#endif /* SIZEOF_SHORT != 4 */ +#endif + +#ifndef uint8 +#define uint8 unsigned char +#endif + +/* zero a structure */ +#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) + +/* zero a structure given a pointer to the structure */ +#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } + +/* Some systems (SCO) treat UNIX domain sockets as FIFOs */ + +#ifndef S_IFSOCK +#define S_IFSOCK S_IFIFO +#endif + +#ifndef S_ISSOCK +#define S_ISSOCK(mode) ((mode & S_IFSOCK) == S_IFSOCK) +#endif + +#endif diff --git a/helpers/ntlm_auth/winbind/winbindd_nss.h b/helpers/ntlm_auth/winbind/winbindd_nss.h new file mode 100644 index 0000000000..476dc71ab2 --- /dev/null +++ b/helpers/ntlm_auth/winbind/winbindd_nss.h @@ -0,0 +1,216 @@ +/* + Unix SMB/CIFS implementation. + + Winbind daemon for ntdom nss module + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef SAFE_FREE +#define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0) +#endif + +#ifndef _WINBINDD_NTDOM_H +#define _WINBINDD_NTDOM_H + +#define WINBINDD_SOCKET_NAME "pipe" /* Name of PF_UNIX socket */ +#define WINBINDD_SOCKET_DIR "/tmp/.winbindd" /* Name of PF_UNIX dir */ + +#define WINBINDD_DOMAIN_ENV "WINBINDD_DOMAIN" /* Environment variables */ +#define WINBINDD_DONT_ENV "_NO_WINBINDD" + +/* Update this when you change the interface. */ + +#define WINBIND_INTERFACE_VERSION 4 + +/* Socket commands */ + +enum winbindd_cmd { + + WINBINDD_INTERFACE_VERSION, /* Always a well known value */ + + /* Get users and groups */ + + WINBINDD_GETPWNAM, + WINBINDD_GETPWUID, + WINBINDD_GETGRNAM, + WINBINDD_GETGRGID, + WINBINDD_GETGROUPS, + + /* Enumerate users and groups */ + + WINBINDD_SETPWENT, + WINBINDD_ENDPWENT, + WINBINDD_GETPWENT, + WINBINDD_SETGRENT, + WINBINDD_ENDGRENT, + WINBINDD_GETGRENT, + + /* PAM authenticate and password change */ + + WINBINDD_PAM_AUTH, + WINBINDD_PAM_AUTH_CRAP, + WINBINDD_PAM_CHAUTHTOK, + + /* List various things */ + + WINBINDD_LIST_USERS, /* List w/o rid->id mapping */ + WINBINDD_LIST_GROUPS, /* Ditto */ + WINBINDD_LIST_TRUSTDOM, + + /* SID conversion */ + + WINBINDD_LOOKUPSID, + WINBINDD_LOOKUPNAME, + + /* Lookup functions */ + + WINBINDD_SID_TO_UID, + WINBINDD_SID_TO_GID, + WINBINDD_UID_TO_SID, + WINBINDD_GID_TO_SID, + + /* Miscellaneous other stuff */ + + WINBINDD_CHECK_MACHACC, /* Check machine account pw works */ + WINBINDD_PING, /* Just tell me winbind is running */ + WINBINDD_INFO, /* Various bit of info. Currently just tidbits */ + WINBINDD_DOMAIN_NAME, /* The domain this winbind server is a member of (lp_workgroup()) */ + + WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */ + + /* Placeholder for end of cmd list */ + + WINBINDD_NUM_CMDS +}; + +/* Winbind request structure */ + +struct winbindd_request { + uint32 length; + enum winbindd_cmd cmd; /* Winbindd command to execute */ + pid_t pid; /* pid of calling process */ + + union { + fstring username; /* getpwnam */ + fstring groupname; /* getgrnam */ + uid_t uid; /* getpwuid, uid_to_sid */ + gid_t gid; /* getgrgid, gid_to_sid */ + struct { + fstring user; + fstring pass; + } auth; /* pam_winbind auth module */ + struct { + unsigned char chal[8]; + fstring user; + fstring domain; + fstring lm_resp; + uint16 lm_resp_len; + fstring nt_resp; + uint16 nt_resp_len; + } auth_crap; + struct { + fstring user; + fstring oldpass; + fstring newpass; + } chauthtok; /* pam_winbind passwd module */ + fstring sid; /* lookupsid, sid_to_[ug]id */ + struct { + fstring dom_name; /* lookupname */ + fstring name; + } name; + uint32 num_entries; /* getpwent, getgrent */ + } data; + fstring domain; /* {set,get,end}{pw,gr}ent() */ +}; + +/* Response values */ + +enum winbindd_result { + WINBINDD_ERROR, + WINBINDD_OK +}; + +/* Winbind response structure */ + +struct winbindd_response { + + /* Header information */ + + uint32 length; /* Length of response */ + enum winbindd_result result; /* Result code */ + + /* Fixed length return data */ + + union { + int interface_version; /* Try to ensure this is always in the same spot... */ + + /* getpwnam, getpwuid */ + + struct winbindd_pw { + fstring pw_name; + fstring pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + fstring pw_gecos; + fstring pw_dir; + fstring pw_shell; + } pw; + + /* getgrnam, getgrgid */ + + struct winbindd_gr { + fstring gr_name; + fstring gr_passwd; + gid_t gr_gid; + int num_gr_mem; + int gr_mem_ofs; /* offset to group membership */ + } gr; + + uint32 num_entries; /* getpwent, getgrent */ + struct winbindd_sid { + fstring sid; /* lookupname, [ug]id_to_sid */ + int type; + } sid; + struct winbindd_name { + fstring dom_name; /* lookupsid */ + fstring name; + int type; + } name; + uid_t uid; /* sid_to_uid */ + gid_t gid; /* sid_to_gid */ + struct winbindd_info { + char winbind_separator; + fstring samba_version; + } info; + fstring domain_name; + + struct auth_reply { + uint32 nt_status; + fstring nt_status_string; + fstring error_string; + int pam_error; + } auth; + } data; + + /* Variable length return data */ + + void *extra_data; /* getgrnam, getgrgid, getgrent */ +}; + +#endif