1    	/*
2    	   SSSD
3    	
4    	   selinux.c
5    	
6    	   Copyright (C) Jakub Hrozek <jhrozek@redhat.com>        2010
7    	
8    	   This program is free software; you can redistribute it and/or modify
9    	   it under the terms of the GNU General Public License as published by
10   	   the Free Software Foundation; either version 3 of the License, or
11   	   (at your option) any later version.
12   	
13   	   This program is distributed in the hope that it will be useful,
14   	   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   	   GNU General Public License for more details.
17   	
18   	   You should have received a copy of the GNU General Public License
19   	   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20   	*/
21   	
22   	#include "config.h"
23   	
24   	#define _GNU_SOURCE
25   	#include <stdio.h>
26   	
27   	#ifdef HAVE_SELINUX
28   	#include <selinux/selinux.h>
29   	#endif
30   	
31   	#ifdef HAVE_SEMANAGE
32   	#include <semanage/semanage.h>
33   	#endif
34   	
35   	#include "util/util.h"
36   	
37   	#ifndef DEFAULT_SERANGE
38   	#define DEFAULT_SERANGE "s0"
39   	#endif
40   	
41   	#ifdef HAVE_SELINUX
42   	/*
43   	 * selinux_file_context - Set the security context before any file or
44   	 *                        directory creation.
45   	 *
46   	 *  selinux_file_context () should be called before any creation of file,
47   	 *  symlink, directory, ...
48   	 *
49   	 *  Callers may have to Reset SELinux to create files with default
50   	 *  contexts:
51   	 *      reset_selinux_file_context();
52   	 */
53   	int selinux_file_context(const char *dst_name)
54   	{
55   	    security_context_t scontext = NULL;
56   	
57   	    if (is_selinux_enabled() == 1) {
58   	        /* Get the default security context for this file */
59   	        if (matchpathcon(dst_name, 0, &scontext) < 0) {
60   	            if (security_getenforce () != 0) {
61   	                return 1;
62   	            }
63   	        }
64   	        /* Set the security context for the next created file */
65   	        if (setfscreatecon(scontext) < 0) {
66   	            if (security_getenforce() != 0) {
67   	                return 1;
68   	            }
69   	        }
70   	        freecon(scontext);
71   	    }
72   	
73   	    return 0;
74   	}
75   	
76   	int reset_selinux_file_context(void)
77   	{
78   	    setfscreatecon(NULL);
79   	    return EOK;
80   	}
81   	
82   	#else   /* HAVE_SELINUX */
83   	int selinux_file_context(const char *dst_name)
84   	{
85   	    return EOK;
86   	}
87   	
88   	int reset_selinux_file_context(void)
89   	{
90   	    return EOK;
91   	}
92   	#endif  /* HAVE_SELINUX */
93   	
94   	#ifdef HAVE_SEMANAGE
95   	/* turn libselinux messages into SSSD DEBUG() calls */
96   	static void sss_semanage_error_callback(void *varg,
97   	                                        semanage_handle_t *handle,
98   	                                        const char *fmt, ...)
99   	{
100  	    int level = -1;
101  	    int ret;
102  	    char * message = NULL;
103  	    va_list ap;
104  	
105  	    switch (semanage_msg_get_level(handle)) {
106  	        case SEMANAGE_MSG_ERR:
107  	            level = 1;
108  	            break;
109  	        case SEMANAGE_MSG_WARN:
110  	            level = 4;
111  	            break;
112  	        case SEMANAGE_MSG_INFO:
113  	            level = 6;
114  	            break;
115  	    }
116  	
Event va_init: Initializing va_list "ap".
Also see events: [missing_va_end]
117  	    va_start(ap, fmt);
118  	    ret = vasprintf(&message, fmt, ap);
At conditional (1): "ret < 0": Taking true branch.
119  	    if (ret < 0) {
120  	        /* ENOMEM */
Event missing_va_end: va_end was not called for "ap".
Also see events: [va_init]
121  	        return;
122  	    }
123  	    va_end(ap);
124  	
125  	    if (level <= debug_level) {
126  	        if (debug_timestamps) {
127  	            time_t rightnow = time(NULL);
128  	            char stamp[25];
129  	            memcpy(stamp, ctime(&rightnow), 24);
130  	            stamp[24] = '\0';
131  	            debug_fn("(%s) [%s] [libsemanage] (%d): %s\n",
132  	                     stamp, debug_prg_name, level, message);
133  	        } else {
134  	            debug_fn("[%s] [libsemanage] (%d): %s\n",
135  	                     debug_prg_name, level, message);
136  	        }
137  	    }
138  	    free(message);
139  	}
140  	
141  	static semanage_handle_t *sss_semanage_init(void)
142  	{
143  	    int ret;
144  	    semanage_handle_t *handle = NULL;
145  	
146  	    handle = semanage_handle_create();
147  	    if (!handle) {
148  	        DEBUG(1, ("Cannot create SELinux management handle\n"));
149  	        return NULL;
150  	    }
151  	
152  	    semanage_msg_set_callback(handle,
153  	                              sss_semanage_error_callback,
154  	                              NULL);
155  	
156  	    ret = semanage_is_managed(handle);
157  	    if (ret != 1) {
158  	        DEBUG(1, ("SELinux policy not managed\n"));
159  	        goto fail;
160  	    }
161  	
162  	    ret = semanage_access_check(handle);
163  	    if (ret < SEMANAGE_CAN_READ) {
164  	        DEBUG(1, ("Cannot read SELinux policy store\n"));
165  	        goto fail;
166  	    }
167  	
168  	    ret = semanage_connect(handle);
169  	    if (ret != 0) {
170  	        DEBUG(1, ("Cannot estabilish SELinux management connection\n"));
171  	        goto fail;
172  	    }
173  	
174  	    ret = semanage_begin_transaction(handle);
175  	    if (ret != 0) {
176  	        DEBUG(1, ("Cannot begin SELinux transaction\n"));
177  	        goto fail;
178  	    }
179  	
180  	    return handle;
181  	fail:
182  	    semanage_handle_destroy(handle);
183  	    return NULL;
184  	}
185  	
186  	static int sss_semanage_user_add(semanage_handle_t *handle,
187  	                                 semanage_seuser_key_t *key,
188  	                                 const char *login_name,
189  	                                 const char *seuser_name)
190  	{
191  	    int ret;
192  	    semanage_seuser_t *seuser = NULL;
193  	
194  	    ret = semanage_seuser_create(handle, &seuser);
195  	    if (ret != 0) {
196  	        DEBUG(1, ("Cannot create SELinux login mapping for %s\n", login_name));
197  	        ret = EIO;
198  	        goto done;
199  	    }
200  	
201  	    ret = semanage_seuser_set_name(handle, seuser, login_name);
202  	    if (ret != 0) {
203  	        DEBUG(1, ("Could not set name for %s\n", login_name));
204  	        ret = EIO;
205  	        goto done;
206  	    }
207  	
208  	    ret = semanage_seuser_set_mlsrange(handle, seuser, DEFAULT_SERANGE);
209  	    if (ret != 0) {
210  	        DEBUG(1, ("Could not set serange for %s\n", login_name));
211  	        ret = EIO;
212  	        goto done;
213  	    }
214  	
215  	    ret = semanage_seuser_set_sename(handle, seuser, seuser_name);
216  	    if (ret != 0) {
217  	        DEBUG(1, ("Could not set SELinux user for %s\n", login_name));
218  	        ret = EIO;
219  	        goto done;
220  	    }
221  	
222  	    ret = semanage_seuser_modify_local(handle, key, seuser);
223  	    if (ret != 0) {
224  	        DEBUG(1, ("Could not add login mapping for %s\n", login_name));
225  	        ret = EIO;
226  	        goto done;
227  	    }
228  	
229  	    ret = EOK;
230  	done:
231  	    semanage_seuser_free(seuser);
232  	    return ret;
233  	}
234  	
235  	static int sss_semanage_user_mod(semanage_handle_t *handle,
236  	                                 semanage_seuser_key_t *key,
237  	                                 const char *login_name,
238  	                                 const char *seuser_name)
239  	{
240  	    int ret;
241  	    semanage_seuser_t *seuser = NULL;
242  	
243  	    semanage_seuser_query(handle, key, &seuser);
244  	    if (seuser == NULL) {
245  	        DEBUG(1, ("Could not query seuser for %s\n", login_name));
246  	        ret = EIO;
247  	        goto done;
248  	    }
249  	
250  	    ret = semanage_seuser_set_mlsrange(handle, seuser, DEFAULT_SERANGE);
251  	    if (ret != 0) {
252  	        DEBUG(1, ("Could not set serange for %s\n", login_name));
253  	        ret = EIO;
254  	        goto done;
255  	    }
256  	
257  	    ret = semanage_seuser_set_sename(handle, seuser, seuser_name);
258  	    if (ret != 0) {
259  	        DEBUG(1, ("Could not set sename for %s\n", login_name));
260  	        ret = EIO;
261  	        goto done;
262  	    }
263  	
264  	    ret = semanage_seuser_modify_local(handle, key, seuser);
265  	    if (ret != 0) {
266  	        DEBUG(1, (("Could not modify login mapping for %s\n"), login_name));
267  	        ret = EIO;
268  	        goto done;
269  	    }
270  	
271  	    ret = EOK;
272  	done:
273  	    semanage_seuser_free(seuser);
274  	    return ret;
275  	}
276  	
277  	int set_seuser(const char *login_name, const char *seuser_name)
278  	{
279  	    semanage_handle_t *handle = NULL;
280  	    semanage_seuser_key_t *key = NULL;
281  	    int ret;
282  	    int seuser_exists = 0;
283  	
284  	    if (seuser_name == NULL) {
285  	        /* don't care, just let system pick the defaults */
286  	        return EOK;
287  	    }
288  	
289  	    handle = sss_semanage_init();
290  	    if (!handle) {
291  	        DEBUG(1, ("Cannot init SELinux management\n"));
292  	        ret = EIO;
293  	        goto done;
294  	    }
295  	
296  	    ret = semanage_seuser_key_create(handle, login_name, &key);
297  	    if (ret != 0) {
298  	        DEBUG(1, ("Cannot create SELinux user key\n"));
299  	        ret = EIO;
300  	        goto done;
301  	    }
302  	
303  	    ret = semanage_seuser_exists(handle, key, &seuser_exists);
304  	    if (ret < 0) {
305  	        DEBUG(1, ("Cannot verify the SELinux user\n"));
306  	        ret = EIO;
307  	        goto done;
308  	    }
309  	
310  	    if (seuser_exists) {
311  	        ret = sss_semanage_user_mod(handle, key, login_name, seuser_name);
312  	        if (ret != 0) {
313  	            DEBUG(1, ("Cannot modify SELinux user mapping\n"));
314  	            ret = EIO;
315  	            goto done;
316  	        }
317  	    } else {
318  	        ret = sss_semanage_user_add(handle, key, login_name, seuser_name);
319  	        if (ret != 0) {
320  	            DEBUG(1, ("Cannot add SELinux user mapping\n"));
321  	            ret = EIO;
322  	            goto done;
323  	        }
324  	    }
325  	
326  	    ret = semanage_commit(handle);
327  	    if (ret != 0) {
328  	        DEBUG(1, ("Cannot commit SELinux transaction\n"));
329  	        ret = EIO;
330  	        goto done;
331  	    }
332  	
333  	    ret = EOK;
334  	done:
335  	    semanage_seuser_key_free(key);
336  	    semanage_handle_destroy(handle);
337  	    return ret;
338  	}
339  	
340  	int del_seuser(const char *login_name)
341  	{
342  	    semanage_handle_t *handle = NULL;
343  	    semanage_seuser_key_t *key = NULL;
344  	    int ret;
345  	    int exists = 0;
346  	
347  	    handle = sss_semanage_init();
348  	    if (!handle) {
349  	        DEBUG(1, ("Cannot init SELinux management\n"));
350  	        ret = EIO;
351  	        goto done;
352  	    }
353  	
354  	    ret = semanage_seuser_key_create(handle, login_name, &key);
355  	    if (ret != 0) {
356  	        DEBUG(1, ("Cannot create SELinux user key\n"));
357  	        ret = EIO;
358  	        goto done;
359  	    }
360  	
361  	    ret = semanage_seuser_exists(handle, key, &exists);
362  	    if (ret < 0) {
363  	        DEBUG(1, ("Cannot verify the SELinux user\n"));
364  	        ret = EIO;
365  	        goto done;
366  	    }
367  	
368  	    if (!exists) {
369  	        DEBUG(5, ("Login mapping for %s is not defined, OK if default mapping "
370  	                  "was used\n", login_name));
371  	        ret = EOK;  /* probably default mapping */
372  	        goto done;
373  	    }
374  	
375  	    ret = semanage_seuser_exists_local(handle, key, &exists);
376  	    if (ret < 0) {
377  	        DEBUG(1, ("Cannot verify the SELinux user\n"));
378  	        ret = EIO;
379  	        goto done;
380  	    }
381  	
382  	    if (!exists) {
383  	        DEBUG(1, ("Login mapping for %s is defined in policy, "
384  	                  "cannot be deleted", login_name));
385  	        ret = ENOENT;
386  	        goto done;
387  	    }
388  	
389  	    ret = semanage_seuser_del_local(handle, key);
390  	    if (ret != 0) {
391  	        DEBUG(1, ("Could not delete login mapping for %s", login_name));
392  	        ret = EIO;
393  	        goto done;
394  	    }
395  	
396  	    ret = semanage_commit(handle);
397  	    if (ret != 0) {
398  	        DEBUG(1, ("Cannot commit SELinux transaction\n"));
399  	        ret = EIO;
400  	        goto done;
401  	    }
402  	
403  	    ret = EOK;
404  	done:
405  	    semanage_handle_destroy(handle);
406  	    return ret;
407  	}
408  	
409  	#else /* HAVE_SEMANAGE */
410  	int set_seuser(const char *login_name, const char *seuser_name)
411  	{
412  	    return EOK;
413  	}
414  	
415  	int del_seuser(const char *login_name)
416  	{
417  	    return EOK;
418  	}
419  	#endif  /* HAVE_SEMANAGE */