pam_selinux.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. /******************************************************************************
  2. * A module for Linux-PAM that will set the default security context after login
  3. * via PAM.
  4. *
  5. * Copyright (c) 2003-2008 Red Hat, Inc.
  6. * Written by Dan Walsh <dwalsh@redhat.com>
  7. * Additional improvements by Tomas Mraz <tmraz@redhat.com>
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, and the entire permission notice in its entirety,
  14. * including the disclaimer of warranties.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. * 3. The name of the author may not be used to endorse or promote
  19. * products derived from this software without specific prior
  20. * written permission.
  21. *
  22. * ALTERNATIVELY, this product may be distributed under the terms of
  23. * the GNU Public License, in which case the provisions of the GPL are
  24. * required INSTEAD OF the above restrictions. (This clause is
  25. * necessary due to a potential bad interaction between the GPL and
  26. * the restrictions contained in a BSD-style copyright.)
  27. *
  28. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  29. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  32. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  33. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  34. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  36. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  37. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  38. * OF THE POSSIBILITY OF SUCH DAMAGE.
  39. */
  40. #include "config.h"
  41. #include <errno.h>
  42. #include <limits.h>
  43. #include <pwd.h>
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <unistd.h>
  48. #include <sys/types.h>
  49. #include <sys/stat.h>
  50. #include <fcntl.h>
  51. #include <syslog.h>
  52. #include <security/pam_modules.h>
  53. #include <security/_pam_macros.h>
  54. #include <security/pam_modutil.h>
  55. #include <security/pam_ext.h>
  56. #include "pam_inline.h"
  57. #include <selinux/selinux.h>
  58. #include <selinux/get_context_list.h>
  59. #include <selinux/context.h>
  60. #include <selinux/get_default_type.h>
  61. #ifdef HAVE_LIBAUDIT
  62. #include <libaudit.h>
  63. #include <sys/select.h>
  64. #endif
  65. /* Send audit message */
  66. static void
  67. send_audit_message(const pam_handle_t *pamh, int success, const char *default_context,
  68. const char *selected_context)
  69. {
  70. #ifdef HAVE_LIBAUDIT
  71. char *msg = NULL;
  72. int audit_fd = audit_open();
  73. char *default_raw = NULL;
  74. char *selected_raw = NULL;
  75. const void *tty = NULL, *rhost = NULL;
  76. if (audit_fd < 0) {
  77. if (errno == EINVAL || errno == EPROTONOSUPPORT ||
  78. errno == EAFNOSUPPORT) {
  79. goto fallback; /* No audit support in kernel */
  80. }
  81. pam_syslog(pamh, LOG_ERR, "Error connecting to audit system: %m");
  82. goto fallback;
  83. }
  84. (void)pam_get_item(pamh, PAM_TTY, &tty);
  85. (void)pam_get_item(pamh, PAM_RHOST, &rhost);
  86. if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) {
  87. pam_syslog(pamh, LOG_ERR, "Error translating default context '%s'.", default_context);
  88. default_raw = NULL;
  89. }
  90. if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) {
  91. pam_syslog(pamh, LOG_ERR, "Error translating selected context '%s'.", selected_context);
  92. selected_raw = NULL;
  93. }
  94. if (asprintf(&msg, "pam: default-context=%s selected-context=%s",
  95. default_raw ? default_raw : (default_context ? default_context : "?"),
  96. selected_raw ? selected_raw : (selected_context ? selected_context : "?")) < 0) {
  97. msg = NULL; /* asprintf leaves msg in undefined state on failure */
  98. pam_syslog(pamh, LOG_ERR, "Error allocating memory.");
  99. goto fallback;
  100. }
  101. if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE,
  102. msg, rhost, NULL, tty, success) <= 0) {
  103. pam_syslog(pamh, LOG_ERR, "Error sending audit message: %m");
  104. goto fallback;
  105. }
  106. goto cleanup;
  107. fallback:
  108. #endif /* HAVE_LIBAUDIT */
  109. pam_syslog(pamh, LOG_NOTICE, "pam: default-context=%s selected-context=%s success %d",
  110. default_context, selected_context, success);
  111. #ifdef HAVE_LIBAUDIT
  112. cleanup:
  113. free(msg);
  114. freecon(default_raw);
  115. freecon(selected_raw);
  116. if (audit_fd >= 0)
  117. close(audit_fd);
  118. #endif /* HAVE_LIBAUDIT */
  119. }
  120. static int
  121. send_text (pam_handle_t *pamh, const char *text, int debug)
  122. {
  123. if (debug)
  124. pam_syslog(pamh, LOG_NOTICE, "%s", text);
  125. return pam_info (pamh, "%s", text);
  126. }
  127. /*
  128. * This function sends a message to the user and gets the response. The caller
  129. * is responsible for freeing the responses.
  130. */
  131. static int
  132. query_response (pam_handle_t *pamh, const char *text, const char *def,
  133. char **response, int debug)
  134. {
  135. int rc;
  136. if (def)
  137. rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s [%s] ", text, def);
  138. else
  139. rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s ", text);
  140. if (*response == NULL) {
  141. rc = PAM_CONV_ERR;
  142. }
  143. if (rc != PAM_SUCCESS) {
  144. pam_syslog(pamh, LOG_WARNING, "No response to query: %s", text);
  145. } else if (debug)
  146. pam_syslog(pamh, LOG_NOTICE, "%s %s", text, *response);
  147. return rc;
  148. }
  149. static char *
  150. config_context (pam_handle_t *pamh, const char *defaultcon, int use_current_range, int debug)
  151. {
  152. char *newcon = NULL;
  153. context_t new_context;
  154. int mls_enabled = is_selinux_mls_enabled();
  155. char *response=NULL;
  156. char *type=NULL;
  157. char resp_val = 0;
  158. pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("The default security context is %s."), defaultcon);
  159. while (1) {
  160. if (query_response(pamh,
  161. _("Would you like to enter a different role or level?"), "n",
  162. &response, debug) == PAM_SUCCESS) {
  163. resp_val = response[0];
  164. _pam_drop(response);
  165. } else {
  166. resp_val = 'N';
  167. }
  168. if ((resp_val == 'y') || (resp_val == 'Y'))
  169. {
  170. if ((new_context = context_new(defaultcon)) == NULL)
  171. goto fail_set;
  172. /* Allow the user to enter role and level individually */
  173. if (query_response(pamh, _("role:"), context_role_get(new_context),
  174. &response, debug) == PAM_SUCCESS && response[0]) {
  175. if (get_default_type(response, &type)) {
  176. pam_prompt(pamh, PAM_ERROR_MSG, NULL,
  177. _("There is no default type for role %s."), response);
  178. _pam_drop(response);
  179. continue;
  180. } else {
  181. if (context_role_set(new_context, response))
  182. goto fail_set;
  183. if (context_type_set (new_context, type))
  184. goto fail_set;
  185. _pam_drop(type);
  186. }
  187. }
  188. _pam_drop(response);
  189. if (mls_enabled)
  190. {
  191. if (use_current_range) {
  192. char *mycon = NULL;
  193. context_t my_context;
  194. if (getcon(&mycon) != 0)
  195. goto fail_set;
  196. my_context = context_new(mycon);
  197. if (my_context == NULL) {
  198. freecon(mycon);
  199. goto fail_set;
  200. }
  201. freecon(mycon);
  202. if (context_range_set(new_context, context_range_get(my_context))) {
  203. context_free(my_context);
  204. goto fail_set;
  205. }
  206. context_free(my_context);
  207. } else if (query_response(pamh, _("level:"), context_range_get(new_context),
  208. &response, debug) == PAM_SUCCESS && response[0]) {
  209. if (context_range_set(new_context, response))
  210. goto fail_set;
  211. }
  212. _pam_drop(response);
  213. }
  214. if (debug)
  215. pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", context_str(new_context));
  216. /* Get the string value of the context and see if it is valid. */
  217. if (!security_check_context(context_str(new_context))) {
  218. newcon = strdup(context_str(new_context));
  219. if (newcon == NULL)
  220. goto fail_set;
  221. context_free(new_context);
  222. /* we have to check that this user is allowed to go into the
  223. range they have specified ... role is tied to an seuser, so that'll
  224. be checked at setexeccon time */
  225. if (mls_enabled &&
  226. selinux_check_access(defaultcon, newcon, "context", "contains", NULL) != 0) {
  227. pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);
  228. send_audit_message(pamh, 0, defaultcon, newcon);
  229. free(newcon);
  230. goto fail_range;
  231. }
  232. return newcon;
  233. }
  234. else {
  235. send_audit_message(pamh, 0, defaultcon, context_str(new_context));
  236. send_text(pamh,_("This is not a valid security context."),debug);
  237. }
  238. context_free(new_context); /* next time around allocates another */
  239. }
  240. else
  241. return strdup(defaultcon);
  242. } /* end while */
  243. return NULL;
  244. fail_set:
  245. free(type);
  246. _pam_drop(response);
  247. context_free (new_context);
  248. send_audit_message(pamh, 0, defaultcon, NULL);
  249. fail_range:
  250. return NULL;
  251. }
  252. static char *
  253. context_from_env (pam_handle_t *pamh, const char *defaultcon, int env_params, int use_current_range, int debug)
  254. {
  255. char *newcon = NULL;
  256. context_t new_context;
  257. context_t my_context = NULL;
  258. int mls_enabled = is_selinux_mls_enabled();
  259. const char *env = NULL;
  260. char *type = NULL;
  261. int fail = 1;
  262. if ((new_context = context_new(defaultcon)) == NULL)
  263. goto fail_set;
  264. if (env_params && (env = pam_getenv(pamh, "SELINUX_ROLE_REQUESTED")) != NULL && env[0] != '\0') {
  265. if (debug)
  266. pam_syslog(pamh, LOG_NOTICE, "Requested role: %s", env);
  267. if (get_default_type(env, &type)) {
  268. pam_syslog(pamh, LOG_NOTICE, "No default type for role %s", env);
  269. goto fail_set;
  270. } else {
  271. if (context_role_set(new_context, env))
  272. goto fail_set;
  273. if (context_type_set(new_context, type))
  274. goto fail_set;
  275. }
  276. }
  277. if (mls_enabled) {
  278. if ((env = pam_getenv(pamh, "SELINUX_USE_CURRENT_RANGE")) != NULL && env[0] == '1') {
  279. if (debug)
  280. pam_syslog(pamh, LOG_NOTICE, "SELINUX_USE_CURRENT_RANGE is set");
  281. use_current_range = 1;
  282. }
  283. if (use_current_range) {
  284. char *mycon = NULL;
  285. if (getcon(&mycon) != 0)
  286. goto fail_set;
  287. my_context = context_new(mycon);
  288. if (my_context == NULL) {
  289. freecon(mycon);
  290. goto fail_set;
  291. }
  292. freecon(mycon);
  293. env = context_range_get(my_context);
  294. } else {
  295. env = pam_getenv(pamh, "SELINUX_LEVEL_REQUESTED");
  296. }
  297. if (env != NULL && env[0] != '\0') {
  298. if (debug)
  299. pam_syslog(pamh, LOG_NOTICE, "Requested level: %s", env);
  300. if (context_range_set(new_context, env))
  301. goto fail_set;
  302. }
  303. }
  304. newcon = strdup(context_str(new_context));
  305. if (newcon == NULL)
  306. goto fail_set;
  307. if (debug)
  308. pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", newcon);
  309. /* Get the string value of the context and see if it is valid. */
  310. if (security_check_context(newcon)) {
  311. pam_syslog(pamh, LOG_NOTICE, "Not a valid security context %s", newcon);
  312. goto fail_set;
  313. }
  314. /* we have to check that this user is allowed to go into the
  315. range they have specified ... role is tied to an seuser, so that'll
  316. be checked at setexeccon time */
  317. if (mls_enabled &&
  318. selinux_check_access(defaultcon, newcon, "context", "contains", NULL) != 0) {
  319. pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);
  320. goto fail_set;
  321. }
  322. fail = 0;
  323. fail_set:
  324. free(type);
  325. context_free(my_context);
  326. context_free(new_context);
  327. if (fail) {
  328. send_audit_message(pamh, 0, defaultcon, newcon);
  329. freecon(newcon);
  330. newcon = NULL;
  331. }
  332. return newcon;
  333. }
  334. #define DATANAME "pam_selinux_context"
  335. typedef struct {
  336. char *exec_context;
  337. char *prev_exec_context;
  338. char *default_user_context;
  339. char *tty_context;
  340. char *prev_tty_context;
  341. char *tty_path;
  342. } module_data_t;
  343. static void
  344. free_module_data(module_data_t *data)
  345. {
  346. free(data->tty_path);
  347. freecon(data->prev_tty_context);
  348. freecon(data->tty_context);
  349. freecon(data->default_user_context);
  350. freecon(data->prev_exec_context);
  351. if (data->exec_context != data->default_user_context)
  352. freecon(data->exec_context);
  353. memset(data, 0, sizeof(*data));
  354. free(data);
  355. }
  356. static void
  357. cleanup(pam_handle_t *pamh UNUSED, void *data, int err UNUSED)
  358. {
  359. free_module_data(data);
  360. }
  361. static const module_data_t *
  362. get_module_data(const pam_handle_t *pamh)
  363. {
  364. const void *data;
  365. return (pam_get_data(pamh, DATANAME, &data) == PAM_SUCCESS) ? data : NULL;
  366. }
  367. static const char *
  368. get_item(const pam_handle_t *pamh, int item_type)
  369. {
  370. const void *item;
  371. return (pam_get_item(pamh, item_type, &item) == PAM_SUCCESS) ? item : NULL;
  372. }
  373. static int
  374. set_exec_context(const pam_handle_t *pamh, const char *context)
  375. {
  376. if (setexeccon(context) == 0)
  377. return 0;
  378. pam_syslog(pamh, LOG_ERR, "Setting executable context \"%s\" failed: %m",
  379. context ? context : "");
  380. return -1;
  381. }
  382. static int
  383. set_file_context(const pam_handle_t *pamh, const char *context,
  384. const char *file)
  385. {
  386. if (!file)
  387. return 0;
  388. if (setfilecon(file, context) == 0 || errno == ENOENT)
  389. return 0;
  390. pam_syslog(pamh, LOG_ERR, "Setting file context \"%s\" failed for %s: %m",
  391. context ? context : "", file);
  392. return -1;
  393. }
  394. static int
  395. compute_exec_context(pam_handle_t *pamh, module_data_t *data,
  396. int select_context, int use_current_range,
  397. int env_params, int debug)
  398. {
  399. const char *username;
  400. #ifdef HAVE_GETSEUSER
  401. const char *service;
  402. #endif
  403. char *seuser = NULL;
  404. char *level = NULL;
  405. char **contextlist = NULL;
  406. int num_contexts = 0;
  407. const struct passwd *pwd;
  408. if (!(username = get_item(pamh, PAM_USER))) {
  409. pam_syslog(pamh, LOG_ERR, "Cannot obtain the user name");
  410. return PAM_USER_UNKNOWN;
  411. }
  412. if ((pwd = pam_modutil_getpwnam(pamh, username)) != NULL) {
  413. username = pwd->pw_name;
  414. } /* ignore error and keep using original username */
  415. /* compute execute context */
  416. #ifdef HAVE_GETSEUSER
  417. if (!(service = get_item(pamh, PAM_SERVICE))) {
  418. pam_syslog(pamh, LOG_ERR, "Cannot obtain the service name");
  419. return PAM_SESSION_ERR;
  420. }
  421. if (getseuser(username, service, &seuser, &level) == 0) {
  422. #else
  423. if (getseuserbyname(username, &seuser, &level) == 0) {
  424. #endif
  425. num_contexts = get_ordered_context_list_with_level(seuser, level, NULL,
  426. &contextlist);
  427. if (debug)
  428. pam_syslog(pamh, LOG_DEBUG, "Username= %s SELinux User= %s Level= %s",
  429. username, seuser, level);
  430. free(level);
  431. }
  432. if (num_contexts > 0) {
  433. free(seuser);
  434. data->default_user_context = strdup(contextlist[0]);
  435. freeconary(contextlist);
  436. if (!data->default_user_context) {
  437. pam_syslog(pamh, LOG_CRIT, "Out of memory");
  438. return PAM_BUF_ERR;
  439. }
  440. data->exec_context = data->default_user_context;
  441. if (select_context)
  442. data->exec_context = config_context(pamh, data->default_user_context,
  443. use_current_range, debug);
  444. else if (env_params || use_current_range)
  445. data->exec_context = context_from_env(pamh, data->default_user_context,
  446. env_params, use_current_range,
  447. debug);
  448. }
  449. if (!data->exec_context) {
  450. pam_syslog(pamh, LOG_ERR, "Unable to get valid context for %s", username);
  451. pam_prompt(pamh, PAM_ERROR_MSG, NULL,
  452. _("A valid context for %s could not be obtained."), username);
  453. }
  454. if (getexeccon(&data->prev_exec_context) < 0)
  455. data->prev_exec_context = NULL;
  456. return PAM_SUCCESS;
  457. }
  458. static int
  459. compute_tty_context(const pam_handle_t *pamh, module_data_t *data)
  460. {
  461. const char *tty = get_item(pamh, PAM_TTY);
  462. security_class_t tclass;
  463. if (!tty || !*tty || !strcmp(tty, "ssh")
  464. || pam_str_skip_prefix(tty, "NODEV") != NULL) {
  465. tty = ttyname(STDIN_FILENO);
  466. if (!tty || !*tty)
  467. tty = ttyname(STDOUT_FILENO);
  468. if (!tty || !*tty)
  469. tty = ttyname(STDERR_FILENO);
  470. if (!tty || !*tty)
  471. return PAM_SUCCESS;
  472. }
  473. if (pam_str_skip_prefix(tty, "/dev/") == NULL) {
  474. if (asprintf(&data->tty_path, "%s%s", "/dev/", tty) < 0)
  475. data->tty_path = NULL;
  476. } else {
  477. data->tty_path = strdup(tty);
  478. }
  479. if (!data->tty_path) {
  480. pam_syslog(pamh, LOG_CRIT, "Out of memory");
  481. return PAM_BUF_ERR;
  482. }
  483. if (getfilecon(data->tty_path, &data->prev_tty_context) < 0) {
  484. data->prev_tty_context = NULL;
  485. if (errno == ENOENT) {
  486. free(data->tty_path);
  487. data->tty_path = NULL;
  488. return PAM_SUCCESS;
  489. }
  490. pam_syslog(pamh, LOG_ERR, "Failed to get current context for %s: %m",
  491. data->tty_path);
  492. return (security_getenforce() == 1) ? PAM_SESSION_ERR : PAM_SUCCESS;
  493. }
  494. tclass = string_to_security_class("chr_file");
  495. if (tclass == 0) {
  496. pam_syslog(pamh, LOG_ERR, "Failed to get chr_file security class");
  497. freecon(data->prev_tty_context);
  498. data->prev_tty_context = NULL;
  499. free(data->tty_path);
  500. data->tty_path = NULL;
  501. return (security_getenforce() == 1) ? PAM_SESSION_ERR : PAM_SUCCESS;
  502. }
  503. if (security_compute_relabel(data->exec_context, data->prev_tty_context,
  504. tclass, &data->tty_context)) {
  505. data->tty_context = NULL;
  506. pam_syslog(pamh, LOG_ERR, "Failed to compute new context for %s: %m",
  507. data->tty_path);
  508. freecon(data->prev_tty_context);
  509. data->prev_tty_context = NULL;
  510. free(data->tty_path);
  511. data->tty_path = NULL;
  512. return (security_getenforce() == 1) ? PAM_SESSION_ERR : PAM_SUCCESS;
  513. }
  514. return PAM_SUCCESS;
  515. }
  516. static int
  517. restore_context(const pam_handle_t *pamh, const module_data_t *data, int debug)
  518. {
  519. int err;
  520. if (!data) {
  521. if (debug)
  522. pam_syslog(pamh, LOG_NOTICE, "No context to restore");
  523. return PAM_SUCCESS;
  524. }
  525. if (debug && data->tty_path)
  526. pam_syslog(pamh, LOG_NOTICE,
  527. "Restore file context of tty %s: [%s] -> [%s]",
  528. data->tty_path,
  529. data->tty_context ? data->tty_context : "",
  530. data->prev_tty_context ? data->prev_tty_context : "");
  531. err = set_file_context(pamh, data->prev_tty_context, data->tty_path);
  532. if (debug)
  533. pam_syslog(pamh, LOG_NOTICE, "Restore executable context: [%s] -> [%s]",
  534. data->exec_context,
  535. data->prev_exec_context ? data->prev_exec_context : "");
  536. err |= set_exec_context(pamh, data->prev_exec_context);
  537. if (err && security_getenforce() == 1)
  538. return PAM_SESSION_ERR;
  539. return PAM_SUCCESS;
  540. }
  541. static int
  542. set_context(pam_handle_t *pamh, const module_data_t *data,
  543. int debug, int verbose)
  544. {
  545. int rc, err;
  546. if (debug && data->tty_path)
  547. pam_syslog(pamh, LOG_NOTICE, "Set file context of tty %s: [%s] -> [%s]",
  548. data->tty_path,
  549. data->prev_tty_context ? data->prev_tty_context : "",
  550. data->tty_context ? data->tty_context : "");
  551. err = set_file_context(pamh, data->tty_context, data->tty_path);
  552. if (debug)
  553. pam_syslog(pamh, LOG_NOTICE, "Set executable context: [%s] -> [%s]",
  554. data->prev_exec_context ? data->prev_exec_context : "",
  555. data->exec_context);
  556. rc = set_exec_context(pamh, data->exec_context);
  557. err |= rc;
  558. send_audit_message(pamh, !rc, data->default_user_context, data->exec_context);
  559. if (verbose && !rc) {
  560. char msg[PATH_MAX];
  561. snprintf(msg, sizeof(msg),
  562. _("Security context %s has been assigned."), data->exec_context);
  563. send_text(pamh, msg, debug);
  564. }
  565. #ifdef HAVE_SETKEYCREATECON
  566. if (debug)
  567. pam_syslog(pamh, LOG_NOTICE, "Set key creation context to %s",
  568. data->exec_context ? data->exec_context : "");
  569. rc = setkeycreatecon(data->exec_context);
  570. err |= rc;
  571. if (rc)
  572. pam_syslog(pamh, LOG_ERR, "Setting key creation context %s failed: %m",
  573. data->exec_context ? data->exec_context : "");
  574. if (verbose && !rc) {
  575. char msg[PATH_MAX];
  576. snprintf(msg, sizeof(msg),
  577. _("Key creation context %s has been assigned."), data->exec_context);
  578. send_text(pamh, msg, debug);
  579. }
  580. #endif
  581. if (err && security_getenforce() == 1)
  582. return PAM_SESSION_ERR;
  583. return PAM_SUCCESS;
  584. }
  585. static int
  586. create_context(pam_handle_t *pamh, int argc, const char **argv,
  587. int debug, int verbose)
  588. {
  589. int i;
  590. int ttys = 1;
  591. int select_context = 0;
  592. int use_current_range = 0;
  593. int env_params = 0;
  594. module_data_t *data;
  595. /* Parse arguments. */
  596. for (i = 0; i < argc; i++) {
  597. if (strcmp(argv[i], "nottys") == 0) {
  598. ttys = 0;
  599. }
  600. if (strcmp(argv[i], "select_context") == 0) {
  601. select_context = 1;
  602. }
  603. if (strcmp(argv[i], "use_current_range") == 0) {
  604. use_current_range = 1;
  605. }
  606. if (strcmp(argv[i], "env_params") == 0) {
  607. env_params = 1;
  608. }
  609. }
  610. if (is_selinux_enabled() <= 0) {
  611. if (debug)
  612. pam_syslog(pamh, LOG_NOTICE, "SELinux is not enabled");
  613. return PAM_SUCCESS;
  614. }
  615. if (select_context && env_params) {
  616. pam_syslog(pamh, LOG_ERR,
  617. "select_context cannot be used with env_params");
  618. select_context = 0;
  619. }
  620. if (!(data = calloc(1, sizeof(*data)))) {
  621. pam_syslog(pamh, LOG_CRIT, "Out of memory");
  622. return PAM_BUF_ERR;
  623. }
  624. i = compute_exec_context(pamh, data, select_context, use_current_range,
  625. env_params, debug);
  626. if (i != PAM_SUCCESS) {
  627. free_module_data(data);
  628. return i;
  629. }
  630. if (!data->exec_context) {
  631. free_module_data(data);
  632. return (security_getenforce() == 1) ? PAM_SESSION_ERR : PAM_SUCCESS;
  633. }
  634. if (ttys && (i = compute_tty_context(pamh, data)) != PAM_SUCCESS) {
  635. free_module_data(data);
  636. return i;
  637. }
  638. if ((i = pam_set_data(pamh, DATANAME, data, cleanup)) != PAM_SUCCESS) {
  639. pam_syslog(pamh, LOG_ERR, "Error saving context: %m");
  640. free_module_data(data);
  641. return i;
  642. }
  643. return set_context(pamh, data, debug, verbose);
  644. }
  645. int
  646. pam_sm_authenticate(pam_handle_t *pamh UNUSED, int flags UNUSED,
  647. int argc UNUSED, const char **argv UNUSED)
  648. {
  649. /* Fail by default. */
  650. return PAM_AUTH_ERR;
  651. }
  652. int
  653. pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
  654. int argc UNUSED, const char **argv UNUSED)
  655. {
  656. return PAM_SUCCESS;
  657. }
  658. int
  659. pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
  660. int argc, const char **argv)
  661. {
  662. const module_data_t *data;
  663. int i, debug = 0, verbose = 0, close_session = 0, restore = 0;
  664. /* Parse arguments. */
  665. for (i = 0; i < argc; i++) {
  666. if (strcmp(argv[i], "debug") == 0) {
  667. debug = 1;
  668. }
  669. if (strcmp(argv[i], "verbose") == 0) {
  670. verbose = 1;
  671. }
  672. if (strcmp(argv[i], "close") == 0) {
  673. close_session = 1;
  674. }
  675. if (strcmp(argv[i], "restore") == 0) {
  676. restore = 1;
  677. }
  678. }
  679. if (debug)
  680. pam_syslog(pamh, LOG_NOTICE, "Open Session");
  681. /* Is this module supposed to execute close_session only? */
  682. if (close_session)
  683. return PAM_SUCCESS;
  684. data = get_module_data(pamh);
  685. /* Is this module supposed only to restore original context? */
  686. if (restore)
  687. return restore_context(pamh, data, debug);
  688. /* If there is a saved context, this module is supposed to set it again. */
  689. return data ? set_context(pamh, data, debug, verbose) :
  690. create_context(pamh, argc, argv, debug, verbose);
  691. }
  692. int
  693. pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
  694. int argc, const char **argv)
  695. {
  696. int i, debug = 0, open_session = 0;
  697. /* Parse arguments. */
  698. for (i = 0; i < argc; i++) {
  699. if (strcmp(argv[i], "debug") == 0) {
  700. debug = 1;
  701. }
  702. if (strcmp(argv[i], "open") == 0) {
  703. open_session = 1;
  704. }
  705. }
  706. if (debug)
  707. pam_syslog(pamh, LOG_NOTICE, "Close Session");
  708. /* Is this module supposed to execute open_session only? */
  709. if (open_session)
  710. return PAM_SUCCESS;
  711. /* Restore original context. */
  712. return restore_context(pamh, get_module_data(pamh), debug);
  713. }