rugged 1.4.3 → 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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