From 094ca96844842928810f14844413109fc6cdd890 Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Sun, 3 Feb 2013 00:59:38 -0700 Subject: Initial Alpine Version --- web/src/pubcookie/INSTALL | 90 +++++ web/src/pubcookie/Makefile.am | 37 ++ web/src/pubcookie/Makefile.in | 621 +++++++++++++++++++++++++++++ web/src/pubcookie/README | 137 +++++++ web/src/pubcookie/_htaccess_session | 4 + web/src/pubcookie/_htaccess_session_logout | 8 + web/src/pubcookie/auth_gss_proxy.c | 380 ++++++++++++++++++ web/src/pubcookie/debug.cgi | 58 +++ web/src/pubcookie/id_table.c | 294 ++++++++++++++ web/src/pubcookie/id_table.h | 58 +++ web/src/pubcookie/wp_gssapi_proxy.c | 412 +++++++++++++++++++ web/src/pubcookie/wp_tclsh.c | 189 +++++++++ web/src/pubcookie/wp_uidmapper.c | 312 +++++++++++++++ web/src/pubcookie/wp_uidmapper_lib.c | 178 +++++++++ web/src/pubcookie/wp_uidmapper_lib.h | 25 ++ web/src/pubcookie/wp_umc.c | 63 +++ 16 files changed, 2866 insertions(+) create mode 100644 web/src/pubcookie/INSTALL create mode 100644 web/src/pubcookie/Makefile.am create mode 100644 web/src/pubcookie/Makefile.in create mode 100644 web/src/pubcookie/README create mode 100644 web/src/pubcookie/_htaccess_session create mode 100644 web/src/pubcookie/_htaccess_session_logout create mode 100644 web/src/pubcookie/auth_gss_proxy.c create mode 100755 web/src/pubcookie/debug.cgi create mode 100644 web/src/pubcookie/id_table.c create mode 100644 web/src/pubcookie/id_table.h create mode 100644 web/src/pubcookie/wp_gssapi_proxy.c create mode 100644 web/src/pubcookie/wp_tclsh.c create mode 100644 web/src/pubcookie/wp_uidmapper.c create mode 100644 web/src/pubcookie/wp_uidmapper_lib.c create mode 100644 web/src/pubcookie/wp_uidmapper_lib.h create mode 100644 web/src/pubcookie/wp_umc.c (limited to 'web/src/pubcookie') diff --git a/web/src/pubcookie/INSTALL b/web/src/pubcookie/INSTALL new file mode 100644 index 00000000..e4685c40 --- /dev/null +++ b/web/src/pubcookie/INSTALL @@ -0,0 +1,90 @@ +alpine.tar.z web/src/pubcookie/INSTALL +$id$ +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +STEPS TO ADD PUBCOOKIE SUPPORT TO WEB ALPINE +-------------------------------------------- + +UW Pubcookie provides single-sign-on +service for web-based applications. Web Alpine can be built to use UW +Pubcookie within a Kerberos authorization framework. + +Building Web Alpine to use pubcookie authentication should be +accomplished by simply adding: + + --with-pubcookie + +and: + + --with-web-bin=/usr/local/libexec/alpine/bin + +to the configure script's command line. Note, the value you supply in +the second configure option is the directory where ultimately the Web +Alpine's binary support tools will be installed. In addition, +Kerberos 5 must be available on the Alpine web server. + +Installation of the extra binary components for pubcookie support +should happen automatically. After the "make install" command typed +in web/src directory completes successfully, verify that: + + web/bin/wp_uidmapper + web/bin/wp_tclsh + web/bin/wp_gssapi_proxy + +all exist. Then simply follow the normal Web Alpine installation +steps described in the web/INSTALL document. + +Once Web Alpine is installed, there is some additional configuration +required. First, you'll need to change permissions on a couple of the +binary components as they do make use of the setuid() system call. It +should be simply a matter of: + + cd /usr/local/libexec/alpine/bin + sudo chmod 4755 wp_gssapi_proxy wp_tclsh + +Next, you'll need to: + + cd /usr/local/libexec/alpine/cgi/session + +In that directory you'll need to edit the ".htaccess" file, adding the +lines contained in the example htaccess file in the distribution's +"web/src/pubcookie/_htaccess_session". + +Then, + + cd /usr/local/libexec/alpine/cgi/session + +and edit the ".htaccess" file therein, adding the lines contained in +the example file "web/src/pubcookie/_htaccess_session_logout". + +Running Web Alpine with pubcookie requires some extra care and +feeding. First, the service provided by "wp_uidmapper" must be +started and maintained as long as the web server is providing Web +Alpine service. It must be run under the same uid as the web server. +The helper script "debug.cgi" can be used to conveniently +start/restart the wp_uidmapper service. Make sure the path defined +within that script is correct for your system. + +Finally, you'll need to create within the Kerberos 5 system the ID of +the "IMAP Superuser". This userid is used by the web server to log +into the UW IMAP server via SASL proxy authentication. That is, to +establish an IMAP session, the web server logs into the IMAP server +via Kerberos as the IMAP Superuser (which must be configured on the +IMAP server separately) and specifies in that SASL exchange that login +in being performed on behalf of the UW Pubcookie-provided userid. + +With the IMAP Superuser ID established and configured on the IMAP +server, you'll need to acquire a Kerbero ticket on the web server. +Typically, you'll want to install a crontab entry to periodically +refresh the ticket. See web/src/pubcookie/README. + diff --git a/web/src/pubcookie/Makefile.am b/web/src/pubcookie/Makefile.am new file mode 100644 index 00000000..e4da1c39 --- /dev/null +++ b/web/src/pubcookie/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in +## Use aclocal -I m4; automake + +# ======================================================================== +# Copyright 2006-2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +WP_UIDMAPPER_SOCKET = "/tmp/wp_uidmapper" +WEBSERVER_UID = 65534 + +CFLAGS = '-DWP_UIDMAPPER_SOCKET=$(WP_UIDMAPPER_SOCKET)' \ + '-DWEBSERVER_UID=$(WEBSERVER_UID)' \ + '-DAUTH_GSS_PROXY_PATH="$(WEB_BINDIR)/wp_gssapi_proxy"' + +bin_PROGRAMS = wp_uidmapper wp_tclsh wp_gssapi_proxy wp_umc + +noinst_LIBRARIES = libauthgssproxy.a + +libauthgssproxy_a_SOURCES = auth_gss_proxy.c + +wp_uidmapper_SOURCES = wp_uidmapper.c id_table.c id_table.h + +wp_tclsh_SOURCES = wp_tclsh.c wp_uidmapper_lib.c + +wp_gssapi_proxy_SOURCES = wp_gssapi_proxy.c wp_uidmapper_lib.c + +wp_umc_SOURCES = wp_umc.c wp_uidmapper_lib.c + +AM_CPPFLAGS = -I@top_builddir@/include -I@top_srcdir@/include diff --git a/web/src/pubcookie/Makefile.in b/web/src/pubcookie/Makefile.in new file mode 100644 index 00000000..c353b8ba --- /dev/null +++ b/web/src/pubcookie/Makefile.in @@ -0,0 +1,621 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# ======================================================================== +# Copyright 2006-2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = wp_uidmapper$(EXEEXT) wp_tclsh$(EXEEXT) \ + wp_gssapi_proxy$(EXEEXT) wp_umc$(EXEEXT) +subdir = web/src/pubcookie +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + INSTALL +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/VERSION \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libauthgssproxy_a_AR = $(AR) $(ARFLAGS) +libauthgssproxy_a_LIBADD = +am_libauthgssproxy_a_OBJECTS = auth_gss_proxy.$(OBJEXT) +libauthgssproxy_a_OBJECTS = $(am_libauthgssproxy_a_OBJECTS) +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_wp_gssapi_proxy_OBJECTS = wp_gssapi_proxy.$(OBJEXT) \ + wp_uidmapper_lib.$(OBJEXT) +wp_gssapi_proxy_OBJECTS = $(am_wp_gssapi_proxy_OBJECTS) +wp_gssapi_proxy_LDADD = $(LDADD) +am_wp_tclsh_OBJECTS = wp_tclsh.$(OBJEXT) wp_uidmapper_lib.$(OBJEXT) +wp_tclsh_OBJECTS = $(am_wp_tclsh_OBJECTS) +wp_tclsh_LDADD = $(LDADD) +am_wp_uidmapper_OBJECTS = wp_uidmapper.$(OBJEXT) id_table.$(OBJEXT) +wp_uidmapper_OBJECTS = $(am_wp_uidmapper_OBJECTS) +wp_uidmapper_LDADD = $(LDADD) +am_wp_umc_OBJECTS = wp_umc.$(OBJEXT) wp_uidmapper_lib.$(OBJEXT) +wp_umc_OBJECTS = $(am_wp_umc_OBJECTS) +wp_umc_LDADD = $(LDADD) +DEFAULT_INCLUDES = +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libauthgssproxy_a_SOURCES) $(wp_gssapi_proxy_SOURCES) \ + $(wp_tclsh_SOURCES) $(wp_uidmapper_SOURCES) $(wp_umc_SOURCES) +DIST_SOURCES = $(libauthgssproxy_a_SOURCES) $(wp_gssapi_proxy_SOURCES) \ + $(wp_tclsh_SOURCES) $(wp_uidmapper_SOURCES) $(wp_umc_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = '-DWP_UIDMAPPER_SOCKET=$(WP_UIDMAPPER_SOCKET)' \ + '-DWEBSERVER_UID=$(WEBSERVER_UID)' \ + '-DAUTH_GSS_PROXY_PATH="$(WEB_BINDIR)/wp_gssapi_proxy"' + +CP = @CP@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +C_CLIENT_CFLAGS = @C_CLIENT_CFLAGS@ +C_CLIENT_GCCOPTLEVEL = @C_CLIENT_GCCOPTLEVEL@ +C_CLIENT_LDFLAGS = @C_CLIENT_LDFLAGS@ +C_CLIENT_SPECIALS = @C_CLIENT_SPECIALS@ +C_CLIENT_TARGET = @C_CLIENT_TARGET@ +C_CLIENT_WITH_IPV6 = @C_CLIENT_WITH_IPV6@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ISPELLPROG = @ISPELLPROG@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN = @LN@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKE = @MAKE@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NPA_PROG = @NPA_PROG@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PWPROG = @PWPROG@ +RANLIB = @RANLIB@ +REGEX_BUILD = @REGEX_BUILD@ +RM = @RM@ +SED = @SED@ +SENDMAIL = @SENDMAIL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPELLPROG = @SPELLPROG@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WEB_BINDIR = @WEB_BINDIR@ +WEB_BUILD = @WEB_BUILD@ +WEB_PUBCOOKIE_BUILD = @WEB_PUBCOOKIE_BUILD@ +WEB_PUBCOOKIE_LIB = @WEB_PUBCOOKIE_LIB@ +WEB_PUBCOOKIE_LINK = @WEB_PUBCOOKIE_LINK@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +acx_pthread_config = @acx_pthread_config@ +alpine_interactive_spellcheck = @alpine_interactive_spellcheck@ +alpine_simple_spellcheck = @alpine_simple_spellcheck@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +WP_UIDMAPPER_SOCKET = "/tmp/wp_uidmapper" +WEBSERVER_UID = 65534 +noinst_LIBRARIES = libauthgssproxy.a +libauthgssproxy_a_SOURCES = auth_gss_proxy.c +wp_uidmapper_SOURCES = wp_uidmapper.c id_table.c id_table.h +wp_tclsh_SOURCES = wp_tclsh.c wp_uidmapper_lib.c +wp_gssapi_proxy_SOURCES = wp_gssapi_proxy.c wp_uidmapper_lib.c +wp_umc_SOURCES = wp_umc.c wp_uidmapper_lib.c +AM_CPPFLAGS = -I@top_builddir@/include -I@top_srcdir@/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign web/src/pubcookie/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign web/src/pubcookie/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libauthgssproxy.a: $(libauthgssproxy_a_OBJECTS) $(libauthgssproxy_a_DEPENDENCIES) + -rm -f libauthgssproxy.a + $(libauthgssproxy_a_AR) libauthgssproxy.a $(libauthgssproxy_a_OBJECTS) $(libauthgssproxy_a_LIBADD) + $(RANLIB) libauthgssproxy.a +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +wp_gssapi_proxy$(EXEEXT): $(wp_gssapi_proxy_OBJECTS) $(wp_gssapi_proxy_DEPENDENCIES) + @rm -f wp_gssapi_proxy$(EXEEXT) + $(LINK) $(wp_gssapi_proxy_OBJECTS) $(wp_gssapi_proxy_LDADD) $(LIBS) +wp_tclsh$(EXEEXT): $(wp_tclsh_OBJECTS) $(wp_tclsh_DEPENDENCIES) + @rm -f wp_tclsh$(EXEEXT) + $(LINK) $(wp_tclsh_OBJECTS) $(wp_tclsh_LDADD) $(LIBS) +wp_uidmapper$(EXEEXT): $(wp_uidmapper_OBJECTS) $(wp_uidmapper_DEPENDENCIES) + @rm -f wp_uidmapper$(EXEEXT) + $(LINK) $(wp_uidmapper_OBJECTS) $(wp_uidmapper_LDADD) $(LIBS) +wp_umc$(EXEEXT): $(wp_umc_OBJECTS) $(wp_umc_DEPENDENCIES) + @rm -f wp_umc$(EXEEXT) + $(LINK) $(wp_umc_OBJECTS) $(wp_umc_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_gss_proxy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_gssapi_proxy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_tclsh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_uidmapper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_uidmapper_lib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_umc.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-noinstLIBRARIES ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/web/src/pubcookie/README b/web/src/pubcookie/README new file mode 100644 index 00000000..9ca8a493 --- /dev/null +++ b/web/src/pubcookie/README @@ -0,0 +1,137 @@ +alpine.tar.z web/src/pubcookie/README +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +WEB ALPINE WITH PUBCOOKIE SUPPORT +--------------------------------- + +UW Pubcookie provides single-sign-on +service for web-based applications. + +For building and installation comments, see web/src/pubcookie/INSTALL. + + +WEB ALPINE PUBCOOKIE COMPONENTS +------------------------------- + +Below are the extra binary helper applications and their descriptions +necessary to implement UW Pubcookie authentication within Web Alpine. + +bin/wp_uidmapper: + wp_uidmapper runs in background. Keeps pubcookie + username <-> uid tables. Handles requests from + wp_tclsh and wp_gssapi_proxy through the named socket + /tmp/wp_uidmapper. This needs to be manually started, + should never stop running, and should run as the same + uid as the web server (nobody). + +bin/wp_tclsh: + + wp_tclsh is a modified version of tclsh (8.0.5) that + does a setuid before doing the tcl stuff. The tcl + scripts directly run by the web server should use this + as their #! interpreter. If REMOTE_USER is set + (pubcookie in use) and the calling uid is the web + server (nobody), it calls wp_uidmapper to obtain its + destination uid. Otherwise, it just changes back to + the calling uid. + + +bin/wp_gssapi_proxy: + + wp_gssapi_proxy is called by the c-client + auth_gss_proxy.c routine, and does the GSSAPI/SASL + dance with the imap server. Looks up the username + corresponding to the calling uid via wp_uidmapper, and + will fail if the calling program is requesting access + to a different username's mail on the imap + server. Compile time options for wp_gssapi_proxy: + + -DDDEBUG: outputs extra info to the syslog mail log. + -DNO_UIDMAPPER: calls getpwuid(getuid()) to look up + username of calling uid. + +bin/alpined + + auth_gss_proxy.c is the c-client authenticator that calls + wp_gssapi_proxy. Stick this in the imap/src/c-client directory + of the pinetcl source tree. Make sure the + AUTH_GSS_PROXY_PATH #define points to the location of + the installed wp_gssapi_proxy. The following lines + should be added to main() function in pine/pinetcl.c: + + /* put this auth_link at the beginning of the list */ + auth_link(&auth_gss_proxy); + /* try to get username from REMOTE_USER (pubcookie) */ + if(user = getenv("REMOTE_USER")) env_init(user,"/"); + +*.tcl: + + The scripts directly run by the web server must be + changed to point to wp_tclsh instead of the normal + tclsh. If for some reason you want to create a script + that should be run as the web server uid, use the + default tclsh interpreter. There is a script + bin/chscriptinterp, which you can run as follows to + change *.tcl to use /www/test/bin/wp_tclsh instead of + whatever they currently use. + +.htaccess: + + AuthType UWNetID + AuthName "Webpine" + PubcookieAppId "Webpine" + require valid-user + + NOTE: to properly scope the pubcookie cookie for the web server, + remove the PubcookieAppId directive + +logout/.htaccess: + + PubcookieEndSesion redirect + +etc/webpine.keytab: + + Should be owned by nobody.nobody with 600 permissions. A cron + entry for user nobody should run kinit often enough so that + the ticket never expires: + + [root@server /]# crontab -u nobody -l + # DO NOT EDIT THIS FILE - edit the master and reinstall. + # (/var/spool/cron.new/nobody installed on Tue Dec 5 16:26:14 2000) + # (Cron version -- $Id: README 910 2008-01-14 22:28:38Z hubert@u.washington.edu $) + MAILTO=root@your-server-name + 0 3,11,19 * * * /usr/local/bin/kinit -k -t /www/test/etc/webpine.keytab webpine + +debug.cgi: + + If you are having weird problems, run this via your web + browser, and it might help you figure things out. Runs as the web + server uid (nobody) and displays the following: + + - output of 'klist' + - output of 'ps auxww |grep wp_uidmapper' + - the environment + - also lists any processes running as uids with no + corresponding usernames, which should tell you if your + pinetcl process is crashing. + + It also will restart wp_uidmapper if /tmp/wp_uidmapper does not + exist, should that have crashed for some reason. + + Finally, visit debug.cgi?stop (via the web browser) and it + will stop a currently running wp_uidmapper, so that you can + restart it in case you do something like move the location of + the binary. + +-- +$Id: README 910 2008-01-14 22:28:38Z hubert@u.washington.edu $ diff --git a/web/src/pubcookie/_htaccess_session b/web/src/pubcookie/_htaccess_session new file mode 100644 index 00000000..24855aab --- /dev/null +++ b/web/src/pubcookie/_htaccess_session @@ -0,0 +1,4 @@ +AuthType UWNetID +AuthName "Webpine" +PubcookieAppId "Webpine" +require valid-user diff --git a/web/src/pubcookie/_htaccess_session_logout b/web/src/pubcookie/_htaccess_session_logout new file mode 100644 index 00000000..ecc269e1 --- /dev/null +++ b/web/src/pubcookie/_htaccess_session_logout @@ -0,0 +1,8 @@ +# +# mod_rewrite rules to coerce secure (https) access to underlying pages +# + +AddHandler cgi-script tcl + +PubcookieAppId "Webpine" +PubcookieEndSession redirect diff --git a/web/src/pubcookie/auth_gss_proxy.c b/web/src/pubcookie/auth_gss_proxy.c new file mode 100644 index 00000000..ea5daf69 --- /dev/null +++ b/web/src/pubcookie/auth_gss_proxy.c @@ -0,0 +1,380 @@ +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include +#include "../../../c-client/mail.h" +#include "../../../c-client/misc.h" +#include "../../../c-client/osdep.h" + +#define PROTOTYPE(x) x +#include +#include + +long auth_gssapi_proxy_valid (void); +long auth_gssapi_proxy_client (authchallenge_t challenger, + authrespond_t responder, + char *service, + NETMBX *mb,void *stream,unsigned long *trial, + char *user); +char *auth_gssapi_proxy_server (authresponse_t responder,int argc,char *argv[]); + +AUTHENTICATOR auth_gss_proxy = { + AU_SECURE | AU_AUTHUSER, /* secure authenticator */ + "GSSAPI", /* authenticator name */ + auth_gssapi_proxy_valid, /* check if valid */ + auth_gssapi_proxy_client, /* client method */ + auth_gssapi_proxy_server, /* server method */ + NIL /* next authenticator */ +}; + +#define AUTH_GSSAPI_P_NONE 1 +#define AUTH_GSSAPI_P_INTEGRITY 2 +#define AUTH_GSSAPI_P_PRIVACY 4 + +#define AUTH_GSSAPI_C_MAXSIZE 8192 + +#define SERVER_LOG(x,y) syslog (LOG_ALERT,x,y) + +extern char *krb5_defkeyname; /* sneaky way to get this name */ + + +/* Placate const declarations */ + +static gss_OID auth_gss_proxy_mech; +static gss_OID_set auth_gss_proxy_mech_set; + +/* Check if GSSAPI valid on this system + * Returns: T if valid, NIL otherwise + */ + +long auth_gssapi_proxy_valid (void) +{ + char *s,tmp[MAILTMPLEN]; + OM_uint32 smn; + gss_buffer_desc buf; + gss_name_t name; + struct stat sbuf; + sprintf (tmp,"host@%s",mylocalhost ()); + buf.length = strlen (buf.value = tmp) + 1; + memcpy (&auth_gss_proxy_mech,&gss_mech_krb5,sizeof (gss_OID)); + memcpy (&auth_gss_proxy_mech_set,&gss_mech_set_krb5,sizeof (gss_OID_set)); + /* see if can build a name */ + if (gss_import_name (&smn,&buf,gss_nt_service_name,&name) != GSS_S_COMPLETE) + return NIL; /* failed */ + if ((s = strchr (krb5_defkeyname,':')) && stat (++s,&sbuf)) + auth_gss_proxy.server = NIL; /* can't do server if no keytab */ + gss_release_name (&smn,&name);/* finished with name */ + return LONGT; +} + +/* Proxy client authenticator (mihodge) + * Accepts: challenger function + * responder function + * parsed network mailbox structure + * stream argument for functions + * pointer to current trial count + * returned user name + * Returns: T if success, NIL otherwise, number of trials incremented if retry + */ + +#ifndef AUTH_GSS_PROXY_PATH +#define AUTH_GSS_PROXY_PATH "/usr/local/libexec/alpine/bin/wp_gssapi_proxy" +#endif +#define AUTH_GSS_PROXY_MESSAGE 1 +#define AUTH_GSS_PROXY_READ 2 +#define AUTH_GSS_PROXY_SUCCESS 3 +#define AUTH_GSS_PROXY_WRITE 4 +#define AUTH_GSS_PROXY_WRITE_NIL 5 +#define AUTH_GSS_PROXY_EXEC_FAILED 6 + +static unsigned long read_full(int fd,void *buf,unsigned long size) { + unsigned long total,s; + for(total = 0; total < size; total += s) { + s = read(fd,(char*)buf + total,size - total); + if(s == -1) { + if((errno == EAGAIN) || (errno == EINTR)) s = 0; + else return -1; + } else if(s == 0) break; + } + return total; +} + +static unsigned long write_full(int fd,void *buf,unsigned long size) { + unsigned long total,s; + for(total = 0; total < size; total += s) { + s = write(fd,(char*)buf + total,size - total); + if(s == -1) { + if((errno == EAGAIN) || (errno == EINTR)) s = 0; + else return -1; + } + } + return total; +} + +long auth_gssapi_proxy_client (authchallenge_t challenger, + authrespond_t responder, + char *service, + NETMBX *mb,void *stream,unsigned long *trial, + char *user) +{ + char err[MAILTMPLEN]; + int status, ipipe[2], opipe[2]; + unsigned long len,cmd[2],maxlogintrials; + char *buf; + pid_t pid; + long ret = NIL; + + imap_parameters(GET_MAXLOGINTRIALS, (void *) &maxlogintrials); + *trial = maxlogintrials + 1; + err[0] = 0; + strcpy (user,mb->user[0] ? mb->user : myusername ()); + + /* open pipe to gss proxy process */ + if(pipe(ipipe)) { + sprintf (err,"auth_gss_proxy: create pipe error: %s",strerror(errno)); + } else if(pipe(opipe)) { + sprintf (err,"auth_gss_proxy: create pipe error: %s",strerror(errno)); + close(ipipe[0]); + close(ipipe[1]); + } else if((pid = fork()) == -1) { + sprintf (err,"auth_gss_proxy: fork error: %s",strerror(errno)); + close(ipipe[0]); + close(ipipe[1]); + close(opipe[0]); + close(opipe[1]); + + } else if(pid == 0) { /* child process */ + close(ipipe[0]); + close(opipe[1]); + dup2(opipe[0],0); + dup2(ipipe[1],1); + close(opipe[0]); + close(ipipe[1]); + + /* a little overloading of the "err" field here */ + sprintf (err,"%s@%s",service,mb->host); + execlp(AUTH_GSS_PROXY_PATH,AUTH_GSS_PROXY_PATH,err,user,0); + + /* tell parent that exec failed and exit */ + cmd[0] = AUTH_GSS_PROXY_EXEC_FAILED; + cmd[1] = 0; + write_full(1,cmd,sizeof(cmd)); + exit(-1); + + } else { /* parent process */ + close(ipipe[1]); + close(opipe[0]); + + while(len = read_full(ipipe[0],cmd,sizeof(cmd))) { + if (len == -1) { + sprintf (err,"auth_gss_proxy: read error: %s",strerror(errno)); + break; + } else if (len != sizeof(cmd)) { + sprintf (err,"auth_gss_proxy: read error: %lu out of %lu", + len,sizeof(cmd)); + break; + + } else if(cmd[0] == AUTH_GSS_PROXY_EXEC_FAILED) { + sprintf (err,"auth_gss_proxy: could not spawn proxy process"); + break; + + } else if(cmd[0] == AUTH_GSS_PROXY_MESSAGE) { + if(cmd[1]) { + buf = fs_get(cmd[1]); + len = read_full(ipipe[0],buf,cmd[1]); + if(len == -1) { + sprintf (err,"auth_gss_proxy: read error: %s",strerror(errno)); + break; + } else if(len != cmd[1]) { + sprintf (err,"auth_gss_proxy: read error: %lu out of %lu", + len,cmd[1]); + break; + } else { + mm_log(buf,WARN); + } + fs_give ((void **) &buf); + } + + } else if(cmd[0] == AUTH_GSS_PROXY_READ) { + buf = (*challenger) (stream,&len); + if(!buf) len = 0; + if(write_full(opipe[1],&len,sizeof(len)) == -1) { + sprintf (err,"auth_gss_proxy: write error: %s",strerror(errno)); + break; + } else if (buf && (write_full(opipe[1],buf,len) == -1)) { + sprintf (err,"auth_gss_proxy: write error: %s",strerror(errno)); + break; + } + if(buf) fs_give ((void **) &buf); + + } else if(cmd[0] == AUTH_GSS_PROXY_SUCCESS) { + ret = T; + + } else if(cmd[0] == AUTH_GSS_PROXY_WRITE) { + if(cmd[1]) { + buf = fs_get(cmd[1]); + len = read_full(ipipe[0],buf,cmd[1]); + if(len == -1) { + sprintf (err,"auth_gss_proxy: read error: %s",strerror(errno)); + break; + } else if(len != cmd[1]) { + sprintf (err,"auth_gss_proxy: read error: %lu out of %lu", + len,cmd[1]); + break; + } else { + (*responder) (stream,buf,cmd[1]); + } + fs_give ((void **) &buf); + } else { + (*responder) (stream,"",0); + } + + } else if(cmd[0] == AUTH_GSS_PROXY_WRITE_NIL) { + (*responder) (stream,NIL,0); + + } else { + sprintf (err,"auth_gss_proxy: unknown command: %lu",cmd[0]); + break; + } + } + + /* close pipes and wait for process to die */ + close(ipipe[0]); + waitpid(pid,&status,0); + close(opipe[1]); + } + + if(err[0]) mm_log(err,WARN); + return ret; +} + +/* Server authenticator + * Accepts: responder function + * argument count + * argument vector + * Returns: authenticated user name or NIL + */ + +char *auth_gssapi_proxy_server (authresponse_t responder,int argc,char *argv[]) +{ + char *ret = NIL; + char *s,tmp[MAILTMPLEN]; + unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE); + int conf; + OM_uint32 smj,smn,dsmj,dsmn,flags; + OM_uint32 mctx = 0; + gss_name_t crname,name; + gss_OID mech; + gss_buffer_desc chal,resp,buf; + gss_cred_id_t crd; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_qop_t qop = GSS_C_QOP_DEFAULT; + /* make service name */ + sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL), + tcp_serverhost ()); + buf.length = strlen (buf.value = tmp) + 1; + /* acquire credentials */ + if ((gss_import_name (&smn,&buf,gss_nt_service_name,&crname)) == + GSS_S_COMPLETE) { + if ((smj = gss_acquire_cred (&smn,crname,0,auth_gss_proxy_mech_set,GSS_C_ACCEPT, + &crd,NIL,NIL)) == GSS_S_COMPLETE) { + if (resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) { + do { /* negotiate authentication */ + smj = gss_accept_sec_context (&smn,&ctx,crd,&resp, + GSS_C_NO_CHANNEL_BINDINGS,&name,&mech, + &chal,&flags,NIL,NIL); + /* don't need response any more */ + fs_give ((void **) &resp.value); + switch (smj) { /* how did it go? */ + case GSS_S_COMPLETE: /* successful */ + /* paranoia */ + if (memcmp (mech->elements,auth_gss_proxy_mech->elements,mech->length)) + fatal ("GSSAPI is bogus"); + case GSS_S_CONTINUE_NEEDED: + if (chal.value) { /* send challenge, get next response */ + resp.value = (*responder) (chal.value,chal.length, + (unsigned long *) &resp.length); + gss_release_buffer (&smn,&chal); + } + break; + } + } + while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED)); + + /* successful exchange? */ + if ((smj == GSS_S_COMPLETE) && + (gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) { + /* extract authentication ID from principal */ + if (s = strchr ((char *) buf.value,'@')) *s = '\0'; + /* send security and size */ + memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4); + tmp[0] = AUTH_GSSAPI_P_NONE; + if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){ + resp.value = (*responder) (chal.value,chal.length, + (unsigned long *) &resp.length); + gss_release_buffer (&smn,&chal); + if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) { + /* client request valid */ + if (chal.value && (chal.length > 4) && (chal.length < MAILTMPLEN) + && memcpy (tmp,chal.value,chal.length) && + (tmp[0] & AUTH_GSSAPI_P_NONE)) { + /* tie off authorization ID */ + tmp[chal.length] = '\0'; + if (authserver_login (tmp+4,buf.value,argc,argv) || + authserver_login (lcase (tmp+4),buf.value,argc,argv)) + ret = myusername (); + } + /* done with user name */ + gss_release_buffer (&smn,&chal); + } + /* finished with response */ + fs_give ((void **) &resp.value); + } + /* don't need name buffer any more */ + gss_release_buffer (&smn,&buf); + } + /* don't need client name any more */ + gss_release_name (&smn,&name); + /* don't need context any more */ + if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL); + } + /* finished with credentials */ + gss_release_cred (&smn,&crd); + } + + else { /* can't acquire credentials! */ + if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE) + SERVER_LOG ("Failed to acquire credentials for %s",buf.value); + if (smj != GSS_S_FAILURE) do + switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE, + GSS_C_NO_OID,&mctx,&resp)) { + case GSS_S_COMPLETE: + mctx = 0; + case GSS_S_CONTINUE_NEEDED: + SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value); + gss_release_buffer (&dsmn,&resp); + } + while (dsmj == GSS_S_CONTINUE_NEEDED); + do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, + GSS_C_NO_OID,&mctx,&resp)) { + case GSS_S_COMPLETE: + case GSS_S_CONTINUE_NEEDED: + SERVER_LOG ("GSSAPI mechanism status: %s",resp.value); + gss_release_buffer (&dsmn,&resp); + } + while (dsmj == GSS_S_CONTINUE_NEEDED); + } + /* finished with credentials name */ + gss_release_name (&smn,&crname); + } + return ret; /* return status */ +} diff --git a/web/src/pubcookie/debug.cgi b/web/src/pubcookie/debug.cgi new file mode 100755 index 00000000..dd998380 --- /dev/null +++ b/web/src/pubcookie/debug.cgi @@ -0,0 +1,58 @@ +#!/usr/bin/perl +$| = 1; +$wp_uidmapper_bin = "/usr/local/libexec/alpine/bin/wp_uidmapper"; +$wp_uidmapper_socket = "/tmp/wp_uidmapper"; + +print "Content-type: text/plain\n\n"; +print "klist:\n"; +system("/usr/local/bin/klist"); +print "\n"; + +#if($ENV{'QUERY_STRING'} eq 'stop') { +# foreach $line (ps("axww")) { +# ($line =~ m/^(\d+).*wp_uidmapper/) && kill(15,$1); +# } +# sleep(1); +# if(-e $wp_uidmapper_socket) { +# print "Could not kill wp_uidmapper\n"; +# exit(1); +# } +# print "wp_uidmapper stopped\n"; +# exit 0; +#} + +if (! -e $wp_uidmapper_socket) { + print "Yikes! need to spawn new wp_uidmapper process\n"; + if(!fork()) { + close(STDIN); + close(STDOUT); + close(STDERR); + setpgrp(0,0); + exec("$wp_uidmapper_bin 60000-64999"); + } + sleep 1; +} + +@ps = ps("auxww"); +print "wp_uidmapper:\n"; +foreach $line (@ps) { ($line =~ m/wp_uidmapper/) && print $line; } + +print "\nEnvironment:\n"; +foreach $key (sort { $a cmp $b } keys(%ENV)) { + print "$key: $ENV{$key}\n"; +} + +print "\nAlpine user processes:\n"; +foreach $line (@ps) { ($line =~ m/^\#/) && print $line; } +exit 0; + +sub ps { + my ($args) = @_; + my (@a); + open(PS,"ps $args|") || return; + @a = ; + close(PS); + return @a; +} + + diff --git a/web/src/pubcookie/id_table.c b/web/src/pubcookie/id_table.c new file mode 100644 index 00000000..1076524e --- /dev/null +++ b/web/src/pubcookie/id_table.c @@ -0,0 +1,294 @@ +#include "id_table.h" +#include "wp_uidmapper_lib.h" + +#include /* opendir */ +#include /* stat */ +#include /* mallloc,free,strtol */ +#include /* memcpy */ +#include /* errno */ + +#include /* opendir */ +#include /* stat */ + +unsigned long hash_func(char *string,unsigned long num_buckets) { + unsigned long i; + char *p; + for(i = 0, p = string; *p; p++) i = (9 * i) + *p; + return i % num_buckets; +} + +struct id_table_entry { + struct id_table_entry **pself; + struct id_table_entry *next; + int id; + char tmp; + char name[1]; +}; + +struct key_hash_entry { + unsigned key[WP_KEY_LEN]; + id_table_entry *e; + struct key_hash_entry **pself; + struct key_hash_entry *next; +}; + +id_table_range *id_table_range_new(char *str) { + id_table_range *rhead,*rtail; + char *p,*pn; + long s,e; + + rhead = rtail = 0; + for(p = str; *p; p = *pn ? pn + 1 : pn) { + s = strtoul(p,&pn,0); + if(pn > p) { + if(*pn == '-') { + p = pn + 1; + e = strtoul(p,&pn,0); + if(pn == p) e = s; + } else { + e = s; + } + + if(rtail) { + rtail->next = (id_table_range*)malloc(sizeof(id_table_range)); + rtail = rtail->next; + } else { + rhead = rtail = (id_table_range*)malloc(sizeof(id_table_range)); + } + rtail->start = s; + rtail->end = e; + } + } + if(rtail) rtail->next = 0; + return rhead; +} + +void id_table_range_delete(id_table_range *range) { + id_table_range *r; + while(r = range) { + range = range->next; + free(r); + } +} + +int id_table_init(id_table *t,id_table_range *range) { + id_table_range *r; + unsigned long array_end,u; + + if(!range) return -1; + t->array_start = range->start; + array_end = range->end; + for(r = range->next; r; r = r->next) { + if(r->start < t->array_start) t->array_start = r->start; + if(r->end > array_end) array_end = r->end; + } + if(t->array_start >= array_end) return -1; + t->array_size = array_end + 1 - t->array_start; + t->hash_size = t->array_size * 2 + 1; + t->key_hash_size = t->array_size * 2 + 1; + + t->array = (id_table_entry**)malloc(sizeof(id_table_entry*) * t->array_size); + t->hash = (id_table_entry**)malloc(sizeof(id_table_entry*) * t->hash_size); + t->key_hash = (key_hash_entry**)malloc(sizeof(key_hash_entry *) * t->key_hash_size); + if(!t->hash || !t->array || !t->key_hash) { + if(t->hash) free(t->hash); + if(t->key_hash) free(t->key_hash); + if(t->array) free(t->array); + return -1; + } + for(u = 0; u < t->array_size; u++) t->array[u] = (id_table_entry*)-1; + t->max_fill = 0; + for(r = range; r; r = r->next) { + t->max_fill += r->end + 1 - r->start; + for(u = r->start; u <= r->end; u++) t->array[u - t->array_start] = 0; + } + bzero(t->hash,sizeof(id_table_entry*) * t->hash_size); + bzero(t->key_hash, sizeof(key_hash_entry*) * t->key_hash_size); + + t->array_ptr = 0; + t->fill = 0; + return 0; +} + +void id_table_destroy(id_table *t) { + unsigned long u; + for(u = 0; u < t->array_size; u++) + if(t->array[u] && (t->array[u] != (id_table_entry*)-1)) free(t->array[u]); + free(t->hash); + free(t->array); +} + +int id_table_create_id(id_table *t,char *name,unsigned *key) { + id_table_entry **pe,*e; + unsigned long size; + + if(name && strlen(name)){ + for(pe = t->hash + hash_func(name,t->hash_size); *pe; pe = &(*pe)->next) + if(!strcmp(name,(*pe)->name)){ + if(key[0]){ + if((e = key_hash_get_entry(t, key)) == NULL){ + if(key_hash_create_entry(t, *pe, key) == NULL){ + return -1; + } + } + else if(e->id != (*pe)->id){ + return -1; + } + } + + return (*pe)->id; + } + + /* no matching name found */ + } + else { + if(e = key_hash_get_entry(t,key)) + return e->id; + + /* MUST have seen name/key pair at least once */ + errno = EINVAL; + return -1; + } + + /* need to add new entry */ + if(t->fill == t->max_fill) { + id_table_remove_stale(t); + if(t->fill == t->max_fill) { + errno = ENOSPC; + return -1; + } + for(pe = t->hash + hash_func(name,t->hash_size); *pe; pe = &(*pe)->next); + } + size = strlen(name); + e = (id_table_entry*)malloc(sizeof(id_table_entry) + size); + if(!e) return -1; + + while(t->array[t->array_ptr]) + t->array_ptr = (t->array_ptr + 1) % t->array_size; + + e->pself = pe; + e->next = 0; + e->id = (int)(t->array_ptr + t->array_start); + memcpy(e->name,name,size + 1); + if(key[0] && key_hash_create_entry(t, e,key) == NULL) + return -1; + + *pe = e; + t->array[t->array_ptr] = e; + t->array_ptr = (t->array_ptr + 1) % t->array_size; + t->fill++; + return e->id; +} + +static id_table_entry *id_table_get_entry(id_table *t,unsigned long id) { + if(id >= t->array_start) { + id -= t->array_start; + if(id < t->array_size) + if(t->array[id] && (t->array[id] != (id_table_entry*)-1)) + return t->array[id]; + } + return 0; +} + +char *id_table_get_name(id_table *t,int id) { + id_table_entry *e = id_table_get_entry(t,(unsigned long)id); + return e ? e->name : 0; +} + +int id_table_remove_stale(id_table *t) { + id_table_entry *e; + unsigned long u; + DIR *d; + struct dirent *de; + struct stat st; + char path[NAME_MAX + 7]; + + /* + * flag all uids inactive + */ + + for(u = 0; u < t->array_size; u++) + if(t->array[u] && (t->array[u] != (id_table_entry*)-1)) + t->array[u]->tmp = 0; + + /* + * go through list of processes, finding active uids + */ + + memcpy(path,"/proc/",6); + if(d = opendir("/proc")) { + while(de = readdir(d)) { + strcpy(path + 6,de->d_name); + if(!stat(path,&st)) { + if(e = id_table_get_entry(t,(unsigned long)st.st_uid)) e->tmp = 1; + } + } + closedir(d); + } + + /* + * remove ones still marked inactive + */ + + for(u = 0; u < t->array_size; u++) { + e = t->array[u]; + if(e && (e != (id_table_entry*)-1)) { + if(!e->tmp) { + if(e->next) e->next->pself = e->pself; + *e->pself = e->next; + t->array[u] = 0; + t->array_ptr = u; + t->fill--; + key_hash_delete_keys(t, e); + free(e); + } + } + } + return 0; +} + +id_table_entry *key_hash_get_entry(id_table *t, unsigned *key) { + key_hash_entry **ke; + + for(ke = t->key_hash + (key[0] % t->key_hash_size); *ke; ke = &(*ke)->next) + if(key[0] && (*ke)->key[0] == key[0] && !memcmp(key,(*ke)->key,WP_KEY_LEN * sizeof(unsigned))) + return (*ke)->e; + + return NULL; +} + +key_hash_entry *key_hash_create_entry(id_table *t, id_table_entry *pe, unsigned *key) { + key_hash_entry **ke, *kep; + + for(ke = &t->key_hash[key[0] % t->key_hash_size]; *ke; ke = &(*ke)->next) + if(!memcmp(key,(*ke)->key,WP_KEY_LEN * sizeof(unsigned))) + return NULL; + + if(kep = malloc(sizeof(key_hash_entry))){ + memcpy(kep->key,key,(WP_KEY_LEN * sizeof(unsigned int))); + kep->e = pe; + kep->pself = ke; + kep->next = NULL; + *ke = kep; + } + + return kep; +} + +void key_hash_delete_keys(id_table *t, id_table_entry *e) { + key_hash_entry *kp, *kd; + int u; + + for(u = 0; u < t->key_hash_size; u++){ + for(kp = t->key_hash[u]; kp; ) + if (kp->e == e){ + kd = kp; + if(kp->next) kp->next->pself = kp->pself; + *kp->pself = kp->next; + kp = kp->next; + free(kd); + } + else + kp = kp->next; + } +} diff --git a/web/src/pubcookie/id_table.h b/web/src/pubcookie/id_table.h new file mode 100644 index 00000000..2ba3f2b4 --- /dev/null +++ b/web/src/pubcookie/id_table.h @@ -0,0 +1,58 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifndef _ID_TABLE_H_ +#define _ID_TABLE_H_ + +struct id_table_entry; +typedef struct id_table_entry id_table_entry; + +struct key_hash_entry; +typedef struct key_hash_entry key_hash_entry; + +typedef struct id_table_range { + unsigned long start; + unsigned long end; + struct id_table_range *next; +} id_table_range; + +typedef struct id_table { + id_table_entry **array; + unsigned long array_start; + unsigned long array_size; + unsigned long array_ptr; + + id_table_entry **hash; + unsigned long hash_size; + + key_hash_entry **key_hash; + unsigned long key_hash_size; + + unsigned long max_fill; + unsigned long fill; +} id_table; + +id_table_range *id_table_range_new(char *str); +void id_table_range_delete(id_table_range *range); + +int id_table_init(id_table *t,id_table_range *range); +void id_table_destroy(id_table *t); + +int id_table_create_id(id_table *t,char *name,unsigned int *key); +char *id_table_get_name(id_table *t,int id); +int id_table_remove_stale(id_table *t); + +id_table_entry *key_hash_get_entry(id_table *, unsigned *key); +key_hash_entry *key_hash_create_entry(id_table *, id_table_entry *pe, unsigned *key); +void key_hash_delete_keys(id_table *t, id_table_entry *e); + +#endif diff --git a/web/src/pubcookie/wp_gssapi_proxy.c b/web/src/pubcookie/wp_gssapi_proxy.c new file mode 100644 index 00000000..f23d6098 --- /dev/null +++ b/web/src/pubcookie/wp_gssapi_proxy.c @@ -0,0 +1,412 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +/* #define PROTOTYPE(x) x */ + +#include +#include + +#include "wp_uidmapper_lib.h" + +#include +#include + +#define AUTH_GSS_PROXY_MESSAGE 1 +#define AUTH_GSS_PROXY_READ 2 +#define AUTH_GSS_PROXY_SUCCESS 3 +#define AUTH_GSS_PROXY_WRITE 4 +#define AUTH_GSS_PROXY_WRITE_NIL 5 + +#define AUTH_GSSAPI_P_NONE 1 +#define AUTH_GSSAPI_P_INTEGRITY 2 +#define AUTH_GSSAPI_P_PRIVACY 4 + +#ifdef NO_UIDMAPPER +int get_calling_username(int uid,char *name,int namelen) { + struct passwd *pw; + unsigned long len; + + pw = getpwuid(uid); + if(!pw) return -1; + len = strlen(pw->pw_name); + if(len >= namelen) len = namelen - 1; + memcpy(name,pw->pw_name,len); + name[len] = 0; + return len; +} +#else +#define get_calling_username wp_uidmapper_getname +#endif + +static unsigned long read_full(int fd,void *buf,unsigned long size) { + unsigned long total,s; + for(total = 0; total < size; total += s) { + s = read(fd,(char*)buf + total,size - total); + if(s == -1) { + if((errno == EAGAIN) || (errno == EINTR)) s = 0; + else return -1; + } else if(s == 0) break; + } + return total; +} + +static unsigned long write_full(int fd,void *buf,unsigned long size) { + unsigned long total,s; + for(total = 0; total < size; total += s) { + s = write(fd,(char*)buf + total,size - total); + if(s == -1) { + if((errno == EAGAIN) || (errno == EINTR)) s = 0; + else return -1; + } + } + return total; +} + +int cmd_message(char *str1, ...) { + va_list list; + unsigned long cmd[2],size; + char *str; + + for(size = 0,str = str1,va_start(list,str1); str; str = va_arg(list,char*)) + size += strlen(str); + va_end(list); + + cmd[0] = AUTH_GSS_PROXY_MESSAGE; + cmd[1] = size; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + for(str = str1, va_start(list,str1); str; str = va_arg(list,char*)) + if(size = strlen(str)) if(write_full(1,str,size) == -1) { + va_end(list); + return -1; + } + va_end(list); + return 0; +} + +int cmd_read(gss_buffer_desc *pbuf) { + unsigned long cmd[2],len,size; + void *buf; + + cmd[0] = AUTH_GSS_PROXY_READ; + cmd[1] = 0; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + + len = read_full(0,&size,sizeof(size)); + if(len != sizeof(size)) return -1; + if(size == 0) { + pbuf->value = 0; + pbuf->length = 0; + return 0; + } + + buf = malloc(size); + len = read_full(0,buf,size); + if(len != size) { + free(buf); + return -1; + } + pbuf->value = buf; + pbuf->length = size; + return 0; +} + +int cmd_success() { + unsigned long cmd[2]; + cmd[0] = AUTH_GSS_PROXY_SUCCESS; + cmd[1] = 0; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + return 0; +} + +int cmd_write(gss_buffer_desc *buf) { + unsigned long cmd[2]; + cmd[0] = AUTH_GSS_PROXY_WRITE; + cmd[1] = buf->length; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + if(buf->length) if(write_full(1,buf->value,buf->length) == -1) return -1; + return 0; +} + +int cmd_write_nil() { + unsigned long cmd[2]; + cmd[0] = AUTH_GSS_PROXY_WRITE_NIL; + cmd[1] = 0; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + return 0; +} + +/* + * service principal in argv[1] + * reqested username in argv[2] + */ + +int main(int argc,char *argv[]) +{ + char *user = 0; + char userbuf[WP_BUF_SIZE]; + char *prog; + OM_uint32 smj,smn,dsmn,mctx; + gss_name_t crname = GSS_C_NO_NAME; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc chal,resp,buf; + int conf,i; + gss_qop_t qop; + gss_OID oid; + int calling_uid,eff_uid; + + if((prog = strrchr(argv[0], '/')) == NULL) + prog = argv[0]; + else + prog++; + + openlog(prog,LOG_PID,LOG_MAIL); + + calling_uid = getuid(); + eff_uid = geteuid(); +#ifdef DEBUG + syslog(LOG_INFO,"uid = %d, euid=%d\n",calling_uid,eff_uid); +#endif + +#ifdef WEBSERVER_UID + /* if euid != uid, change to web server user */ + if(calling_uid != eff_uid) if(setuid(WEBSERVER_UID)) { + syslog(LOG_ERR,"setuid ((%d != %d) -> %d) failed: %s", + calling_uid,eff_uid,WEBSERVER_UID,strerror(errno)); + cmd_write_nil(); + goto cleanup; + } +#endif + + if(argc < 2) { + syslog(LOG_WARNING,"not enough arguments"); + cmd_write_nil(); + goto cleanup; + } + if(get_calling_username(calling_uid,userbuf,WP_BUF_SIZE) == -1) { + syslog(LOG_WARNING,"cannot determine calling username"); + cmd_write_nil(); + goto cleanup; + } + if(argc == 2) { + user = userbuf; +#ifdef DEBUG + syslog(LOG_INFO,"calling=%s\n",user); +#endif + } else if(argc > 2) { + user = argv[2]; +#ifdef DEBUG + syslog(LOG_INFO,"requested=%s calling=%s\n",user,userbuf); +#endif +#ifndef NO_NAME_CHECK + if(strcmp(user,userbuf)) { + syslog(LOG_WARNING,"cannot act on behalf of user %s (%s)",user,userbuf); + cmd_write_nil(); + goto cleanup; + } +#endif + } + + /* expect empty challenge from server */ + if(cmd_read(&chal)) { + syslog(LOG_WARNING,"cmd_read[initial] failed"); + goto cleanup; + } else if(chal.length) { + free(chal.value); + syslog(LOG_WARNING,"cmd_read[initial] not empty"); + goto cleanup; + } + + /* + * obtain credentials for requested service + */ + + buf.value = argv[1]; + buf.length = strlen(argv[1]); + if(gss_import_name (&smn,&buf,gss_nt_service_name,&crname) != + GSS_S_COMPLETE) { + syslog(LOG_WARNING,"gss_import_name(%s) failed",buf.value); + cmd_write_nil(); + goto cleanup; + } + + /* initial init_sec_context call, and send data */ + memcpy(&oid,&gss_mech_krb5,sizeof(oid)); + smj = gss_init_sec_context + (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,oid, + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS, + GSS_C_NO_BUFFER,0,&resp,0,0); + if((smj == GSS_S_COMPLETE) || (smj == GSS_S_CONTINUE_NEEDED)) { + i = cmd_write(&resp); + gss_release_buffer (&smn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_write[init_sec_context] failed"); + goto cleanup; + } + } + + /* loop until init_sec_context is done */ + while(smj == GSS_S_CONTINUE_NEEDED) { + if(cmd_read(&chal)) { + syslog(LOG_WARNING,"cmd_read[init_sec_context] failed"); + goto cleanup; + } else if(!chal.length) { + syslog(LOG_WARNING,"cmd_read[init_sec_context] empty"); + goto cleanup; + } else { + smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname, + GSS_C_NO_OID, + GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG,0, + GSS_C_NO_CHANNEL_BINDINGS,&chal,0, + &resp,0,0); + if(chal.value) free(chal.value); + if((smj == GSS_S_COMPLETE) || (smj == GSS_S_CONTINUE_NEEDED)) { + i = cmd_write(&resp); + gss_release_buffer (&smn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_write[init_sec_context] failed"); + goto cleanup; + } + } + } + } + + switch(smj) { + case GSS_S_COMPLETE: + /* get challenge and unwrap it */ + if(cmd_read(&chal)) { + syslog(LOG_WARNING,"cmd_read[gss_unwrap] failed"); + goto cleanup; + } + smj = gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop); + if(chal.value) free(chal.value); + if(smj != GSS_S_COMPLETE) { + syslog(LOG_WARNING,"gss_unwrap failed"); + cmd_write_nil(); + goto cleanup; + } else if(resp.length < 4) { + syslog(LOG_WARNING,"challenge too short"); + gss_release_buffer (&smn,&resp); + cmd_write_nil(); + goto cleanup; + } else if(!( ((char*)resp.value)[0] & AUTH_GSSAPI_P_NONE)) { + syslog(LOG_WARNING,"invalid challenge"); + gss_release_buffer (&smn,&resp); + cmd_write_nil(); + goto cleanup; + } + + /* prepare response to challenge */ + buf.length = 4 + (user ? strlen(user) : 0); + buf.value = malloc(buf.length); + memcpy (buf.value,resp.value,4); + gss_release_buffer (&smn,&resp); + *(char*)buf.value = AUTH_GSSAPI_P_NONE; + if(user) memcpy((char*)buf.value + 4, user, buf.length - 4); + + /* wrap response and send */ + smj = gss_wrap (&smn,ctx,0,qop,&buf,&conf,&resp); + free(buf.value); + if(smj != GSS_S_COMPLETE) { + syslog(LOG_WARNING,"gss_unwrap failed"); + cmd_write_nil(); + goto cleanup; + } + i = cmd_write(&resp); + gss_release_buffer (&smn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_write[gss_wrap] failed"); + goto cleanup; + } + + /* success! */ + if(cmd_success()) syslog(LOG_WARNING,"cmd_success failed"); + goto cleanup; + + case GSS_S_CREDENTIALS_EXPIRED: +#ifdef DEBUG + syslog(LOG_INFO,"Kerberos credentials expired (try running kinit)"); +#endif + if(cmd_message("Kerberos credentials expired (try running kinit)",0)) { + syslog(LOG_WARNING,"cmd_message[credentials expired] failed"); + goto cleanup; + } + cmd_write_nil(); + goto cleanup; + + case GSS_S_FAILURE: + if (smn == (OM_uint32) KRB5_FCC_NOFILE) { +#ifdef DEBUG + syslog(LOG_INFO,"No credentials cache found (try running kinit)"); +#endif + if(cmd_message("No credentials cache found (try running kinit)",0)) { + syslog(LOG_WARNING,"cmd_message[no cache file found] failed"); + goto cleanup; + } + } else { + mctx = 0; + do { + gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, + GSS_C_NO_OID,&mctx,&resp); +#ifdef DEBUG + syslog(LOG_INFO,"GSSAPI failure: %s",resp.value); +#endif + i = cmd_message("GSSAPI failure: ",resp.value,0); + gss_release_buffer (&dsmn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_message[failure] failed"); + goto cleanup; + } + } while(mctx); + } + cmd_write_nil(); + goto cleanup; + + default: + mctx = 0; + do { + gss_display_status (&dsmn,smn,GSS_C_GSS_CODE, + GSS_C_NO_OID,&mctx,&resp); +#ifdef DEBUG + syslog(LOG_INFO,"GSSAPI failure: %s",resp.value); +#endif + i = cmd_message("Unknown GSSAPI failure: ",resp.value,0); + gss_release_buffer (&dsmn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_message[unknown failure] failed"); + goto cleanup; + } + } while(mctx); + if(!mctx) do { + gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, + GSS_C_NO_OID,&mctx,&resp); +#ifdef DEBUG + syslog(LOG_INFO,"GSSAPI mechanism status: %s",resp.value); +#endif + i = cmd_message("GSSAPI mechanism status: ",resp.value,0); + gss_release_buffer (&dsmn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_message[unknown failure 2] failed"); + goto cleanup; + } + } while(mctx); + cmd_write_nil(); + goto cleanup; + } + + cleanup: + if(ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,0); + if(crname != GSS_C_NO_NAME) gss_release_name (&smn,&crname); + closelog(); + exit(0); + return 0; +} diff --git a/web/src/pubcookie/wp_tclsh.c b/web/src/pubcookie/wp_tclsh.c new file mode 100644 index 00000000..e7fe14a7 --- /dev/null +++ b/web/src/pubcookie/wp_tclsh.c @@ -0,0 +1,189 @@ +/* + * tclAppInit.c -- + * + * Provides a default version of the main program and Tcl_AppInit + * procedure for Tcl applications (without Tk). + * + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclAppInit.c,v 1.4 1999/02/03 02:58:26 stanton Exp $ + */ + +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifdef TCL_XT_TEST +#include +#endif + +#include "tcl.h" + +/********** (start mihodge) *************************************/ +#include "wp_uidmapper_lib.h" +#include +#include /* getenv */ +/********** (end mihodge) *************************************/ + +/* + * The following variable is a special hack that is needed in order for + * Sun shared libraries to be used for Tcl. + */ + +extern int matherr(); +int *tclDummyMathPtr = (int *) matherr; + + +#ifdef TCL_TEST +extern int Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +extern int Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); +extern int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +extern int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +#endif /* TCL_TEST */ +#ifdef TCL_XT_TEST +extern int Tclxttest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +#endif + +/* + *---------------------------------------------------------------------- + * + * main -- + * + * This is the main program for the application. + * + * Results: + * None: Tcl_Main never returns here, so this procedure never + * returns either. + * + * Side effects: + * Whatever the application does. + * + *---------------------------------------------------------------------- + */ + +int +main(argc, argv) + int argc; /* Number of command-line arguments. */ + char **argv; /* Values of command-line arguments. */ +{ + /********** PUBCOOKIE-Specific Inclusion **************************/ + char *user,sessid[WP_BUF_SIZE],*cookie; + int uid; + unsigned key[WP_KEY_LEN]; + + memset((void *) key, 0, sizeof(unsigned int) * WP_KEY_LEN); + sessid[0] = '\0'; + user = getenv("REMOTE_USER"); + if(!((((cookie = getenv("QUERY_STRING")) + && wp_parse_cookie(cookie,"sessid","&@% ",sessid,WP_BUF_SIZE)) + || ((cookie = getenv("HTTP_COOKIE")) + && wp_parse_cookie(cookie,"sessid",";@ ",sessid,WP_BUF_SIZE))) + && wp_sessid2key(sessid,key))) + cookie = NULL; + + if((getuid() == WEBSERVER_UID) && (user || cookie)){ + if(wp_uidmapper_getuid(user ? user : "",key,&uid) == -1) { + fprintf(stderr,"wp_uidmapper_getname(%s,%s) failed\n",user ? user : "",sessid); + return 1; + } else if(setuid(uid)) { + fprintf(stderr,"setuid(%i) failed: %s\n",uid,strerror(errno)); + return 1; + } + } else { + setuid(getuid()); + } + /********** (end PUBCOOKIE) *************************************/ + +#ifdef TCL_XT_TEST + XtToolkitInitialize(); +#endif + Tcl_Main(argc, argv, Tcl_AppInit); + return 0; /* Needed only to prevent compiler warning. */ +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AppInit -- + * + * This procedure performs application-specific initialization. + * Most applications, especially those that incorporate additional + * packages, will have their own version of this procedure. + * + * Results: + * Returns a standard Tcl completion code, and leaves an error + * message in interp->result if an error occurs. + * + * Side effects: + * Depends on the startup script. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_AppInit(interp) + Tcl_Interp *interp; /* Interpreter for application. */ +{ + if (Tcl_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + +#ifdef TCL_TEST +#ifdef TCL_XT_TEST + if (Tclxttest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } +#endif + if (Tcltest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, + (Tcl_PackageInitProc *) NULL); + if (TclObjTest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + if (Procbodytest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init, + Procbodytest_SafeInit); +#endif /* TCL_TEST */ + + /* + * Call the init procedures for included packages. Each call should + * look like this: + * + * if (Mod_Init(interp) == TCL_ERROR) { + * return TCL_ERROR; + * } + * + * where "Mod" is the name of the module. + */ + + /* + * Call Tcl_CreateCommand for application-specific commands, if + * they weren't already created by the init procedures called above. + */ + + /* + * Specify a user-specific startup file to invoke if the application + * is run interactively. Typically the startup file is "~/.apprc" + * where "app" is the name of the application. If this line is deleted + * then no user-specific startup file will be run under any conditions. + */ + + Tcl_SetVar(interp, "tcl_rcFileName", "~/.tclshrc", TCL_GLOBAL_ONLY); + return TCL_OK; +} diff --git a/web/src/pubcookie/wp_uidmapper.c b/web/src/pubcookie/wp_uidmapper.c new file mode 100644 index 00000000..662e9b3a --- /dev/null +++ b/web/src/pubcookie/wp_uidmapper.c @@ -0,0 +1,312 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include +#include + +#include "id_table.h" +#include "wp_uidmapper_lib.h" + + +/* Makefile should #define: + * + * WP_UIDMAPPER_SOCKET + */ + +unsigned long send_full(int fd,void *buf,unsigned long len,int flags) { + unsigned long total,i; + for(total = 0; total < len; total += i) { + i = send(fd,(char*)buf + total, len - total,flags); + if(i == -1) return -1; + } + return total; +} + +static char *socketname = WP_UIDMAPPER_SOCKET; +static int socketname_remove = 0; + +void socketname_cleanup(void) { + unlink(socketname); +} + +void quit_handler(int signal) { + exit(signal); +} + +int main(int argc, char *argv[]) { + extern char *optarg; + extern int optind, opterr, optopt; + + int debug,log_opt; + mode_t sockmode; + + id_table_range *range; + id_table table; + struct sockaddr_un sun,rsun; + struct sigaction sa; + int is_err,i,ssock,uid; + unsigned int kbuf[WP_KEY_LEN]; + char rbuf[WP_BUF_SIZE],cbuf[WP_BUF_SIZE],rcmd; + struct msghdr rmh,smh; + struct iovec riov[3],siov[1]; +#ifndef DGRAM_MODE + int csock,rsun_len; +#endif + struct ucred cred; + + /* + * process command line arguments + */ + + debug = 0; + log_opt = 0; + sockmode = 0600; + + for(is_err = 0; !is_err && ((i = getopt(argc,argv,"dlrm:s:u:")) != -1); ) { + switch(i) { + case 'd': debug++; break; + case 'l': log_opt |= LOG_PERROR; break; + case 'm': sockmode = strtol(optarg,NULL,0); break; + case 'r': socketname_remove = 1; break; + case 's': socketname = optarg; break; + case 'u': umask(strtol(optarg,NULL,0)); break; + case '?': is_err = 1; break; + } + } + if((optind + 1) == argc) { + range = id_table_range_new(argv[optind]); + if(!range) is_err = 1; + } else { + is_err = 1; + } + if(is_err) { + fprintf(stderr,"Usage: uidmapper [-d] [-l] [-r] [-m mode] [-s socketname] [-u umask] uidranges\n"); + exit(1); + } + + /* + * main initialization + */ + + openlog(argv[0],log_opt,LOG_MAIL); + + if(id_table_init(&table,range)) { + syslog(LOG_ERR,"could not initialize tables: %s\n",strerror(errno)); + exit(1); + } + id_table_range_delete(range); + + sa.sa_handler = quit_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGHUP,&sa,0); + sigaction(SIGINT,&sa,0); + sigaction(SIGQUIT,&sa,0); + sigaction(SIGTERM,&sa,0); + + if(socketname_remove) + socketname_cleanup(); + + /* + * open socket + */ + +#ifdef DGRAM_MODE + ssock = socket(AF_UNIX,SOCK_DGRAM,0); +#else + ssock = socket(AF_UNIX,SOCK_STREAM,0); +#endif + if(ssock < 0) { + syslog(LOG_ERR,"%s: socket: %s\n",socketname,strerror(errno)); + exit(1); + } + /* sun.sun_len = strlen(socketname) + 1; */ + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path,socketname); + if(bind(ssock,(struct sockaddr*)&sun,sizeof(sun))) { + syslog(LOG_ERR,"%s: bind: %s\n",socketname,strerror(errno)); + exit(1); + } + atexit(socketname_cleanup); + chmod(ssock,sockmode); + +#ifndef DGRAM_MODE + if(listen(ssock,8)) { + syslog(LOG_ERR,"%s: listen: %s\n",socketname,strerror(errno)); + exit(1); + } +#endif + +#ifdef DGRAM_MODE + if(debug >= 1) syslog(LOG_INFO,"SOCK_DGRAM socket opened"); +#else + if(debug >= 1) syslog(LOG_INFO,"SOCK_STREAM socket opened"); +#endif + + /* + * accept commands + */ + + riov[0].iov_base = &rcmd; + riov[0].iov_len = 1; + riov[1].iov_base = kbuf; + riov[1].iov_len = WP_KEY_LEN * sizeof(unsigned int); + riov[2].iov_base = rbuf; + riov[2].iov_len = WP_BUF_SIZE - 1; + rmh.msg_name = &rsun; + rmh.msg_namelen = sizeof(rsun); + rmh.msg_iov = riov; + rmh.msg_iovlen = 3; + rmh.msg_control = cbuf; + rmh.msg_controllen = riov[0].iov_len + riov[1].iov_len + riov[2].iov_len; + rmh.msg_flags = 0; + + /* siov[0].iov_base */ + /* siov[0].iov_len */ + smh.msg_name = NULL; + smh.msg_namelen = 0; + smh.msg_iov = siov; + /* smh.msg_iovlen */ + smh.msg_control = NULL; + smh.msg_controllen = 0; + smh.msg_flags = 0; + +#ifndef DGRAM_MODE + csock = -1; +#endif + + while(1) { +#ifdef DGRAM_MODE + i = recvmsg(ssock,&rmh,0); +#else + if(csock >= 0) close(csock); + rsun.sun_family = AF_UNIX; + rsun_len = sizeof(rsun); + csock = accept(ssock,(struct sockaddr*)&rsun,&rsun_len); + if(csock == -1) { + syslog(LOG_ERR,"accept: %s\n",strerror(errno)); + break; + } + if(debug >= 2) { + i = sizeof(cred); + if(getsockopt(csock,SOL_SOCKET,SO_PEERCRED,&cred,&i) == -1) { + syslog(LOG_INFO,"getsockopt(SO_PEERCRED) failed: %s",strerror(errno)); + } else { + syslog(LOG_INFO,"connection from pid=%i uid=%i gid=%i\n", + cred.pid,cred.uid,cred.gid); + } + } + i = recvmsg(csock,&rmh,0); +#endif + + if(i == -1) { + syslog(LOG_ERR,"recvmsg: %s\n",strerror(errno)); + break; + } + if(debug >= 2) + syslog(LOG_INFO,"recvd datagram [size=%i] from %s [size=%i]\n", + i,rsun.sun_path,rmh.msg_namelen); + + /* check that datagram is well formed */ + if(i < 1) { + syslog(LOG_WARNING,"recv: recvd datagram that is too small\n"); + continue; + } + i--; +#ifdef DGRAM_MODE + smh.msg_name = rmh.msg_name; + smh.msg_namelen = rmh.msg_namelen; +#endif + + if(rcmd == 'u') { + if(!i) { + syslog(LOG_WARNING,"recv: recvd 'u' datagram with no payload\n"); + continue; + } + rbuf[i - (WP_KEY_LEN * sizeof(unsigned int))] = 0; + uid = id_table_create_id(&table,rbuf,kbuf); + if(debug >= 1) syslog(LOG_INFO,"request uid(%s) = %i\n",rbuf,uid); + if(uid == -1) { + char sbuf[2 * WP_BUF_SIZE],*sep = strerror(errno); + sprintf(sbuf,"id_table_create_id(%s,[",rbuf); + for(i = 0; i < WP_KEY_LEN; i++) + sprintf(sbuf + strlen(sbuf), "%u,", kbuf[i]); + + sprintf(sbuf + strlen(sbuf) - 1, "]): %s\n",sep); + syslog(LOG_ERR,sbuf); + /* break; hobble along rather than die */ + } + + siov[0].iov_base = &uid; + siov[0].iov_len = sizeof(uid); + smh.msg_iovlen = 1; +#ifdef DGRAM_MODE + if(sendmsg(ssock,&smh,0) == -1) +#else + if(sendmsg(csock,&smh,0) == -1) +#endif + syslog(LOG_WARNING,"sendmsg: %s\n",strerror(errno)); + + } else if(rcmd == 'n') { + if(i != sizeof(uid)) { + syslog(LOG_WARNING,"recv: recvd 'n' datagram with invalid payload\n"); + continue; + } + + memcpy(&uid,kbuf,sizeof(uid)); + siov[0].iov_base = id_table_get_name(&table,uid); + if(debug >= 1) + syslog(LOG_INFO,"request name(%d) = %s\n",uid,siov[0].iov_base); + + if(siov[0].iov_base) { + siov[0].iov_len = strlen(siov[0].iov_base); + smh.msg_iovlen = 1; + } else { + smh.msg_iovlen = 0; + } +#ifdef DGRAM_MODE + if(sendmsg(ssock,&smh,0) == -1) +#else + if(sendmsg(csock,&smh,0) == -1) +#endif + syslog(LOG_WARNING,"sendmsg: %s\n",strerror(errno)); + + } else if(rcmd == 'c') { + if(debug >= 1) syslog(LOG_INFO,"request clear()"); + if(id_table_remove_stale(&table)) { + syslog(LOG_WARNING,"id_table_remove_stale: %s\n",strerror(errno)); + break; + } + } +#ifdef HONOR_QUIT + else if(rcmd == 'q') { + if(debug >= 1) syslog(LOG_INFO,"quit requested"); + break; + } +#endif + else { + syslog(LOG_WARNING,"invalid request received"); + } + } +#ifndef DGRAM_MODE + if(csock >= 0) close(csock); +#endif + + /* + * clean up (never really get this far) + */ + + id_table_destroy(&table); + close(ssock); + exit(0); + return 0; +} diff --git a/web/src/pubcookie/wp_uidmapper_lib.c b/web/src/pubcookie/wp_uidmapper_lib.c new file mode 100644 index 00000000..ddaf5175 --- /dev/null +++ b/web/src/pubcookie/wp_uidmapper_lib.c @@ -0,0 +1,178 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include +#include + +#include "wp_uidmapper_lib.h" + + +static char *xdigits = "0123456789ABCDEF"; + +static int do_handshake(char *sockname, + struct iovec *out,int outlen,int *routbytes, + struct iovec *in,int inlen,int *rinbytes) { + int sock,i; + struct msghdr mh; + struct sockaddr_un sun; + +#ifdef DGRAM_MODE + sock = socket(AF_UNIX,SOCK_DGRAM,0); +#else + sock = socket(AF_UNIX,SOCK_STREAM,0); +#endif + if(sock < 0) return -1; + + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path,sockname); + if(connect(sock,(struct sockaddr*)&sun,sizeof(sun))) return -1; + + mh.msg_name = NULL; + mh.msg_namelen = 0; + mh.msg_iov = out; + mh.msg_iovlen = outlen; + mh.msg_control = NULL; + mh.msg_controllen = 0; + mh.msg_flags = 0; + + if((i = sendmsg(sock,&mh,0)) == -1) { + close(sock); + return -1; + } + if(routbytes) *routbytes = i; + + if(in) { + mh.msg_iov = in; + mh.msg_iovlen = inlen; + mh.msg_flags = 0; + if((i = recvmsg(sock,&mh,0)) == -1) { + close(sock); + return -1; + } + if(rinbytes) *rinbytes = i; + } + close(sock); + return 0; +} + +int wp_uidmapper_getuid(char *name,unsigned int *key,int *puid) { + int uid,outbytes,inbytes; + char cmd; + struct iovec out[3],in[1]; + + cmd = 'u'; + out[0].iov_base = &cmd; + out[0].iov_len = 1; + out[1].iov_base = key; + out[1].iov_len = WP_KEY_LEN * sizeof(unsigned int); + out[2].iov_base = name ? name : ""; + out[2].iov_len = name ? strlen(name) : 0; + in[0].iov_base = &uid; + in[0].iov_len = sizeof(uid); + + if(do_handshake(WP_UIDMAPPER_SOCKET,out,3,&outbytes,in,1,&inbytes)) + return -1; + if((outbytes != (1 + out[1].iov_len) + out[2].iov_len) || (inbytes != in[0].iov_len)) + return -1; + *puid = uid; + return 0; +} + +int wp_uidmapper_getname(int uid,char *name,int namelen) { + int outbytes,inbytes; + char cmd; + struct iovec out[2],in[1]; + + cmd = 'n'; + out[0].iov_base = &cmd; + out[0].iov_len = 1; + out[1].iov_base = &uid; + out[1].iov_len = sizeof(uid); + in[0].iov_base = name; + in[0].iov_len = namelen - 1; + + if(do_handshake(WP_UIDMAPPER_SOCKET,out,2,&outbytes,in,1,&inbytes)) + return -1; + if(outbytes != (1 + out[1].iov_len)) return -1; + name[inbytes] = 0; + return 0; +} + +int wp_uidmapper_clear() { + int outbytes; + char cmd; + struct iovec out[1]; + + cmd = 'c'; + out[0].iov_base = &cmd; + out[0].iov_len = 1; + + if(do_handshake(WP_UIDMAPPER_SOCKET,out,1,&outbytes,NULL,0,NULL)) return -1; + if(outbytes != 1) return -1; + return 0; +} + +int wp_uidmapper_quit() { + int outbytes; + char cmd; + struct iovec out[1]; + + cmd = 'q'; + out[0].iov_base = &cmd; + out[0].iov_len = 1; + + if(do_handshake(WP_UIDMAPPER_SOCKET,out,1,&outbytes,NULL,0,NULL)) return -1; + if(outbytes != 1) return -1; + return 0; +} + +int wp_sessid2key(char *ids,unsigned int *ida) { + int i, j, k; + unsigned int n; + char *p; + + i = j = 0; + while(1){ + n = 0; + for(k = 0; k < 8; k++) + if((p = strchr(xdigits, toupper((int) ids[j++]))) != NULL) + n = (n << 4) | (p - xdigits); + else + return(0); + + ida[i] = n; + if(++i == WP_KEY_LEN) + return(ids[j] == '\0'); + else if(ids[j++] != '.') + return(0); + } +} + +int wp_parse_cookie (char *cookie,char *cname,char *terms,char *cvalue,int vmax) { + char *p, *q; + int i; + + if((p = strstr(cookie, cname)) != NULL){ + p += strlen(cname) + 1; /* skip cname and equals */ + q = cvalue; + while(*p && !strchr(terms, *p)){ + *q++ = *p++; + if((q - cvalue) >= vmax) + return(0); + } + + *q = '\0'; + return(1); + } + + return(0); +} diff --git a/web/src/pubcookie/wp_uidmapper_lib.h b/web/src/pubcookie/wp_uidmapper_lib.h new file mode 100644 index 00000000..e1832454 --- /dev/null +++ b/web/src/pubcookie/wp_uidmapper_lib.h @@ -0,0 +1,25 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifndef _WP_UIDMAPPER_LIB_H_ +#define _WP_UIDMAPPER_LIB_H_ + +int wp_uidmapper_getuid(char *name,unsigned int *key,int *puid); +int wp_uidmapper_getname(int uid,char *name,int namelen); +int wp_uidmapper_clear(); +int wp_uidmapper_quit(); +int wp_sessid2key(char *ids,unsigned int *ida); + +#define WP_BUF_SIZE 1024 +#define WP_KEY_LEN 6 + +#endif diff --git a/web/src/pubcookie/wp_umc.c b/web/src/pubcookie/wp_umc.c new file mode 100644 index 00000000..a55d2127 --- /dev/null +++ b/web/src/pubcookie/wp_umc.c @@ -0,0 +1,63 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include +#include + +#include "wp_uidmapper_lib.h" + + +int main(int argc,char *argv[]) { + char name[WP_BUF_SIZE],sessid[WP_BUF_SIZE]; + int uid,i,key[WP_KEY_LEN]; + + if(argc >= 2) { + if(*argv[1] == 'u') { + if(argc >= 3) { + memset(key,0,WP_KEY_LEN * sizeof(int)); + if(argc >= 4){ + if(wp_parse_cookie(argv[3],"sessid",";@",sessid,WP_BUF_SIZE)) + (void)wp_sessid2key(sessid,key); + } + + if(wp_uidmapper_getuid((argv[2][0] == '\0') ? NULL : argv[2],key,&uid) != -1) { + printf("uid = %i\n",uid); + return 0; + } else fprintf(stderr,"wp_uidmapper_getuid error: %s\n", + strerror(errno)); + } + } else if(*argv[1] == 'n') { + if(argc >= 3) { + i = wp_uidmapper_getname(strtol(argv[2],NULL,0),name,WP_BUF_SIZE); + if(i != -1) { + printf("name = %s\n",name); + return 0; + } else fprintf(stderr,"wp_uidmapper_getname error: %s\n", + strerror(errno)); + } + } else if(*argv[1] == 'c') { + if(wp_uidmapper_clear() != -1) { + printf("clear command sent\n"); + return 0; + } else fprintf(stderr,"wp_uidmapper_clear error: %s\n", + strerror(errno)); + } else if(*argv[1] == 'q') { + if(wp_uidmapper_quit() != -1) { + printf("quit command sent\n"); + return 0; + } else fprintf(stderr,"wp_uidmapper_quit error: %s\n", + strerror(errno)); + } + } + fprintf(stderr,"Usage: wp_umc [u name [key] ] [n uid] [c] [q]\n"); + return -1; +} -- cgit v1.2.3-70-g09d2