6 |
#include <string.h> |
#include <string.h> |
7 |
|
|
8 |
#include "fileutil.h" |
#include "fileutil.h" |
9 |
|
#include "../safefile-1.0/safe_id_range_list.h" |
10 |
|
#include "../safefile-1.0/safe_is_path_trusted.h" |
11 |
|
|
12 |
static int priv_drop(uid_t unpriv_uid,gid_t unpriv_gid); |
static int priv_drop(uid_t unpriv_uid,gid_t unpriv_gid); |
13 |
static int raise_priv(uid_t euid, gid_t egid); |
static int raise_priv(uid_t euid, gid_t egid); |
108 |
/** |
/** |
109 |
* Reads proxy from *path using given lock_type (see cgul_filelock). It tries to |
* Reads proxy from *path using given lock_type (see cgul_filelock). It tries to |
110 |
* drop privilege to real-uid/read_gid. Space needed will be malloc-ed. |
* drop privilege to real-uid/read_gid. Space needed will be malloc-ed. |
111 |
|
* Upon successful completion config contains the contents of path. |
112 |
* Return values: |
* Return values: |
113 |
* 0: success |
* 0: success |
114 |
* -1: I/O error |
* -1: I/O error |
123 |
struct stat st1,st2,*sptr1,*sptr2,*sptr3; |
struct stat st1,st2,*sptr1,*sptr2,*sptr3; |
124 |
uid_t uid=getuid(),euid=geteuid(); |
uid_t uid=getuid(),euid=geteuid(); |
125 |
gid_t egid=getegid(); |
gid_t egid=getegid(); |
126 |
char *buf,*buf_new; |
char *buf,*buf_new; /* *proxy will be updated when we know everything is ok */ |
127 |
ssize_t size; |
ssize_t size; |
128 |
|
|
|
/* *proxy will be updated when we know everything is ok */ |
|
|
buf=*proxy; |
|
|
|
|
129 |
/* Drop privilege to real uid and special read group */ |
/* Drop privilege to real uid and special read group */ |
130 |
if (priv_drop(uid,read_gid)) |
if (priv_drop(uid,read_gid)) |
131 |
return -2; |
return -2; |
132 |
/* Open file */ |
/* Open file */ |
133 |
if ((fd=open(path,O_RDONLY))==-1) |
if ((fd=open(path,O_RDONLY))==-1) { |
134 |
return -1; |
raise_priv(euid,egid); return -1; |
135 |
|
} |
136 |
/* Lock file */ |
/* Lock file */ |
137 |
if (cgul_filelock(fd,lock_type,LCK_READ)) { |
if (cgul_filelock(fd,lock_type,LCK_READ)) { |
138 |
close(fd); return -1; |
close(fd); raise_priv(euid,egid); return -1; |
139 |
} |
} |
140 |
/* Stat the file before reading: |
/* Stat the file before reading: |
141 |
* Need ownership and mode for allowed values, size for malloc */ |
* Need ownership and mode for allowed values, size for malloc */ |
142 |
if (fstat(fd,&st1)) { |
if (fstat(fd,&st1)) { |
143 |
close(fd); return -1; |
close(fd); raise_priv(euid,egid); return -1; |
144 |
} |
} |
145 |
/* Check we own it (only uid) and is unreadable/unwriteable for anyone else |
/* Check we own it (only uid) and is unreadable/unwriteable for anyone else |
146 |
* */ |
* */ |
147 |
if ( st1.st_uid!=uid || |
if ( st1.st_uid!=uid || |
148 |
st1.st_mode & S_IRGRP || st1.st_mode & S_IWGRP || |
st1.st_mode & S_IRGRP || st1.st_mode & S_IWGRP || |
149 |
st1.st_mode & S_IROTH || st1.st_mode & S_IWOTH ) { |
st1.st_mode & S_IROTH || st1.st_mode & S_IWOTH ) { |
150 |
close(fd); return -3; |
close(fd); raise_priv(euid,egid); return -3; |
151 |
} |
} |
152 |
/* Get expected space */ |
/* Get expected space */ |
153 |
if ( (buf=(char *)malloc(st1.st_size))==NULL) { |
if ( (buf=(char *)malloc(st1.st_size))==NULL) { |
154 |
close(fd); return -4; |
close(fd); raise_priv(euid,egid); return -4; |
155 |
} |
} |
156 |
/* use pointers to the two so that we can swap them easily */ |
/* use pointers to the two so that we can swap them easily */ |
157 |
sptr1=&st1; sptr2=&st2; |
sptr1=&st1; sptr2=&st2; |
206 |
} |
} |
207 |
|
|
208 |
/** |
/** |
209 |
|
* Used to read in a config file, the path is checked to be trusted using |
210 |
|
* safe_is_path_trusted_r() from the safefile library of J. Kupsch. |
211 |
|
* Upon successful completion config contains the contents of path |
212 |
|
* Return values: |
213 |
|
* 0: succes |
214 |
|
* -1: I/O error |
215 |
|
* -2: privilege-drop error |
216 |
|
* -3: permission error (untrusted path) |
217 |
|
* -4: memory error |
218 |
|
* -5: unknown or safefile error |
219 |
|
*/ |
220 |
|
int cgul_read_config(const char *path, char **config, gid_t read_gid) { |
221 |
|
int fd,rc,trust; |
222 |
|
uid_t uid=getuid(),euid=geteuid(); |
223 |
|
gid_t gid=getgid(),egid=getegid(),target_gid=read_gid<0 ? gid : read_gid; |
224 |
|
struct safe_id_range_list ulist,glist; |
225 |
|
struct stat st; |
226 |
|
char *buf; |
227 |
|
|
228 |
|
/* Drop privilege to real uid and special read group */ |
229 |
|
if (priv_drop(uid,read_gid)) |
230 |
|
return -2; |
231 |
|
/* initialize the lists of trusted uid/gid, can basically only fail when |
232 |
|
* out of memory */ |
233 |
|
if ( safe_init_id_range_list(&ulist) || |
234 |
|
safe_init_id_range_list(&glist) || |
235 |
|
safe_add_id_to_list(&ulist,uid) || |
236 |
|
safe_add_id_to_list(&glist,target_gid) ) { |
237 |
|
raise_priv(euid,egid); return -4; |
238 |
|
} |
239 |
|
/* Check trust */ |
240 |
|
trust=safe_is_path_trusted_r(path,&ulist,&glist); |
241 |
|
/* free the range lists */ |
242 |
|
safe_destroy_id_range_list(&ulist); |
243 |
|
safe_destroy_id_range_list(&glist); |
244 |
|
/* Check the level of trust */ |
245 |
|
switch (trust) { |
246 |
|
case SAFE_PATH_ERROR: |
247 |
|
raise_priv(euid,egid); return -5; break; /* */ |
248 |
|
case SAFE_PATH_UNTRUSTED: |
249 |
|
case SAFE_PATH_TRUSTED_STICKY_DIR: |
250 |
|
raise_priv(euid,egid); return -3; break; /* Perms are somehow wrong */ |
251 |
|
case SAFE_PATH_TRUSTED: |
252 |
|
case SAFE_PATH_TRUSTED_CONFIDENTIAL: |
253 |
|
break; /* trusted */ |
254 |
|
default: |
255 |
|
raise_priv(euid,egid); return -5; break; /* unknown error */ |
256 |
|
} |
257 |
|
/* Open file and stat the file (latter for size) */ |
258 |
|
if ((fd=open(path,O_RDONLY))==-1 || fstat(fd,&st)) { |
259 |
|
raise_priv(euid,egid); return -1; |
260 |
|
} |
261 |
|
/* Get expected space */ |
262 |
|
if ( (buf=(char *)malloc(st.st_size))==NULL) { |
263 |
|
close(fd); raise_priv(euid,egid); return -4; |
264 |
|
} |
265 |
|
/* Read the file, check we get right size */ |
266 |
|
if (read(fd,buf,st.st_size)!=st.st_size) |
267 |
|
/* read error, but don't return yet, we want to free the memory centrally */ |
268 |
|
rc=-1; |
269 |
|
else |
270 |
|
rc=0; |
271 |
|
/* Close file */ |
272 |
|
close(fd); |
273 |
|
/* reset euid/egid if it was (effective) root. Ignore exit value. */ |
274 |
|
raise_priv(euid,egid); |
275 |
|
/* finalize */ |
276 |
|
if (rc!=0) |
277 |
|
free(buf); |
278 |
|
else /* Only now put buf in *proxy */ |
279 |
|
*config=buf; |
280 |
|
return rc; |
281 |
|
} |
282 |
|
|
283 |
|
/** |
284 |
* Writes proxy from *proxy to *path using given lock_type (see cgul_filelock). |
* Writes proxy from *proxy to *path using given lock_type (see cgul_filelock). |
285 |
* It tries to drop privilege to given write_uid, gid_t write_gid. When either |
* It tries to drop privilege to given write_uid, gid_t write_gid. When either |
286 |
* of them is -1, that one is ignored. |
* of them is -1, that one is ignored. |
427 |
free(dir); |
free(dir); |
428 |
return rc; |
return rc; |
429 |
} |
} |
|
|
|
|
#if 0 |
|
|
/*************************************************************************/ |
|
|
/* config read */ |
|
|
char *safe_read_file_readonly(char *name) { |
|
|
drop_priv(); |
|
|
fd=fopen(name); |
|
|
st1=fstat(fd); /* 0X00 & owned ? */ |
|
|
st2=pathcheck(name); /* -> lstat() */ |
|
|
if (st1!=st2) |
|
|
kill; |
|
|
buffer=malloc(); |
|
|
read_file(fd,buffer); |
|
|
close(); |
|
|
raise_priv(); |
|
|
return buffer; |
|
|
} |
|
|
#endif |
|