source: trunk/src/slib.c@ 166

Last change on this file since 166 was 162, checked in by katerina, 17 years ago

Fix for ticket #89, #90, and #91 (locking,compile failure).

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