source: trunk/src/trustfile.c@ 153

Last change on this file since 153 was 137, checked in by rainer, 17 years ago

Fix compile errors.

File size: 27.2 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
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
[131]101
[1]102#include "slib.h"
103#define SH_NEED_PWD_GRP 1
104#include "sh_static.h"
[137]105#include "sh_pthread.h"
[1]106
107#else
108
109#define sh_getgrgid getgrgid
[131]110#define sh_getgrgid_r getgrgid_r
[1]111#define sh_getpwnam getpwnam
[131]112#define sh_getpwnam_r getpwnam_r
[1]113#define sh_getpwuid getpwuid
[131]114#define sh_getpwuid_r getpwuid_r
115#define sh_getpwent getpwent
[1]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(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{
[137]412 struct passwd *w; /* info about group member */
[1]413 register uid_t *u; /* points to current ulist member */
414 register char **p; /* points to current group member */
[137]415 struct group *g; /* pointer to group information */
[1]416
[131]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
[1]424 SL_ENTER(_("isingrp"));
425
[131]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)
[1]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 */
[131]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
[1]454#ifdef TRUST_MAIN
[131]455 if (w != NULL && *u == (uid_t)(w->pw_uid) )
[1]456 SL_IRETURN(SL_TRUE, _("isingrp"));
457#else
[131]458 if (w != NULL && *u == (uid_t)(w->pw_uid) )
[1]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 {
[131]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
[1]475#ifdef TRUST_MAIN
[131]476 if (w != NULL && grp == (gid_t)(w->pw_gid) )
[1]477 SL_IRETURN(SL_TRUE, _("isingrp"));
478#else
[131]479 if (w != NULL && grp == (gid_t)(w->pw_gid) )
[1]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{
[137]495 struct passwd *w; /* info about group member */
[1]496 register uid_t *u; /* points to current ulist member */
497 register char **p; /* points to current group member */
[137]498 struct group *g; /* pointer to group information */
[1]499 register int flag = -1; /* group member found */
500
[131]501#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
502 struct group gr;
503 char buffer[SH_GRBUF_SIZE];
[137]504 struct passwd pw;
[131]505 char pbuffer[SH_PWBUF_SIZE];
506#endif
507
[134]508 int retval = SL_FALSE;
509
[1]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
[131]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)
[1]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 */
[131]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
[1]552 w = sh_getpwnam(*p);
553#endif
[131]554
[1]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 */
[134]606 SH_MUTEX_LOCK(mutex_pwent);
607
[1]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;
[134]648 retval = SL_FALSE;
649 goto out;
650 /* SL_IRETURN(SL_FALSE, _("onlytrustedingrp")); */
[1]651 }
652 }
653 }
[134]654 retval = SL_TRUE;
[1]655
[134]656 out:
657
[1]658#ifdef HAVE_ENDPWENT
659 sh_endpwent();
660#endif
[134]661
662 SH_MUTEX_UNLOCK(mutex_pwent);
663
[1]664 /* TEST_ONLY */
665#endif
666 /* #ifdef HAVE_GETPWENT */
667#endif
668
669#ifdef TRUST_DEBUG
[134]670 if (retval == SL_TRUE)
671 fprintf(stderr,
672 "trustfile: group %ld: all members are trusted users --> OK\n",
673 (UID_CAST)grp);
[1]674#endif
675 /* all found
676 */
[134]677 SL_IRETURN(retval, _("onlytrustedingrp"));
[1]678}
679
680int sl_trustfile(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 {
[76]744 (void) strncpy(tf_path, fexp, sizeof(tf_path));
745 tf_path[sizeof(tf_path)-1] = '\0';
[1]746#ifdef TRUST_MAIN
747 fprintf(stderr, "---------------------------------------------\n");
[76]748 fprintf(stderr, "trustfile: ESTAT: stat(%s) failed,\n", fexp);
749 fprintf(stderr, "maybe the file does not exist\n");
[1]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
784 /*
785 * get what the symbolic link points to
786 *
787 * The original code does not check the return code of readlink(),
788 * and has an off-by-one error
789 * (MAXFILENAME instead of MAXFILENAME-1)
790 * R.W. Tue May 29 22:05:16 CEST 2001
791 */
792 lsym = readlink(fexp, csym, MAXFILENAME-1);
793 if (lsym >= 0)
794 csym[lsym] = '\0';
795 else
796 {
797#ifdef TRUST_MAIN
798 fprintf(stderr, "---------------------------------------------\n");
799 fprintf(stderr, "trustfile: EBADNAME: readlink(%s) failed\n",
800 fexp);
801 fprintf(stderr, "---------------------------------------------\n");
802#endif
803 SL_IRETURN(SL_EBADNAME, _("sl_trustfile"));
804 }
805
806 /*
807 * relative or absolute referent?
808 */
809 if (csym[0] != '/')
810 {
811 /* initialize pointers
812 */
813 b = full;
814
815 /* copy in base path
816 */
817 t = fexp;
818 while(*t && b < &full[MAXFILENAME])
819 *b++ = *t++;
820
821 /* smack on the /../
822 */
823 t = "/../";
824 while(*t && b < &full[MAXFILENAME])
825 *b++ = *t++;
826
827 /* append the symlink referent
828 */
829 t = csym;
830 while(*t && b < &full[MAXFILENAME])
831 *b++ = *t++;
832
833 /* see if we're too big
834 */
835 if (*t || b == &full[MAXFILENAME])
836 {
837 /* yes -- error
838 */
[76]839 (void) strncpy(tf_path, fexp, sizeof(tf_path));
840 tf_path[sizeof(tf_path)-1] = '\0';
[1]841#ifdef TRUST_MAIN
842 fprintf(stderr, "---------------------------------------------\n");
843 fprintf(stderr,
844 "trustfile: ETRUNC: normalized path too long (%s)\n",
845 fexp);
846 fprintf(stderr, "---------------------------------------------\n");
847#endif
848 SL_IRETURN(SL_ETRUNC, _("sl_trustfile"));
849 }
850 *b = '\0';
851 }
852 else
853 {
854 /* absolute -- just copy */
855 /* overflow can't occur as the arrays */
856 /* are the same size */
857 (void) strcpy(full, csym); /* known to fit */
858 }
859 /*
860 * now check out this file and its ancestors
861 */
862 if ((i = sl_trustfile(full, okusers, badusers)) != SL_ENONE)
863 SL_IRETURN(i, _("sl_trustfile"));
864
865 /*
866 * okay, this part is valid ... let's check the rest
867 * put the / back
868 */
869 if (p == fexp)
870 {
871 /* special case for root */
872 p[1] = c;
873 p++;
874 }
875 else
876 {
877 /* ordinary case for everything else */
878 *p = c;
879 if (*p)
880 p++;
881 }
882 continue;
883 }
884#endif
885
886
887#ifdef TRUST_DEBUG
888 fprintf(stderr, "\ntrustfile: checking path=%s\n", fexp);
889#endif
890 /*
891 * if the owner is not trusted then -- as the owner can
892 * change protection modes -- he/she can write to the
893 * file regardless of permissions, so bomb
894 */
895 if (((okusers != NULL && SL_FALSE == isin((uid_t)stbuf.st_uid,okusers))||
896 (badusers != NULL && SL_TRUE == isin((uid_t)stbuf.st_uid,badusers))))
897 {
898#ifdef TRUST_DEBUG
899 fprintf(stderr, "---------------------------------------------\n");
900 fprintf(stderr, "trustfile: EBADUID %s (owner not trusted)\n",
901 fexp);
902 fprintf(stderr, "The owner of this file/directory is not in samhains\n");
903 fprintf(stderr, "list of trusted users.\n");
904 fprintf(stderr, "Please run ./configure again with the option\n");
905 fprintf(stderr, " ./configure [more options] --with-trusted=0,...,UID\n");
906 fprintf(stderr, "where UID is the UID of the (yet) untrusted user.\n");
907 fprintf(stderr, "---------------------------------------------\n");
908#endif
[76]909 (void) strncpy(tf_path, fexp, sizeof(tf_path));
910 tf_path[sizeof(tf_path)-1] = '\0';
911
[1]912 tf_baduid = (uid_t) stbuf.st_uid;
913 SL_IRETURN(SL_EBADUID, _("sl_trustfile"));
914 }
915
916 /*
917 * if a group member can write but the
918 * member is not trusted, bomb; but if
919 * sticky bit semantics are honored, it's
920 * okay
921 */
922 /* Thu Mar 29 21:10:28 CEST 2001 Rainer Wichmann
923 * replace !isingrp() with onlytrustedingrp(), as isingrp()
924 * will return at the first trusted user, even if there are additional
925 * (untrusted) users in the group
926 */
927 if (((stbuf.st_mode & S_IWGRP) == S_IWGRP) &&
928 ((okusers != NULL && !onlytrustedingrp((gid_t)stbuf.st_gid,okusers))||
929 (badusers != NULL && isingrp((gid_t)stbuf.st_gid, badusers)))
930#ifdef STICKY
931 && ((stbuf.st_mode&S_IFDIR) != S_IFDIR ||
932 (stbuf.st_mode&S_ISVTX) != S_ISVTX)
933#endif
934 )
935 {
936#ifdef TRUST_DEBUG
937 fprintf(stderr, "---------------------------------------------\n");
938 fprintf(stderr,
939 "trustfile: EBADGID %ld %s (group member not trusted)\n",
940 (UID_CAST)stbuf.st_gid, fexp);
941 fprintf(stderr, "This file/directory is group writeable, and one of the group members\n");
942 fprintf(stderr, "is not in samhains list of trusted users.\n");
943 fprintf(stderr, "Please run ./configure again with the option\n");
944 fprintf(stderr, " ./configure [more options] --with-trusted=0,...,UID\n");
945 fprintf(stderr, "where UID is the UID of the (yet) untrusted user.\n");
946 fprintf(stderr, "---------------------------------------------\n");
947#endif
[76]948 (void) strncpy(tf_path, fexp, sizeof(tf_path));
949 tf_path[sizeof(tf_path)-1] = '\0';
950
[1]951 tf_badgid = (gid_t) stbuf.st_gid;
952 SL_IRETURN(SL_EBADGID, _("sl_trustfile"));
953 }
954 /*
955 * if other can write, bomb; but if the sticky
956 * bit semantics are honored, it's okay
957 */
958 if (((stbuf.st_mode & S_IWOTH) == S_IWOTH)
959#ifdef STICKY
960 && ((stbuf.st_mode&S_IFDIR) != S_IFDIR ||
961 (stbuf.st_mode&S_ISVTX) != S_ISVTX)
962#endif
963 )
964 {
965#ifdef TRUST_DEBUG
966 fprintf(stderr, "---------------------------------------------\n");
967 fprintf(stderr, "trustfile: EBADOTH (world writeable): %s\n",
968 fexp);
969 fprintf(stderr, "This file/directory is world writeable.\n");
970 fprintf(stderr, "---------------------------------------------\n");
971#endif
[76]972 (void) strncpy(tf_path, fexp, sizeof(tf_path));
973 tf_path[sizeof(tf_path)-1] = '\0';
974
[1]975 SL_IRETURN(SL_EBADOTH, _("sl_trustfile"));
976 }
977 /*
978 * put the / back
979 */
980 if (p == fexp)
981 {
982 /* special case for root */
983 p[1] = c;
984 p++;
985 }
986 else
987 {
988 /* ordinary case for everything else */
989 *p = c;
990 if (*p)
991 p++;
992 }
993 }
994 /*
995 * yes, it can be trusted
996 */
[76]997 (void) strncpy(tf_path, fexp, sizeof(tf_path));
998 tf_path[sizeof(tf_path)-1] = '\0';
999
[1]1000 SL_IRETURN(SL_ENONE, _("sl_trustfile"));
1001}
1002
1003#ifdef TRUST_MAIN
1004int main (int argc, char * argv[])
1005{
1006 int status;
1007#if defined(SH_WITH_SERVER)
1008 struct passwd * pass;
1009#endif
1010
1011 if (argc < 2) {
1012 fprintf(stderr, "%s: Usage: %s <fullpath>\n", argv[0], argv[0]);
1013 return 1;
1014 }
1015
1016 tf_path[0] = '\0';
1017#if defined(SH_WITH_SERVER)
[131]1018 pass = sh_getpwnam(SH_IDENT); /* TESTONLY */
[1]1019 if (pass != NULL)
1020 tf_euid = pass->pw_uid;
1021 else
1022 {
1023 fprintf(stderr, "trustfile: ERROR: getpwnam(%s) failed\n",
1024 SH_IDENT);
1025 return 1;
1026 }
1027#else
1028 tf_euid = geteuid();
1029#endif
1030
1031 status = sl_trustfile(argv[1], NULL, NULL);
1032 if (status != SL_ENONE)
1033 {
1034 fprintf(stderr, "trustfile: ERROR: not a trusted path: %s\n",
1035 argv[1]);
1036 return 1;
1037 }
1038 return 0;
1039}
1040#endif
1041
1042
1043
Note: See TracBrowser for help on using the repository browser.