rugged 1.4.3 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1779,9 +1779,9 @@ done:
1779
1779
  return supported;
1780
1780
  }
1781
1781
 
1782
- static git_fs_path__mock_owner_t mock_owner = GIT_FS_PATH_MOCK_OWNER_NONE;
1782
+ static git_fs_path_owner_t mock_owner = GIT_FS_PATH_OWNER_NONE;
1783
1783
 
1784
- void git_fs_path__set_owner(git_fs_path__mock_owner_t owner)
1784
+ void git_fs_path__set_owner(git_fs_path_owner_t owner)
1785
1785
  {
1786
1786
  mock_owner = owner;
1787
1787
  }
@@ -1873,74 +1873,52 @@ static int file_owner_sid(PSID *out, const char *path)
1873
1873
  return error;
1874
1874
  }
1875
1875
 
1876
- int git_fs_path_owner_is_current_user(bool *out, const char *path)
1876
+ int git_fs_path_owner_is(
1877
+ bool *out,
1878
+ const char *path,
1879
+ git_fs_path_owner_t owner_type)
1877
1880
  {
1878
1881
  PSID owner_sid = NULL, user_sid = NULL;
1879
- int error = -1;
1882
+ BOOL is_admin, admin_owned;
1883
+ int error;
1880
1884
 
1881
1885
  if (mock_owner) {
1882
- *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER);
1886
+ *out = ((mock_owner & owner_type) != 0);
1883
1887
  return 0;
1884
1888
  }
1885
1889
 
1886
- if ((error = file_owner_sid(&owner_sid, path)) < 0 ||
1887
- (error = current_user_sid(&user_sid)) < 0)
1890
+ if ((error = file_owner_sid(&owner_sid, path)) < 0)
1888
1891
  goto done;
1889
1892
 
1890
- *out = EqualSid(owner_sid, user_sid);
1891
- error = 0;
1892
-
1893
- done:
1894
- git__free(owner_sid);
1895
- git__free(user_sid);
1896
- return error;
1897
- }
1898
-
1899
- int git_fs_path_owner_is_system(bool *out, const char *path)
1900
- {
1901
- PSID owner_sid;
1902
-
1903
- if (mock_owner) {
1904
- *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM);
1905
- return 0;
1906
- }
1907
-
1908
- if (file_owner_sid(&owner_sid, path) < 0)
1909
- return -1;
1910
-
1911
- *out = IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
1912
- IsWellKnownSid(owner_sid, WinLocalSystemSid);
1893
+ if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0) {
1894
+ if ((error = current_user_sid(&user_sid)) < 0)
1895
+ goto done;
1913
1896
 
1914
- git__free(owner_sid);
1915
- return 0;
1916
- }
1917
-
1918
- int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path)
1919
- {
1920
- PSID owner_sid = NULL, user_sid = NULL;
1921
- int error = -1;
1922
-
1923
- if (mock_owner) {
1924
- *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM ||
1925
- mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER);
1926
- return 0;
1897
+ if (EqualSid(owner_sid, user_sid)) {
1898
+ *out = true;
1899
+ goto done;
1900
+ }
1927
1901
  }
1928
1902
 
1929
- if (file_owner_sid(&owner_sid, path) < 0)
1930
- goto done;
1903
+ admin_owned =
1904
+ IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
1905
+ IsWellKnownSid(owner_sid, WinLocalSystemSid);
1931
1906
 
1932
- if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
1933
- IsWellKnownSid(owner_sid, WinLocalSystemSid)) {
1934
- *out = 1;
1935
- error = 0;
1907
+ if (admin_owned &&
1908
+ (owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR) != 0) {
1909
+ *out = true;
1936
1910
  goto done;
1937
1911
  }
1938
1912
 
1939
- if (current_user_sid(&user_sid) < 0)
1913
+ if (admin_owned &&
1914
+ (owner_type & GIT_FS_PATH_USER_IS_ADMINISTRATOR) != 0 &&
1915
+ CheckTokenMembership(NULL, owner_sid, &is_admin) &&
1916
+ is_admin) {
1917
+ *out = true;
1940
1918
  goto done;
1919
+ }
1941
1920
 
1942
- *out = EqualSid(owner_sid, user_sid);
1943
- error = 0;
1921
+ *out = false;
1944
1922
 
1945
1923
  done:
1946
1924
  git__free(owner_sid);
@@ -1950,12 +1928,36 @@ done:
1950
1928
 
1951
1929
  #else
1952
1930
 
1953
- static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uids_len)
1931
+ static int sudo_uid_lookup(uid_t *out)
1932
+ {
1933
+ git_str uid_str = GIT_STR_INIT;
1934
+ int64_t uid;
1935
+ int error;
1936
+
1937
+ if ((error = git__getenv(&uid_str, "SUDO_UID")) == 0 &&
1938
+ (error = git__strntol64(&uid, uid_str.ptr, uid_str.size, NULL, 10)) == 0 &&
1939
+ uid == (int64_t)((uid_t)uid)) {
1940
+ *out = (uid_t)uid;
1941
+ }
1942
+
1943
+ git_str_dispose(&uid_str);
1944
+ return error;
1945
+ }
1946
+
1947
+ int git_fs_path_owner_is(
1948
+ bool *out,
1949
+ const char *path,
1950
+ git_fs_path_owner_t owner_type)
1954
1951
  {
1955
1952
  struct stat st;
1956
- size_t i;
1953
+ uid_t euid, sudo_uid;
1957
1954
 
1958
- *out = false;
1955
+ if (mock_owner) {
1956
+ *out = ((mock_owner & owner_type) != 0);
1957
+ return 0;
1958
+ }
1959
+
1960
+ euid = geteuid();
1959
1961
 
1960
1962
  if (p_lstat(path, &st) != 0) {
1961
1963
  if (errno == ENOENT)
@@ -1965,54 +1967,41 @@ static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uid
1965
1967
  return -1;
1966
1968
  }
1967
1969
 
1968
- for (i = 0; i < uids_len; i++) {
1969
- if (uids[i] == st.st_uid) {
1970
- *out = true;
1971
- break;
1972
- }
1970
+ if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0 &&
1971
+ st.st_uid == euid) {
1972
+ *out = true;
1973
+ return 0;
1973
1974
  }
1974
1975
 
1975
- return 0;
1976
- }
1977
-
1978
- int git_fs_path_owner_is_current_user(bool *out, const char *path)
1979
- {
1980
- uid_t userid = geteuid();
1981
-
1982
- if (mock_owner) {
1983
- *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER);
1976
+ if ((owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR) != 0 &&
1977
+ st.st_uid == 0) {
1978
+ *out = true;
1984
1979
  return 0;
1985
1980
  }
1986
1981
 
1987
- return fs_path_owner_is(out, path, &userid, 1);
1988
- }
1989
-
1990
- int git_fs_path_owner_is_system(bool *out, const char *path)
1991
- {
1992
- uid_t userid = 0;
1993
-
1994
- if (mock_owner) {
1995
- *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM);
1982
+ if ((owner_type & GIT_FS_PATH_OWNER_RUNNING_SUDO) != 0 &&
1983
+ euid == 0 &&
1984
+ sudo_uid_lookup(&sudo_uid) == 0 &&
1985
+ st.st_uid == sudo_uid) {
1986
+ *out = true;
1996
1987
  return 0;
1997
1988
  }
1998
1989
 
1999
- return fs_path_owner_is(out, path, &userid, 1);
1990
+ *out = false;
1991
+ return 0;
2000
1992
  }
2001
1993
 
2002
- int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path)
2003
- {
2004
- uid_t userids[2] = { geteuid(), 0 };
2005
-
2006
- if (mock_owner) {
2007
- *out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM ||
2008
- mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER);
2009
- return 0;
2010
- }
1994
+ #endif
2011
1995
 
2012
- return fs_path_owner_is(out, path, userids, 2);
1996
+ int git_fs_path_owner_is_current_user(bool *out, const char *path)
1997
+ {
1998
+ return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_CURRENT_USER);
2013
1999
  }
2014
2000
 
2015
- #endif
2001
+ int git_fs_path_owner_is_system(bool *out, const char *path)
2002
+ {
2003
+ return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_ADMINISTRATOR);
2004
+ }
2016
2005
 
2017
2006
  int git_fs_path_find_executable(git_str *fullpath, const char *executable)
2018
2007
  {
@@ -732,18 +732,42 @@ int git_fs_path_normalize_slashes(git_str *out, const char *path);
732
732
  bool git_fs_path_supports_symlinks(const char *dir);
733
733
 
734
734
  typedef enum {
735
- GIT_FS_PATH_MOCK_OWNER_NONE = 0, /* do filesystem lookups as normal */
736
- GIT_FS_PATH_MOCK_OWNER_SYSTEM = 1,
737
- GIT_FS_PATH_MOCK_OWNER_CURRENT_USER = 2,
738
- GIT_FS_PATH_MOCK_OWNER_OTHER = 3
739
- } git_fs_path__mock_owner_t;
735
+ GIT_FS_PATH_OWNER_NONE = 0,
736
+
737
+ /** The file must be owned by the current user. */
738
+ GIT_FS_PATH_OWNER_CURRENT_USER = (1 << 0),
739
+
740
+ /** The file must be owned by the system account. */
741
+ GIT_FS_PATH_OWNER_ADMINISTRATOR = (1 << 1),
742
+
743
+ /**
744
+ * The file may be owned by a system account if the current
745
+ * user is in an administrator group. Windows only; this is
746
+ * a noop on non-Windows systems.
747
+ */
748
+ GIT_FS_PATH_USER_IS_ADMINISTRATOR = (1 << 2),
749
+
750
+ /**
751
+ * The file is owned by the current user, who is running `sudo`.
752
+ */
753
+ GIT_FS_PATH_OWNER_RUNNING_SUDO = (1 << 3),
754
+
755
+ /** The file may be owned by another user. */
756
+ GIT_FS_PATH_OWNER_OTHER = (1 << 4)
757
+ } git_fs_path_owner_t;
740
758
 
741
759
  /**
742
760
  * Sets the mock ownership for files; subsequent calls to
743
- * `git_fs_path_owner_is_*` functions will return this data until cleared
744
- * with `GIT_FS_PATH_MOCK_OWNER_NONE`.
761
+ * `git_fs_path_owner_is_*` functions will return this data until
762
+ * cleared with `GIT_FS_PATH_OWNER_NONE`.
745
763
  */
746
- void git_fs_path__set_owner(git_fs_path__mock_owner_t owner);
764
+ void git_fs_path__set_owner(git_fs_path_owner_t owner);
765
+
766
+ /** Verify that the file in question is owned by the given owner. */
767
+ int git_fs_path_owner_is(
768
+ bool *out,
769
+ const char *path,
770
+ git_fs_path_owner_t owner_type);
747
771
 
748
772
  /**
749
773
  * Verify that the file in question is owned by an administrator or system
@@ -757,12 +781,6 @@ int git_fs_path_owner_is_system(bool *out, const char *path);
757
781
 
758
782
  int git_fs_path_owner_is_current_user(bool *out, const char *path);
759
783
 
760
- /**
761
- * Verify that the file in question is owned by an administrator or system
762
- * account _or_ the current user;
763
- */
764
- int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path);
765
-
766
784
  /**
767
785
  * Search the current PATH for the given executable, returning the full
768
786
  * path if it is found.
@@ -488,7 +488,7 @@ static int read_gitfile(git_str *path_out, const char *file_path)
488
488
  typedef struct {
489
489
  const char *repo_path;
490
490
  git_str tmp;
491
- bool is_safe;
491
+ bool *is_safe;
492
492
  } validate_ownership_data;
493
493
 
494
494
  static int validate_ownership_cb(const git_config_entry *entry, void *payload)
@@ -496,49 +496,102 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload)
496
496
  validate_ownership_data *data = payload;
497
497
 
498
498
  if (strcmp(entry->value, "") == 0)
499
- data->is_safe = false;
499
+ *data->is_safe = false;
500
500
 
501
501
  if (git_fs_path_prettify_dir(&data->tmp, entry->value, NULL) == 0 &&
502
502
  strcmp(data->tmp.ptr, data->repo_path) == 0)
503
- data->is_safe = true;
503
+ *data->is_safe = true;
504
504
 
505
505
  return 0;
506
506
  }
507
507
 
508
- static int validate_ownership(const char *repo_path)
508
+ static int validate_ownership_config(bool *is_safe, const char *path)
509
509
  {
510
- git_config *config = NULL;
511
- validate_ownership_data data = { repo_path, GIT_STR_INIT, false };
512
- bool is_safe;
510
+ validate_ownership_data ownership_data = {
511
+ path, GIT_STR_INIT, is_safe
512
+ };
513
+ git_config *config;
513
514
  int error;
514
515
 
515
- if ((error = git_fs_path_owner_is_current_user(&is_safe, repo_path)) < 0) {
516
- if (error == GIT_ENOTFOUND)
517
- error = 0;
516
+ if (load_global_config(&config) != 0)
517
+ return 0;
518
518
 
519
- goto done;
520
- }
519
+ error = git_config_get_multivar_foreach(config,
520
+ "safe.directory", NULL,
521
+ validate_ownership_cb,
522
+ &ownership_data);
523
+
524
+ git_config_free(config);
525
+ git_str_dispose(&ownership_data.tmp);
526
+
527
+ return error;
528
+ }
529
+
530
+ static int validate_ownership_path(bool *is_safe, const char *path)
531
+ {
532
+ git_fs_path_owner_t owner_level =
533
+ GIT_FS_PATH_OWNER_CURRENT_USER |
534
+ GIT_FS_PATH_USER_IS_ADMINISTRATOR |
535
+ GIT_FS_PATH_OWNER_RUNNING_SUDO;
536
+ int error = 0;
521
537
 
522
- if (is_safe) {
538
+ if (path)
539
+ error = git_fs_path_owner_is(is_safe, path, owner_level);
540
+
541
+ if (error == GIT_ENOTFOUND) {
542
+ *is_safe = true;
523
543
  error = 0;
524
- goto done;
525
544
  }
526
545
 
527
- if (load_global_config(&config) == 0) {
528
- error = git_config_get_multivar_foreach(config, "safe.directory", NULL, validate_ownership_cb, &data);
546
+ return error;
547
+ }
548
+
549
+ static int validate_ownership(git_repository *repo)
550
+ {
551
+ const char *validation_paths[3] = { NULL }, *path;
552
+ size_t validation_len = 0, i;
553
+ bool is_safe = false;
554
+ int error = 0;
555
+
556
+ /*
557
+ * If there's a worktree, validate the permissions to it *and*
558
+ * the git directory, and use the worktree as the configuration
559
+ * key for allowlisting the directory. In a bare setup, only
560
+ * look at the gitdir and use that as the allowlist. So we
561
+ * examine all `validation_paths` but use only the first as
562
+ * the configuration lookup.
563
+ */
564
+
565
+ if (repo->workdir)
566
+ validation_paths[validation_len++] = repo->workdir;
567
+
568
+ if (repo->gitlink)
569
+ validation_paths[validation_len++] = repo->gitlink;
529
570
 
530
- if (!error && data.is_safe)
571
+ validation_paths[validation_len++] = repo->gitdir;
572
+
573
+ for (i = 0; i < validation_len; i++) {
574
+ path = validation_paths[i];
575
+
576
+ if ((error = validate_ownership_path(&is_safe, path)) < 0)
531
577
  goto done;
578
+
579
+ if (!is_safe)
580
+ break;
532
581
  }
533
582
 
534
- git_error_set(GIT_ERROR_CONFIG,
535
- "repository path '%s' is not owned by current user",
536
- repo_path);
537
- error = GIT_EOWNER;
583
+ if (is_safe ||
584
+ (error = validate_ownership_config(&is_safe, validation_paths[0])) < 0)
585
+ goto done;
586
+
587
+ if (!is_safe) {
588
+ git_error_set(GIT_ERROR_CONFIG,
589
+ "repository path '%s' is not owned by current user",
590
+ path);
591
+ error = GIT_EOWNER;
592
+ }
538
593
 
539
594
  done:
540
- git_config_free(config);
541
- git_str_dispose(&data.tmp);
542
595
  return error;
543
596
  }
544
597
 
@@ -915,7 +968,6 @@ int git_repository_open_ext(
915
968
  gitlink = GIT_STR_INIT, commondir = GIT_STR_INIT;
916
969
  git_repository *repo = NULL;
917
970
  git_config *config = NULL;
918
- const char *validation_path;
919
971
  int version = 0;
920
972
 
921
973
  if (flags & GIT_REPOSITORY_OPEN_FROM_ENV)
@@ -974,12 +1026,11 @@ int git_repository_open_ext(
974
1026
  }
975
1027
 
976
1028
  /*
977
- * Ensure that the git directory is owned by the current user.
1029
+ * Ensure that the git directory and worktree are
1030
+ * owned by the current user.
978
1031
  */
979
- validation_path = repo->is_bare ? repo->gitdir : repo->workdir;
980
-
981
1032
  if (git_repository__validate_ownership &&
982
- (error = validate_ownership(validation_path)) < 0)
1033
+ (error = validate_ownership(repo)) < 0)
983
1034
  goto cleanup;
984
1035
 
985
1036
  cleanup:
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rugged
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.3
4
+ version: 1.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Chacon
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-04-16 00:00:00.000000000 Z
12
+ date: 2022-07-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
@@ -712,7 +712,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
712
712
  - !ruby/object:Gem::Version
713
713
  version: '0'
714
714
  requirements: []
715
- rubygems_version: 3.2.33
715
+ rubygems_version: 3.3.7
716
716
  signing_key:
717
717
  specification_version: 4
718
718
  summary: Rugged is a Ruby binding to the libgit2 linkable library