> Date: Mon, 4 Oct 2021 22:03:32 +0200
> From: Rafael Sadowski <[email protected]>
>
> On Sun Sep 26, 2021 at 02:36:02PM +0200, Mark Kettenis wrote:
> > > Date: Fri, 24 Sep 2021 19:36:21 +0200
> > > From: Rafael Sadowski <[email protected]>
> > >
> > > I'm trying to port the more KDE stuff so my question is from porter
> > > perspective.
> > >
> > > I need sigwaitinfo(2)/sigtimedwait(2) and I found both functions in
> > > lib/libc/gen/sigwait.c with the comment "need kernel to fill in more
> > > siginfo_t bits first". Is the comment still up to date? If no, is it
> > > possible to unlock the functions?
> >
> > Still true. These functions are somewhat underspecified by POSIX so
> > it isn't really obvious whatadditional bits need to be filled in.
> > Having examples of code that use these interfaces from ports could
> > help with that.
> >
>
> One use-case from kscreenlocker-5.22.5/kcheckpass/kcheckpass.c
>
> Full code:
> https://github.com/KDE/kscreenlocker/blob/master/kcheckpass/kcheckpass.c
>
> It tries to handle SIGUSR1 and SIGUSR2. I think this can be solved in
> another way, so this is a bad example, isn't it?
So they're using SIGUSR1 and SIGUSR2 as a primitive form of IPC and
using si_pid to check that the signal actually came from the parent
process. I suppose this is to prevent a local DOS against the
password checker. If you don't care about that, you could just drop
sigwaitinfo() call and the si_pid checks.
> /* signal_info for sigwaitinfo() */
> siginfo_t signalInfo;
>
> // now lets block on the fd
> for (;;) {
> conv_server(ConvPutReadyForAuthentication, 0);
>
> keventData = kevent(keventQueue, NULL, 0, keventEvent, 1, NULL);
> if (keventData == -1) {
> /* Let's figure this out in the future, shall we */
> message("kevent() failed with %d\n", errno);
> return 1;
> } else if (keventData == 0) {
> /* Do we need to handle timeouts? */
> message("kevent timeout\n");
> continue;
> }
> // We know we got a SIGUSR1 or SIGUSR2, so fetch it via
> sigwaitinfo()
> // (otherwise, we could have used sigtimedwait() )
> int signalReturn = sigwaitinfo(&signalMask, &signalInfo);
> if (signalReturn < 0) {
> if (errno == EINTR) {
> message("sigawaitinfo() interrupted by unblocked caught
> signal");
> continue;
> } else if (errno == EAGAIN) {
> /* This should not happen, as kevent notified us about
> such a signal */
> message("no signal of type USR1 or USR2 pending.");
> continue;
> } else {
> message("Unhandled error in sigwaitinfo()");
> conv_server(ConvPutAuthError, 0);
> return 1;
> }
> }
> if (signalReturn == SIGUSR1) {
> if (signalInfo.si_pid != parentPid) {
> message("signal from wrong process\n");
> continue;
> }
> /* Now do the fandango */
> ret = Authenticate(method, username, conv_server);
>
> if (ret == AuthBad) {
> message("Authentication failure\n");
> if (!nullpass) {
> openlog("kcheckpass", LOG_PID, LOG_AUTH);
> syslog(LOG_NOTICE, "Authentication failure for %s
> (invoked by uid %d)", username, uid);
> }
> }
> switch (ret) {
> case AuthOk:
> conv_server(ConvPutAuthSucceeded, 0);
> break;
> case AuthBad:
> conv_server(ConvPutAuthFailed, 0);
> break;
> case AuthError:
> conv_server(ConvPutAuthError, 0);
> break;
> case AuthAbort:
> conv_server(ConvPutAuthAbort, 0);
> default:
> break;
> }
> if (uid != geteuid()) {
> // we don't support multiple auth for setuid kcheckpass
> break;
> }
> } else if (signalReturn == SIGUSR2) {
> if (signalInfo.si_pid != parentPid) {
> message("signal from wrong process\n");
> continue;
> }
> break;
> }
>