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