inetd

def

a super-server daemon on many Unix systems that provides Internet services.

functionality

inetd listens on designated ports used by Internet services such as FTP, POP3, and telnet.
The server program is invoked with the service socket as its standard input, output and error descriptors. After the program is finished,inetd continues to listen on the socket(with exceptions)

TFTPd

def:a server which supports the Internet Trivial File Transfer Protocol (RFC 1350)

Motion

  • initiated by the client
  • request form:negotiated transfer parameters proposed by the client under the terms specified by RFC 2347
  • If server grants:sent files that in fixed length blocks of 512 bytes by default or the number specified in the blocksize negotiated option defined by RFC 2348

flags

-c:
Changes the default root directory of a connecting host
-C:
same as -c
-F:
this strftime(3) compatible format string for the creation of the suffix if -W is specified. By default the string "%Y%m%d" is used.
-d [value]:
Enables debug output

Purpose

  • implemented on top of the Internet User Datagram protocol
  • Can only read and write files (or mail) from/to a remote server
  • used to move files between machines on different networks.

Overview

  • begins with a request to read or write a file and request a connection
  • file is sent in fixed length blocks of 512 bytes
  • a data packet less than 512 bytes signals termination of a transfer.

Each data packet contains one block of data, and must be acknowledged by an acknowledgment packet before the next packet can be sent.

Structure

  • file
  • io
  • transfer
  • util
  • main

file

initialization and convert of file
memberfun:
static size_t convert_from_net(char *,size_t)

static size_t convert_to_net(char *buffer, size_t count, int init)

int write_init(int fd, FILE *f, const char *mode)

size_t write_file(char *buffer, int count)

int write_close(void)

off_t tell_file(void)

int seek_file(off_t offset)

int read_init(int fd, FILE *f, const char *mode)

size_t read_file(char *buffer, int count)

int read_close(void)

int synchnet(int peer)
-reflush socket

io

const char * errtomsg(int error)
static int send_packet(int peer, uint16_t block, char *pkt, int size)
void send_error(int peer, int error)
int send_wrq(int peer, char *filename, char *mode)
int send_rrq(int peer, char *filename, char *mode)
int send_oack(int peer)
int send_ack(int fp, uint16_t block)
int send_data(int peer, uint16_t block, char *data, int size)
int receive_packet(int,char, int, struct sockaddr_storage *,int)
int tftp_send(int peer, uint16_t *block, struct tftp_stats *ts)
int tftp_receive(int, uint16_t *, struct tftp_stats *,struct tftphdr *, size_t)

utils

int settimeouts(intn, int, int _maxtimeouts __unused)
void unmappedaddr(struct sockaddr_in6 *sin6)
size_t get_field(int peer, char *buffer, size_t size)
void tftp_openlog(const char *ident, int logopt, int facility)
void tftp_closelog(void)
void tftp_log(int priority, const char *message, โ€ฆ)
const char * packettype(int type)
int debug_find(char *s)
int debug_finds(char *s)
const char * debug_show(int d)
char * rp_strerror(int error)
void stats_init(struct tftp_stats *ts)
void printstats(const char *, int , struct tftp_stats *)

transfer

int tftp_send(int peer, uint16_t *block, struct tftp_stats *ts)
int tftp_receive(int , uint16_t *, struct tftp_stats *,struct tftphdr *, size_t )

options

void init_options(void);
uint16_t make_options(int peer, char *buffer, uint16_t size);
int parse_options(int peer, char *buffer, uint16_t size);
int option_tsize(int peer, struct tftphdr *, int, struct stat *);
int option_timeout(int peer);
int option_blksize(int peer);
int option_blksize2(int peer);
int option_rollover(int peer);
int option_windowsize(int peer);

When to fork?

After read out of the UDP socket,we fork and exit
ๅญProcessๆœƒๆ•ดๅ€‹ๆŠŠๆฏProcessๆŠ„้Žไพ†๏ผŒ่ฎŠๆˆๅ…ฉๅ€‹็จ็ซ‹ไฝ†ๅ…งๅฎน็›ธๅŒ็š„่จ˜ๆ†ถ้ซ”็ฉบ้–“
ๅœจๅŒๅ€‹็ต‚็ซฏๆฉŸๅŸท่กŒ็š„่‹ฅๅนฒprocessๆœƒๅ…ฑ็”จไธ€ๅ€‹stdout๏ผŒ็”ข็”Ÿ่ณ‡ๆบๅ…ฑไบซ็š„ๅ•้กŒ

Three modes of transfer are currently supported:

  • netascii
  • octet (This replaces the "binary" mode
    of previous versions of this document.) raw 8 bit bytes;
  • mail,
    netascii characters sent to a user rather than a file. (The mail
    mode is obsolete and should not be implemented or used.)
    Additional modes can be defined by pairs of cooperating hosts.

Packets

TFTP supports five types of packets, all of which have been mentioned
above:

โ€‹โ€‹โ€‹โ€‹      opcode  operation
โ€‹โ€‹โ€‹โ€‹        1     Read request (RRQ)
โ€‹โ€‹โ€‹โ€‹        2     Write request (WRQ)
โ€‹โ€‹โ€‹โ€‹        3     Data (DATA)
โ€‹โ€‹โ€‹โ€‹        4     Acknowledgment (ACK)
โ€‹โ€‹โ€‹โ€‹        5     Error (ERROR)

next_state <= {next_state[0], next_state[7:1]};

capability

Capsicum capabilities are
an extension of UNIX file descriptors, and reflect rights
on specific objects, such as files or sockets
example:
For in-
stance, if file descriptor 4 is a capability allowing ac-
cess to /lib, then openat(4, "libc.so.7") will suc-
ceed, whereas openat(4, "../etc/passwd") and
openat(4, "/etc/passwd") will not

hanslu95@hanslu95:/usr/libexec % gdb -tui tftpd

Casper

idea:allow in simple way to obtain more rights in a sandboxed process
When Casper was first implemented it was a daemon
in an operating system.

  • It was divided to four parts
    โ€ข Casper daemon (called casperd(8)),
    โ€ข services (located in /libexec/casper),
    โ€ข list of services (located in /etc/casper),
    โ€ข IPC library (called libcapsicum(3))

PXEboot

def:a form of smart boot ROM, built into Intel EtherExpress Pro/100 and 3Com 3c905c Ethernet cards, and Ethernet-equipped Intel motherboards

Background

Some application:
PXE ็’ฐๅขƒๅปบ็ฝฎๅ€ๅŸŸ็ถฒ่ทฏๅฎ‰่ฃไผบๆœๅ™จ็ณป็ตฑ

TFTP Formats

Type Op # Format without header

โ€‹โ€‹โ€‹โ€‹      2 bytes    string   1 byte     string   1 byte
โ€‹โ€‹โ€‹โ€‹      -----------------------------------------------

RRQ/ | 01/02 | Filename | 0 | Mode | 0 |
WRQ โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“-
2 bytes 2 bytes n bytes
โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“-
DATA | 03 | Block # | Data |
โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“-
2 bytes 2 bytes
โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“-
ACK | 04 | Block # |
โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“
2 bytes 2 bytes string 1 byte
โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“
ERROR | 05 | ErrorCode | ErrMsg | 0 |
โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“

Initial Connection Protocol for reading a file

  1. Host A sends a "RRQ" to host B with source= A's TID,
    destination= 69.

  2. Host B sends a "DATA" (with block number= 1) to host A with
    source= B's TID, destination= A's TID.

mode that needs to read file:

tftp_wrq โ€“- parse_headerโ€“-validate_access

rrq
tftphdr -> recvbuffer ->filename

some structs:

struct tftphdr {
unsigned short th_opcode; /* packet type /
union {
unsigned short tu_block; /
block # /
unsigned short tu_code; /
error code /
char tu_stuff[1]; /
request packet stuff /
} __packed th_u;
char th_data[1]; /
data or error string */
} __packed;

struct block_data {
off_t offset;
uint16_t block;
int size;
};

openfile operation

validate_access(peer, &filename, WRQ)โ€“find_next_name

TCP wrapper part

It seems that I dont have to adjust it.

#ifdef  LIBWRAP
        /*
         * See if the client is allowed to talk to me.
         * (This needs to be done before the chroot())
         */
        {
                printf("req\n");
                struct request_info req;

                request_init(&req, RQ_CLIENT_ADDR, peername, 0);
                request_set(&req, RQ_DAEMON, "tftpd", 0);

                if (hosts_access(&req) == 0) {
                        if (debug & DEBUG_ACCESS)
                                tftp_log(LOG_WARNING,
                                    "Access denied by 'tftpd' entry "
                                    "in /etc/hosts.allow");

                        /*
                         * Full access might be disabled, but maybe the
                         * client is allowed to do read-only access.
                         */
                        request_set(&req, RQ_DAEMON, "tftpd-ro", 0);
                        allow_ro = hosts_access(&req);

                        request_set(&req, RQ_DAEMON, "tftpd-wo", 0);
                        allow_wo = hosts_access(&req);

                        if (allow_ro == 0 && allow_wo == 0) {
                                tftp_log(LOG_WARNING,
                                    "Unauthorized access from %s", peername);
                                exit(1);
                        }

                        if (debug & DEBUG_ACCESS) {
                                if (allow_ro)
                                        tftp_log(LOG_WARNING,
                                            "But allowed readonly access "
                                            "via 'tftpd-ro' entry");
                                if (allow_wo)
                                        tftp_log(LOG_WARNING,
                                            "But allowed writeonly access "
                                            "via 'tftpd-wo' entry");
                        }
                } else
                        if (debug & DEBUG_ACCESS)
                                tftp_log(LOG_WARNING,
                                    "Full access allowed"
                                    "in /etc/hosts.allow");
        }
#endif