3
3
#include "strbuf.h"
4
4
#include "pkt-line.h"
5
5
#include "thread-utils.h"
6
+ #include "accctrl.h"
7
+ #include "aclapi.h"
6
8
7
9
#ifndef SUPPORTS_SIMPLE_IPC
8
10
/*
@@ -592,11 +594,132 @@ static void *server_thread_proc(void *_server_thread_data)
592
594
return NULL ;
593
595
}
594
596
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
+
595
716
static HANDLE create_new_pipe (wchar_t * wpath , int is_first )
596
717
{
597
718
HANDLE hPipe ;
598
719
DWORD dwOpenMode , dwPipeMode ;
599
- LPSECURITY_ATTRIBUTES lpsa = NULL ;
720
+ struct my_sa_data my_sa_data ;
721
+
722
+ init_sa (& my_sa_data );
600
723
601
724
dwOpenMode = PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND |
602
725
FILE_FLAG_OVERLAPPED ;
@@ -612,20 +735,15 @@ static HANDLE create_new_pipe(wchar_t *wpath, int is_first)
612
735
* set the ACL / Security Attributes on the named
613
736
* pipe; subsequent instances inherit and cannot
614
737
* change them.
615
- *
616
- * TODO Should we allow the application layer to
617
- * specify security attributes, such as `LocalService`
618
- * or `LocalSystem`, when we create the named pipe?
619
- * This question is probably not important when the
620
- * daemon is started by a foreground user process and
621
- * only needs to talk to the current user, but may be
622
- * if the daemon is run via the Control Panel as a
623
- * System Service.
624
738
*/
739
+ get_sa (& my_sa_data );
625
740
}
626
741
627
742
hPipe = CreateNamedPipeW (wpath , dwOpenMode , dwPipeMode ,
628
- 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 );
629
747
630
748
return hPipe ;
631
749
}
0 commit comments