source: trunk/src/trustfile.c@ 217

Last change on this file since 217 was 211, checked in by katerina, 16 years ago

Allow shell expansion for cofiguration file values (ticket #137).

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