update control to reflect move of primary repo to collab-maint
[debian/sudo] / src / exec.c
1 /*
2  * Copyright (c) 2009-2012 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #ifdef HAVE_SYS_SYSMACROS_H
22 # include <sys/sysmacros.h>
23 #endif
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <sys/wait.h>
28 #include <sys/ioctl.h>
29 #ifdef HAVE_SYS_SELECT_H
30 # include <sys/select.h>
31 #endif /* HAVE_SYS_SELECT_H */
32 #include <stdio.h>
33 #ifdef STDC_HEADERS
34 # include <stdlib.h>
35 # include <stddef.h>
36 #else
37 # ifdef HAVE_STDLIB_H
38 #  include <stdlib.h>
39 # endif
40 #endif /* STDC_HEADERS */
41 #ifdef HAVE_STRING_H
42 # include <string.h>
43 #endif /* HAVE_STRING_H */
44 #ifdef HAVE_STRINGS_H
45 # include <strings.h>
46 #endif /* HAVE_STRINGS_H */
47 #ifdef HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif /* HAVE_UNISTD_H */
50 #if TIME_WITH_SYS_TIME
51 # include <time.h>
52 #endif
53 #ifdef HAVE_SETLOCALE
54 # include <locale.h>
55 #endif
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <signal.h>
59 #include <termios.h>
60
61 #include "sudo.h"
62 #include "sudo_exec.h"
63 #include "sudo_plugin.h"
64 #include "sudo_plugin_int.h"
65
66 /* Shared with exec_pty.c for use with handler(). */
67 int signal_pipe[2];
68
69 /* We keep a tailq of signals to forward to child. */
70 struct sigforward {
71     struct sigforward *prev, *next;
72     int signo;
73 };
74 TQ_DECLARE(sigforward)
75 static struct sigforward_list sigfwd_list;
76
77 static int handle_signals(int sv[2], pid_t child, int log_io,
78     struct command_status *cstat);
79 static void forward_signals(int fd);
80 static void schedule_signal(int signo);
81 #ifdef SA_SIGINFO
82 static void handler_nofwd(int s, siginfo_t *info, void *context);
83 #endif
84
85 /*
86  * Fork and execute a command, returns the child's pid.
87  * Sends errno back on sv[1] if execve() fails.
88  */
89 static int fork_cmnd(struct command_details *details, int sv[2])
90 {
91     struct command_status cstat;
92     sigaction_t sa;
93     pid_t child;
94     debug_decl(fork_cmnd, SUDO_DEBUG_EXEC)
95
96     zero_bytes(&sa, sizeof(sa));
97     sigemptyset(&sa.sa_mask);
98     sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
99     sa.sa_handler = handler;
100     sigaction(SIGCONT, &sa, NULL);
101
102     /*
103      * The policy plugin's session init must be run before we fork
104      * or certain pam modules won't be able to track their state.
105      */
106     if (policy_init_session(details) != true)
107         errorx(1, _("policy plugin failed session initialization"));
108
109     child = sudo_debug_fork();
110     switch (child) {
111     case -1:
112         error(1, _("unable to fork"));
113         break;
114     case 0:
115         /* child */
116         close(sv[0]);
117         close(signal_pipe[0]);
118         close(signal_pipe[1]);
119         fcntl(sv[1], F_SETFD, FD_CLOEXEC);
120         restore_signals();
121         if (exec_setup(details, NULL, -1) == true) {
122             /* headed for execve() */
123             sudo_debug_execve(SUDO_DEBUG_INFO, details->command,
124                 details->argv, details->envp);
125             if (details->closefrom >= 0) {
126                 int maxfd = details->closefrom;
127                 dup2(sv[1], maxfd);
128                 (void)fcntl(maxfd, F_SETFD, FD_CLOEXEC);
129                 sv[1] = maxfd++;
130                 if (sudo_debug_fd_set(maxfd) != -1)
131                     maxfd++;
132                 closefrom(maxfd);
133             }
134 #ifdef HAVE_SELINUX
135             if (ISSET(details->flags, CD_RBAC_ENABLED)) {
136                 selinux_execve(details->command, details->argv, details->envp,
137                     ISSET(details->flags, CD_NOEXEC));
138             } else
139 #endif
140             {
141                 sudo_execve(details->command, details->argv, details->envp,
142                     ISSET(details->flags, CD_NOEXEC));
143             }
144             sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to exec %s: %s",
145                 details->command, strerror(errno));
146         }
147         cstat.type = CMD_ERRNO;
148         cstat.val = errno;
149         send(sv[1], &cstat, sizeof(cstat), 0);
150         sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1);
151         _exit(1);
152     }
153     debug_return_int(child);
154 }
155
156 static struct signal_state {
157     int signo;
158     sigaction_t sa;
159 } saved_signals[] = {
160     { SIGALRM },
161     { SIGCHLD },
162     { SIGCONT },
163     { SIGHUP },
164     { SIGINT },
165     { SIGPIPE },
166     { SIGQUIT },
167     { SIGTERM },
168     { SIGTSTP },
169     { SIGTTIN },
170     { SIGTTOU },
171     { SIGUSR1 },
172     { SIGUSR2 },
173     { -1 }
174 };
175
176 /*
177  * Save signal handler state so it can be restored before exec.
178  */
179 void
180 save_signals(void)
181 {
182     struct signal_state *ss;
183     debug_decl(save_signals, SUDO_DEBUG_EXEC)
184
185     for (ss = saved_signals; ss->signo != -1; ss++)
186         sigaction(ss->signo, NULL, &ss->sa);
187
188     debug_return;
189 }
190
191 /*
192  * Restore signal handlers to initial state.
193  */
194 void
195 restore_signals(void)
196 {
197     struct signal_state *ss;
198     debug_decl(restore_signals, SUDO_DEBUG_EXEC)
199
200     for (ss = saved_signals; ss->signo != -1; ss++)
201         sigaction(ss->signo, &ss->sa, NULL);
202
203     debug_return;
204 }
205
206 /*
207  * Execute a command, potentially in a pty with I/O loggging.
208  * This is a little bit tricky due to how POSIX job control works and
209  * we fact that we have two different controlling terminals to deal with.
210  */
211 int
212 sudo_execute(struct command_details *details, struct command_status *cstat)
213 {
214     int maxfd, n, nready, sv[2];
215     const char *utmp_user = NULL;
216     bool log_io = false;
217     fd_set *fdsr, *fdsw;
218     sigaction_t sa;
219     pid_t child;
220     debug_decl(sudo_execute, SUDO_DEBUG_EXEC)
221
222     /* If running in background mode, fork and exit. */
223     if (ISSET(details->flags, CD_BACKGROUND)) {
224         switch (sudo_debug_fork()) {
225             case -1:
226                 cstat->type = CMD_ERRNO;
227                 cstat->val = errno;
228                 debug_return_int(-1);
229             case 0:
230                 /* child continues without controlling terminal */
231                 (void)setpgid(0, 0);
232                 break;
233             default:
234                 /* parent exits (but does not flush buffers) */
235                 sudo_debug_exit_int(__func__, __FILE__, __LINE__,
236                     sudo_debug_subsys, 0);
237                 _exit(0);
238         }
239     }
240
241     /*
242      * If we have an I/O plugin or the policy plugin has requested one, we
243      * need to allocate a pty.  It is OK to set log_io in the pty-only case
244      * as the io plugin tailqueue will be empty and no I/O logging will occur.
245      */
246     if (!tq_empty(&io_plugins) || ISSET(details->flags, CD_USE_PTY)) {
247         log_io = true;
248         if (ISSET(details->flags, CD_SET_UTMP))
249             utmp_user = details->utmp_user ? details->utmp_user : user_details.username;
250         sudo_debug_printf(SUDO_DEBUG_INFO, "allocate pty for I/O logging");
251         pty_setup(details->euid, user_details.tty, utmp_user);
252     }
253
254     /*
255      * We communicate with the child over a bi-directional pair of sockets.
256      * Parent sends signal info to child and child sends back wait status.
257      */
258     if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
259         error(1, _("unable to create sockets"));
260
261     /*
262      * We use a pipe to atomically handle signal notification within
263      * the select() loop.
264      */
265     if (pipe_nonblock(signal_pipe) != 0)
266         error(1, _("unable to create pipe"));
267
268     zero_bytes(&sa, sizeof(sa));
269     sigemptyset(&sa.sa_mask);
270
271     /*
272      * Signals to forward to the child process (excluding SIGALRM and SIGCHLD).
273      * Note: HP-UX select() will not be interrupted if SA_RESTART set.
274      */
275     sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
276     sa.sa_handler = handler;
277     sigaction(SIGALRM, &sa, NULL);
278     sigaction(SIGCHLD, &sa, NULL);
279     sigaction(SIGPIPE, &sa, NULL);
280     sigaction(SIGTERM, &sa, NULL);
281     sigaction(SIGUSR1, &sa, NULL);
282     sigaction(SIGUSR2, &sa, NULL);
283
284     /*
285      * When not running the command in a pty, we do not want to
286      * forward signals generated by the kernel that the child will
287      * already have received either by virtue of being in the
288      * controlling tty's process group (SIGINT, SIGQUIT) or because
289      * the session is terminating (SIGHUP).
290      */
291 #ifdef SA_SIGINFO
292     if (!log_io) {
293         sa.sa_flags |= SA_SIGINFO;
294         sa.sa_sigaction = handler_nofwd;
295     }
296 #endif
297     sigaction(SIGHUP, &sa, NULL);
298     sigaction(SIGINT, &sa, NULL);
299     sigaction(SIGQUIT, &sa, NULL);
300
301     /* Max fd we will be selecting on. */
302     maxfd = MAX(sv[0], signal_pipe[0]);
303
304     /*
305      * Child will run the command in the pty, parent will pass data
306      * to and from pty.  Adjusts maxfd as needed.
307      */
308     if (log_io)
309         child = fork_pty(details, sv, &maxfd);
310     else
311         child = fork_cmnd(details, sv);
312     close(sv[1]);
313
314     /* Set command timeout if specified. */
315     if (ISSET(details->flags, CD_SET_TIMEOUT))
316         alarm(details->timeout);
317
318 #ifdef HAVE_SETLOCALE
319     /*
320      * I/O logging must be in the C locale for floating point numbers
321      * to be logged consistently.
322      */
323     setlocale(LC_ALL, "C");
324 #endif
325
326     /*
327      * In the event loop we pass input from user tty to master
328      * and pass output from master to stdout and IO plugin.
329      */
330     fdsr = emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
331     fdsw = emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
332     for (;;) {
333         memset(fdsw, 0, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
334         memset(fdsr, 0, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
335
336         FD_SET(signal_pipe[0], fdsr);
337         FD_SET(sv[0], fdsr);
338         if (!tq_empty(&sigfwd_list))
339             FD_SET(sv[0], fdsw);
340         if (log_io)
341             fd_set_iobs(fdsr, fdsw); /* XXX - better name */
342         nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
343         sudo_debug_printf(SUDO_DEBUG_DEBUG, "select returns %d", nready);
344         if (nready == -1) {
345             if (errno == EINTR || errno == ENOMEM)
346                 continue;
347             if (errno == EBADF || errno == EIO) {
348                 /* One of the ttys must have gone away. */
349                 goto do_tty_io;
350             }
351             warning(_("select failed"));
352             sudo_debug_printf(SUDO_DEBUG_ERROR,
353                 "select failure, terminating child");
354             schedule_signal(SIGKILL);
355             forward_signals(sv[0]);
356             break;
357         }
358         if (FD_ISSET(sv[0], fdsw)) {
359             forward_signals(sv[0]);
360         }
361         if (FD_ISSET(signal_pipe[0], fdsr)) {
362             n = handle_signals(sv, child, log_io, cstat);
363             if (n == 0) {
364                 /* Child has exited, cstat is set, we are done. */
365                 break;
366             }
367             if (n == -1) {
368                 /* Error reading signal_pipe[0], should not happen. */
369                 break;
370             }
371             /* Restart event loop so signals get sent to child immediately. */
372             continue;
373         }
374         if (FD_ISSET(sv[0], fdsr)) {
375             /* read child status */
376             n = recv(sv[0], cstat, sizeof(*cstat), 0);
377             if (n != sizeof(*cstat)) {
378                 if (n == -1) {
379                     if (errno == EINTR)
380                         continue;
381                     /*
382                      * If not logging I/O we may receive ECONNRESET when
383                      * the command is executed and sv is closed.
384                      * It is safe to ignore this.
385                      */
386                     if (log_io && errno != EAGAIN) {
387                         cstat->type = CMD_ERRNO;
388                         cstat->val = errno;
389                         break;
390                     }
391                     sudo_debug_printf(SUDO_DEBUG_ERROR,
392                         "failed to read child status: %s", strerror(errno));
393                 } else {
394                     /* Short read or EOF. */
395                     sudo_debug_printf(SUDO_DEBUG_ERROR,
396                         "failed to read child status: %s",
397                         n ? "short read" : "EOF");
398                     /* XXX - should set cstat */
399                     break;
400                 }
401             }
402             if (cstat->type == CMD_WSTATUS) {
403                 if (WIFSTOPPED(cstat->val)) {
404                     /* Suspend parent and tell child how to resume on return. */
405                     sudo_debug_printf(SUDO_DEBUG_INFO,
406                         "child stopped, suspending parent");
407                     n = suspend_parent(WSTOPSIG(cstat->val));
408                     schedule_signal(n);
409                     continue;
410                 } else {
411                     /* Child exited or was killed, either way we are done. */
412                     sudo_debug_printf(SUDO_DEBUG_INFO, "child exited or was killed");
413                     break;
414                 }
415             } else if (cstat->type == CMD_ERRNO) {
416                 /* Child was unable to execute command or broken pipe. */
417                 sudo_debug_printf(SUDO_DEBUG_INFO, "errno from child: %s",
418                     strerror(cstat->val));
419                 break;
420             }
421         }
422 do_tty_io:
423         if (perform_io(fdsr, fdsw, cstat) != 0) {
424             /* I/O error, kill child if still alive and finish. */
425             sudo_debug_printf(SUDO_DEBUG_ERROR, "I/O error, terminating child");
426             schedule_signal(SIGKILL);
427             forward_signals(sv[0]);
428             break;
429         }
430     }
431
432     if (log_io) {
433         /* Flush any remaining output and free pty-related memory. */
434         pty_close(cstat);
435    }
436
437 #ifdef HAVE_SELINUX
438     if (ISSET(details->flags, CD_RBAC_ENABLED)) {
439         /* This is probably not needed in log_io mode. */
440         if (selinux_restore_tty() != 0)
441             warningx(_("unable to restore tty label"));
442     }
443 #endif
444
445     efree(fdsr);
446     efree(fdsw);
447     while (!tq_empty(&sigfwd_list)) {
448         struct sigforward *sigfwd = tq_first(&sigfwd_list);
449         tq_remove(&sigfwd_list, sigfwd);
450         efree(sigfwd);
451     }
452
453     debug_return_int(cstat->type == CMD_ERRNO ? -1 : 0);
454 }
455
456 /*
457  * Read signals on fd written to by handler().
458  * Returns -1 on error, 0 on child exit, else 1.
459  */
460 static int
461 handle_signals(int sv[2], pid_t child, int log_io, struct command_status *cstat)
462 {
463     unsigned char signo;
464     ssize_t nread;
465     int status;
466     pid_t pid;
467     debug_decl(handle_signals, SUDO_DEBUG_EXEC)
468
469     for (;;) {
470         /* read signal pipe */
471         nread = read(signal_pipe[0], &signo, sizeof(signo));
472         if (nread <= 0) {
473             /* It should not be possible to get EOF but just in case. */
474             if (nread == 0)
475                 errno = ECONNRESET;
476             /* Restart if interrupted by signal so the pipe doesn't fill. */
477             if (errno == EINTR)
478                 continue;
479             /* If pipe is empty, we are done. */
480             if (errno == EAGAIN)
481                 break;
482             sudo_debug_printf(SUDO_DEBUG_ERROR, "error reading signal pipe %s",
483                 strerror(errno));
484             cstat->type = CMD_ERRNO;
485             cstat->val = errno;
486             debug_return_int(-1);
487         }
488         sudo_debug_printf(SUDO_DEBUG_DIAG, "received signal %d", signo);
489         if (signo == SIGCHLD) {
490             /*
491              * If logging I/O, child is the intermediate process,
492              * otherwise it is the command itself.
493              */
494             do {
495                 pid = waitpid(child, &status, WUNTRACED|WNOHANG);
496             } while (pid == -1 && errno == EINTR);
497             if (pid == child) {
498                 if (log_io) {
499                     /*
500                      * On BSD we get ECONNRESET on sv[0] if monitor dies
501                      * and select() will return with sv[0] readable.
502                      * On Linux that doesn't appear to happen so if the
503                      * monitor dies, shut down the socketpair to force a
504                      * select() notification.
505                      */
506                     (void) shutdown(sv[0], SHUT_WR);
507                 } else {
508                     if (WIFSTOPPED(status)) {
509                         /*
510                          * Save the controlling terminal's process group
511                          * so we can restore it after we resume.
512                          */
513                         pid_t saved_pgrp = (pid_t)-1;
514                         int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
515                         if (fd != -1)
516                             saved_pgrp = tcgetpgrp(fd);
517                         if (kill(getpid(), WSTOPSIG(status)) != 0) {
518                             warning("kill(%d, %d)", (int)getpid(),
519                                 WSTOPSIG(status));
520                         }
521                         if (fd != -1) {
522                             if (saved_pgrp != (pid_t)-1)
523                                 (void)tcsetpgrp(fd, saved_pgrp);
524                             close(fd);
525                         }
526                     } else {
527                         /* Child has exited, we are done. */
528                         cstat->type = CMD_WSTATUS;
529                         cstat->val = status;
530                         debug_return_int(0);
531                     }
532                 }
533             }
534         } else {
535             if (log_io) {
536                 /* Schedule signo to be forwared to the child. */
537                 schedule_signal(signo);
538             } else {
539                 /* Nothing listening on sv[0], send directly. */
540                 if (signo == SIGALRM)
541                     terminate_child(child, false);
542                 else if (kill(child, signo) != 0)
543                     warning("kill(%d, %d)", (int)child, signo);
544             }
545         }
546     }
547     debug_return_int(1);
548 }
549
550 /*
551  * Forward signals in sigfwd_list to child listening on fd.
552  */
553 static void
554 forward_signals(int sock)
555 {
556     struct sigforward *sigfwd;
557     struct command_status cstat;
558     ssize_t nsent;
559     debug_decl(forward_signals, SUDO_DEBUG_EXEC)
560
561     while (!tq_empty(&sigfwd_list)) {
562         sigfwd = tq_first(&sigfwd_list);
563         sudo_debug_printf(SUDO_DEBUG_INFO,
564             "sending signal %d to child over backchannel", sigfwd->signo);
565         cstat.type = CMD_SIGNO;
566         cstat.val = sigfwd->signo;
567         do {
568             nsent = send(sock, &cstat, sizeof(cstat), 0);
569         } while (nsent == -1 && errno == EINTR);
570         tq_remove(&sigfwd_list, sigfwd);
571         efree(sigfwd);
572         if (nsent != sizeof(cstat)) {
573             if (errno == EPIPE) {
574                 sudo_debug_printf(SUDO_DEBUG_ERROR,
575                     "broken pipe writing to child over backchannel");
576                 /* Other end of socket gone, empty out sigfwd_list. */
577                 while (!tq_empty(&sigfwd_list)) {
578                     sigfwd = tq_first(&sigfwd_list);
579                     tq_remove(&sigfwd_list, sigfwd);
580                     efree(sigfwd);
581                 }
582                 /* XXX - child (monitor) is dead, we should exit too? */
583             }
584             break;
585         }
586     }
587     debug_return;
588 }
589
590 /*
591  * Schedule a signal to be forwared.
592  */
593 static void
594 schedule_signal(int signo)
595 {
596     struct sigforward *sigfwd;
597     debug_decl(schedule_signal, SUDO_DEBUG_EXEC)
598
599     sudo_debug_printf(SUDO_DEBUG_DIAG, "forwarding signal %d to child", signo);
600
601     sigfwd = ecalloc(1, sizeof(*sigfwd));
602     sigfwd->prev = sigfwd;
603     /* sigfwd->next = NULL; */
604     sigfwd->signo = signo;
605     tq_append(&sigfwd_list, sigfwd);
606
607     debug_return;
608 }
609
610 /*
611  * Generic handler for signals passed from parent -> child.
612  * The other end of signal_pipe is checked in the main event loop.
613  */
614 void
615 handler(int s)
616 {
617     unsigned char signo = (unsigned char)s;
618
619     /*
620      * The pipe is non-blocking, if we overflow the kernel's pipe
621      * buffer we drop the signal.  This is not a problem in practice.
622      */
623     ignore_result(write(signal_pipe[1], &signo, sizeof(signo)));
624 }
625
626 #ifdef SA_SIGINFO
627 /*
628  * Generic handler for signals passed from parent -> child.
629  * The other end of signal_pipe is checked in the main event loop.
630  * This version is for the non-pty case and does not forward
631  * signals that are generated by the kernel.
632  */
633 static void
634 handler_nofwd(int s, siginfo_t *info, void *context)
635 {
636     unsigned char signo = (unsigned char)s;
637
638     /* Only forward user-generated signals. */
639     if (info == NULL || info->si_code <= 0) {
640         /*
641          * The pipe is non-blocking, if we overflow the kernel's pipe
642          * buffer we drop the signal.  This is not a problem in practice.
643          */
644         ignore_result(write(signal_pipe[1], &signo, sizeof(signo)));
645     }
646 }
647 #endif /* SA_SIGINFO */
648
649 /*
650  * Open a pipe and make both ends non-blocking.
651  * Returns 0 on success and -1 on error.
652  */
653 int
654 pipe_nonblock(int fds[2])
655 {
656     int flags, rval;
657     debug_decl(pipe_nonblock, SUDO_DEBUG_EXEC)
658
659     rval = pipe(fds);
660     if (rval != -1) {
661         flags = fcntl(fds[0], F_GETFL, 0);
662         if (flags != -1 && !ISSET(flags, O_NONBLOCK))
663             rval = fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);
664         if (rval != -1) {
665             flags = fcntl(fds[1], F_GETFL, 0);
666             if (flags != -1 && !ISSET(flags, O_NONBLOCK))
667                 rval = fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
668         }
669         if (rval == -1) {
670             close(fds[0]);
671             close(fds[1]);
672         }
673     }
674
675     debug_return_int(rval);
676 }