source: trunk/src/slib.c@ 136

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

Use thread-safe libc functions.

File size: 58.9 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 SL_ENTER(_("sl_policy_get_real"));
1428 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1429 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1430
1431 if (euid == 0 || ruid == 0)
1432 {
1433#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1434 struct passwd pwd;
1435 char buffer[SH_PWBUF_SIZE];
1436 struct passwd * tempres;
1437 sh_getpwnam_r(user, &pwd, buffer, sizeof(buffer), &tempres);
1438#else
1439 struct passwd * tempres = sh_getpwnam(user);
1440#endif
1441
1442 SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1443
1444 rgid_orig = tempres->pw_gid;
1445 ruid_orig = tempres->pw_uid;
1446 }
1447 else
1448 {
1449 rgid_orig = rgid;
1450 ruid_orig = ruid;
1451 }
1452
1453 SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1454 _("sl_drop_privileges() == SL_ENONE"));
1455
1456 suid_is_set = SL_TRUE;
1457 SL_IRETURN(SL_ENONE, _("sl_policy_get_real"));
1458}
1459
1460
1461/*
1462 * Define a policy: Get user.
1463 * Drops privileges.
1464 * Do nothing if not SUID.
1465 */
1466int sl_policy_get_user(char * user)
1467{
1468 struct passwd * tempres;
1469
1470 SL_ENTER(_("sl_policy_get_user"));
1471
1472 SL_REQUIRE(user != NULL, _("user != NULL"));
1473 SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1474 SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1475
1476 if (euid != ruid || egid != rgid)
1477 {
1478#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1479 struct passwd pwd;
1480 char buffer[SH_PWBUF_SIZE];
1481 struct passwd * tempres;
1482 sh_getpwnam_r(user, &pwd, buffer, sizeof(buffer), &tempres);
1483#else
1484 struct passwd * tempres = sh_getpwnam(user);
1485#endif
1486
1487 SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1488
1489 SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1490 _("sl_drop_privileges() == SL_ENONE"));
1491 }
1492 SL_IRETURN(SL_ENONE, _("sl_policy_get_user"));
1493}
1494
1495
1496
1497/* ----------------------------------------------------------------
1498 *
1499 * File access routines
1500 *
1501 * ---------------------------------------------------------------- */
1502
1503#define TOFFSET 0x1234
1504
1505/* this would prevent opening files if the first 16 fds are open :( */
1506/* #define MAXFD FOPEN_MAX */
1507
1508#define MAXFD 1024
1509
1510typedef struct openfiles {
1511 SL_TICKET ticket; /* The unique ID. */
1512 int fd; /* The file descriptor. */
1513 char * path; /* The file path. */
1514} SL_OFILE;
1515
1516static SL_OFILE * ofiles[MAXFD];
1517
1518
1519static unsigned int nonce_counter = TOFFSET;
1520
1521static
1522SL_TICKET sl_create_ticket (unsigned int myindex)
1523{
1524 unsigned int high; /* index */
1525 unsigned int low; /* nonce */
1526
1527 SL_ENTER(_("sl_create_ticket"));
1528
1529 if (myindex >= MAXFD)
1530 SL_IRETURN (SL_EINTERNAL, _("sl_create_ticket"));
1531
1532 /* mask out the high bit and check that it is not used
1533 * -> verify that it fits into 16 bits as positive
1534 */
1535 high = (myindex + TOFFSET) & 0x7fff;
1536
1537 if (high != myindex + TOFFSET)
1538 SL_IRETURN (SL_EINTERNAL, _("sl_create_ticket"));
1539
1540 low = nonce_counter & 0xffff;
1541
1542 /* Overflow -> nonce too big.
1543 */
1544 if ((low != nonce_counter++) || low == 0)
1545 SL_IRETURN (SL_EINTERNAL, _("sl_create_ticket"));
1546
1547 /* Wrap around the nonce counter.
1548 * This is a dirty trick.
1549 */
1550 if (nonce_counter > 0x7fff)
1551 nonce_counter = TOFFSET;
1552
1553 SL_RETURN ((SL_TICKET) ((high << 16) | low), _("sl_create_ticket"));
1554}
1555
1556static
1557int sl_read_ticket (SL_TICKET fno)
1558{
1559 register unsigned myindex;
1560 register SL_OFILE *of;
1561
1562 myindex = ((fno >> 16) & 0xffff) - TOFFSET;
1563 if (myindex >= MAXFD)
1564 return (SL_ETICKET);
1565
1566 if (ofiles[myindex] == NULL)
1567 return (SL_ETICKET);
1568
1569 if (ofiles[myindex]->ticket != fno)
1570 return (SL_ETICKET);
1571
1572 if ((of = ofiles[myindex])->fd < 0 || of->fd >= MAXFD )
1573 return (SL_EINTERNAL);
1574
1575 if (((of->ticket) & 0xffff) == 0)
1576 return (SL_EINTERNAL);
1577
1578 return (myindex);
1579}
1580
1581SL_TICKET sl_make_ticket (int fd, const char * filename)
1582{
1583 size_t len;
1584 SL_TICKET ticket;
1585 SL_ENTER(_("sl_make_ticket"));
1586 /* Make entry.
1587 */
1588 if (fd >= MAXFD || fd < 0)
1589 {
1590 SL_IRETURN(SL_TOOMANY, _("sl_make_ticket"));
1591 }
1592
1593 if (ofiles[fd] != NULL)
1594 {
1595 SL_IRETURN(SL_EINTERNAL, _("sl_make_ticket"));
1596 }
1597
1598 if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1599 {
1600 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1601 }
1602
1603 len = sl_strlen(filename)+1;
1604
1605 if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
1606 {
1607 free(ofiles[fd]);
1608 ofiles[fd] = NULL;
1609 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1610 }
1611
1612 /* Get a ticket.
1613 */
1614 ticket = sl_create_ticket((unsigned int)fd);
1615
1616 if (SL_ISERROR(ticket))
1617 {
1618 (void) free (ofiles[fd]->path);
1619 (void) free (ofiles[fd]);
1620 SL_IRETURN(ticket, _("sl_make_ticket"));
1621 }
1622
1623 sl_strlcpy (ofiles[fd]->path, filename, len);
1624 ofiles[fd]->ticket = ticket;
1625 ofiles[fd]->fd = fd;
1626
1627 SL_IRETURN(ticket, _("sl_make_ticket"));
1628}
1629
1630#define SL_OPEN_MIN 113
1631#define SL_OPEN_FOR_READ 113
1632#define SL_OPEN_FOR_WRITE 114
1633#define SL_OPEN_FOR_RDWR 115
1634#define SL_OPEN_FOR_WTRUNC 116
1635#define SL_OPEN_FOR_RWTRUNC 117
1636#define SL_OPEN_SAFE_RDWR 118
1637#define SL_OPEN_FOR_FASTREAD 119
1638#define SL_OPEN_MAX 119
1639
1640#if !defined(O_NOATIME)
1641#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
1642#define O_NOATIME 01000000
1643#else
1644 /*
1645 * bitwise 'or' with zero does not modify any bit
1646 */
1647#define O_NOATIME 0
1648#endif
1649#endif
1650
1651static int o_noatime = O_NOATIME;
1652static mode_t open_mode = (S_IWUSR|S_IRUSR|S_IRGRP);
1653
1654
1655static
1656int sl_open_file (const char *filename, int mode, int priv)
1657{
1658 struct stat lbuf;
1659 struct stat buf;
1660 int lstat_return;
1661 int stat_return;
1662 int fd;
1663 int sflags;
1664 size_t len;
1665 SL_TICKET ticket;
1666
1667#if !defined(O_NONBLOCK)
1668#if defined(O_NDELAY)
1669#define O_NONBLOCK O_NDELAY
1670#else
1671#define O_NONBLOCK 0
1672#endif
1673#endif
1674
1675 SL_ENTER(_("sl_open_file"));
1676
1677 if (filename == NULL)
1678 SL_IRETURN(SL_ENULL, _("sl_open_file"));
1679 if (mode < SL_OPEN_MIN || mode > SL_OPEN_MAX)
1680 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1681
1682 /* "This system call always succeeds and the previous value of
1683 * the mask is returned."
1684 */
1685 (void) umask (0);
1686
1687 if (mode == SL_OPEN_FOR_FASTREAD)
1688 {
1689 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1690 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
1691 /*
1692 if (fd >= 0) {
1693 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1694 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1695 }
1696 */
1697 if (fd < 0)
1698 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1699 goto createTicket;
1700 }
1701
1702#ifdef USE_SUID
1703 if (priv == SL_YESPRIV)
1704 sl_set_suid();
1705#endif
1706 if (mode == SL_OPEN_FOR_READ)
1707 lstat_return = retry_stat (FIL__, __LINE__, filename, &lbuf);
1708 else
1709 lstat_return = retry_lstat(FIL__, __LINE__, filename, &lbuf);
1710#ifdef USE_SUID
1711 if (priv == SL_YESPRIV)
1712 sl_unset_suid();
1713#endif
1714
1715 if (lstat_return == -1)
1716 {
1717 lstat_return = ENOENT;
1718 if ( (mode == SL_OPEN_FOR_READ && lstat_return == ENOENT) ||
1719 (errno != ENOENT))
1720 {
1721 TPT(( 0, FIL__, __LINE__, _("msg=<lstat: %s> errno=<%d>\n"),
1722 filename, errno));
1723 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1724 }
1725 }
1726
1727 if ( (mode != SL_OPEN_FOR_READ) && (lstat_return != ENOENT) &&
1728 ( S_ISDIR(lbuf.st_mode) || (S_IWOTH & lbuf.st_mode) )
1729 )
1730 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1731
1732
1733 /* O_NOATIME has an effect for read(). But write() ?.
1734 */
1735 switch (mode)
1736 {
1737 case SL_OPEN_FOR_READ:
1738 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1739 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
1740 if (fd >= 0) {
1741 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1742 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1743 }
1744 break;
1745 case SL_OPEN_FOR_WRITE:
1746 if (lstat_return == ENOENT)
1747 fd = aud_open (FIL__, __LINE__, priv, filename,
1748 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1749 else
1750 fd = aud_open (FIL__, __LINE__, priv, filename,
1751 O_WRONLY, open_mode);
1752 break;
1753 case SL_OPEN_SAFE_RDWR:
1754 if (lstat_return == ENOENT)
1755 fd = aud_open (FIL__, __LINE__, priv, filename,
1756 O_RDWR|O_CREAT|O_EXCL, open_mode);
1757 else
1758 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1759 break;
1760 case SL_OPEN_FOR_RDWR:
1761 if (lstat_return == ENOENT)
1762 fd = aud_open (FIL__, __LINE__, priv, filename,
1763 O_RDWR|O_CREAT|O_EXCL, open_mode);
1764 else
1765 fd = aud_open (FIL__, __LINE__, priv, filename,
1766 O_RDWR, open_mode);
1767 break;
1768 case SL_OPEN_FOR_WTRUNC:
1769 if (lstat_return == ENOENT)
1770 fd = aud_open (FIL__, __LINE__, priv, filename,
1771 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1772 else
1773 fd = aud_open (FIL__, __LINE__, priv, filename,
1774 O_WRONLY|O_TRUNC, open_mode);
1775 break;
1776 case SL_OPEN_FOR_RWTRUNC:
1777 if (lstat_return == ENOENT)
1778 fd = aud_open (FIL__, __LINE__, priv, filename,
1779 O_RDWR|O_CREAT|O_EXCL, open_mode);
1780 else
1781 fd = aud_open (FIL__, __LINE__, priv, filename,
1782 O_RDWR|O_TRUNC, open_mode);
1783 break;
1784 default:
1785 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1786 }
1787
1788 if (fd < 0)
1789 {
1790 TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s> errno=<%d>\n"),
1791 filename, errno));
1792 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1793 }
1794
1795#ifdef USE_SUID
1796 if (priv == SL_YESPRIV)
1797 sl_set_suid();
1798#endif
1799 stat_return = retry_fstat(FIL__, __LINE__, fd, &buf);
1800#ifdef USE_SUID
1801 if (priv == SL_YESPRIV)
1802 sl_unset_suid();
1803#endif
1804
1805 if (stat_return < 0)
1806 {
1807 close (fd);
1808 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1809 }
1810
1811 if (lstat_return != ENOENT && buf.st_ino != lbuf.st_ino)
1812 {
1813 close (fd);
1814 SL_IRETURN(SL_EBOGUS, _("sl_open_file"));
1815 }
1816
1817 createTicket:
1818
1819 /* Make entry.
1820 */
1821 if (fd >= MAXFD)
1822 {
1823 close(fd);
1824 SL_IRETURN(SL_TOOMANY, _("sl_open_file"));
1825 }
1826
1827 if (ofiles[fd] != NULL)
1828 {
1829 close(fd);
1830 SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1831 }
1832
1833 if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1834 {
1835 close(fd);
1836 SL_IRETURN(SL_EMEM, _("sl_open_file"));
1837 }
1838
1839 len = sl_strlen(filename)+1;
1840
1841 if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
1842 {
1843 free(ofiles[fd]);
1844 ofiles[fd] = NULL;
1845 close(fd);
1846 SL_IRETURN(SL_EMEM, _("sl_open_file"));
1847 }
1848
1849 /* Get a ticket.
1850 */
1851 ticket = sl_create_ticket(fd);
1852
1853 if (SL_ISERROR(ticket))
1854 {
1855 (void) free (ofiles[fd]->path);
1856 (void) free (ofiles[fd]);
1857 close(fd);
1858 SL_IRETURN(ticket, _("sl_open_file"));
1859 }
1860
1861 sl_strlcpy (ofiles[fd]->path, filename, len);
1862 ofiles[fd]->ticket = ticket;
1863 ofiles[fd]->fd = fd;
1864
1865 SL_IRETURN(ticket, _("sl_open_file"));
1866}
1867
1868static
1869int check_fname_priv (const char * fname, int priv)
1870{
1871 SL_ENTER(_("check_fname_priv"));
1872 if (fname == NULL)
1873 SL_IRETURN(SL_ENULL, _("check_fname_priv"));
1874 if (priv != SL_YESPRIV && priv != SL_NOPRIV)
1875 SL_IRETURN(SL_EINTERNAL, _("check_fname_priv"));
1876 SL_IRETURN(SL_ENONE, _("check_fname_priv"));
1877}
1878
1879SL_TICKET sl_open_write (const char * fname, int priv)
1880{
1881 long status;
1882 SL_ENTER(_("sl_open_write"));
1883
1884 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1885 SL_IRETURN(status, _("sl_open_write"));
1886
1887 status = sl_open_file(fname, SL_OPEN_FOR_WRITE, priv);
1888 SL_IRETURN(status, _("sl_open_write"));
1889}
1890
1891SL_TICKET sl_open_read (const char * fname, int priv)
1892{
1893 long status;
1894 SL_ENTER(_("sl_open_read"));
1895
1896 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1897 {
1898 TPT(( 0, FIL__, __LINE__,
1899 _("msg=<Error in check_fname_priv.> status=<%ld>\n"),
1900 status));
1901 SL_IRETURN(status, _("sl_open_read"));
1902 }
1903
1904 status = sl_open_file(fname, SL_OPEN_FOR_READ, priv);
1905 SL_IRETURN(status, _("sl_open_read"));
1906}
1907
1908SL_TICKET sl_open_fastread (const char * fname, int priv)
1909{
1910 long status;
1911 SL_ENTER(_("sl_open_fastread"));
1912
1913 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1914 SL_IRETURN(status, _("sl_open_read"));
1915
1916 status = sl_open_file(fname, SL_OPEN_FOR_FASTREAD, priv);
1917 SL_IRETURN(status, _("sl_open_fastread"));
1918}
1919
1920SL_TICKET sl_open_rdwr (const char * fname, int priv)
1921{
1922 long status;
1923 SL_ENTER(_("sl_open_rdwr"));
1924
1925 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1926 SL_IRETURN(status, _("sl_open_rdwr"));
1927
1928 status = sl_open_file(fname, SL_OPEN_FOR_RDWR, priv);
1929 SL_IRETURN(status, _("sl_open_rdwr"));
1930}
1931
1932SL_TICKET sl_open_safe_rdwr (const char * fname, int priv)
1933{
1934 long status;
1935 SL_ENTER(_("sl_open_safe_rdwr"));
1936
1937 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1938 SL_IRETURN(status, _("sl_open_safe_rdwr"));
1939
1940 status = sl_open_file(fname, SL_OPEN_SAFE_RDWR, priv);
1941 SL_IRETURN(status, _("sl_open_safe_rdwr"));
1942}
1943
1944SL_TICKET sl_open_write_trunc (const char * fname, int priv)
1945{
1946 long status;
1947 SL_ENTER(_("sl_open_write_trunc"));
1948
1949 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1950 SL_IRETURN(status, _("sl_open_write_trunc"));
1951
1952 status = sl_open_file(fname, SL_OPEN_FOR_WTRUNC, priv);
1953 SL_IRETURN(status, _("sl_open_write_trunc"));
1954}
1955
1956SL_TICKET sl_open_rdwr_trunc (const char * fname, int priv)
1957{
1958 long status;
1959 SL_ENTER(_("sl_open_rdwr_trunc"));
1960
1961 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1962 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
1963
1964 status = sl_open_file(fname, SL_OPEN_FOR_RWTRUNC, priv);
1965 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
1966}
1967
1968
1969int get_the_fd (SL_TICKET ticket)
1970{
1971 int fd;
1972
1973 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
1974 return (fd);
1975
1976 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
1977 return (SL_EINTERNAL);
1978 return (fd);
1979}
1980
1981int sl_close (SL_TICKET ticket)
1982{
1983 register int fd;
1984
1985 SL_ENTER(_("sl_close"));
1986
1987 if (SL_ISERROR(fd = get_the_fd (ticket)))
1988 SL_IRETURN(fd, _("sl_close"));
1989
1990 /* This may fail, but what to do then ?
1991 */
1992 if (0 != close(fd) && ofiles[fd] != NULL)
1993 {
1994 TPT((0, FIL__, __LINE__,
1995 _("msg=<Error closing file.>, path=<%s>, fd=<%d>, err=<%s>\n"),
1996 ofiles[fd]->path, fd, strerror(errno)));
1997 }
1998
1999 if (ofiles[fd] != NULL)
2000 {
2001 (void) free(ofiles[fd]->path);
2002 (void) free(ofiles[fd]);
2003 ofiles[fd] = NULL;
2004 }
2005
2006 SL_IRETURN(SL_ENONE, _("sl_close"));
2007}
2008
2009int sl_dropall(int fd, int except)
2010{
2011 while (fd < MAXFD)
2012 {
2013 if (ofiles[fd] != NULL && fd != except)
2014 {
2015 if (ofiles[fd]->path != NULL)
2016 (void) free(ofiles[fd]->path);
2017 (void) free(ofiles[fd]);
2018 ofiles[fd] = NULL;
2019 }
2020 ++fd;
2021 }
2022 return 0;
2023}
2024
2025
2026int sl_unlink (SL_TICKET ticket)
2027{
2028 register int fd;
2029
2030 SL_ENTER(_("sl_unlink"));
2031
2032 if (SL_ISERROR(fd = get_the_fd(ticket)))
2033 SL_IRETURN(fd, _("sl_unlink"));
2034
2035 if (retry_aud_unlink(FIL__, __LINE__, ofiles[fd]->path) < 0)
2036 SL_IRETURN(SL_EUNLINK, _("sl_unlink"));
2037
2038 SL_IRETURN(SL_ENONE, _("sl_unlink"));
2039}
2040
2041
2042int sl_seek (SL_TICKET ticket, off_t off_data)
2043{
2044 register int fd;
2045
2046 SL_ENTER(_("sl_seek"));
2047
2048 if (SL_ISERROR(fd = get_the_fd(ticket)))
2049 SL_IRETURN(fd, _("sl_seek"));
2050
2051 if (lseek(fd, off_data, SEEK_SET) == (off_t)-1)
2052 SL_IRETURN(SL_EREWIND, _("sl_seek"));
2053
2054 SL_IRETURN(SL_ENONE, _("sl_seek"));
2055}
2056
2057int sl_rewind (SL_TICKET ticket)
2058{
2059 register int fd;
2060
2061 SL_ENTER(_("sl_rewind"));
2062
2063 if (SL_ISERROR(fd = get_the_fd(ticket)))
2064 SL_IRETURN(fd, _("sl_rewind"));
2065
2066 if (lseek (fd, 0L, SEEK_SET) == (off_t)-1)
2067 SL_IRETURN(SL_EREWIND, _("sl_rewind"));
2068
2069 SL_IRETURN(SL_ENONE, _("sl_rewind"));
2070}
2071
2072int sl_forward (SL_TICKET ticket)
2073{
2074 register int fd;
2075
2076 SL_ENTER(_("sl_forward"));
2077
2078 if (SL_ISERROR(fd = get_the_fd(ticket)))
2079 SL_IRETURN(fd, _("sl_forward"));
2080
2081 if (lseek (fd, 0L, SEEK_END) == (off_t)-1)
2082 SL_IRETURN(SL_EFORWARD, _("sl_forward"));
2083
2084 SL_IRETURN(SL_ENONE, _("sl_forward"));
2085}
2086
2087
2088int sl_sync (SL_TICKET ticket)
2089{
2090 register int fd;
2091
2092 SL_ENTER(_("sl_sync"));
2093
2094 if (SL_ISERROR(fd = get_the_fd(ticket)))
2095 SL_IRETURN(fd, _("sl_sync"));
2096
2097 if (fsync (fd) == -1)
2098 SL_IRETURN(SL_ESYNC, _("sl_sync"));
2099
2100 SL_IRETURN(SL_ENONE, _("sl_sync"));
2101}
2102
2103int sl_read_timeout_prep (SL_TICKET ticket)
2104{
2105 int fd;
2106 int sflags;
2107
2108 SL_ENTER(_("sl_read_timeout_prep"));
2109
2110 if (SL_ISERROR(fd = get_the_fd(ticket)))
2111 {
2112 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2113 SL_IRETURN(fd, _("sl_read_timeout_prep"));
2114 }
2115
2116 /* set to non-blocking mode
2117 */
2118 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2119 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
2120
2121 SL_IRETURN(SL_ENONE, _("sl_read_timeout_prep"));
2122}
2123
2124
2125int sl_read_timeout_fd (int fd, void * buf_in, size_t count,
2126 int timeout, int is_nonblocking)
2127{
2128 int sflags;
2129 fd_set readfds;
2130 struct timeval tv;
2131 /* int sflags; */
2132 int retval;
2133
2134 int fd;
2135 int byteread = 0;
2136 int bytes = 0;
2137 char * buf;
2138
2139 time_t tnow;
2140 time_t tstart;
2141 time_t tdiff;
2142 extern volatile int sig_termfast;
2143
2144 if (is_nonblocking == SL_FALSE)
2145 {
2146 /* set to non-blocking mode
2147 */
2148 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2149 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
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 if (is_nonblocking == SL_FALSE)
2194 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2195 return (SL_EREAD);
2196 }
2197 }
2198 }
2199 else if ((retval == -1) && (errno == EINTR || errno == EAGAIN))
2200 {
2201 retry_msleep(1, 0);
2202 tnow = time(NULL);
2203 tdiff = tnow - tstart;
2204 continue;
2205 }
2206 else if (retval == 0)
2207 {
2208 if (is_nonblocking == SL_FALSE)
2209 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2210 return (SL_TIMEOUT);
2211 }
2212 else
2213 {
2214 if (is_nonblocking == SL_FALSE)
2215 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2216 return (SL_EREAD);
2217 }
2218
2219 if (sig_termfast == 1)
2220 {
2221 if (is_nonblocking == SL_FALSE)
2222 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2223 return (SL_EREAD);
2224 }
2225
2226 tnow = time(NULL);
2227 tdiff = tnow - tstart;
2228
2229 if (tdiff > timeout)
2230 {
2231 if (is_nonblocking == SL_FALSE)
2232 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2233 return (SL_TIMEOUT);
2234 }
2235 }
2236
2237 if (is_nonblocking == SL_FALSE)
2238 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2239 return ((int) bytes);
2240}
2241
2242int sl_read_timeout (SL_TICKET ticket, void * buf_in, size_t count,
2243 int timeout, int is_nonblocking)
2244{
2245 int fd;
2246
2247 if (buf_in == NULL || SL_ISERROR(fd = get_the_fd(ticket)))
2248 {
2249 if (buf_in == NULL)
2250 {
2251 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2252 return (SL_ENULL);
2253 }
2254 if (SL_ISERROR(fd = get_the_fd(ticket)))
2255 {
2256 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2257 return (fd);
2258 }
2259 }
2260
2261 return sl_read_timeout_fd (fd, buf_in, count, timeout, is_nonblocking);
2262}
2263
2264
2265int sl_read (SL_TICKET ticket, void * buf_in, size_t count)
2266{
2267 int fd;
2268 int byteread = 0;
2269 int bytes = 0;
2270
2271 char * buf;
2272
2273 if (count < 1)
2274 {
2275 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
2276 return(SL_ERANGE);
2277 }
2278 if (buf_in == NULL)
2279 {
2280 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2281 return (SL_ENULL);
2282 }
2283
2284 if (SL_ISERROR(fd = get_the_fd(ticket)))
2285 {
2286 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2287 return (fd);
2288 }
2289
2290 buf = (char *) buf_in;
2291
2292 do
2293 {
2294 byteread = read (fd, buf, count);
2295 if (byteread > 0)
2296 {
2297 bytes += byteread; count -= byteread;
2298 buf += byteread;
2299 }
2300 } while ( byteread > 0 ||
2301 ( byteread == -1 && (errno == EINTR || errno == EAGAIN))
2302 );
2303
2304
2305 if (byteread == (-1))
2306 {
2307 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
2308 return (SL_EREAD);
2309 }
2310 return (bytes);
2311}
2312
2313int sl_read_fast (SL_TICKET ticket, void * buf_in, size_t count)
2314{
2315 int fd;
2316 int byteread = 0;
2317
2318 char * buf;
2319
2320 if (count < 1)
2321 {
2322 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
2323 return(SL_ERANGE);
2324 }
2325 if (buf_in == NULL)
2326 {
2327 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2328 return (SL_ENULL);
2329 }
2330
2331 if (SL_ISERROR(fd = get_the_fd(ticket)))
2332 {
2333 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2334 return (fd);
2335 }
2336
2337 buf = (char *) buf_in;
2338
2339 do
2340 {
2341 byteread = read (fd, buf, count);
2342 if (byteread >= 0)
2343 {
2344 return (byteread);
2345 }
2346 } while ( byteread == -1 && (errno == EINTR || errno == EAGAIN));
2347
2348
2349 if (byteread == (-1))
2350 {
2351 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
2352 return (SL_EREAD);
2353 }
2354 return (0);
2355}
2356
2357
2358int sl_write (SL_TICKET ticket, void * msg_in, long nbytes)
2359{
2360 long bytewritten;
2361 long bytecount;
2362 int fd;
2363
2364 char * msg;
2365
2366 SL_ENTER(_("sl_write"));
2367
2368 if (nbytes < 1)
2369 SL_IRETURN(SL_ERANGE, _("sl_write"));
2370 if (msg_in == NULL)
2371 SL_IRETURN(SL_ENULL, _("sl_write"));
2372 if (SL_ISERROR(fd = get_the_fd(ticket)))
2373 SL_IRETURN(fd, _("sl_write"));
2374
2375 msg = (char *) msg_in;
2376
2377 /* write
2378 */
2379 bytecount = 0;
2380 bytewritten = 0;
2381 while (bytecount < nbytes)
2382 {
2383 if ((bytewritten = write (fd, msg, nbytes-bytecount)) > 0)
2384 {
2385 bytecount += bytewritten;
2386 msg += bytewritten; /* move buffer pointer forward */
2387 }
2388 else if (bytewritten <= 0)
2389 {
2390 if ( errno == EINTR || errno == EAGAIN) /* try again */
2391 continue;
2392 else
2393 SL_IRETURN(SL_EWRITE, _("sl_write"));
2394 }
2395 }
2396 SL_IRETURN(SL_ENONE, _("sl_write"));
2397}
2398
2399int sl_write_line (SL_TICKET ticket, void * msg, long nbytes)
2400{
2401 int status;
2402
2403 SL_ENTER(_("sl_write_line"));
2404
2405 status = sl_write(ticket, msg, nbytes);
2406 if (!SL_ISERROR(status))
2407 status = sl_write(ticket, "\n", 1);
2408
2409 SL_IRETURN(status, _("sl_write_line"));
2410}
2411
2412int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes)
2413{
2414 int status;
2415 char * p = (char *) msg;
2416
2417 SL_ENTER(_("sl_write_line_fast"));
2418
2419 /* Here nbytes is strlen(msg), so p[nbytes] is the terminating '\0'
2420 * Overwrite the terminator, write out, then write back the terminator.
2421 */
2422 p[nbytes] = '\n';
2423 status = sl_write(ticket, msg, nbytes+1);
2424 p[nbytes] = '\0';
2425
2426 SL_IRETURN(status, _("sl_write_line_fast"));
2427}
2428
2429
2430/* ----------------------------------------------------------------
2431 *
2432 * Trustfile interface
2433 *
2434 * ---------------------------------------------------------------- */
2435
2436extern uid_t rootonly[];
2437extern int EUIDSLOT;
2438extern int ORIG_EUIDSLOT;
2439
2440extern char tf_path[MAXFILENAME]; /* Error path for trust function. */
2441extern uid_t tf_euid; /* Space for EUID of process. */
2442
2443char * sl_error_string(int errorcode)
2444{
2445 switch (errorcode)
2446 {
2447 case SL_EBOGUS:
2448 return _("Bogus file. Modified during access.");
2449 case SL_EWRITE:
2450 return _("Write error.");
2451 case SL_EREAD:
2452 return _("Read error.");
2453 case SL_ESYNC:
2454 return _("Error in fsync().");
2455 case SL_EFORWARD:
2456 return _("Error in lseek().");
2457 case SL_EREWIND:
2458 return _("Error in lseek().");
2459 case SL_EUNLINK:
2460 return _("Error in unlink().");
2461 case SL_EMEM:
2462 return _("Out of memory.");
2463 case SL_EINTERNAL:
2464 return _("Internal error.");
2465 case SL_ETICKET:
2466 return _("Bad ticket.");
2467 case SL_EREPEAT:
2468 return _("Illegal repeated use of function.");
2469 case SL_ERANGE:
2470 return _("Argument out of range.");
2471 case SL_ENULL:
2472 return _("Dereferenced NULL pointer.");
2473
2474 case SL_EBADUID:
2475 return _("Owner not trustworthy.");
2476 case SL_EBADGID:
2477 return _("Group writeable and member not trustworthy.");
2478 case SL_EBADOTH:
2479 return _("World writeable.");
2480 case SL_EBADFILE:
2481 return _("File access error.");
2482 case SL_EBADNAME:
2483 return _("Invalid filename (prob. too long or null).");
2484
2485 case SL_ETRUNC:
2486 return _("Truncation occured.");
2487 case SL_ESTAT:
2488 return _("stat() failed.");
2489 default:
2490 return _("Unknown error.");
2491 }
2492}
2493
2494
2495
2496char * sl_trust_errfile()
2497{
2498 return &tf_path[0];
2499}
2500
2501extern uid_t tf_baduid;
2502uid_t sl_trust_baduid()
2503{
2504 return tf_baduid;
2505}
2506
2507extern gid_t tf_badgid;
2508gid_t sl_trust_badgid()
2509{
2510 return tf_badgid;
2511}
2512
2513
2514static int trust_count = 0;
2515
2516int sl_trust_purge_user ()
2517{
2518 int i;
2519
2520 EUIDSLOT = ORIG_EUIDSLOT;
2521 trust_count = 0;
2522
2523 for (i = EUIDSLOT; i < (EUIDSLOT + 15); ++i)
2524 rootonly[i] = sh_uid_neg;
2525 return 0;
2526}
2527
2528int sl_trust_add_user (uid_t pwid)
2529{
2530 SL_ENTER(_("sl_trust_add_user"));
2531
2532 if (trust_count == 15)
2533 SL_IRETURN(SL_ERANGE, _("sl_trust_add_user"));
2534
2535 rootonly[EUIDSLOT] = pwid;
2536 ++EUIDSLOT;
2537 ++trust_count;
2538
2539 SL_IRETURN(SL_ENONE, _("sl_trust_add_user"));
2540}
2541
2542#include "sh_mem.h"
2543extern char * sh_util_strdup (const char * str);
2544
2545struct sl_trustfile_store {
2546 char * filename;
2547 uid_t teuid;
2548 struct sl_trustfile_store * next;
2549};
2550
2551static struct sl_trustfile_store * sl_trusted_files = NULL;
2552
2553void sl_add_trusted_file(char * filename, uid_t teuid)
2554{
2555 struct sl_trustfile_store *new = SH_ALLOC(sizeof(struct sl_trustfile_store));
2556
2557 new->filename = sh_util_strdup (filename);
2558 new->teuid = teuid;
2559 new->next = sl_trusted_files;
2560
2561 sl_trusted_files = new;
2562 return;
2563}
2564
2565char * sl_check_trusted_file(char * filename, uid_t teuid)
2566{
2567 struct sl_trustfile_store *new = sl_trusted_files;
2568
2569 while (new)
2570 {
2571 if ((new->teuid == teuid) && (0 == strcmp(new->filename, filename)))
2572 return filename;
2573 new = new->next;
2574 }
2575
2576 return NULL;
2577}
2578
2579void sl_clear_trusted_file(struct sl_trustfile_store * file)
2580{
2581 if (file)
2582 {
2583 if (file->next != NULL)
2584 sl_clear_trusted_file(file->next);
2585 SH_FREE(file->filename);
2586 SH_FREE(file);
2587 }
2588 return;
2589}
2590
2591int sl_trustfile_euid(char * filename, uid_t teuid)
2592{
2593 long status;
2594 static time_t old = 0;
2595 static time_t now;
2596
2597 SL_ENTER(_("sl_trustfile_euid"));
2598
2599 tf_path[0] = '\0';
2600 if (filename == NULL || filename[0] == '\0')
2601 SL_IRETURN(SL_EBADNAME, _("sl_trustfile_euid"));
2602
2603 now = time(NULL);
2604 if (now < (old + 300))
2605 {
2606 if (NULL != sl_check_trusted_file(filename, teuid))
2607 {
2608 sl_strlcpy(tf_path, filename, sizeof(tf_path));
2609 SL_IRETURN(SL_ENONE, _("sl_trustfile_euid"));
2610 }
2611 }
2612 else
2613 {
2614 sl_clear_trusted_file(sl_trusted_files);
2615 sl_trusted_files = NULL;
2616 old = now;
2617 }
2618
2619 tf_euid = teuid;
2620 status = sl_trustfile(filename, NULL, NULL);
2621 if (status == SL_ENONE)
2622 sl_add_trusted_file(filename, teuid);
2623 SL_IRETURN(status, _("sl_trustfile_euid"));
2624}
2625
2626/* ----------------------------------------------------------------
2627 *
2628 * Overflow tests
2629 *
2630 * ---------------------------------------------------------------- */
2631
2632#ifndef SIZE_MAX
2633#define SIZE_MAX (4294967295U)
2634#endif
2635
2636int sl_ok_muli (int a, int b) /* a*b */
2637{
2638 if ((b == 0) || (a >= (INT_MIN / b) && a <= (INT_MAX / b)))
2639 return SL_TRUE; /* no overflow */
2640 return SL_FALSE;
2641}
2642
2643int sl_ok_muls (size_t a, size_t b) /* a*b */
2644{
2645 if ((b == 0) || (a <= (SIZE_MAX / b)))
2646 return SL_TRUE; /* no overflow */
2647 return SL_FALSE;
2648}
2649
2650int sl_ok_divi (int a, int b) /* a/b */
2651{
2652 (void) a;
2653 if (b != 0)
2654 return SL_TRUE; /* no overflow */
2655 return SL_FALSE;
2656}
2657
2658int sl_ok_addi (int a, int b) /* a+b */
2659{
2660 if (a >= 0 && b >= 0)
2661 {
2662 if (a <= (INT_MAX - b))
2663 return SL_TRUE; /* no overflow */
2664 else
2665 return SL_FALSE;
2666 }
2667 else if (a < 0 && b < 0)
2668 {
2669 if (a >= (INT_MIN - b))
2670 return SL_TRUE; /* no overflow */
2671 else
2672 return SL_FALSE;
2673 }
2674 return SL_TRUE;
2675}
2676
2677int sl_ok_adds (size_t a, size_t b) /* a+b */
2678{
2679 if (a <= (SIZE_MAX - b))
2680 return SL_TRUE; /* no overflow */
2681 else
2682 return SL_FALSE;
2683}
2684
2685int sl_ok_subi (int a, int b) /* a-b */
2686{
2687 if (a >= 0 && b < 0)
2688 {
2689 if (a <= (INT_MAX + b))
2690 return SL_TRUE; /* no overflow */
2691 else
2692 return SL_FALSE;
2693 }
2694 else if (a < 0 && b >= 0)
2695 {
2696 if (a >= (INT_MIN + b))
2697 return SL_TRUE; /* no overflow */
2698 else
2699 return SL_FALSE;
2700 }
2701 return SL_TRUE;
2702}
Note: See TracBrowser for help on using the repository browser.