|
32 | 32 | #define AGENT_PIPE_ID L"\\\\.\\pipe\\ssh-agent"
|
33 | 33 | #define BUFSIZE 5 * 1024
|
34 | 34 |
|
35 |
| -static HANDLE ioc_port; |
36 |
| -static volatile long action_queue; |
37 |
| -static struct agent_connection* list; |
38 |
| - |
39 |
| -#define ACTION_LISTEN 0x80000000 |
40 |
| -#define ACTION_SHUTDOWN 0x40000000 |
41 |
| - |
42 |
| -void agent_sm_process_action_queue() { |
43 |
| - |
44 |
| - do { |
45 |
| - if (action_queue & ACTION_SHUTDOWN) { |
46 |
| - /* go through the list and disconect each connection */ |
47 |
| - struct agent_connection* tmp = list; |
48 |
| - while (tmp) { |
49 |
| - agent_connection_disconnect(tmp); |
50 |
| - tmp = tmp->next; |
51 |
| - } |
| 35 | +static HANDLE ioc_port = NULL; |
| 36 | +static BOOL debug_mode = FALSE; |
52 | 37 |
|
53 |
| - /* remove unwanted queued actions */ |
54 |
| - InterlockedAnd(&action_queue, ~ACTION_LISTEN); |
55 |
| - if (InterlockedAnd(&action_queue, ~ACTION_SHUTDOWN) == ACTION_SHUTDOWN) |
56 |
| - break; |
57 |
| - } |
58 |
| - else if (action_queue & ACTION_LISTEN) { |
59 |
| - HANDLE h; |
60 |
| - long prev_queue; |
61 |
| - SECURITY_ATTRIBUTES sa; |
62 |
| - struct agent_connection* con = |
63 |
| - (struct agent_connection*)malloc(sizeof(struct agent_connection)); |
64 |
| - memset(con, 0, sizeof(struct agent_connection)); |
65 |
| - memset(&sa, 0, sizeof(sa)); |
66 |
| - sa.bInheritHandle = FALSE; |
67 |
| - sa.lpSecurityDescriptor = NULL; |
68 |
| - h = CreateNamedPipeW( |
69 |
| - AGENT_PIPE_ID, // pipe name |
70 |
| - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access |
71 |
| - PIPE_TYPE_BYTE | // message type pipe |
72 |
| - PIPE_READMODE_BYTE | // message-read mode |
73 |
| - PIPE_WAIT, // blocking mode |
74 |
| - PIPE_UNLIMITED_INSTANCES, // max. instances |
75 |
| - BUFSIZE, // output buffer size |
76 |
| - BUFSIZE, // input buffer size |
77 |
| - 0, // client time-out |
78 |
| - &sa); |
79 |
| - |
80 |
| - /* remove action from queue before assigning iocp port*/ |
81 |
| - con->connection = h; |
82 |
| - con->next = list; |
83 |
| - list = con; |
84 |
| - prev_queue = InterlockedAnd(&action_queue, ~ACTION_LISTEN); |
85 |
| - CreateIoCompletionPort(h, ioc_port, (ULONG_PTR)con, 0); |
86 |
| - ConnectNamedPipe(h, &con->ol); |
87 |
| - if (prev_queue == ACTION_LISTEN) |
88 |
| - break; |
89 |
| - } |
90 |
| - else { |
91 |
| - /* cleanup up a done connection*/ |
92 |
| - struct agent_connection *prev = NULL, *tmp = list; |
93 |
| - while (tmp) { |
94 |
| - if (tmp->state == DONE) { |
95 |
| - if (prev == NULL) |
96 |
| - list = tmp->next; |
97 |
| - else |
98 |
| - prev->next = tmp->next; |
99 |
| - CloseHandle(tmp->connection); |
100 |
| - printf("deleting %p\n", tmp); |
101 |
| - free(tmp); |
102 |
| - break; |
103 |
| - } |
104 |
| - prev = tmp; |
105 |
| - tmp = tmp->next; |
106 |
| - } |
107 |
| - if (InterlockedDecrement(&action_queue) == 0) |
108 |
| - break; |
109 |
| - } |
110 |
| - } while (1); |
111 |
| -} |
| 38 | +#define NUM_LISTENERS 1 |
| 39 | +#define KEY_AGENT_PIPE_ID L"\\\\.\\pipe\\ssh-agent" |
112 | 40 |
|
113 |
| -void |
114 |
| -agent_cleanup_connection(struct agent_connection* con) { |
115 |
| - if (InterlockedIncrement(&action_queue) == 1) |
116 |
| - agent_sm_process_action_queue(); |
117 |
| -} |
| 41 | +static wchar_t *pipe_ids[NUM_LISTENERS] = { KEY_AGENT_PIPE_ID }; |
| 42 | +static enum agent_type types[NUM_LISTENERS] = { KEY_AGENT }; |
| 43 | +HANDLE event_stop_agent; |
118 | 44 |
|
119 |
| -void |
120 |
| -agent_listen() { |
121 |
| - if (InterlockedOr(&action_queue, ACTION_LISTEN) == 0) |
122 |
| - agent_sm_process_action_queue(); |
123 |
| -} |
| 45 | +struct listener { |
| 46 | + OVERLAPPED ol; |
| 47 | + HANDLE pipe; |
| 48 | + wchar_t *pipe_id; |
| 49 | + enum agent_type type; |
| 50 | + SECURITY_ATTRIBUTES sa; |
| 51 | +} listeners[NUM_LISTENERS]; |
124 | 52 |
|
| 53 | +static int |
| 54 | +init_listeners() { |
| 55 | + int i; |
| 56 | + memset(listeners, 0, sizeof(listeners)); |
| 57 | + for (i = 0; i < NUM_LISTENERS; i++) { |
| 58 | + if ((listeners[i].ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { |
| 59 | + debug("cannot create event ERROR:%d", GetLastError()); |
| 60 | + return GetLastError(); |
| 61 | + } |
| 62 | + listeners[i].pipe_id = pipe_ids[i]; |
| 63 | + listeners[i].type = types[i]; |
| 64 | + listeners[i].pipe = INVALID_HANDLE_VALUE; |
| 65 | + listeners[i].sa.bInheritHandle = TRUE; |
| 66 | + } |
125 | 67 |
|
126 |
| -void agent_shutdown() { |
127 |
| - if (InterlockedOr(&action_queue, ACTION_SHUTDOWN) == 0) |
128 |
| - agent_sm_process_action_queue(); |
129 |
| - while (list != NULL) |
130 |
| - Sleep(100); |
131 |
| - CloseHandle(ioc_port); |
| 68 | + return 0; |
132 | 69 | }
|
133 | 70 |
|
134 |
| -HANDLE iocp_workers[4]; |
| 71 | +static void |
| 72 | +agent_cleanup() { |
| 73 | + int i; |
| 74 | + for (i = 0; i < NUM_LISTENERS; i++) { |
| 75 | + if (listeners[i].ol.hEvent != NULL) |
| 76 | + CloseHandle(listeners[i].ol.hEvent); |
| 77 | + if (listeners[i].pipe != INVALID_HANDLE_VALUE) |
| 78 | + CloseHandle(listeners[i].pipe); |
| 79 | + } |
| 80 | + if (ioc_port) |
| 81 | + CloseHandle(ioc_port); |
| 82 | + return; |
| 83 | +} |
135 | 84 |
|
136 |
| -DWORD WINAPI iocp_work(LPVOID lpParam) { |
| 85 | +static DWORD WINAPI |
| 86 | +iocp_work(LPVOID lpParam) { |
137 | 87 | DWORD bytes;
|
138 | 88 | struct agent_connection* con = NULL;
|
139 | 89 | OVERLAPPED *p_ol;
|
140 | 90 | while (1) {
|
141 | 91 | con = NULL;
|
142 | 92 | p_ol = NULL;
|
143 | 93 | if (GetQueuedCompletionStatus(ioc_port, &bytes, &(ULONG_PTR)con, &p_ol, INFINITE) == FALSE) {
|
144 |
| - printf("error: %d on %p \n", GetLastError(), con); |
145 |
| - if (con) |
| 94 | + debug("iocp error: %d on %p \n", GetLastError(), con); |
| 95 | + if (con) |
146 | 96 | agent_connection_on_error(con, GetLastError());
|
147 | 97 | else
|
148 | 98 | return 0;
|
149 | 99 | }
|
150 |
| - //printf("io on %p state %d bytes %d\n", con, con->state, bytes); |
151 |
| - agent_connection_on_io(con, bytes, p_ol); |
| 100 | + else |
| 101 | + agent_connection_on_io(con, bytes, p_ol); |
152 | 102 |
|
153 | 103 | }
|
154 | 104 | }
|
155 | 105 |
|
156 |
| -int agent_start(BOOL dbg, BOOL child, HANDLE pipe) { |
157 |
| - int i; |
| 106 | + |
| 107 | +static int |
| 108 | +process_connection(HANDLE pipe, int type) { |
| 109 | + struct agent_connection* con; |
| 110 | + |
| 111 | + if ((con = malloc(sizeof(struct agent_connection))) == NULL) { |
| 112 | + debug("out of memory"); |
| 113 | + return ERROR_OUTOFMEMORY; |
| 114 | + } |
| 115 | + memset(con, 0, sizeof(struct agent_connection)); |
| 116 | + con->connection = pipe; |
| 117 | + con->type = type; |
| 118 | + CreateIoCompletionPort(pipe, ioc_port, (ULONG_PTR)con, 0); |
| 119 | + agent_connection_on_io(con, 0, &con->ol); |
| 120 | + iocp_work(NULL); |
| 121 | +} |
| 122 | + |
| 123 | +static void |
| 124 | +agent_listen_loop() { |
| 125 | + DWORD i, r; |
| 126 | + HANDLE wait_events[NUM_LISTENERS + 1]; |
| 127 | + |
| 128 | + wait_events[0] = event_stop_agent; |
| 129 | + for (i = 0; i < NUM_LISTENERS; i++) |
| 130 | + wait_events[i + 1] = listeners[i].ol.hEvent; |
| 131 | + |
| 132 | + while (1) { |
| 133 | + for (i = 0; i < NUM_LISTENERS; i++) { |
| 134 | + if (listeners[i].pipe == INVALID_HANDLE_VALUE) { |
| 135 | + listeners[i].pipe = CreateNamedPipeW( |
| 136 | + listeners[i].pipe_id, // pipe name |
| 137 | + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access |
| 138 | + PIPE_TYPE_BYTE | // message type pipe |
| 139 | + PIPE_READMODE_BYTE | // message-read mode |
| 140 | + PIPE_WAIT, // blocking mode |
| 141 | + PIPE_UNLIMITED_INSTANCES, // max. instances |
| 142 | + BUFSIZE, // output buffer size |
| 143 | + BUFSIZE, // input buffer size |
| 144 | + 0, // client time-out |
| 145 | + &listeners[i].sa); |
| 146 | + |
| 147 | + if (listeners[i].pipe == INVALID_HANDLE_VALUE) { |
| 148 | + debug("cannot create listener pipe ERROR:%d", GetLastError()); |
| 149 | + SetEvent(event_stop_agent); |
| 150 | + } |
| 151 | + else if (ConnectNamedPipe(listeners[i].pipe, &listeners[i].ol) != FALSE) { |
| 152 | + debug("ConnectNamedPipe returned unexpectedly"); |
| 153 | + SetEvent(event_stop_agent); |
| 154 | + } |
| 155 | + |
| 156 | + if (GetLastError() == ERROR_PIPE_CONNECTED) |
| 157 | + SetEvent(listeners[i].ol.hEvent); |
| 158 | + |
| 159 | + if (GetLastError() != ERROR_IO_PENDING) { |
| 160 | + debug("ConnectNamedPipe failed ERROR: %d", GetLastError()); |
| 161 | + SetEvent(event_stop_agent); |
| 162 | + } |
| 163 | + |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + r = WaitForMultipleObjects(NUM_LISTENERS + 1, wait_events, FALSE, INFINITE); |
| 168 | + if (r == WAIT_OBJECT_0) { |
| 169 | + //received signal to shutdown |
| 170 | + debug("shutting down"); |
| 171 | + agent_cleanup(); |
| 172 | + return; |
| 173 | + } |
| 174 | + else if ((r > WAIT_OBJECT_0) && (r <= (WAIT_OBJECT_0 + NUM_LISTENERS))) { |
| 175 | + /* process incoming connection */ |
| 176 | + HANDLE con = listeners[r - 1].pipe; |
| 177 | + listeners[r - 1].pipe = INVALID_HANDLE_VALUE; |
| 178 | + |
| 179 | + if (debug_mode) { |
| 180 | + process_connection(con, listeners[r - 1].type); |
| 181 | + agent_cleanup(); |
| 182 | + return; |
| 183 | + } |
| 184 | + else { |
| 185 | + /* todo - spawn a child to take care of this*/ |
| 186 | + wchar_t path[MAX_PATH], module_path[MAX_PATH]; |
| 187 | + PROCESS_INFORMATION pi; |
| 188 | + STARTUPINFO si; |
| 189 | + |
| 190 | + si.cb = sizeof(STARTUPINFO); |
| 191 | + memset(&si, 0, sizeof(STARTUPINFO)); |
| 192 | + GetModuleFileNameW(NULL, module_path, MAX_PATH); |
| 193 | + swprintf_s(path, MAX_PATH, L"%s %d %d", module_path, con, listeners[r - 1].type); |
| 194 | + if (CreateProcessW(NULL, path, NULL, NULL, TRUE, |
| 195 | + DETACHED_PROCESS, NULL, NULL, |
| 196 | + &si, &pi) == FALSE) { |
| 197 | + debug("CreateProcess failure: %d", GetLastError()); |
| 198 | + CloseHandle(con); |
| 199 | + agent_cleanup(); |
| 200 | + return; |
| 201 | + } |
| 202 | + |
| 203 | + CloseHandle(con); |
| 204 | + |
| 205 | + } |
| 206 | + |
| 207 | + } |
| 208 | + else { |
| 209 | + debug("wait on events ended with %d ERROR:%d", r, GetLastError()); |
| 210 | + agent_cleanup(); |
| 211 | + return; |
| 212 | + } |
| 213 | + |
| 214 | + } |
| 215 | +} |
| 216 | + |
| 217 | +void agent_cleanup_connection(struct agent_connection* con) { |
| 218 | + debug("connection %p clean up", con); |
| 219 | + CloseHandle(con->connection); |
| 220 | + free(con); |
| 221 | + CloseHandle(ioc_port); |
| 222 | + ioc_port = NULL; |
| 223 | +} |
| 224 | + |
| 225 | +void agent_shutdown() { |
| 226 | + SetEvent(event_stop_agent); |
| 227 | +} |
| 228 | + |
| 229 | +int agent_start(BOOL dbg_mode, BOOL child, HANDLE pipe, enum agent_type type) { |
| 230 | + int i, r; |
158 | 231 | HKEY agent_root;
|
159 | 232 | DWORD process_id = GetCurrentProcessId();
|
160 | 233 |
|
161 |
| - debug("agent_start pid:%d, dbg:%d, child:%d, pipe:%d", process_id, dbg, child, pipe); |
162 |
| - action_queue = 0; |
163 |
| - list = NULL; |
164 |
| - ioc_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0); |
| 234 | + debug("agent_start pid:%d, dbg:%d, child:%d, pipe:%d", process_id, dbg_mode, child, pipe); |
| 235 | + debug_mode = dbg_mode; |
| 236 | + |
| 237 | + if ((ioc_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0)) == NULL) { |
| 238 | + debug("cannot create ioc port ERROR:%d", GetLastError()); |
| 239 | + return GetLastError(); |
| 240 | + } |
165 | 241 |
|
166 |
| - for (i = 0; i < 3; i++) |
167 |
| - QueueUserWorkItem(iocp_work, NULL, 0); |
| 242 | + if (child == FALSE) { |
| 243 | + RegCreateKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_ROOT, 0, 0, 0, KEY_WRITE, 0, &agent_root, 0); |
| 244 | + RegSetValueExW(agent_root, L"ProcessID", 0, REG_DWORD, (BYTE*)&process_id, 4); |
| 245 | + if ((event_stop_agent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) |
| 246 | + return GetLastError(); |
| 247 | + if ((r = init_listeners()) != 0) |
| 248 | + return r; |
| 249 | + agent_listen_loop(); |
| 250 | + } |
| 251 | + else { |
| 252 | + return process_connection(pipe, type); |
| 253 | + } |
168 | 254 |
|
169 |
| - agent_listen(); |
170 |
| - RegCreateKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_ROOT, 0, 0, 0, KEY_WRITE, 0, &agent_root, 0); |
171 |
| - RegSetValueExW(agent_root, L"ProcessID", 0, REG_DWORD, (BYTE*)&process_id, 4); |
172 |
| - iocp_work(NULL); |
173 |
| - return 1; |
| 255 | + return 0; |
174 | 256 | }
|
175 | 257 |
|
0 commit comments