source: trunk/src/slib.c@ 168

Last change on this file since 168 was 167, checked in by katerina, 17 years ago

First parts of changes for MODI_TXT

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