source: trunk/src/sh_subuid.c@ 546

Last change on this file since 546 was 537, checked in by katerina, 6 years ago

Fix for issue #429 (compile error on non-Linux systems).

File size: 6.0 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2018 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#undef FIL__
23#define FIL__ _("sh_subuid.c")
24
25
26#include <sys/types.h>
27#include <time.h>
28#include <sys/stat.h>
29#include <unistd.h>
30
31#include <stdlib.h>
32#include <errno.h>
33#include <limits.h>
34
35#if defined(__linux__)
36
37#include "samhain.h"
38#include "sh_unix.h"
39
40#define SH_SUBUID_FILE _("/etc/subuid")
41#define SH_SUBGID_FILE _("/etc/subgid")
42
43struct subuid_t {
44 char name[32];
45 unsigned long first;
46 unsigned long last;
47 struct subuid_t * next;
48};
49
50static time_t last_subuid = 0;
51static time_t last_subgid = 0;
52
53struct subuid_t * list_subuid = NULL;
54struct subuid_t * list_subgid = NULL;
55
56/* Check whether we need to re-read the subuid/subgid file
57 */
58static int needs_reread (char * file, time_t * last)
59{
60 int retval = S_FALSE;
61 struct stat buf;
62 int status = retry_lstat (FIL__, __LINE__, file, &buf);
63
64 if (status == 0)
65 {
66 if ((buf.st_mtime - *last) > 1)
67 {
68 *last = buf.st_mtime;
69 retval = S_TRUE;
70 }
71 }
72 else if (status && errno == ENOENT)
73 {
74 /* If there was a file make sure we attempt to re-read
75 * to zero out the list.
76 */
77 if (*last > 0) retval = S_TRUE;
78 *last = 0;
79 }
80 return retval;
81}
82
83/* free the whole list
84 */
85static void free_subordinate(struct subuid_t * head)
86{
87 struct subuid_t * prev;
88 struct subuid_t * curr = head;
89
90 while (curr)
91 {
92 prev = curr;
93 curr = curr->next;
94 SH_FREE(prev);
95 }
96 return;
97}
98
99#define NFIELDS_SUBUID 3
100
101static int get_ulong(char * str, unsigned long * result)
102{
103 char * endptr;
104
105 errno = 0;
106 *result = strtoul(str, &endptr, 0);
107 if (*str != '\0' && *endptr == '\0' && errno != ERANGE)
108 return S_TRUE;
109 return S_FALSE;
110}
111
112/* Parse a single line into name / startuid / lastuid
113 */
114static struct subuid_t * parse_subordinate(char * line)
115{
116 unsigned int nfields = NFIELDS_SUBUID;
117 size_t lengths[NFIELDS_SUBUID];
118 unsigned long start, count;
119 struct subuid_t * new;
120
121 char ** array = split_array(line, &nfields, ':', lengths);
122
123 if (nfields != NFIELDS_SUBUID)
124 { SH_FREE(array); return NULL; }
125
126 if (S_TRUE != get_ulong(array[1], &start))
127 { SH_FREE(array); return NULL; }
128 if ((S_TRUE != get_ulong(array[2], &count)) || (count == 0))
129 { SH_FREE(array); return NULL; }
130 if (lengths[0] == 0)
131 { SH_FREE(array); return NULL; }
132
133 /* we have checked that count != 0 */
134 --count;
135
136 if (start > (ULONG_MAX - count))
137 { SH_FREE(array); return NULL; }
138
139 new = SH_ALLOC(sizeof(struct subuid_t));
140 sl_strlcpy(new->name, array[0], 32);
141 new->first = start;
142 new->last = start + count; /* start+count-1, but we already did --count */
143 new->next = NULL;
144
145 SH_FREE(array);
146 return new;
147}
148
149/* (re-)read the subuid/subgid file
150 */
151static void reread_subordinate (char * file, struct subuid_t ** head_ref)
152{
153 SL_TICKET fd = (-1);
154 char line[1024];
155
156 if (*head_ref) { free_subordinate(*head_ref); *head_ref = NULL; }
157
158 fd = sl_open_read (FIL__, __LINE__, file, SL_YESPRIV);
159 if (!SL_ISERROR(fd))
160 {
161 while ( sh_unix_getline(fd, line, sizeof(line)) > 0 )
162 {
163 /* for invalid lines, NULL will be returned
164 */
165 struct subuid_t * new = parse_subordinate(line);
166
167 if (new)
168 {
169 new->next = *head_ref;
170 *head_ref = new;
171 }
172 }
173 sl_close(fd);
174 }
175 return;
176}
177
178/* Return the username for a given subuid/subgid
179 */
180static char * get_name4id (unsigned long id, struct subuid_t * head)
181{
182 struct subuid_t * cur = head;
183
184 while (cur)
185 {
186 if (id >= cur->first && id <= cur->last)
187 return cur->name;
188 cur = cur->next;
189 }
190 return NULL;
191}
192
193/***********************************************
194 *
195 * Public functions
196 *
197 ***********************************************/
198
199/* Returns username or NULL for a subuid
200 */
201char * sh_get_subuid (unsigned long subuid)
202{
203 static int init = 0;
204 static char file[256];
205
206 if (!init) { sl_strlcpy(file, SH_SUBUID_FILE, sizeof(file)); init = 1; }
207
208 if (S_TRUE == needs_reread(file, &last_subuid))
209 reread_subordinate(file, &list_subuid);
210
211 return get_name4id (subuid, list_subuid);
212}
213
214/* Returns group name or NULL for subgid
215 */
216char * sh_get_subgid (unsigned long subgid)
217{
218 static int init = 0;
219 static char file[256];
220
221 if (!init) { sl_strlcpy(file, SH_SUBGID_FILE, sizeof(file)); init = 1; }
222
223 if (S_TRUE == needs_reread(file, &last_subgid))
224 reread_subordinate(file, &list_subgid);
225
226 return get_name4id (subgid, list_subgid);
227}
228
229/* Not Linux, hence no sub(u|g)id
230 */
231#else
232
233char * sh_get_subuid (unsigned long subuid)
234{
235 (void) subuid;
236 return NULL;
237}
238
239char * sh_get_subgid (unsigned long subgid)
240{
241 (void) subgid;
242 return NULL;
243}
244
245#endif
Note: See TracBrowser for help on using the repository browser.