source: trunk/src/trustfile.c@ 91

Last change on this file since 91 was 76, checked in by rainer, 18 years ago

Fix for ticket #38 (csv escaping) and #39 (building on cygwin). Also optimize a bit.

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