source: trunk/src/slib.c@ 139

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

Fix compile errors.

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