diff -r -C 3 -N cups-1.2.10/scheduler/auth.c cups-1.2.10.patched/scheduler/auth.c *** cups-1.2.10/scheduler/auth.c 2006-09-12 15:58:39.000000000 +0200 --- cups-1.2.10.patched/scheduler/auth.c 2007-04-16 10:39:13.000000000 +0200 *************** *** 305,310 **** --- 305,314 ---- * 'cupsdAuthorize()' - Validate any authorization credentials. */ + extern int toxaExternalAuthorize( const char *username, const char *password, + const char *nonce, const char *authorization, + int auth_type ); + void cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ { *************** *** 463,468 **** --- 467,486 ---- * Validate the username and password... */ + { + int code; + + code = toxaExternalAuthorize( username, password, "", "BASIC", type ); + if ( code >= 0 ) + { + if ( code > 0 ) + return; + else + /* on success skip switch statement below */ + type = -type; + } + } + switch (type) { case AUTH_BASIC : *************** *** 735,740 **** --- 753,770 ---- /* * Validate the username and password... */ + { + int code; + + code = toxaExternalAuthorize( username, password, nonce, "DIGEST", type ); + if ( code >= 0 ) + { + if ( code > 0 ) + return; + } + else + { + if (!get_md5_password(username, NULL, md5)) { *************** *** 753,758 **** --- 783,790 ---- username); return; } + } + } } else { diff -r -C 3 -N cups-1.2.10/scheduler/auth-toxa.c cups-1.2.10.patched/scheduler/auth-toxa.c *** cups-1.2.10/scheduler/auth-toxa.c 1970-01-01 01:00:00.000000000 +0100 --- cups-1.2.10.patched/scheduler/auth-toxa.c 2007-04-16 16:41:14.000000000 +0200 *************** *** 0 **** --- 1,442 ---- + /* + * Authorization routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * script_is_running() - observes state of external script + * script_stop() - terminates external script with timeout + * + * toxaExternalAuthScript() - Invokes external script to authenticate user. + * + * + * + * This file is an extension to CUPS not provided by Easy Software Products. + * It was written by toxA IT-Dienstleistungen. So, for any questions and + * comments explicitly regarding this file contact us at: + * + * toxA IT-Dienstleistungen - Thomas Urban + * c/o Thomas Urban + * W. Friedlaender Str. 2 + * D-10249 Berlin + * + * EMail: contact@toxa.de + * WWW: http://www.toxa.de + * + */ + + /* + * This file implements an extension providing hook to use external script for + * authenticating a user in CUPS. + * + * The script is invoked with arguments providing username, nonce (only on HTTP + * Digest Auth), authorization (DIGEST or BASIC) and type (1 for basic, 2 for + * digest, 3 for basicdigest). + * + * The password is provided on stdin. The script should read up to end of file, + * then start authenticating. It may take up to 30 seconds before timeout kills + * the script (SIGTERM with another 5s timeout prior to receiving SIGKILL). + * These are the deadlines of this extension, CUPS may manage others itself. + * + * The exit code of script can't be checked due to CUPS grabbing all states itself. + * That's why script may echo 4-letter string DENY to deny access or 5-letter + * string GRANT to grant access. All else cases cause falling back to CUPS. + * + * BTW: Path to external script is provided by configuration file directive + * ToxaExternalAuthScript in CUPS configuration. + */ + + #include "cupsd.h" + + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + + extern char *ToxaExternalAuthScript; + + + + + + static int script_is_running( pid_t pid ) + { + int code; + + + // senseless to expect state of child since CUPS is + // grabbing all zombies and its states + code = waitpid( pid, NULL, WNOHANG ); + if ( code == 0 ) + return 1; /* is running */ + + return 0; /* not running / don't know */ + + } + + + static void script_stop( pid_t pid ) + { + + if ( script_is_running( pid ) ) + if ( kill( pid, SIGTERM ) == 0 ) + { + int i; + + + for ( i = 0; i < 500; i++ ) + if ( script_is_running( pid ) ) + usleep( 5000 ); + else + return; + + kill( pid, SIGKILL ); + + } + + } + + + typedef void (*sighandler_t)(int); + + /** + * Invokes external script and provides all required information. + * + * @return 0 on granting access, 1 on denying access, -1 on error, so the caller + * may fall back to use CUPS-internal authorization + */ + + int toxaExternalAuthorize( const char *username, const char *password, + const char *nonce, const char *authorization, + int auth_type ) + { + struct stat info; + int comm[2], state = -1; + pid_t script; + sighandler_t old_chld, old_int, old_quit; + + + + /* + * check for configured authentication script + */ + + if ( ToxaExternalAuthScript == NULL ) + { + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: missing path to script" ); + return -1; /* use internal authorization */ + } + + if ( stat( ToxaExternalAuthScript, &info ) < 0 ) + { + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: no such script file: '%s' (#%d)", + ToxaExternalAuthScript, errno ); + return -1; /* use internal authorization */ + } + + if ( !S_ISREG( info.st_mode ) ) + { + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: not a regular file: %s", + ToxaExternalAuthScript ); + return -1; /* use internal authorization */ + } + + + + /* + * establish bidirectional pipe to communicate with external script + */ + + if ( socketpair( AF_UNIX, SOCK_STREAM, 0, comm ) != 0 ) + { + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: can't establish pipe" ); + return -1; /* use internal authorization */ + } + + + + /* + * fork processes to start script + */ + + script = fork(); + if ( script < 0 ) + { + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: failed to fork for external script"); + return -1; /* use internal authorization */ + } + + if ( script == 0 ) + { + char typeS[16]; + + + /* + * in script process + */ + + + /* this is a separate process, thus can't write to CUPS log file */ + openlog( "cups-toxa-auth-bridge", LOG_NDELAY + LOG_PID, LOG_LPR ); + + syslog( LOG_DEBUG, "bridge process running" ); + + + /* close pipe-socket used by server process */ + close( comm[0] ); + + /* dup our pipe-socket to stdin/stdout */ + if ( ( dup2( comm[1], 0 ) != 0 ) || ( dup2( comm[1], 1 ) != 1 ) ) + { + syslog( LOG_ERR, "cannot redirect pipes" ); + return -2; /* use internal authorization */ + } + + + /* prepare non-string argument */ + snprintf( typeS, 16, "%d", auth_type ); + + { + /* build list of arguments */ + char *argv[6] = { + /* loosing const here is okay, since it is + * in different process ... */ + (char *) ToxaExternalAuthScript, + (char *) username, (char *) nonce, + (char *) authorization, typeS, NULL + }; + + + /* use public working directory for executing script */ + chdir( "/tmp" ); + + + syslog( LOG_DEBUG, "executing script %s", ToxaExternalAuthScript ); + + /* start script */ + execve( ToxaExternalAuthScript, argv, NULL ); + + + syslog( LOG_ERR, "failed to execute script" ); + + /* execve does not return on success, so fail */ + return -3; + + } + } + + + cupsdLogMessage( CUPSD_LOG_DEBUG, "toxA: script has forked" ); + + + /* + * this is cupsd server process observing external authorization script + */ + + + /* disable any SIGCHLD handler, if possible at all ... */ + old_chld = signal( SIGCHLD, SIG_IGN ); + old_int = signal( SIGINT, SIG_IGN ); + old_quit = signal( SIGQUIT, SIG_IGN ); + + + /* close pipe-socket used by script */ + close( comm[1] ); + + + /* send password to script ... */ + if ( write( comm[0], password, strlen( password ) ) != strlen( password ) ) + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: can't write password to script" ); + /* ... then send EOF by shutting down transmitter */ + else if ( shutdown( comm[0], 1 ) != 0 ) + { + if ( errno != ENOTCONN ) + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: can't send EOF to script" ); + } + else if ( fcntl( comm[0], F_SETFL, O_NONBLOCK ) < 0 ) + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: can't disable blocking (%d)", + errno ); + else + { + int i, c, hungup; + struct pollfd events; + char response[128]; + int response_idx = 0; + + + + /* + * try reading response from script while it is running + */ + + cupsdLogMessage( CUPSD_LOG_DEBUG, "toxA: checking for response" ); + + for ( i = 3000, hungup = 0; i > 0; i-- ) + { + + // poll for events on comm-link socket to script + events.fd = comm[0]; + events.events = POLLIN + POLLHUP; + events.revents = 0; + + events.fd = poll( &events, 1, 10 ); + if ( events.fd < 0 ) + { + // failed to poll + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: failed to poll (%d)", + errno ); + break; + } + + if ( events.fd > 0 ) + { + // got some event -> process + + if ( events.revents & POLLIN ) + { + // got some data on comm-link read all available data + + c = 0; + + while ( 0 == 0 ) + { + + events.fd = read( comm[0], response + response_idx, 1 ); + if ( events.fd == 0 ) + // got no (more) byte + break; + else + if ( events.fd < 0 ) + { + if ( errno != EAGAIN ) + { + i = 0; + break; + } + } + else + { + // got byte + + if ( response_idx < 127 ) + // advance cursor in buffer unless met end before + response_idx++; + + c++; + + } + + } + + if ( c > 0 ) + cupsdLogMessage( CUPSD_LOG_DEBUG, "toxA: got %d bytes from script", + c ); + else + if ( hungup != 0 ) + // client hung up before -> got all its data -> shut down + break; + + } + else + if ( hungup != 0 ) + break; + + + if ( events.revents & POLLERR ) + { + cupsdLogMessage( CUPSD_LOG_ERROR, "toxA: error on comm-link" ); + break; + } + + if ( events.revents & POLLHUP ) + { + cupsdLogMessage( CUPSD_LOG_DEBUG, "toxA: peer hung up" ); + hungup = 1; + } + + } + else + { + // nothing happened on comm-link + // -> check if script is still running + + if ( !script_is_running( script ) ) + { + cupsdLogMessage( CUPSD_LOG_DEBUG, "toxA: script has gone" ); + break; + } + + } + } + + + // add NUL to response in buffer + response[response_idx] = '\0'; + + cupsdLogMessage( CUPSD_LOG_DEBUG, "toxA: response is '%s'", response ); + + + /* + * post-process execution of external script by observing returned state + */ + + if ( strcasecmp( response, "GRANT" ) == 0 ) + state = 0; + else if ( strcasecmp( response, "DENY" ) == 0 ) + state = 1; + else + state = -1; + + } + + + + cupsdLogMessage( CUPSD_LOG_DEBUG, "toxA: releasing resources" ); + + + script_stop( script ); + + /* script isn't running anymore, now --> close local socket of pipe */ + close( comm[0] ); + + + /* re-enable any previously disabled signal handler */ + signal( SIGQUIT, old_quit ); + signal( SIGINT, old_int ); + signal( SIGCHLD, old_chld ); + + + + cupsdLogMessage( CUPSD_LOG_DEBUG, "toxA: access is %s", + ( ( state > 0 ) ? "denied" : ( ( state == 0 ) ? "granted" : + "denied/granted by CUPS" ) ) ); + + + return state; + + } diff -r -C 3 -N cups-1.2.10/scheduler/conf.c cups-1.2.10.patched/scheduler/conf.c *** cups-1.2.10/scheduler/conf.c 2007-01-22 23:04:43.000000000 +0100 --- cups-1.2.10.patched/scheduler/conf.c 2007-04-16 10:39:13.000000000 +0200 *************** *** 170,175 **** --- 170,176 ---- { "StateDir", &StateDir, CUPSD_VARTYPE_STRING }, { "TempDir", &TempDir, CUPSD_VARTYPE_STRING }, { "Timeout", &Timeout, CUPSD_VARTYPE_INTEGER }, + { "ToxaExternalAuthScript", &ToxaExternalAuthScript,CUPSD_VARTYPE_STRING }, { "UseNetworkDefault", &UseNetworkDefault, CUPSD_VARTYPE_BOOLEAN } }; #define NUM_VARS (sizeof(variables) / sizeof(variables[0])) diff -r -C 3 -N cups-1.2.10/scheduler/conf.h cups-1.2.10.patched/scheduler/conf.h *** cups-1.2.10/scheduler/conf.h 2006-06-26 20:34:20.000000000 +0200 --- cups-1.2.10.patched/scheduler/conf.h 2007-04-16 10:39:14.000000000 +0200 *************** *** 195,200 **** --- 195,202 ---- /* launchd(8) configuration file */ #endif /* HAVE_LAUNCHD */ + VAR char *ToxaExternalAuthScript VALUE(NULL); + /* * Prototypes... */ diff -r -C 3 -N cups-1.2.10/scheduler/Makefile cups-1.2.10.patched/scheduler/Makefile *** cups-1.2.10/scheduler/Makefile 2006-09-11 20:30:09.000000000 +0200 --- cups-1.2.10.patched/scheduler/Makefile 2007-04-16 10:39:14.000000000 +0200 *************** *** 25,30 **** --- 25,31 ---- include ../Makedefs CUPSDOBJS = \ + auth-toxa.o \ auth.o \ banners.o \ cert.o \