LCOV - code coverage report
Current view: top level - openssh-6.6p1/openbsd-compat - port-linux.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 19 25 76.0 %
Date: 2014-08-01 Functions: 2 2 100.0 %
Branches: 8 16 50.0 %

           Branch data     Line data    Source code
       1                 :            : /* $Id: port-linux.c,v 1.18 2013/06/01 22:07:32 dtucker Exp $ */
       2                 :            : 
       3                 :            : /*
       4                 :            :  * Copyright (c) 2005 Daniel Walsh <dwalsh@redhat.com>
       5                 :            :  * Copyright (c) 2006 Damien Miller <djm@openbsd.org>
       6                 :            :  *
       7                 :            :  * Permission to use, copy, modify, and distribute this software for any
       8                 :            :  * purpose with or without fee is hereby granted, provided that the above
       9                 :            :  * copyright notice and this permission notice appear in all copies.
      10                 :            :  *
      11                 :            :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12                 :            :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13                 :            :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14                 :            :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15                 :            :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16                 :            :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17                 :            :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18                 :            :  */
      19                 :            : 
      20                 :            : /*
      21                 :            :  * Linux-specific portability code - just SELinux support at present
      22                 :            :  */
      23                 :            : 
      24                 :            : #include "includes.h"
      25                 :            : 
      26                 :            : #if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST)
      27                 :            : #include <errno.h>
      28                 :            : #include <stdarg.h>
      29                 :            : #include <string.h>
      30                 :            : #include <stdio.h>
      31                 :            : 
      32                 :            : #include "log.h"
      33                 :            : #include "xmalloc.h"
      34                 :            : #include "port-linux.h"
      35                 :            : 
      36                 :            : #ifdef WITH_SELINUX
      37                 :            : #include <selinux/selinux.h>
      38                 :            : #include <selinux/flask.h>
      39                 :            : #include <selinux/get_context_list.h>
      40                 :            : 
      41                 :            : #ifndef SSH_SELINUX_UNCONFINED_TYPE
      42                 :            : # define SSH_SELINUX_UNCONFINED_TYPE ":unconfined_t:"
      43                 :            : #endif
      44                 :            : 
      45                 :            : /* Wrapper around is_selinux_enabled() to log its return value once only */
      46                 :            : int
      47                 :            : ssh_selinux_enabled(void)
      48                 :            : {
      49                 :            :         static int enabled = -1;
      50                 :            : 
      51                 :            :         if (enabled == -1) {
      52                 :            :                 enabled = (is_selinux_enabled() == 1);
      53                 :            :                 debug("SELinux support %s", enabled ? "enabled" : "disabled");
      54                 :            :         }
      55                 :            : 
      56                 :            :         return (enabled);
      57                 :            : }
      58                 :            : 
      59                 :            : /* Return the default security context for the given username */
      60                 :            : static security_context_t
      61                 :            : ssh_selinux_getctxbyname(char *pwname)
      62                 :            : {
      63                 :            :         security_context_t sc = NULL;
      64                 :            :         char *sename = NULL, *lvl = NULL;
      65                 :            :         int r;
      66                 :            : 
      67                 :            : #ifdef HAVE_GETSEUSERBYNAME
      68                 :            :         if (getseuserbyname(pwname, &sename, &lvl) != 0)
      69                 :            :                 return NULL;
      70                 :            : #else
      71                 :            :         sename = pwname;
      72                 :            :         lvl = NULL;
      73                 :            : #endif
      74                 :            : 
      75                 :            : #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
      76                 :            :         r = get_default_context_with_level(sename, lvl, NULL, &sc);
      77                 :            : #else
      78                 :            :         r = get_default_context(sename, NULL, &sc);
      79                 :            : #endif
      80                 :            : 
      81                 :            :         if (r != 0) {
      82                 :            :                 switch (security_getenforce()) {
      83                 :            :                 case -1:
      84                 :            :                         fatal("%s: ssh_selinux_getctxbyname: "
      85                 :            :                             "security_getenforce() failed", __func__);
      86                 :            :                 case 0:
      87                 :            :                         error("%s: Failed to get default SELinux security "
      88                 :            :                             "context for %s", __func__, pwname);
      89                 :            :                         sc = NULL;
      90                 :            :                         break;
      91                 :            :                 default:
      92                 :            :                         fatal("%s: Failed to get default SELinux security "
      93                 :            :                             "context for %s (in enforcing mode)",
      94                 :            :                             __func__, pwname);
      95                 :            :                 }
      96                 :            :         }
      97                 :            : 
      98                 :            : #ifdef HAVE_GETSEUSERBYNAME
      99                 :            :         free(sename);
     100                 :            :         free(lvl);
     101                 :            : #endif
     102                 :            : 
     103                 :            :         return sc;
     104                 :            : }
     105                 :            : 
     106                 :            : /* Set the execution context to the default for the specified user */
     107                 :            : void
     108                 :            : ssh_selinux_setup_exec_context(char *pwname)
     109                 :            : {
     110                 :            :         security_context_t user_ctx = NULL;
     111                 :            : 
     112                 :            :         if (!ssh_selinux_enabled())
     113                 :            :                 return;
     114                 :            : 
     115                 :            :         debug3("%s: setting execution context", __func__);
     116                 :            : 
     117                 :            :         user_ctx = ssh_selinux_getctxbyname(pwname);
     118                 :            :         if (setexeccon(user_ctx) != 0) {
     119                 :            :                 switch (security_getenforce()) {
     120                 :            :                 case -1:
     121                 :            :                         fatal("%s: security_getenforce() failed", __func__);
     122                 :            :                 case 0:
     123                 :            :                         error("%s: Failed to set SELinux execution "
     124                 :            :                             "context for %s", __func__, pwname);
     125                 :            :                         break;
     126                 :            :                 default:
     127                 :            :                         fatal("%s: Failed to set SELinux execution context "
     128                 :            :                             "for %s (in enforcing mode)", __func__, pwname);
     129                 :            :                 }
     130                 :            :         }
     131                 :            :         if (user_ctx != NULL)
     132                 :            :                 freecon(user_ctx);
     133                 :            : 
     134                 :            :         debug3("%s: done", __func__);
     135                 :            : }
     136                 :            : 
     137                 :            : /* Set the TTY context for the specified user */
     138                 :            : void
     139                 :            : ssh_selinux_setup_pty(char *pwname, const char *tty)
     140                 :            : {
     141                 :            :         security_context_t new_tty_ctx = NULL;
     142                 :            :         security_context_t user_ctx = NULL;
     143                 :            :         security_context_t old_tty_ctx = NULL;
     144                 :            : 
     145                 :            :         if (!ssh_selinux_enabled())
     146                 :            :                 return;
     147                 :            : 
     148                 :            :         debug3("%s: setting TTY context on %s", __func__, tty);
     149                 :            : 
     150                 :            :         user_ctx = ssh_selinux_getctxbyname(pwname);
     151                 :            : 
     152                 :            :         /* XXX: should these calls fatal() upon failure in enforcing mode? */
     153                 :            : 
     154                 :            :         if (getfilecon(tty, &old_tty_ctx) == -1) {
     155                 :            :                 error("%s: getfilecon: %s", __func__, strerror(errno));
     156                 :            :                 goto out;
     157                 :            :         }
     158                 :            : 
     159                 :            :         if (security_compute_relabel(user_ctx, old_tty_ctx,
     160                 :            :             SECCLASS_CHR_FILE, &new_tty_ctx) != 0) {
     161                 :            :                 error("%s: security_compute_relabel: %s",
     162                 :            :                     __func__, strerror(errno));
     163                 :            :                 goto out;
     164                 :            :         }
     165                 :            : 
     166                 :            :         if (setfilecon(tty, new_tty_ctx) != 0)
     167                 :            :                 error("%s: setfilecon: %s", __func__, strerror(errno));
     168                 :            :  out:
     169                 :            :         if (new_tty_ctx != NULL)
     170                 :            :                 freecon(new_tty_ctx);
     171                 :            :         if (old_tty_ctx != NULL)
     172                 :            :                 freecon(old_tty_ctx);
     173                 :            :         if (user_ctx != NULL)
     174                 :            :                 freecon(user_ctx);
     175                 :            :         debug3("%s: done", __func__);
     176                 :            : }
     177                 :            : 
     178                 :            : void
     179                 :            : ssh_selinux_change_context(const char *newname)
     180                 :            : {
     181                 :            :         int len, newlen;
     182                 :            :         char *oldctx, *newctx, *cx;
     183                 :            :         void (*switchlog) (const char *fmt,...) = logit;
     184                 :            : 
     185                 :            :         if (!ssh_selinux_enabled())
     186                 :            :                 return;
     187                 :            : 
     188                 :            :         if (getcon((security_context_t *)&oldctx) < 0) {
     189                 :            :                 logit("%s: getcon failed with %s", __func__, strerror(errno));
     190                 :            :                 return;
     191                 :            :         }
     192                 :            :         if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) ==
     193                 :            :             NULL) {
     194                 :            :                 logit ("%s: unparseable context %s", __func__, oldctx);
     195                 :            :                 return;
     196                 :            :         }
     197                 :            : 
     198                 :            :         /*
     199                 :            :          * Check whether we are attempting to switch away from an unconfined
     200                 :            :          * security context.
     201                 :            :          */
     202                 :            :         if (strncmp(cx, SSH_SELINUX_UNCONFINED_TYPE,
     203                 :            :             sizeof(SSH_SELINUX_UNCONFINED_TYPE) - 1) == 0)
     204                 :            :                 switchlog = debug3;
     205                 :            : 
     206                 :            :         newlen = strlen(oldctx) + strlen(newname) + 1;
     207                 :            :         newctx = xmalloc(newlen);
     208                 :            :         len = cx - oldctx + 1;
     209                 :            :         memcpy(newctx, oldctx, len);
     210                 :            :         strlcpy(newctx + len, newname, newlen - len);
     211                 :            :         if ((cx = index(cx + 1, ':')))
     212                 :            :                 strlcat(newctx, cx, newlen);
     213                 :            :         debug3("%s: setting context from '%s' to '%s'", __func__,
     214                 :            :             oldctx, newctx);
     215                 :            :         if (setcon(newctx) < 0)
     216                 :            :                 switchlog("%s: setcon %s from %s failed with %s", __func__,
     217                 :            :                     newctx, oldctx, strerror(errno));
     218                 :            :         free(oldctx);
     219                 :            :         free(newctx);
     220                 :            : }
     221                 :            : 
     222                 :            : void
     223                 :            : ssh_selinux_setfscreatecon(const char *path)
     224                 :            : {
     225                 :            :         security_context_t context;
     226                 :            : 
     227                 :            :         if (!ssh_selinux_enabled())
     228                 :            :                 return;
     229                 :            :         if (path == NULL) {
     230                 :            :                 setfscreatecon(NULL);
     231                 :            :                 return;
     232                 :            :         }
     233                 :            :         if (matchpathcon(path, 0700, &context) == 0)
     234                 :            :                 setfscreatecon(context);
     235                 :            : }
     236                 :            : 
     237                 :            : #endif /* WITH_SELINUX */
     238                 :            : 
     239                 :            : #ifdef LINUX_OOM_ADJUST
     240                 :            : /*
     241                 :            :  * The magic "don't kill me" values, old and new, as documented in eg:
     242                 :            :  * http://lxr.linux.no/#linux+v2.6.32/Documentation/filesystems/proc.txt
     243                 :            :  * http://lxr.linux.no/#linux+v2.6.36/Documentation/filesystems/proc.txt
     244                 :            :  */
     245                 :            : 
     246                 :            : static int oom_adj_save = INT_MIN;
     247                 :            : static char *oom_adj_path = NULL;
     248                 :            : struct {
     249                 :            :         char *path;
     250                 :            :         int value;
     251                 :            : } oom_adjust[] = {
     252                 :            :         {"/proc/self/oom_score_adj", -1000},  /* kernels >= 2.6.36 */
     253                 :            :         {"/proc/self/oom_adj", -17},          /* kernels <= 2.6.35 */
     254                 :            :         {NULL, 0},
     255                 :            : };
     256                 :            : 
     257                 :            : /*
     258                 :            :  * Tell the kernel's out-of-memory killer to avoid sshd.
     259                 :            :  * Returns the previous oom_adj value or zero.
     260                 :            :  */
     261                 :            : void
     262                 :         16 : oom_adjust_setup(void)
     263                 :            : {
     264                 :            :         int i, value;
     265                 :            :         FILE *fp;
     266                 :            : 
     267                 :         16 :         debug3("%s", __func__);
     268         [ +  - ]:         16 :          for (i = 0; oom_adjust[i].path != NULL; i++) {
     269                 :         16 :                 oom_adj_path = oom_adjust[i].path;
     270                 :         16 :                 value = oom_adjust[i].value;
     271         [ +  - ]:         16 :                 if ((fp = fopen(oom_adj_path, "r+")) != NULL) {
     272         [ -  + ]:         16 :                         if (fscanf(fp, "%d", &oom_adj_save) != 1)
     273                 :          0 :                                 verbose("error reading %s: %s", oom_adj_path,
     274                 :          0 :                                     strerror(errno));
     275                 :            :                         else {
     276                 :         16 :                                 rewind(fp);
     277         [ -  + ]:         16 :                                 if (fprintf(fp, "%d\n", value) <= 0)
     278                 :          0 :                                         verbose("error writing %s: %s",
     279                 :          0 :                                            oom_adj_path, strerror(errno));
     280                 :            :                                 else
     281                 :         16 :                                         verbose("Set %s from %d to %d",
     282                 :            :                                            oom_adj_path, oom_adj_save, value);
     283                 :            :                         }
     284                 :         16 :                         fclose(fp);
     285                 :         16 :                         return;
     286                 :            :                 }
     287                 :            :         }
     288                 :          0 :         oom_adj_path = NULL;
     289                 :            : }
     290                 :            : 
     291                 :            : /* Restore the saved OOM adjustment */
     292                 :            : void
     293                 :        105 : oom_adjust_restore(void)
     294                 :            : {
     295                 :            :         FILE *fp;
     296                 :            : 
     297                 :        105 :         debug3("%s", __func__);
     298 [ +  - ][ +  - ]:        105 :         if (oom_adj_save == INT_MIN || oom_adj_path == NULL ||
                 [ +  - ]
     299                 :            :             (fp = fopen(oom_adj_path, "w")) == NULL)
     300                 :            :                 return;
     301                 :            : 
     302         [ -  + ]:        105 :         if (fprintf(fp, "%d\n", oom_adj_save) <= 0)
     303                 :          0 :                 verbose("error writing %s: %s", oom_adj_path, strerror(errno));
     304                 :            :         else
     305                 :        105 :                 verbose("Set %s to %d", oom_adj_path, oom_adj_save);
     306                 :            : 
     307                 :        105 :         fclose(fp);
     308                 :        105 :         return;
     309                 :            : }
     310                 :            : #endif /* LINUX_OOM_ADJUST */
     311                 :            : #endif /* WITH_SELINUX || LINUX_OOM_ADJUST */

Generated by: LCOV version 1.9