source: trunk/src/trustfile.c@ 132

Last change on this file since 132 was 131, checked in by rainer, 17 years ago

Use thread-safe libc functions.

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