Line data Source code
1 : /*
2 : SSSD
3 :
4 : Check file permissions and open file
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2009 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include <sys/types.h>
26 : #include <sys/stat.h>
27 : #include <fcntl.h>
28 : #include <unistd.h>
29 :
30 : #include "util/util.h"
31 :
32 : static errno_t perform_checks(struct stat *stat_buf,
33 : uid_t uid, gid_t gid,
34 : mode_t mode, mode_t mask);
35 :
36 2 : errno_t check_file(const char *filename,
37 : uid_t uid, uid_t gid, mode_t mode, mode_t mask,
38 : struct stat *caller_stat_buf, bool follow_symlink)
39 : {
40 : int ret;
41 : struct stat local_stat_buf;
42 : struct stat *stat_buf;
43 :
44 2 : if (caller_stat_buf == NULL) {
45 2 : stat_buf = &local_stat_buf;
46 : } else {
47 0 : stat_buf = caller_stat_buf;
48 : }
49 :
50 2 : if (follow_symlink) {
51 1 : ret = stat(filename, stat_buf);
52 : } else {
53 1 : ret = lstat(filename, stat_buf);
54 : }
55 2 : if (ret == -1) {
56 0 : DEBUG(SSSDBG_TRACE_FUNC, "lstat for [%s] failed: [%d][%s].\n",
57 : filename, errno, strerror(errno));
58 0 : return errno;
59 : }
60 :
61 2 : return perform_checks(stat_buf, uid, gid, mode, mask);
62 : }
63 :
64 12 : errno_t check_fd(int fd, uid_t uid, gid_t gid,
65 : mode_t mode, mode_t mask,
66 : struct stat *caller_stat_buf)
67 : {
68 : int ret;
69 : struct stat local_stat_buf;
70 : struct stat *stat_buf;
71 :
72 12 : if (caller_stat_buf == NULL) {
73 0 : stat_buf = &local_stat_buf;
74 : } else {
75 12 : stat_buf = caller_stat_buf;
76 : }
77 :
78 12 : ret = fstat(fd, stat_buf);
79 12 : if (ret == -1) {
80 0 : DEBUG(SSSDBG_CRIT_FAILURE,
81 : "fstat for [%d] failed: [%d][%s].\n", fd, errno,
82 : strerror(errno));
83 0 : return errno;
84 : }
85 :
86 12 : return perform_checks(stat_buf, uid, gid, mode, mask);
87 : }
88 :
89 14 : static errno_t perform_checks(struct stat *stat_buf,
90 : uid_t uid, gid_t gid,
91 : mode_t mode, mode_t mask)
92 : {
93 : mode_t st_mode;
94 :
95 14 : if (mask) {
96 0 : st_mode = stat_buf->st_mode & mask;
97 : } else {
98 14 : st_mode = stat_buf->st_mode & (S_IFMT|ALLPERMS);
99 : }
100 :
101 14 : if ((mode & S_IFMT) != (st_mode & S_IFMT)) {
102 2 : DEBUG(SSSDBG_TRACE_LIBS, "File is not the right type.\n");
103 2 : return EINVAL;
104 : }
105 :
106 12 : if ((st_mode & ALLPERMS) != (mode & ALLPERMS)) {
107 1 : DEBUG(SSSDBG_TRACE_LIBS,
108 : "File has the wrong (bit masked) mode [%.7o], "
109 : "expected [%.7o].\n",
110 : (st_mode & ALLPERMS), (mode & ALLPERMS));
111 1 : return EINVAL;
112 : }
113 :
114 11 : if (uid != (uid_t)(-1) && stat_buf->st_uid != uid) {
115 1 : DEBUG(SSSDBG_TRACE_LIBS, "File must be owned by uid [%d].\n", uid);
116 1 : return EINVAL;
117 : }
118 :
119 10 : if (gid != (gid_t)(-1) && stat_buf->st_gid != gid) {
120 1 : DEBUG(SSSDBG_TRACE_LIBS, "File must be owned by gid [%d].\n", gid);
121 1 : return EINVAL;
122 : }
123 :
124 9 : return EOK;
125 : }
126 :
127 13 : errno_t check_and_open_readonly(const char *filename, int *fd,
128 : uid_t uid, gid_t gid,
129 : mode_t mode, mode_t mask)
130 : {
131 : int ret;
132 : struct stat stat_buf;
133 :
134 13 : *fd = open(filename, O_RDONLY);
135 13 : if (*fd == -1) {
136 3 : DEBUG(SSSDBG_CRIT_FAILURE,
137 : "open [%s] failed: [%d][%s].\n", filename, errno,
138 : strerror(errno));
139 3 : return errno;
140 : }
141 :
142 10 : ret = check_fd(*fd, uid, gid, mode, mask, &stat_buf);
143 10 : if (ret != EOK) {
144 4 : close(*fd);
145 4 : *fd = -1;
146 4 : DEBUG(SSSDBG_CRIT_FAILURE, "check_fd failed.\n");
147 4 : return ret;
148 : }
149 :
150 6 : return EOK;
151 : }
152 :
|