source: branches/samhain-2_2-branch/src/slib.c@ 271

Last change on this file since 271 was 34, checked in by rainer, 19 years ago

Code cleanup and minor fixes

File size: 55.6 KB
Line 
1#include "config_xor.h"
2
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <stdarg.h>
7#include <string.h>
8#include <limits.h>
9#ifdef HAVE_STDINT_H
10/* for SIZE_MAX */
11#include <stdint.h>
12#endif
13
14#include <unistd.h>
15#include <sys/stat.h>
16#include <sys/types.h>
17#include <fcntl.h>
18#include <signal.h>
19
20#if TIME_WITH_SYS_TIME
21#include <sys/time.h>
22#include <time.h>
23#else
24#if HAVE_SYS_TIME_H
25#include <sys/time.h>
26#else
27#include <time.h>
28#endif
29#endif
30
31#ifdef HAVE_MEMORY_H
32#include <memory.h>
33#endif
34#ifdef HAVE_SYS_SELECT_H
35#include <sys/select.h>
36#endif
37
38#ifndef FD_SET
39#define NFDBITS 32
40#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
41#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
42#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
43#endif /* !FD_SET */
44#ifndef FD_SETSIZE
45#define FD_SETSIZE 32
46#endif
47#ifndef FD_ZERO
48#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
49#endif
50
51#include "slib.h"
52#include "sh_calls.h"
53#define SH_NEED_PWD_GRP 1
54#include "sh_static.h"
55
56#undef FIL__
57#define FIL__ _("slib.c")
58
59const uid_t sh_uid_neg = ((uid_t) -1);
60const gid_t sh_gid_neg = ((gid_t) -1);
61
62#undef BREAKEXIT
63#if defined(SCREW_IT_UP) && defined(__linux__) && defined(__i386__)
64
65#ifdef SH_DEBUG
66#define BREAKEXIT(expr) \
67 do { \
68 int ixi; \
69 for (ixi = 0; ixi < 8; ++ixi) { \
70 if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc) \
71 { dlog(0, FIL__, __LINE__, _("BREAKEXIT")); _exit(EXIT_FAILURE); } \
72 } \
73 } \
74 while (1 == 0)
75#else
76#define BREAKEXIT(expr) \
77 do { \
78 int ixi; \
79 for (ixi = 0; ixi < 8; ++ixi) { \
80 if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc) \
81 _exit(EXIT_FAILURE); \
82 } \
83 } \
84 while (1 == 0)
85#endif
86
87#else
88#define BREAKEXIT(expr)
89#endif
90
91/****************************************************************
92 *
93 * The debug/trace subsystem
94 *
95 ****************************************************************/
96
97int slib_do_trace = 0;
98int slib_trace_fd = -1;
99
100static char trace_log[256] = { '\0' };
101static int trace_level = 0;
102static FILE * trace_fp = NULL;
103
104int sl_trace_use (const char * dummy)
105{
106 if (dummy)
107 slib_do_trace = 1;
108 else
109 slib_do_trace = 1;
110 return 0;
111}
112
113int sl_trace_file (const char * str)
114{
115 if (!str)
116 return -1;
117 if (str[0] != '/')
118 return -1;
119 sl_strlcpy(trace_log, str, 256);
120 return 0;
121}
122
123FILE * sl_tracefile_open(char * file, char * mode)
124{
125 FILE * xp = NULL;
126 slib_trace_fd = open(file, O_WRONLY|O_CREAT|O_APPEND, 0600);
127 if (slib_trace_fd >= 0)
128 xp = fdopen(slib_trace_fd, mode);
129 return xp;
130}
131
132void sl_trace_in(char * str, char * file, int line)
133{
134 int i;
135 if (trace_log[0] == '\0')
136 {
137 fprintf(stderr, "++ ");
138 for (i = 0; i < trace_level; ++i)
139 fprintf(stderr, ". ");
140 fprintf(stderr, "[%2d] %s \t - File %c%s%c at line %d\n",
141 trace_level, str, 0x22, file, 0x22, line);
142 }
143 else if (!sl_is_suid())
144 {
145 if (!trace_fp)
146 trace_fp = sl_tracefile_open(trace_log, "a");
147 if (trace_fp)
148 {
149 fprintf(trace_fp, "++ ");
150 for (i = 0; i < trace_level; ++i)
151 fprintf(trace_fp, ". ");
152 fprintf(trace_fp, "[%2d] %s \t - File %c%s%c at line %d\n",
153 trace_level, str, 0x22, file, 0x22, line);
154 }
155 else
156 {
157 perror(_("sl_trace_in: fopen"));
158 _exit(1);
159 }
160 }
161 ++trace_level;
162}
163
164void sl_trace_out(char * str, char * file, int line)
165{
166 int i;
167
168 --trace_level; if (trace_level < 0) trace_level = 0;
169
170 if (trace_log[0] == '\0')
171 {
172 fprintf(stderr, "-- ");
173 for (i = 0; i < trace_level; ++i)
174 fprintf(stderr, ". ");
175 fprintf(stderr, _("[%2d] %s \t - File %c%s%c at line %d\n"),
176 trace_level, str, 0x22, file, 0x22, line);
177 }
178 else if (!sl_is_suid())
179 {
180 if (!trace_fp)
181 trace_fp = sl_tracefile_open(trace_log, "a");
182 if (trace_fp)
183 {
184 fprintf(trace_fp, "-- ");
185 for (i = 0; i < trace_level; ++i)
186 fprintf(trace_fp, ". ");
187 fprintf(trace_fp, _("[%2d] %s \t - File %c%s%c at line %d\n"),
188 trace_level, str, 0x22, file, 0x22, line);
189 }
190 else
191 {
192 perror(_("sl_trace_out: fopen"));
193 _exit(1);
194 }
195 }
196}
197
198extern int sh_log_console (char * msg);
199
200static int dlogActive = 0;
201
202/* this is called from sh_error_setprint()
203 */
204void dlog_set_active(int flag)
205{
206 dlogActive = flag;
207}
208
209/* flag = 0 debug messages
210 * = 1 descriptive error messages
211 * = 3 backtrace
212 */
213int dlog (int flag, char * file, int line, const char *fmt, ...)
214{
215 va_list ap;
216 char val[81];
217 char msg[512];
218 char tmp[512];
219 int retval = 0;
220 int i;
221
222#ifdef SH_STEALTH
223 /*
224 * do not even print descriptive failure messages in stealth mode
225 */
226 if (dlogActive == 0)
227 return 0;
228 if (dlogActive == 1 && flag == 0) /* debug requires debug level */
229 return 0;
230#else
231 if (dlogActive <= 1 && flag == 0) /* debug requires debug level */
232 return 0;
233#endif
234
235 if (flag == 1)
236 {
237 sl_snprintf (val, 81, _("\n--------- %10s "), file);
238 sl_strlcpy (msg, val, 80);
239 sl_snprintf (val, 81, _(" --- %6d ---------\n"), line);
240 sl_strlcat (msg, val, 80);
241 sh_log_console (msg);
242 }
243
244 va_start (ap, fmt);
245 if (flag == 1)
246 sl_strlcpy(tmp, fmt, 512);
247 else
248 sl_strlcpy(tmp, fmt, 256);
249 retval = sl_strlen(tmp);
250 if (retval > 0 && tmp[retval-1] == '\n')
251 tmp[retval-1] = '\0';
252 retval = 0;
253 if (flag == 1)
254 {
255 sl_vsnprintf (msg, 511, tmp, ap);
256 }
257 else
258 {
259 sl_strlcpy (msg, "## ", 256);
260 for (i = 0; i < trace_level; ++i)
261 sl_strlcat (msg, ". ", 256);
262 sprintf (val, _("[%2d] "), trace_level);
263 sl_strlcat (msg, val, 256);
264 sl_vsnprintf (&msg[sl_strlen(msg)], 255, tmp, ap);
265 sl_snprintf (tmp, 255, _(" \t - File %c%s%c at line %d"),
266 0x22, file, 0x22, line);
267 sl_strlcat (msg, tmp, 512);
268 }
269 va_end (ap);
270 if (flag != 0 || sl_is_suid())
271 retval = sh_log_console (msg);
272 else
273 {
274 if (trace_log[0] == '\0')
275 {
276 /* sh_log_console (msg); */
277 fprintf(stderr, "%s\n", msg);
278 }
279 else
280 {
281 if (!trace_fp)
282 trace_fp = sl_tracefile_open(trace_log, "a");
283 if (trace_fp)
284 {
285 fprintf(trace_fp, "%s\n", msg);
286 }
287 else
288 {
289 perror(_("dlog: fopen"));
290 _exit(1);
291 }
292 }
293 }
294 if (flag == 1)
295 sh_log_console (_("\n----------------------------------------------\n"));
296 return retval;
297}
298
299extern char aud_err_message[64];
300static char alt_err_message[64];
301char * sl_get_errmsg()
302{
303 if (aud_err_message[0] == '\0')
304 {
305 sl_strlcpy(alt_err_message, sl_error_string(sl_errno), 64);
306 return &alt_err_message[0];
307 }
308 return &aud_err_message[0];
309}
310
311
312#if defined(SL_DEBUG)
313#define SL_MAX_MYSTACK 128
314
315static char sl_mystack[SL_MAX_MYSTACK][32];
316static int sl_mystack_count = 0;
317
318void sl_stack_push(char * c, char * file, int line )
319{
320 if (slib_do_trace)
321 sl_trace_in(c, file, line);
322 if (c && sl_mystack_count < SL_MAX_MYSTACK)
323 {
324 strncpy(sl_mystack[sl_mystack_count], c, 31);
325 sl_mystack[sl_mystack_count][31] = '\0';
326 ++sl_mystack_count;
327 /*
328 fprintf(stderr, "#%03d %s\n", sl_mystack_count,
329 sl_mystack[sl_mystack_count-1]);
330 */
331 }
332 return;
333}
334
335void sl_stack_pop(char * c, char * file, int line)
336{
337 if (slib_do_trace)
338 sl_trace_out(c, file, line);
339 if (sl_mystack_count > 0)
340 {
341 /*
342 fprintf(stderr, " <- #%03d %s\n", sl_mystack_count,
343 sl_mystack[sl_mystack_count-1]);
344 */
345 --sl_mystack_count;
346 }
347 return;
348}
349
350void sl_stack_print()
351{
352 int i;
353 /* FILE * dfile; */
354
355 if (sl_mystack_count > 0)
356 {
357 sh_log_console(_("\nBacktrace:\n"));
358 /* dlog(3, FIL__, __LINE__, _("\nBacktrace:\n")); */
359 for (i = 0; i < sl_mystack_count; ++i)
360 sh_log_console(sl_mystack[i]);
361 /* dlog(3, FIL__, __LINE__, _("#%03d %s\n"), i, sl_mystack[i]); */
362 }
363 return;
364}
365
366#endif
367
368
369/*
370 * The global errno.
371 * On error, this is set to the return value of the function.
372 */
373long int sl_errno;
374
375
376/* ----------------------------------------------------------------
377 *
378 * Capability routines
379 *
380 * ---------------------------------------------------------------- */
381
382int sl_useCaps = 0;
383
384#ifdef FANCY_LIBCAP
385#include <sys/capability.h>
386
387/*
388 * While these routines are tested and work, we don't use POSIX
389 * capabilities, as they don't seem to be useful (root can write
390 * to root-owned files anyway). Things would be more interesting
391 * if we could switch to a non-root UID with just a few capabilities
392 * enabled.
393 */
394int sl_drop_cap ()
395{
396 int error;
397 cap_t caps;
398 cap_flag_t capflag;
399 cap_flag_value_t capfval = CAP_CLEAR;
400 cap_value_t capvals_e[] =
401 {
402 CAP_CHOWN, CAP_FOWNER, CAP_FSETID,
403 CAP_LINUX_IMMUTABLE, CAP_MKNOD, CAP_NET_ADMIN,
404 CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW,
405 CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
406 CAP_SYS_PACCT, CAP_SYS_PTRACE, CAP_SYS_RAWIO,
407 CAP_SYS_RESOURCE, CAP_SYS_TIME, CAP_SYS_TTY_CONFIG,
408 CAP_SETGID, CAP_SETUID, CAP_KILL,
409 CAP_DAC_OVERRIDE,
410#if !defined(WITH_MESSAGE_QUEUE)
411 CAP_IPC_OWNER,
412#endif
413 CAP_SYS_MODULE, CAP_LEASE
414 };
415 cap_value_t capvals_p[] =
416 {
417 CAP_CHOWN, CAP_LEASE, CAP_FSETID,
418 CAP_LINUX_IMMUTABLE, CAP_MKNOD, CAP_NET_ADMIN,
419 CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW,
420 CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
421 CAP_SYS_PACCT, CAP_SYS_PTRACE, CAP_SYS_RAWIO,
422 CAP_SYS_RESOURCE, CAP_SYS_TIME, CAP_SYS_TTY_CONFIG,
423#if !defined(WITH_EXTERNAL) && !defined(HAVE_UNIX_RANDOM)
424 CAP_SETGID, CAP_SETUID, CAP_KILL,
425#endif
426#if !defined(SH_USE_SUIDCHK)
427 CAP_DAC_OVERRIDE, CAP_FOWNER,
428#endif
429#if !defined(WITH_MESSAGE_QUEUE)
430 CAP_IPC_OWNER,
431#endif
432 CAP_SYS_MODULE
433 };
434
435 if (0 == sl_useCaps) /* 0 = S_FALSE */
436 {
437 return 0;
438 }
439
440 if(NULL == (caps = cap_get_proc()))
441 {
442 return errno;
443 }
444
445 capflag = CAP_EFFECTIVE;
446 if (0 != cap_set_flag(caps, capflag, sizeof(capvals_e)/sizeof(cap_value_t),
447 capvals_e, capfval))
448 {
449 error = errno;
450 cap_free(caps);
451 return error;
452 }
453 if (0 != cap_set_proc(caps))
454 {
455 error = errno;
456 cap_free(caps);
457 return error;
458 }
459
460 capflag = CAP_PERMITTED;
461 if (0 != cap_set_flag(caps, capflag, sizeof(capvals_p)/sizeof(cap_value_t),
462 capvals_p, capfval))
463 {
464 error = errno;
465 cap_free(caps);
466 return error;
467 }
468 if (0 != cap_set_proc(caps))
469 {
470 error = errno;
471 cap_free(caps);
472 return error;
473 }
474 cap_free(caps);
475 return 0;
476}
477
478int sl_drop_cap_int(int what)
479{
480#if defined(SL_DEBUG)
481 char * captext;
482#endif
483 cap_flag_t capflag = CAP_EFFECTIVE;
484 cap_flag_value_t capfval = CAP_CLEAR;
485 cap_value_t capvals_a[] = { CAP_SETGID, CAP_SETUID, CAP_KILL };
486 cap_value_t capvals_b[] = { CAP_DAC_OVERRIDE, CAP_FOWNER };
487 cap_value_t * capvals;
488 int nvals;
489 int error = 0;
490 cap_t caps = cap_get_proc();
491
492 if (0 == sl_useCaps) /* 0 = S_FALSE */
493 {
494 return 0;
495 }
496
497 if (caps == NULL)
498 {
499 return errno;
500 }
501
502 switch (what) {
503 case 1:
504 capvals = capvals_a;
505 nvals = 3;
506 capfval = CAP_CLEAR;
507 break;
508 case 2:
509 capvals = capvals_a;
510 nvals = 3;
511 capfval = CAP_SET;
512 break;
513 case 3:
514 capvals = capvals_b;
515 nvals = 2;
516 capfval = CAP_CLEAR;
517 break;
518 case 4:
519 capvals = capvals_b;
520 nvals = 2;
521 capfval = CAP_SET;
522 break;
523 default:
524 return (0);
525 }
526
527 if (0 != cap_set_flag(caps, capflag, nvals, capvals, capfval))
528 {
529 error = errno;
530 cap_free(caps);
531 return error;
532 }
533 if (0 != cap_set_proc(caps))
534 {
535 error = errno;
536 cap_free(caps);
537 return error;
538 }
539#if defined(SL_DEBUG)
540 captext = cap_to_text(caps, NULL);
541 TPT(( 0, FIL__, __LINE__, _("msg=<cap_int %d: %s>\n"), what, captext));
542 cap_free(captext);
543#endif
544 cap_free(caps);
545 return 0;
546}
547
548int sl_drop_cap_sub() { return sl_drop_cap_int(1); }
549int sl_get_cap_sub() { return sl_drop_cap_int(2); }
550int sl_drop_cap_qdel() { return sl_drop_cap_int(3); }
551int sl_get_cap_qdel() { return sl_drop_cap_int(4); }
552
553#else
554int sl_drop_cap () { return 0; }
555int sl_drop_cap_sub() { return 0; }
556int sl_get_cap_sub() { return 0; }
557int sl_drop_cap_qdel() { return 0; }
558int sl_get_cap_qdel() { return 0; }
559#endif
560
561/* ----------------------------------------------------------------
562 *
563 * String handling routines
564 *
565 * ---------------------------------------------------------------- */
566
567/*
568 * A memset that does not get optimized away
569 */
570void *sl_memset(void *s, int c, size_t n)
571{
572 volatile char *p = (char *) s;
573
574 if (s != NULL)
575 {
576 while (n--)
577 *p++ = c;
578 }
579 return s;
580}
581
582#if !defined(HOST_IS_I86SOLARIS)
583#if !defined (_GNU_SOURCE) && !defined(__linux__)
584/* flawfinder: ignore */
585extern int vsnprintf ( char *str, size_t n,
586 const char *format, va_list ap );
587#endif
588#endif
589
590#if !defined (VA_COPY)
591#if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
592#define VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
593#elif defined (VA_COPY_AS_ARRAY)
594#define VA_COPY(ap1, ap2) memmove ((ap1), (ap2), sizeof (va_list))
595#else /* va_list is a pointer */
596#define VA_COPY(ap1, ap2) ((ap1) = (ap2))
597#endif
598#endif
599
600#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
601static
602size_t sl_printf_count (const char * fmt, va_list vl)
603{
604 size_t length = 1;
605 int fini = 0;
606 int islong = 0;
607 int islonglong = 0;
608 int islongdouble = 0;
609 char * string_arg;
610
611 SL_ENTER(_("sl_printf_count"));
612
613 if (fmt == NULL)
614 SL_IRETURN(SL_ENULL, _("sl_printf_count"));
615
616 while (*fmt) {
617
618 if ( (*fmt) == '%' ) { /* a format specifier */
619
620 fmt++; /* point to first char after '%' */
621
622 fini = 0;
623 islong = 0;
624 islongdouble = 0;
625
626 while (*fmt && (fini == 0) ) {
627
628 switch (*fmt) {
629
630 case '*': /* field width supplied by an integer */
631 length = length + va_arg (vl, int);
632 ++fmt;
633 break;
634 case '1':
635 case '2':
636 case '3':
637 case '4':
638 case '5':
639 case '6':
640 case '7':
641 case '8':
642 case '9':
643 length = length + strtol (fmt, (char**) &fmt, 10);
644 /* strtol makes FastForward to first invalid char */
645 break;
646
647 case 'l': /* 'long' modifier */
648 if (islong == 0)
649 islong = 1;
650 else
651 {
652 islonglong = 1;
653 islong = 0;
654 }
655 ++fmt;
656 break;
657
658 case 'L': /* 'long double' modifier */
659#ifdef HAVE_LONG_DOUBLE
660 islongdouble = 1;
661#else
662 islong = 1;
663#endif
664 ++fmt;
665 break;
666
667 case 'd':
668 case 'i':
669 case 'o':
670 case 'u':
671 case 'x':
672 case 'X':
673 if (islonglong == 1)
674#ifdef HAVE_LONG_LONG
675 (void) va_arg (vl, long long);
676#else
677 (void) va_arg (vl, long);
678#endif
679 else if (islong == 1)
680 (void) va_arg (vl, long);
681 else
682 (void) va_arg (vl, int);
683 islong = 0;
684 islonglong = 0;
685 length = length + 24;
686 ++fmt;
687 fini = 1;
688 break;
689
690 case 'D':
691 case 'O':
692 case 'U':
693 (void) va_arg (vl, long);
694 length = length + 24;
695 fmt++;
696 fini = 1;
697 break;
698
699 case 'e':
700 case 'E':
701 case 'f':
702 case 'g':
703#ifdef HAVE_LONG_DOUBLE
704 if (islongdouble == 1) {
705 (void) va_arg (vl, long double);
706 islongdouble = 0;
707 length = length + 20;
708 }
709 else
710#endif
711 (void) va_arg (vl, double);
712 length = length + 20;
713 fini = 1;
714 ++fmt;
715 break;
716
717 case 's':
718 string_arg = va_arg (vl, char *);
719 if (string_arg != NULL)
720 length = length + sl_strlen (string_arg);
721 else
722 length = length + 16;
723 fini = 1;
724 ++fmt;
725 break;
726
727 case 'c':
728 (void) va_arg (vl, int);
729 length = length + 1;
730 fini = 1;
731 ++fmt;
732 break;
733
734 case 'p':
735 case 'n':
736 (void) va_arg (vl, void * );
737 length = length + 32;
738 fini = 1;
739 ++fmt;
740 break;
741
742 case '%': /* %% will print '%' */
743 length = length + 1;
744 fini = 1;
745 ++fmt;
746 break;
747
748 default:
749 length = length + 1;
750 ++fmt;
751 break;
752
753 } /* end switch */
754 }
755 /* end parsing a single format specifier */
756 } else {
757 length = length + 1;
758 fmt++;
759 }
760 }
761 SL_IRETURN(length, _("sl_printf_count"));
762}
763#endif /* #ifndef HAVE_VSNPRINTF */
764
765/*
766 * An implementation of vsnprintf. va_start/va_end are in the caller
767 * function.
768 * Returns C99 (#bytes that would heve been written) on success.
769 */
770int sl_vsnprintf(char *str, size_t n,
771 const char *format, va_list vl )
772{
773 int len = 0;
774#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
775 size_t total;
776 va_list vl2;
777#endif
778
779 SL_ENTER(_("sl_vsnprintf"));
780 if (str == NULL || format == NULL)
781 SL_IRETURN(0, _("sl_vsnprintf"));
782
783#if defined(HAVE_VSNPRINTF) && !defined(HAVE_BROKEN_VSNPRINTF)
784 len = vsnprintf (str, n, format, vl); /* flawfinder: ignore */
785 str[n-1] = '\0';
786#else
787 VA_COPY (vl2, vl); /* save the argument list */
788 total = sl_printf_count (format, vl);
789 len = (int) total;
790 if (total < n)
791 {
792 /* flawfinder: ignore */
793 vsprintf (str, format, vl2); /* program has checked that it fits */
794 str[n-1] = '\0';
795 }
796 else
797 {
798 sl_strlcpy (str, format, n);
799 va_end(vl2);
800 SL_IRETURN(len, _("sl_vsnprintf"));
801 }
802 va_end(vl2);
803#endif
804 SL_IRETURN(len, _("sl_vsnprintf"));
805}
806
807/*
808 * An implementation of snprintf.
809 * Returns SL_ENONE on success.
810 * ENULL: src || format == NULL
811 * ERANGE: n out of range
812 * ETRUNC: truncated (unimplemented)
813 */
814int sl_snprintf(char *str, size_t n,
815 const char *format, ... )
816{
817 va_list vl;
818#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
819 size_t total = 0;
820 va_list vl2;
821#endif
822
823 SL_ENTER(_("sl_snprintf"));
824 if (str == NULL || format == NULL)
825 SL_IRETURN(SL_ENULL, _("sl_snprintf"));
826
827 va_start (vl, format);
828#if defined(HAVE_VSNPRINTF) && !defined(HAVE_BROKEN_VSNPRINTF)
829 /* flawfinder: ignore */
830 vsnprintf (str, n, format, vl);
831 str[n-1] = '\0';
832#else
833 VA_COPY (vl2, vl); /* save the argument list */
834 total = sl_printf_count (format, vl);
835 if (total < n)
836 {
837 /* flawfinder: ignore */
838 vsprintf (str, format, vl2); /* program has checked that it fits */
839 str[n-1] = '\0';
840 }
841 else
842 {
843 sl_strlcpy (str, format, n);
844 va_end(vl2);
845 va_end(vl);
846 SL_IRETURN(SL_ETRUNC, _("sl_snprintf"));
847 }
848 va_end(vl2);
849#endif
850 va_end(vl);
851 SL_IRETURN(SL_ENONE, _("sl_snprintf"));
852}
853
854/*
855 * Appends src to string dst of size siz (unlike strncat, siz is the
856 * full size of dst, not space left). At most siz-1 characters
857 * will be copied. Always NUL terminates (unless siz == 0).
858 * Returns SL_NONE on success, errcode on failure.
859 *
860 * ENULL: dst == NULL
861 * ERANGE: siz out of range
862 * ETRUNC: src truncated
863 */
864int sl_strlcat(char * dst, /*@null@*/const char *src, size_t siz)
865{
866 register size_t dst_end;
867 register size_t dst_free;
868
869 register char * p;
870 register const char * q;
871
872 if (dst == NULL)
873 return SL_ENONE;
874 if (src == NULL || *src == '\0')
875 return SL_ENONE;
876
877 if (siz > 0) {
878
879 /* How much free space do we have ?
880 */
881 dst_end = strlen(dst);
882 dst_free = siz - dst_end - 1;
883
884 p = &dst[dst_end];
885 q = src;
886
887 while (dst_free > 0 && *q != '\0')
888 {
889 *p++ = *q++;
890 --dst_free;
891 }
892
893 /* NULL terminate dst.
894 */
895 *p = '\0';
896
897 if (*q != '\0')
898 return SL_ETRUNC;
899 }
900
901 return SL_ENONE;
902}
903
904/*
905 * An alternative implementation of the OpenBSD strlcpy() function.
906 *
907 * Copy src to string dst of size siz. At most siz-1 characters
908 * will be copied. Always NUL terminates (unless siz == 0).
909 * Returns SL_NONE on success, errcode on failure.
910 *
911 * ENULL: dst == NULL
912 * ERANGE: siz out of range
913 * ETRUNC: src truncated
914 */
915int sl_strlcpy(char * dst, /*@null@*/const char * src, size_t siz)
916{
917 /* SL_ENTER(_("sl_strlcpy")); */
918
919 if (dst == NULL)
920 return SL_ENULL;
921 if (src == NULL)
922 {
923 if (siz > 0)
924 dst[0] = '\0';
925 return SL_ENONE;
926 }
927
928
929 if (siz > 0) {
930 /* copy siz-1 characters
931 */
932 (void) strncpy(dst, src, siz-1);
933
934 /* NULL terminate
935 */
936 dst[siz-1] = '\0';
937 }
938 return SL_ENONE;
939}
940
941/*
942 * A robust drop-in replacement of strncpy. strlcpy is preferable.
943 */
944char * sl_strncpy(char *dst, const char *src, size_t size)
945{
946
947#ifdef SL_FAIL_ON_ERROR
948 SL_REQUIRE(dst != NULL, _("dst != NULL"));
949 SL_REQUIRE(src != NULL, _("src != NULL"));
950 SL_REQUIRE(size > 0, _("size > 0"));
951#endif
952
953 if (dst == NULL)
954 {
955 sl_errno = SL_ENULL;
956 return (NULL);
957 }
958 if (size < 1)
959 {
960 sl_errno = SL_ERANGE;
961 return (dst);
962 }
963 if (!src)
964 {
965 sl_errno = SL_ENULL;
966 dst[0] = '\0';
967 }
968 else if (src[0] == '\0')
969 dst[0] = '\0';
970 else
971 strncpy(dst, src, size);
972
973 if (sl_strlen(src) >= size)
974 {
975 errno = ENOSPC;
976 dst[size-1] = '\0';
977 }
978 return (dst);
979}
980
981/*
982 * A robust drop-in replacement of strncat. strlcat is preferable.
983 */
984char * sl_strncat(char *dst, const char *src, size_t n)
985{
986#ifdef SL_FAIL_ON_ERROR
987 SL_REQUIRE(dst != NULL, _("dst != NULL"));
988 SL_REQUIRE(src != NULL, _("src != NULL"));
989 SL_REQUIRE(n > 0, _("n > 0"));
990#endif
991
992 if (dst == NULL)
993 {
994 sl_errno = SL_ENULL;
995 return (NULL);
996 }
997 if (n < 1)
998 {
999 sl_errno = SL_ERANGE;
1000 return (dst);
1001 }
1002 if (!src)
1003 {
1004 sl_errno = SL_ENULL;
1005 return (dst);
1006 }
1007 else if (src[0] == '\0')
1008 dst[0] = '\0';
1009 else
1010 strncat(dst, src, n);
1011
1012 return (dst);
1013}
1014
1015
1016int sl_strcmp(const char * a, const char * b)
1017{
1018#ifdef SL_FAIL_ON_ERROR
1019 SL_REQUIRE (a != NULL, _("a != NULL"));
1020 SL_REQUIRE (b != NULL, _("b != NULL"));
1021#endif
1022
1023 if (a != NULL && b != NULL)
1024 return (strcmp(a, b));
1025 else if (a == NULL && b != NULL)
1026 return (-1);
1027 else if (a != NULL && b == NULL)
1028 return (1);
1029 else
1030 return (-7); /* arbitrary */
1031}
1032
1033int sl_strncmp(const char * a, const char * b, size_t n)
1034{
1035#ifdef SL_FAIL_ON_ERROR
1036 SL_REQUIRE (a != NULL, _("a != NULL"));
1037 SL_REQUIRE (b != NULL, _("b != NULL"));
1038 SL_REQUIRE (n > 0, _("n > 0"));
1039#endif
1040
1041 if (a != NULL && b != NULL)
1042 return (strncmp(a, b, n));
1043 else if (a == NULL && b != NULL)
1044 return (-1);
1045 else if (a != NULL && b == NULL)
1046 return (1);
1047 else
1048 return (-7); /* arbitrary */
1049}
1050
1051/* string searching
1052 */
1053
1054char * sl_strstr (const char * haystack, const char * needle)
1055{
1056#ifndef HAVE_STRSTR
1057 int i;
1058 size_t needle_len;
1059 size_t haystack_len;
1060#endif
1061
1062 if (haystack == NULL || needle == NULL)
1063 return NULL;
1064 if (*needle == '\0' || *haystack == '\0')
1065 return NULL;
1066
1067#if defined(HAVE_STRSTR)
1068 return (strstr(haystack, needle));
1069#else
1070 needle_len = strlen(needle);
1071 haystack_len = strlen(haystack);
1072
1073 for (i = 0; i <= (haystack_len-needle_len); ++i)
1074 if (0 == sl_strncmp(&haystack[i], needle, needle_len))
1075 return (needle);
1076 return NULL;
1077#endif
1078}
1079
1080
1081/* ----------------------------------------------------------------
1082 *
1083 * Privilege handling routines
1084 *
1085 * ---------------------------------------------------------------- */
1086
1087
1088
1089static uid_t euid;
1090static uid_t ruid;
1091static uid_t ruid_orig;
1092static gid_t egid;
1093static gid_t rgid;
1094static gid_t rgid_orig;
1095
1096static int uids_are_stored = SL_FALSE;
1097static int suid_is_set = SL_TRUE;
1098
1099#ifdef HAVE_SETRESUID
1100extern int setresuid (uid_t truid, uid_t teuid, uid_t tsuid);
1101extern int setresgid (gid_t trgid, gid_t tegid, gid_t tsgid);
1102#endif
1103
1104
1105/*
1106 * This function returns true if the program is SUID.
1107 * It calls abort() if the uid's are not saved already.
1108 */
1109int sl_is_suid()
1110{
1111 if (uids_are_stored == SL_FALSE)
1112 {
1113 if (getuid() == geteuid() && getgid() == getegid())
1114 return (0); /* FALSE */
1115 else
1116 return (1); /* TRUE */
1117 }
1118 else
1119 {
1120 if (euid == ruid && egid == rgid)
1121 return (0); /* FALSE */
1122 else
1123 return (1); /* TRUE */
1124 }
1125}
1126
1127/*
1128 * This function returns the saved euid.
1129 * It calls abort() if the uid's are not saved already.
1130 */
1131int sl_get_euid(uid_t * ret)
1132{
1133 SL_ENTER(_("sl_get_euid"));
1134 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1135 if (uids_are_stored == SL_TRUE)
1136 *ret = euid;
1137 else
1138 *ret = geteuid();
1139 SL_IRETURN (SL_ENONE, _("sl_get_euid"));
1140}
1141
1142uid_t sl_ret_euid()
1143{
1144 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1145 if (uids_are_stored == SL_TRUE)
1146 return (euid);
1147 else
1148 return (geteuid());
1149}
1150
1151/*
1152 * This function returns the saved egid.
1153 * It calls abort() if the uid's are not saved already.
1154 */
1155int sl_get_egid(gid_t * ret)
1156{
1157 SL_ENTER(_("sl_get_egid"));
1158 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1159 if (uids_are_stored == SL_TRUE)
1160 *ret = egid;
1161 else
1162 *ret = getegid();
1163 SL_IRETURN (SL_ENONE, _("sl_get_egid"));
1164}
1165
1166/*
1167 * This function returns the saved ruid.
1168 * It calls abort() if the uid's are not saved already.
1169 */
1170int sl_get_ruid(uid_t * ret)
1171{
1172 SL_ENTER(_("sl_get_ruid"));
1173 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1174 if (uids_are_stored == SL_TRUE)
1175 *ret = ruid;
1176 else
1177 *ret = getuid();
1178 SL_IRETURN (SL_ENONE, _("sl_get_ruid"));
1179}
1180
1181/*
1182 * This function returns the saved rgid.
1183 * It calls abort() if the uid's are not saved already.
1184 */
1185int sl_get_rgid(gid_t * ret)
1186{
1187 SL_ENTER(_("sl_get_rgid"));
1188 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1189 if (uids_are_stored == SL_TRUE)
1190 *ret = rgid;
1191 else
1192 *ret = getgid();
1193 SL_IRETURN (SL_ENONE, _("sl_get_rgid"));
1194}
1195
1196/*
1197 * This function returns the saved original ruid.
1198 * It calls abort() if the uid's are not saved already.
1199 */
1200int sl_get_ruid_orig(uid_t * ret)
1201{
1202 SL_ENTER(_("sl_get_ruid_orig"));
1203 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1204 if (uids_are_stored == SL_TRUE)
1205 *ret = ruid_orig;
1206 else
1207 *ret = getuid();
1208 SL_IRETURN (SL_ENONE, _("sl_get_ruid_orig"));
1209}
1210
1211/*
1212 * This function returns the saved original rgid.
1213 * It calls abort() if the uid's are not saved already.
1214 */
1215int sl_get_rgid_orig(gid_t * ret)
1216{
1217 SL_ENTER(_("sl_get_rgid_orig"));
1218 /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1219 if (uids_are_stored == SL_TRUE)
1220 *ret = rgid_orig;
1221 else
1222 *ret = getgid();
1223 SL_IRETURN (SL_ENONE, _("sl_get_rgid_orig"));
1224}
1225
1226static int suid_warn_flag = 1;
1227static void suid_warn(int a)
1228{
1229 fprintf(stderr, _("ERROR: open set/unset suid !!! %d\n"), a);
1230 return;
1231}
1232
1233/*
1234 * This function sets the effective uid
1235 * to the saved effective uid.
1236 * It will abort on failure.
1237 */
1238int sl_set_suid ()
1239{
1240 int retval;
1241
1242 SL_ENTER(_("sl_set_suid"));
1243
1244 if (uids_are_stored == SL_FALSE)
1245 {
1246 SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1247 }
1248
1249 SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));
1250
1251 if (ruid == euid && rgid == egid)
1252 {
1253 suid_is_set = SL_TRUE;
1254 SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1255 }
1256 SL_REQUIRE(suid_is_set == SL_FALSE, _("suid_is_set == SL_FALSE"));
1257
1258#if defined(HAVE_SETRESUID)
1259 retval = setresuid (sh_uid_neg, euid, sh_uid_neg);
1260 if (retval == 0)
1261 retval = setresgid (sh_gid_neg, egid, sh_gid_neg);
1262
1263#elif defined(HAVE_SETEUID)
1264 retval = seteuid (egid);
1265 if (retval == 0)
1266 retval = setegid (euid);
1267
1268 /* on AIX, setreuid does not behave well for non-root users.
1269 */
1270#elif defined(HAVE_SETREUID)
1271 retval = setreuid (ruid, euid);
1272 if (retval == 0)
1273 retval = setregid (rgid, egid);
1274
1275#else
1276 retval = setuid (euid);
1277 if (retval == 0)
1278 retval = setgid (egid);
1279#endif
1280 if (suid_warn_flag == 1)
1281 suid_warn(1);
1282 suid_warn_flag = 1;
1283
1284 SL_REQUIRE(retval == 0, _("retval == 0"));
1285 suid_is_set = SL_TRUE;
1286 SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1287}
1288
1289/*
1290 * This function sets the effective uid to the real uid.
1291 * It will abort on failure.
1292 */
1293int sl_unset_suid ()
1294{
1295 register int retval;
1296
1297 SL_ENTER(_("sl_unset_suid"));
1298
1299 if (uids_are_stored == SL_FALSE)
1300 {
1301 SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1302 }
1303
1304 SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));
1305
1306 if (ruid == euid && rgid == egid)
1307 {
1308 suid_is_set = SL_FALSE;
1309 SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1310 }
1311 SL_REQUIRE(suid_is_set == SL_TRUE, _("suid_is_set == SL_TRUE"));
1312
1313#if defined(HAVE_SETRESUID)
1314 retval = setresgid (sh_gid_neg, rgid, sh_gid_neg);
1315 if (retval == 0)
1316 retval = setresuid (sh_uid_neg, ruid, sh_uid_neg);
1317
1318#elif defined(HAVE_SETEUID)
1319 retval = setegid (rgid);
1320 if (retval == 0)
1321 retval = seteuid (ruid);
1322
1323#elif defined(HAVE_SETREUID)
1324 retval = setregid (egid, rgid);
1325 if (retval == 0)
1326 retval = setreuid (euid, ruid);
1327
1328#else
1329 retval = setgid (rgid);
1330 if (retval == 0)
1331 retval = setuid (ruid);
1332#endif
1333
1334 if (suid_warn_flag == 0)
1335 suid_warn(0);
1336 suid_warn_flag = 0;
1337
1338 SL_REQUIRE(retval == 0, _("retval == 0"));
1339 suid_is_set = SL_FALSE;
1340 SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1341}
1342
1343
1344/*
1345 * This function saves the uid's.
1346 */
1347int sl_save_uids()
1348{
1349 SL_ENTER(_("sl_save_uids"));
1350 if (uids_are_stored == SL_TRUE)
1351 SL_IRETURN(SL_EREPEAT, _("sl_save_uids"));
1352
1353 ruid_orig = getuid();
1354 rgid_orig = getgid();
1355 egid = getegid();
1356 euid = geteuid();
1357 ruid = ruid_orig;
1358 rgid = rgid_orig;
1359 uids_are_stored = SL_TRUE;
1360
1361 SL_IRETURN(SL_ENONE, _("sl_save_uids"));
1362}
1363
1364/*
1365 * This function drops SUID privileges irrevocably.
1366 * It set the effective uid to the original real uid.
1367 */
1368extern int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid);
1369int sl_drop_privileges()
1370{
1371 SL_ENTER(_("sl_drop_privileges"));
1372 SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));
1373
1374 SL_REQUIRE(setgid(rgid_orig) == 0, _("setgid(rgid_orig) == 0"));
1375 SL_REQUIRE(sh_unix_initgroups2(ruid_orig, rgid_orig) == 0, _("sh_unix_initgroups2(ruid_orig,rgid_orig) == 0"));
1376 SL_REQUIRE(setuid(ruid_orig) == 0, _("setuid(ruid_orig) == 0"));
1377
1378 /* make sure that setuid(0) fails
1379 */
1380 SL_REQUIRE(setuid(0) < 0, _("setuid(0) < 0"));
1381
1382 euid = ruid_orig;
1383 egid = rgid_orig;
1384 ruid = ruid_orig;
1385 rgid = rgid_orig;
1386
1387 SL_IRETURN(SL_ENONE, _("sl_drop_privileges"));
1388}
1389
1390/*
1391 * Define a policy: Stay root.
1392 * Do nothing if not SUID.
1393 */
1394int sl_policy_get_root()
1395{
1396 SL_ENTER(_("sl_policy_get_root"));
1397 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1398
1399 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1400
1401 if (euid != ruid || egid != rgid)
1402 {
1403 SL_REQUIRE(setgid(egid) == 0, _("setgid(egid) == 0"));
1404 SL_REQUIRE(setuid(euid) == 0, _("setuid(euid) == 0"));
1405 SL_REQUIRE(ruid == getuid() && rgid == getgid(),
1406 _("ruid == getuid() && rgid == getgid()"));
1407 ruid = euid;
1408 rgid = egid;
1409 }
1410 suid_is_set = SL_TRUE;
1411 if (euid == 0)
1412 {
1413 SL_REQUIRE(sh_unix_initgroups2(euid, egid) == 0, _("sh_unix_initgroups2(euid,egid) == 0"));
1414 }
1415 SL_IRETURN(SL_ENONE, _("sl_policy_get_root"));
1416}
1417
1418#include <pwd.h>
1419
1420/*
1421 * Define a policy: Get real (irrevocably).
1422 * This function drops SUID privileges irrevocably.
1423 * Do nothing if not SUID (? not true - drops if root).
1424 */
1425
1426int sl_policy_get_real(char * user)
1427{
1428 struct passwd * tempres;
1429
1430 SL_ENTER(_("sl_policy_get_real"));
1431 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1432 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1433
1434 if (euid == 0 || ruid == 0)
1435 {
1436 tempres = sh_getpwnam(user);
1437
1438 SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1439
1440 rgid_orig = tempres->pw_gid;
1441 ruid_orig = tempres->pw_uid;
1442 }
1443 else
1444 {
1445 rgid_orig = rgid;
1446 ruid_orig = ruid;
1447 }
1448
1449 SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1450 _("sl_drop_privileges() == SL_ENONE"));
1451
1452 suid_is_set = SL_TRUE;
1453 SL_IRETURN(SL_ENONE, _("sl_policy_get_real"));
1454}
1455
1456
1457/*
1458 * Define a policy: Get user.
1459 * Drops privileges.
1460 * Do nothing if not SUID.
1461 */
1462int sl_policy_get_user(char * user)
1463{
1464 struct passwd * tempres;
1465
1466 SL_ENTER(_("sl_policy_get_user"));
1467
1468 SL_REQUIRE(user != NULL, _("user != NULL"));
1469 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1470 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1471
1472 if (euid != ruid || egid != rgid)
1473 {
1474 tempres = sh_getpwnam(user);
1475
1476 SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1477
1478#if 0
1479 rgid = tempres->pw_gid;
1480 ruid = tempres->pw_uid;
1481 SL_REQUIRE(sl_unset_suid() == SL_ENONE,
1482 _("sl_unset_suid() == SL_ENONE"));
1483#endif
1484 SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1485 _("sl_drop_privileges() == SL_ENONE"));
1486 }
1487 SL_IRETURN(SL_ENONE, _("sl_policy_get_user"));
1488}
1489
1490
1491
1492/* ----------------------------------------------------------------
1493 *
1494 * File access routines
1495 *
1496 * ---------------------------------------------------------------- */
1497
1498#define TOFFSET 0x1234
1499
1500/* this would prevent opening files if the first 16 fds are open :( */
1501/* #define MAXFD FOPEN_MAX */
1502
1503#define MAXFD 1024
1504
1505typedef struct openfiles {
1506 SL_TICKET ticket; /* The unique ID. */
1507 int fd; /* The file descriptor. */
1508 char * path; /* The file path. */
1509} SL_OFILE;
1510
1511static SL_OFILE * ofiles[MAXFD];
1512
1513
1514static unsigned int nonce_counter = TOFFSET;
1515
1516static
1517SL_TICKET sl_create_ticket (unsigned int myindex)
1518{
1519 unsigned int high; /* index */
1520 unsigned int low; /* nonce */
1521
1522 SL_ENTER(_("sl_create_ticket"));
1523
1524 if (myindex >= MAXFD)
1525 SL_IRETURN (SL_EINTERNAL, _("sl_create_ticket"));
1526
1527 /* mask out the high bit and check that it is not used
1528 * -> verify that it fits into 16 bits as positive
1529 */
1530 high = (myindex + TOFFSET) & 0x7fff;
1531
1532 if (high != myindex + TOFFSET)
1533 SL_IRETURN (SL_EINTERNAL, _("sl_create_ticket"));
1534
1535 low = nonce_counter & 0xffff;
1536
1537 /* Overflow -> nonce too big.
1538 */
1539 if ((low != nonce_counter++) || low == 0)
1540 SL_IRETURN (SL_EINTERNAL, _("sl_create_ticket"));
1541
1542 /* Wrap around the nonce counter.
1543 * This is a dirty trick.
1544 */
1545 if (nonce_counter > 0x7fff)
1546 nonce_counter = TOFFSET;
1547
1548 SL_RETURN ((SL_TICKET) ((high << 16) | low), _("sl_create_ticket"));
1549}
1550
1551static
1552int sl_read_ticket (SL_TICKET fno)
1553{
1554 register unsigned myindex;
1555 register SL_OFILE *of;
1556
1557 myindex = ((fno >> 16) & 0xffff) - TOFFSET;
1558 if (myindex >= MAXFD)
1559 return (SL_ETICKET);
1560
1561 if (ofiles[myindex] == NULL)
1562 return (SL_ETICKET);
1563
1564 if (ofiles[myindex]->ticket != fno)
1565 return (SL_ETICKET);
1566
1567 if ((of = ofiles[myindex])->fd < 0 || of->fd >= MAXFD )
1568 return (SL_EINTERNAL);
1569
1570 if (((of->ticket) & 0xffff) == 0)
1571 return (SL_EINTERNAL);
1572
1573 return (myindex);
1574}
1575
1576SL_TICKET sl_make_ticket (int fd, char * filename)
1577{
1578 size_t len;
1579 SL_TICKET ticket;
1580 SL_ENTER(_("sl_make_ticket"));
1581 /* Make entry.
1582 */
1583 if (fd >= MAXFD || fd < 0)
1584 {
1585 SL_IRETURN(SL_TOOMANY, _("sl_make_ticket"));
1586 }
1587
1588 if (ofiles[fd] != NULL)
1589 {
1590 SL_IRETURN(SL_EINTERNAL, _("sl_make_ticket"));
1591 }
1592
1593 if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1594 {
1595 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1596 }
1597
1598 len = sl_strlen(filename)+1;
1599
1600 if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
1601 {
1602 free(ofiles[fd]);
1603 ofiles[fd] = NULL;
1604 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1605 }
1606
1607 /* Get a ticket.
1608 */
1609 ticket = sl_create_ticket((unsigned int)fd);
1610
1611 if (SL_ISERROR(ticket))
1612 {
1613 (void) free (ofiles[fd]->path);
1614 (void) free (ofiles[fd]);
1615 SL_IRETURN(ticket, _("sl_make_ticket"));
1616 }
1617
1618 sl_strlcpy (ofiles[fd]->path, filename, len);
1619 ofiles[fd]->ticket = ticket;
1620 ofiles[fd]->fd = fd;
1621
1622 SL_IRETURN(ticket, _("sl_make_ticket"));
1623}
1624
1625#define SL_OPEN_MIN 113
1626#define SL_OPEN_FOR_READ 113
1627#define SL_OPEN_FOR_WRITE 114
1628#define SL_OPEN_FOR_RDWR 115
1629#define SL_OPEN_FOR_WTRUNC 116
1630#define SL_OPEN_FOR_RWTRUNC 117
1631#define SL_OPEN_SAFE_RDWR 118
1632#define SL_OPEN_FOR_FASTREAD 119
1633#define SL_OPEN_MAX 119
1634
1635#if !defined(O_NOATIME)
1636#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
1637#define O_NOATIME 01000000
1638#else
1639 /*
1640 * bitwise 'or' with zero does not modify any bit
1641 */
1642#define O_NOATIME 0
1643#endif
1644#endif
1645
1646static int o_noatime = O_NOATIME;
1647static mode_t open_mode = (S_IWUSR|S_IRUSR|S_IRGRP);
1648
1649
1650static
1651int sl_open_file (const char *filename, int mode, int priv)
1652{
1653 struct stat lbuf;
1654 struct stat buf;
1655 int lstat_return;
1656 int stat_return;
1657 int fd;
1658 int sflags;
1659 size_t len;
1660 SL_TICKET ticket;
1661
1662#if !defined(O_NONBLOCK)
1663#if defined(O_NDELAY)
1664#define O_NONBLOCK O_NDELAY
1665#else
1666#define O_NONBLOCK 0
1667#endif
1668#endif
1669
1670 SL_ENTER(_("sl_open_file"));
1671
1672 if (filename == NULL)
1673 SL_IRETURN(SL_ENULL, _("sl_open_file"));
1674 if (mode < SL_OPEN_MIN || mode > SL_OPEN_MAX)
1675 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1676
1677 /* "This system call always succeeds and the previous value of
1678 * the mask is returned."
1679 */
1680 (void) umask (0);
1681
1682 if (mode == SL_OPEN_FOR_FASTREAD)
1683 {
1684 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1685 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
1686 /*
1687 if (fd >= 0) {
1688 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1689 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1690 }
1691 */
1692 if (fd < 0)
1693 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1694 goto createTicket;
1695 }
1696
1697#ifdef USE_SUID
1698 if (priv == SL_YESPRIV)
1699 sl_set_suid();
1700#endif
1701 if (mode == SL_OPEN_FOR_READ)
1702 lstat_return = retry_stat (FIL__, __LINE__, filename, &lbuf);
1703 else
1704 lstat_return = retry_lstat(FIL__, __LINE__, filename, &lbuf);
1705#ifdef USE_SUID
1706 if (priv == SL_YESPRIV)
1707 sl_unset_suid();
1708#endif
1709
1710 if (lstat_return == -1)
1711 {
1712 lstat_return = ENOENT;
1713 if ( (mode == SL_OPEN_FOR_READ && lstat_return == ENOENT) ||
1714 (errno != ENOENT))
1715 {
1716 TPT(( 0, FIL__, __LINE__, _("msg=<lstat: %s> errno=<%d>\n"),
1717 filename, errno));
1718 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1719 }
1720 }
1721
1722 if ( (mode != SL_OPEN_FOR_READ) && (lstat_return != ENOENT) &&
1723 ( S_ISDIR(lbuf.st_mode) || (S_IWOTH & lbuf.st_mode) )
1724 )
1725 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1726
1727
1728 /* O_NOATIME has an effect for read(). But write() ?.
1729 */
1730 switch (mode)
1731 {
1732 case SL_OPEN_FOR_READ:
1733 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1734 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
1735 if (fd >= 0) {
1736 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1737 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1738 }
1739 break;
1740 case SL_OPEN_FOR_WRITE:
1741 if (lstat_return == ENOENT)
1742 fd = aud_open (FIL__, __LINE__, priv, filename,
1743 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1744 else
1745 fd = aud_open (FIL__, __LINE__, priv, filename,
1746 O_WRONLY, open_mode);
1747 break;
1748 case SL_OPEN_SAFE_RDWR:
1749 if (lstat_return == ENOENT)
1750 fd = aud_open (FIL__, __LINE__, priv, filename,
1751 O_RDWR|O_CREAT|O_EXCL, open_mode);
1752 else
1753 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1754 break;
1755 case SL_OPEN_FOR_RDWR:
1756 if (lstat_return == ENOENT)
1757 fd = aud_open (FIL__, __LINE__, priv, filename,
1758 O_RDWR|O_CREAT|O_EXCL, open_mode);
1759 else
1760 fd = aud_open (FIL__, __LINE__, priv, filename,
1761 O_RDWR, open_mode);
1762 break;
1763 case SL_OPEN_FOR_WTRUNC:
1764 if (lstat_return == ENOENT)
1765 fd = aud_open (FIL__, __LINE__, priv, filename,
1766 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1767 else
1768 fd = aud_open (FIL__, __LINE__, priv, filename,
1769 O_WRONLY|O_TRUNC, open_mode);
1770 break;
1771 case SL_OPEN_FOR_RWTRUNC:
1772 if (lstat_return == ENOENT)
1773 fd = aud_open (FIL__, __LINE__, priv, filename,
1774 O_RDWR|O_CREAT|O_EXCL, open_mode);
1775 else
1776 fd = aud_open (FIL__, __LINE__, priv, filename,
1777 O_RDWR|O_TRUNC, open_mode);
1778 break;
1779 default:
1780 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1781 }
1782
1783 if (fd < 0)
1784 {
1785 TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s> errno=<%d>\n"),
1786 filename, errno));
1787 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1788 }
1789
1790#ifdef USE_SUID
1791 if (priv == SL_YESPRIV)
1792 sl_set_suid();
1793#endif
1794 stat_return = retry_fstat(FIL__, __LINE__, fd, &buf);
1795#ifdef USE_SUID
1796 if (priv == SL_YESPRIV)
1797 sl_unset_suid();
1798#endif
1799
1800 if (stat_return < 0)
1801 {
1802 close (fd);
1803 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1804 }
1805
1806 if (lstat_return != ENOENT && buf.st_ino != lbuf.st_ino)
1807 {
1808 close (fd);
1809 SL_IRETURN(SL_EBOGUS, _("sl_open_file"));
1810 }
1811
1812 createTicket:
1813
1814 /* Make entry.
1815 */
1816 if (fd >= MAXFD)
1817 {
1818 close(fd);
1819 SL_IRETURN(SL_TOOMANY, _("sl_open_file"));
1820 }
1821
1822 if (ofiles[fd] != NULL)
1823 {
1824 close(fd);
1825 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1826 }
1827
1828 if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1829 {
1830 close(fd);
1831 SL_IRETURN(SL_EMEM, _("sl_open_file"));
1832 }
1833
1834 len = sl_strlen(filename)+1;
1835
1836 if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
1837 {
1838 free(ofiles[fd]);
1839 ofiles[fd] = NULL;
1840 close(fd);
1841 SL_IRETURN(SL_EMEM, _("sl_open_file"));
1842 }
1843
1844 /* Get a ticket.
1845 */
1846 ticket = sl_create_ticket(fd);
1847
1848 if (SL_ISERROR(ticket))
1849 {
1850 (void) free (ofiles[fd]->path);
1851 (void) free (ofiles[fd]);
1852 close(fd);
1853 SL_IRETURN(ticket, _("sl_open_file"));
1854 }
1855
1856 sl_strlcpy (ofiles[fd]->path, filename, len);
1857 ofiles[fd]->ticket = ticket;
1858 ofiles[fd]->fd = fd;
1859
1860 SL_IRETURN(ticket, _("sl_open_file"));
1861}
1862
1863static
1864int check_fname_priv (const char * fname, int priv)
1865{
1866 SL_ENTER(_("check_fname_priv"));
1867 if (fname == NULL)
1868 SL_IRETURN(SL_ENULL, _("check_fname_priv"));
1869 if (priv != SL_YESPRIV && priv != SL_NOPRIV)
1870 SL_IRETURN(SL_EINTERNAL, _("check_fname_priv"));
1871 SL_IRETURN(SL_ENONE, _("check_fname_priv"));
1872}
1873
1874SL_TICKET sl_open_write (const char * fname, int priv)
1875{
1876 long status;
1877 SL_ENTER(_("sl_open_write"));
1878
1879 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1880 SL_IRETURN(status, _("sl_open_write"));
1881
1882 status = sl_open_file(fname, SL_OPEN_FOR_WRITE, priv);
1883 SL_IRETURN(status, _("sl_open_write"));
1884}
1885
1886SL_TICKET sl_open_read (const char * fname, int priv)
1887{
1888 long status;
1889 SL_ENTER(_("sl_open_read"));
1890
1891 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1892 {
1893 TPT(( 0, FIL__, __LINE__,
1894 _("msg=<Error in check_fname_priv.> status=<%ld>\n"),
1895 status));
1896 SL_IRETURN(status, _("sl_open_read"));
1897 }
1898
1899 status = sl_open_file(fname, SL_OPEN_FOR_READ, priv);
1900 SL_IRETURN(status, _("sl_open_read"));
1901}
1902
1903SL_TICKET sl_open_fastread (const char * fname, int priv)
1904{
1905 long status;
1906 SL_ENTER(_("sl_open_fastread"));
1907
1908 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1909 SL_IRETURN(status, _("sl_open_read"));
1910
1911 status = sl_open_file(fname, SL_OPEN_FOR_FASTREAD, priv);
1912 SL_IRETURN(status, _("sl_open_fastread"));
1913}
1914
1915SL_TICKET sl_open_rdwr (const char * fname, int priv)
1916{
1917 long status;
1918 SL_ENTER(_("sl_open_rdwr"));
1919
1920 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1921 SL_IRETURN(status, _("sl_open_rdwr"));
1922
1923 status = sl_open_file(fname, SL_OPEN_FOR_RDWR, priv);
1924 SL_IRETURN(status, _("sl_open_rdwr"));
1925}
1926
1927SL_TICKET sl_open_safe_rdwr (const char * fname, int priv)
1928{
1929 long status;
1930 SL_ENTER(_("sl_open_safe_rdwr"));
1931
1932 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1933 SL_IRETURN(status, _("sl_open_safe_rdwr"));
1934
1935 status = sl_open_file(fname, SL_OPEN_SAFE_RDWR, priv);
1936 SL_IRETURN(status, _("sl_open_safe_rdwr"));
1937}
1938
1939SL_TICKET sl_open_write_trunc (const char * fname, int priv)
1940{
1941 long status;
1942 SL_ENTER(_("sl_open_write_trunc"));
1943
1944 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1945 SL_IRETURN(status, _("sl_open_write_trunc"));
1946
1947 status = sl_open_file(fname, SL_OPEN_FOR_WTRUNC, priv);
1948 SL_IRETURN(status, _("sl_open_write_trunc"));
1949}
1950
1951SL_TICKET sl_open_rdwr_trunc (const char * fname, int priv)
1952{
1953 long status;
1954 SL_ENTER(_("sl_open_rdwr_trunc"));
1955
1956 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1957 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
1958
1959 status = sl_open_file(fname, SL_OPEN_FOR_RWTRUNC, priv);
1960 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
1961}
1962
1963
1964int get_the_fd (SL_TICKET ticket)
1965{
1966 int fd;
1967
1968 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
1969 return (fd);
1970
1971 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
1972 return (SL_EINTERNAL);
1973 return (fd);
1974}
1975
1976int sl_close (SL_TICKET ticket)
1977{
1978 register int fd;
1979
1980 SL_ENTER(_("sl_close"));
1981
1982 if (SL_ISERROR(fd = get_the_fd (ticket)))
1983 SL_IRETURN(fd, _("sl_close"));
1984
1985 /* This may fail, but what to do then ?
1986 */
1987 if (0 != close(fd) && ofiles[fd] != NULL)
1988 {
1989 TPT((0, FIL__, __LINE__,
1990 _("msg=<Error closing file.>, path=<%s>, fd=<%d>, err=<%s>\n"),
1991 ofiles[fd]->path, fd, strerror(errno)));
1992 }
1993
1994 if (ofiles[fd] != NULL)
1995 {
1996 (void) free(ofiles[fd]->path);
1997 (void) free(ofiles[fd]);
1998 ofiles[fd] = NULL;
1999 }
2000
2001 SL_IRETURN(SL_ENONE, _("sl_close"));
2002}
2003
2004int sl_dropall(int fd, int except)
2005{
2006 while (fd < MAXFD)
2007 {
2008 if (ofiles[fd] != NULL && fd != except)
2009 {
2010 if (ofiles[fd]->path != NULL)
2011 (void) free(ofiles[fd]->path);
2012 (void) free(ofiles[fd]);
2013 ofiles[fd] = NULL;
2014 }
2015 ++fd;
2016 }
2017 return 0;
2018}
2019
2020
2021int sl_unlink (SL_TICKET ticket)
2022{
2023 register int fd;
2024
2025 SL_ENTER(_("sl_unlink"));
2026
2027 if (SL_ISERROR(fd = get_the_fd(ticket)))
2028 SL_IRETURN(fd, _("sl_unlink"));
2029
2030 if (retry_aud_unlink(FIL__, __LINE__, ofiles[fd]->path) < 0)
2031 SL_IRETURN(SL_EUNLINK, _("sl_unlink"));
2032
2033 SL_IRETURN(SL_ENONE, _("sl_unlink"));
2034}
2035
2036
2037int sl_seek (SL_TICKET ticket, off_t off_data)
2038{
2039 register int fd;
2040
2041 SL_ENTER(_("sl_seek"));
2042
2043 if (SL_ISERROR(fd = get_the_fd(ticket)))
2044 SL_IRETURN(fd, _("sl_seek"));
2045
2046 if (lseek(fd, off_data, SEEK_SET) == (off_t)-1)
2047 SL_IRETURN(SL_EREWIND, _("sl_seek"));
2048
2049 SL_IRETURN(SL_ENONE, _("sl_seek"));
2050}
2051
2052int sl_rewind (SL_TICKET ticket)
2053{
2054 register int fd;
2055
2056 SL_ENTER(_("sl_rewind"));
2057
2058 if (SL_ISERROR(fd = get_the_fd(ticket)))
2059 SL_IRETURN(fd, _("sl_rewind"));
2060
2061 if (lseek (fd, 0L, SEEK_SET) == (off_t)-1)
2062 SL_IRETURN(SL_EREWIND, _("sl_rewind"));
2063
2064 SL_IRETURN(SL_ENONE, _("sl_rewind"));
2065}
2066
2067int sl_forward (SL_TICKET ticket)
2068{
2069 register int fd;
2070
2071 SL_ENTER(_("sl_forward"));
2072
2073 if (SL_ISERROR(fd = get_the_fd(ticket)))
2074 SL_IRETURN(fd, _("sl_forward"));
2075
2076 if (lseek (fd, 0L, SEEK_END) == (off_t)-1)
2077 SL_IRETURN(SL_EFORWARD, _("sl_forward"));
2078
2079 SL_IRETURN(SL_ENONE, _("sl_forward"));
2080}
2081
2082
2083int sl_sync (SL_TICKET ticket)
2084{
2085 register int fd;
2086
2087 SL_ENTER(_("sl_sync"));
2088
2089 if (SL_ISERROR(fd = get_the_fd(ticket)))
2090 SL_IRETURN(fd, _("sl_sync"));
2091
2092 if (fsync (fd) == -1)
2093 SL_IRETURN(SL_ESYNC, _("sl_sync"));
2094
2095 SL_IRETURN(SL_ENONE, _("sl_sync"));
2096}
2097
2098int sl_read_timeout_prep (SL_TICKET ticket)
2099{
2100 int fd;
2101 int sflags;
2102
2103 SL_ENTER(_("sl_read_timeout_prep"));
2104
2105 if (SL_ISERROR(fd = get_the_fd(ticket)))
2106 {
2107 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2108 SL_IRETURN(fd, _("sl_read_timeout_prep"));
2109 }
2110
2111 /* set to non-blocking mode
2112 */
2113 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2114 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
2115
2116 SL_IRETURN(SL_ENONE, _("sl_read_timeout_prep"));
2117}
2118
2119
2120int sl_read_timeout (SL_TICKET ticket, void * buf_in, size_t count,
2121 int timeout)
2122{
2123 fd_set readfds;
2124 struct timeval tv;
2125 /* int sflags; */
2126 int retval;
2127
2128 int fd;
2129 int byteread = 0;
2130 int bytes = 0;
2131 char * buf;
2132
2133 time_t tnow;
2134 time_t tstart;
2135 time_t tdiff;
2136 extern volatile int sig_termfast;
2137
2138 if (buf_in == NULL || SL_ISERROR(fd = get_the_fd(ticket)))
2139 {
2140 if (buf_in == NULL)
2141 {
2142 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2143 return (SL_ENULL);
2144 }
2145 if (SL_ISERROR(fd = get_the_fd(ticket)))
2146 {
2147 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2148 return (fd);
2149 }
2150 }
2151
2152 buf = (char *) buf_in;
2153
2154 tstart = time(NULL);
2155 tdiff = 0;
2156
2157 while (count > 0)
2158 {
2159 FD_ZERO(&readfds);
2160 FD_SET(fd, &readfds);
2161
2162 tv.tv_sec = timeout - tdiff;
2163 tv.tv_usec = 0;
2164
2165 retval = select (fd+1, &readfds, NULL, NULL, &tv);
2166
2167 if (retval > 0)
2168 {
2169 byteread = read (fd, buf, count);
2170
2171 if (byteread > 0)
2172 {
2173 bytes += byteread; count -= byteread;
2174 buf += byteread;
2175 if (count == 0)
2176 break;
2177 }
2178 else if (byteread == 0)
2179 {
2180 break;
2181 }
2182 else
2183 {
2184 if (errno == EINTR || errno == EAGAIN)
2185 {
2186 retry_msleep(1, 0);
2187 tnow = time(NULL);
2188 tdiff = tnow - tstart;
2189 continue;
2190 }
2191 else
2192 {
2193 return (SL_EREAD);
2194 }
2195 }
2196 }
2197 else if ((retval == -1) && (errno == EINTR || errno == EAGAIN))
2198 {
2199 retry_msleep(1, 0);
2200 tnow = time(NULL);
2201 tdiff = tnow - tstart;
2202 continue;
2203 }
2204 else if (retval == 0)
2205 {
2206 return (SL_TIMEOUT);
2207 }
2208 else
2209 {
2210 return (SL_EREAD);
2211 }
2212
2213 if (sig_termfast == 1)
2214 {
2215 return (SL_EREAD);
2216 }
2217
2218 tnow = time(NULL);
2219 tdiff = tnow - tstart;
2220
2221 if (tdiff > timeout)
2222 {
2223 return (SL_TIMEOUT);
2224 }
2225 }
2226
2227 return ((int) bytes);
2228}
2229
2230
2231int sl_read (SL_TICKET ticket, void * buf_in, size_t count)
2232{
2233 int fd;
2234 int byteread = 0;
2235 int bytes = 0;
2236
2237 char * buf;
2238
2239 if (count < 1)
2240 {
2241 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
2242 return(SL_ERANGE);
2243 }
2244 if (buf_in == NULL)
2245 {
2246 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2247 return (SL_ENULL);
2248 }
2249
2250 if (SL_ISERROR(fd = get_the_fd(ticket)))
2251 {
2252 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2253 return (fd);
2254 }
2255
2256 buf = (char *) buf_in;
2257
2258 do
2259 {
2260 byteread = read (fd, buf, count);
2261 if (byteread > 0)
2262 {
2263 bytes += byteread; count -= byteread;
2264 buf += byteread;
2265 }
2266 } while ( byteread > 0 ||
2267 ( byteread == -1 && (errno == EINTR || errno == EAGAIN))
2268 );
2269
2270
2271 if (byteread == (-1))
2272 {
2273 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
2274 return (SL_EREAD);
2275 }
2276 return (bytes);
2277}
2278
2279int sl_read_fast (SL_TICKET ticket, void * buf_in, size_t count)
2280{
2281 int fd;
2282 int byteread = 0;
2283
2284 char * buf;
2285
2286 if (count < 1)
2287 {
2288 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
2289 return(SL_ERANGE);
2290 }
2291 if (buf_in == NULL)
2292 {
2293 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2294 return (SL_ENULL);
2295 }
2296
2297 if (SL_ISERROR(fd = get_the_fd(ticket)))
2298 {
2299 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2300 return (fd);
2301 }
2302
2303 buf = (char *) buf_in;
2304
2305 do
2306 {
2307 byteread = read (fd, buf, count);
2308 if (byteread >= 0)
2309 {
2310 return (byteread);
2311 }
2312 } while ( byteread == -1 && (errno == EINTR || errno == EAGAIN));
2313
2314
2315 if (byteread == (-1))
2316 {
2317 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
2318 return (SL_EREAD);
2319 }
2320 return (0);
2321}
2322
2323
2324int sl_write (SL_TICKET ticket, void * msg_in, long nbytes)
2325{
2326 long bytewritten;
2327 long bytecount;
2328 int fd;
2329
2330 char * msg;
2331
2332 SL_ENTER(_("sl_write"));
2333
2334 if (nbytes < 1)
2335 SL_IRETURN(SL_ERANGE, _("sl_write"));
2336 if (msg_in == NULL)
2337 SL_IRETURN(SL_ENULL, _("sl_write"));
2338 if (SL_ISERROR(fd = get_the_fd(ticket)))
2339 SL_IRETURN(fd, _("sl_write"));
2340
2341 msg = (char *) msg_in;
2342
2343 /* write
2344 */
2345 bytecount = 0;
2346 bytewritten = 0;
2347 while (bytecount < nbytes)
2348 {
2349 if ((bytewritten = write (fd, msg, nbytes-bytecount)) > 0)
2350 {
2351 bytecount += bytewritten;
2352 msg += bytewritten; /* move buffer pointer forward */
2353 }
2354 else if (bytewritten <= 0)
2355 {
2356 if ( errno == EINTR || errno == EAGAIN) /* try again */
2357 continue;
2358 else
2359 SL_IRETURN(SL_EWRITE, _("sl_write"));
2360 }
2361 }
2362 SL_IRETURN(SL_ENONE, _("sl_write"));
2363}
2364
2365int sl_write_line (SL_TICKET ticket, void * msg, long nbytes)
2366{
2367 int status;
2368
2369 SL_ENTER(_("sl_write_line"));
2370
2371 status = sl_write(ticket, msg, nbytes);
2372 if (!SL_ISERROR(status))
2373 status = sl_write(ticket, "\n", 1);
2374
2375 SL_IRETURN(status, _("sl_write_line"));
2376}
2377
2378
2379/* ----------------------------------------------------------------
2380 *
2381 * Trustfile interface
2382 *
2383 * ---------------------------------------------------------------- */
2384
2385extern uid_t rootonly[];
2386extern int EUIDSLOT;
2387extern int ORIG_EUIDSLOT;
2388
2389extern char tf_path[MAXFILENAME]; /* Error path for trust function. */
2390extern uid_t tf_euid; /* Space for EUID of process. */
2391
2392
2393char * sl_error_string(int errorcode)
2394{
2395 switch (errorcode)
2396 {
2397 case SL_EBOGUS:
2398 return _("Bogus file. Modified during access.");
2399 case SL_EWRITE:
2400 return _("Write error.");
2401 case SL_EREAD:
2402 return _("Read error.");
2403 case SL_ESYNC:
2404 return _("Error in fsync().");
2405 case SL_EFORWARD:
2406 return _("Error in lseek().");
2407 case SL_EREWIND:
2408 return _("Error in lseek().");
2409 case SL_EUNLINK:
2410 return _("Error in unlink().");
2411 case SL_EMEM:
2412 return _("Out of memory.");
2413 case SL_EINTERNAL:
2414 return _("Internal error.");
2415 case SL_ETICKET:
2416 return _("Bad ticket.");
2417 case SL_EREPEAT:
2418 return _("Illegal repeated use of function.");
2419 case SL_ERANGE:
2420 return _("Argument out of range.");
2421 case SL_ENULL:
2422 return _("Dereferenced NULL pointer.");
2423
2424 case SL_EBADUID:
2425 return _("Owner not trustworthy.");
2426 case SL_EBADGID:
2427 return _("Group writeable and member not trustworthy.");
2428 case SL_EBADOTH:
2429 return _("World writeable.");
2430 case SL_EBADFILE:
2431 return _("File access error.");
2432 case SL_EBADNAME:
2433 return _("Invalid filename (prob. too long or null).");
2434
2435 case SL_ETRUNC:
2436 return _("Truncation occured.");
2437 case SL_ESTAT:
2438 return _("stat() failed.");
2439 default:
2440 return _("Unknown error.");
2441 }
2442}
2443
2444
2445
2446char * sl_trust_errfile()
2447{
2448 return &tf_path[0];
2449}
2450
2451extern uid_t tf_baduid;
2452uid_t sl_trust_baduid()
2453{
2454 return tf_baduid;
2455}
2456
2457extern gid_t tf_badgid;
2458gid_t sl_trust_badgid()
2459{
2460 return tf_badgid;
2461}
2462
2463
2464static int trust_count = 0;
2465
2466int sl_trust_purge_user ()
2467{
2468 int i;
2469
2470 EUIDSLOT = ORIG_EUIDSLOT;
2471 trust_count = 0;
2472
2473 for (i = EUIDSLOT; i < (EUIDSLOT + 15); ++i)
2474 rootonly[i] = sh_uid_neg;
2475 return 0;
2476}
2477
2478int sl_trust_add_user (uid_t pwid)
2479{
2480 SL_ENTER(_("sl_trust_add_user"));
2481
2482 if (trust_count == 15)
2483 SL_IRETURN(SL_ERANGE, _("sl_trust_add_user"));
2484
2485 rootonly[EUIDSLOT] = pwid;
2486 ++EUIDSLOT;
2487 ++trust_count;
2488
2489 SL_IRETURN(SL_ENONE, _("sl_trust_add_user"));
2490}
2491
2492int sl_trustfile_euid(char * filename, uid_t teuid)
2493{
2494 long status;
2495 SL_ENTER(_("sl_trustfile_euid"));
2496
2497 tf_path[0] = '\0';
2498 if (filename == NULL || filename[0] == '\0')
2499 SL_IRETURN(SL_EBADNAME, _("sl_trustfile_euid"));
2500
2501 tf_euid = teuid;
2502 status = sl_trustfile(filename, NULL, NULL);
2503 SL_IRETURN(status, _("sl_trustfile_euid"));
2504}
2505
2506/* ----------------------------------------------------------------
2507 *
2508 * Overflow tests
2509 *
2510 * ---------------------------------------------------------------- */
2511
2512#ifndef SIZE_MAX
2513#define SIZE_MAX (4294967295U)
2514#endif
2515
2516int sl_ok_muli (int a, int b) /* a*b */
2517{
2518 if ((b == 0) || (a >= (INT_MIN / b) && a <= (INT_MAX / b)))
2519 return SL_TRUE; /* no overflow */
2520 return SL_FALSE;
2521}
2522
2523int sl_ok_muls (size_t a, size_t b) /* a*b */
2524{
2525 if ((b == 0) || (a <= (SIZE_MAX / b)))
2526 return SL_TRUE; /* no overflow */
2527 return SL_FALSE;
2528}
2529
2530int sl_ok_divi (int a, int b) /* a/b */
2531{
2532 (void) a;
2533 if (b != 0)
2534 return SL_TRUE; /* no overflow */
2535 return SL_FALSE;
2536}
2537
2538int sl_ok_addi (int a, int b) /* a+b */
2539{
2540 if (a >= 0 && b >= 0)
2541 {
2542 if (a <= (INT_MAX - b))
2543 return SL_TRUE; /* no overflow */
2544 else
2545 return SL_FALSE;
2546 }
2547 else if (a < 0 && b < 0)
2548 {
2549 if (a >= (INT_MIN - b))
2550 return SL_TRUE; /* no overflow */
2551 else
2552 return SL_FALSE;
2553 }
2554 return SL_TRUE;
2555}
2556
2557int sl_ok_adds (size_t a, size_t b) /* a+b */
2558{
2559 if (a <= (SIZE_MAX - b))
2560 return SL_TRUE; /* no overflow */
2561 else
2562 return SL_FALSE;
2563}
2564
2565int sl_ok_subi (int a, int b) /* a-b */
2566{
2567 if (a >= 0 && b < 0)
2568 {
2569 if (a <= (INT_MAX + b))
2570 return SL_TRUE; /* no overflow */
2571 else
2572 return SL_FALSE;
2573 }
2574 else if (a < 0 && b >= 0)
2575 {
2576 if (a >= (INT_MIN + b))
2577 return SL_TRUE; /* no overflow */
2578 else
2579 return SL_FALSE;
2580 }
2581 return SL_TRUE;
2582}
Note: See TracBrowser for help on using the repository browser.