This file is indexed.

/usr/sbin/condor_aklog is in htcondor 8.6.8~dfsg.1-2.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/bin/bash

##**************************************************************
##
## Copyright (C) 1990-2016, Condor Team, Computer Sciences Department,
## University of Wisconsin-Madison, WI.
##
## Licensed under the Apache License, Version 2.0 (the "License"); you
## may not use this file except in compliance with the License.  You may
## obtain a copy of the License at
##
##    http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
##**************************************************************

## Author: Todd Tannenbaum <tannenba@cs.wisc.edu>, December 1, 2016.

# condor_aklog is a wrapper script for aklog on Linux.
#
# How to use:
# 1. Set environment variable KRB5CCNAME to point to the FILE-based
#    Kerberos 5 credential cache that will be used to create the
#    AFS token (same as with aklog).
# 2. Optionally, set environment variable CONDOR_KRB5_UID to the uid
#    which should have access to the AFS token to be created by aklog.
#    If unset, condor_aklog attempt to lookup the Kerberos credential cache
#    default principal in the passwd database (as defined by nsswitch.conf).
# 3. Run condor_aklog with the same real-uid that was used to launch the
#    condor_master daemon (typically root), using the same command-line
#    arguments (if any) as were desired with aklog.
#
# Options:
# Same as aklog.
#
# Exit status:
# 50 if there is an error setting up the keyrings, else whatever exit
# status is returned by aklog (zero on success, non-zero on failure).
#
# Description:
# condor_aklog is a Linux-specifc wrapper script for aklog that will
# store the AFS token into a kernel session keyring named "htcondor_uidX",
# where X is the UID of the user being impersonated, by
# 1. securely creating or joining session htcondor_uidX, 
# 2. creating a PAG # in the session via pagsh if and only if a PAG does 
#    not already exist, then
# 3. run aklog, and finally
# 4. link this session keyring to the user-specific keyring for the
#    user that invoked condor_aklog so it is not garbage-collected.
#
# More information:
# https://htcondor-wiki.cs.wisc.edu/index.cgi/tktview?tn=6032

##**************************************************************

# Helper function: Exit with status $1 and send $2 to stderr.
exitwitherr() { 
  printf "%s. Aborting.\n" "$2" >&2
  exit "$1"
}

# Helper function: Check that each parameter can be found in the PATH.
checkexist() {
  for prog in "$@"; do
    hash $prog 2>/dev/null || exitwitherr 50 "Failed to find $prog installed in path"
  done
}

# Our script is divded into two parts; Part 1 is invokved by the
# user running "condor_aklog".  At the end of Part 1, condor_aklog
# invokes itself a second time with "condor_aklog -htcpart2 ..." which
# results in Part 2 of the script being executed as a child process.
# This is neccesary because the "keyctl session" command
# starts a new subshell process.
# Part 2 does more setup and then invokes aklog, writing the exit
# status of aklog into stdout where it is read by Part 1 and returned
# to the user.

#
# PART 1
# This is the entry-point of the script.
#

if [ "$1" != "-htcpart2" ]; then

  # Make sure some required utilities are installed in our PATH.

  checkexist klist keyctl aklog awk cut

  # Validate we have a Kerberos credential cache.

  klist -s || exitwitherr 50 "Failed to find a valid KRB5 credential cache"

  # Set up reasonable defaults for CONDOR_RINGID and CONDOR_KRB5_UID.
  # If CONDOR_KRB5_UID is unset, try to figure out the uid associated with the
  # AFS token we are about to stash by looking for the Kerberos cache
  # default principal in the passwd database.

  export master_ring=${CONDOR_RINGID:-"@u"}
  if [ -n "$CONDOR_KRB5_UID" ]; then
    id="$CONDOR_KRB5_UID"
  else
    checkexist grep xargs getent
    id="${CONDOR_KRB5_UID:-`klist | grep "Default principal" | cut -d' ' -f3 | cut -d@ -f1 | cut -d/ -f1 | xargs getent passwd`}" \
      || exitwitherr 50 "Failed to find uid for default principal"
    id=`echo "$id" | cut -d: -f3`
  fi 

  # Invoke "keyctl session htcondor_uidX", and run Part 2 of this
  # script (see below) in that new session. Echo any output back
  # to the terminal except for the "Joined session key..." crud that
  # keyctl pollutes into stdout (we want our output to mimic aklog). Also
  # Part2 of our script below will echo the exit status of the real aklog
  # to our stream; read that exit status and exit with the same value
  # so condor_aklog returns whatever aklog returned.  We need to do this
  # because "keyctrl session" fails to propagate exit codes.

  export uid_ring_name="htcondor_uid$id"
  keyctl session "$uid_ring_name" "$0" "-htcpart2" "$@" |& awk \
  '/^Joined session key/ { next }
   /^aklog_real_exit_code/ { exit $2 }
   { print $0 }
  ' -

  # Exit with whatever awk exits with in the command above, which
  # is the same as whatever aklog exited with in Part 2 below.

  exit $?

#
# End of PART 1
#

else 

#
# PART 2
# This part of the script runs in after Part 1 has completed
# and the htcondor_uidX keyring has been setup as the active
# session keyring.
#

  # Throw away argument "-htcpart2" so we don't pass it to aklog.

  shift

  # Make sure we have some required utilities, aware that the PATH
  # may have changed since PART 1 ran (although this is not likely).

  checkexist keyctl aklog cut flock

  # Make certain our real-uid matches the uid of the htcondor_uidX
  # session keyring we joined at the end of PART 1.  We do this as
  # a security safeguard because, unfortunately, "keyctl session <name>"
  # will simply join the first visible keyring found with that description,
  # and there is no way to join a keyring by id.  Sigh, the Linux kernel
  # really should have a call to join a keyring by id, but it does not.
  # The concern is a malicious non-privledged user could create a keyring
  # named "htcondor_uidX" and set the Search permission control mask
  # such that condor_aklog running "keyctl session htcondor_uidX" as root
  # joins it (and then connects an AFS PAG to this keyring).  To prevent
  # this, validate the uid owner of the session keyring is the same as
  # our real-uid and bail-out now if funny business is detected.

  session_uid=`keyctl rdescribe @s | cut -d\; -f2`
  if [ "$session_uid" != $UID ]; then
    exitwitherr 50 "Uid of keyring $uid_ring_name is $session_uid, but ruid is $UID"
  fi

  # Link our session keyring to the user-specific keyring that invoked
  # condor_aklog (typically, the user keyring for uid 0) so that
  # this session keyring is not immediately garbage-collected by the kernel
  # when condor_aklog exits.

  keyctl link @s "$master_ring" \
    || exitwitherr 50 "Failed to link keyring $uid_ring_name to master ring $master_ring"

  # Create a PAG in the session via pagsh if and only if a PAG does not
  # already exist, and upon creating a it, link it to our
  # current session keyring. If a PAG is not already found, we need
  # to use a lock file to ensure there is only one PAG attached to this
  # session keyring even in the event of multiple instances of condor_aklog
  # running simultaneously.  If we need to lock, we use a read-only file
  # descriptor to the KRB5 credential cache file since only trusted
  # processes (root or the user that owns the cache) should be able to
  # read that file.  This way we avoid creating lock files in /tmp with
  # well-known names and expose root to symlink attacks (some Linux
  # distros still have world-write permission on /var/lock... I am looking
  # at you, Debian 7!).

  export uid_ring_id=`keyctl search @s keyring "$uid_ring_name"`
  lockfile="/${KRB5CCNAME#*/}"
  if [ "$KRB5CCNAME" != "$lockfile" -a "${KRB5CCNAME%%:*}" != "FILE" ]; then
    exitwitherr 50 "Only KRB5 caches of type FILE are supported"
  fi
  keyctl search @s afs_pag _pag >&/dev/null || \
    { 
	  # Wait for an exclusive lock, 20 second timeout
	  flock -x -w 20 200 \
	    || exitwitherr 50 "Failed to obtain file lock on $lockfile"
	  # Make certain session keyring has uid write access so we can link
	  # the PAG session below.
	  keyctl setperm @s 0x1f3f0000 \
		  || exitwitherr 50 "Failed to setperm on session keyring"
	  # We must test again for the pag once we have the lock, in
	  # order to guarantee an atomic test-and-set operation. If a search
	  # for an afs_pag fails, create it via pagsh and link to our session.
	  keyctl search @s afs_pag _pag >&/dev/null || \
	    pagsh -c "keyctl link @s $uid_ring_id" || \
		  exitwitherr 50 "Failed to link PAG to htcondor_uid session"
    } 200<$lockfile || exitwitherr 50 "KRB5CCNAME file does not exist"

  # Finally, run aklog with whatever command-line args the user gave us.
  # Write the exit code returned by aklog onto stdout, which is read
  # by our parent process (at the tail end of PART 1 above).

  aklog "$@"
  echo aklog_real_exit_code $?

#
# End PART2
#

fi

# End of condor_aklog