29 Commits

Author SHA1 Message Date
solusipse
10129c8302 Simplified mechanism for null-terminating main buffer 2017-10-19 22:18:57 +02:00
solusipse
288bf2ef84 Added info about beautification service 2017-10-16 16:34:00 +02:00
solusipse
6d292a3001 Fixed #63 2017-10-12 01:28:35 +02:00
solusipse
680bb77f2c Blocked dir traversal 2017-10-09 20:15:22 +02:00
solusipse
1220515107 Merge branch 'master' of github.com:solusipse/fiche 2017-10-09 19:58:42 +02:00
solusipse
801231514c Created very simple script for serving pastes with numbering (#51) 2017-10-09 19:58:21 +02:00
solusipse
4537a6897a Merge pull request #62 from dotlambda/patch-1
Move /bin suffix to $prefix
2017-10-09 19:22:40 +02:00
Robert Schütz
e3f7005180 Move /bin suffix to $prefix
This makes it a lot more portable. For example, on NixOS, there is no `bin` directory.
2017-10-02 19:03:43 +02:00
solusipse
e2daffecd3 Added additional example for -d switch 2017-09-18 02:27:24 +02:00
solusipse
9e3986fa66 Updated usage info 2017-09-17 15:14:35 +02:00
solusipse
ef12b5d54f Added instructions for -S option 2017-09-17 15:13:17 +02:00
solusipse
cdd910b150 Re-added support for https (#33) 2017-09-17 14:34:44 +02:00
solusipse
1cba8ad493 Adding lacking dependency for python's port of scan-build 2017-09-06 01:13:57 +02:00
solusipse
9bab68e44a Trying to resolve scan-build dependencies 2017-09-06 01:10:18 +02:00
solusipse
5abe89fc9c Added lacking clang package for scan-build 2017-09-06 00:59:09 +02:00
solusipse
f4114ce2a6 Added scan-build 2017-09-06 00:55:57 +02:00
solusipse
a2fb9ab838 Added cppcheck 2017-09-06 00:39:00 +02:00
solusipse
10cb524891 Reworked date function to take buffer as an argument 2017-09-05 22:04:21 +02:00
solusipse
99b45b93f2 Changed method of touching logfile before using 2017-09-02 22:20:08 +02:00
solusipse
c1725790bb Update README.md 2017-09-02 21:39:15 +02:00
solusipse
b554845749 Added pure-bash alias alternative to nc 2017-09-02 21:38:03 +02:00
solusipse
7ad6a82fd4 Added some aliases, performed minor cleanup 2017-09-02 21:22:35 +02:00
solusipse
53c0027b3c Extra checks, fixed cleanup in file generating routine 2017-09-02 19:48:02 +02:00
solusipse
7575609c41 Fixed null dereference, renamed argument to match declaration 2017-09-02 19:44:08 +02:00
solusipse
319bd73273 Failure on slug generation is now properly handled 2017-09-02 19:30:08 +02:00
solusipse
2c88f3c990 Merge branch 'master' of github.com:solusipse/fiche 2017-09-02 19:15:48 +02:00
solusipse
bd1751693b Fixed wrong order of cleanup calls 2017-09-02 19:12:10 +02:00
solusipse
54838f5dab Major cleanup 2017-09-02 18:53:43 +02:00
solusipse
8ff08a0409 Entirely rewritten fiche 2017-09-02 17:51:43 +02:00
9 changed files with 1368 additions and 640 deletions

6
.gitignore vendored
View File

@@ -1,2 +1,8 @@
# ignore binaries # ignore binaries
/fiche /fiche
# ignore default outpit dir
code/
# ignore log files
*.log

View File

@@ -1,2 +1,21 @@
language: c language: c
script: make
compiler:
- gcc
- clang
addons:
apt:
packages:
- cppcheck
- clang-3.5
install:
- export PYTHONUSERBASE=~/.local
- easy_install --user scan-build
- easy_install --user typing
script:
- cppcheck --enable=all --error-exitcode=1 --inconclusive main.c fiche.c
- make
- scan-build --status-bugs make -B

View File

@@ -1,16 +1,12 @@
# ----------------------------------- # for debug add -g -O0 to line below
# Fiche MAKEFILE CFLAGS+=-pthread -O2 -Wall -Wextra -Wpedantic -Wstrict-overflow -fno-strict-aliasing -std=gnu11 -g -O0
# https://github.com/solusipse/fiche prefix=/usr/local/bin
# solusipse.net
# -----------------------------------
CFLAGS+=-pthread -O2 all:
prefix=/usr/local ${CC} main.c fiche.c $(CFLAGS) -o fiche
all: fiche
install: fiche install: fiche
install -m 0755 fiche $(prefix)/bin install -m 0755 fiche $(prefix)
clean: clean:
rm -f fiche rm -f fiche

331
README.md
View File

@@ -1,5 +1,330 @@
# fiche fiche [![Build Status](https://travis-ci.org/solusipse/fiche.svg?branch=master)](https://travis-ci.org/solusipse/fiche)
=====
## Warning Command line pastebin for sharing terminal output.
Do not use code from this branch. Please use code from [master](https://github.com/solusipse/fiche) instead. # Client-side usage
Self-explanatory live examples (using public server):
```
echo just testing! | nc termbin.com 9999
```
```
cat file.txt | nc termbin.com 9999
```
In case you installed and started fiche on localhost:
```
ls -la | nc localhost 9999
```
You will get an url to your paste as a response, e.g.:
```
http://termbin.com/ydxh
```
You can use our beautification service to get any paste colored and numbered. Just ask for it using `l.termbin.com` subdomain, e.g.:
```
http://l.termbin.com/ydxh
```
-------------------------------------------------------------------------------
## Useful aliases
You can make your life easier by adding a termbin alias to your rc file. We list some of them here:
-------------------------------------------------------------------------------
### Pure-bash alternative to netcat
__Linux/macOS:__
```
alias tb="(exec 3<>/dev/tcp/termbin.com/9999; cat >&3; cat <&3; exec 3<&-)"
```
```
echo less typing now! | tb
```
_See [#42](https://github.com/solusipse/fiche/issues/42), [#43](https://github.com/solusipse/fiche/issues/43) for more info._
-------------------------------------------------------------------------------
### `tb` alias
__Linux (Bash):__
```
echo 'alias tb="nc termbin.com 9999"' >> .bashrc
```
```
echo less typing now! | tb
```
__macOS:__
```
echo 'alias tb="nc termbin.com 9999"' >> .bash_profile
```
```
echo less typing now! | tb
```
-------------------------------------------------------------------------------
### Copy output to clipboard
__Linux (Bash):__
```
echo 'alias tbc="netcat termbin.com 9999 | xclip -selection c"' >> .bashrc
```
```
echo less typing now! | tbc
```
__macOS:__
```
echo 'alias tbc="nc termbin.com 9999 | pbcopy"' >> .bash_profile
```
```
echo less typing now! | tbc
```
__Remember__ to restart your terminal session after adding any of provided above!
-------------------------------------------------------------------------------
## Requirements
To use fiche you have to have netcat installed. You probably already have it - try typing `nc` or `netcat` into your terminal!
-------------------------------------------------------------------------------
# Server-side usage
## Installation
1. Clone:
```
git clone https://github.com/solusipse/fiche.git
```
2. Build:
```
make
```
3. Install:
```
sudo make install
```
-------------------------------------------------------------------------------
## Usage
```
usage: fiche [-D6epbsdSolBuw].
[-d domain] [-p port] [-s slug size]
[-o output directory] [-B buffer size] [-u user name]
[-l log file] [-b banlist] [-w whitelist] [-S]
```
These are command line arguments. You don't have to provide any of them to run the application. Default settings will be used in such case. See section below for more info.
### Settings
-------------------------------------------------------------------------------
#### Output directory `-o`
Relative or absolute path to the directory where you want to store user-posted pastes.
```
fiche -o ./code
```
```
fiche -o /home/www/code/
```
__Default value:__ `./code`
-------------------------------------------------------------------------------
#### Domain `-d`
This will be used as a prefix for an output received by the client.
Value will be prepended with `http`.
```
fiche -d domain.com
```
```
fiche -d subdomain.domain.com
```
```
fiche -d subdomain.domain.com/some_directory
```
__Default value:__ `localhost`
-------------------------------------------------------------------------------
#### Slug size `-s`
This will force slugs to be of required length:
```
fiche -s 6
```
__Output url with default value__: `http://localhost/xxxx`,
where x is a randomized character
__Output url with example value 6__: `http://localhost/xxxx`,
where is a randomized character
__Default value:__ 4
-------------------------------------------------------------------------------
#### HTTPS `-S`
If set, fiche returns url with https prefix instead of http
```
fiche -S
```
__Output url with this parameter__: `https://localhost/xxxx`,
where x is a randomized character
-------------------------------------------------------------------------------
#### User name `-u`
Fiche will try to switch to the requested user on startup if any is provided.
```
fiche -u _fiche
```
__Default value:__ not set
__WARNING:__ This requires that fiche is started as a root.
-------------------------------------------------------------------------------
#### Buffer size `-B`
This parameter defines size of the buffer used for getting data from the user.
Maximum size (in bytes) of all input files is defined by this value.
```
fiche -B 2048
```
__Default value:__ 32768
-------------------------------------------------------------------------------
#### Log file `-l`
```
fiche -l /home/www/fiche-log.txt
```
__Default value:__ not set
__WARNING:__ this file has to be user-writable
-------------------------------------------------------------------------------
#### Ban list `-b`
Relative or absolute path to a file containing IP addresses of banned users.
```
fiche -b fiche-bans.txt
```
__Format of the file:__ this file should contain only addresses, one per line.
__Default value:__ not set
__WARNING:__ not implemented yet
-------------------------------------------------------------------------------
#### White list `-w`
If whitelist mode is enabled, only addresses from the list will be able
to upload files.
```
fiche -w fiche-whitelist.txt
```
__Format of the file:__ this file should contain only addresses, one per line.
__Default value:__ not set
__WARNING:__ not implemented yet
-------------------------------------------------------------------------------
### Running as a service
There's a simple systemd example:
```
[Unit]
Description=FICHE-SERVER
[Service]
ExecStart=/usr/local/bin/fiche -d yourdomain.com -o /path/to/output -l /path/to/log -u youruser
[Install]
WantedBy=multi-user.target
```
__WARNING:__ In service mode you have to set output directory with `-o` parameter.
-------------------------------------------------------------------------------
### Example nginx config
Fiche has no http server built-in, thus you need to setup one if you want to make files available through http.
There's a sample configuration for nginx:
```
server {
listen 80;
server_name mysite.com www.mysite.com;
charset utf-8;
location / {
root /home/www/code/;
index index.txt index.html;
}
}
```
## License
Fiche is MIT licensed.

0
extras/lines/__init__.py Normal file
View File

51
extras/lines/lines.py Normal file
View File

@@ -0,0 +1,51 @@
from flask import Flask, abort, redirect
app = Flask(__name__)
import argparse, os, pygments
from pygments import highlight
from pygments.lexers import guess_lexer
from pygments.formatters import HtmlFormatter
parser = argparse.ArgumentParser()
parser.add_argument("root_dir", help="Path to directory with pastes")
args = parser.parse_args()
@app.route('/')
def main():
return redirect("http://termbin.com", code=302)
@app.route('/<slug>')
def beautify(slug):
# Return 404 in case of urls longer than 64 chars
if len(slug) > 64:
abort(404)
# Create path for the target dir
target_dir = os.path.join(args.root_dir, slug)
# Block directory traversal attempts
if not target_dir.startswith(args.root_dir):
abort(404)
# Check if directory with requested slug exists
if os.path.isdir(target_dir):
target_file = os.path.join(target_dir, "index.txt")
# File index.txt found inside that dir
with open(target_file) as f:
code = f.read()
# Identify language
lexer = guess_lexer(code)
# Create formatter with line numbers
formatter = HtmlFormatter(linenos=True, full=True)
# Return parsed code
return highlight(code, lexer, formatter)
# Not found
abort(404)
if __name__ == '__main__':
app.run()

1278
fiche.c

File diff suppressed because it is too large Load Diff

165
fiche.h
View File

@@ -5,7 +5,7 @@ Fiche - Command line pastebin for sharing terminal output.
License: MIT (http://www.opensource.org/licenses/mit-license.php) License: MIT (http://www.opensource.org/licenses/mit-license.php)
Repository: https://github.com/solusipse/fiche/ Repository: https://github.com/solusipse/fiche/
Live example: http://code.solusipse.net/ Live example: http://termbin.com
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@@ -14,15 +14,7 @@ usage: fiche [-DepbsdolBuw].
[-o output directory] [-B buffer size] [-u user name] [-o output directory] [-B buffer size] [-u user name]
[-l log file] [-b banlist] [-w whitelist] [-l log file] [-b banlist] [-w whitelist]
-D option is for daemonizing fiche
-e option is for using an extended character set for the URL
Compile with Makefile or manually with -O2 and -pthread flags.
To install use `make install` command.
Use netcat to push text - example: Use netcat to push text - example:
$ cat fiche.c | nc localhost 9999 $ cat fiche.c | nc localhost 9999
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@@ -31,91 +23,92 @@ $ cat fiche.c | nc localhost 9999
#ifndef FICHE_H #ifndef FICHE_H
#define FICHE_H #define FICHE_H
#ifndef HAVE_INET6 #include <stdint.h>
#define HAVE_INET6 1 #include <stdbool.h>
#endif
#include <pwd.h>
#include <time.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
int UID = -1; /**
int GID = -1; * @brief Used as a container for fiche settings. Create before
char *LOG; * the initialization
char *BASEDIR; *
char *BANLIST; */
char *BANFILE; typedef struct Fiche_Settings {
char *WHITEFILE; /**
char *WHITELIST; * @brief Domain used in output links
int DAEMON = 0; */
int HTTPS = 0; char *domain;
int PORT = 9999;
int IPv6 = 0;
int SLUG_SIZE = 4;
int BUFSIZE = 32768;
int QUEUE_SIZE = 500;
char DOMAIN[128] = "localhost/";
char symbols[67] = "abcdefghijklmnopqrstuvwxyz0123456789";
unsigned int time_seed; /**
* @brief Path to directory used for storing uploaded pastes
*/
char *output_dir_path;
struct thread_arguments /**
{ * @brief Port on which fiche is waiting for connections
int connection_socket; */
struct sockaddr_in client_address; uint16_t port;
#if (HAVE_INET6)
struct sockaddr_in6 client_address6;
#endif
};
struct client_data /**
{ * @brief Length of a paste's name
char *ip_address; */
char *hostname; uint8_t slug_len;
};
int create_socket(); /**
int create_directory(char *slug); * @brief If set, returns url with https prefix instead of http
int check_protocol(char *buffer); */
bool https;
void bind_to_port(int listen_socket, struct sockaddr_in serveraddr); /**
#if (HAVE_INET6) * @brief Connection buffer length
void bind_to_port6(int listen_socket, struct sockaddr_in6 serveraddr6); *
#endif * @remarks Length of this buffer limits max size of uploaded files
void error(char *buffer); */
void perform_connection(int listen_socket); uint32_t buffer_len;
void generate_url(char *buffer, char *slug, size_t slug_length, struct client_data data);
void save_to_file(char *buffer, char *slug, struct client_data data);
void display_info(struct client_data data, char *slug, char *message);
void startup_message();
void set_basedir();
void set_domain_name();
void load_list(char *file_path, int type);
void parse_parameters(int argc, char **argv);
void save_log(char *slug, char *hostaddrp, char *h_name);
void set_uid_gid();
char *check_banlist(char *ip_address); /**
char *check_whitelist(char *ip_address); * @brief Name of the user that runs fiche process
char *get_date(); */
char *user_name;
/**
* @brief Path to the log file
*/
char *log_file_path;
/**
* @brief Path to the file with banned IPs
*/
char *banlist_path;
/**
* @brief Path to the file with whitelisted IPs
*/
char *whitelist_path;
} Fiche_Settings;
/**
* @brief Initializes Fiche_Settings instance
*/
void fiche_init(Fiche_Settings *settings);
/**
* @brief Runs fiche server
*
* @return 0 if it was able to start, any other value otherwise
*/
int fiche_run(Fiche_Settings settings);
/**
* @brief array of symbols used in slug generation
* @remarks defined in fiche.c
*/
extern const char *Fiche_Symbols;
struct sockaddr_in set_address(struct sockaddr_in serveraddr);
#if (HAVE_INET6)
struct sockaddr_in6 set_address6(struct sockaddr_in6 serveraddr6);
#endif
struct client_data get_client_address(struct sockaddr_in client_address);
#if (HAVE_INET6)
struct client_data get_client_address6(struct sockaddr_in6 client_address6);
#endif
#endif #endif

140
main.c Normal file
View File

@@ -0,0 +1,140 @@
/*
Fiche - Command line pastebin for sharing terminal output.
-------------------------------------------------------------------------------
License: MIT (http://www.opensource.org/licenses/mit-license.php)
Repository: https://github.com/solusipse/fiche/
Live example: http://termbin.com
-------------------------------------------------------------------------------
usage: fiche [-DepbsdolBuw].
[-D] [-e] [-d domain] [-p port] [-s slug size]
[-o output directory] [-B buffer size] [-u user name]
[-l log file] [-b banlist] [-w whitelist]
Use netcat to push text - example:
$ cat fiche.c | nc localhost 9999
-------------------------------------------------------------------------------
*/
#include "fiche.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
int main(int argc, char **argv) {
// Fiche settings instance
Fiche_Settings fs;
// Initialize settings instance to default values
fiche_init(&fs);
// Note: fiche_run is responsible for checking if these values
// were set correctly
// Note: according to getopt documentation, we don't need to
// copy strings, so we decided to go with pointer approach for these
// Parse input arguments
int c;
while ((c = getopt(argc, argv, "D6eSp:b:s:d:o:l:B:u:w:")) != -1) {
switch (c) {
// domain
case 'd':
{
fs.domain = optarg;
}
break;
// port
case 'p':
{
fs.port = atoi(optarg);
}
break;
// slug size
case 's':
{
fs.slug_len = atoi(optarg);
}
break;
// https
case 'S':
{
fs.https = true;
}
break;
// output directory path
case 'o':
{
fs.output_dir_path = optarg;
}
break;
// buffer size
case 'B':
{
fs.buffer_len = atoi(optarg);
}
break;
// user name
case 'u':
{
fs.user_name = optarg;
}
break;
// log file path
case 'l':
{
fs.log_file_path = optarg;
}
break;
// banlist file path
case 'b':
{
fs.banlist_path = optarg;
}
break;
// whitelist file path
case 'w':
{
fs.whitelist_path = optarg;
}
break;
// Display help in case of any unsupported argument
default:
{
printf("usage: fiche [-dpsSoBulbw].\n");
printf(" [-d domain] [-p port] [-s slug size]\n");
printf(" [-o output directory] [-B buffer size] [-u user name]\n");
printf(" [-l log file] [-b banlist] [-w whitelist] [-S]\n");
return 0;
}
break;
}
}
fiche_run(fs);
return 0;
}