/* * THIS CODE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * User authentication through an external program. The program (or script) * should read a username from command line and a password from standard * input. Exit status 0 means successful authentication. The message * directed to standard output or standard error is logged via syslogd * (facility=auth, priority=info). The authentication mechanism can be * dangerous when used without care! * * , 1999 */ #define _GNU_SOURCE /* Very short hand define to please compilation at glibc 2.1.* -- _XOPEN_SOURCE_EXTENDED + BSD + ... */ #include #include #include #include #include #include "smtpserver.h" #define NOTOK (-1) #define OK 0 #define NBITS ((sizeof (int)) * 8) int pipeauthchild_pid = -1; int pipeauthchild_status = 0; static int run __(( FILE **rfp, FILE **wfp, const char *path, char *const argv[], char *const envp[])); static int run(rfp, wfp, path, argv, envp) FILE **rfp, **wfp; const char *path; char *const argv[]; char *const envp[]; { int pdi[2], pdo[2], i, pid; fflush( stdout ); fflush( stderr ); if( pipe( pdi ) == NOTOK ) return NOTOK; if( pipe( pdo ) == NOTOK ) { (void)close( pdi[0] ); (void)close( pdi[1] ); return NOTOK; } pid = fork(); switch (pid) { case -1: /* Various failures */ MIBMtaEntry->ss.ForkFailures ++; close( pdo[0] ); close( pdo[1] ); close( pdi[0] ); close( pdi[1] ); *rfp = *wfp = NULL; break; case 0: /* Child */ if( pdo[0] != fileno(stdin) ) (void) dup2( pdo[0], fileno(stdin) ); if( pdi[1] != fileno(stdout) ) (void) dup2( pdi[1], fileno(stdout) ); if( pdi[1] != fileno(stderr) ) (void) dup2( pdi[1], fileno(stderr) ); for( i=fileno(stderr)+1; i 1) { fprintf( wfp, "%s\n", password ); fflush(wfp); fclose( wfp ); /* Following weird thing is because we have top-level child-death reaper code at the main part of this program... */ do { int rc = wait( &status ); if (rc < 0 && errno == EINTR) continue; if (rc < 0) break; if (rc != pid) continue; /* Eh... should not.. */ pipeauthchild_status = status; break; } while(1); if ( msg ) { msg[ msgsize-1 ] = 0; fgets( msg, msgsize, rfp ); } } return pipeauthchild_status; } char *pipezpwmatch __((char *cmd, char *uname, char *password, long *uidp)); char *pipezpwmatch( cmd, uname, password, uidp ) char *cmd, *uname, *password; long *uidp; { char msg[256] = ""; int status; status = pipeauth( cmd, msg, sizeof(msg), uname, password ); if (status) *uidp = -1; #ifdef LOG_AUTHPRIV syslog( LOG_AUTHPRIV|LOG_INFO, "%s: %s", uname, msg ); #else syslog( LOG_AUTH|LOG_INFO, "%s: %s", uname, msg ); #endif return status ? "Authentication failed" : NULL; }