Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • alex_orange/emulab-devel
  • hakasapl/emulab-devel
  • cecchet/emulab-devel
  • srirams/emulab-devel
  • chuck/emulab-devel
  • crd/emulab-devel
  • kwebb/emulab-devel
  • moate/emulab-devel
  • grubb/emulab-devel
  • nasir/emulab-devel
  • asydney/emulab-devel
  • kdownie/emulab-devel
  • wvdemeer/emulab-devel
  • anilmr/emulab-devel
  • bvermeul/emulab-devel
  • emulab/emulab-devel
16 results
Show changes
Commits on Source (15055)
Showing with 3742 additions and 489 deletions
VERSION export-subst
# Files that already had DOS-style line endings and those
# that require them should be added to the list below.
clientside/sensors/slothd/idlemon.vbs -crlf
clientside/tmcc/cygwinseven/SetupComplete.cmd -crlf
clientside/tmcc/cygwinseven/unattend-x86.xml.in -crlf
clientside/tmcc/cygwinxp/cygwin-tcsh.bat -crlf
clientside/tmcc/cygwinxp/resolv.conf -crlf
clientside/tmcc/cygwinxp/site-lisp/cygwin-mount.el -crlf
clientside/tmcc/cygwinxp/site-lisp/site-start.el -crlf
clientside/tmcc/cygwinxp/sysprep.inf -crlf
delay/linux/iptables_mods/iptables-1.3.6-imq.diff -crlf
hyperviewer/hv.dsp -crlf
hyperviewer/hv.dsw -crlf
......@@ -64,16 +72,10 @@ protogeni/demo/src/RequestSliverStart.as -crlf
protogeni/demo/src/RequestSliverUpdate.as -crlf
protogeni/demo/src/SimpleNodeClip.as -crlf
protogeni/demo/src/SliceWait.as -crlf
sensors/slothd/idlemon.vbs -crlf
tbsetup/ipassign/dre/prepass/pistream.h -crlf
tbsetup/ipassign/dre/prepass/postream.h -crlf
tbsetup/ipassign/etc/autocheck.conf -crlf
tbsetup/plab/libdslice/xmlrpcserver.py -crlf
tmcd/cygwinxp/cygwin-tcsh.bat -crlf
tmcd/cygwinxp/resolv.conf -crlf
tmcd/cygwinxp/site-lisp/cygwin-mount.el -crlf
tmcd/cygwinxp/site-lisp/site-start.el -crlf
tmcd/cygwinxp/sysprep.inf -crlf
www/csshover.htc -crlf
www/cssmenu.css -crlf
www/cssmenu-new.css -crlf
......
event/trafgen/tg2.0
.merge-build
clientside/tmcc/cygwinseven/unattend-7pro-x86.xml.in
extendCMV
\ No newline at end of file
[submodule "protogeni/rspec-geni"]
path = protogeni/rspec-geni
url = git://git-public.flux.utah.edu/geni-rspec.git
......@@ -2,6 +2,16 @@ configure
autoconf/config.guess
autoconf/config.sub
autoconf/install.sh
clientside/configure
clientside/autoconf/config.guess
clientside/autoconf/config.sub
clientside/autoconf/install.sh
clientside/os/imagezip/fat
clientside/os/imagezip/ntfs/liblocale
clientside/lib/event/event_wrap*
clientside/tmcc/cygwinxp/site-lisp
clientside/tmcc/freebsd/init
clientside/tmcc/plab
os/shd
www/cvsweb
robots/vmcd/camera_data/output_camera*
......@@ -40,3 +50,8 @@ LGPL-COPYING
AGPL-COPYING
TODO.plab
MOVED-TO-WIKI
VERSION
protogeni/flack/js/forge
protogeni/flack/src/com/hurlant
protogeni/flack/src/com/mattism
protogeni/protogeniflash/src/com/mattism
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2000-2021 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
# Testbed Makefile
#
......@@ -14,6 +31,8 @@ EVENTSYS = @EVENTSYS@
PELABSUPPORT = @PELABSUPPORT@
PGENISUPPORT = @PROTOGENI_SUPPORT@
ISMAINSITE = @TBMAINSITE@
SPEWFROMOPS = @SPEWFROMOPS@
MOBILESUPPORT = @MOBILESUPPORT@
SYSTEM := $(shell uname -s)
include Makeconf
......@@ -26,16 +45,21 @@ include Makeconf
# @optional_subdirs@ (has event)
# ipod os security sensors
# Then things that only depend on stuff we've done:
# pxe tbsetup tmcd utils backend www tip capture vis
# pxe tbsetup tmcd utils backend www tip vis
# Then things that depend on stuff we just did:
#
ifeq ($(STANDALONE_CLEARINGHOUSE),0)
SUBDIRS = lib db assign www @optional_subdirs@ ipod security sensors \
pxe tbsetup account tmcd utils backend tip capture ipod vis \
sensors os xmlrpc install/newnode_sshkeys mote tools/whol \
tools/svn wiki bugdb collab protogeni node_usage install
SUBDIRS = \
clientside/lib \
db assign www @optional_subdirs@ clientside ipod security sensors \
pxe tbsetup account tmcd utils wbstore backend ipod vis \
sensors os xmlrpc autofs install/newnode_sshkeys \
tools/svn collab/exp-vis node_usage install
ifeq ($(ISMAINSITE),1)
SUBDIRS += tools/rmanage
SUBDIRS += tools/whol
endif
ifeq ($(PGENISUPPORT),1)
SUBDIRS += protogeni apt powder
endif
else
SUBDIRS = db tbsetup account protogeni
......@@ -84,7 +108,8 @@ boss-install-noupdatecheck: install-schemacheck \
install-setbuildinfo
# Only the checks:
install-checks: install-updatecheck \
install-checks: \
install-updatecheck \
install-schemacheck \
install-sitevarscheck \
install-dbfillcheck install-genischemacheck
......@@ -104,10 +129,10 @@ post-install:
ifeq ($(EVENTSYS),1)
@$(MAKE) -C event post-install
endif
@$(MAKE) -C mote post-install
ifeq ($(MOBILESUPPORT),1)
@$(MAKE) -C mobile
endif
@$(MAKE) -C tools post-install
@$(MAKE) -C wiki post-install
@$(MAKE) -C bugdb post-install
@$(MAKE) -C collab post-install
@$(MAKE) -C utils post-install
ifeq ($(NODE_USAGE_SUPPORT),1)
......@@ -123,38 +148,39 @@ ops-install:
-chmod 770 $(INSTALL_TOPDIR)/log/mysql
-chown mysql $(INSTALL_TOPDIR)/log/mysql
-chgrp mysql $(INSTALL_TOPDIR)/log/mysql
-mkdir -p $(INSTALL_TOPDIR)/log/logfiles
-chmod 777 $(INSTALL_TOPDIR)/log/logfiles
@$(MAKE) -C rc.d control-install
@$(MAKE) -C tbsetup control-install
@$(MAKE) -C security control-install
@$(MAKE) -C tip control-install
# @$(MAKE) -C os control-install
@$(MAKE) -C db control-install
@$(MAKE) -C tbsetup control-install
@$(MAKE) -C utils control-install
@$(MAKE) -C lib control-install
@$(MAKE) -C clientside control-install
ifeq ($(EVENTSYS),1)
@$(MAKE) -C event control-install
endif
@$(MAKE) -C sensors control-install
@$(MAKE) -C xmlrpc control-install
@$(MAKE) -C tmcd control-install
@$(MAKE) -C account control-install
ifeq ($(PELABSUPPORT),1)
@$(MAKE) -C pelab control-install
endif
fs-install:
@$(MAKE) -C rc.d fs-install
@$(MAKE) -C tbsetup fs-install
@$(MAKE) -C clientside fs-install
@$(MAKE) -C sensors fs-install
opsfs-install: ops-install fs-install
@echo "Combined ops/fs install done."
install-mkdirs:
-mkdir -p $(INSTALL_TOPDIR)/db
-mkdir -p $(INSTALL_TOPDIR)/locks
-mkdir -p $(INSTALL_TOPDIR)/log
-mkdir -p $(INSTALL_TOPDIR)/log/mysql
-mkdir -p $(INSTALL_TOPDIR)/etc
-mkdir -p $(INSTALL_TOPDIR)/www
-mkdir -p $(INSTALL_TOPDIR)/suidbin
-mkdir -p $(INSTALL_TOPDIR)/ssl
-chmod 770 $(INSTALL_TOPDIR)/ssl
ifeq ($(STANDALONE_CLEARINGHOUSE),0)
......@@ -173,7 +199,7 @@ ifeq ($(STANDALONE_CLEARINGHOUSE),0)
-chmod 777 $(INSTALL_TOPDIR)/exparchive/Archive
-mkdir -p $(INSTALL_TOPDIR)/images
-chmod 775 $(INSTALL_TOPDIR)/images
-ln -s /usr/testbed/bin/nse $(INSTALL_TOPDIR)/bin
-ln -sf /usr/testbed/bin/nse $(INSTALL_TOPDIR)/bin
endif
just-builddirs:
......@@ -183,8 +209,8 @@ just-builddirs:
tipserv-install:
-mkdir -p $(INSTALL_TOPDIR)/log/tiplogs
-mkdir -p $(INSTALL_TOPDIR)/etc
@$(MAKE) -C tip tipserv-install
@$(MAKE) -C capture tipserv-install
@$(MAKE) -C clientside/tip tipserv-install
@$(MAKE) -C clientside/os/capture tipserv-install
@$(MAKE) -C tbsetup tipserv-install
client-mkdirs:
......@@ -192,53 +218,28 @@ client-mkdirs:
-mkdir -p $(DESTDIR)$(CLIENT_MANDIR)
client:
@$(MAKE) -C lib/libtb client
ifeq ($(EVENTSYS),1)
@$(MAKE) -C event client
endif
@$(MAKE) -C clientside client
@$(MAKE) -C os client
ifneq ($(SYSTEM),CYGWIN_NT-5.1)
@$(MAKE) -C capture client
@$(MAKE) -C tip client
@$(MAKE) -C tools client
endif
@$(MAKE) -C sensors client
@$(MAKE) -C tmcd client
client-install: client client-mkdirs
ifeq ($(EVENTSYS),1)
@$(MAKE) -C event client-install
endif
@$(MAKE) -C clientside client-install
@$(MAKE) -C os client-install
ifneq ($(SYSTEM),CYGWIN_NT-5.1)
@$(MAKE) -C capture client-install
@$(MAKE) -C tip client-install
@$(MAKE) -C tools client-install
endif
@$(MAKE) -C sensors client-install
@$(MAKE) -C tmcd client-install
subboss: client
subboss:
@$(MAKE) -C clientside subboss
@$(MAKE) -C tbsetup subboss
@$(MAKE) -C db subboss
@$(MAKE) -C os subboss
@$(MAKE) -C utils subboss
subboss-install: subboss
ifeq ($(EVENTSYS),1)
@$(MAKE) -C event client-install
endif
ifneq ($(SYSTEM),CYGWIN_NT-5.1)
@$(MAKE) -C capture client-install
@$(MAKE) -C tip client-install
@$(MAKE) -C tools client-install
endif
@$(MAKE) -C sensors client-install
@$(MAKE) -C utils subboss-install
@$(MAKE) -C clientside subboss-install
@$(MAKE) -C tbsetup subboss-install
@$(MAKE) -C os subboss-install
@$(MAKE) -C utils subboss-install
@$(MAKE) -C db subboss-install
@$(MAKE) -C tmcd subboss-install
@$(MAKE) -C rc.d subboss-install
@$(MAKE) -C dhcpd subboss-install
@$(MAKE) -C tbsetup client-install
# Hack: this should probably be done by a subboss-install
# script, but there isn't a huge need for that yet
@rm -f $(INSTALL_RCDIR)/isc-dhcpd
......@@ -246,19 +247,19 @@ endif
TARBALLDESTDIR = /var/tmp/emulab-client
client-tarball:
@if [ `id -u` -ne 0 ]; then \
echo '*** Must run as root!'; \
false; \
fi
@if [ -d "$(TARBALLDESTDIR)" ]; then \
echo "$(TARBALLDESTDIR) already exists."; \
echo "Remove it and try again."; \
false; \
fi
echo "Building and installing client-side in $(TARBALLDESTDIR)..."
DESTDIR=$(TARBALLDESTDIR) $(MAKE) client-install
echo "Creating tarball..."
tar czf emulab-client.tar.gz -C $(TARBALLDESTDIR) .
@$(MAKE) -C clientside client-tarball
client-src-tarball:
@rm -f emulab-client-src.tar.gz
tar clzf emulab-client-src.tar.gz -C clientside
# This is not finished yet.
client-shadow-rpm:
-$(RM) -rf rpmbuild
mkdir -p rpmbuild/SOURCES rpmbuild/SRPMS
$(CP) emulab-client-src.tar.gz rpmbuild/SOURCES
$(RPM) -v -bs --nodeps --define='_topdir $(TOPDIR)/rpmbuild' \
clientside/shadow.spec
destdircheck:
@if [ -z "$(DESTDIR)" ]; then \
......@@ -277,59 +278,56 @@ mfsoscheck:
fi
mfs: mfsoscheck
@$(MAKE) -C os mfs
@$(MAKE) -C sensors mfs
@$(MAKE) -C tmcd mfs
@$(MAKE) -C clientside mfs
mfs-nostatic: mfsoscheck
@NOSTATIC=1 $(MAKE) -C os mfs
@NOSTATIC=1 $(MAKE) -C sensors mfs
@NOSTATIC=1 $(MAKE) -C tmcd mfs
@NOSTATIC=1 $(MAKE) -C clientside mfs
mfs-install: destdircheck mfs client-mkdirs
@$(MAKE) -C os mfs-install
@$(MAKE) -C sensors mfs-install
@$(MAKE) -C tmcd mfs-install
@$(MAKE) -C clientside mfs-install
mfs-nostatic-install: destdircheck mfs-nostatic client-mkdirs
@$(MAKE) -C os mfs-install
@$(MAKE) -C sensors mfs-install
@$(MAKE) -C tmcd mfs-install
@$(MAKE) -C clientside mfs-install
frisbee-mfs: mfsoscheck
@$(MAKE) -C cdrom/groklilo client
@$(MAKE) -C os frisbee-mfs
@$(MAKE) -C tmcd frisbee-mfs
@$(MAKE) -C clientside frisbee-mfs
frisbee-mfs-nostatic: mfsoscheck
@NOSTATIC=1 $(MAKE) -C cdrom/groklilo client
@NOSTATIC=1 $(MAKE) -C os frisbee-mfs
@NOSTATIC=1 $(MAKE) -C tmcd frisbee-mfs
@NOSTATIC=1 $(MAKE) -C clientside frisbee-mfs
frisbee-mfs-install: destdircheck frisbee-mfs
@CLIENT_BINDIR=/etc/testbed $(MAKE) -e -C cdrom/groklilo client-install
@$(MAKE) -C os frisbee-mfs-install
@$(MAKE) -C tmcd frisbee-mfs-install
@$(MAKE) -C clientside frisbee-mfs-install
frisbee-mfs-nostatic-install: destdircheck frisbee-mfs-nostatic
@CLIENT_BINDIR=/etc/testbed $(MAKE) -e -C cdrom/groklilo client-install
@$(MAKE) -C os frisbee-mfs-install
@$(MAKE) -C tmcd frisbee-mfs-install
@$(MAKE) -C clientside frisbee-mfs-install
newnode-mfs: mfsoscheck
@$(MAKE) -C clientside newnode-mfs
newnode-mfs-nostatic: mfsoscheck
@NOSTATIC=1 $(MAKE) -C clientside newnode-mfs
newnode-mfs-install: destdircheck newnode-mfs client-mkdirs
@$(MAKE) -C clientside newnode-mfs-install
newnode-mfs-nostatic-install: destdircheck newnode-mfs-nostatic client-mkdirs
@$(MAKE) -C clientside newnode-mfs-install
cdboot: mfsoscheck client
@echo "CD/Dongle files built"
cdboot-install: destdircheck cdboot
@$(MAKE) -C cdrom client-install
@$(MAKE) -C tmcd/freebsd6 cdboot-install
@$(MAKE) -C clientside/tmcc/freebsd6 cdboot-install
flashboot: mfsoscheck client
@echo "Flash dongle files built"
flashboot-install: destdircheck flashboot
@$(MAKE) -C tmcd/freebsd6 cdboot-install
@$(MAKE) -C clientside/tmcc/freebsd6 cdboot-install
@$(MAKE) -C os frisbee-mfs-install
@$(MAKE) -C flash client-install
@$(MAKE) -C clientside frisbee-mfs-install
#
# A check to see if this is a 'real' install. Kinda hacky, but as far as I can
......@@ -413,6 +411,19 @@ ifeq ($(PGENISUPPORT),1)
endif
@echo "Done"
BRANCHCHECK=
BRANCHECHO= @echo "Skipping branch check since not the Mothership"
ifeq ($(ISMAINSITE),1)
ifeq ($(TBROOT),/usr/testbed)
BRANCHCHECK= cd $(SRCDIR) && \
git status --porcelain -s -b | head -1 | grep -q -s current
BRANCHECHO= @echo "Checking to make sure you are on the mothership branch"
endif
endif
install-branchcheck:
$(BRANCHECHO)
$(BRANCHCHECK)
# We use separate src and obj trees in Emulab, so the traditional distclean to
# clean "made" files from a mingled source-and-obj tree is unnecessary.
# However, this may be useful if you mistakenly configure and make a src tree.
......@@ -420,6 +431,25 @@ clean: clean-subdirs
distclean: distclean-subdirs
rm -f Makeconf GNUmakefile config.h config.status config.cache config.log
rm -f $(DISTCLEAN_FILES)
#
# Be careful, do not run these unless you are updating your installation
# with a new IP subnet or domain name.
#
boss-updateip-clean: clean
@$(MAKE) -C rc.d clean
@$(MAKE) -C apache clean
@$(MAKE) -C named clean
@$(MAKE) -C dhcpd clean
ops-updateip-clean: clean
@$(MAKE) -C rc.d clean
@$(MAKE) -C apache clean
update-rcd:
@$(MAKE) -C rc.d all
@$(MAKE) -C rc.d install
#
# Here's a different approch to recover from just configure problems. It cleans
# all files from an obj tree that have a corresponding .in file in the src tree.
......@@ -427,15 +457,45 @@ undo-configure:
find $SRCDIR -name '*.in' -a -not -name configure.in | \
sed -e "s;$SRCDIR;$OBJDIR;" -e 's;[.]in$;;' | xargs rm -f
elabinelab:
#
# XXX a "temporary" hack for scripts that were evolving fast.
# We didn't want to have to remake the client image whenever we changed these.
# They are copied over to the embryonic boss and ops during setup.
#
elabinelab-scripts:
mkdir -p $(INSTALL_TOPDIR)/etc
cp -f $(SRCDIR)/clientside/tmcc/freebsd/mkextrafs.pl $(INSTALL_TOPDIR)/etc/
cp -f $(SRCDIR)/clientside/tmcc/common/config/rc.mkelab $(INSTALL_TOPDIR)/etc/
ifeq ($(SPEWFROMOPS),1)
elabinelab-nogit: elabinelab-scripts
-mkdir -p /share/emulab
rm -f /share/emulab/emulab-src.tar.gz
tar czf /share/emulab/emulab-src.tar.gz -C $(SRCDIR) --exclude=.git .
elabinelab-git: elabinelab-scripts
-mkdir -p /share/emulab
rm -f /share/emulab/emulab-src.tar.gz
(cd $(SRCDIR); \
git archive HEAD > /share/emulab/emulab-src.tar)
tar rf /share/emulab/emulab-src.tar -C $(SRCDIR) \
--exclude=.git protogeni/rspec-geni
gzip /share/emulab/emulab-src.tar
else
elabinelab-nogit: elabinelab-scripts
-mkdir -p $(INSTALL_TOPDIR)/src
rm -f $(INSTALL_TOPDIR)/src/emulab-src.tar.gz
tar czf $(INSTALL_TOPDIR)/src/emulab-src.tar.gz -C $(SRCDIR) --exclude=.git .
elabinelab-git:
elabinelab-git: elabinelab-scripts
-mkdir -p $(INSTALL_TOPDIR)/src
rm -f $(INSTALL_TOPDIR)/src/emulab-src.tar.gz
git archive --prefix=testbed/ | gzip -c > $(INSTALL_TOPDIR)/src/emulab-src.tar.gz
(cd $(SRCDIR); \
git archive HEAD > $(INSTALL_TOPDIR)/src/emulab-src.tar)
tar rf $(INSTALL_TOPDIR)/src/emulab-src.tar -C $(SRCDIR) \
--exclude=.git protogeni/rspec-geni
gzip $(INSTALL_TOPDIR)/src/emulab-src.tar
endif
# How to recursively descend into subdirectories to make general
# targets such as `all'.
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2009 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2000-2012, 2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
# Get rid of a bunch of nasty built-in implicit rules,
# to avoid bogus circular dependencies and make things go faster.
......@@ -36,29 +53,76 @@ $(INSTALL_ETCDIR)/%: %
-mkdir -p $(INSTALL_ETCDIR)
$(INSTALL_DATA) $< $@
$(addprefix $(INSTALL_SBINDIR)/, $(SETUID_SBIN_SCRIPTS)): $(INSTALL_SBINDIR)/%: %
$(addprefix $(INSTALL_SBINDIR)/, $(SETUID_SBIN_PROGS)): $(INSTALL_SBINDIR)/%: %
echo "Installing (setuid) $<"
-mkdir -p $(INSTALL_SBINDIR)
$(SUDO) $(INSTALL) -o root -m 4755 $< $@
$(addprefix $(INSTALL_BINDIR)/, $(SETUID_BIN_SCRIPTS)): $(INSTALL_BINDIR)/%: %
$(addprefix $(INSTALL_BINDIR)/, $(SETUID_BIN_PROGS)): $(INSTALL_BINDIR)/%: %
echo "Installing (setuid) $<"
-mkdir -p $(INSTALL_BINDIR)
$(SUDO) $(INSTALL) -o root -m 4755 $< $@
$(addprefix $(INSTALL_LIBEXECDIR)/, $(SETUID_LIBX_SCRIPTS)): $(INSTALL_LIBEXECDIR)/%: %
$(addprefix $(INSTALL_LIBEXECDIR)/, $(SETUID_LIBX_PROGS)): $(INSTALL_LIBEXECDIR)/%: %
echo "Installing (setuid) $<"
-mkdir -p $(INSTALL_LIBEXECDIR)
$(SUDO) $(INSTALL) -o root -m 4755 $< $@
$(addprefix $(INSTALL_SBINDIR)/, $(SETUID_SBIN_SCRIPTS)): $(INSTALL_SBINDIR)/%: % $(INSTALL_SUIDDIR)/%
echo "Installing (link to wrapper) $<"
-mkdir -p $(INSTALL_SBINDIR)
-rm -f $@
ln -s $(INSTALL_LIBEXECDIR)/runsuid $@
$(addprefix $(INSTALL_BINDIR)/, $(SETUID_BIN_SCRIPTS)): $(INSTALL_BINDIR)/%: % $(INSTALL_SUIDDIR)/%
echo "Installing (link to wrapper) $<"
-mkdir -p $(INSTALL_BINDIR)
-rm -f $@
ln -s $(INSTALL_LIBEXECDIR)/runsuid $@
$(addprefix $(INSTALL_LIBEXECDIR)/, $(SETUID_LIBX_SCRIPTS)): $(INSTALL_LIBEXECDIR)/%: % $(INSTALL_SUIDDIR)/%
echo "Installing (link to wrapper) $<"
-mkdir -p $(INSTALL_LIBEXECDIR)
-rm -f $@
ln -s $(INSTALL_LIBEXECDIR)/runsuid $@
# Special libexec rule for scripts invoked by suexec (cannot be a symlink)
$(addprefix $(INSTALL_LIBEXECDIR)/, $(SETUID_SUEXEC_SCRIPTS)): $(INSTALL_LIBEXECDIR)/%: % $(INSTALL_SUIDDIR)/%
echo "Installing (hard link to wrapper) $<"
-mkdir -p $(INSTALL_LIBEXECDIR)
-rm -f $@
ln $(INSTALL_LIBEXECDIR)/runsuid $@
$(INSTALL_SUIDDIR)/%: %
echo "Installing (real script) $<"
-mkdir -p $(INSTALL_SUIDDIR)
$(SUDO) $(INSTALL_PROGRAM) $< $@
CFLAGS += $(LOCALCFLAGS)
clean:
distclean: clean
# This is to avoid warnings about duplicate targets.
distclean: default-clean
default-clean:
rm -f GNUmakefile
# This is to avoid warnings about duplicate targets.
default-install-notusing:
ifeq ($(ISMAINSITE),1)
ifeq ($(TBROOT),/usr/testbed)
(cd $(SRCDIR) ; \
git status --porcelain -s -b | head -1 | grep -q -s current)
else
/usr/bin/true
endif
else
/usr/bin/true
endif
#install: default-install
#
# Where to find source files.
# Using specific patterns instead of the catch-all VPATH variable
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2009 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2000-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
# Most of the configure-substitution magic is done here.
# All the other makefiles in the NodeOS include
......@@ -27,6 +44,7 @@ export JAR = @JAR@
prefix = @prefix@
exec_prefix = @exec_prefix@
ISMAINSITE = @TBMAINSITE@
TBROOT = @prefix@
TBDEFS = @TBDEFS@
TBDBNAME = @TBDBNAME@
......@@ -62,6 +80,7 @@ INSTALL_LIBEXECDIR = @libexecdir@
INSTALL_ETCDIR = @sysconfdir@
INSTALL_INCDIR = @includedir@
INSTALL_WWWDIR = @exec_prefix@/www
INSTALL_SUIDDIR = @exec_prefix@/suidbin
INSTALL_RCDIR = @INSTALL_RCDIR@
INSTALL_APACHE_CONFIG = @INSTALL_APACHE_CONFIG@
......@@ -83,6 +102,11 @@ ELVIN_COMPAT = @ELVIN_COMPAT@
HAVE_MEZZANINE = @HAVE_MEZZANINE@
GTK_CONFIG = @GTK_CONFIG@
BRAINSTEM_DIR = @BRAINSTEM_DIR@
WITH_EMULAB = @WITH_EMULAB@
OPSVM_ENABLE = @OPSVM_ENABLE@
OPSVM_MOUNTPOINT= @OPSVM_MOUNTPOINT@
APACHE_VERSION = @APACHE_VERSION@
APACHE_START_COMMAND = @APACHE_START_COMMAND@
host_cpu = @host_cpu@
......@@ -95,3 +119,6 @@ MERGE_BUILD = @MERGE_BUILD@
MERGE_BUILD_SANDBOX = @MERGE_BUILD_SANDBOX@
EXP_VIS_SUPPORT = @EXP_VIS_SUPPORT@
TESTBED_LIBSRCDIR = ${TESTBED_SRCDIR}/clientside/lib
TESTBED_LIBOBJDIR = ${OBJDIR}/clientside/lib
TESTBED_IMAGEZIPSRCDIR = ${TESTBED_SRCDIR}/clientside/os/imagezip
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
# All rights reserved.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2009 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2000-2024 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
SRCDIR = @srcdir@
......@@ -13,16 +30,22 @@ UNIFIED = @UNIFIED_BOSS_AND_OPS@
include $(OBJDIR)/Makeconf
SBIN_STUFF = tbacct addsfskey addpubkey mkusercert quotamail genpubkeys \
newuser newproj mksyscert spewcert
newuser newproj mksyscert spewcert dumpuser dumpproject \
manageremote regencerts
LIBEXEC_STUFF = webtbacct webaddsfskey webaddpubkey webmkusercert \
webnewuser webnewproj webspewcert
CTRLSBIN_STUFF = adduserhook
webnewuser webnewproj webspewcert webmanageremote
CTRLSBIN_STUFF = adduserhook accountsetup
# These scripts installed setuid, with sudo.
SETUID_BIN_SCRIPTS =
SETUID_SBIN_SCRIPTS = tbacct addpubkey mkusercert mksyscert
SETUID_LIBX_SCRIPTS =
ifeq ($(PROTOGENI_SUPPORT),1)
SBIN_STUFF += manageremote
SETUID_SBIN_SCRIPTS += manageremote
endif
#
# Targets
#
......@@ -51,7 +74,8 @@ boss-install: all script-install
@echo "Don't forget to do a post-install as root"
script-install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_STUFF)) \
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_STUFF))
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_STUFF)) \
$(addprefix $(INSTALL_DIR)/opsdir/sbin/, $(CTRLSBIN_STUFF))
post-install:
chmod 775 $(INSTALL_BINDIR)
......
This diff is collapsed.
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2000-2020 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use Getopt::Std;
use XML::Simple;
use File::Temp qw(tempfile :POSIX );
#
# Parse ssh public keys and enter into the DB. The default format is
......@@ -31,7 +49,7 @@ sub usage()
print " -r Force a regenerate of initial key for user\n";
exit(-1);
}
my $optlist = "dkniwfu:rX:";
my $optlist = "dkniwfu:rX:sRNC:S:Ia";
my $iskey = 0;
my $verify = 0;
my $initmode = 0;
......@@ -39,6 +57,11 @@ my $force = 0;
my $genmode = 0;
my $nobody = 0;
my $noemail = 0;
my $remove = 0;
my $nodelete = 0;
my $internal = 0;
my $isaptkey = 0;
my $Comment;
my $xmlfile;
#
......@@ -48,7 +71,11 @@ my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@";
my $OURDOMAIN = "@OURDOMAIN@";
my $CONTROL = "@USERNODE@";
my $KEYGEN = "/usr/bin/ssh-keygen";
my $ACCOUNTPROXY= "$TB/sbin/accountsetup";
my $SSH = "$TB/bin/sshtb";
my $SAVEUID = $UID;
my $USERUID;
# Locals
......@@ -63,6 +90,7 @@ my $user_name;
my $user_email;
my $user_dbid;
my $user_uid;
my $user_gid;
my $debug = 0;
#
......@@ -73,6 +101,9 @@ use libaudit;
use libdb;
use libtestbed;
use User;
if (@PROTOGENI_SUPPORT@) {
require APT_Utility;
}
#
# Function prototypes
......@@ -135,6 +166,9 @@ if (! getopts($optlist, \%options)) {
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"a"})) {
$isaptkey = 1;
}
if (defined($options{"k"})) {
$iskey = 1;
}
......@@ -147,15 +181,30 @@ if (defined($options{"n"})) {
if (defined($options{"i"})) {
$initmode = 1;
}
if (defined($options{"N"})) {
$nodelete = 1;
}
if (defined($options{"I"})) {
$internal = 1;
}
if (defined($options{"r"})) {
$force = 1;
}
if (defined($options{"R"})) {
$remove = 1;
}
if (defined($options{"s"})) {
$noemail = 1;
}
if (defined($options{"w"})) {
$genmode = 1;
}
if (defined($options{"u"})) {
$user = $options{"u"};
}
if (defined($options{"C"})) {
$Comment = $options{"C"};
}
if (defined($options{"X"})) {
$xmlfile = $options{"X"};
......@@ -216,6 +265,18 @@ if (defined($user)) {
$user_dbid = $target_user->dbid();
$user_uid = $target_user->uid();
$USERUID = $target_user->unix_uid();
my $firstproject;
if ($target_user->FirstApprovedProject(\$firstproject) < 0) {
fatal("Could not determine first approved project");
}
if (defined($firstproject)) {
$user_gid = $firstproject->unix_gid();
}
else {
$user_gid = "guest";
}
}
#
......@@ -241,18 +302,16 @@ else {
}
#
# Initmode or genmode, do it and exit. Eventually get rid of the switch
# to the target user.
# Initmode or genmode, do it and exit.
#
if ($initmode) {
# Drop root privs, switch to target user.
$EUID = $UID = $USERUID;
exit InitUser();
}
if ($genmode) {
# Drop root privs, switch to target user.
$EUID = $UID = $USERUID;
exit GenerateKeyFile();
if ($initmode || $genmode) {
if ($initmode) {
exit(InitUser());
}
if ($genmode) {
exit(GenerateKeyFile());
}
exit(1);
}
# Else, key parse mode ...
......@@ -275,29 +334,40 @@ else {
if (! -e $keyfile) {
fatal("No such file: $keyfile\n");
}
$keyline = `head -1 $keyfile`;
open(KEY, "$keyfile")
or fatal("Could not open $keyfile to read");
#
# Ick, look at first line to see if it looks like an openssh key,
# and if so we want to remove the embedded newlines.
#
$keyline = <KEY>;
my $chompit = 0;
if ($keyline =~ /^ssh/ || $keyline =~ /^\d+\s+\d+/) {
$chompit = 1;
}
while (<KEY>) {
chomp($_) if ($chompit);
$keyline .= $_;
}
close(KEY);
}
#
# Check user
#
if (!$verify) {
# If its the user himself, then we can generate a new authkeys file.
if (!$target_user->SameUser($this_user) && !TBAdmin()) {
# If its the user himself, then we can generate a new authkeys file.
# Assume nodelete option comes from internal script, so do not worry.
if (!$target_user->SameUser($this_user) && !$this_user->IsAdmin() &&
!$nodelete) {
fatal("You are not allowed to set pubkeys for $target_user\n");
}
if (-d "$HOMEDIR/$user_uid/.ssh") {
if ($target_user->SameUser($this_user) && $this_user->active()) {
# Drop root privs, switch to target user.
$EUID = $UID = $USERUID;
$genmode = 1;
}
#
# This script is audited when not in verify mode. Since all keys are first
# checked with verify mode, this should not cause any extra email from bad
# keys.
#
AuditStart(0);
}
#
......@@ -340,7 +410,7 @@ sub ParseKey($) {
return 0;
}
if ($keyline =~ /^(\d*\s\d*\s[0-9a-zA-Z]*) ([-\w\@\.\ ]*)\s*$/) {
if ($keyline =~ /^(\d*\s\d*\s[0-9a-zA-Z]*) ([-\\\w\@\.:\ ]*)\s*$/) {
# Protocol 1
$type = "ssh-rsa1";
$key = $1;
......@@ -352,21 +422,20 @@ sub ParseKey($) {
$key = $1;
}
elsif ($keyline =~
/^(ssh-rsa|ssh-dss) ([-\w\.\@\+\/\=]*) ([-\w\@\.\ ]*)$/) {
/^(ssh-rsa|ssh-ed25519) ([-\w\.\@\+\/\=]*) ([-\\\w\@\.:\ ]*)$/) {
# Protocol 2
$type = $1;
$key = "$1 $2";
$comment = $3;
}
elsif ($keyline =~ /^(ssh-rsa|ssh-dss) ([-\w\.\@\+\/\=]*)$/) {
elsif ($keyline =~ /^(ssh-rsa|ssh-ed25519) ([-\w\.\@\+\/\=:]*)$/) {
# Protocol 2 but no comment field
$type = $1;
$key = "$1 $2";
}
if (!defined($key)) {
print "Key cannot be parsed!\n";
print "Key: $keyline\n";
print STDERR "Key cannot be parsed, we accept rsa and ed25519 only!\n";
return 0;
}
......@@ -380,19 +449,34 @@ sub ParseKey($) {
# Make up a comment field for the DB.
#
if (!defined($comment)) {
$comment = "$type-${user_email}";
$comment = (defined($Comment) ? $Comment : "$type-${user_email}");
}
$key = "$key $comment";
my $safe_key = DBQuoteSpecial($key);
my $safe_comment = DBQuoteSpecial($comment);
DBQueryFatal("replace into user_pubkeys ".
"values ('$user_uid', '$user_dbid', ".
" 0, '$key', now(), '$comment')");
if ($remove) {
DBQueryFatal("delete from user_pubkeys ".
"where uid_idx='$user_dbid' and comment=$safe_comment");
}
# Only one APT key allowed
if ($isaptkey) {
DBQueryFatal("delete from user_pubkeys ".
"where uid_idx='$user_dbid' and isaptkey=1");
}
DBQueryFatal("replace into user_pubkeys set ".
" uid='$user_uid', uid_idx='$user_dbid', ".
" internal='$internal', nodelete='$nodelete', ".
" isaptkey='$isaptkey',idx=NULL, stamp=now(), ".
" pubkey=$safe_key, comment=$safe_comment");
#
# Mark user record as modified so nodes are updated.
#
TBNodeUpdateAccountsByUID($user_uid);
if (@PROTOGENI_SUPPORT@) {
APT_Utility::UpdateInstancesByUser($target_user);
}
my $chunked = "";
while (length($key)) {
......@@ -415,7 +499,7 @@ sub ParseKey($) {
"SSH Public Key for '$user_uid' added:\n".
"\n".
"$chunked\n",
"$TBOPS");
"$TBOPS", "Bcc: $TBAUDIT");
}
return 1;
}
......@@ -427,96 +511,47 @@ sub ParseKey($) {
#
sub InitUser()
{
my $sshdir = "$HOMEDIR/$user_uid/.ssh";
#
# Set up the ssh key, but only if not done so already.
#
if (! -e "$sshdir") {
mkdir("$sshdir", 0700) or
fatal("Could not mkdir $sshdir: $!");
}
if (! -e "$sshdir/identity" || $force) {
print "Creating ssh protocol 1 key for $user.\n";
#
# Want to delete existing key from DB.
#
if (-e "$sshdir/identity") {
my $ident = `cat $sshdir/identity.pub`;
if ($ident =~ /(\d*\s\d*\s[0-9a-zA-Z]*)\s([-\w\@\.]*)/) {
DBQueryFatal("delete from user_pubkeys ".
"where uid_idx='$user_dbid' and pubkey='$1 $2'");
}
unlink("$sshdir/identity");
}
# Hmm, need to use -C option so comment field makes sense.
if (system("$KEYGEN -t rsa1 -P '' ".
"-C '${user}" . "\@" . ${OURDOMAIN} . "' ".
"-f $sshdir/identity")) {
fatal("Failure in ssh-keygen!");
}
#
# Grab a copy for the DB.
#
my $ident = `cat $sshdir/identity.pub`;
if ($ident =~ /(\d*\s\d*\s[0-9a-zA-Z]*)\s([-\w\@\.]*)/) {
DBQueryFatal("replace into user_pubkeys ".
"values ('$user_uid', '$user_dbid', ".
" 0, '$1 $2', now(), '$2')");
}
else {
fatal("Bad protocol 1 public key: $ident\n");
}
}
#
# Moving to V2 keys ...
# Want to delete existing keys from DB, but not the sslcert key.
#
if (! -e "$sshdir/id_rsa" || $force) {
print "Creating ssh protocol 2 key for $user.\n";
#
# Want to delete existing key from DB.
#
if (-e "$sshdir/id_rsa") {
my $ident = `cat $sshdir/id_rsa.pub`;
if ($ident =~
/^(ssh-rsa [-\w\.\@\+\/\=]*) ([-\w\@\.\ ]*)$/) {
DBQueryFatal("delete from user_pubkeys ".
"where uid_idx='$user_dbid' and pubkey='$1 $2'");
}
unlink("$sshdir/id_rsa");
}
# Hmm, need to use -C option so comment field makes sense.
DBQueryFatal("delete from user_pubkeys ".
"where uid_idx='$user_dbid' and ".
" (internal=1 or comment like '%\@${OURDOMAIN}' or ".
" comment like '%\@boss.${OURDOMAIN}') and ".
" isaptkey=0 and comment not like 'sslcert:%'");
# Redirect pub key to file, redirect STDERR to STDIN for display.
my $outfile = tmpnam();
my $command = "$ACCOUNTPROXY createsshkey $user_uid $user_gid ";
$UID = 0;
open ERR, "$SSH -host $CONTROL '$command rsa' 2>&1 > $outfile |";
$UID = $SAVEUID;
$errs = "";
while (<ERR>) {
$errs .= $_;
}
close(ERR);
print STDERR $errs;
if ($?) {
unlink($outfile);
fatal("Could not create rsa key");
}
$pubkey = `cat $outfile`;
chomp($pubkey);
$safe_pubkey = DBQuoteSpecial($pubkey);
$comment = "rsa\@${OURDOMAIN}";
if (system("$KEYGEN -t rsa -P '' ".
"-C '${user}" . "\@" . ${OURDOMAIN} . "' ".
"-f $sshdir/id_rsa")) {
fatal("Failure in ssh-keygen!");
}
#
# Grab a copy for the DB.
#
my $ident = `cat $sshdir/id_rsa.pub`;
if ($ident =~
/^(ssh-rsa [-\w\.\@\+\/\=]*) ([-\w\@\.\ ]*)$/) {
DBQueryFatal("replace into user_pubkeys ".
"values ('$user_uid', '$user_dbid', ".
" 0, '$1 $2', now(), '$2')");
}
else {
fatal("Bad protocol 2 public key: $ident\n");
}
}
if (! DBQueryWarn("replace into user_pubkeys set ".
" uid='$user_uid', uid_idx='$user_dbid', ".
" internal='1', nodelete='1', idx=NULL, stamp=now(), ".
" pubkey=$safe_pubkey, comment='$comment'")) {
unlink($outfile);
fatal("Could not add rsa key to database");
}
unlink($outfile);
return GenerateKeyFile();
}
......@@ -527,15 +562,9 @@ sub InitUser()
sub GenerateKeyFile()
{
my @pkeys = ();
my $outfile = tmpnam();
my $sshdir = "$HOMEDIR/$user_uid/.ssh";
my $keyfile = "$sshdir/authorized_keys";
if (! -e $sshdir) {
if (! mkdir($sshdir, 0700)) {
warn("*** WARNING: Could not mkdir $sshdir: $!\n");
return -1;
}
}
my $query_result =
DBQueryFatal("select pubkey from user_pubkeys ".
"where uid_idx='$user_dbid'");
......@@ -544,15 +573,14 @@ sub GenerateKeyFile()
push(@pkeys, $key);
}
print "Generating $keyfile ...\n";
if (!open(AUTHKEYS, "> ${keyfile}.new")) {
warn("*** WARNING: Could not open ${keyfile}.new: $!\n");
print "Generating authorized_keys ...\n";
if (!open(AUTHKEYS, "> $outfile")) {
warn("*** WARNING: Could not open $outfile: $!\n");
return -1;
}
print AUTHKEYS "#\n";
print AUTHKEYS "# DO NOT EDIT! This file auto generated by ".
"Emulab.Net account software.\n";
"Emulab account software.\n";
print AUTHKEYS "#\n";
print AUTHKEYS "# Please use the web interface to edit your ".
"public key list.\n";
......@@ -563,28 +591,17 @@ sub GenerateKeyFile()
}
close(AUTHKEYS);
if (!chmod(0600, "${keyfile}.new")) {
warn("*** WARNING: Could not chmod ${keyfile}.new: $!\n");
return -1;
}
if (-e "${keyfile}") {
if (system("cp -p -f ${keyfile} ${keyfile}.old")) {
warn("*** Could not save off ${keyfile}: $!\n");
return -1;
}
if (!chmod(0600, "${keyfile}.old")) {
warn("*** Could not chmod ${keyfile}.old: $!\n");
}
}
if (system("mv -f ${keyfile}.new ${keyfile}")) {
warn("*** Could not mv ${keyfile} to ${keyfile}.new: $!\n");
}
elsif (-e "$sshdir/authorized_keys2") {
#
# Save to remove deprecated authorized_keys2 file at this point.
#
unlink("$sshdir/authorized_keys2");
$EUID = $UID = 0;
system("$SSH -host $CONTROL ".
"'$ACCOUNTPROXY dropfile $user_uid $user_gid 0600 $sshdir ".
"authorized_keys' < $outfile");
$EUID = $UID = $SAVEUID;
if ($?) {
unlink($outfile);
fatal("Could not copy authorized_keys file to $CONTROL");
}
unlink($outfile);
return 0;
}
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
# All rights reserved.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use Getopt::Std;
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2008 University of Utah and the Flux Group.
# All rights reserved.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use strict;
use English;
......
#!/usr/bin/perl -w
#
# Copyright (c) 2010-2011 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use strict;
use Getopt::Std;
use CGI;
use Data::Dumper;
#
# Dump a project in XML format suitable for reading into newproj script.
#
sub usage()
{
print("Usage: dumpproject [-d] <pid>\n");
exit(-1);
}
my $optlist = "d";
my $debug = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
#
# Untaint the path
#
$ENV{'PATH'} = "$TB/bin:$TB/sbin:/bin:/usr/bin:/usr/bin:/usr/sbin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
use User;
use Project;
# Protos
sub fatal($);
sub DumpProject($);
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (@ARGV != 1) {
usage();
}
my $pid = $ARGV[0];
# Map invoking user to object.
my $this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
#
# Figure out who called us. Must have admin status to do this.
#
if (!$this_user->IsAdmin()) {
fatal("You must be a TB administrator to run this script!");
}
# Map target user to object.
my $project = Project->Lookup($pid);
if (! defined($project)) {
fatal("$pid does not exist!");
}
DumpProject($project);
exit(0);
#
# Dump the project in XML.
#
sub DumpProject($)
{
my ($project) = @_;
# Array of string values to print.
my %xmlnames = (
"pid" => {"tag" => "name",
"optional" => 0 },
"head_uid" => {"tag" => "leader",
"optional" => 0 },
"description" => {"tag" => "short description",
"optional" => 0 },
"URL" => {"tag" => "URL",
"optional" => 0 },
"funders" => {"tag" => "funders",
"optional" => 0 },
"why" => {"tag" => "long description",
"optional" => 0 },
"public" => {"tag" => "public",
"optional" => 0 },
"num_pcs" => {"tag" => "num_pcs",
"optional" => 0 },
"linked_to_us" => {"tag" => "linkedtous",
"optional" => 0 },
);
print "<project>\n";
foreach my $key (keys(%xmlnames)) {
my $ref = $xmlnames{$key};
my $tag = $ref->{'tag'};
my $optional = $ref->{'optional'};
my $val = $project->$key();
next
if (!defined($val) && $optional);
$val = "None"
if (!defined($val) &&
($key eq "funders" || $key eq "why"));
print " <attribute name=\"$tag\">";
print "<value>" . CGI::escapeHTML($val) . "</value>";
print "</attribute>\n";
}
print "</project>\n";
}
sub fatal($)
{
my ($mesg) = @_;
print STDERR "*** $0:\n".
" $mesg\n";
exit(-1);
}
#!/usr/bin/perl -w
#
# Copyright (c) 2010-2020 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use strict;
use Getopt::Std;
use CGI;
use Data::Dumper;
#
# Dump a user in XML format suitable for reading into newuser script.
#
sub usage()
{
print("Usage: dumpuser [-d] [-p] <uid>\n");
exit(-1);
}
my $optlist = "dp";
my $debug = 0;
my $nopswd = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $PGENISUPPORT= @PROTOGENI_SUPPORT@;
my $OURDOMAIN = "@OURDOMAIN@";
#
# Untaint the path
#
$ENV{'PATH'} = "$TB/bin:$TB/sbin:/bin:/usr/bin:/usr/bin:/usr/sbin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
use User;
use Project;
if ($PGENISUPPORT) {
require GeniHRN;
}
# Protos
sub fatal($);
sub DumpUser($);
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"p"})) {
$nopswd = 1;
}
if (@ARGV != 1) {
usage();
}
my $user = $ARGV[0];
# Map invoking user to object.
my $this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
# Map target user to object.
my $target_user = User->Lookup($user);
if (! defined($target_user)) {
fatal("$user does not exist!");
}
DumpUser($target_user);
exit(0);
#
# Dump the user in XML.
#
sub DumpUser($)
{
my ($user) = @_;
my @keys = ();
# Array of string values to print.
my %xmlnames = (
"name" => {"tag" => "name",
"optional" => 0 },
"email" => {"tag" => "email",
"optional" => 0 },
"pswd" => {"tag" => "passhash",
"optional" => 0 },
"uid" => {"tag" => "uid",
"optional" => 0 },
"URL" => {"tag" => "URL",
"optional" => 1 },
"addr" => {"tag" => "address",
"optional" => 1 },
"addr2" => {"tag" => "address2",
"optional" => 1 },
"city" => {"tag" => "city",
"optional" => 0 },
"state" => {"tag" => "state",
"optional" => 0 },
"zip" => {"tag" => "zip",
"optional" => 1 },
"country" => {"tag" => "country",
"optional" => 0 },
"phone" => {"tag" => "phone",
"optional" => 1 },
"title" => {"tag" => "title",
"optional" => 1 },
"affil" => {"tag" => "affiliation",
"optional" => 0 },
"shell" => {"tag" => "shell",
"optional" => 1 },
"wikiname" => {"tag" => "wikiname",
"optional" => 1 },
"affil_abbrev" => {"tag" => "affiliation_abbreviation",
"optional" => 0 },
);
$user->GetSSHKeys(\@keys) == 0
or fatal("Could not net ssh keys");
print "<userinfo>\n";
foreach my $key (keys(%xmlnames)) {
my $ref = $xmlnames{$key};
my $tag = $ref->{'tag'};
my $optional = $ref->{'optional'};
my $val = $user->$key();
next
if ($optional && (!defined($val) || $val eq ""));
$val = "None"
if (!defined($val) && $key eq "affil_abbrev");
next
if ($nopswd && $key eq "pswd");
print " <attribute name=\"$tag\">";
print "<value>" . CGI::escapeHTML($val) . "</value>";
print "</attribute>\n";
}
# Pubkeys are special.
if (@keys) {
foreach my $key (@keys) {
next
if ($key =~ /^ssh-dss/);
print "<pubkeys>$key</pubkeys>\n";
}
}
print "</userinfo>\n";
}
sub fatal($)
{
my ($mesg) = @_;
print STDERR "*** $0:\n".
" $mesg\n";
exit(-1);
}
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use Getopt::Std;
......
#!/usr/bin/perl -w
#
# Copyright (c) 2005-2022 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use strict;
use Getopt::Std;
use Data::Dumper;
use File::Temp qw(tempfile);
use JSON;
#
# Ask https://ipinfo.io/ for IP info
#
# select cc.country,sum(t.count) as count from
# (select country,count(distinct(uid)) as count from login_history
# where IP is not null and location is not null and portal='cloudlab'
# group by country,uid) as t
# left join ccodes.ccodes as cc on cc.code=t.country
# group by cc.country order by count desc;
#
#select region,sum(t.count) as count from
# (select region,count(distinct(uid)) as count from login_history
# where IP is not null and location is not null and country='US' and
# portal='cloudlab'
# group by region,uid) as t
#group by region order by count desc;
#
#
sub usage()
{
print "Usage: getipinfo [-n]\n";
print " getipinfo [-n] -p portal\n";
exit(1);
}
my $optlist = "ndp:";
my $impotent = 0;
my $debug = 0;
my $limit = 200;
#
# Configure variables
#
my $TB = "@prefix@";
my $token = "850749cc3b77dc";
my $URL = "http://ipinfo.io/batch?token=${token}";
my $CURL = "/usr/local/bin/curl";
# Load the Testbed support stuff.
use lib "@prefix@/lib";
use emdb;
use User;
use emutil;
# Protos
sub fatal($);
sub WriteResults($);
#
# Turn off line buffering on output
#
$| = 1;
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"n"})) {
$impotent++;
}
if (defined($options{"d"})) {
$debug++;
}
if (defined($options{"p"})) {
my $portal = $options{"p"};
if ($portal ne "cloudlab" && $portal ne "powder") {
fatal("Only cloudlab or powder portal please");
}
exit(WriteResults($portal));
}
#
# Find unmatched IPs in the login_history table and batch them up
# for the request.
#
my $count = 0;
while ($limit) {
$limit--;
my $query_result =
DBQueryFatal("select distinct IP from login_history ".
"where location is null and IP is not null ".
"limit 100");
last
if ($query_result->numrows == 0);
my %IPs = ();
while (my ($IP) = $query_result->fetchrow_array()) {
$IPs{$IP} = $IP;
}
if (keys(%IPs)) {
# Create a temporary files for curl
my ($fpIn, $fnameIn) = tempfile("/tmp/iplistInXXXXX", UNLINK => 0);
if (!defined($fpIn)) {
fatal("Could not create temp file for IPs");
}
my ($fpOut, $fnameOut) = tempfile("/tmp/iplistOutXXXXX", UNLINK => 0);
if (!defined($fpOut)) {
fatal("Could not create temp file for IPs");
}
foreach my $IP (keys(%IPs)) {
print $fpIn "$IP\n";
}
my $command =
"$CURL -s -o $fnameOut -XPOST --data-binary \@${fnameIn} $URL";
if ($debug) {
print "$command\n";
}
system($command);
if ($?) {
fatal("curl failure: '$command'\n");
}
my $json = emutil::ReadFile($fnameOut);
if (!$json || $json eq "") {
fatal("No json received");
}
my $results = eval { decode_json($json) };
if ($@) {
fatal("Could not decode json data");
}
if ($debug) {
print Dumper($results);
}
foreach my $IP (keys(%IPs)) {
my $ref = $results->{$IP};
if (!defined($ref)) {
print STDERR "No data for $IP\n";
next;
}
my $loc = $ref->{'loc'};
my $country = $ref->{'country'};
my $region = $ref->{'region'};
if (!defined($loc)) {
print STDERR "No data for $IP\n";
DBQueryFatal("update login_history set ".
" location='' ".
"where IP='$IP'");
next;
}
$count++;
if ($impotent) {
print "Would set $IP: $loc,$country,$region\n";
next;
}
else {
print "$IP: $loc,$country,$region\n";
DBQueryFatal("update login_history set ".
" location=" . DBQuoteSpecial($loc) . ", ".
" country=" . DBQuoteSpecial($country) . ", ".
" region=" . DBQuoteSpecial($region) . " ".
"where IP='$IP'");
}
}
unlink($fnameIn);
unlink($fnameOut);
}
print "$count IPs completed\n";
last
if (!$count);
sleep(10);
}
exit(0);
#
# Write per portal results files. Queries take a while.
#
sub WriteResults($)
{
my ($portal) = @_;
print "These queries take time, get a cup of coffee.\n";
my $query_result =
DBQueryFatal("select cc.country,sum(t.count) as count from ".
" (select country,count(distinct(uid)) as count ".
" from login_history ".
" where IP is not null and location is not null and ".
" portal='$portal' ".
" group by country,uid) as t ".
"left join ccodes.ccodes as cc on cc.code=t.country ".
"group by cc.country order by count desc");
my $fname = "world-counts-${portal}.csv";
print "Writing $fname ... \n";
if (open(WORLD, ">$fname")) {
print WORLD "name,count\n";
while (my ($country,$count) = $query_result->fetchrow_array()) {
next
if (!defined($country));
$country = "USA"
if ($country eq "United States");
print WORLD "$country,$count\n";
}
close(WORLD);
}
else {
fatal("Could not open $fname for writing: $!\n");
}
$query_result =
DBQueryFatal("select region,sum(t.count) as count from ".
" (select region,count(distinct(uid)) as count ".
" from login_history ".
" where IP is not null and location is not null and ".
" country='US' and portal='$portal' ".
" group by region,uid) as t ".
"group by region order by count desc");
$fname = "us-counts-${portal}.csv";
print "Writing $fname ... \n";
if (open(STATES, ">$fname")) {
print STATES "name,count\n";
while (my ($region,$count) = $query_result->fetchrow_array()) {
next
if (!defined($region));
print STATES "$region,$count\n";
}
close(STATES);
}
else {
fatal("Could not open $fname for writing: $!\n");
}
exit(0);
}
sub fatal($) {
my($mesg) = $_[0];
die("*** $0:\n".
" $mesg\n");
}
#!/usr/bin/perl -w
#
# Copyright (c) 2010-2016, 2019 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
# GENI Public License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
#
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Data::Dumper;
use CGI;
#
#
#
sub usage()
{
print "Usage: manageremote version <remote>\n";
print " manageremote addpeer <remote> <urn> <url> [is_primary]\n";
print " manageremote adduser <remote> <uid>\n";
print " manageremote deluser <remote> <uid>\n";
print " manageremote moduser <remote> <uid>\n";
print " manageremote setgroups <remote> <uid>\n";
print " manageremote xlogin <remote> <uid>\n";
print " manageremote addproject <remote> <pid>\n";
print " manageremote addgroup <remote> <gid>\n";
exit(1);
}
my $optlist = "dnfp";
my $debug = 0;
my $force = 0;
my $impotent = 0;
my $locked = 0;
my $fromdaemon = 0;
#
# Function prototypes
#
sub Version();
sub AddUser(;$);
sub AddPeer();
sub DeleteUser();
sub ModifyUser();
sub SetGroups(;$);
sub CrossLogin();
sub AddProject();
sub AddGroup();
sub fatal($);
sub do_method($$;$);
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $PGENISUPPORT = @PROTOGENI_SUPPORT@;
my $PEER_ENABLE = @PEER_ENABLE@;
my $PEER_PRIMARY = @PEER_ISPRIMARY@;
my $OURDOMAIN = "@OURDOMAIN@";
my $DUMPUSER = "$TB/sbin/dumpuser";
my $DUMPPROJ = "$TB/sbin/dumpproject";
my $SACERT = "$TB/etc/genisa.pem";
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/site/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
use lib '@prefix@/lib';
use emdb;
use libtestbed;
use User;
use Project;
use Group;
use emutil;
use GeniHRN;
use Genixmlrpc;
use GeniResponse;
use GeniCredential;
use GeniAuthority;
#
# Check args.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"f"})) {
$force = 1;
}
if (defined($options{"n"})) {
$impotent = 1;
}
if (defined($options{"p"})) {
$fromdaemon = 1;
}
usage()
if (@ARGV < 2 || @ARGV > 5);
my $cmd = shift(@ARGV);
my $peername = shift(@ARGV);
my $peerurn;
if (! $PEER_ENABLE) {
fatal("Peer mode is not enabled");
}
if (! ($PEER_PRIMARY || $cmd eq "addpeer")) {
fatal("You can only run addpeer on this boss");
}
#
# Map invoking user to object.
#
my $this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
#
# Mere users can call only one function.
#
if (!$this_user->IsAdmin() && $cmd ne "xlogin") {
fatal("You must be a TB administrator to run this script!");
}
#
# Load the SA cert to act as caller context.
#
my $certificate = GeniCertificate->LoadFromFile($SACERT);
if (!defined($certificate)) {
fatal("Could not load certificate from $SACERT\n");
}
my $context = Genixmlrpc->Context($certificate);
if (!defined($context)) {
fatal("Could not create context to talk to clearinghouse");
}
Genixmlrpc->SetContext($context);
my $me = GeniAuthority->Lookup($certificate->uuid());
if (!defined($me)) {
fatal("Could not find my own authority object");
}
my $credential = GeniCredential->GetSelfCredential($me);
if (!defined($credential)) {
fatal("Could not create self credential for $me");
}
my $authority;
#
# All operations other then AddPeer require that the peer be
# in the DB.
#
if ($cmd ne "addpeer") {
my $query_result =
DBQueryFatal("select name,urn from emulab_peers ".
"where name='$peername' or urn='$peername'");
fatal("Unknown peer")
if (!$query_result->numrows);
($peername,$peerurn) = $query_result->fetchrow_array();
$authority = GeniAuthority->CreateFromRegistry("sa", $peerurn);
if (!defined($authority)) {
fatal("Could not locate authority for $peername");
}
}
#
# All operations other then xlogin require locking to avoid a
# race with the peer_daemon.
#
if ($cmd ne "xlogin" && !$fromdaemon) {
while (TBScriptLock("portal_op", 0, 5) != TBSCRIPTLOCK_OKAY()) {
print "Could not get the lock; trying again ... ^C to stop trying.\n";
next;
}
$locked = 1;
}
#
# Now dispatch operation.
#
SWITCH: for ($cmd) {
/^version$/ && do {
Version();
last SWITCH;
};
/^adduser$/ && do {
AddUser();
last SWITCH;
};
/^addpeer$/ && do {
AddPeer();
last SWITCH;
};
/^deluser$/ && do {
DeleteUser();
last SWITCH;
};
/^moduser$/ && do {
ModifyUser();
last SWITCH;
};
/^setgroups$/ && do {
SetGroups();
last SWITCH;
};
/^xlogin$/ && do {
CrossLogin();
last SWITCH;
};
/^addproject$/ && do {
AddProject();
last SWITCH;
};
/^addgroup$/ && do {
AddGroup();
last SWITCH;
};
# Default
TBScriptUnlock()
if ($locked);
usage();
}
TBScriptUnlock()
if ($locked);
exit(0);
#
# Get the version.
#
sub Version()
{
my $response = do_method($authority, "GetVersion");
fatal("Could not get version from $authority")
if (! (defined($response) &&
$response->code() == GENIRESPONSE_SUCCESS));
my $version = $response->value();
print "Version: $version\n";
return 0;
}
#
# Add a peer to the list
#
sub AddPeer()
{
usage()
if (@ARGV < 2);
my $urn = shift(@ARGV);
my $url = shift(@ARGV);
my $primary = (@ARGV ? shift(@ARGV) : 0);
my $safe_url = DBQuoteSpecial($url);
$primary = ($primary ? 1 : 0);
fatal("Invalid URN")
if (!GeniHRN::IsValid($urn));
fatal("Invalid peer name")
if (! ($peername =~ /^[-\w]*$/));
my $authority = GeniAuthority->CreateFromRegistry("sa", $urn);
if (!defined($authority)) {
fatal("Could not locate authority for $peername");
}
my $query_result =
DBQueryFatal("select * from emulab_peers ".
"where name='$peername' or urn='$urn' or ".
" weburl=$safe_url");
fatal("Peer already exists. Please delete first")
if ($query_result->numrows);
fatal("Could not add new peer")
if (!DBQueryWarn("insert into emulab_peers set ".
" name='$peername', urn='$urn', weburl=$safe_url, ".
" is_primary='$primary'"));
return 0;
}
#
# Add a user.
#
sub AddUser(;$)
{
my ($token) = @_;
if (! defined($token)) {
usage()
if (! @ARGV);
$token = $ARGV[0];
}
my $user = User->Lookup($token);
if (!defined($user)) {
fatal("No such user");
}
my $uid_idx = $user->uid_idx();
my $uid = $user->uid();
# Check for existing export.
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if ($query_result->numrows && !$force) {
fatal("User already exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my $xmlgoo = emutil::ExecQuiet("$DUMPUSER $uid");
if ($?) {
print STDERR "$xmlgoo";
fatal("$DUMPUSER failed");
}
my $args = {"xmlstring" => $xmlgoo,
"urn" => $urn};
my $response = do_method($authority, "AddUser", $args);
fatal("Could not add user to $authority")
if (! (defined($response) &&
($response->code() == GENIRESPONSE_SUCCESS ||
$response->code() == GENIRESPONSE_ALREADYEXISTS)));
DBQueryFatal("replace into user_exports set ".
" uid='$uid', uid_idx='$uid_idx', peer='$peername', ".
" exported=now()");
return 0;
}
#
# Delete a user.
#
sub DeleteUser()
{
usage()
if (! @ARGV);
my $user = User->Lookup($ARGV[0]);
if (!defined($user)) {
fatal("No such user");
}
my $uid = $user->uid();
my $uid_idx = $user->uid_idx();
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if (!$query_result->numrows && !$force) {
fatal("User has not been exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my $args = {"urn" => $urn};
my $response = do_method($authority, "DeleteUser", $args);
fatal("Could not delete user from $authority")
if (! (defined($response) &&
($response->code() == GENIRESPONSE_SUCCESS ||
$response->code() == GENIRESPONSE_SEARCHFAILED)));
DBQueryFatal("delete from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
return 0;
}
#
# Modify a user.
#
sub ModifyUser()
{
usage()
if (! @ARGV);
my $user = User->Lookup($ARGV[0]);
if (!defined($user)) {
fatal("No such user");
}
my $uid = $user->uid();
my $uid_idx = $user->uid_idx();
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if (!$query_result->numrows && !$force) {
fatal("User has not been exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my $xmlgoo = emutil::ExecQuiet("$DUMPUSER $uid");
if ($?) {
fatal("$DUMPUSER failed");
}
my $args = {"xmlstring" => $xmlgoo,
"urn" => $urn};
my $response = do_method($authority, "ModifyUser", $args);
fatal("Could not modify user at $authority")
if (! (defined($response) &&
$response->code() == GENIRESPONSE_SUCCESS));
return 0;
}
#
# Set the groups for a user.
#
sub SetGroups(;$)
{
my ($token) = @_;
if (! defined($token)) {
usage()
if (! @ARGV);
$token = $ARGV[0];
}
my $user = User->Lookup($token);
if (!defined($user)) {
fatal("No such user");
}
my $uid = $user->uid();
my $uid_idx = $user->uid_idx();
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if (!$query_result->numrows && !$force) {
fatal("User has not been exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my @grouplist = ();
if ($user->GroupMembershipList(\@grouplist)) {
fatal("Could not get group list for user");
}
if (! @grouplist) {
print STDERR "$user is not a member of any groups";
return 0;
}
my %grouparray = ();
foreach my $group (@grouplist) {
my $pid_idx = $group->pid_idx();
my $gid_idx = $group->gid_idx();
#
# See if this group has been exported. Skip if not.
#
$query_result =
DBQueryFatal("select pid_idx,gid_idx from group_exports ".
"where pid_idx='$pid_idx' and gid_idx='$gid_idx' and ".
" peer='$peername'");
next
if (!$query_result->numrows);
my $membership = $group->LookupUser($user);
if (!defined($membership)) {
fatal("Could not get membership for $user in $group");
}
my $pid = $group->pid();
my $gid = $group->gid();
my $trust = $membership->trust();
$grouparray{"$pid,$gid"} = $trust;
}
print STDERR Dumper(\%grouparray) if ($debug);
my $args = {"groups" => \%grouparray,
"urn" => $urn};
my $response = do_method($authority, "SetGroups", $args);
fatal("Could not setgroups for user at $authority")
if (! (defined($response) &&
$response->code() == GENIRESPONSE_SUCCESS));
return 0;
}
#
# Cross Login
#
sub CrossLogin()
{
usage()
if (! @ARGV);
my $user = User->Lookup($ARGV[0]);
if (!defined($user)) {
fatal("No such user");
}
my $uid = $user->uid();
my $uid_idx = $user->uid_idx();
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if (!$query_result->numrows && !$force) {
fatal("User has not been exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my $args = {"urn" => $urn};
#
# Since this is coming from the web interface, want to limit
# how long we wait, and return status if timed out.
#
Genixmlrpc->SetTimeout(20);
my $response = do_method($authority, "CrossLogin", $args);
fatal("Could not xlogin user at $authority")
if (! (defined($response) &&
$response->code() == GENIRESPONSE_SUCCESS));
my $key = $response->value();
print "$key\n";
return 0;
}
#
# Add a Project
#
sub AddProject()
{
usage()
if (! @ARGV);
my $project = Project->Lookup($ARGV[0]);
if (!defined($project)) {
fatal("No such project");
}
my $pid = $project->pid();
my $pid_idx = $project->pid_idx();
my $leader_uid = $project->head_uid();
my $leader_idx = $project->head_idx();
my $query_result =
DBQueryFatal("select * from group_exports ".
"where pid_idx='$pid_idx' and gid_idx='$pid_idx' and ".
" peer='$peername'");
if ($query_result->numrows && !$force) {
fatal("Project has already been exported to peer. Use -f option");
}
#
# Check that the leader has been exported, and if not do that first.
#
my $leader_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$leader_idx' and peer='$peername'");
if (!$leader_result->numrows) {
AddUser($leader_idx);
}
my $xmlgoo = emutil::ExecQuiet("$DUMPPROJ $pid");
if ($?) {
fatal("$DUMPPROJ failed");
}
my $args = {"xmlstring" => $xmlgoo};
my $response = do_method($authority, "AddProject", $args);
fatal("Could not add project to $authority")
if (! (defined($response) &&
($response->code() == GENIRESPONSE_SUCCESS ||
$response->code() == GENIRESPONSE_ALREADYEXISTS)));
DBQueryFatal("replace into group_exports set ".
" pid='$pid', pid_idx='$pid_idx', ".
" gid='$pid', gid_idx='$pid_idx', ".
" exported=now(), updated=now(), ".
" peer='$peername'");
SetGroups($leader_idx);
return 0;
}
#
# Add a Group
#
sub AddGroup()
{
usage()
if (! @ARGV);
my $group = Group->Lookup($ARGV[0]);
if (!defined($group)) {
fatal("No such group");
}
if ($group->IsProjectGroup()) {
fatal("Please use addproject instead.");
}
my $pid_idx = $group->pid_idx();
my $gid_idx = $group->gid_idx();
my $pid = $group->pid();
my $gid = $group->gid();
my $query_result =
DBQueryFatal("select * from group_exports ".
"where pid_idx='$pid_idx' and gid_idx='$pid_idx' and ".
" peer='$peername'");
if (!$query_result->numrows) {
fatal("Project has not been exported to peer.\n");
}
$query_result =
DBQueryFatal("select * from group_exports ".
"where pid_idx='$pid_idx' and gid_idx='$gid_idx' and ".
" peer='$peername'");
if ($query_result->numrows && !$force) {
fatal("Group has already been exported to peer. Use -f option");
}
my %tags = (
"project" => $group->pid(),
"group_id" => $group->gid(),
"group_leader" => $group->leader(),
"group_description" => $group->description() || "",
);
my $args = {"tags" => \%tags};
my $response = do_method($authority, "AddGroup", $args);
fatal("Could not add group to $authority")
if (! (defined($response) &&
($response->code() == GENIRESPONSE_SUCCESS ||
$response->code() == GENIRESPONSE_ALREADYEXISTS)));
DBQueryFatal("replace into group_exports set ".
" pid='$pid', pid_idx='$pid_idx', ".
" gid='$gid', gid_idx='$gid_idx', ".
" exported=now(), updated=now(), ".
" peer='$peername'");
return 0;
}
#
# Make an rpc call to the Emulab interface on the remote authority.
#
sub do_method($$;$)
{
my ($authority, $method, $args) = @_;
$args = {} if (!defined($args));
#
# The URL refers to the sa, but we want the emulab interface.
#
my $url = $authority->url();
$url =~ s/\/sa$/\/emulab/;
$args->{'credentials'} = [$credential->asString()];
my $response =
Genixmlrpc::CallMethod($url, undef, $method, $args);
if (!defined($response)) {
print STDERR "*** Internal error at $authority\n";
return undef;
}
if ($response->code() != GENIRESPONSE_SUCCESS) {
print STDERR "Error at $authority:";
print STDERR " " . $response->output() . "\n";
}
return $response;
}
sub fatal($) {
my ($msg) = @_;
print STDERR "$msg\n";
exit(-1);
}
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2000-2024 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use strict;
use English;
use Getopt::Long;
use Getopt::Long qw(:config no_ignore_case);
use POSIX qw(strftime);
use Date::Parse;
#
# Load the Testbed support stuff.
......@@ -22,7 +41,8 @@ use libtestbed;
sub usage()
{
print("Usage: mksyscert [-d] [-o file] [-p password] [-e email] ".
"[-u url] [-i urn] [-k keyfile] [-a authority] <orgunit> [uuid]\n");
"[-u url] [-i urn] [-k keyfile] [-a authority] <orgunit> " .
"[-n] [-U] [uuid]\n");
exit(-1);
}
my $debug = 0;
......@@ -34,6 +54,9 @@ my @urls;
my $urn;
my $oldkeyfile;
my $authority;
my $notca = 0;
my $days = 2000;
my $include_uuid = 0;
my %optlist = ( "debug" => \$debug,
"password=s" => \$password,
"output=s" => \$outfile,
......@@ -42,7 +65,9 @@ my %optlist = ( "debug" => \$debug,
"url=s" => \@urls,
"identifier=s" => \$urn,
"keyfile=s" => \$oldkeyfile,
"authority=s" => \$authority );
"authority=s" => \$authority,
"UUID" => \$include_uuid,
"notca" => \$notca );
#
# Configure variables
......@@ -62,6 +87,7 @@ my $EMULAB_CERT = "$TB/etc/emulab.pem";
my $EMULAB_KEY = "$TB/etc/emulab.key";
my $OPENSSL = "/usr/bin/openssl";
my $WORKDIR = "$TB/ssl";
my $RANDFILE = "./.rnd";
my $SAVEUID = $UID;
my $certfile = $EMULAB_CERT;
my $keyfile = $EMULAB_KEY;
......@@ -158,6 +184,8 @@ if (@ARGV < 1) {
my $orgunit = shift(@ARGV);
my $uuid = (@ARGV ? shift(@ARGV) : undef);
my $is_ca = !$notca;
# Moved before uuid generation. Might be a race, might not.
TBScriptLock("mkusercert") == 0 or
fatal("Could not get the lock!");
......@@ -180,6 +208,22 @@ if (!defined($email)) {
chdir("$WORKDIR") or
fatal("Could not chdir to $WORKDIR: $!");
#
# Some sillyness to deal with changes to .rnd file handling across
# versions of openssl.
#
if (! -e $RANDFILE) {
system("/bin/dd if=/dev/urandom of=${RANDFILE} bs=256 count=4");
if ($?) {
fatal("Could not generate $RANDFILE");
}
}
#
# Older versions of openssl ignore -rand option, but use this environment
# variable. New versions ignore the environment variable but use -rand.
#
$ENV{"RANDFILE"} = $RANDFILE;
#
# Need an index file, which is the openssl version of the DB.
#
......@@ -212,13 +256,21 @@ system("cp -f $TEMPLATE syscert.cnf") == 0
open(TEMP, ">>syscert.cnf")
or fatal("Could not open $TEMPLATE for append: $!");
if (defined($urn)) {
print TEMP "subjectAltName=\@req_altname\n";
}
print TEMP "basicConstraints=critical,CA:" .
( $is_ca ? "TRUE" : "FALSE" ) . "\n\n";
if (@urls) {
my $count = 0;
foreach( @urls ) {
# unregistered OID 2.25.305821105408246119474742976030998643995
# (corresponding to UUID e61300a0-c4c5-11de-b14e-0002a5d5c51b)
# is used to indicate generic ProtoGENI XMLRPC servers.
print TEMP "authorityInfoAccess=2.25.305821105408246119474742976030998643995;URI:$_\n";
# print TEMP "authorityInfoAccess=2.25.305821105408246119474742976030998643995;URI:$_\n";
print TEMP
"authorityInfoAccess=2.25.305821105.408246119.47474297.603099864.3995;URI:$_\n";
}
}
......@@ -232,10 +284,15 @@ print TEMP "OU\t\t= \"$orgunit\"\n";
print TEMP "CN\t\t= $uuid\n";
print TEMP "emailAddress\t= $email\n";
print TEMP "\n";
print TEMP "[ req_altname ]\n";
print TEMP "URI=$urn\n" if defined( $urn );
print TEMP "\n";
if (defined($urn)) {
print TEMP "\n";
print TEMP "[ req_altname ]\n";
print TEMP "URI.1=$urn\n";
if( $include_uuid ) {
print TEMP "URI.2=urn:uuid:$uuid\n";
}
print TEMP "\n";
}
close(TEMP)
or fatal("Could not close syscert.cnf: $!");
......@@ -251,22 +308,77 @@ if( defined( $oldkeyfile ) ) {
($encrypted ? " -passout 'pass:${sh_password}' " : " -nodes ") .
" -out syscert_req.pem $outline") == 0
or fatal("Could not create certificate request");
system("cp $oldkeyfile syscert_key.pem");
system("$OPENSSL rsa -in $oldkeyfile -out syscert_key.pem $outline") == 0
or fatal("Could not suck key out of old keyfile");
} else {
#
# Create a client side private key and certificate request.
#
system("$OPENSSL req -text -new -config syscert.cnf ".
($encrypted ? " -passout 'pass:${sh_password}' " : " -nodes ") .
" -keyout syscert_key.pem -out syscert_req.pem $outline") == 0
or fatal("Could not create certificate request");
my $genopts = " -rand $RANDFILE " .
($encrypted ? " -passout 'pass:${sh_password}' -des3 " : "");
my $output =
emutil::ExecQuiet("$OPENSSL genrsa $genopts -out syscert_key.pem 2048");
if ($?) {
print STDERR $output;
fatal("Could generate new key");
}
$output =
emutil::ExecQuiet("$OPENSSL req -text -new -config syscert.cnf ".
($encrypted ? " -passin 'pass:${sh_password}' " : "") .
" -key syscert_key.pem -out syscert_req.pem $outline");
if ($?) {
print STDERR $output;
fatal("Could not create certificate request");
}
}
#
# Sign the client cert request, creating a client certificate.
# We set the start date an hour in the past, to avoid clock skew
# problems.
#
my $startdate = POSIX::strftime("%y%m%d%H%M%SZ", gmtime(time() - 3600));
#
# Check the expiration on the CA cert, we do not want the new
# certificate to expire after the CA (signer) cert expires.
#
$UID = 0;
system("$OPENSSL ca -batch -policy policy_sslxmlrpc ".
my $expires = `$OPENSSL x509 -enddate -noout -in $certfile`;
if ($?) {
fatal("Could not get expiration from $certfile");
}
if ($expires =~ /^notAfter=(.*)$/i) {
my $tmp = str2time($1);
if (!defined($tmp)) {
fatal("Could not convert $certfile expiration to time: $1");
}
$expires = $tmp;
}
else {
fatal("Could not parse $certfile expiration: $expires");
}
if ($expires < time()) {
fatal("$certfile certificate has expired!");
}
# If the CA expires in less then 30 days, grind to a halt.
my $daystoexpire = int(($expires - time()) / (3600 * 24));
if ($daystoexpire <= 30) {
fatal("Refusing to sign new certificate; the $certfile expires in less ".
"then 30 days!");
}
if ($debug) {
print "CA certificate expires in $daystoexpire days.\n";
}
if ($days > $daystoexpire) {
$days = $daystoexpire - 1;
print "Shortening certificate expiration to $days days\n";
}
system("$OPENSSL ca -batch -policy policy_sslxmlrpc -startdate $startdate ".
" -days $days ".
" -name CA_syscerts -config $CACONFIG ".
" -out syscert_cert.pem -cert $certfile -keyfile $keyfile ".
" -infiles syscert_req.pem $outline") == 0
......
This diff is collapsed.