33#include "strbuf.h"
44#include "pkt-line.h"
55#include "thread-utils.h"
6+ #include "accctrl.h"
7+ #include "aclapi.h"
68
79#ifndef SUPPORTS_SIMPLE_IPC
810/*
@@ -49,6 +51,9 @@ static enum ipc_active_state get_active_state(wchar_t *pipe_path)
4951 if (GetLastError () == ERROR_FILE_NOT_FOUND )
5052 return IPC_STATE__PATH_NOT_FOUND ;
5153
54+ trace2_data_intmax ("ipc-debug" , NULL , "getstate/waitpipe/gle" ,
55+ (intmax_t )GetLastError ());
56+
5257 return IPC_STATE__OTHER_ERROR ;
5358}
5459
@@ -109,9 +114,15 @@ static enum ipc_active_state connect_to_server(
109114 t_start_ms = (DWORD )(getnanotime () / 1000000 );
110115
111116 if (!WaitNamedPipeW (wpath , timeout_ms )) {
112- if (GetLastError () == ERROR_SEM_TIMEOUT )
117+ DWORD gleWait = GetLastError ();
118+
119+ if (gleWait == ERROR_SEM_TIMEOUT )
113120 return IPC_STATE__NOT_LISTENING ;
114121
122+ trace2_data_intmax ("ipc-debug" , NULL ,
123+ "connect/waitpipe/gle" ,
124+ (intmax_t )gleWait );
125+
115126 return IPC_STATE__OTHER_ERROR ;
116127 }
117128
@@ -133,17 +144,31 @@ static enum ipc_active_state connect_to_server(
133144 break ; /* try again */
134145
135146 default :
147+ trace2_data_intmax ("ipc-debug" , NULL ,
148+ "connect/createfile/gle" ,
149+ (intmax_t )gle );
150+
136151 return IPC_STATE__OTHER_ERROR ;
137152 }
138153 }
139154
140155 if (!SetNamedPipeHandleState (hPipe , & mode , NULL , NULL )) {
156+ gle = GetLastError ();
157+ trace2_data_intmax ("ipc-debug" , NULL ,
158+ "connect/setpipestate/gle" ,
159+ (intmax_t )gle );
160+
141161 CloseHandle (hPipe );
142162 return IPC_STATE__OTHER_ERROR ;
143163 }
144164
145165 * pfd = _open_osfhandle ((intptr_t )hPipe , O_RDWR |O_BINARY );
146166 if (* pfd < 0 ) {
167+ gle = GetLastError ();
168+ trace2_data_intmax ("ipc-debug" , NULL ,
169+ "connect/openosfhandle/gle" ,
170+ (intmax_t )gle );
171+
147172 CloseHandle (hPipe );
148173 return IPC_STATE__OTHER_ERROR ;
149174 }
@@ -208,15 +233,16 @@ void ipc_client_close_connection(struct ipc_client_connection *connection)
208233
209234int ipc_client_send_command_to_connection (
210235 struct ipc_client_connection * connection ,
211- const char * message , struct strbuf * answer )
236+ const char * message , size_t message_len ,
237+ struct strbuf * answer )
212238{
213239 int ret = 0 ;
214240
215241 strbuf_setlen (answer , 0 );
216242
217243 trace2_region_enter ("ipc-client" , "send-command" , NULL );
218244
219- if (write_packetized_from_buf_no_flush (message , strlen ( message ) ,
245+ if (write_packetized_from_buf_no_flush (message , message_len ,
220246 connection -> fd ) < 0 ||
221247 packet_flush_gently (connection -> fd ) < 0 ) {
222248 ret = error (_ ("could not send IPC command" ));
@@ -239,7 +265,8 @@ int ipc_client_send_command_to_connection(
239265
240266int ipc_client_send_command (const char * path ,
241267 const struct ipc_client_connect_options * options ,
242- const char * message , struct strbuf * response )
268+ const char * message , size_t message_len ,
269+ struct strbuf * response )
243270{
244271 int ret = -1 ;
245272 enum ipc_active_state state ;
@@ -250,7 +277,9 @@ int ipc_client_send_command(const char *path,
250277 if (state != IPC_STATE__LISTENING )
251278 return ret ;
252279
253- ret = ipc_client_send_command_to_connection (connection , message , response );
280+ ret = ipc_client_send_command_to_connection (connection ,
281+ message , message_len ,
282+ response );
254283
255284 ipc_client_close_connection (connection );
256285
@@ -458,7 +487,7 @@ static int do_io(struct ipc_server_thread_data *server_thread_data)
458487 if (ret >= 0 ) {
459488 ret = server_thread_data -> server_data -> application_cb (
460489 server_thread_data -> server_data -> application_data ,
461- buf .buf , do_io_reply_callback , & reply_data );
490+ buf .buf , buf . len , do_io_reply_callback , & reply_data );
462491
463492 packet_flush_gently (reply_data .fd );
464493
@@ -565,11 +594,132 @@ static void *server_thread_proc(void *_server_thread_data)
565594 return NULL ;
566595}
567596
597+ /*
598+ * We need to build a Windows "SECURITY_ATTRIBUTES" object and use it
599+ * to apply an ACL when we create the initial instance of the Named
600+ * Pipe. The construction is somewhat involved and consists of
601+ * several sequential steps and intermediate objects.
602+ *
603+ * We use this structure to hold these intermediate pointers so that
604+ * we can free them as a group. (It is unclear from the docs whether
605+ * some of these intermediate pointers can be freed before we are
606+ * finished using the "lpSA" member.)
607+ */
608+ struct my_sa_data
609+ {
610+ PSID pEveryoneSID ;
611+ PACL pACL ;
612+ PSECURITY_DESCRIPTOR pSD ;
613+ LPSECURITY_ATTRIBUTES lpSA ;
614+ };
615+
616+ static void init_sa (struct my_sa_data * d )
617+ {
618+ memset (d , 0 , sizeof (* d ));
619+ }
620+
621+ static void release_sa (struct my_sa_data * d )
622+ {
623+ if (d -> pEveryoneSID )
624+ FreeSid (d -> pEveryoneSID );
625+ if (d -> pACL )
626+ LocalFree (d -> pACL );
627+ if (d -> pSD )
628+ LocalFree (d -> pSD );
629+ if (d -> lpSA )
630+ LocalFree (d -> lpSA );
631+
632+ memset (d , 0 , sizeof (* d ));
633+ }
634+
635+ /*
636+ * Create SECURITY_ATTRIBUTES to apply to the initial named pipe. The
637+ * creator of the first server instance gets to set the ACLs on it.
638+ *
639+ * We allow the well-known group `EVERYONE` to have read+write access
640+ * to the named pipe so that clients can send queries to the daemon
641+ * and receive the response.
642+ *
643+ * Normally, this is not necessary since the daemon is usually
644+ * automatically started by a foreground command like `git status`,
645+ * but in those cases where an elevated Git command started the daemon
646+ * (such that the daemon itself runs with elevation), we need to add
647+ * the ACL so that non-elevated commands can write to it.
648+ *
649+ * The following document was helpful:
650+ * https://docs.microsoft.com/en-us/windows/win32/secauthz/creating-a-security-descriptor-for-a-new-object-in-c--
651+ *
652+ * Returns d->lpSA set to a SA or NULL.
653+ */
654+ static LPSECURITY_ATTRIBUTES get_sa (struct my_sa_data * d )
655+ {
656+ SID_IDENTIFIER_AUTHORITY sid_auth_world = SECURITY_WORLD_SID_AUTHORITY ;
657+ #define NR_EA (1)
658+ EXPLICIT_ACCESS ea [NR_EA ];
659+ DWORD dwResult ;
660+
661+ if (!AllocateAndInitializeSid (& sid_auth_world , 1 ,
662+ SECURITY_WORLD_RID , 0 ,0 ,0 ,0 ,0 ,0 ,0 ,
663+ & d -> pEveryoneSID )) {
664+ DWORD gle = GetLastError ();
665+ trace2_data_intmax ("ipc-debug" , NULL , "alloc-world-sid/gle" ,
666+ (intmax_t )gle );
667+ goto fail ;
668+ }
669+
670+ memset (ea , 0 , NR_EA * sizeof (EXPLICIT_ACCESS ));
671+
672+ ea [0 ].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE ;
673+ ea [0 ].grfAccessMode = SET_ACCESS ;
674+ ea [0 ].grfInheritance = NO_INHERITANCE ;
675+ ea [0 ].Trustee .MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE ;
676+ ea [0 ].Trustee .TrusteeForm = TRUSTEE_IS_SID ;
677+ ea [0 ].Trustee .TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP ;
678+ ea [0 ].Trustee .ptstrName = (LPTSTR )d -> pEveryoneSID ;
679+
680+ dwResult = SetEntriesInAcl (NR_EA , ea , NULL , & d -> pACL );
681+ if (dwResult != ERROR_SUCCESS ) {
682+ DWORD gle = GetLastError ();
683+ trace2_data_intmax ("ipc-debug" , NULL , "set-acl-entry/gle" ,
684+ (intmax_t )gle );
685+ trace2_data_intmax ("ipc-debug" , NULL , "set-acl-entry/dw" ,
686+ (intmax_t )dwResult );
687+ goto fail ;
688+ }
689+
690+ d -> pSD = (PSECURITY_DESCRIPTOR )LocalAlloc (
691+ LPTR , SECURITY_DESCRIPTOR_MIN_LENGTH );
692+ if (!InitializeSecurityDescriptor (d -> pSD , SECURITY_DESCRIPTOR_REVISION )) {
693+ DWORD gle = GetLastError ();
694+ trace2_data_intmax ("ipc-debug" , NULL , "init-sd/gle" , (intmax_t )gle );
695+ goto fail ;
696+ }
697+
698+ if (!SetSecurityDescriptorDacl (d -> pSD , TRUE, d -> pACL , FALSE)) {
699+ DWORD gle = GetLastError ();
700+ trace2_data_intmax ("ipc-debug" , NULL , "set-sd-dacl/gle" , (intmax_t )gle );
701+ goto fail ;
702+ }
703+
704+ d -> lpSA = (LPSECURITY_ATTRIBUTES )LocalAlloc (LPTR , sizeof (SECURITY_ATTRIBUTES ));
705+ d -> lpSA -> nLength = sizeof (SECURITY_ATTRIBUTES );
706+ d -> lpSA -> lpSecurityDescriptor = d -> pSD ;
707+ d -> lpSA -> bInheritHandle = FALSE;
708+
709+ return d -> lpSA ;
710+
711+ fail :
712+ release_sa (d );
713+ return NULL ;
714+ }
715+
568716static HANDLE create_new_pipe (wchar_t * wpath , int is_first )
569717{
570718 HANDLE hPipe ;
571719 DWORD dwOpenMode , dwPipeMode ;
572- LPSECURITY_ATTRIBUTES lpsa = NULL ;
720+ struct my_sa_data my_sa_data ;
721+
722+ init_sa (& my_sa_data );
573723
574724 dwOpenMode = PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND |
575725 FILE_FLAG_OVERLAPPED ;
@@ -585,20 +735,15 @@ static HANDLE create_new_pipe(wchar_t *wpath, int is_first)
585735 * set the ACL / Security Attributes on the named
586736 * pipe; subsequent instances inherit and cannot
587737 * change them.
588- *
589- * TODO Should we allow the application layer to
590- * specify security attributes, such as `LocalService`
591- * or `LocalSystem`, when we create the named pipe?
592- * This question is probably not important when the
593- * daemon is started by a foreground user process and
594- * only needs to talk to the current user, but may be
595- * if the daemon is run via the Control Panel as a
596- * System Service.
597738 */
739+ get_sa (& my_sa_data );
598740 }
599741
600742 hPipe = CreateNamedPipeW (wpath , dwOpenMode , dwPipeMode ,
601- PIPE_UNLIMITED_INSTANCES , 1024 , 1024 , 0 , lpsa );
743+ PIPE_UNLIMITED_INSTANCES , 1024 , 1024 , 0 ,
744+ my_sa_data .lpSA );
745+
746+ release_sa (& my_sa_data );
602747
603748 return hPipe ;
604749}
0 commit comments