/*
 * sftpsh -- Secure Shell File Transfer Protocol Shell
 *
 * This "shell" is to be used to restrict a user's usage of SSH to SFTP access
 * only.  By setting the user's shell to /path/to/sftpsh the SSH server will
 * allow the user access to SFTP services without interactive login access.
 *
 * To use, be certain to change the USER-DEFINED VALUES below to settings
 * appropriate to your system.
 *
 * This and other hacks can be found at: http://oddgeek.info/
 *
 * Copyright (c) 2005 Jason A. Dour
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from the
 * use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *     1. The origin of this software must not be misrepresented; you must not
 *     claim that you wrote the original software. If you use this software in
 *     a product, an acknowledgment in the product documentation would be
 *     appreciated but is not required.
 *
 *     2. Altered source versions must be plainly marked as such, and must not
 *     be misrepresented as being the original software.
 *
 *     3. This notice may not be removed or altered from any source
 *     distribution.
 *
 */

/*
 * Version Information
 *
 * 1.0	2005.05.25
 * 
 * 	First public release.  Nothing really changed other than comments and
 * 	adding one include to ensure a -Wall returns no warnings.
 *
 * ooze	2001.05.31
 * 
 * 	First documented version.  Given to a few people in the SSH community,
 * 	but not distributed widely.  This version has since been hosted by
 * 	others, and even used as a basis for other code projects such as
 * 	chressh.
 *
 * primordial ooze
 *
 * 	Used briefly on various private systems.  Given to a few others
 * 	privately when they had need of it.  Never distributed widely.
 *
 */

/*
 * USER-DEFINED VALUES
 * 
 * Define the path to the SFTP Server binary, the execution
 * command name of the server, and any command arguments.
 * With openssh these values are generally '/path/to/sftp-server,'
 * 'sftp-server,' and '' respectively.
 *
 * Lastly, define the message that is written to stdout when
 * an interactive shell is attempted.
 */
#define SFTP_BINARY "/usr/local/libexec/sftp-server"
#define SFTP_EXNAME "sftp-server"
#define SFTP_ARGS   ""

#define DENY_MESG   "\n\rYou do not have interactive login access to this machine.\n\r\n\rContact the system administrator should this not be the case.\n\r"



/*
 * DO NOT MODIFY BEYOND THIS POINT UNLESS YOU ARE CERTAIN YOU
 * WILL NOT OPEN UP THE SHELL TO ALLOW ANYTHING OTHER THAN THE
 * SFTP SERVER TO EXECUTE.
 */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>



/*
 * Output the error and return.
 */
void error(char *program, char *why) {
	/* Holder for output format. */
	char *outputstr;
   
	/* Build the output format... */
	if ( strlen(program) )
		/* Prepend error output with program name. */
		outputstr = "%s: %s\n\r";
	else
		/* Just output the error. */
		outputstr = "%s%s\n\n";

	/* If stderr is a tty... */
	if ( isatty( fileno(stderr) ) ) {
		/* Output this to stderr... */
		fprintf(stderr, outputstr, program, why);
	} else {
		/* Otherwise, output to stdout. */
		fprintf(stdout, outputstr, program, why);
	}
	
	/* All is well.  Return. */
	return;
}



/*
 * There isn't much to this program.  Grab the shell's name.
 * Check the argument passed.  Either execute or error out.
 */
int main(int argc, char **argv) {
	char *progname;          /* The sftpsh execution name.     */
	char *sftp_cmd[] = {     /* The SFTP Server command array. */
		SFTP_EXNAME,
		SFTP_ARGS,
		NULL
	};

	/* Grab the sftpsh execution name. */
	if ( strchr(argv[0], '/') )
		progname = strrchr(argv[0], '/') + 1;
	else
		progname = argv[0];

	/* Check the of args.  Error out if bad. */
	if ( (	(argc == 3) &&
		(strcmp(argv[1], "-c") == 0) && 
		(strcmp(argv[2], SFTP_EXNAME) == 0) ) ||
	     (	(argc == 2) &&
		(strcmp(argv[1], SFTP_EXNAME) == 0) ) ) {

		/* Exec the SFTP Server binary. */
		execv(SFTP_BINARY, sftp_cmd);

		/* 
		 * Still here?  Where's the kaboom?  There was supposed to be
		 * an earth-shattering kaboom!
		 */
		error(progname, "SFTP Server binary cannot be executed.");
		exit(-1);
	}

	/* Check whether it is a command attempt or a login. */
	if (argc > 1) {
		/* Command not allowed.  Exit.  */
		error(progname, "Command not allowed.");
		exit(1);
	} else {
		/* Print DENY_MESG and exit. */
		error("", DENY_MESG);
		sleep(3);
		exit(2);
	}

	/* That's it...we should never get past the above checks. */
	exit(255);
}
