source: trunk/src/trustfile.c@ 592

Last change on this file since 592 was 592, checked in by katerina, 7 days ago

Fixes for compiler warnings.

File size: 29.8 KB
RevLine 
[1]1/* debug problems */
2/* #define TRUST_DEBUG */
3
4/* switch off full check */
5/* #define TEST_ONLY */
6
7/* standalone */
8/* #define TRUST_MAIN */
9/* $(CC) -DTRUST_MAIN -DSL_ALWAYS_TRUSTED=... */
10
11/* LINTLIBRARY */
12/*
13 * This is the file with all the library routines in it
14 *
15 * Author information:
16 * Matt Bishop
17 * Department of Computer Science
18 * University of California at Davis
19 * Davis, CA 95616-8562
20 * phone (916) 752-8060
21 * email bishop@cs.ucdavis.edu
22 *
23 * This code is placed in the public domain. I do ask that
24 * you keep my name associated with it, that you not represent
25 * it as written by you, and that you preserve these comments.
26 * This software is provided "as is" and without any guarantees
27 * of any sort.
28 *
29 * Compilation notes:
30 * * this does NOT use malloc(3), but fixed storage. this means we
31 * do lots of bounds checking, but it still is faster, and smaller,
32 * than forcing inclusion of malloc. All buffers etc. are of size
33 * MAXFILENAME (defined in trustfile.h); to get more room, recompile
34 * with this set larger.
35 * * if you support the following directory semantics, define STICKY;
36 * otherwise, undefine it
37 * "if a directory is both world-writeable AND has the sticky bit
38 * set, then ONLY the owner of an existing file may delete it"
39 * On some systems (eg, IRIX), you can delete the file under these
40 * conditions if the file is world writeable. Foor our purposes,
41 * this is irrelevant since if the file is world-writeable it is
42 * untrustworthy; either it can be replaced with another file (the
43 * IRIX version) or it can be altered (all versions).
44 * if this is true and STICKY is not set, the sticky bit is ignored
45 * and the directory will be flagged as untrustworthy, even when only
46 * a trusted user could delete the file
47 * * this uses a library call to get the name of the current working
48 * directory. Define the following to get the various versions:
49 * GETCWD for Solaris 2.x, SunOS 4.1.x, IRIX 5.x
50 * char *getcwd(char *buf, int bufsz);
51 * where buf is a buffer for the path name, and bufsz is
52 * the size of the buffer; if the size if too small, you
53 * get an error return (NULL)
54 * GETWD for Ultrix 4.4
55 * char *getwd(char *buf)
56 * where buf is a buffer for the path name, and it is
57 * assumed to be at lease as big as MAXPATHLEN.
58 * *** IMPORTANT NOTE ***
59 * Ultrix supports getcwd as well, but it uses popen to
60 * run the command "pwd" (according to the manual). This
61 * means it's vulnerable to a number of attacks if used
62 * in a privileged program. YOU DON'T WANT THIS.
63 * * the debugging flag DEBUG prints out each step of the file name
64 * checking, as well as info on symbolic links (if S_IFLNK defined),
65 * file name canonicalization, and user, group, and permission for
66 * each file or directory; this is useful if you want to be sure
67 * you're checking the right file
68 *
69 * Version information:
70 * 1.0 December 28, 1995 Matt Bishop
71 *
72 * 2.0 March 26, 2000 Rainer Wichmann -- adapted for slib.
73 */
74
75/* --- Why strcpy is safe here: ---- */
76
77/* The input path is checked once, and then either shortened [in dirz()],
78 * or safely expanded (symlinks) with bound checking.
79 * I.e., the path length can never exceed (MAXFILENAME-1), while the path
80 * is always copied between buffers of length MAXFILENAME.
81 */
82
83#ifndef TRUST_MAIN
84#include "config_xor.h"
85#include "sh_calls.h"
86#else
87#define UID_CAST long
[220]88#define HAVE_GETPWENT
89#define SH_MUTEX_LOCK(a) ((void)0)
90#define SH_MUTEX_UNLOCK(a) ((void)0)
[1]91#endif
92
93#include <stdio.h>
94#include <stdlib.h>
95#include <sys/types.h>
96#include <sys/stat.h>
97#include <grp.h>
98#include <pwd.h>
99#include <string.h>
100#include <unistd.h>
[430]101#include <errno.h>
[1]102
103
[481]104#if !defined(TRUST_MAIN)
[131]105
[1]106#include "slib.h"
107#define SH_NEED_PWD_GRP 1
108#include "sh_static.h"
[137]109#include "sh_pthread.h"
[1]110
111#else
112
113#define sh_getgrgid getgrgid
[131]114#define sh_getgrgid_r getgrgid_r
[1]115#define sh_getpwnam getpwnam
[131]116#define sh_getpwnam_r getpwnam_r
[1]117#define sh_getpwuid getpwuid
[131]118#define sh_getpwuid_r getpwuid_r
119#define sh_getpwent getpwent
[1]120#define sh_endpwent endpwent
121
122#define TRUST_DEBUG
[481]123#define S_FALSE 0
124#define S_TRUE 1
[1]125#define SL_ENTER(string)
126#define SL_IRETURN(a, b) return a
127#define retry_lstat(a,b,c,d) lstat(c,d)
128#define _(string) string
129#define N_(string) string
130#define MAXFILENAME 4096
131static int sl_errno = 0;
132#define SL_ENONE 0
133#define SL_ENULL -1024 /* Invalid use of NULL pointer. */
134#define SL_ERANGE -1025 /* Argument out of range. */
135#define SL_ETRUNC -1026 /* Result truncated. */
136#define SL_EINTERNAL -1028 /* Internal error. */
137#define SL_EBADFILE -1030 /* File access error. Check errno. */
[230]138#define SL_EMEM -1032 /* Out of memory. */
[1]139#define SL_EBADNAME -1040 /* Invalid name. */
140#define SL_ESTAT -1041 /* stat of file failed. Check errno. */
141#define SL_EBADUID -1050 /* Owner not trustworthy. */
142#define SL_EBADGID -1051 /* Group writeable and not trustworthy.*/
143#define SL_EBADOTH -1052 /* World writeable. */
144
145#endif
146
147
148#if defined(__linux__) || defined(__FreeBSD__)
149#define STICKY
150#endif
151
152#undef FIL__
153#define FIL__ _("trustfile.c")
154
155/*
156 * the get current working directory function
157 * every version of UNIX seems to have its own
158 * idea of how to do this, so we group them by
159 * arguments ...
160 * all must return a pointer to the right name
161 */
162
163
164#ifndef TRUST_MAIN
165
166#if defined(HAVE_GETCWD) && !defined(HAVE_BROKEN_GETCWD)
167#define CURDIR(buf,nbuf) getcwd((buf), (nbuf))
168#elif defined(HAVE_GETWD)
169#define CURDIR(buf,nbuf) getwd((buf))
170#endif
171
172#else
173
174#define CURDIR(buf,nbuf) getcwd((buf), (nbuf))
175
176#endif
177
178
179
180/*
181 * this checks to see if there are symbolic links
182 * assumes the link bit in the protection mask is called S_IFLNK
183 * (seems to be true on all UNIXes with them)
184 */
185#ifndef S_IFLNK
186#define lstat stat
187#endif
188
189
190/*
191 * these are useful global variables
192 *
193 * first set: who you gonna trust, by default?
194 * if the user does not specify a trusted or untrusted set of users,
195 * all users are considered untrusted EXCEPT:
196 * UID 0 -- root as root can do anything on most UNIX systems, this
197 * seems reasonable
198 * tf_euid -- programmer-selectable UID
199 * if the caller specifies a specific UID by putting
200 * it in this variable, it will be trusted; this is
201 * typically used to trust the effective UID of the
202 * process (note: NOT the real UID, which will cause all
203 * sorts of problems!) By default, this is set to -1,
204 * so if it's not set, root is the only trusted user
205 */
206
207/* modified Tue Feb 22 10:36:44 NFT 2000 Rainer Wichmann */
208
209
210#ifndef SL_ALWAYS_TRUSTED
211#define SL_ALWAYS_TRUSTED 0
212#endif
[474]213uid_t test_rootonly[] = { SL_ALWAYS_TRUSTED };
[1]214
215#define tf_uid_neg ((uid_t)-1)
216
217uid_t rootonly[] = { SL_ALWAYS_TRUSTED,
218 tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg,
219 tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg,
220 tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg,
221 tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg };
222
223uid_t tf_euid = tf_uid_neg;
[481]224unsigned int EUIDSLOT = sizeof(test_rootonly)/sizeof(uid_t);
225unsigned int ORIG_EUIDSLOT = sizeof(test_rootonly)/sizeof(uid_t);
[1]226
227char tf_path[MAXFILENAME]; /* error path for trust function */
228uid_t tf_baduid;
229gid_t tf_badgid;
230
231static
232int dirz(char *path)
233{
234 register char *p = path;/* points to rest of path to clean up */
235 register char *q; /* temp pointer for skipping over stuff */
236
237 static char swp[MAXFILENAME];
238
239 SL_ENTER(_("dirz"));
240 /*
241 * standard error checking
242 */
243 if (path == NULL)
244 SL_IRETURN(SL_ENULL, _("dirz"));
245 if (path[0] == '.')
246 SL_IRETURN(SL_EINTERNAL, _("dirz"));
247
248
249 /*
250 * loop over the path name until everything is checked
251 */
252 while(*p)
253 {
254 /* skip
255 */
256 if (*p != '/')
257 {
258 p++;
259 continue;
260 }
261
262 /* "/./" or "/."
263 */
264 if (p[1] == '.' && (p[2] == '/' || p[2] == '\0'))
265 {
266 /* yes -- delete "/."
267 */
268 (void) strcpy(swp, &p[2]); /* known to fit */
269 (void) strcpy(p, swp); /* known to fit */
270
271 /* special case "/." as full path name
272 */
273 if (p == path && *p == '\0')
274 {
275 *p++ = '/';
276 *p = '\0';
277 }
278 }
279
280 /* "//"
281 */
282 else if (p[1] == '/')
283 {
284 /* yes -- skip
285 */
286 for(q = &p[2]; *q == '/'; q++)
287 ;
288 (void) strcpy(swp, q); /* known to fit */
289 (void) strcpy(&p[1], swp); /* known to fit */
290 }
291
292 /* "/../" or "/.."
293 */
294 else if (p[1] == '.' && p[2] == '.' && (p[3] == '/' || p[3] == '\0'))
295 {
296 /* yes -- if it's root, delete .. only
297 */
298 if (p == path)
299 {
300 (void) strcpy(swp, &p[3]); /* known to fit */
301 (void) strcpy(p, swp); /* known to fit */
302 }
303 else
304 {
305 /* back up over previous component
306 */
307 q = p - 1;
308 while(q != path && *q != '/')
309 q--;
310 /* now wipe it out
311 */
312 (void) strcpy(swp, &p[3]); /* known to fit */
313 (void) strcpy(q, swp); /* known to fit */
314 p = q;
315 }
316 }
317 else
318 p++;
319 }
320 SL_IRETURN(SL_ENONE, _("dirz"));
321}
322
323
324
325/* not static to circumvent stupid gcc 4 bug */
[183]326int getfname(const char *fname, char *rbuf, int rsz)
[1]327{
328#ifndef TRUST_MAIN
329 register int status;
330#endif
331
332 SL_ENTER(_("getfname"));
333 /*
334 * do the initial checking
335 * NULL pointer
336 */
337 if (fname == NULL || rbuf == NULL)
338 SL_IRETURN(SL_ENULL, _("getfname"));
339 if (rsz <= 0)
340 SL_IRETURN(SL_ERANGE, _("getfname"));
341
342
343 /* already a full path name */
344 if (*fname == '/')
345 rbuf[0] = '\0';
346 else
347 {
348 if (CURDIR(rbuf, rsz) == NULL)
349 {
350#ifdef TRUST_DEBUG
351 fprintf(stderr, "trustfile: getcwd failed\n");
352#endif
353 SL_IRETURN(SL_EBADNAME, _("getfname"));
354 }
355 }
356
357 /*
358 * append the file name and reduce
359 */
360 if (fname != NULL && *fname != '\0')
361 {
362#ifndef TRUST_MAIN
363 status = sl_strlcat(rbuf, "/", rsz);
364 if (status == SL_ENONE)
365 status = sl_strlcat(rbuf, fname, rsz);
366 if (status != SL_ENONE)
367 SL_IRETURN(status, _("getfname"));
368#else
[220]369 strncat(rbuf, "/", rsz-strlen(rbuf)-1);
[221]370 rbuf[rsz-1] = '\0';
[220]371 strncat(rbuf, fname, rsz-strlen(rbuf)-1);
372 rbuf[rsz-1] = '\0';
[1]373#endif
374 }
375 SL_IRETURN(dirz(rbuf), _("getfname"));
376}
377
378static
379int isin(uid_t n, uid_t *list)
380{
381 SL_ENTER(_("isin"));
382 if (list == NULL)
[481]383 SL_IRETURN(S_FALSE, _("isin"));
[1]384
385 while(*list != tf_uid_neg && *list != n)
386 {
387#ifdef TRUST_DEBUG
388 fprintf (stderr,
389 "trustfile: owner_uid=%ld, trusted uid=%ld, no match\n",
390 (UID_CAST) n, (UID_CAST) *list);
391#endif
392 list++;
393 }
394
395 if (*list == tf_uid_neg)
396 {
397#ifdef TRUST_DEBUG
398 fprintf (stderr,
399 "trustfile: owner_uid=%ld, no match with any trusted user --> ERROR\n",
400 (UID_CAST) n);
401#endif
[481]402 SL_IRETURN(S_FALSE, _("isin"));
[1]403 }
404
405#ifdef TRUST_DEBUG
406 fprintf (stderr,
407 "trustfile: owner_uid=%ld, trusted_uid=%ld, match found --> OK\n",
408 (UID_CAST)n, (UID_CAST)*list);
409#endif
[481]410 SL_IRETURN(S_TRUE, _("isin"));
[1]411}
412
413/* comment added by R. Wichmann
414 * RETURN TRUE if ANYONE in ulist is group member
415 */
416/* not static to circumvent stupid gcc 4 bug */
[428]417int isingrp(gid_t grp, uid_t *ulist, int * errval)
[1]418{
[137]419 struct passwd *w; /* info about group member */
[1]420 register uid_t *u; /* points to current ulist member */
421 register char **p; /* points to current group member */
[137]422 struct group *g; /* pointer to group information */
[428]423
424 int status;
[1]425
[131]426#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
427 struct group gr;
[227]428 char * buffer = NULL;
[131]429 struct passwd pwd;
[227]430 char * pbuffer = NULL;
[131]431#endif
432
[1]433 SL_ENTER(_("isingrp"));
434
[428]435 *errval = 0;
436
[131]437#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
[454]438 buffer = calloc(1,SH_GRBUF_SIZE);
[592]439 if (!buffer)
440 goto end_false;
[428]441 status = sh_getgrgid_r(grp, &gr, buffer, SH_GRBUF_SIZE, &g);
[131]442#else
[428]443 errno = 0;
[131]444 g = sh_getgrgid(grp);
[428]445 status = errno;
[131]446#endif
447
448 if (g == NULL)
[1]449 {
[428]450 if (status == ERANGE)
451 *errval = status;
452
[227]453 goto end_false;
[1]454 }
455
456 /* this will return at the first match
457 */
[227]458#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
[454]459 pbuffer = calloc(1,SH_PWBUF_SIZE);
[592]460 if (!pbuffer)
461 goto end_false;
[227]462#endif
463
[1]464 for(p = g->gr_mem; *p != NULL; p++)
465 {
466 for(u = ulist; *u != tf_uid_neg; u++)
467 {
468 /* map user name to UID and compare */
[131]469#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
[227]470 sh_getpwnam_r(*p, &pwd, pbuffer, SH_PWBUF_SIZE, &w);
[131]471#else
472 w = sh_getpwnam(*p);
473#endif
474
[1]475#ifdef TRUST_MAIN
[131]476 if (w != NULL && *u == (uid_t)(w->pw_uid) )
[227]477 goto end_true;
[1]478#else
[131]479 if (w != NULL && *u == (uid_t)(w->pw_uid) )
[1]480 {
[227]481 goto end_true;
[1]482 }
483#endif
484 }
485 }
486 /* added by R. Wichmann Fri Mar 30 08:16:14 CEST 2001:
487 * a user can have a GID but no entry in /etc/group
488 */
489 for(u = ulist; *u != tf_uid_neg; u++)
490 {
[131]491#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
[227]492 sh_getpwuid_r(*u, &pwd, pbuffer, SH_PWBUF_SIZE, &w);
[131]493#else
494 w = sh_getpwuid(*u);
495#endif
[1]496#ifdef TRUST_MAIN
[131]497 if (w != NULL && grp == (gid_t)(w->pw_gid) )
[227]498 goto end_true;
[1]499#else
[131]500 if (w != NULL && grp == (gid_t)(w->pw_gid) )
[1]501 {
[227]502 goto end_true;
[1]503 }
504#endif
505 }
506
[227]507 end_false:
508#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
509 if (buffer) free(buffer);
510 if (pbuffer) free(pbuffer);
511#endif
[481]512 SL_IRETURN(S_FALSE, _("isingrp"));
[227]513
514 end_true:
515#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
516 if (buffer) free(buffer);
517 if (pbuffer) free(pbuffer);
518#endif
[481]519 SL_IRETURN(S_TRUE, _("isingrp"));
[1]520}
521
522/* added by R. Wichmann Fri Mar 30 08:16:14 CEST 2001
523 * RETURN TRUE only if ALL group members are trusted
524 */
525/* not static to circumvent stupid gcc 4 bug */
[428]526int onlytrustedingrp(gid_t grp, uid_t *ulist, int * errval)
[1]527{
[137]528 struct passwd *w; /* info about group member */
[1]529 register uid_t *u; /* points to current ulist member */
530 register char **p; /* points to current group member */
[137]531 struct group *g; /* pointer to group information */
[1]532 register int flag = -1; /* group member found */
533
[428]534 int status;
535
[131]536#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
537 struct group gr;
[227]538 char * buffer = NULL;
[137]539 struct passwd pw;
[227]540 char * pbuffer = NULL;
[131]541#endif
542
[481]543 int retval = S_FALSE;
[134]544
[1]545 SL_ENTER(_("onlytrustedingrp"));
546
[428]547 *errval = 0;
548
[1]549#ifdef TRUST_DEBUG
550 fprintf(stderr, "trustfile: group writeable, group_gid: %ld\n",
551 (UID_CAST)grp);
552#endif
553
[131]554#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
[454]555 buffer = calloc(1,SH_GRBUF_SIZE);
[592]556 if (!buffer) {
557 retval = S_FALSE;
558 goto end_retval;
559 }
[428]560 status = sh_getgrgid_r(grp, &gr, buffer, SH_GRBUF_SIZE, &g);
[131]561#else
[428]562 errno = 0;
[131]563 g = sh_getgrgid(grp);
[428]564 status = errno;
[131]565#endif
566
567 if (g == NULL)
[1]568 {
[428]569 if (status == ERANGE)
570 *errval = status;
571
[1]572#ifdef TRUST_DEBUG
573 fprintf(stderr,
574 "trustfile: group_gid: %ld, no such group --> ERROR\n",
575 (UID_CAST)grp);
576#endif
[481]577 retval = S_FALSE;
[227]578 goto end_retval;
[1]579 }
580
581 /* empty group -> no problem
582
583 if(g->gr_mem == NULL || g->gr_mem[0] == NULL )
[481]584 SL_IRETURN(S_TRUE, _("onlytrustedingrp") );
[1]585 */
586
587 /* check for untrusted members of the group
588 */
[227]589#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
[454]590 pbuffer = calloc(1,SH_PWBUF_SIZE);
[592]591 if (!pbuffer) {
592 retval = S_FALSE;
593 goto end_retval;
594 }
[227]595#endif
596
[1]597 for(p = g->gr_mem; *p != NULL; p++)
598 {
599 flag = -1;
600#ifdef TRUST_DEBUG
601 fprintf(stderr, "trustfile: group_member: %s\n", *p);
602#endif
603 /* map user name to UID and compare
604 */
[131]605#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
[227]606 sh_getpwnam_r(*p, &pw, pbuffer, SH_PWBUF_SIZE, &w);
[131]607#else
[1]608 w = sh_getpwnam(*p);
609#endif
[131]610
[1]611 if (w == NULL) /* not a valid user, ignore */
612 {
613 flag = 0;
614 }
615 else /* check list of trusted users */
616 {
617#ifdef TRUST_DEBUG
618 fprintf (stderr,
619 "trustfile: uid=%ld, checking whether it is trusted\n",
620 (UID_CAST)(w->pw_uid));
621#endif
622 for(u = ulist; *u != tf_uid_neg; u++)
623 {
624 if (*u == (w->pw_uid) )
625 {
626#ifdef TRUST_DEBUG
627 fprintf (stderr,
628 "trustfile: uid=%ld, trusted_uid=%ld, match found --> OK\n",
629 (UID_CAST)(w->pw_uid), (UID_CAST)*u);
630#endif
631 flag = 0;
632 break;
633 }
634 else
635 {
636#ifdef TRUST_DEBUG
637 fprintf (stderr,
638 "trustfile: uid=%ld, trusted_uid=%ld, no match\n",
639 (UID_CAST)(w->pw_uid), (UID_CAST)*u);
640#endif
641 ;
642 }
643 }
644 }
645 /* not found
646 */
647 if (flag == -1)
648 {
649#ifdef TRUST_DEBUG
650 fprintf (stderr,
651 "trustfile: user=%s (gid %ld), not a trusted user --> ERROR\n", *p, (UID_CAST)grp);
652#endif
653 tf_baduid = w->pw_uid;
[481]654 retval = S_FALSE;
[227]655#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
656 if (pbuffer) free(pbuffer);
657#endif
658 goto end_retval;
[1]659 }
660 }
661
[227]662#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
663 if (pbuffer) free(pbuffer);
664#endif
665
[1]666#ifndef TEST_ONLY
667#ifdef HAVE_GETPWENT
668 /* now check ALL users for their GID !!!
669 */
[134]670 SH_MUTEX_LOCK(mutex_pwent);
671
[1]672 while (NULL != (w = sh_getpwent()))
673 {
674 if (grp == (gid_t)(w->pw_gid))
675 {
676#ifdef TRUST_DEBUG
677 fprintf(stderr, "trustfile: checking group member %s, uid %ld\n",
678 w->pw_name, (UID_CAST)w->pw_uid);
679#endif
680 /* is it a trusted user ?
681 */
682 flag = -1;
683 for(u = ulist; *u != tf_uid_neg; u++)
684 {
685 if (*u == (uid_t)(w->pw_uid))
686 {
687#ifdef TRUST_DEBUG
688 fprintf (stderr,
689 "trustfile: uid=%ld, trusted_uid=%ld, match found --> OK\n",
[220]690 (UID_CAST)(w->pw_uid), (UID_CAST)(*u));
[1]691#endif
692 flag = 0;
693 break;
694 }
695 else
696 {
697#ifdef TRUST_DEBUG
698 fprintf (stderr,
699 "trustfile: uid=%ld, trusted_uid=%ld, no match\n",
700 (UID_CAST)(w->pw_uid), (UID_CAST)*u);
701#endif
702 ;
703 }
704 }
705 /* not found */
706 if (flag == -1)
707 {
708#ifdef TRUST_DEBUG
709 fprintf(stderr,"trustfile: group member %s not found in trusted users --> ERROR\n", w->pw_name);
710#endif
711 tf_baduid = w->pw_uid;
[481]712 retval = S_FALSE;
[134]713 goto out;
[481]714 /* SL_IRETURN(S_FALSE, _("onlytrustedingrp")); */
[1]715 }
716 }
717 }
[481]718 retval = S_TRUE;
[1]719
[134]720 out:
721
[1]722#ifdef HAVE_ENDPWENT
723 sh_endpwent();
724#endif
[134]725
726 SH_MUTEX_UNLOCK(mutex_pwent);
727
[1]728 /* TEST_ONLY */
729#endif
730 /* #ifdef HAVE_GETPWENT */
731#endif
732
733#ifdef TRUST_DEBUG
[481]734 if (retval == S_TRUE)
[134]735 fprintf(stderr,
736 "trustfile: group %ld: all members are trusted users --> OK\n",
737 (UID_CAST)grp);
[1]738#endif
739 /* all found
740 */
[227]741 end_retval:
742#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
743 if (buffer) free(buffer);
744#endif
[134]745 SL_IRETURN(retval, _("onlytrustedingrp"));
[1]746}
747
[183]748int sl_trustfile(const char *fname, uid_t *okusers, uid_t *badusers)
[1]749{
[227]750 char * fexp = NULL; /* file name fully expanded */
751 register char *p; /* used to hold name to be checked */
[1]752 struct stat stbuf; /* used to check file permissions */
753 char c; /* used to hold temp char */
754
[428]755 int errgrp = 0;
756
[1]757 SL_ENTER(_("sl_trustfile"));
758 if (fname == NULL)
759 SL_IRETURN(SL_EBADFILE, _("sl_trustfile"));
760
[454]761 fexp = calloc(1, MAXFILENAME );
[227]762 if (!fexp)
763 SL_IRETURN(SL_EMEM, _("sl_trustfile"));
764
765 p = fexp;
766
[1]767 /*
768 * next expand to the full file name
769 * getfname sets sl_errno as appropriate
770 */
771#ifdef TRUST_MAIN
772 sl_errno = getfname(fname, fexp, MAXFILENAME);
773 if (sl_errno != 0)
[227]774 {
775 free(fexp);
776 return sl_errno;
777 }
[1]778#else
779 if (SL_ISERROR(getfname(fname, fexp, MAXFILENAME)))
[227]780 {
781 free(fexp);
[1]782 SL_IRETURN(sl_errno, _("sl_trustfile"));
[227]783 }
[1]784#endif
785
786 if (okusers == NULL && badusers == NULL)
787 {
788 okusers = rootonly;
789 rootonly[EUIDSLOT] = tf_euid;
790 }
791
792 /*
793 * now loop through the path a component at a time
794 * note we have to special-case root
795 */
796 while(*p)
797 {
798 /*
799 * get next component
800 */
801 while(*p && *p != '/')
802 p++;
803
804 /* save where you are
805 */
806 if (p == fexp)
807 {
808 /* keep the / if it's the root dir
809 */
810 c = p[1];
811 p[1] = '\0';
812 }
813 else
814 {
815 /* clobber the / if it isn't the root dir
816 */
817 c = *p;
818 *p = '\0';
819 }
820
821 /*
822 * now get the information
823 */
824 if (retry_lstat(FIL__, __LINE__, fexp, &stbuf) < 0)
825 {
[76]826 (void) strncpy(tf_path, fexp, sizeof(tf_path));
827 tf_path[sizeof(tf_path)-1] = '\0';
[1]828#ifdef TRUST_MAIN
829 fprintf(stderr, "---------------------------------------------\n");
[76]830 fprintf(stderr, "trustfile: ESTAT: stat(%s) failed,\n", fexp);
831 fprintf(stderr, "maybe the file does not exist\n");
[1]832 fprintf(stderr, "---------------------------------------------\n");
833#endif
[227]834 free(fexp);
[1]835 SL_IRETURN(SL_ESTAT, _("sl_trustfile"));
836 }
837
838#ifdef S_IFLNK
839 /*
840 * if it's a symbolic link, recurse
841 */
842 if ((stbuf.st_mode & S_IFLNK) == S_IFLNK)
843 {
844 /*
845 * this is tricky
846 * if the symlink is to an absolute path
847 * name, just call trustfile on it; but
848 * if it's a relative path name, it's
849 * interpreted WRT the current working
850 * directory AND NOT THE FILE NAME!!!!!
851 * so, we simply put /../ at the end of
852 * the file name, then append the symlink
853 * contents; trustfile will canonicalize
854 * this, and the /../ we added "undoes"
855 * the name of the symlink to put us in
856 * the current working directory, at
857 * which point the symlink contents (appended
858 * to the CWD) are interpreted correctly.
859 * got it?
860 */
[227]861 char * csym; /* contents of symlink file */
862 char * full; /* "full" name of symlink */
[481]863 char *b; /* used to copy stuff around */
864 const char *t; /* used to copy stuff around */
865 int lsym; /* num chars in symlink ref */
866 int i; /* trustworthy or not? */
[170]867 const char * t_const;
[171]868 char *end;
[1]869
870 /*
871 * get what the symbolic link points to
872 *
873 * The original code does not check the return code of readlink(),
874 * and has an off-by-one error
875 * (MAXFILENAME instead of MAXFILENAME-1)
876 * R.W. Tue May 29 22:05:16 CEST 2001
877 */
[454]878 csym = calloc(1, MAXFILENAME );
[227]879 if (!csym)
880 {
881 free(fexp);
882 SL_IRETURN(SL_EMEM, _("sl_trustfile"));
883 }
884
[1]885 lsym = readlink(fexp, csym, MAXFILENAME-1);
886 if (lsym >= 0)
887 csym[lsym] = '\0';
888 else
889 {
890#ifdef TRUST_MAIN
891 fprintf(stderr, "---------------------------------------------\n");
892 fprintf(stderr, "trustfile: EBADNAME: readlink(%s) failed\n",
893 fexp);
894 fprintf(stderr, "---------------------------------------------\n");
895#endif
[227]896 free(csym);
897 free(fexp);
[1]898 SL_IRETURN(SL_EBADNAME, _("sl_trustfile"));
899 }
900
[454]901 full = calloc(1, MAXFILENAME );
[227]902 if (!full)
903 {
904 free(csym);
905 free(fexp);
906 SL_IRETURN(SL_EMEM, _("sl_trustfile"));
907 }
908
[1]909 /*
910 * relative or absolute referent?
911 */
912 if (csym[0] != '/')
913 {
[171]914 /* pointer to one above last element
915 */
916 end = &full[MAXFILENAME-1]; ++end;
917
[1]918 /* initialize pointers
919 */
920 b = full;
921
922 /* copy in base path
923 */
924 t = fexp;
[171]925 while(*t && b < end)
[1]926 *b++ = *t++;
927
928 /* smack on the /../
929 */
[481]930 t_const = "/../"; t = (const char *)t_const;
[171]931 while(*t && b < end)
[211]932 *b++ = *t++;
[1]933
934 /* append the symlink referent
935 */
936 t = csym;
[171]937 while(*t && b < end)
[1]938 *b++ = *t++;
939
940 /* see if we're too big
941 */
[171]942 if (*t || b == end)
[1]943 {
944 /* yes -- error
945 */
[76]946 (void) strncpy(tf_path, fexp, sizeof(tf_path));
947 tf_path[sizeof(tf_path)-1] = '\0';
[1]948#ifdef TRUST_MAIN
949 fprintf(stderr, "---------------------------------------------\n");
950 fprintf(stderr,
951 "trustfile: ETRUNC: normalized path too long (%s)\n",
952 fexp);
953 fprintf(stderr, "---------------------------------------------\n");
954#endif
[227]955 free(full);
956 free(csym);
957 free(fexp);
[1]958 SL_IRETURN(SL_ETRUNC, _("sl_trustfile"));
959 }
960 *b = '\0';
961 }
962 else
963 {
964 /* absolute -- just copy */
965 /* overflow can't occur as the arrays */
966 /* are the same size */
967 (void) strcpy(full, csym); /* known to fit */
968 }
969 /*
970 * now check out this file and its ancestors
971 */
972 if ((i = sl_trustfile(full, okusers, badusers)) != SL_ENONE)
[227]973 {
974 free(full);
975 free(csym);
976 free(fexp);
977 SL_IRETURN(i, _("sl_trustfile"));
978 }
[1]979
980 /*
981 * okay, this part is valid ... let's check the rest
982 * put the / back
983 */
984 if (p == fexp)
985 {
986 /* special case for root */
987 p[1] = c;
988 p++;
989 }
990 else
991 {
992 /* ordinary case for everything else */
993 *p = c;
994 if (*p)
995 p++;
996 }
[227]997 free(full);
998 free(csym);
[1]999 continue;
1000 }
1001#endif
1002
1003
1004#ifdef TRUST_DEBUG
1005 fprintf(stderr, "\ntrustfile: checking path=%s\n", fexp);
1006#endif
1007 /*
1008 * if the owner is not trusted then -- as the owner can
1009 * change protection modes -- he/she can write to the
1010 * file regardless of permissions, so bomb
1011 */
[481]1012 if (((okusers != NULL && S_FALSE == isin((uid_t)stbuf.st_uid,okusers))||
1013 (badusers != NULL && S_TRUE == isin((uid_t)stbuf.st_uid,badusers))))
[1]1014 {
1015#ifdef TRUST_DEBUG
1016 fprintf(stderr, "---------------------------------------------\n");
1017 fprintf(stderr, "trustfile: EBADUID %s (owner not trusted)\n",
1018 fexp);
1019 fprintf(stderr, "The owner of this file/directory is not in samhains\n");
1020 fprintf(stderr, "list of trusted users.\n");
1021 fprintf(stderr, "Please run ./configure again with the option\n");
1022 fprintf(stderr, " ./configure [more options] --with-trusted=0,...,UID\n");
1023 fprintf(stderr, "where UID is the UID of the (yet) untrusted user.\n");
1024 fprintf(stderr, "---------------------------------------------\n");
1025#endif
[76]1026 (void) strncpy(tf_path, fexp, sizeof(tf_path));
1027 tf_path[sizeof(tf_path)-1] = '\0';
1028
[1]1029 tf_baduid = (uid_t) stbuf.st_uid;
[227]1030 free(fexp);
[1]1031 SL_IRETURN(SL_EBADUID, _("sl_trustfile"));
1032 }
1033
1034 /*
1035 * if a group member can write but the
1036 * member is not trusted, bomb; but if
1037 * sticky bit semantics are honored, it's
1038 * okay
1039 */
1040 /* Thu Mar 29 21:10:28 CEST 2001 Rainer Wichmann
1041 * replace !isingrp() with onlytrustedingrp(), as isingrp()
1042 * will return at the first trusted user, even if there are additional
1043 * (untrusted) users in the group
1044 */
1045 if (((stbuf.st_mode & S_IWGRP) == S_IWGRP) &&
[428]1046 ((okusers != NULL && !onlytrustedingrp((gid_t)stbuf.st_gid,okusers,&errgrp))||
1047 (badusers != NULL && isingrp((gid_t)stbuf.st_gid, badusers,&errgrp)))
[1]1048#ifdef STICKY
1049 && ((stbuf.st_mode&S_IFDIR) != S_IFDIR ||
1050 (stbuf.st_mode&S_ISVTX) != S_ISVTX)
1051#endif
1052 )
1053 {
1054#ifdef TRUST_DEBUG
1055 fprintf(stderr, "---------------------------------------------\n");
1056 fprintf(stderr,
1057 "trustfile: EBADGID %ld %s (group member not trusted)\n",
1058 (UID_CAST)stbuf.st_gid, fexp);
1059 fprintf(stderr, "This file/directory is group writeable, and one of the group members\n");
1060 fprintf(stderr, "is not in samhains list of trusted users.\n");
1061 fprintf(stderr, "Please run ./configure again with the option\n");
1062 fprintf(stderr, " ./configure [more options] --with-trusted=0,...,UID\n");
1063 fprintf(stderr, "where UID is the UID of the (yet) untrusted user.\n");
1064 fprintf(stderr, "---------------------------------------------\n");
1065#endif
[76]1066 (void) strncpy(tf_path, fexp, sizeof(tf_path));
1067 tf_path[sizeof(tf_path)-1] = '\0';
1068
[1]1069 tf_badgid = (gid_t) stbuf.st_gid;
[227]1070 free(fexp);
[428]1071 SL_IRETURN((errgrp == ERANGE) ? SL_ERANGE : SL_EBADGID, _("sl_trustfile"));
[1]1072 }
1073 /*
1074 * if other can write, bomb; but if the sticky
1075 * bit semantics are honored, it's okay
1076 */
1077 if (((stbuf.st_mode & S_IWOTH) == S_IWOTH)
1078#ifdef STICKY
1079 && ((stbuf.st_mode&S_IFDIR) != S_IFDIR ||
1080 (stbuf.st_mode&S_ISVTX) != S_ISVTX)
1081#endif
1082 )
1083 {
1084#ifdef TRUST_DEBUG
1085 fprintf(stderr, "---------------------------------------------\n");
1086 fprintf(stderr, "trustfile: EBADOTH (world writeable): %s\n",
1087 fexp);
1088 fprintf(stderr, "This file/directory is world writeable.\n");
1089 fprintf(stderr, "---------------------------------------------\n");
1090#endif
[76]1091 (void) strncpy(tf_path, fexp, sizeof(tf_path));
1092 tf_path[sizeof(tf_path)-1] = '\0';
1093
[227]1094 free(fexp);
[1]1095 SL_IRETURN(SL_EBADOTH, _("sl_trustfile"));
1096 }
1097 /*
1098 * put the / back
1099 */
1100 if (p == fexp)
1101 {
1102 /* special case for root */
1103 p[1] = c;
1104 p++;
1105 }
1106 else
1107 {
1108 /* ordinary case for everything else */
1109 *p = c;
1110 if (*p)
1111 p++;
1112 }
1113 }
1114 /*
1115 * yes, it can be trusted
1116 */
[76]1117 (void) strncpy(tf_path, fexp, sizeof(tf_path));
1118 tf_path[sizeof(tf_path)-1] = '\0';
1119
[227]1120 free(fexp);
[1]1121 SL_IRETURN(SL_ENONE, _("sl_trustfile"));
1122}
1123
1124#ifdef TRUST_MAIN
[192]1125
1126#if defined(HOST_IS_CYGWIN) || defined(__cygwin__) || defined(__CYGWIN32__) || defined(__CYGWIN__)
1127int main()
1128{
1129 return 0;
1130}
1131#else
[1]1132int main (int argc, char * argv[])
1133{
1134 int status;
1135#if defined(SH_WITH_SERVER)
1136 struct passwd * pass;
1137#endif
1138
1139 if (argc < 2) {
1140 fprintf(stderr, "%s: Usage: %s <fullpath>\n", argv[0], argv[0]);
1141 return 1;
1142 }
1143
1144 tf_path[0] = '\0';
1145#if defined(SH_WITH_SERVER)
[131]1146 pass = sh_getpwnam(SH_IDENT); /* TESTONLY */
[1]1147 if (pass != NULL)
1148 tf_euid = pass->pw_uid;
1149 else
1150 {
1151 fprintf(stderr, "trustfile: ERROR: getpwnam(%s) failed\n",
1152 SH_IDENT);
1153 return 1;
1154 }
1155#else
1156 tf_euid = geteuid();
1157#endif
1158
1159 status = sl_trustfile(argv[1], NULL, NULL);
1160 if (status != SL_ENONE)
1161 {
1162 fprintf(stderr, "trustfile: ERROR: not a trusted path: %s\n",
1163 argv[1]);
1164 return 1;
1165 }
1166 return 0;
1167}
1168#endif
[192]1169#endif
[1]1170
1171
1172
Note: See TracBrowser for help on using the repository browser.