source: trunk/src/slib.c@ 111

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