diff --git a/include/config.h b/include/config.h index ac3b6c15e..5509d5356 100644 --- a/include/config.h +++ b/include/config.h @@ -150,10 +150,11 @@ * If SYSCF is defined, the following configuration info is * available in a global config space, with the compiled-in * entries as defaults: - * WIZARD ( a value of * allows anyone to be wizard) + * WIZARDS ( a value of * allows anyone to be wizard) * MAXPLAYERS (see MAX_NR_OF_PLAYERS above and nethack.sh) * SUPPORT (how to get local support)(no default) * RECOVER (how to recover a game at your site)(no default) + * SHELLERS (who can use !, syntax as WIZARDS) * * The following options select how the config space is stored: * SYSCF_FILE in the named file diff --git a/include/extern.h b/include/extern.h index 9ace6362b..96d78078a 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2322,6 +2322,7 @@ E void NDECL(port_help); # endif E void FDECL(sethanguphandler, (void (*)(int))); E boolean NDECL(authorize_wizard_mode); +E boolean FDECL(check_user_string, (char *)); #endif /* UNIX */ /* ### unixtty.c ### */ diff --git a/include/sys.h b/include/sys.h index 7ec3db55b..587fb01bb 100644 --- a/include/sys.h +++ b/include/sys.h @@ -13,6 +13,7 @@ struct sysopt { char *support; /* local support contact */ char *recover; /* how to run recover - may be overridden by win port */ char *wizards; + char *shellers; /* like wizards, for ! command (-DSHELL) */ int maxplayers; }; E struct sysopt sysopt; diff --git a/include/unixconf.h b/include/unixconf.h index 79c14fa87..d322e4aab 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -279,7 +279,9 @@ #endif #define tgetch getchar -#define SHELL /* do not delete the '!' command */ +#ifndef NOSHELL +# define SHELL /* do not delete the '!' command */ +#endif #include "system.h" diff --git a/src/files.c b/src/files.c index cb10c0d40..75495c3f8 100644 --- a/src/files.c +++ b/src/files.c @@ -2066,10 +2066,14 @@ int src; } else if (match_varname(buf, "CATNAME", 3)) { (void) strncpy(catname, bufp, PL_PSIZ-1); #ifdef SYSCF - } else if ( (src==SET_IN_SYS) && match_varname(buf, "WIZARDS", 6)) { + } else if ( (src==SET_IN_SYS) && match_varname(buf, "WIZARDS", 7)) { if(sysopt.wizards) free(sysopt.wizards); sysopt.wizards = alloc(strlen(bufp)); (void) strcpy(sysopt.wizards, bufp); + } else if ( (src==SET_IN_SYS) && match_varname(buf, "SHELLERS", 8)) { + if(sysopt.shellers) free(sysopt.shellers); + sysopt.shellers = alloc(strlen(bufp)); + (void) strcpy(sysopt.shellers, bufp); } else if ( (src==SET_IN_SYS) && match_varname(buf, "SUPPORT", 7)) { if(sysopt.support) free(sysopt.support); sysopt.support = alloc(strlen(bufp)); diff --git a/src/sys.c b/src/sys.c index 895c73438..2575d6624 100644 --- a/src/sys.c +++ b/src/sys.c @@ -14,6 +14,7 @@ sys_early_init(){ /* replace use of WIZARD vs WIZARD_NAME vs KR1ED, by filling this in */ #endif sysopt.wizards = NULL; + sysopt.shellers = NULL; sysopt.maxplayers = 0; /* XXX eventually replace MAX_NR_OF_PLAYERS */ } diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index 742380035..3cf757323 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -38,7 +38,7 @@ DIRPERM = 0755 # instructions) #HACKDIR = $(PREFIX)/games/lib/$(GAME)dir VARDIR = $(HACKDIR) -SHELLDIR = $(PREFIX)/games +#SHELLDIR = $(PREFIX)/games # per discussion in Install.X11 and Install.Qt #VARDATND = @@ -245,7 +245,7 @@ install: rootcheck $(GAME) recover $(VARDAT) dungeon spec_levs -mkdir -p $(SHELLDIR) -rm -rf $(HACKDIR) $(VARDIR) -mkdir -p $(HACKDIR) $(VARDIR) $(VARDIR)/save - -rmdir ./-p + if test -d ./-p; then rmdir ./-p; fi -$(CHOWN) $(GAMEUID) $(HACKDIR) $(VARDIR) $(VARDIR)/save $(CHGRP) $(GAMEGRP) $(HACKDIR) $(VARDIR) $(VARDIR)/save # order counts here: diff --git a/sys/unix/hints/linux b/sys/unix/hints/linux index 46971c6e6..099c3d662 100644 --- a/sys/unix/hints/linux +++ b/sys/unix/hints/linux @@ -9,6 +9,7 @@ HACKDIR=$(PREFIX)/games/lib/$(GAME)dir +SHELLDIR = $(PREFIX)/games #PREFIX=/usr PREFIX=$(wildcard ~)/nh/install diff --git a/sys/unix/hints/linux-x11 b/sys/unix/hints/linux-x11 index 84adc1cf2..baa316e68 100644 --- a/sys/unix/hints/linux-x11 +++ b/sys/unix/hints/linux-x11 @@ -9,6 +9,7 @@ HACKDIR=$(PREFIX)/games/lib/$(GAME)dir +SHELLDIR = $(PREFIX)/games #PREFIX=/usr PREFIX=$(wildcard ~)/nh/install diff --git a/sys/unix/hints/macosx.sh b/sys/unix/hints/macosx.sh index a40f9d99e..4eb9e20a9 100755 --- a/sys/unix/hints/macosx.sh +++ b/sys/unix/hints/macosx.sh @@ -1,22 +1,28 @@ #!/bin/sh -# SCCS Id: @(#)macosx-mu.sh 3.5 2007/12/12 +# SCCS Id: @(#)macosx.sh 3.5 2007/12/12 # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # # hints helper script for macosx -# DO NOT invoke directly +# DO NOT invoke directly. + +# Works for 10.4 and 10.5. (The 10.5 support might work for 10.4 but keep +# both versions in case we need to support earlier versions.) cmd=$1 +echo "macosx: $*" + case "x$cmd" in xuser) + # fail unless user exists (good through 10.4) user=$2 gotuser=`niutil -readval . /users/$user name 0 2>/dev/null` [ -z $gotuser ] && (echo "User $user does not exist." exit 1; ) - exit 0 ;; + #name: dummy1 #_writers_passwd: dummy1 #_writers_tim_password: dummy1 @@ -35,14 +41,16 @@ xuser) #authentication_authority: ;ShadowHash; #realname: dummyname1 #generateduid: F6D4991C-BDF5-481F-A407-D84C6A2D0E2A + xgroup) + # fail unless group exists (good through 10.4) group=$2 gotgrp=`niutil -readval . /groups/$group name 0 2>/dev/null` [ -z $gotgrp ] && ( echo "Group $group does not exist." exit 1 ) - exit 0 ;; + #niutil -read . /groups/bin name 0 #name: bin #gid: 7 @@ -51,7 +59,92 @@ xgroup) #smb_sid: S-1-5-21-107 #realname: Binary +xuser2) + # fail unless user exists (required as of 10.5) + user=$2 + if( dscl localhost -read /Search/Users/$user 1>/dev/null 2>&1 ); + then + true; + else + echo "User $user does not exist."; + exit 1; + fi + ;; + +xgroup2) + # if group does not exist, create it (required as of 10.5) + group=$2 + [ -z $group ] && ( echo "No group specified." + exit 1 + ) + if( dscl localhost -read /Search/Groups/$group 1>/dev/null 2>&1 ); + then + true; + else + echo "Group $group does not exist - creating."; + dseditgroup -o create -r "Games Group" -s 3600 $group + if( dscl localhost -read /Search/Groups/$group 1>/dev/null 2>&1 ); + then + true; + else + echo "Unable to create group $group." + exit 1 + fi + fi + ;; + +#% dscl localhost -read /Search/Groups/wheel +# AppleMetaNodeLocation: /Local/Default +# GeneratedUID: ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000000 +# GroupMembership: root +# Password: * +# PrimaryGroupID: 0 +# RealName: +# System Group +# RecordName: wheel +# RecordType: dsRecTypeStandard:Groups +# SMBSID: S-1-5-21-100 + *) echo "Unknown command $cmd" exit 1 ;; esac + +# dscl localhost -read /Search/Users/games +# dsAttrTypeNative:_writers_hint: games +# dsAttrTypeNative:_writers_jpegphoto: games +# dsAttrTypeNative:_writers_LinkedIdentity: games +# dsAttrTypeNative:_writers_passwd: games +# dsAttrTypeNative:_writers_picture: games +# dsAttrTypeNative:_writers_realname: games +# dsAttrTypeNative:_writers_UserCertificate: games +# AppleMetaNodeLocation: /Local/Default +# AuthenticationAuthority: ;ShadowHash; ;Kerberosv5;;games@LKDC:SHA1.3F695B215C78511043D9787CA51DE92E6494A021;LKDC:SHA1.3F695B215C78511043D9787CA51DE92E6494A021; +# AuthenticationHint: games +# GeneratedUID: A727EFB1-D6AA-4FE2-8524-0E154890E9A9 +# NFSHomeDirectory: /Users/games +# Password: ******** +# Picture: +# /Library/User Pictures/Flowers/Sunflower.tif +# PrimaryGroupID: 20 +# RealName: games +# RecordName: games +# RecordType: dsRecTypeStandard:Users +# UniqueID: 505 +# UserShell: /bin/bash + +# see also: http://developer.apple.com/documentation/Porting/Conceptual/PortingUnix/additionalfeatures/chapter_10_section_9.html + +# another mess: 10.4 creates a group for every user, 10.5 dumps you into staff. +# so I think we need to explicitly create group games in both (if it doesn't +# exist) and use owner bin (nope that fails since everything seems to be owned +# by root. Do we want that? How about just creating user games as well?) + +# [Hermes:sys/unix/hints] keni% dscl localhost -read /Search/Users/games9 +# DS Error: -14136 (eDSRecordNotFound) +# [Hermes:sys/unix/hints] keni% dscl localhost -read /Search/Users/games9 >/dev/null +# DS Error: -14136 (eDSRecordNotFound) +# [Hermes:sys/unix/hints] keni% dscl localhost -read /Search/Users/games > /dev/null +# status is good: 0 or 56 + +# file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/releasenotes/MacOSXServer/RN-DirectoryServices/index.html diff --git a/sys/unix/hints/macosx10.5 b/sys/unix/hints/macosx10.5 new file mode 100644 index 000000000..9a864b6e0 --- /dev/null +++ b/sys/unix/hints/macosx10.5 @@ -0,0 +1,152 @@ +# +# SCCS Id: @(#)macosx 3.5 2007/12/12 +# Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. +# NetHack may be freely redistributed. See license for details. +# +# Mac OS X (Darwin) hints file +# This is for Mac OS X 10.5.3 (Darwin 9.3). If this doesn't work for some +# other version of either Darwin or Mac OS X, make a new file for that OS, +# don't change this one. And let us know about it. +# Useful info: http://www.opensource.apple.com/darwinsource/index.html + +# This hints file can build several different types of installations. +# Edit the next section to match the type of build you need. + +# 1. Which window system(s) should be included in this binary? +WANT_WIN_TTY=1 +#WANT_WIN_X11=1 +#WANT_WIN_QT=1 + +# 1a. What is the default window system? +WANT_DEFAULT=tty +#WANT_DEFAULT=x11 +#WANT_DEFAULT=qt + +# 1b. If you set WANT_WIN_QT, you need to +# A) set QTDIR either here or in the environment to point to the Qt2 or Qt3 +# library installation root. (Qt4 will not work; Qt3 does not presently +# compile under Leopard (MacOSX 10.5) out-of-the-box.) +# B) set XPMLIB to point to the Xpm library +ifdef WANT_WIN_QT +QTDIR=/Developer/Qt +LIBXPM= -L/Developer/SDKs/MacOSX10.3.9.sdk/usr/X11R6/lib -lXpm +endif + +# 2. Is this a build for a binary that will be shared among different users +# or will it be private to you? +# If it is shared: +# - it will be owned by the user and group listed +# - if the user does not exist, you MUST create it before installing +# NetHack +# - if the group does not exist, it will be created. +# NB: if the group already exists and is being used for something +# besides games, you probably want to specify a new group instead +# NB: the group will be created locally; if your computer is centrally +# administered this may not be what you (or your admin) want. +# Consider a non-shared install (WANT_SHARE_INSTALL=0) instead. +# - 'make install' must be run as "sudo make install" +WANT_SHARE_INSTALL=1 +GAMEUID = root +GAMEGRP = games + +#CC=gcc -W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN +CC=gcc -Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi + +# +# You shouldn't need to change anything below here. +# + +# XXX -g vs -O should go here, -I../include goes in the makefile +CFLAGS=-g -I../include +CFLAGS+=-DNOCLIPPING -DNOMAIL -DNOTPARMDECL -DHACKDIR=\"$(HACKDIR)\" +CFLAGS+= -DDEFAULT_WINDOW_SYS=\"$(WANT_DEFAULT)\" + +ifdef WANT_WIN_TTY +WINSRC = $(WINTTYSRC) +WINOBJ = $(WINTTYOBJ) +WINLIB = $(WINTTYLIB) +WINTTYLIB=-lncurses +else +CFLAGS += -DNOTTYGRAPHICS +endif + +ifdef WANT_WIN_X11 +WINSRC += $(WINX11SRC) +WINOBJ += $(WINX11OBJ) +WINLIB += $(WINX11LIB) +LFLAGS=-L/usr/X11R6/lib +VARDATND = x11tiles NetHack.ad pet_mark.xbm +POSTINSTALL= bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; (cd $(HACKDIR); mkfontdir) +CFLAGS += -DX11_GRAPHICS +endif + +ifdef WANT_WIN_QT +CFLAGS += -DQT_GRAPHICS -DNOUSER_SOUNDS +CFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 +LINK=g++ +WINSRC += $(WINQTSRC) +WINLIB += $(WINQTLIB) $(LIBXPM) +WINLIB += -framework Carbon -framework QuickTime -lz -framework OpenGL +WINLIB += -framework AGL +ifdef WANT_WIN_X11 + # prevent duplicate tile.o in WINOBJ +WINOBJ = $(sort $(WINQTOBJ) $(WINX11OBJ)) +ifdef WANT_WIN_TTY +WINOBJ += $(WINTTYOBJ) +endif +else +WINOBJ += $(WINQTOBJ) +endif +# XXX if /Developer/qt exists and QTDIR not set, use that +ifndef QTDIR +$(error QTDIR not defined in the environment or Makefile) +endif +# XXX make sure QTDIR points to something reasonable +else +LINK=$(CC) +endif + +ifdef WANT_SHARE_INSTALL +# if $GAMEUID is root, we install into roughly proper Mac locations, otherwise +# we install into ~/nethackdir +ifeq ($(GAMEUID),root) +PREFIX:=/Library/NetHack +SHELLDIR=/usr/local/bin +HACKDIR=$(PREFIX)/nethackdir +else +PREFIX:=/Users/$(GAMEUID) +SHELLDIR=$(PREFIX)/bin +HACKDIR=$(PREFIX)/nethackdir +endif +CHOWN=chown +CHGRP=chgrp +# We run sgid so the game has access to both HACKDIR and user preferences. +GAMEPERM = 02755 +VARFILEPERM = 0664 +VARDIRPERM = 0775 +ROOTCHECK= [[ `id -u` == 0 ]] || ( echo "Must run install with sudo."; exit 1) +# make sure we have group GAMEUID and group GAMEGRP +PREINSTALL= . sys/unix/hints/macosx.sh user2 $(GAMEUID); . sys/unix/hints/macosx.sh group2 $(GAMEGRP); mkdir $(SHELLDIR); chown $(GAMEUID) $(SHELLDIR) +POSTINSTALL= touch $(HACKDIR)/sysconf; $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; chmod $(VARFILEPERM) $(HACKDIR)/sysconf +CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE +else +PREFIX:=$(wildcard ~) +SHELLDIR=$(PREFIX)/bin +HACKDIR=$(PREFIX)/nethackdir +CHOWN=true +CHGRP=true +GAMEPERM = 0700 +VARFILEPERM = 0600 +VARDIRPERM = 0700 +ifdef WANT_WIN_X11 +# XXX install nethack.rc as ~/.nethackrc if no ~/.nethackrc exists +endif +endif + + +# ~/Library/Preferences/NetHack Defaults +# OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp +# OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt +# +# Install.Qt mentions a patch for macos - it's not there (it seems to be in the Qt binary +# package under the docs directory). diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 773cda08f..308c1c35b 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -42,6 +42,7 @@ extern void NDECL(init_linux_cons); static void NDECL(wd_message); static boolean wiz_error_flag = FALSE; +static struct passwd *NDECL(get_unix_pw); int main(argc,argv) @@ -530,40 +531,10 @@ boolean authorize_wizard_mode() { #ifdef WIZARD - char *user; - int uid; - struct passwd *pw = (struct passwd *)0; - - uid = getuid(); - user = getlogin(); - if (user) { - pw = getpwnam(user); - if (pw && (pw->pw_uid != uid)) pw = 0; - } - if (pw == 0) { - user = nh_getenv("USER"); - if (user) { - pw = getpwnam(user); - if (pw && (pw->pw_uid != uid)) pw = 0; - } - if (pw == 0) { - pw = getpwuid(uid); - } - } + struct passwd *pw = get_unix_pw(); #ifdef SYSCF if (pw && sysopt.wizards[0]) { - if(sysopt.wizards[0] == '*') return TRUE; /*allow any user to be wizard*/ - int pwlen = strlen(pw->pw_name); - char *eop = eos(sysopt.wizards); - char *w = sysopt.wizards; - while( w+pwlen <= eop ){ - if( ! *w ) break; - if( isspace(*w) ){ w++; continue;} - if( !strncmp(w, pw->pw_name, pwlen) ){ - if( !w[pwlen] || isspace(w[pwlen]) ) return TRUE; - } - while( *w && !isspace(*w) ) w++; - } + if(check_user_string(sysopt.wizards)) return TRUE; } else #endif if (pw && !strcmp(pw->pw_name, WIZARD_NAME)) return TRUE; @@ -607,4 +578,50 @@ char *name; return; } +boolean +check_user_string(optstr) +char *optstr; +{ + struct passwd *pw = get_unix_pw(); + if(optstr[0] == '*') return TRUE; /* allow any user */ + if(!pw) return FALSE; + int pwlen = strlen(pw->pw_name); + char *eop = eos(optstr); + char *w = optstr; + while( w+pwlen <= eop ){ + if( ! *w ) break; + if( isspace(*w) ){ w++; continue;} + if( !strncmp(w, pw->pw_name, pwlen) ){ + if( !w[pwlen] || isspace(w[pwlen]) ) return TRUE; + } + while( *w && !isspace(*w) ) w++; + } + return FALSE; +} + +static struct passwd * +get_unix_pw(){ + char *user; + int uid; + static struct passwd *pw = (struct passwd *)0; + if(pw) return pw; /* cache answer */ + + uid = getuid(); + user = getlogin(); + if (user) { + pw = getpwnam(user); + if (pw && (pw->pw_uid != uid)) pw = 0; + } + if (pw == 0) { + user = nh_getenv("USER"); + if (user) { + pw = getpwnam(user); + if (pw && (pw->pw_uid != uid)) pw = 0; + } + if (pw == 0) { + pw = getpwuid(uid); + } + } + return pw; +} /*unixmain.c*/ diff --git a/sys/unix/unixunix.c b/sys/unix/unixunix.c index e333e4ae1..d47ebe7c7 100644 --- a/sys/unix/unixunix.c +++ b/sys/unix/unixunix.c @@ -244,6 +244,15 @@ int dosh() { register char *str; +# ifdef SYSCF + if( !sysopt.shellers + || !sysopt.shellers[0] + || !check_user_string(sysopt.shellers) + ){ + Norep("Unknown command '!'."); + return 0; + } +# endif if(child(0)) { if((str = getenv("SHELL")) != (char*)0) (void) execl(str, str, (char *)0);