⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmds.c

📁 ftp服务器源程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (c->recv_buf[0] == 'A') {		c->ascii_mode = 1;		numeric(c, 200, "Type is ASCII.");	} else if (c->recv_buf[0] == 'I') {		c->ascii_mode = 0;		numeric(c, 200, "Type is IMAGE.");	} else {		numeric(c, 504, "Unknown type.");	}#else	numeric(c, 200, "TYPE ignored (always I)");#endif	return 1;}/* * cmd_mode():	Handles the MODE command. Only stream mode is supported. */int cmd_mode(struct conn * const c){ 	c->recv_buf[0] &= (255-32);	/* convert to upper case */	if (c->recv_buf[0] == 'S') {		numeric(c, 200, "Mode is STREAM.");	} else {		numeric(c, 504, "Unknown mode.");	}	return 1;}/* * cmd_stru():	Handles the STRU command. Only file mode is supported. */int cmd_stru(struct conn * const c){	c->recv_buf[0] &= (255-32);	/* convert to upper case */	if (c->recv_buf[0] == 'F') {		numeric(c, 200, "Structure is FILE.");	} else {		numeric(c, 504, "Unknown structure.");	}	return 1;}/* * cmd_help():	Handle the HELP command. I'm sorry, but I'm unwilling *		to use a lot of space to explain the RFCs in such a message, *		and BetaFTPD doesn't have any special things that should *		be noted anywhere. Thus, this message is close to empty. I *		feel that a 5xx entry would have been better, but that is *		disallowed. * *		As with ACCT, this command is supposed to be executed from *		everywhere, so we have to run without setuid. I don't like *		it, but at the same time I have to idea what could go *		wrong... * *		Perhaps I should make this message sound a little less *		like an error, since the error code is intended for helpful *		messages? :-) */int cmd_help(struct conn * const c){	numeric(c, 414, "Sorry, no detailed help; use standard FTP commands.");	return 1;}/* * cmd_quit():	Handles the QUIT command, which shuts down the control *		and data sockets. */int cmd_quit(struct conn * const c){	numeric(c, 221, "Have a nice day!");	destroy_conn(c);	return 0;}/* * cmd_rein():  Handle the REIN command, which does close to a full reset *		of the connection. Much of the code here is intentionally *		copied directly from alloc_new_conn() -- perhaps we should *		modularize this? */int cmd_rein(struct conn * const c){	destroy_ftran(c->transfer);	c->buf_len = c->auth = c->rest_pos = 0;	/* equals: strcpy(c->curr_dir, "/") ; strcpy(c->last_cmd, ""); */	c->curr_dir[0] = '/';#if WANT_FULLSCREEN	c->curr_dir[1] = c->last_cmd[0] = '\0';#else	c->curr_dir[1] = '\0';#endif	time(&(c->last_transfer));	numeric(c, 220, "BetaFTPD " VERSION " ready.");	return 1;}#if DOING_PROFILING/* * cmd_exit():	Handles the EXIT command, my own `extension' to the *		FTP protocol... IMPORTANT: Only to be used for profiling *		purposes!! (It's needed to get some profiling data out *		of the server after compiling it with -pg, since such data *		is only written on a clear exit()). Any user (even those *		not logged in) can issue an EXIT, and make the server shut *		down without clearing any sockets etc. In other words: *		Don't use it on a production site. */void cmd_exit(struct conn * const c){	while (first_conn->next_conn)		destroy_conn(first_conn->next_conn);	exit(0);}#endif/* * parse_command(): *		Gets a command from c->recv_buf, determines which command *		it is, sets proper effective user-ID and calls the command *		handler. Finally, it cleans up. * *		To me, this command seems optimizable, but I'm not really *		sure where :-) */void parse_command(struct conn *c){	int cmlen;	const struct handler *h = handler_table;  	/* first entry */	if (c == NULL) return;	/* strip any leading non-ASCII characters (including CR/LFs) */	while (c->buf_len > 0 && (c->recv_buf[0] < 'a' || c->recv_buf[0] > 'z')			      && (c->recv_buf[0] < 'A' || c->recv_buf[0] > 'Z')) {		remove_bytes(c, 1);		/* not good */	}	/* scan, searching for CR or LF */		cmlen = strcspn(c->recv_buf, "\r\n");	if (cmlen >= c->buf_len) return;#if WANT_FULLSCREEN	strncpy(c->last_cmd, c->recv_buf, cmlen);	c->last_cmd[cmlen] = 0;#endif	do {		if ((cmlen >= (strlen(h->cmd_name) + h->add_cmlen)) &&		    (strncasecmp(c->recv_buf, h->cmd_name, strlen(h->cmd_name)) == 0)) {			if (c->auth < h->min_auth) {				numeric(c, 503, "Please login with USER and PASS.");				while (c->recv_buf[0] != '\n') remove_bytes(c, 1);			} else {				char schar;#if !WANT_NONROOT				if (h->do_setuid) {					seteuid(c->uid);				} else {					seteuid(0);				}#endif				remove_bytes(c, strlen(h->cmd_name));				cmlen -= strlen(h->cmd_name);				while (c->recv_buf[0] == ' ') {					remove_bytes(c, 1);					cmlen--;				}				schar = c->recv_buf[cmlen];				c->recv_buf[cmlen] = 0;				/* result of zero means the connection is freed */				if (h->callback(c)) {					c->recv_buf[cmlen] = schar;#if !WANT_NONROOT					if (h->do_setuid) seteuid(getuid());#endif					remove_bytes(c, cmlen);				}			}			return;		}	} while ((++h)->callback != NULL);	numeric(c, 500, "Sorry, no such command.");	remove_bytes(c, cmlen); }/* * prepare_for_transfer(): *		Prepares an ftran object for a file transfer, setting *		file size, opening sockets etc. * *		nonroot notice: prepare_for_transfer() assumes all access *		checks are already done. */void prepare_for_transfer(struct ftran *f){#if WANT_NONROOT#warning No nonroot checking for prepare_for_transfer() yet#endif#if HAVE_MMAP	/* mmap doesn't make temp files for dir listings */	if (!f->dir_listing) {#endif		f->size = lseek(f->local_file, 0, SEEK_END);		errno = 0;#if WANT_UPLOAD		if (f->upload == 0 || f->append == 0 || f->owner->rest_pos != 0)#endif 			lseek(f->local_file, f->owner->rest_pos, SEEK_SET);#if HAVE_MMAP	}#endif		if (f->state == 1) {		/* PASV connection */		f->state = 2;		/* waiting */	} else if (f->state == 3) {	/* PORT connection */		f->state = 4;		connect(f->sock, (struct sockaddr *)&f->sin, sizeof(f->sin));		add_fd(f->sock, POLLOUT);	}	time(&(f->tran_start));}/* * decode_mode(): *		Takes a mode_t argument (from a `struct stat'), and *		returns the proper dirlist letter for that type. * *		Note: S_IFLNK seems to be broken, or perhaps I just have *		missed something (S_IFLNK is always set for all *files* on *		my glibc 2.0.111 system). * *		The most common cases are put first, for speed :-) */char decode_mode(mode_t mode) {	if (S_ISREG(mode))  return '-';	if (S_ISDIR(mode))  return 'd';	if (S_ISLNK(mode))  return 'l';	if (S_ISBLK(mode))  return 'b';	if (S_ISCHR(mode))  return 'c';	if (S_ISSOCK(mode)) return 's';	if (S_ISFIFO(mode))  return 'f';	return '-';}/* * translate_path(): *		Take an FTP path, do all neccessary root_dir checks, *		change to the correct directory and return the proper *		file name to open/stat/whatever. The path returned is *		relative to the current directory (NOT absolute). chdir() *		in any way will `destroy' this argument. * *		Note that `path' will be _changed_, and used as a return pointer *		base. Do not attempt to free the result from this function -- *		if you need to, free path instead. */char *translate_path(struct conn * const c, char * const path){	char *ptr = NULL;	/* chdir to the right dir, then chop it off */	chdir(c->curr_dir);	ptr = strrchr(path, '/');	if (ptr != NULL) {		char save_char = ptr[0];		ptr[0] = 0;		if (do_chdir(c, path) == -1) {			return NULL;		}		ptr[0] = save_char;		ptr++;	} else {		ptr = path;	}	return ptr;}/* * do_openfile(): *		Opens the file PATH with access parameters FLAGS, translating *		paths and checking permissions as neccessary. Generally, this *		should be used whenever you need an open(). * *		The parameters might be a bit confusing. To clarify them a bit: *		c:		IN/OUT (will be changed) *		path:		IN (but _will_ be changed) *		filename:	OUT *		flags:		IN *		check_perm:	IN */int do_openfile(struct conn * const c, char * const path,		char * const filename, const int flags#if WANT_NONROOT		, const int check_permission#endif){	char *ptr;	struct stat buf;#if WANT_NONROOT	if (nr_check_permission(c->uid, path, check_permission, 0, NULL) == -1) {		return -1;	}#endif	ptr = translate_path(c, c->recv_buf);	if (ptr == NULL) return -1;#if WANT_UPLOAD	if ((flags & O_CREAT) == 0) {#endif		TRAP_ERROR(stat(ptr, &buf) == -1, 550, return -2); 		if (!S_ISREG(buf.st_mode)) {			numeric(c, 550, "Not a plain file.", ptr);			return -2; 		}#if WANT_UPLOAD	}#endif	if (filename != NULL) {	/* filename should always be != NULL */		strcpy(filename, ptr);	}	return open(ptr, flags, 0666);}/* * prepare_for_listing(): *		Parse list options, put them back into the list_options *		structure lo, and make temporary room for the list. */int prepare_for_listing(struct conn * const c, char ** const ptr,			struct list_options * const lo){#if !HAVE_MMAP	char *tfname;#endif	struct ftran *f = c->transfer;	char *tmp;	char *optr = NULL, *fptr = NULL; #if WANT_NONROOT	char chd[512];#endif#if WANT_NONROOT#warning No nonroot checking for prepare_for_listing() yet#endif	if ((f == NULL) || ((f->state != 1) && (f->state != 3))) {		numeric(c, 425, "No data connection set up; please use PASV or PORT.");		return -1;	}	/*	 * A little parameter scanning is required here. There can only	 * be two parts: the directory name, and any options. We'll find	 * any options first.	 */	if (c->recv_buf[0] == '-') {		optr = c->recv_buf;	} else {		optr = strstr(c->recv_buf, " -");	}	/* Then see if there are any options to parse. */	if (optr != NULL) {		while (*++optr) {			switch (*optr & (255-32)) {	/* uppercase */			case 'R':	/* actually case sensitive... */				lo->recursive = 1;				break;			case 'L':				lo->long_listing = 1;				break;			case 'F':				lo->classify = 1;				break;			case ' ':				fptr = optr + 1;				*(optr--) = 0;				break;			default:				break;			}		}	} else {		fptr = c->recv_buf;	}		/* then we chdir to the dir in fptr (if any) */	tmp = fptr ? strrchr(fptr, '/') : NULL;	if (tmp != NULL) {		tmp[0] = 0;		if (do_chdir(c, fptr) == -1) return -1;		fptr = tmp + 1;	} else {		/* current directory */		TRAP_ERROR(chdir(c->curr_dir) == -1, 550, return -1);	}	/* if no argument, choose all files */	if (fptr == NULL || fptr[0] == 0) {		fptr = "*";	} else {		/* we need to check if the last part is a directory (no -d switch) */		struct stat buf;		if (stat(fptr, &buf) == 0 && S_ISDIR(buf.st_mode)) {			TRAP_ERROR(chdir(fptr) == -1, 550, return -1);			fptr = "*";		}	}	*ptr = fptr;#if WANT_NONROOT	getcwd(chd, 512);	if (nr_check_permission(c->uid, chd, 4, 1, NULL) == -1) {	 	numeric(c, 550, "Permission denied");		return -1;	}#endif#if !HAVE_MMAP	tfname = tempnam(NULL, "ftp");#if WANT_NONROOT	if (tfname == NULL) tfname = tempnam("/", "ftp");#endif	TRAP_ERROR(tfname == NULL, 550, return -1);	strcpy(f->filename, tfname);	free(tfname);	f->local_file = open(f->filename, O_RDWR | O_CREAT | O_TRUNC, 0666);	TRAP_ERROR(f->local_file == -1, 550, return -1);#endif	f->dir_listing = 1;#if WANT_UPLOAD	f->upload = 0;#endif	return 0;}/* * classify():	Takes a mode_t argument (from `struct stat'), and returns *		the parameter to be used in an `ls -F'-style listing. */char classify(const mode_t mode){	if (S_ISREG(mode)) {		if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {			return '*';		} else {			return '\0';		}	}	if (S_ISDIR(mode)) return '/';	if (S_ISLNK(mode)) return '@';	if (S_ISSOCK(mode)) return '=';	if (S_ISFIFO(mode)) return '|';	return '\0'; }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -