]> git.sven.stormbind.net Git - sven/jattach.git/blobdiff - src/windows/jattach.c
releasing package jattach version 2.2-1
[sven/jattach.git] / src / windows / jattach.c
index b43e2f875e2aeaef9f692c4282859ee7e0ce5652..f25f1d6f049f1f2acac970e02850736e0104d82b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Andrei Pangin
+ * Copyright jattach authors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,7 +16,8 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <Windows.h>
+#include <windows.h>
+#include <sddl.h>
 
 typedef HMODULE (WINAPI *GetModuleHandle_t)(LPCTSTR lpModuleName);
 typedef FARPROC (WINAPI *GetProcAddress_t)(HMODULE hModule, LPCSTR lpProcName);
@@ -84,10 +85,19 @@ static LPVOID allocate_data(HANDLE hProcess, char* pipeName, int argc, char** ar
     strcpy(data.strJvm, "jvm");
     strcpy(data.strEnqueue, "_JVM_EnqueueOperation");
     strcpy(data.pipeName, pipeName);
+    data.args[0][0] = data.args[1][0] = data.args[2][0] = data.args[3][0] = 0;
 
+    // jcmd has 2 arguments maximum; merge excessive arguments into one
+    int cmd_args = argc >= 2 && strcmp(argv[0], "jcmd") == 0 ? 2 : argc >= 4 ? 4 : argc;
+
+    size_t n = 0;
     int i;
-    for (i = 0; i < 4; i++) {
-        strcpy(data.args[i], i < argc ? argv[i] : "");
+    for (i = 0; i < argc; i++) {
+        if (i < cmd_args) {
+            n = snprintf(data.args[i], sizeof(data.args[i]), "%s", argv[i]);
+        } else if (n < sizeof(data.args[cmd_args - 1])) {
+            n += snprintf(data.args[cmd_args - 1] + n, sizeof(data.args[cmd_args - 1]) - n, " %s", argv[i]);
+        }
     }
 
     LPVOID remoteData = VirtualAllocEx(hProcess, NULL, sizeof(CallData), MEM_COMMIT, PAGE_READWRITE);
@@ -202,7 +212,7 @@ static int inject_thread(int pid, char* pipeName, int argc, char** argv) {
 }
 
 // JVM response is read from the pipe and mirrored to stdout
-static int read_response(HANDLE hPipe) {
+static int read_response(HANDLE hPipe, int print_output) {
     ConnectNamedPipe(hPipe, NULL);
 
     char buf[8192];
@@ -216,17 +226,54 @@ static int read_response(HANDLE hPipe) {
     buf[bytesRead] = 0;
     int result = atoi(buf);
 
-    do {
-        fwrite(buf, 1, bytesRead, stdout);
-    } while (ReadFile(hPipe, buf, sizeof(buf), &bytesRead, NULL));
+    if (print_output) {
+        // Mirror JVM response to stdout
+        printf("JVM response code = ");
+        do {
+            fwrite(buf, 1, bytesRead, stdout);
+        } while (ReadFile(hPipe, buf, sizeof(buf), &bytesRead, NULL));
+         printf("\n");
+     }
 
     return result;
 }
 
+int jattach(int pid, int argc, char** argv, int print_output) {
+    // When attaching as an Administrator, make sure the target process can connect to our pipe,
+    // i.e. allow read-write access to everyone. For the complete format description, see
+    // https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
+    SECURITY_ATTRIBUTES sec = {sizeof(SECURITY_ATTRIBUTES), NULL, FALSE};
+    ConvertStringSecurityDescriptorToSecurityDescriptor("D:(A;;GRGW;;;WD)", SDDL_REVISION_1,
+                                                        &sec.lpSecurityDescriptor, NULL);
+
+    char pipeName[MAX_PATH];
+    sprintf(pipeName, "\\\\.\\pipe\\javatool%d", GetTickCount());
+    HANDLE hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+                                   1, 4096, 8192, NMPWAIT_USE_DEFAULT_WAIT, &sec);
+    if (hPipe == INVALID_HANDLE_VALUE) {
+        print_error("Could not create pipe", GetLastError());
+        LocalFree(sec.lpSecurityDescriptor);
+        return 1;
+    }
+
+    LocalFree(sec.lpSecurityDescriptor);
+
+    if (!inject_thread(pid, pipeName, argc, argv)) {
+        CloseHandle(hPipe);
+        return 1;
+    }
+
+    int result = read_response(hPipe, print_output);
+    CloseHandle(hPipe);
+
+    return result;
+}
+
+#ifdef JATTACH_VERSION
+
 int main(int argc, char** argv) {
     if (argc < 3) {
         printf("jattach " JATTACH_VERSION " built on " __DATE__ "\n"
-               "Copyright 2021 Andrei Pangin\n"
                "\n"
                "Usage: jattach <pid> <cmd> [args ...]\n"
                "\n"
@@ -238,27 +285,12 @@ int main(int argc, char** argv) {
     }
 
     int pid = atoi(argv[1]);
-
-    char pipeName[MAX_PATH];
-    sprintf(pipeName, "\\\\.\\pipe\\javatool%d", GetTickCount());
-    HANDLE hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
-        1, 4096, 8192, NMPWAIT_USE_DEFAULT_WAIT, NULL);
-    if (hPipe == NULL) {
-        print_error("Could not create pipe", GetLastError());
+    if (pid <= 0) {
+        fprintf(stderr, "%s is not a valid process ID\n", argv[1]);
         return 1;
     }
 
-    if (!inject_thread(pid, pipeName, argc - 2, argv + 2)) {
-        CloseHandle(hPipe);
-        return 1;
-    }
-
-    printf("Response code = ");
-    fflush(stdout);
-
-    int result = read_response(hPipe);
-    printf("\n");
-    CloseHandle(hPipe);
-
-    return result;
+    return jattach(pid, argc - 2, argv + 2, 1);
 }
+
+#endif // JATTACH_VERSION