Is it possible to access the Mac OS X pasteboard when logged in via SSH? - pasteboard

We have the following snippet.
OSStatus createErr = PasteboardCreate(kPasteboardClipboard, &m_pboard);
if (createErr != noErr) {
LOG((CLOG_DEBUG "failed to create clipboard reference: error %i" createErr));
}
This compiles fine, however, it fails to run when called from SSH. This is because there is no pasteboard available in the SSH terminal. However, the idea here is to share clipboards between computers.
When run from desktop terminal, this works just fine. But when run from SSH, PasteboardCreate returns -4960 (aka, coreFoundationUnknownErr). I assume that the only way around this issue is to run the application from within the same environment as the pasteboard, but is this possible?
Synergy+ issue 67

Accessing the pasteboard directly looks to be a no-go. First, launchd won't register the processes1 with the pasteboard server's mach port. You'd first need find a way to get the pasteboard server's mach port (mach_port_names?). Also, direct communication between user sessions is prohibited2, and other communication is limited. I'm not sure if your program will have the rights to connect to the pasteboard server.
Here's a first shot at an illustrative example on using Apple events to get & set the clipboard as a string. Error handling is minimal to nonexistent (I'm not certain how I feel about require_noerr). If you're going to get/set clipboard data multiple times during a run, you can save the Apple events and, when copying to the clipboard, use AECreateDesc & AEPutParamDesc or (maybe) AEBuildParameters. AEVTBuilder might be of use.
NSString* paste() {
NSString *content;
AppleEvent paste, reply = { typeNull, 0L };
AEBuildError buildError = { typeNull, 0L };
AEDesc clipDesc = { typeNull, 0L };
OSErr err;
err = AEBuildAppleEvent(kAEJons, kAEGetClipboard,
typeApplicationBundleID, "com.apple.finder", strlen("com.apple.finder"),
kAutoGenerateReturnID, kAnyTransactionID,
&paste, &buildError,
""
);
require_noerr(err, paste_end);
err = AESendMessage(&paste, &reply, kAEWaitReply, kAEDefaultTimeout);
err = AEGetParamDesc(&reply, keyDirectObject, typeUTF8Text, &clipDesc);
require_noerr(err, pastErr_getReply);
Size dataSize = AEGetDescDataSize(&clipDesc);
char* clipData = malloc(dataSize);
if (clipData) {
err = AEGetDescData(&clipDesc, clipData, dataSize);
if (noErr == err) {
content = [NSString stringWithCString:clipData encoding:NSUTF8StringEncoding];
} else {}
free(clipData);
}
AEDisposeDesc(&clipDesc);
pastErr_getReply:
AEDisposeDesc(&reply);
pasteErr_sending:
AEDisposeDesc(&paste);
paste_end:
return content;
}
OSStatus copy(NSString* clip) {
AppleEvent copy, reply = { typeNull, 0L };
AEBuildError buildError = { typeNull, 0L };
OSErr err = AEBuildAppleEvent(kAEJons, kAESetClipboard,
typeApplicationBundleID, "com.apple.finder", strlen("com.apple.finder"),
kAutoGenerateReturnID, kAnyTransactionID,
&copy, &buildError,
"'----':utf8(#)",
AEPARAMSTR([clip UTF8String])
/*
"'----':obj {form: enum(prop), want: type(#), seld: type(#), from: null()}"
"data:utf8(#)",
AEPARAM(typeUTF8Text),
AEPARAM(pClipboard),
AEPARAMSTR([clip UTF8String])
*/
);
if (aeBuildSyntaxNoErr != buildError.fError) {
return err;
}
AESendMessage(&copy, &reply, kAENoReply, kAEDefaultTimeout);
AEDisposeDesc(&reply);
AEDisposeDesc(&copy);
return noErr;
}
I'm leaving the Core Foundation approach above, but you'll probably want to use NSAppleEventDescriptor to extract the clipboard contents from the Apple Event reply.
err = AESendMessage(&paste, &reply, kAEWaitReply, kAEDefaultTimeout);
require_noerr(err, pasteErr_sending);
// nsReply takes ownership of reply
NSAppleEventDescriptor *nsReply = [[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&reply];
content = [[nsReply descriptorAtIndex:1] stringValue];
[nsReply release];
pasteErr_sending:
AEDisposeDesc(&paste);
paste_end:
return content;
}
An NSAppleEventDescriptor is also easier to examine in a debugger than an AEDesc. To examine replies, you can also to set the AEDebugReceives environment variable when using osascript or Script Editor.app:
AEDebugReceives=1 osascript -e 'tell application "Finder" to get the clipboard'
References:
"Configuring User Sessions"
"Communicating Across Login Sessions"
Mach Kernel Interface, especially:
mach_msg_header
mach_msg
CFMessagePort Reference (mach port wrapper):
CFMessagePortCreateRemote
CFMessagePortSendRequest
Apple Events Programming Guide
Apple Event Manager Reference
AEBuild*, AEPrint* and Friends
AEBuildAppleEvent on CocoaDev
Mac OS X Debugging Magic (for AEDebugSends and other AEDebug* environment variables)

I tried doing it in AppleScript, and it worked (even when invoked via SSH). My script is as follows:
#!/usr/bin/osascript
on run
tell application "Finder"
display dialog (get the clipboard)
end tell
end run
This definitely isn't an ideal solution, but perhaps if you worked out how AppleScript does it then it'd help you implement it yourself.

Take a look at pbpaste (getting the contents of the clipboard) and pbcopy (copying contents TO the clipboard). Works fine, also over SSH. :)
On Mac OS X Snow Leopard:
(source: hillrippers.ch)
On Ubuntu 9.04:
(source: hillrippers.ch)

You can access the pasteboard with PasteboardCreate via SSH on SnowLeopard but not on Leopard or Tiger.
You probably don't want to use pbcopy and pbpaste for a full pasteboard sync since those only deal with plain text, RTF, and EPS. If, for example, you copy an image and then try to write it out with pbpaste, you'll get no output.
Assuming you have an app running in the user's session on both computers, you could serialize the pasteboard data out to a file, transfer it over SSH, read it from your app on the remote side, and then put the pasteboard data on the remote pasteboard. However, getting the pasteboard serialization right may be tricky and I'm not sure how portable pasteboard data is between OSes and architectures.

Related

LwIP Clilent can't establish a connection

I want to connect two F746ZG boards so that they can communicate via TCP. I am using the STM implementation of LwIP with the netconn API. The IP address is supplied via DHCP, but it is always the same address. Also, the address matches the expected value. The problem I am facing is that the client seemingly can't establish a connection. I am binding the connection to port 8880. Since I ran into this issue, I have written a debug client that should just periodically send a predefined message to a server. Here is the code for the client:
static void tcpecho_client_thread(void const *arg)
{
struct netconn *xNetConn = NULL;
err_t bind_err, connect_err;
char* b_data = "OK"; // Data to be sent
uint16_t b_len = sizeof ( b_data );
IP4_ADDR(&local_ip, IP_ADDR0_CLIENT, IP_ADDR1_CLIENT, IP_ADDR2_CLIENT, IP_ADDR3_CLIENT);
IP4_ADDR(&pc_ip, IP_ADDR0_PC, IP_ADDR0_PC, IP_ADDR2_PC, IP_ADDR3_PC);
xNetConn = netconn_new ( NETCONN_TCP );
if (xNetConn != NULL){
bind_err = netconn_bind ( xNetConn, &local_ip, TCP_PORT_NETCONN );
if(bind_err == ERR_OK){
// Try to connect to server
for(;;){
connect_err = netconn_connect ( xNetConn, &pc_ip, TCP_PORT_NETCONN);
if (connect_err == ERR_OK){
// We are connected
while(1){
BSP_LED_On(LED1);
netconn_write(xNetConn, b_data, b_len, NETCONN_COPY);
vTaskDelay(1000); // To see the result easily in Comm Operator
}
}
}
}else{
// Failed to bind the connection
BSP_LED_On(LED3);
}
}else{
// Failed to allocate a new connection
BSP_LED_On(LED3);
}
}
When I debug this, netconn_connect never manages to actually connect to something. Since I am able to ping the board and get a response, I am confused, what is going wrong here. I have tried to use Hercules to set up a TCP server on my PC so that the board can connect to that, but that also doesn't work. Using Wireshark, I can see the responses to my ping command coming in, but I don't see anything that would indicate the board trying to connect to my PC.
I have tested the corresponding server on the second board, but that runs fine. I can connect to it with Hercules and send data, so I doubt there is anything fundamentally wrong with the LwIP stack.
What I could guess is that I messed up the netconn_bind, I am not 100% sure what IP you are supposed to bind the connection to. The way it currently is, is how I read the documentation. For the server, I have bound it to IP_ADDR_ANY. Besides that, my implementation mostly matches with the examples you can find online (e.g. LwIP Wiki).
I have figured out the problem. After I delete the netconn_bind call, everything works fine for me.

How to set Powered property of /org/bluez/hci0 using sd_bus_set_property?

Recently I started to develop a bluetooth app using API exposed via D-BUS. After some research, I chose to use sd-bus library to communicate with D-Bus.
Here is my code:
#include <systemd/sd-bus.h>
sd_bus* bus_;
if (sd_bus_open_system(&bus_) < 0)
{
throw std::runtime_error("sd_bus_open_system");
}
sd_bus_error sd_error;
bool powered = true;
if (sd_bus_set_property(bus_,
"org.bluez",
"/org/bluez/hci0",
"org.bluez.Adapter1",
"Powered",
&sd_error,
"b", &powered) < 0)
{
throw std::runtime_error("Bluetooth Power On");
}
The code above throws "Bluetooth Power On" and the return value of sd_bus_set_property is -22 (EINVAL). I couldn't make much sense from sd_error, but for to whom may be interested, here is the details:
name:0x7fffffffdce8 "И\277UUU"
message:0x5555555d6fbd <handler::handler(std::span<door, 18446744073709551615ul>)+191> "\220H\213E\350dH+\004%("
_need_free:1439044320
I have checked the literal strings using D-Feet app and everything seems to be right.
I've tried running as root or without root.
I've tried adding the user to bluetooth group.
What is wrong with this code?
source code of sd_bus_set_property shows that internally, it calls "Set" from "org.freedesktop.DBus.Properties". Most of the bluetooth examples I've seen, do this without using "sd_bus_set_property", but I'm curious to see how it can be done via "sd_bus_set_property".
Thanks for reading.
I built systemd from source and stepped into its functions and saw at some point it checks the error and since it's not null, returns.
sd_bus_error sd_error = SD_BUS_ERROR_NULL;
fixed the issue.

Monitoring a couchbase bucket with libevent

I'm trying to implement a C application that will monitor writes / modifications / new documents events happening on a couchbase remote cluster coming from a different application. I am now familiar with couchbase C SDK and synchronous instances but I have trouble combining it with libevent for asynchronous I/O.
I read couchbase libevent plugin documentation and the external event loop integration example but I cannot grasp how I would tell my event_base that, for instance:
Monitor this file on this bucket and send me a callback when it's modified
Here's what I do so far:
Firstly, I create my libevent IO option
struct event_base *mEvbase = event_base_new();
lcb_t instance;
lcb_error_t err;
struct lcb_create_io_ops_st ciops;
lcb_io_opt_t ioops;
memset(&ciops, 0, sizeof(ciops));
ciops.v.v0.type = LCB_IO_OPS_LIBEVENT;
ciops.v.v0.cookie = mEvbase;
err = lcb_create_libevent_io_opts(0, &ioops, mEvbase);
if (err != LCB_SUCCESS) {
ERRORMSG0("Failed to create an IOOPS structure for libevent: %s\n", lcb_strerror(NULL, error));
}
and then I create my instance:
struct lcb_create_st create_options;
std::string host = std::string("couchbase://192.168.130.10/");
host.append(bucket);
const char password[] = "password";
create_options.version = 3;
create_options.v.v3.connstr = host.c_str();
create_options.v.v3.passwd = password;
create_options.v.v3.io = ioops;
//Creating a lcb instance
err = lcb_create(&instance, &create_options);
if (err != LCB_SUCCESS) {
die(NULL, "Couldn't create couchbase handler\n", err);
return;
}
/* Assign the handlers to be called for the operation types */
lcb_set_bootstrap_callback(instance, bootstrap_callback);
lcb_set_get_callback(instance, generic_get_callback);
lcb_set_store_callback(instance, generic_store_callback);
and then I schedule a connection.
//We now schedule a connection to the server
err = lcb_connect(instance);
if (err != LCB_SUCCESS) {
die(instance, "Couldn't schedule connection\n", err);
lcb_destroy(instance);
}
lcb_set_cookie(instance, mEvbase);
I use libcouchbase version 2.0.17, libevent core version 2.0.so.5.1.9 and libevent extra version 2.0.so.5.1.9. With the code above, my instance cannot connect to couchbase. I get the following warnings:
event_pending: event has no event_base set.
event_add: event has no event_base set.
So two problems here: I can't connect using the above code and I don't know which direction to go to start receiving events. If anyone point me towards a link or a coded example of this simple case that would unblock me.
Ensure that you are using the same libevent version for both the library and your application. Installing the packages from the repository, you will need to align with the libevent version used therein (e.g. ldd /usr/lib64/libcouchbase_libevent.so). Keep in mind that this must be of the same ABI (so for example, using libevent's 2.0 -> 1.4 compat layer will not work, as the two versions contain different ABIs, and using a libcouchbase_libevent.so linked against 1.4 will break under 2.0).
For the full exchange, see the the comments on the question :)

MS CryptoAPI - Machine Keystore with Error 0x80090016 (NTE_BAD_KEYSET) with certreq created keys

Summary
I create a PKCS#10 CSR with certreq and have set the option Exportable=TRUE. This successfully creates a key under the location REQUEST. I also have a valid certificate with key in MY. If I try to access any one of them the CryptoAPI reports error code 0x80090016.
Running under different access rights could not solve this problem so far.
Goal
My goal is to get both the keys in MY and REQUEST. If I call CryptAcquireContextA() on any of those, it fails.
System
Windows 7 x64
Sample Source Code
My complete code looks like this:
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, "REQUEST");
pCert = CertFindCertificateInStore(hStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_A, "CERTIFICATE_SUBJECT", NULL);
CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len);
pinfo = (CRYPT_KEY_PROV_INFO *) malloc(len);
CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len);
provname = wide_to_asc(pinfo->pwszProvName);
contname = wide_to_asc(pinfo->pwszContainerName);
if(!CryptAcquireContextA(&hCryptProv, contname, provname, pinfo->dwProvType, 0)) {
err = GetLastError();
fprintf(stderr, "Error: 0x%x\n", err);
}
CryptGetUserKey(hCryptProv, pinfo->dwKeySpec, &hUserkey);
This code is mostly copied from the OpenSSL capi engine. Since the engine failed, I created the smallest possible code to search the error.
The error
If I run this, it fails with the output Error: 0x80090016. This means one of three things according to Microsoft:
Key container does not exist.
You do not have access to the key container.
The Protected Storage Service is not running.
What have I done so far?
Started service "Protected Storage"
Verified container exists with MMC & Certificate Snap-In for Local Computer
Ran the same code on the User store in user context - it worked
File System Permissions
After some googling, I tried to change permissions on the file system. I found the files by looking at the contname variable of my code and searching for the file. I changed permissions on them (more accurate, I changed permissions on the parent folder). While this fixed the issue for MY, it seems I cannot change it for REQUEST.
One note here is that my container for MY seems to be here:
%APPDATA%\Microsoft\Crypto\RSA\S-1-5-21-1650336054-1974872081-316617838-545102
For REQUEST I found it under a different address:
%ALLUSERSPROFILE%\Microsoft\Crypto\RSA\MachineKeys
I am not sure on the workings here so I cannot explain why it would put them in different locations (one being user centric, the other one a system folder). The MY store was created with a regular administrator prompt and the command certreq -new inf_file.inf cert-csr.csr and after I received my certificate, I issued certreq -accept cert.pem. Then I created a new csr with the same command.
Different privilege levels
I tried to execute my program with the following privileges:
my local user account
admin prompt (cmd->start as administrator)
nt authority\system (whoami output)
To recieve a service prompt, I executed psexec.exe –ids cmd.exe according to a tip from MaaSters Center
Final words
Any help or guidance on how to further narrow this problem down will be greatly appreciated.
I was finally able to solve this problem and it is a lot simpler than I thought. I was sure that I would receive an unambiguous container name and don't need to be more specific but CryptAcquireContext actually requires me to pass a flag CRYPT_MACHINE_KEYSET.
So my function call has to look like this:
CryptAcquireContextA(&hCryptProv, contname, provname, pinfo->dwProvType, CRYPT_MACHINE_KEYSET)
Unfortunately this is not supported by the OpenSSL engine, so you would have to alter it yourself in the engine.
See MSDN: "A key container created without this flag by a user that is not an administrator can be accessed only by the user creating the key container and the local system account."
Complete details here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v=vs.85).aspx

Generating RDP file on the fly

I want to create a web application similar to TS Web Access, where I can create rdp files on the fly for Remote Apps configured on the server. Any idea??
We had to do this exact thing.
private void InvokeRDPSign(String fileName, String certificateThumbPrint)
{
Process signingProcess = new Process();
signingProcess.StartInfo.FileName = #"rdpsign.exe";
String arguments = String.Format("/sha1 {0} {1}", certificateThumbPrint, fileName);
signingProcess.StartInfo.Arguments = arguments;
signingProcess.StartInfo.UseShellExecute = false;
signingProcess.StartInfo.RedirectStandardOutput = true;
signingProcess.StartInfo.WorkingDirectory = Environment.SystemDirectory;
signingProcess.Start();
String signingOutput = signingProcess.StandardOutput.ReadToEnd();
signingProcess.WaitForExit();
int exitCode = signingProcess.ExitCode;
//TODO: should we throw an error if the exitcode is not 0
}
Be aware that that the RDPSign.exe is different on each version of windows. You will find that an older version of the utility will ignore newer settings from the signature.
well Having looked at a 'rdp' file this is the contents:
screen mode id:i:2
desktopwidth:i:1280
desktopheight:i:768
session bpp:i:32
winposstr:s:2,3,1430,104,2230,704
compression:i:1
keyboardhook:i:2
displayconnectionbar:i:1
disable wallpaper:i:1
disable full window drag:i:1
allow desktop composition:i:0
allow font smoothing:i:0
disable menu anims:i:1
disable themes:i:0
disable cursor setting:i:0
bitmapcachepersistenable:i:1
full address:s: [YOUR IP]
audiomode:i:0
redirectprinters:i:1
redirectcomports:i:0
redirectsmartcards:i:1
redirectclipboard:i:1
redirectposdevices:i:0
autoreconnection enabled:i:1
authentication level:i:0
prompt for credentials:i:0
negotiate security layer:i:1
remoteapplicationmode:i:0
alternate shell:s:
shell working directory:s:
gatewayhostname:s:
gatewayusagemethod:i:4
gatewaycredentialssource:i:4
gatewayprofileusagemethod:i:0
promptcredentialonce:i:1
drivestoredirect:s:
Just create that as a string, seems straightforward.
ps I have no idea what the 'winposstr' parameter is...

Resources