1 /* utftpd: the tftp daemon */
2 
3 /*
4  * Copyright (C) 1999 Uwe Ohse
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "config.h"
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25 #include <signal.h>
26 #include <fcntl.h>
27 
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include "no_tftp.h"
31 #include <netdb.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #ifdef HAVE_ARPA_INET_H
35 #include <arpa/inet.h>
36 #endif
37 
38 #include <syslog.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include "uogetopt.h"
44 #include "timselsysdep.h"
45 #include "timing.h"
46 #include "nonblock.h"
47 #include "str2num.h"
48 #include "uostr.h"
49 #include "uoio.h"
50 #include "cdb.h"
51 #include "sys/wait.h"
52 #include "wildmat.h"
53 #include "utftpd.h"
54 #include "str_ulong.h"
55 #include "uosock.h"
56 
57 #ifndef errno
58 extern int errno;
59 #endif
60 
61 int nullfd;
62 
63 #define TFTP_OFFSET 4
64 static struct utftpd_ctrl *ctrl;
65 
66 static uostr_t rules=UOSTR_INIT;
67 ssize_t got;
68 
69 static char *opt_configfile;
70 static char *opt_global_chdir;
71 #ifdef HAVE_CHROOT
72 static char *opt_global_chroot;
73 #endif
74 static char *opt_global_uid;
75 static char **opt_old_style_ac;
76 int opt_verbose;
77 
78 /* from configfile */
79 static char *opt_chdir;
80 static char *opt_chroot;
81 static char *opt_write;
82 static char *opt_create;
83 static char *opt_read;
84 static char *opt_uid;
85 char *opt_rcs_ci;
86 char *opt_rcs_co;
87 char *opt_sccs_get;
88 char *opt_sccs_unget;
89 char *opt_sccs_clean;
90 char *opt_sccs_delta;
91 static int opt_syslog; /* "-l" option of inetutils tftpd. This is just a dummy variable */
92 static int opt_keeprun;
93 static const char *opt_standalone;
94 int opt_suppress_naks;
95 int opt_timing;
96 
97 static const char *need_commit; /* a filename */
98 static char *argv0;
99 
100 char *remoteip=NULL;
101 static struct utftpd_ctrl *
102 	utftpd_setup_ctrl(struct utftpd_ctrl *old, size_t segsize);
103 
104 static uogetopt_t myopts[]={
105 	{'c',"config-file",   UOGO_STRING,&opt_configfile,0,
106 	 "Specify location of configuration file.\n"
107 	 "This has to be a cdb file, created by utftpd_make.\n"
108 	 "It will be opened before a chroot, if any.","CDBFILE"},
109 #ifdef HAVE_CHROOT
110 	{'C',"global-chroot",   UOGO_STRING,&opt_global_chroot,0,
111 	/*12345678901234567890123456789012345678901234567890 */
112 	 "Chroot to DIRECTORY before reading configuration.\n"
113 	 "This will change the working directory, too.","DIR"},
114 #endif
115 	{'d',"global-chdir",   UOGO_STRING,&opt_global_chdir,0,
116 	 "Chdir to DIRECTORY before reading configuration.\n"
117 	 "This will happen _after_ the chroot.", "DIR"},
118 	{'k',"keeprunning",   UOGO_FLAG,&opt_keeprun,1,
119 	 "Accept other request until all are finished",0},
120 	{'l',0,   UOGO_FLAG,&opt_syslog,1,
121 	 "Log all request to syslog() (active by default).\n"
122 	 "This option is for compatability",0},
123 	{'n',"suppress-naks",   UOGO_FLAG,&opt_suppress_naks,1,
124 	 "Suppress NAKs for nonexistant files.\n"
125 	/*12345678901234567890123456789012345678901234567890 */
126 	 "Don't send ACK on read requests for nonexistant\n"
127 	 "relative filenames.",0},
128 	{'s',"standalone",   UOGO_STRING,&opt_standalone,1,
129 	 "Don't use inetd.\n"
130 	 "Needs an address and port to bind to:\n"
131 	 "  HOST:PORT -> bind to address HOST, port PORT\n"
132 	 "  HOST      -> bind to address HOST, port 69\n"
133 	 "  HOST:     -> same\n"
134 	 "  :PORT     -> bind to IPADDR_ANY, port PORT\n"
135 	 "  :         -> bind to IPADDR_ANY, port 69\n" ,"ADDRESS:PORT"},
136 	{'t',"timing",   UOGO_FLAG,&opt_timing,1,
137 	 "Log transfer rates to syslog().",0},
138 	{'u',"global-uid",   UOGO_STRING,&opt_global_uid,0,
139 	 "Change user id before reading configuration.\n"
140 	 "Use \"user.group\" to spefify a group.\n"
141 	 "Use \".group\" to specify only a group.\n"
142 	 "Numerical ids are allowed, as are names."
143 	 ,0},
144 	{'v',"verbose",   UOGO_FLAG,&opt_verbose,1,
145 	 "Be verbose to syslog().",0},
146 	{  0,"copyright", UOGO_HIDDEN|UOGO_PRINT,0,0,
147 	 "Copyright (C) 1999 Uwe Ohse\n"
148 	 PACKAGE " comes with NO WARRANTY,\n"
149 	 "to the extent permitted by law.\n"
150 	 "You may redistribute copies of " PACKAGE "\n"
151 	 "under the terms of the GNU General Public License.\n"
152 	 "For more information about these matters,\n"
153 	 "see the files named COPYING.\n"
154 	 ,0},
155 	{0,0,0,0,0,0,0}
156 };
157 
158 static struct utftpd_vc *
find_vc(const char * filename,struct utftpd_ctrl * flags)159 find_vc(const char *filename, struct utftpd_ctrl *flags)
160 {
161 	if (0==utftpd_sccs.test(filename,flags)) return &utftpd_sccs;
162 	if (0==utftpd_rcs.test(filename,flags)) return &utftpd_rcs;
163 	return &utftpd_novc;
164 }
165 
166 static char *
rule_lookup(const char * tag)167 rule_lookup(const char *tag)
168 {
169 	char *s;
170 	size_t tl=strlen(tag);
171 	s=rules.data;
172 	while (*s) {
173 		char *nul;
174 		char *eq;
175 		char *q;
176 		char *end;
177 		int found=0;
178 		end=rules.data+rules.len;
179 		eq=s;
180 		while (eq!=end && *eq!='=') eq++;
181 		if (eq==end) goto bad_format;
182 		nul=eq+1;
183 		while (nul!=end && *nul!='\0') nul++;
184 		if (nul==end) goto bad_format;
185 		q=strstr(s,tag);
186 		if (q && (q==s || q[-1]==',') && (q[tl]=='=' || q[tl]==','))
187 			found=1;
188 		if (found) {
189 			char *v;
190 			v=(char *) malloc(nul-eq);
191 			if (!v) goto oom;
192 			memcpy(v,eq+1,nul-eq);
193 			if (opt_verbose)
194 				syslog(LOG_INFO,"CONFIG %s=%s",tag,v);
195 			return v;
196 		}
197 		s=nul+1;
198 		if (s==end) break;
199 	}
200 	return NULL;
201   bad_format:
202 	syslog(LOG_ERR,"bad config file %s",opt_configfile);
203 	_exit(1);
204   oom:
205 	syslog(LOG_ERR,"out of memory");
206 	_exit(1);
207 }
208 
209 static void
do_config(int config_fd)210 do_config(int config_fd)
211 {
212 	int did_default=0;
213 	uostr_t a;
214 	a.data=0;
215 	if (!uostr_dup_cstr(&a,remoteip)) goto oom;
216 
217 	/* try 1.2.3.4 1.2.3. 1.2. 1. */
218 	while (a.len || !did_default) {
219 		uint32 dlen32;
220 		unsigned int datalen;
221 		if (!a.len)
222 			did_default=0;
223 		switch(cdb_seek(config_fd,
224 			(const unsigned char *) (a.len ? a.data : "default"),
225 			a.len ? a.len : 7,
226 			&dlen32)) {
227 		case -1: goto some_error;
228 		case 0:  break;
229 		default:
230 			datalen = dlen32;
231 			if (!uostr_needmore(&rules,datalen)) goto oom;
232 			if (cdb_bread(config_fd,
233 				(unsigned char *)(rules.data+rules.len),
234 				datalen) != 0) goto some_error;
235 			rules.len+=datalen;
236 			break;
237 		}
238 		if (!a.len)
239 			break;
240 		a.len--;
241 		while (a.len)  {
242 			if (a.data[a.len-1]=='.')
243 				break;
244 			a.len--;
245 		}
246 	}
247 	if (!rules.data)
248 		return;
249 	if (!uostr_add_mem(&rules,"",1)) goto  oom;
250 	opt_uid=rule_lookup("uid");
251 	opt_chroot=rule_lookup("root");
252 	opt_chdir=rule_lookup("dir");
253 	opt_read=rule_lookup("read");
254 	opt_write=rule_lookup("write");
255 	opt_create=rule_lookup("create");
256 	opt_sccs_clean=rule_lookup("sccs-clean"); if (opt_sccs_clean && !*opt_sccs_clean) opt_sccs_clean=0;
257 	opt_sccs_unget=rule_lookup("sccs-unget"); if (opt_sccs_unget && !*opt_sccs_unget) opt_sccs_unget=0;
258 	opt_sccs_get=rule_lookup("sccs-get"); if (opt_sccs_get && !*opt_sccs_get) opt_sccs_get=0;
259 	opt_sccs_delta=rule_lookup("sccs-delta"); if (opt_sccs_delta && !*opt_sccs_delta) opt_sccs_delta=0;
260 	opt_rcs_ci=rule_lookup("rcs-ci"); if (opt_rcs_ci && !*opt_rcs_ci) opt_rcs_ci=0;
261 	opt_rcs_co=rule_lookup("rcs-co"); if (opt_rcs_co && !*opt_rcs_co) opt_rcs_co=0;
262 	return;
263   some_error:
264 	syslog(LOG_ERR,"error reading %s: %s",opt_configfile,strerror(errno));
265 	_exit(1);
266   oom:
267 	syslog(LOG_ERR,"out of memory");
268 	_exit(1);
269 }
270 
271 static void
get_ids(char * str,uid_t * puid,gid_t * pgid)272 get_ids(char *str,uid_t *puid, gid_t *pgid)
273 {
274 	uid_t uid;
275 	unsigned long ul;
276 	char *dot;
277 	*pgid=(uid_t) -1; /* magic */
278 	*puid=(gid_t) -1; /* magic */
279 	dot=strchr(str,'.');
280 	if (!dot) dot=strchr(str,':');
281 	if (dot) {
282 		gid_t gid;
283 		*dot++=0;
284 		if (0>=str2ulong(dot,&ul,0)) {
285 			struct group * g;
286 			g=getgrnam(dot);
287 			if (!g) {
288 				syslog(LOG_ERR,"%s is not a valid group name",dot);
289 				_exit(1);
290 			}
291 			gid=g->gr_gid;
292 		} else {
293 			gid=(gid_t) ul;
294 			if ((unsigned long) gid != ul) {
295 				syslog(LOG_ERR,"%s is not a valid group number",dot);
296 				_exit(1);
297 			}
298 		}
299 		*pgid=gid;
300 	}
301 	if (!*str) /* .gid */
302 		return;
303 
304 	if (0>=str2ulong(str,&ul,0)) {
305 		struct passwd * pw;
306 		pw=getpwnam(str);
307 		if (!pw) {
308 			syslog(LOG_ERR,"%s is not a valid user name",str);
309 			_exit(1);
310 		}
311 		uid=pw->pw_uid;
312 	} else {
313 		uid=(uid_t) ul;
314 		if ((unsigned long) uid != ul) {
315 			syslog(LOG_ERR,"%s is not a valid user number",str);
316 			_exit(1);
317 		}
318 	}
319 	*puid=uid;
320 }
321 
322 static void
set_ids(uid_t uid,gid_t gid)323 set_ids(uid_t uid, gid_t gid)
324 {
325 	if (gid != (gid_t) -1 && -1==setgid(gid)) {
326 		syslog(LOG_ERR,"setgid(%lu): %s",(unsigned long) gid, strerror(errno));
327 		_exit(1);
328 	}
329 	if (uid!=(uid_t) -1 && -1==setuid(uid)) {
330 		syslog(LOG_ERR,"setuid(%lu): %s",(unsigned long) uid, strerror(errno));
331 		_exit(1);
332 	}
333 }
334 
335 void
do_nak(int peer,int ec,const char * et)336 do_nak(int peer, int ec, const char *et)
337 {
338 	utftpd_nak(peer,ec,et,ctrl);
339 }
340 
341 static char *
qualify(const char * prefix,const char * filename)342 qualify(const char *prefix, const char *filename)
343 {
344 	char *n;
345 	size_t l1,l2;
346 	l1=strlen(prefix);
347 	l2=strlen(filename);
348 	n=(char *) malloc(l1+l2+2);
349 	if (!n) return 0;
350 	memcpy(n,prefix,l1);
351 	if (prefix[l1-1]!='/')
352 		n[l1++]='/';
353 	memcpy(n+l1,filename,l2+1);
354 	return n;
355 }
356 
357 static const char *
qualify_filename(int peer,int opcode,const char * filename)358 qualify_filename(int peer, int opcode, const char *filename)
359 {
360 	const char *old_filename=filename;
361 	/* first qualify the filename, if it doesn't start with a / */
362 	/* this is actually very simple, although it looks somewhat complicated:
363 	 * prefix with opt_chdir (from configfile), and if that's still not enough:
364 	 * prefix with opt_global_chdir, if we didn't chroot since then
365 	 */
366 	if (*filename!='/' && opt_chdir) {
367 		filename=qualify(opt_chdir,filename);
368 		if (!filename) goto oom;
369 	}
370 	if (*filename!='/' && opt_global_chdir && !opt_chroot) {
371 		filename=qualify(opt_global_chdir,filename);
372 		if (!filename) goto oom;
373 	}
374 	if (*filename!='/') {
375 		if (!opt_configfile) {
376 			char **a;
377 			uostr_t s;
378 			/* traditional mode */
379 			if (opcode!=RRQ) {
380 				syslog(LOG_ERR,"denied write access to relative filename");
381 				do_nak(peer, EACCESS,"denied write access to relative filename");
382 				_exit(1);
383 			}
384 			/* walk through all directories trying to find that file */
385 			s.data=0;
386 			a=opt_old_style_ac;
387 			while (*a) {
388 				struct stat st;
389 				if (!uostr_dup_cstr(&s,*a)) goto oom;
390 				if (!uostr_add_mem(&s,"/",1)) goto oom;
391 				if (!uostr_add_cstr(&s,filename)) goto oom;
392 				if (!uostr_add_mem(&s,"",1)) goto oom;
393 				if (0==stat(s.data,&st)) {
394 					if (S_ISREG(st.st_mode) && (st.st_mode & S_IROTH) != 0) {
395 						filename=s.data;
396 						return filename;
397 					}
398 					break;
399 				}
400 				a++;
401 			}
402 			syslog(LOG_ERR,"denied read access to relative filename");
403 			do_nak(peer, EACCESS,"access denied");
404 			_exit(1);
405 		}
406 		filename=qualify("/",filename);
407 		if (!filename) goto oom;
408 	}
409 	if (opt_verbose && filename!=old_filename) syslog(LOG_INFO,"qualified filename %s to %s",old_filename,filename);
410 	return filename;
411   oom:
412   	syslog(LOG_ERR,"out of memory");
413 	do_nak(peer, EUNDEF,"out of memory");
414 	_exit(1);
415 }
416 
417 #define AC_READ 0
418 #define AC_WRITE 1
419 #define AC_CREATE 2
420 static struct utftpd_vc *
check_access(const char * dir,const char * filename,int mode)421 check_access(const char *dir,const char *filename, int mode)
422 {
423 	int ok=0;
424 	struct utftpd_vc *vc;
425 	/* prevent simple trickery */
426 	if (strstr(filename,"/../")) goto deny;
427 	if (!dir && !opt_configfile) {
428 		/* old style compatibility */
429 		char **a=opt_old_style_ac;
430 		/* /xx will allow /xx/y, but not /xxy */
431 		while (*a) {
432 			size_t l=strlen(*a);
433 			if (l==1 && **a=='/') break; /* "/" */
434 			if (0==strncmp(filename,*a,l) && filename[l]=='/') break;
435 			a++;
436 		}
437 		if (*a) {
438 			/* found it. now check access rights */
439 			struct stat st;
440 			if (stat(filename,&st)==-1) goto deny;
441 			if (!S_ISREG(st.st_mode)) goto deny;
442 			if (mode==AC_READ) {
443 				if (st.st_mode & S_IROTH) {
444 					utftpd_novc.checkout(TSG_READ,ctrl);
445 					return &utftpd_novc;
446 				}
447 			} else {
448 				if (st.st_mode & S_IWOTH) {
449 					utftpd_novc.checkout(TSG_WRITE,ctrl);
450 					return &utftpd_novc;
451 				}
452 			}
453 		}
454 		goto deny;
455 	}
456 	if (!dir || !*dir) /* means: no dir found in config file */
457 		goto deny;
458 	if (opt_verbose) syslog(LOG_INFO,"check access to %s against %s",filename,dir);
459 	/* go through the list of directories */
460 	while (dir) {
461 		char *dp=strchr(dir,':');
462 		size_t l;
463 		if (dp) {
464 			*dp=0;
465 			l=dp-dir;
466 		} else
467 			l=strlen(dir);
468 		/* cut of trailing / */
469 		while (l && dir[l-1]=='/') l--;
470 		if (0==l) {
471 			/* uah, access to root directory allowed. Hope admin chroot()ed */
472 			ok=1;
473 		} else {
474 			if (0==memcmp(filename,dir,l)) { /* "/xxx/Z" | "/xxxB/Z", "/xxxA" | "/xxx", 4|5 */
475 				if (filename[l]=='/' || filename[l]=='\0')
476 					ok=1;
477 			}
478 			if (!ok) ok=dir_wildmat(filename,dir);
479 		}
480 		if (ok) break;
481 		if (dp) dir=dp+1;
482 		else dir=0;
483 	}
484 	if (ok) {
485 		struct stat st;
486 		int ret;
487 		vc=find_vc(filename, ctrl);
488 		if (mode==AC_READ)  {
489 			vc->checkout(TSG_READ,ctrl);
490 			return vc;
491 		}
492 		ret=stat(filename,&st);
493 		if (mode==AC_CREATE) {
494 			if (ret==-1 && vc==&utftpd_novc) {
495 				vc->checkout(TSG_CREATE,ctrl);
496 				/* yup, that's create */
497 				return vc;
498 			}
499 			return 0; /* that would be a write */
500 		}
501 		if (ret!=-1 && vc!=&utftpd_novc) {
502 			/* writeable file? can't overwrite it, maybe some other process does
503 			 * also an upload now.
504 			 */
505 			if (st.st_mode & (S_IWOTH |S_IWGRP|S_IWUSR)) {
506 				syslog(LOG_ERR,"writeable %s exists -> DENY",filename);
507 				goto deny;
508 			}
509 			unlink(filename);
510 		}
511 		if (ret==-1 && vc==&utftpd_novc) {
512 			/* this would be an create */
513 			if (mode==AC_WRITE) return 0;
514 		}
515 
516 		vc->checkout(TSG_WRITE,ctrl);
517 		need_commit=filename;
518 		return vc;
519 	}
520  /* FALLTHROUGH */
521   deny:
522     return 0;
523 }
524 
525 static void
oack_append(int peer,size_t * oack_length,const char * n,const char * v)526 oack_append(int peer, size_t *oack_length, const char *n, const char *v)
527 {
528 	size_t l1,l2;
529 	l1=strlen(n)+1;
530 	l2=strlen(v)+1;
531 	if (*oack_length+l1+l2 >ctrl->segsize) {
532 		syslog(LOG_ERR,"OACK too large for new %s %s",n,v);
533 		utftpd_nak(peer,EUNDEF,"OACK too large",ctrl);
534 		_exit(1);
535 	}
536 	memcpy(ctrl->sendbuf.buf+TFTP_OFFSET+*oack_length,n,l1);
537 	memcpy(ctrl->sendbuf.buf+TFTP_OFFSET+*oack_length+l1,v,l2);
538 	*oack_length+=l1+l2;
539 }
540 
541 static void
do_init(int peer)542 do_init(int peer)
543 {
544 	char *filename;
545 	char *convert;
546 	char *p;
547 	struct tftphdr *hdr;
548 	size_t oack_length=0;
549 	size_t new_blksize=512;
550 	const char *realfilename;
551 	short opcode;
552 	int got_options=0;
553 	hdr = ctrl->recvbuf.hdr;
554 	opcode = ntohs(hdr->th_opcode);
555 	if (opcode != RRQ && opcode != WRQ) {
556 		syslog(LOG_ERR,"got opcode %d in init",(int) opcode);
557 		_exit(1);
558 	}
559 	filename=((char *)&hdr->th_opcode)+2; /* slowlartis doesn't have th_u union */
560 	/* proceed to end of filename */
561 	p=filename;
562 	while (p!=ctrl->recvbuf.buf+got && *p!=0) p++;
563 	if (p==ctrl->recvbuf.buf+got) {
564 		syslog(LOG_ERR,"unterminated filename in init packet");
565 		_exit(1);
566 	}
567 
568 	convert=p+1;
569 	/* proceed to end of conversion */
570 	p=convert;
571 	while (p!=ctrl->recvbuf.buf+got && *p!=0) p++;
572 	if (p==ctrl->recvbuf.buf+got) {
573 		syslog(LOG_ERR,"unterminated conversion in init packet");
574 		_exit(1);
575 	}
576 	if (opcode==RRQ) {
577 		syslog(LOG_INFO,"peer requests %s, conversion %s", filename, convert);
578 	} else {
579 		syslog(LOG_INFO,"peer sends %s, conversion %s", filename, convert);
580 	}
581 
582 	/* now there may be options */
583 	p++;
584 	while (p!=ctrl->recvbuf.buf+got) {
585 		char *opt;
586 		char *val;
587 		opt=p;
588 		/* proceed to end of option name */
589 		while (p!=ctrl->recvbuf.buf+got && *p!=0) p++;
590 		if (p==ctrl->recvbuf.buf+got) {
591 			if (got_options) {
592 				syslog(LOG_ERR,"unterminated option name in init packet");
593 				utftpd_nak(peer,EUNDEF,"unterminated option name in init packet",ctrl);
594 				_exit(1);
595 			} else {
596 				syslog(LOG_INFO,"ignored unterminated option name in init "
597 					"packet. bad client implementation?");
598 				break;
599 			}
600 		}
601 		got_options++;
602 		val=p+1;
603 		p=val;
604 		/* proceed to end of option name */
605 		while (p!=ctrl->recvbuf.buf+got && *p!=0) p++;
606 		if (p==ctrl->recvbuf.buf+got) {
607 			syslog(LOG_ERR,"unterminated option value in init packet");
608 			utftpd_nak(peer,EUNDEF,"unterminated option value in init packet",
609 				ctrl);
610 			_exit(1);
611 		}
612 		if (opt_verbose)
613 			syslog(LOG_INFO,"peer requests option %s, value %s", opt, val);
614 		p++;
615 		if (0==strcasecmp(opt,"blksize")) {
616 			unsigned long x;
617 			/* the actual resizing of the buffers is done later, we know parse a set of strings
618 			 * inside those buffers.
619 			 * ignore illegal numbers or blksizes below 512 (which can't work).
620 			 */
621 			if (-1!=str2ulong(val,&x,0) && x >= 512) {
622 				if (x>=65464) {
623 					x=65464;
624 					if (opt_verbose) syslog(LOG_INFO,"changed that to %lu bytes", x);
625 				}
626 				new_blksize=x;
627 			}
628 		} else if (0==strcasecmp(opt,"timeout")) {
629 			unsigned long x;
630 			/* must be between 1 and 255 inclusivly */
631 			if (-1!=str2ulong(val,&x,0) && x>=1 && x<=256) {
632 				ctrl->timeout=x;
633 				oack_append(peer,&oack_length, opt,val);
634 			}
635 		} else if (0==strcasecmp(opt,"revision")) {
636 			size_t x=strlen(val)+1;
637 			/* we will NACK that later, if that revision doesn't exist */
638 			ctrl->revision=(char *) malloc(x);
639 			if (!ctrl->revision) goto oom;
640 			memcpy(ctrl->revision,val,x);
641 			oack_append(peer,&oack_length, opt,val);
642 		}
643 	}
644 	filename=strdup(filename);
645 	convert=strdup(convert);
646 	if (!filename || !convert) goto oom;
647 
648 	/* stop using "hdr" now: it will move. */
649 
650 	if (new_blksize != 512) {
651 		struct utftpd_ctrl *n;
652 		char buf[STR_ULONG];
653 		n=utftpd_setup_ctrl(ctrl, new_blksize);
654 		if (!n) goto oom;
655 		ctrl=n;
656 		str_ulong(buf,new_blksize);
657 		/* note: this also checks wether the buffer now is to small to hold the old OACK values */
658 		oack_append(peer,&oack_length,"blksize",buf);
659 	}
660 	if (0==strcasecmp(convert,"netascii")) {
661 		ctrl->netascii=1;
662 	} else if (0==strcasecmp(convert,"octet")) {
663 		ctrl->netascii=0;
664 	} else {
665 		syslog(LOG_ERR,"unknown conversion -> NAK");
666 		utftpd_nak(peer,EUNDEF,"unknown conversion",ctrl);
667 		_exit(1);
668 	}
669 
670 	realfilename=qualify_filename(peer, opcode, filename);
671 	ctrl->filename=strdup(realfilename);
672 	if (!ctrl->filename) goto oom;
673 	ctrl->origfilename=filename;
674 	if (opcode==RRQ) {
675 		int ret;
676 		ctrl->vc=check_access(opt_read,realfilename,AC_READ);
677 		if (!ctrl->vc) {
678 			syslog(LOG_NOTICE,"denied read access to %s", filename);
679 			do_nak(peer, EACCESS,"access denied");
680 			_exit(1);
681 		}
682 		ctrl->first_packet_length=oack_length;
683 		ctrl->sendbuf.hdr->th_opcode=htons(OACK);
684 		ret=utftpd_send(ctrl);
685 		if (opt_timing) {
686 			unsigned long used=stop();
687 			char buf[STR_ULONG];
688 			unsigned long x,y;
689 			x=str_ulong(buf,used/1000000);
690 			buf[x++]='.';
691 			y=used%1000000;
692 			if (y>99999) str_ulong(buf+x,y);
693 			else if (y>9999) {buf[x++]='0'; str_ulong(buf+x,y);}
694 			else if (y>999) {buf[x++]='0'; buf[x++]='0'; str_ulong(buf+x,y);}
695 			else if (y>99) {buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; str_ulong(buf+x,y);}
696 			else if (y>9) {buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; str_ulong(buf+x,y);}
697 			else {buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; str_ulong(buf+x,y);}
698 
699 			syslog(LOG_INFO,"transferred %lu bytes in %s seconds", ctrl->bytes,buf);
700 		}
701 		_exit (0!=ret);
702 	} else {
703 		int retcode;
704 
705 		/* if we are root we never write. */
706 		if (getuid()==0) {
707 			syslog(LOG_ERR,"%s: will not write as root",realfilename);
708 			do_nak(peer, EACCESS,"access denied");
709 			_exit(1);
710 		}
711 
712 		ctrl->vc=check_access(opt_write,realfilename,AC_WRITE);
713 		if (!ctrl->vc) {
714 			ctrl->vc=check_access(opt_create,realfilename,AC_CREATE);
715 			if (!ctrl->vc) {
716 				syslog(LOG_NOTICE,"denied write access to %s", filename);
717 				do_nak(peer, EACCESS,"access denied");
718 				_exit(1);
719 			}
720 		}
721 
722 		/* we have to send either an OACK or an ACK. We prepare that here, but sending (and possible resending)
723 		 * is done in the receiving code.
724 		 */
725 		ctrl->first_packet_length=oack_length;
726 		if (oack_length)
727 			ctrl->sendbuf.hdr->th_opcode=htons(OACK);
728 		else
729 			ctrl->sendbuf.hdr->th_opcode=htons(ACK);
730 
731 
732 		retcode=utftpd_recv(ctrl);
733 		if (retcode==-1) {
734 			if (need_commit && ctrl->vc->unget)
735 				ctrl->vc->unget(ctrl);
736 			unlink(ctrl->filename);
737 			_exit(1);
738 		}
739 		/* we _do_ have the whole file now, but didn't send the last ACK.
740 		 * we delay that until we did the version control checkin
741 		 */
742 		if (need_commit) {
743 			ctrl->vc->commit("got from remote",ctrl);
744 		}
745 
746 		syslog(LOG_INFO,"got %s",realfilename);
747 		if (send(peer, ctrl->sendbuf.buf, TFTP_OFFSET, 0) != (ssize_t) TFTP_OFFSET) {
748 			syslog(LOG_ERR,"send() for final ACK failed for %s: %s",remoteip,strerror(errno));
749 			/* minor problem, so we return 0 */
750 		}
751 		if (opt_timing) {
752 			unsigned long used=stop();
753 			char buf[STR_ULONG];
754 			unsigned long x,y;
755 			x=str_ulong(buf,used/1000000);
756 			buf[x++]='.';
757 			y=used%1000000;
758 			if (y>99999) str_ulong(buf+x,y);
759 			else if (y>9999) {buf[x++]='0'; str_ulong(buf+x,y);}
760 			else if (y>999) {buf[x++]='0'; buf[x++]='0'; str_ulong(buf+x,y);}
761 			else if (y>99) {buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; str_ulong(buf+x,y);}
762 			else if (y>9) {buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; str_ulong(buf+x,y);}
763 			else {buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; buf[x++]='0'; str_ulong(buf+x,y);}
764 
765 			syslog(LOG_INFO,"received %lu bytes in %s seconds", ctrl->bytes,buf);
766 		}
767 		_exit(0);
768 	}
769   oom:
770 	syslog(LOG_ERR,"out of memory");
771 	utftpd_nak(peer,EUNDEF,"out of memory",ctrl);
772 	_exit(1);
773 }
774 
775 static void
chld_handler(int x)776 chld_handler(int x)
777 {
778 	(void) x;
779 	signal(SIGCHLD,&chld_handler);
780 }
781 
782 int
main(int argc,char ** argv)783 main(int argc, char **argv)
784 {
785 	int config_fd=-1;
786 	struct	sockaddr_in from;
787 	struct	sockaddr_in s_in;
788 	socklen_t	fromlen;
789 	pid_t pid;
790 	uid_t guid,uid;
791 	gid_t ggid,gid;
792 	size_t l;
793 	const char *s;
794 	int initial_packet_errno;
795 	int peer;
796 	struct in_addr ina;
797 	unsigned short port;
798 	int mastersocket=0;
799 
800 	nullfd=open("/dev/null",O_RDWR);
801 	if (nullfd==-1) {
802 		syslog(LOG_ERR,"cannot open /dev/null: %s",strerror(errno));
803 		_exit(1);
804 	}
805 #ifdef HAVE_LIBEFENCE
806 	/* hack around efence */
807 	{int fd2;void *waste;
808 	 if (-1==(fd2=dup(2))) _exit(1);
809 	 if (-1==(dup2(nullfd,2))) _exit(1);
810 	 waste=malloc(1);
811 	 if (-1==(dup2(fd2,2))) _exit(1);
812 	 close(fd2);
813 	}
814 #endif
815 
816 	argv0=strrchr(argv[0],'/');
817 	if (!argv0++) argv0=argv[0];
818 	ctrl=utftpd_setup_ctrl(0,512);
819 	if (!ctrl)  goto oom;
820 
821 
822 	/* at least read input even in case we crash / exit very early due to a
823 	 * configuration or resource problem. We have to to that
824 	 */
825 	fromlen = sizeof (from);
826 	got = recvfrom(mastersocket, ctrl->recvbuf.buf, ctrl->segsize+TFTP_OFFSET, 0,
827 	    (struct sockaddr *)&from, &fromlen);
828 	initial_packet_errno=errno;
829 
830 	uogetopt("utftpd","GNU " PACKAGE,VERSION,&argc,argv,uogetopt_out,0,myopts,
831 		"Report bugs to uwe-utftpd@bulkmail.ohse.de");
832 	/* in standalone mode it's okay to lose here, nobody gave us a socket on fd 0 */
833 	if (opt_standalone
834 #ifdef ENOTSOCK /* BEOS doesn't know this */
835 		&& got==-1 && errno==ENOTSOCK
836 #endif
837 		) {
838 		got=0;
839 		initial_packet_errno=0;
840 	}
841 
842 	openlog("utftpd", LOG_PID|LOG_NDELAY, LOG_DAEMON);
843 	/* open configuration file now */
844 	if (opt_configfile) {
845 		config_fd=open(opt_configfile, O_RDONLY);
846 		if (config_fd==-1) {
847 			syslog(LOG_ERR,"cannot open %s: %s", opt_configfile, strerror(errno));
848 			_exit(1);
849 		}
850 	} else {
851 		opt_old_style_ac=argv;
852 	}
853 
854 	/* parse host:port before the chroot happens. No /etc/services and so on afterwards */
855 	if (opt_standalone) {
856 		int r;
857 		port=htons(69);
858 		ina.s_addr=INADDR_ANY;
859 		r=parse_ip_port(opt_standalone,&ina,&port,"udp");
860 		if (r==-1) {
861 			syslog(LOG_ERR,"cannot understand %s", opt_standalone);
862 			_exit(1);
863 		}
864 		mastersocket=socket(AF_INET,SOCK_DGRAM, 0);
865 		if (mastersocket < 0) { syslog (LOG_ERR, "socket: %s", strerror (errno)); _exit (1); }
866 		s_in.sin_addr.s_addr=ina.s_addr;
867 		s_in.sin_port=port;
868 		s_in.sin_family=AF_INET;
869 		if (bind (mastersocket, (struct sockaddr *) &s_in, sizeof (s_in)) < 0) {
870 			syslog (LOG_ERR, "bind: %s", strerror (errno)); _exit (1);
871 		}
872 	}
873 
874 	/* now get rid of rights ... */
875 	if (opt_global_uid) get_ids(opt_global_uid,&guid,&ggid);
876 #ifdef HAVE_CHROOT
877 	if (opt_global_chroot) {
878 		if (-1==chdir(opt_global_chroot)) { syslog(LOG_ERR,"chdir %s: %s",opt_global_chroot,strerror(errno)); _exit(1); }
879 		if (-1==chroot(opt_global_chroot)) { syslog(LOG_ERR,"chroot %s: %s",opt_global_chroot,strerror(errno)); _exit(1); }
880 		if (opt_verbose) syslog(LOG_INFO,"did chdir/root to %s",opt_global_chroot);
881 	}
882 #endif
883 	if (opt_global_uid) set_ids(guid,ggid);
884 	if (opt_global_chdir) {
885 		if (-1==chdir(opt_global_chdir)) { syslog(LOG_ERR,"chdir %s: %s",opt_global_chdir,strerror(errno)); _exit(1); }
886 		if (opt_verbose) syslog(LOG_INFO,"did chdir to %s",opt_global_chdir);
887 	}
888 
889 
890 #ifndef __BEOS__
891 	/* why did i do this? */
892 	nonblock(0,1); /* it's a UDP socket - this should not be needed! */
893 #endif
894 
895 	if (got < 0) {
896 #ifdef ENOTSOCK /* BEOS doesn't know this */
897 		 /* try to be nice to the user */
898 		if (got==-1 && errno==ENOTSOCK) {
899 			const char *m1,*m2;
900 			m1=": must be started by inetd.\n";
901 			m2="  Give --help option for usage information.\n";
902 			write(2,argv0,strlen(argv0));
903 			write(2,m1,strlen(m1));
904 			write(2,m2,strlen(m2));
905 			_exit(2);
906 		}
907 
908 #endif
909 		syslog(LOG_ERR, "recvfrom(initial packet): %s",
910 			strerror(initial_packet_errno));
911 		exit(1);
912 	}
913 
914 	/* fork/exit for inetd nowait mode */
915 	if (!opt_standalone) {
916 		pid = fork();
917 		if (pid==-1) {
918 			syslog(LOG_ERR,"can't fork: %s", strerror(errno));
919 			_exit(1);
920 		}
921 	}
922 	if (opt_standalone || pid!=0) {
923 		int childs;
924 		if (opt_standalone) childs=0;
925 		else childs=1;
926 		/* mother */
927 		if (!opt_keeprun && !opt_standalone)
928 			_exit(0);
929 		signal(SIGCHLD,&chld_handler);
930 		while (1) {
931 			fd_set set;
932 			int r;
933 			FD_ZERO(&set);
934 			FD_SET(mastersocket,&set);
935 			r=select(mastersocket+1,&set,0,0,0);
936 			if (r==-1 && errno!=EINTR) {
937 				syslog(LOG_ERR,"select failed: %s", strerror(errno));
938 				_exit(1);
939 			}
940 			if (FD_ISSET(mastersocket,&set)) {
941 				fromlen = sizeof (from);
942 				got = recvfrom(mastersocket, ctrl->recvbuf.buf, ctrl->segsize+TFTP_OFFSET, 0,
943 					(struct sockaddr *)&from, &fromlen);
944 				if (got==-1) {
945 					syslog(LOG_ERR, "recvfrom(initial packet on new connection): %s", strerror(errno));
946 				} else {
947 					pid=fork();
948 					if (pid==0)
949 						break; /* child */
950 					if (pid!=-1)
951 						childs++;
952 				}
953 			}
954 			while (r==-1) {
955 				pid_t pi=waitpid(WAIT_ANY,0,WNOHANG);
956 				if (pi==0 || pi==-1)
957 					break;
958 				childs--;
959 			}
960 			if (!childs && opt_keeprun) _exit(0);
961 		}
962 	}
963 	/* child */
964 	if (opt_timing) start();
965 	/* make a copy of the remote ip address, as string */
966 	s=inet_ntoa(from.sin_addr);
967 	l=strlen(s)+1;
968 	remoteip=(char *) malloc(l);
969 	if (!remoteip) goto oom;
970 	memcpy(remoteip,s,l);
971 
972 	openlog("utftpd", LOG_PID|LOG_NDELAY, LOG_DAEMON);
973 	syslog(LOG_INFO,"connect from %s",remoteip);
974 
975 	if (config_fd!=-1) {
976 		do_config(config_fd);
977 		close(config_fd);
978 	}
979 
980 	from.sin_family = AF_INET;
981 	alarm(0);
982 	if (-1==dup2(nullfd,0)) { syslog(LOG_ERR,"cannot dup2 /dev/null -> 0: %s",strerror(errno)); _exit(1); }
983 	if (-1==dup2(nullfd,1)) { syslog(LOG_ERR,"cannot dup2 /dev/null -> 1: %s",strerror(errno)); _exit(1); }
984 
985 	peer = socket(AF_INET, SOCK_DGRAM, 0);
986 	if (peer < 0) { syslog(LOG_ERR, "socket: %s",strerror(errno)); _exit(1); }
987 	ctrl->remotefd=peer;
988 
989 	/* we need to bind to the same port we received this on ... */
990 	s_in.sin_addr.s_addr=INADDR_ANY;
991 	s_in.sin_port=0;
992 	s_in.sin_family=AF_INET;
993 	if (bind(peer, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) { syslog(LOG_ERR, "bind: %s",strerror(errno)); _exit(1); }
994 
995 	/* now get rid of rights ... */
996 	if (opt_uid) get_ids(opt_uid,&uid,&gid);
997 	if (opt_chroot) {
998 #ifdef HAVE_CHROOT
999 		const char *e;
1000 		if (-1==chdir(opt_chroot)) { e=strerror(errno); syslog(LOG_ERR,"chdir %s: %s",opt_chroot,e);_exit(1); }
1001 		if (-1==chroot(opt_chroot)) { e=strerror(errno); syslog(LOG_ERR,"chroot %s: %s",opt_chroot,e); _exit(1); }
1002 		if (opt_verbose) syslog(LOG_INFO,"did chdir/root to %s",opt_chroot);
1003 #else
1004 		syslog(LOG_ERR,"chroot is not available on this platform");
1005 		/* XXX should send a nak, but socket is still not connected */
1006 		_exit(1);
1007 #endif
1008 	}
1009 	if (opt_uid) set_ids(uid,gid);
1010 	if (opt_chdir) {
1011 		const char *e;
1012 		if (-1==chdir(opt_chdir)) { e=strerror(errno); syslog(LOG_ERR,"chdir %s: %s",opt_chdir,e); _exit(1); }
1013 		if (opt_verbose) syslog(LOG_INFO,"did chdir to %s",opt_chdir);
1014 	}
1015 	if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { syslog(LOG_ERR, "connect: %s",strerror(errno)); exit(1); }
1016 	setsid();
1017 
1018 	do_init(peer);
1019 	_exit(1);
1020 oom:
1021 	syslog(LOG_ERR,"out of memory");
1022 	_exit(1);
1023 }
1024 
1025 
1026 static struct utftpd_ctrl *
utftpd_setup_ctrl(struct utftpd_ctrl * old,size_t segsize)1027 utftpd_setup_ctrl(struct utftpd_ctrl *old, size_t segsize)
1028 {
1029 	if (!old) {
1030 		old=(struct utftpd_ctrl *)malloc(sizeof(struct utftpd_ctrl));
1031 		if (!old) return 0;
1032 		memset(old,0,sizeof(*old));
1033 		old->segsize=512; /* default */
1034 		old->netascii=0;
1035 		old->timeout=5;
1036 		old->retries=5;
1037 		old->first_packet_length=0; /* tftp_open() adjusts this */
1038 		old->filefd=-1;
1039 		old->sendbuf.buf=(char *) malloc(old->segsize+TFTP_OFFSET);
1040 		old->recvbuf.buf=(char *) malloc(old->segsize+TFTP_OFFSET);
1041 		if (!old->sendbuf.buf || !old->recvbuf.buf) {
1042 			free(old->sendbuf.buf);
1043 			free(old->recvbuf.buf);
1044 			free(old);
1045 			return 0;
1046 		}
1047 	}
1048 	if (segsize!=0 && old->segsize!=segsize) {
1049 		void *v,*u;
1050 		u=realloc(old->sendbuf.buf,segsize+TFTP_OFFSET);
1051 		v=realloc(old->recvbuf.buf,segsize+TFTP_OFFSET);
1052 		if (!u || !v) {
1053 			if (u) free(u); else free(old->sendbuf.buf);
1054 			if (v) free(v); else free(old->recvbuf.buf);
1055 			free(old);
1056 			return 0;
1057 		}
1058 		old->sendbuf.buf=(char *) u;
1059 		old->recvbuf.buf=(char *) v;
1060 		old->segsize=segsize;
1061 	}
1062 	return old;
1063 }
1064 
1065