source: trunk/src/slib.c@ 148

Last change on this file since 148 was 144, checked in by rainer, 17 years ago

Fix some more queer compile problems.

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