rugged 1.3.2.1 → 1.3.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -2024,9 +2024,9 @@ done:
2024
2024
  return supported;
2025
2025
  }
2026
2026
 
2027
- static git_path__mock_owner_t mock_owner = GIT_PATH_MOCK_OWNER_NONE;
2027
+ static git_path_owner_t mock_owner = GIT_PATH_OWNER_NONE;
2028
2028
 
2029
- void git_path__set_owner(git_path__mock_owner_t owner)
2029
+ void git_path__set_owner(git_path_owner_t owner)
2030
2030
  {
2031
2031
  mock_owner = owner;
2032
2032
  }
@@ -2118,74 +2118,52 @@ static int file_owner_sid(PSID *out, const char *path)
2118
2118
  return error;
2119
2119
  }
2120
2120
 
2121
- int git_path_owner_is_current_user(bool *out, const char *path)
2121
+ int git_path_owner_is(
2122
+ bool *out,
2123
+ const char *path,
2124
+ git_path_owner_t owner_type)
2122
2125
  {
2123
2126
  PSID owner_sid = NULL, user_sid = NULL;
2124
- int error = -1;
2127
+ BOOL is_admin, admin_owned;
2128
+ int error;
2125
2129
 
2126
2130
  if (mock_owner) {
2127
- *out = (mock_owner == GIT_PATH_MOCK_OWNER_CURRENT_USER);
2131
+ *out = ((mock_owner & owner_type) != 0);
2128
2132
  return 0;
2129
2133
  }
2130
2134
 
2131
- if ((error = file_owner_sid(&owner_sid, path)) < 0 ||
2132
- (error = current_user_sid(&user_sid)) < 0)
2135
+ if ((error = file_owner_sid(&owner_sid, path)) < 0)
2133
2136
  goto done;
2134
2137
 
2135
- *out = EqualSid(owner_sid, user_sid);
2136
- error = 0;
2137
-
2138
- done:
2139
- git__free(owner_sid);
2140
- git__free(user_sid);
2141
- return error;
2142
- }
2143
-
2144
- int git_path_owner_is_system(bool *out, const char *path)
2145
- {
2146
- PSID owner_sid;
2147
-
2148
- if (mock_owner) {
2149
- *out = (mock_owner == GIT_PATH_MOCK_OWNER_SYSTEM);
2150
- return 0;
2151
- }
2152
-
2153
- if (file_owner_sid(&owner_sid, path) < 0)
2154
- return -1;
2155
-
2156
- *out = IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
2157
- IsWellKnownSid(owner_sid, WinLocalSystemSid);
2138
+ if ((owner_type & GIT_PATH_OWNER_CURRENT_USER) != 0) {
2139
+ if ((error = current_user_sid(&user_sid)) < 0)
2140
+ goto done;
2158
2141
 
2159
- git__free(owner_sid);
2160
- return 0;
2161
- }
2162
-
2163
- int git_path_owner_is_system_or_current_user(bool *out, const char *path)
2164
- {
2165
- PSID owner_sid = NULL, user_sid = NULL;
2166
- int error = -1;
2167
-
2168
- if (mock_owner) {
2169
- *out = (mock_owner == GIT_PATH_MOCK_OWNER_SYSTEM ||
2170
- mock_owner == GIT_PATH_MOCK_OWNER_CURRENT_USER);
2171
- return 0;
2142
+ if (EqualSid(owner_sid, user_sid)) {
2143
+ *out = true;
2144
+ goto done;
2145
+ }
2172
2146
  }
2173
2147
 
2174
- if (file_owner_sid(&owner_sid, path) < 0)
2175
- goto done;
2148
+ admin_owned =
2149
+ IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
2150
+ IsWellKnownSid(owner_sid, WinLocalSystemSid);
2176
2151
 
2177
- if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
2178
- IsWellKnownSid(owner_sid, WinLocalSystemSid)) {
2179
- *out = 1;
2180
- error = 0;
2152
+ if (admin_owned &&
2153
+ (owner_type & GIT_PATH_OWNER_ADMINISTRATOR) != 0) {
2154
+ *out = true;
2181
2155
  goto done;
2182
2156
  }
2183
2157
 
2184
- if (current_user_sid(&user_sid) < 0)
2158
+ if (admin_owned &&
2159
+ (owner_type & GIT_PATH_USER_IS_ADMINISTRATOR) != 0 &&
2160
+ CheckTokenMembership(NULL, owner_sid, &is_admin) &&
2161
+ is_admin) {
2162
+ *out = true;
2185
2163
  goto done;
2164
+ }
2186
2165
 
2187
- *out = EqualSid(owner_sid, user_sid);
2188
- error = 0;
2166
+ *out = false;
2189
2167
 
2190
2168
  done:
2191
2169
  git__free(owner_sid);
@@ -2195,12 +2173,36 @@ done:
2195
2173
 
2196
2174
  #else
2197
2175
 
2198
- static int path_owner_is(bool *out, const char *path, uid_t *uids, size_t uids_len)
2176
+ static int sudo_uid_lookup(uid_t *out)
2177
+ {
2178
+ git_buf uid_str = GIT_BUF_INIT;
2179
+ int64_t uid;
2180
+ int error;
2181
+
2182
+ if ((error = git__getenv(&uid_str, "SUDO_UID")) == 0 &&
2183
+ (error = git__strntol64(&uid, uid_str.ptr, uid_str.size, NULL, 10)) == 0 &&
2184
+ uid == (int64_t)((uid_t)uid)) {
2185
+ *out = (uid_t)uid;
2186
+ }
2187
+
2188
+ git_buf_dispose(&uid_str);
2189
+ return error;
2190
+ }
2191
+
2192
+ int git_path_owner_is(
2193
+ bool *out,
2194
+ const char *path,
2195
+ git_path_owner_t owner_type)
2199
2196
  {
2200
2197
  struct stat st;
2201
- size_t i;
2198
+ uid_t euid, sudo_uid;
2202
2199
 
2203
- *out = false;
2200
+ if (mock_owner) {
2201
+ *out = ((mock_owner & owner_type) != 0);
2202
+ return 0;
2203
+ }
2204
+
2205
+ euid = geteuid();
2204
2206
 
2205
2207
  if (p_lstat(path, &st) != 0) {
2206
2208
  if (errno == ENOENT)
@@ -2210,51 +2212,38 @@ static int path_owner_is(bool *out, const char *path, uid_t *uids, size_t uids_l
2210
2212
  return -1;
2211
2213
  }
2212
2214
 
2213
- for (i = 0; i < uids_len; i++) {
2214
- if (uids[i] == st.st_uid) {
2215
- *out = true;
2216
- break;
2217
- }
2215
+ if ((owner_type & GIT_PATH_OWNER_CURRENT_USER) != 0 &&
2216
+ st.st_uid == euid) {
2217
+ *out = true;
2218
+ return 0;
2218
2219
  }
2219
2220
 
2220
- return 0;
2221
- }
2222
-
2223
- int git_path_owner_is_current_user(bool *out, const char *path)
2224
- {
2225
- uid_t userid = geteuid();
2226
-
2227
- if (mock_owner) {
2228
- *out = (mock_owner == GIT_PATH_MOCK_OWNER_CURRENT_USER);
2221
+ if ((owner_type & GIT_PATH_OWNER_ADMINISTRATOR) != 0 &&
2222
+ st.st_uid == 0) {
2223
+ *out = true;
2229
2224
  return 0;
2230
2225
  }
2231
2226
 
2232
- return path_owner_is(out, path, &userid, 1);
2233
- }
2234
-
2235
- int git_path_owner_is_system(bool *out, const char *path)
2236
- {
2237
- uid_t userid = 0;
2238
-
2239
- if (mock_owner) {
2240
- *out = (mock_owner == GIT_PATH_MOCK_OWNER_SYSTEM);
2227
+ if ((owner_type & GIT_PATH_OWNER_RUNNING_SUDO) != 0 &&
2228
+ euid == 0 &&
2229
+ sudo_uid_lookup(&sudo_uid) == 0 &&
2230
+ st.st_uid == sudo_uid) {
2231
+ *out = true;
2241
2232
  return 0;
2242
2233
  }
2243
2234
 
2244
- return path_owner_is(out, path, &userid, 1);
2235
+ *out = false;
2236
+ return 0;
2245
2237
  }
2246
2238
 
2247
- int git_path_owner_is_system_or_current_user(bool *out, const char *path)
2248
- {
2249
- uid_t userids[2] = { geteuid(), 0 };
2250
-
2251
- if (mock_owner) {
2252
- *out = (mock_owner == GIT_PATH_MOCK_OWNER_SYSTEM ||
2253
- mock_owner == GIT_PATH_MOCK_OWNER_CURRENT_USER);
2254
- return 0;
2255
- }
2239
+ #endif
2256
2240
 
2257
- return path_owner_is(out, path, userids, 2);
2241
+ int git_path_owner_is_current_user(bool *out, const char *path)
2242
+ {
2243
+ return git_path_owner_is(out, path, GIT_PATH_OWNER_CURRENT_USER);
2258
2244
  }
2259
2245
 
2260
- #endif
2246
+ int git_path_owner_is_system(bool *out, const char *path)
2247
+ {
2248
+ return git_path_owner_is(out, path, GIT_PATH_OWNER_ADMINISTRATOR);
2249
+ }
@@ -723,18 +723,42 @@ int git_path_normalize_slashes(git_buf *out, const char *path);
723
723
  bool git_path_supports_symlinks(const char *dir);
724
724
 
725
725
  typedef enum {
726
- GIT_PATH_MOCK_OWNER_NONE = 0, /* do filesystem lookups as normal */
727
- GIT_PATH_MOCK_OWNER_SYSTEM = 1,
728
- GIT_PATH_MOCK_OWNER_CURRENT_USER = 2,
729
- GIT_PATH_MOCK_OWNER_OTHER = 3
730
- } git_path__mock_owner_t;
726
+ GIT_PATH_OWNER_NONE = 0,
727
+
728
+ /** The file must be owned by the current user. */
729
+ GIT_PATH_OWNER_CURRENT_USER = (1 << 0),
730
+
731
+ /** The file must be owned by the system account. */
732
+ GIT_PATH_OWNER_ADMINISTRATOR = (1 << 1),
733
+
734
+ /**
735
+ * The file may be owned by a system account if the current
736
+ * user is in an administrator group. Windows only; this is
737
+ * a noop on non-Windows systems.
738
+ */
739
+ GIT_PATH_USER_IS_ADMINISTRATOR = (1 << 2),
740
+
741
+ /**
742
+ * The file is owned by the current user, who is running `sudo`.
743
+ */
744
+ GIT_PATH_OWNER_RUNNING_SUDO = (1 << 3),
745
+
746
+ /** The file may be owned by another user. */
747
+ GIT_PATH_OWNER_OTHER = (1 << 4)
748
+ } git_path_owner_t;
731
749
 
732
750
  /**
733
751
  * Sets the mock ownership for files; subsequent calls to
734
- * `git_path_owner_is_*` functions will return this data until cleared
735
- * with `GIT_PATH_MOCK_OWNER_NONE`.
752
+ * `git_path_owner_is_*` functions will return this data until
753
+ * cleared with `GIT_FS_PATH_OWNER_NONE`.
736
754
  */
737
- void git_path__set_owner(git_path__mock_owner_t owner);
755
+ void git_path__set_owner(git_path_owner_t owner);
756
+
757
+ /** Verify that the file in question is owned by the given owner. */
758
+ int git_path_owner_is(
759
+ bool *out,
760
+ const char *path,
761
+ git_path_owner_t owner_type);
738
762
 
739
763
  /**
740
764
  * Verify that the file in question is owned by an administrator or system
@@ -748,10 +772,4 @@ int git_path_owner_is_system(bool *out, const char *path);
748
772
 
749
773
  int git_path_owner_is_current_user(bool *out, const char *path);
750
774
 
751
- /**
752
- * Verify that the file in question is owned by an administrator or system
753
- * account _or_ the current user;
754
- */
755
- int git_path_owner_is_system_or_current_user(bool *out, const char *path);
756
-
757
775
  #endif
@@ -487,7 +487,7 @@ static int read_gitfile(git_buf *path_out, const char *file_path)
487
487
  typedef struct {
488
488
  const char *repo_path;
489
489
  git_buf tmp;
490
- bool is_safe;
490
+ bool *is_safe;
491
491
  } validate_ownership_data;
492
492
 
493
493
  static int validate_ownership_cb(const git_config_entry *entry, void *payload)
@@ -495,49 +495,102 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload)
495
495
  validate_ownership_data *data = payload;
496
496
 
497
497
  if (strcmp(entry->value, "") == 0)
498
- data->is_safe = false;
498
+ *data->is_safe = false;
499
499
 
500
500
  if (git_path_prettify_dir(&data->tmp, entry->value, NULL) == 0 &&
501
501
  strcmp(data->tmp.ptr, data->repo_path) == 0)
502
- data->is_safe = true;
502
+ *data->is_safe = true;
503
503
 
504
504
  return 0;
505
505
  }
506
506
 
507
- static int validate_ownership(const char *repo_path)
507
+ static int validate_ownership_config(bool *is_safe, const char *path)
508
508
  {
509
- git_config *config = NULL;
510
- validate_ownership_data data = { repo_path, GIT_BUF_INIT, false };
511
- bool is_safe;
509
+ validate_ownership_data ownership_data = {
510
+ path, GIT_BUF_INIT, is_safe
511
+ };
512
+ git_config *config;
512
513
  int error;
513
514
 
514
- if ((error = git_path_owner_is_current_user(&is_safe, repo_path)) < 0) {
515
- if (error == GIT_ENOTFOUND)
516
- error = 0;
515
+ if (load_global_config(&config) != 0)
516
+ return 0;
517
517
 
518
- goto done;
519
- }
518
+ error = git_config_get_multivar_foreach(config,
519
+ "safe.directory", NULL,
520
+ validate_ownership_cb,
521
+ &ownership_data);
522
+
523
+ git_config_free(config);
524
+ git_buf_dispose(&ownership_data.tmp);
525
+
526
+ return error;
527
+ }
528
+
529
+ static int validate_ownership_path(bool *is_safe, const char *path)
530
+ {
531
+ git_path_owner_t owner_level =
532
+ GIT_PATH_OWNER_CURRENT_USER |
533
+ GIT_PATH_USER_IS_ADMINISTRATOR |
534
+ GIT_PATH_OWNER_RUNNING_SUDO;
535
+ int error = 0;
520
536
 
521
- if (is_safe) {
537
+ if (path)
538
+ error = git_path_owner_is(is_safe, path, owner_level);
539
+
540
+ if (error == GIT_ENOTFOUND) {
541
+ *is_safe = true;
522
542
  error = 0;
523
- goto done;
524
543
  }
525
544
 
526
- if (load_global_config(&config) == 0) {
527
- error = git_config_get_multivar_foreach(config, "safe.directory", NULL, validate_ownership_cb, &data);
545
+ return error;
546
+ }
547
+
548
+ static int validate_ownership(git_repository *repo)
549
+ {
550
+ const char *validation_paths[3] = { NULL }, *path;
551
+ size_t validation_len = 0, i;
552
+ bool is_safe = false;
553
+ int error = 0;
554
+
555
+ /*
556
+ * If there's a worktree, validate the permissions to it *and*
557
+ * the git directory, and use the worktree as the configuration
558
+ * key for allowlisting the directory. In a bare setup, only
559
+ * look at the gitdir and use that as the allowlist. So we
560
+ * examine all `validation_paths` but use only the first as
561
+ * the configuration lookup.
562
+ */
563
+
564
+ if (repo->workdir)
565
+ validation_paths[validation_len++] = repo->workdir;
566
+
567
+ if (repo->gitlink)
568
+ validation_paths[validation_len++] = repo->gitlink;
528
569
 
529
- if (!error && data.is_safe)
570
+ validation_paths[validation_len++] = repo->gitdir;
571
+
572
+ for (i = 0; i < validation_len; i++) {
573
+ path = validation_paths[i];
574
+
575
+ if ((error = validate_ownership_path(&is_safe, path)) < 0)
530
576
  goto done;
577
+
578
+ if (!is_safe)
579
+ break;
531
580
  }
532
581
 
533
- git_error_set(GIT_ERROR_CONFIG,
534
- "repository path '%s' is not owned by current user",
535
- repo_path);
536
- error = GIT_EOWNER;
582
+ if (is_safe ||
583
+ (error = validate_ownership_config(&is_safe, validation_paths[0])) < 0)
584
+ goto done;
585
+
586
+ if (!is_safe) {
587
+ git_error_set(GIT_ERROR_CONFIG,
588
+ "repository path '%s' is not owned by current user",
589
+ path);
590
+ error = GIT_EOWNER;
591
+ }
537
592
 
538
593
  done:
539
- git_config_free(config);
540
- git_buf_dispose(&data.tmp);
541
594
  return error;
542
595
  }
543
596
 
@@ -914,7 +967,6 @@ int git_repository_open_ext(
914
967
  gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT;
915
968
  git_repository *repo = NULL;
916
969
  git_config *config = NULL;
917
- const char *validation_path;
918
970
  int version = 0;
919
971
 
920
972
  if (flags & GIT_REPOSITORY_OPEN_FROM_ENV)
@@ -973,12 +1025,11 @@ int git_repository_open_ext(
973
1025
  }
974
1026
 
975
1027
  /*
976
- * Ensure that the git directory is owned by the current user.
1028
+ * Ensure that the git directory and worktree are
1029
+ * owned by the current user.
977
1030
  */
978
- validation_path = repo->is_bare ? repo->gitdir : repo->workdir;
979
-
980
1031
  if (git_repository__validate_ownership &&
981
- (error = validate_ownership(validation_path)) < 0)
1032
+ (error = validate_ownership(repo)) < 0)
982
1033
  goto cleanup;
983
1034
 
984
1035
  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.3.2.1
4
+ version: 1.3.2.3
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
@@ -697,7 +697,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
697
697
  - !ruby/object:Gem::Version
698
698
  version: '0'
699
699
  requirements: []
700
- rubygems_version: 3.2.33
700
+ rubygems_version: 3.3.7
701
701
  signing_key:
702
702
  specification_version: 4
703
703
  summary: Rugged is a Ruby binding to the libgit2 linkable library