Avoiding problems with gpg-agent when running from scripts - gpg2 - bash

I'm trying to use gpg to --clearsign a file (for debian packaging purposes) from a script.
I have an exported password-less private-key.gpg file and want to:
gpg --clearsign -o output input
I don't want to mess with the current user's ~/.gnupg or /run/user/$(id -u)/gnupg because they have nothing to do with my script. Also, the script could be running in multiple instances simultaneously and I don't want them interfering with one another.
I thought that would be easy. Setup $GNUPGHOME to a temp dir and be done with it. But I cannot figure out how to get gpg to run in a script without messing with the user's standard configuration at all. It seems gpg has gone to great lengths to make it impossible to avoid the gpg-agent and gpg-agent insists on using global/hard-coded paths.
Can I keep everything under $GNUPGHOME? Or how do I safely use gpg from a shell script without influencing the user's config or use of gpg or other instances of my script?
Details
Reading the gpg docs I see that:
--use-agent
--no-use-agent
This is dummy option. gpg always requires the agent.
And gpg-agent docs say:
--use-standard-socket
--no-use-standard-socket
--use-standard-socket-p
Since GnuPG 2.1 the standard socket is always used.
These options have no more effect. The command gpg-agent
--use-standard-socket-p will thus always return success.
This "standard socket" is presumably in /run/user/$(id -u)/gnupg - so it seems I can't avoid gpg messing with the user's "normal" use of gpg.
Versions: gpg 2.1.18 on Debian 9 / stretch / stable

If you can't stop gpg from creating files, would it help to give gpg a place to put them that's unique to the current process?
# Create a temporary directory for gpg.
dir="$(mktemp -d)"
# Remove the directory and its contents when the script exits.
trap '[[ ! -d "${dir}" ]] || rm -r "${dir}"' EXIT
# Put your private-key.gpg in the temporary directory.
$(your command here)
# Tell gpg to use the temporary directory.
gpg --homedir "${dir}" --clearsign -o output input

After multiple hours of searching the internet for some option to enable running multiple instances of gpg-agent with different gnupg homes I tried just restricting the access to the global socket location and it worked. It fell back to placing the socket files in the gnupg home directory. I used bwrap to do that. Here's the full command that worked: bwrap --dev-bind / / --tmpfs /run/user/$(id -u)/gnupg gpg-agent .... Since your question is about scripts in general, you probably can't rely on bwrap being installed, so the next best thing is a shim that prevents gpg-agent from using the user's xdg runtime directory for its sockets.
After looking through the output of strace, the switch of location when running under bwrap to gnupg home seems to happen after a stat on /run/user/${UID}/gnupg is issued. Looking through the gpg-agent.c code this seems to do that check:
/* Check that it is a directory, owned by the user, and only the
* user has permissions to use it. */
if (!S_ISDIR(sb.st_mode)
|| sb.st_uid != getuid ()
|| (sb.st_mode & (S_IRWXG|S_IRWXO)))
{
*r_info |= 4; /* Bad permissions or not a directory. */
if (!skip_checks)
goto leave;
}
Using this we can just tell gpg-agent that the /run/user/${UID}/gnupg exists, but is not a directory, so it will fail the first of these checks.
Here's the code for a shim that does just that (could be better, but it works):
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
#include <stdio.h>
#define STR_MAX 4096
#define MIN(a, b) (a < b ? a : b)
#define MAX(a, b) (a > b ? a : b)
// Set up checking stuff
#define MAX_UID_LEN 11
#define PREFIX_1 "/run/user"
#define PREFIX_2 "/var/run/user"
#define TEST_LEN_1 (sizeof(PREFIX_1) - 1 + 1 + MAX_UID_LEN + sizeof("/gnupg") - 1)
#define TEST_LEN_2 (sizeof(PREFIX_2) - 1 + 1 + MAX_UID_LEN + sizeof("/gnupg") - 1)
#define MAX_TEST_LEN MAX(TEST_LEN_1, TEST_LEN_2)
// Override stat function
int stat(const char *restrict pathname, struct stat *restrict statbuf) {
int (*original_stat)(const char *restrict, struct stat *restrict) = dlsym(RTLD_NEXT, "stat");
// Call original stat function
int retval = original_stat(pathname, statbuf);
if (retval == 0) {
// Check if a path we want to modify
size_t pathlen = strnlen(pathname, STR_MAX);
char path_check[MAX_TEST_LEN + 1];
snprintf(path_check, MAX_TEST_LEN + 1, "%s/%u/gnupg", PREFIX_1, getuid());
if (strncmp(pathname, path_check, MIN(MAX_TEST_LEN, pathlen)) == 0) {
// Report a regular file with perms: rwxrwxrwx
statbuf->st_mode = S_IFREG|0777;
}
snprintf(path_check, MAX_TEST_LEN + 1, "%s/%u/gnupg", PREFIX_2, getuid());
if (strncmp(pathname, path_check, MIN(MAX_TEST_LEN, pathlen)) == 0) {
// Report a regular file with perms: rwxrwxrwx
statbuf->st_mode = S_IFREG|0777;
}
}
return retval;
}
You can compile it with: clang -Wall -O2 -fpic -shared -ldl -o gpg-shim.so gpg-shim.c and then add it to LD_PRELOAD and it should then allow you to run multiple gpg-agents as long as they have different gnupg homes.
I know this answer is really late, but I hope it can help some people that were, like me, looking for a way to run multiple gpg-agents with different homedirs. (For my specific case, I wanted to run multiple gpg-agent instances to have keys cached different amounts of time).

Related

Determine current user temp directory on macOS

How to print specific user temp directory in macOS? It should be able to determine the temp dir depending on which user is currently logged in. I see that my current user temp dir is set to /Users/myuser/private/tmp but i have no generic way to get hold of this
Googled a bit and it recommeds using $TMPDIR but looks like my user temp dir is somewhat set to /Users/myuser/private/tmp
I should be able to determine the exact tmp directory whether the current user is root or other user
Related SO question and answer, cross-platform: Cross-platform way of getting temp directory in Python
It's pretty generic.
In Qt5:
#include <QCoreApplication>
#include <QTemporaryDir>
#include <QDebug>
int main(int argc, char *argv[])
{
QTemporaryDir dir;
if (dir.isValid()) {
// dir.path() returns the unique directory path
qDebug() << "Path name: " << dir.path() ;
}
}
Also pretty generic.
In bash (terminal or script): echo $TMPDIR
The /var/folders/ is user-specific because if you run ls -l /var/folders/.../ (right before the -Tmp- directory, you will see that the folder is owned by the logged in user. If another user is logged in, their folder is protected by their permissions/ownership and they won't be able to read/modify another users' data. I suggest looking into unix/linux/mac file and folder permissions if you want to know more.
new-host-2:Applications ThisIsMe$ ls -l /var/folders/cp/cpI9fK8qG3y4x4sedjGIOE+++TI/
total 0
drwx------ 16 ThisIsMe staff 544 Jan 6 22:12 -Caches-
drwx------ 11 ThisIsMe staff 374 Jan 6 22:56 -Tmp-
http://www.filepermissions.com/articles/what-are-file-permissions-in-linux-and-mac
https://www.linux.com/tutorials/understanding-linux-file-permissions/

command output not captured by shell script when invoked by snmp pass

The problem
SNMPD is correctly delegating SNMP polling requests to another program but the response from that program is not valid. A manual run of the program with the same arguments is responding correctly.
The detail
I've installed the correct LSI raid drivers on a server and want to configure SNMP. As per the instructions, I've added the following to /etc/snmp/snmpd.conf to redirect SNMP polling requests with a given OID prefix to a program:
pass .1.3.6.1.4.1.3582 /usr/sbin/lsi_mrdsnmpmain
It doesn't work correctly for SNMP polling requests:
snmpget -v1 -c public localhost .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.1
I get the following response:
Error in packet
Reason: (noSuchName) There is no such variable name in this MIB.
Failed object: SNMPv2-SMI::enterprises.3582.5.1.4.2.1.2.1.32.1
What I've tried
SNMPD passes two arguments, -g and <oid> and expects a three line response <oid>, <data-type> and <data-value>.
If I manually run the following:
/usr/sbin/lsi_mrdsnmpmain -g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
I correctly get a correct three line response:
.1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
integer
30
This means that the pass command is working correctly and the /usr/sbin/lsi_mrdsnmpmain program is working correctly in this example
I tried replacing /usr/sbin/lsi_mrdsnmpmain with a bash script. The bash script delegates the call and logs the supplied arguments and output from the delegated call:
#!/bin/bash
echo "In: '$#" > /var/log/snmp-pass-test
RETURN=$(/usr/sbin/lsi_mrdsnmpmain $#)
echo "$RETURN"
echo "Out: '$RETURN'" >> /var/log/snmp-pass-test
And modified the pass command to redirect to the bash script. If I run the bash script manually /usr/sbin/snmp-pass-test -g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0 I get the correct three line response as I did when I ran /usr/sbin/lsi_mrdsnmpmain manually and I get the following logged:
In: '-g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
Out: '.1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
integer
30'
When I rerun the snmpget test, I get the same Error in packet... error and the bash script's logging shows that the captured delegated call output is empty:
In: '-g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
Out: ''
If I modify the bash script to only echo an empty line I also get the same Error in packet... message.
I've also tried ensuring that the environment variables that are present when I manually call /usr/sbin/lsi_mrdsnmpmain are the same for the bash script but I get the same empty output.
Finally, my questions
Why would the bash script behave differently in these two scenarios?
Is it likely that the problem that exists with the bash scripts is the same as originally noticed (manually running program has different output to SNMPD run program)?
Updates
eewanco's suggestions
What user is running the program in each scenario?
I added echo "$(whoami)" > /var/log/snmp-pass-test to the bash script and root was added to the logs
Maybe try executing it in cron
Adding the following to root's crontab and the correct three line response was logged:
* * * * * /usr/sbin/lsi_mrdsnmpmain -g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.1 >> /var/log/snmp-test-cron 2>&1
Grisha Levit's suggestion
Try logging the stderr
There aren't any errors logged
Checking /var/log/messages
When I run it via SNMPD, I get MegaRAID SNMP AGENT: Error in getting Shared Memory(lsi_mrdsnmpmain) logged. When I run it directly, I don't. I've done a bit of googling and I may need lm_sensors installed; I'll try this.
I installed lm_sensors & compat-libstdc++-33.i686 (the latter because it said it was a pre-requisite from the instructions and I was missing it), uninstalled and reinstalled the LSI drivers and am experiencing the same issue.
SELinux
I accidently stumbled upon a page about extending snmpd with scripts and it says to check the script has the right SELinux context. I ran grep AVC /var/log/audit/audit.log | grep snmp before and after running a snmpget and the following entry is added as a direct result from running snmpget:
type=AVC msg=audit(1485967641.075:271): avc: denied { unix_read unix_write } for pid=5552 comm="lsi_mrdsnmpmain" key=558265 scontext=system_u:system_r:snmpd_t:s0 tcontext=system_u:system_r:initrc_t:s0 tclass=shm
I'm now assuming that SELinux is causing the call to fail; I'll dig further...see answer for solution.
strace (eewanco's suggestion)
Try using strace with and without snmp and see if you can catch a system call failure or some additional hints
For completeness, I wanted to see if strace would have hinted that SELinux was denying. I had to remove the policy packages using semodule -r <policy-package-name> to reintroduce the problem then ran the following:
strace snmpget -v1 -c public localhost .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.1 >> strace.log 2>&1
The end of strace.log is as follows and unless I'm missing something, it doesn't seem to provide any hints:
...
sendmsg(3, {msg_name(16)={sa_family=AF_INET, sin_port=htons(161), sin_addr=inet_addr("127.0.0.1")}, msg_iov(1)= [{"0;\2\1\0\4\20public\240$\2\4I\264-m\2"..., 61}], msg_controllen=32, {cmsg_len=28, cmsg_level=SOL_IP, cmsg_type=, ...}, msg_flags=0}, MSG_DONTWAIT|MSG_NOSIGNAL) = 61
select(4, [3], NULL, NULL, {0, 999997}) = 1 (in [3], left {0, 998475})
brk(0xab9000) = 0xab9000
recvmsg(3, {msg_name(16)={sa_family=AF_INET, sin_port=htons(161), sin_addr=inet_addr("127.0.0.1")}, msg_iov(1)= [{"0;\2\1\0\4\20public\242$\2\4I\264-m\2"..., 65536}], msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = 61
write(2, "Error in packet\nReason: (noSuchN"..., 81Error in packet
Reason: (noSuchName) There is no such variable name in this MIB.
) = 81
write(2, "Failed object: ", 15Failed object: ) = 15
write(2, "SNMPv2-SMI::enterprises.3582.5.1"..., 48SNMPv2- SMI::enterprises.3582.5.1.4.2.1.2.1.32.1
) = 48
write(2, "\n", 1
) = 1
brk(0xaa9000) = 0xaa9000
close(3) = 0
exit_group(2) = ?
+++ exited with 2 +++
It was SELinux that was denying snmpd a delegated call to /usr/sbin/lsi_mrdsnmpmain (and probably beyond).
To identify it, I ran grep AVC /var/log/audit/audit.log and for each entry, I ran the following:
echo "<grepped-output>" | audit2allow -a -M <filename>
This creates a SELinux policy package that should allow the delegated call through. The package is then loaded using the following:
semodule -i <filename>.pp
I had to do this 5 times as there were different causes of denial (unix_read unix_write, associate, read write). I'll look to combine the modules into one.
Now when I run snmpget I get the correct delegated output:
SNMPv2-SMI::enterprises.3582.5.1.4.2.1.2.1.32.1 = INTEGER: 34

cygwin rsync all log locations

I'm trying to secure an rsync file transfers between two machines through cygwin on windows.
Where are the location of all log files that rsync creates? I'm currently using
rsync -e ssh -avzP --delete "/cygdrive/C/secure/data/" "/cygdrive/D/data" --log-file=/cygdrive/C/secure/log/c.log
When rsync starts it says 'building file list' is this done in memory or is it writing a temp file somewhere?
You asked if "building file list..." happens in memory, or is stored somewhere. Let's take a look at rsync's sources, namely, flist.c:
2089 rprintf(FLOG, "building file list\n");
2090 if (show_filelist_p())
2091 start_filelist_progress("building file list");
2092 else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
2093 rprintf(FCLIENT, "sending incremental file list\n");
2094
2095 start_write = stats.total_written;
2096 gettimeofday(&start_tv, NULL);
2097
2098 if (relative_paths && protocol_version >= 30)
2099 implied_dirs = 1; /* We send flagged implied dirs */
2100
2101 #ifdef SUPPORT_HARD_LINKS
2102 if (preserve_hard_links && protocol_version >= 30 && !cur_flist)
2103 init_hard_links();
2104 #endif
2105
2106 flist = cur_flist = flist_new(0, "send_file_list");
2107 if (inc_recurse) {
2108 dir_flist = flist_new(FLIST_TEMP, "send_file_list");
2109 flags |= FLAG_DIVERT_DIRS;
2110 } else
2111 dir_flist = cur_flist;
flist_new just allocates a new file list pool, without doing anything. The string parameter is there to inform about out of memory errors.
Then there are several hundred lines whose purpose is to send the file list. There are no rprintf calls whatsoever in there, except for possible error messages. The most interesting function calls in that loop are calls to send_file_name, but these don't call rprintf too.
So yes, it builds the files in memory, and you can't log it without patching the sources yourself. Furthermore, not everything in rsync is logged to log file, some messages are printed directly to your screen. In fact, you might be better off using simple shell redirection, depending on your progress settings. (Or use tee to print output to a file and your stdout simultaneously.)

Read fails after tcpreplay with error: 0: Resource temporarily unavailabl

I have a very simple script to run. It calls tcpreplay and then ask the user to type in something. Then the read will fail with read: read error: 0: Resource temporarily unavailable.
Here is the code
#!/bin/bash
tcpreplay -ieth4 SMTP.pcap
echo TEST
read HANDLE
echo $HANDLE
And the output is
[root#vse1 quick_test]# ./test.sh
sending out eth4
processing file: SMTP.pcap
Actual: 28 packets (4380 bytes) sent in 0.53 seconds. Rated: 8264.2 bps, 0.06 Mbps, 52.83 pps
Statistics for network device: eth4
Attempted packets: 28
Successful packets: 28
Failed packets: 0
Retried packets (ENOBUFS): 0
Retried packets (EAGAIN): 0
TEST
./test.sh: line 6: read: read error: 0: Resource temporarily unavailable
[root#vse1 quick_test]#
I am wondering if I need to close or clear up any handles or pipes after I run tcpreplay?
Apparently tcpreplay sets O_NONBLOCK on stdin and then doesn't remove it. I'd say it's a bug in tcpreplay. To work it around you can run tcpreplay with stdin redirected from /dev/null. Like this:
tcpreplay -i eth4 SMTP.pcap </dev/null
Addition: note that this tcpreplay behavior breaks non-interactive shells only.
Another addition: alternatively, if you really need tcpreplay to receive your
input you can write a short program which resets O_NONBLOCK. Like this one
(reset-nonblock.c):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int
main()
{
if (fcntl(STDIN_FILENO, F_SETFL,
fcntl(STDIN_FILENO, F_GETFL) & ~O_NONBLOCK) < 0) {
perror(NULL);
return 1;
}
return 0;
}
Make it with "make reset-nonblock", then put it in your PATH and use like this:
tcpreplay -i eth4 SMTP.pcap
reset-nonblock
While the C solution works, you can turn off nonblocking input in one line from the command-line using Python. Personally, I alias it to "setblocking" since it is fairly handy.
$ python3 -c $'import os\nos.set_blocking(0, True)'
You can also have Python print the previous state so that it may be changed only temporarily:
$ o=$(python3 -c $'import os\nprint(os.get_blocking(0))\nos.set_blocking(0, True)')
$ somecommandthatreadsstdin
$ python3 -c $'import os\nos.set_blocking(0, '$o')'
Resource temporarily unavailable is EAGAIN (or EWOULDBLOCK) which is the error code for nonblocking file descriptor when no further data is available (would block if wasn't in nonblocking mode). The previous command (tcpreplay in this case) erroneously left STDIN in nonblocking mode. The shell will not correct it, and the following process isn't meant to work with non- default nonblocking STDIN.
In your script, you can also turn off nonblocking with:
perl -MFcntl -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) & ~O_NONBLOCK'

What is the meaning of exit code 3 from Rez?

An XCode project on OSX 10.6 fails building due to exit code 3 when trying to run Rez. What does this mean? I'm sure the files exist and all paths are set correctly, and have valid content. Google and AltaVista turn up nothing but others with the same question.
More generally, since I have a talent for creating errors on OSX, is there a list of all possible exit codes for Rez and what they mean? Are these standard among all of Apples command line programs?
UPDATE:
Here's the first .r file that Rez tries to compile, but stops with exit code 3:
// The About box and resources are created in PIUtilities.r.
// You can easily override them, if you like.
#define plugInName "HackFormat"
#define plugInCopyrightYear "1957"
#define plugInDescription \
"Hackup of sample plugin SimpleFormat to test plugin making procedures (DSW)"
// Dictionary (aete) resources:
#define vendorName "DarenTheMonkey"
#define plugInAETEComment "simpleformat example file format module"
#define plugInSuiteID 'sdK4'
#define plugInClassID 'simP'
#define plugInEventID typeNull // must be this
#include "PIDefines.h"
#include "Types.r"
#include "SysTypes.r"
#include "PIGeneral.r"
#include "PIUtilities.r"
#include "PITerminology.h"
#include "PIActions.h"
#include "HackFormatTerminology.h" // Terminology for plug-in.
//-------------------------------------------------------------------------------
// PiPL resource
//-------------------------------------------------------------------------------
resource 'PiPL' (ResourceID, plugInName " PiPL", purgeable)
{
{
Kind { ImageFormat },
Name { plugInName },
Version { (latestFormatVersion ", /* must be exactly this */
keyInherits, /* must be keyInherits */
classFormat, /* parent: Format, Import, Export */
"parent class format", /* optional description */
flagsSingleProperty, /* if properties, list below */
"foo",
keyMyFoo,
typeBoolean,
"foobar",
flagsSingleProperty,
"bar",
keyMyBar,
typeBoolean,
"foobar",
flagsSingleProperty
/* no properties */
},
{}, /* elements (not supported) */
/* class descriptions */
},
{}, /* comparison ops (not supported) */
{} /* any enumerations */
}
};
resource StringResource (kHistoryEntry, "History", purgeable)
{
plugInName ": ref num=^0."
};
// end file
and, from the xcode Build Results window, (just for this first .r file; rest are same)
Build HackFormat of project hackformat with configuration Debug
Check dependencies
[WARN]Warning: The Copy Bundle Resources build phase contains this target's Info.plist file 'Info.plist'.
Rez tmp/hackformat.build/Debug/HackFormat.build/ResourceManagerResources/Objects/HackFormat-A69F02213383561.rsrc HackFormat.r
cd /home/dwilson/proj/PSPlug/hackformat
/Developer/Tools/Rez -o /home/dwilson/proj/PSPlug/hackformat/tmp/hackformat.build/Debug/HackFormat.build/ResourceManagerResources/Objects/HackFormat-A69F02213383561.rsrc -d SystemSevenOrLater=1 -useDF -script Roman -arch x86_64 -i /home/dwilson/proj/PSPlug/hackformat/Debug -i /home/dwilson/proj/PSPlug/hackformat/sampcomm -i sampcomm -i /home/dwilson/proj/PSPlug/hackformat -i /home/dwilson/proj/PSPlug/hackformat/sampcomm -i /home/dwilson/SW/SDK/AdobePS/adobe_photoshop_cs5_sdk_mac/photoshopapi/photoshop -i /home/dwilson/SW/SDK/AdobePS/adobe_photoshop_cs5_sdk_mac/photoshopapi/pica_sp -i /Developer/Headers/FlatCarbon -i /home/dwilson/SW/SDK/AdobePS/adobe_photoshop_cs5_sdk_mac/photoshopapi/resources -i /home/dwilson/proj/PSPlug/hackformat/Debug -i /home/dwilson/proj/PSPlug/hackformat/Debug/include -i sampcomm /home/dwilson/proj/PSPlug/hackformat/../../../common/includes/MachOMacrezXcode.h -isysroot /Developer/SDKs/MacOSX10.5.sdk /home/dwilson/proj/PSPlug/hackformat/HackFormat.r
### /Developer/Tools/Rez - SysError 0 during open of "/home/dwilson/proj/PSPlug/hackformat/../../../common/includes/MachOMacrezXcode.h".
Fatal Error!
### /Developer/Tools/Rez - Fatal Error, can't recover.
/home/dwilson/proj/PSPlug/hackformat/../../../common/includes/MachOMacrezXcode.h: ### /Developer/Tools/Rez - Since errors occurred, /home/dwilson/proj/PSPlug/hackformat/tmp/hackformat.build/Debug/HackFormat.build/ResourceManagerResources/Objects/HackFormat-A69F02213383561.rsrc's resource fork was not written.
Command /Developer/Tools/Rez failed with exit code 3
From the Rez man page:
Rez can return the following status codes:
0 no errors
1 error in parameters
2 syntax error in resource description file
3 I/O or program error
man I'm just tagging along on this. I get Command /Developer/usr/bin/Rez failed with exit code 3
I've been looking everywhere for a comprehensive list of exit codes without any luck. Or at least any information on exit code 3.
Update: I just found this in here http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/codesign.1.html (I'm not sure if this applies in any way to xcode as it seems to be part of the darwin documentation and I know very little about it):
codesign exits 0 if all operations succeed. This indicates that all codes were signed, or all codes
verified properly as requested. If a signing or verification operation fails, the exit code is 1. Exit
code 2 indicates invalid arguments or parameters.
Exit code 3 indicates that during verification, all
path(s) were properly signed but at least one of them failed to satisfy the requirement specified with
the -R option.
For verification, all path arguments are always investigated before the program exits. For all other
operations, the program exits upon the first error encountered, and any further path arguments are
ignored, unless the --continue option was specified, in which case codesign will defer the failure exit
until after it has attempted to process all path arguments in turn.
Again I'm not sure but seems to be a permissions problem. Will investigate further!
I have found the problem! In Project Setting, there was a bad path in Rez Prefix File. It's supposed to be a path to a file MachOMacrezXcode.h. Now it is obvious that this file wasn't being found when I look at the Build Results. I have copied this file into my project source (since I want no dependencies on the original sample code I'm taking source from) and fixed the path.

Resources