1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
| #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <pwd.h> #include <grp.h>
/** * 权限切换安全检查 */ typedef enum { PRIV_CHECK_SUCCESS = 0, PRIV_CHECK_PERMISSION_DENIED, PRIV_CHECK_INVALID_ID, PRIV_CHECK_OTHER_ERROR } privilege_check_result_t;
/** * 检查权限切换的可行性 */ privilege_check_result_t check_privilege_switch_feasibility(uid_t target_uid, gid_t target_gid) { uid_t current_ruid = getuid(); uid_t current_euid = geteuid(); gid_t current_rgid = getgid(); gid_t current_egid = getegid(); printf("权限切换可行性检查:\n"); printf(" 当前真实UID: %d, 有效UID: %d\n", current_ruid, current_euid); printf(" 当前真实GID: %d, 有效GID: %d\n", current_rgid, current_egid); printf(" 目标UID: %d, 目标GID: %d\n", target_uid, target_gid); // 检查是否已经是目标权限 if (current_ruid == target_uid && current_euid == target_uid && current_rgid == target_gid && current_egid == target_gid) { printf(" ✓ 已经是目标权限\n"); return PRIV_CHECK_SUCCESS; } // 检查是否具有足够权限 if (current_ruid == 0 || current_euid == 0) { printf(" ✓ 具有root权限,可以切换到任意权限\n"); return PRIV_CHECK_SUCCESS; } // 检查普通用户的权限切换限制 if ((target_uid == current_ruid || target_uid == current_euid) && (target_gid == current_rgid || target_gid == current_egid)) { printf(" ✓ 可以切换到目标权限(在允许范围内)\n"); return PRIV_CHECK_SUCCESS; } printf(" ✗ 权限不足,无法切换到目标权限\n"); return PRIV_CHECK_PERMISSION_DENIED; }
/** * 安全的权限切换函数 */ int safe_privilege_switch(uid_t target_uid, gid_t target_gid, int preserve_saved_ids) { uid_t current_ruid = getuid(); uid_t current_euid = geteuid(); gid_t current_rgid = getgid(); gid_t current_egid = getegid(); printf("执行安全权限切换:\n"); printf(" 从 UID %d/%d, GID %d/%d\n", current_ruid, current_euid, current_rgid, current_egid); printf(" 切换到 UID %d, GID %d\n", target_uid, target_gid); // 使用setresuid/setresgid进行完整切换 uid_t new_ruid = target_uid; uid_t new_euid = target_uid; uid_t new_suid = preserve_saved_ids ? -1 : target_uid; gid_t new_rgid = target_gid; gid_t new_egid = target_gid; gid_t new_sgid = preserve_saved_ids ? -1 : target_gid; int result; // 先切换组ID(通常更安全) result = setresgid(new_rgid, new_egid, new_sgid); if (result != 0) { printf(" ✗ 组权限切换失败: %s\n", strerror(errno)); return -1; } // 再切换用户ID result = setresuid(new_ruid, new_euid, new_suid); if (result != 0) { printf(" ✗ 用户权限切换失败: %s\n", strerror(errno)); // 尝试恢复组ID setresgid(current_rgid, current_egid, -1); return -1; } printf(" ✓ 权限切换成功\n"); show_user_group_ids(); return 0; }
/** * 权限切换回滚机制 */ typedef struct { uid_t saved_ruid; uid_t saved_euid; gid_t saved_rgid; gid_t saved_egid; int valid; } rollback_info_t;
/** * 保存回滚信息 */ int save_rollback_info(rollback_info_t *rb) { rb->saved_ruid = getuid(); rb->saved_euid = geteuid(); rb->saved_rgid = getgid(); rb->saved_egid = getegid(); rb->valid = 1; printf("保存回滚信息: UID %d/%d, GID %d/%d\n", rb->saved_ruid, rb->saved_euid, rb->saved_rgid, rb->saved_egid); return 0; }
/** * 执行回滚 */ int perform_rollback(rollback_info_t *rb) { if (!rb->valid) { printf("无效的回滚信息\n"); return -1; } printf("执行权限回滚:\n"); printf(" 目标 UID %d/%d, GID %d/%d\n", rb->saved_ruid, rb->saved_euid, rb->saved_rgid, rb->saved_egid); // 恢复权限 int result = setresuid(rb->saved_ruid, rb->saved_euid, -1); if (result != 0) { printf(" ✗ 用户权限回滚失败: %s\n", strerror(errno)); return -1; } result = setresgid(rb->saved_rgid, rb->saved_egid, -1); if (result != 0) { printf(" ✗ 组权限回滚失败: %s\n", strerror(errno)); return -1; } printf(" ✓ 权限回滚成功\n"); show_user_group_ids(); return 0; }
/** * 演示权限切换最佳实践 */ int demo_best_practices() { rollback_info_t rb = {0}; uid_t current_uid = getuid(); printf("=== 权限切换最佳实践演示 ===\n"); // 1. 保存当前状态用于回滚 printf("1. 保存当前权限状态\n"); if (save_rollback_info(&rb) != 0) { printf("保存回滚信息失败\n"); return -1; } // 2. 检查权限切换可行性 printf("\n2. 检查权限切换可行性\n"); privilege_check_result_t check_result = check_privilege_switch_feasibility(1000, 1000); if (check_result != PRIV_CHECK_SUCCESS) { printf("权限切换不可行,跳过演示\n"); return 0; } // 3. 执行安全权限切换 printf("\n3. 执行安全权限切换\n"); if (current_uid == 0) { // 如果是root,演示降权 printf("当前为root权限,演示安全降权:\n"); if (safe_privilege_switch(1000, 1000, 1) == 0) { printf("✓ 安全降权成功\n"); // 模拟降权后的操作 printf("执行降权后的安全操作...\n"); sleep(2); // 4. 执行权限回滚 printf("\n4. 执行权限回滚\n"); if (perform_rollback(&rb) == 0) { printf("✓ 权限成功回滚到原始状态\n"); } else { printf("✗ 权限回滚失败\n"); } } else { printf("✗ 安全降权失败\n"); } } else { // 如果是普通用户,演示权限检查 printf("当前为普通用户权限,演示权限检查:\n"); // 尝试切换到相同权限(应该成功) if (safe_privilege_switch(current_uid, getgid(), 1) == 0) { printf("✓ 相同权限切换成功\n"); } // 尝试切换到不同权限(应该失败) printf("尝试切换到不同权限:\n"); int result = setresuid(0, 0, 0); // 尝试切换到root if (result == 0) { printf("✗ 意外获得root权限\n"); } else { printf("✓ 权限切换被正确拒绝: %s\n", strerror(errno)); } } // 5. 显示最佳实践总结 printf("\n=== 权限切换最佳实践总结 ===\n"); printf("1. ✓ 始终保存原始权限状态用于回滚\n"); printf("2. ✓ 在切换前检查权限可行性\n"); printf("3. ✓ 使用setresuid/setresgid进行完整控制\n"); printf("4. ✓ 先切换组权限,再切换用户权限\n"); printf("5. ✓ 及时回滚到原始权限状态\n"); printf("6. ✓ 记录权限切换操作日志\n"); printf("7. ✓ 遵循最小权限原则\n"); printf("8. ✓ 在特权操作后立即降权\n"); // 6. 安全审计 printf("\n=== 最终安全审计 ===\n"); uid_t final_ruid = getuid(); uid_t final_euid = geteuid(); gid_t final_rgid = getgid(); gid_t final_egid = getegid(); printf("最终权限状态:\n"); printf(" 真实UID: %d (原始: %d)\n", final_ruid, rb.saved_ruid); printf(" 有效UID: %d (原始: %d)\n", final_euid, rb.saved_euid); printf(" 真实GID: %d (原始: %d)\n", final_rgid, rb.saved_rgid); printf(" 有效GID: %d (原始: %d)\n", final_egid, rb.saved_egid); if (final_ruid == rb.saved_ruid && final_euid == rb.saved_euid && final_rgid == rb.saved_rgid && final_egid == rb.saved_egid) { printf("✓ 权限状态已正确恢复\n"); } else { printf("⚠ 权限状态异常,需要手动检查\n"); } return 0; }
// 辅助函数声明 void show_user_group_ids();
int main() { return demo_best_practices(); }
|