00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <config.h>
00027
00028 #include <sefs/filesystem.hh>
00029 #include <sefs/query.hh>
00030 #include <selinux/selinux.h>
00031 #include <apol/util.h>
00032
00033 using namespace std;
00034
00035 #include <assert.h>
00036 #include <errno.h>
00037 #include <getopt.h>
00038 #include <iostream>
00039 #include <stdlib.h>
00040
00041 #define COPYRIGHT_INFO "Copyright (C) 2003-2007 Tresys Technology, LLC"
00042
00043 enum OPTIONS
00044 {
00045 OPTION_CONTEXT = 256
00046 };
00047
00048 static struct option const longopts[] = {
00049 {"class", required_argument, NULL, 'c'},
00050 {"type", required_argument, NULL, 't'},
00051 {"user", required_argument, NULL, 'u'},
00052 {"role", required_argument, NULL, 'r'},
00053 {"mls-range", required_argument, NULL, 'm'},
00054 {"path", required_argument, NULL, 'p'},
00055 {"regex", no_argument, NULL, 'R'},
00056 {"context", required_argument, NULL, OPTION_CONTEXT},
00057 {"verbose", no_argument, NULL, 'v'},
00058 {"help", no_argument, NULL, 'h'},
00059 {"version", no_argument, NULL, 'V'},
00060 {NULL, 0, NULL, 0}
00061 };
00062
00063 extern int lsetfilecon_raw(const char *, security_context_t) __attribute__ ((weak));
00064
00065
00066
00067
00068
00069
00070
00071 static int replcon_lsetfilecon(const char *path, security_context_t context)
00072 {
00073 if (lsetfilecon_raw != NULL)
00074 {
00075 return lsetfilecon_raw(path, context);
00076 }
00077 else
00078 {
00079 return lsetfilecon(path, context);
00080 }
00081 }
00082
00083 struct replcon_info
00084 {
00085 bool verbose, mls;
00086 apol_context_t *replcon;
00087 };
00088
00089 static void usage(const char *program_name, bool brief)
00090 {
00091 cout << "Usage: " << program_name << " NEW_CONTEXT DIR [OPTIONS] [EXPRESSION]" << endl << endl;
00092 if (brief)
00093 {
00094 cout << "\tTry " << program_name << " --help for more help." << endl << endl;
00095 return;
00096 }
00097
00098 cout << "Replace SELinux file contexts for files matching a given context." << endl << endl;
00099
00100 cout << "REQUIRED ARGUMENTS :" << endl;
00101 cout << " NEW_CONTEXT partial or full context to relabel" << endl;
00102 cout << " DIR starting directory to replace" << endl;
00103 cout << endl;
00104 cout << "EXPRESSION:" << endl;
00105 cout << " -t TYPE, --type=TYPE find contexts with type TYPE" << endl;
00106 cout << " -u USER, --user=USER find contexts with user USER" << endl;
00107 cout << " -r ROLE, --role=ROLE find contexts with role ROLE" << endl;
00108 cout << " -m RANGE, --mls-range=RANGE find contexts with MLS range RANGE" << endl;
00109 cout << " --context=CONTEXT partial or full context to find" << endl;
00110 cout << " (overrides expression options above)" << endl;
00111 cout << " -p PATH, --path=PATH find files in PATH" << endl;
00112 cout << " -c CLASS, --class=CLASS find files of object class CLASS" << endl;
00113 cout << endl;
00114
00115 cout << "OPTIONS:" << endl;
00116 cout << " -R, --regex enable regular expressions" << endl;
00117 cout << " -v, --verbose show context of matching files" << endl;
00118 cout << " -h, --help print this help text and exit" << endl;
00119 cout << " -V, --version print version information and exit" << endl;
00120 cout << endl;
00121 cout << "If the fclist does not contain MLS ranges and -m was given," << endl;
00122 cout << "then the search will return nothing." << endl;
00123 cout << endl;
00124 cout << "NEW_CONTEXT is as a colon separated list of user, role, type, and MLS range" << endl;
00125 cout << "such as follows: user_u:object_r:user_t:s0. If a field is not specified," << endl;
00126 cout << "that portion of the context will not be replaced." << endl;
00127 cout << "Examples:" << endl;
00128 cout << " replcon ::type_t: ." << endl;
00129 cout << " Replace all files and subdirectories in current directory with" << endl;
00130 cout << " type type_t, recursing within the directory." << endl;
00131 cout << " replcon -u user_u *:role_r:* ." << endl;
00132 cout << " Replace files that contain user_u with role role_r." << endl;
00133 cout << " replcon --context ::type_t:so :::s0:c0 /tmp" << endl;
00134 cout << " Replace files with type type_t and level s0 in /tmp with MLS" << endl;
00135 cout << " range s0:c0." << endl;
00136 }
00137
00138 static int replace_entry(sefs_fclist * fclist, const sefs_entry * e, void *arg)
00139 {
00140 struct replcon_info *r = static_cast < struct replcon_info *>(arg);
00141 const apol_context_t *scon = e->context();
00142 const char *user, *role, *type;
00143 char *con_str = NULL;
00144 size_t len = 0;
00145
00146
00147 if ((user = apol_context_get_user(r->replcon)) == NULL)
00148 {
00149 user = apol_context_get_user(scon);
00150 }
00151 if ((role = apol_context_get_role(r->replcon)) == NULL)
00152 {
00153 role = apol_context_get_role(scon);
00154 }
00155 if ((type = apol_context_get_type(r->replcon)) == NULL)
00156 {
00157 type = apol_context_get_type(scon);
00158 }
00159 if (apol_str_appendf(&con_str, &len, "%s:%s:%s", user, role, type) < 0)
00160 {
00161 return -1;
00162 }
00163 if (r->mls)
00164 {
00165 const apol_mls_range_t *apol_range = NULL;
00166 char *range = NULL;
00167 if ((apol_range = apol_context_get_range(r->replcon)) == NULL)
00168 {
00169 apol_range = apol_context_get_range(scon);
00170 }
00171 if ((range = apol_mls_range_render(NULL, apol_range)) == NULL || apol_str_appendf(&con_str, &len, ":%s", range) < 0)
00172 {
00173 free(range);
00174 free(con_str);
00175 return -1;
00176 }
00177 free(range);
00178 }
00179
00180 if (r->verbose)
00181 {
00182 char *lcon = NULL, *rcon = NULL;
00183 if (r->mls)
00184 {
00185 lcon = apol_context_render(NULL, r->replcon);
00186 rcon = apol_context_render(NULL, scon);
00187 }
00188 else
00189 {
00190 if (asprintf(&lcon, "%s:%s:%s",
00191 apol_context_get_user(r->replcon),
00192 apol_context_get_role(r->replcon), apol_context_get_type(r->replcon)) < 0)
00193 {
00194 lcon = NULL;
00195 }
00196 if (asprintf(&rcon, "%s:%s:%s",
00197 apol_context_get_user(scon), apol_context_get_role(scon), apol_context_get_type(scon)) < 0)
00198 {
00199 rcon = NULL;
00200 }
00201 }
00202 if (lcon == NULL || rcon == NULL)
00203 {
00204 free(lcon);
00205 free(rcon);
00206 return -1;
00207 }
00208 printf("%s: %s --> %s\n", e->path(), lcon, rcon);
00209 free(lcon);
00210 free(rcon);
00211 }
00212
00213
00214
00215 if (replcon_lsetfilecon(e->path(), con_str) != 0)
00216 {
00217 cerr << "Could not set context " << con_str << " for file " << e->path() << "." << endl;
00218 free(con_str);
00219 return -1;
00220 }
00221
00222 free(con_str);
00223 return 0;
00224 }
00225
00226 int main(int argc, char *argv[])
00227 {
00228 int optc;
00229 struct replcon_info r;
00230
00231 r.verbose = false;
00232 r.replcon = NULL;
00233 sefs_query *query = new sefs_query();
00234
00235 apol_context_t *context = NULL;
00236 try
00237 {
00238 while ((optc = getopt_long(argc, argv, "t:u:r:m:p:c:RvhV", longopts, NULL)) != -1)
00239 {
00240 switch (optc)
00241 {
00242 case 't':
00243 if (context == NULL)
00244 {
00245 query->type(optarg, false);
00246 }
00247 break;
00248 case 'u':
00249 if (context == NULL)
00250 {
00251 query->user(optarg);
00252 }
00253 break;
00254 case 'r':
00255 if (context == NULL)
00256 {
00257 query->role(optarg);
00258 }
00259 break;
00260 case 'm':
00261 if (context == NULL)
00262 {
00263 query->range(optarg, APOL_QUERY_EXACT);
00264 }
00265 break;
00266 case OPTION_CONTEXT:
00267 if ((context = apol_context_create_from_literal(optarg)) == NULL)
00268 {
00269 cerr << "Could not create source context." << endl;
00270 throw runtime_error(strerror(errno));
00271 }
00272 break;
00273 case 'p':
00274 query->path(optarg);
00275 break;
00276 case 'c':
00277 query->objectClass(optarg);
00278 break;
00279 case 'R':
00280 query->regex(true);
00281 break;
00282 case 'v':
00283 r.verbose = true;
00284 break;
00285 case 'h':
00286 usage(argv[0], false);
00287 exit(0);
00288 case 'V':
00289 cout << "replcon " << VERSION << endl << COPYRIGHT_INFO << endl;
00290 exit(0);
00291 default:
00292 usage(argv[0], true);
00293 exit(1);
00294 }
00295 if (context != NULL)
00296 {
00297 query->user(apol_context_get_user(context));
00298 query->role(apol_context_get_role(context));
00299 query->type(apol_context_get_type(context), false);
00300 if (apol_context_get_range(context) != NULL)
00301 {
00302 char *rng = apol_mls_range_render(NULL, apol_context_get_range(context));
00303 query->range(rng, APOL_QUERY_EXACT);
00304 free(rng);
00305 }
00306 else
00307 {
00308 query->range(NULL, APOL_QUERY_EXACT);
00309 }
00310 }
00311 }
00312 }
00313 catch(bad_alloc)
00314 {
00315 cerr << strerror(errno) << endl;
00316 apol_context_destroy(&context);
00317 delete query;
00318 exit(-1);
00319 }
00320 apol_context_destroy(&context);
00321
00322 if (optind + 2 != argc)
00323 {
00324 usage(argv[0], 1);
00325 delete query;
00326 exit(-1);
00327 }
00328
00329 sefs_fclist *fclist = NULL;
00330 try
00331 {
00332 fclist = new sefs_filesystem(argv[optind + 1], NULL, NULL);
00333 r.mls = fclist->isMLS();
00334
00335 if ((r.replcon = apol_context_create_from_literal(argv[optind])) == NULL)
00336 {
00337 cerr << "Could not create replacement context." << endl;
00338 throw runtime_error(strerror(errno));
00339 }
00340
00341 if (fclist->runQueryMap(query, replace_entry, &r) < 0)
00342 {
00343 throw runtime_error(strerror(errno));
00344 }
00345 }
00346 catch(...)
00347 {
00348 delete query;
00349 delete fclist;
00350 apol_context_destroy(&(r.replcon));
00351 exit(-1);
00352 }
00353
00354 delete query;
00355 delete fclist;
00356 apol_context_destroy(&(r.replcon));
00357 return 0;
00358 }