1 /*
2 ** NOTICE:
3 **
4 **	Portions of this file contain code based on ideas derived
5 **	from the source code of "sendmail" written by Eric Allman
6 **	at the University of California, Berkeley.
7 */
8 #include	"qpage.h"
9 
10 #ifdef TCP_WRAPPERS
11 #include	"tcpd.h"
12 #endif
13 
14 
15 /*
16 ** Level 1 commands
17 */
18 #define		CMDERROR	0	/* bad command */
19 #define		CMDPAGE 	1	/* specify a pagerid */
20 #define		CMDMESS		2	/* specify the message text */
21 #define		CMDRESE		3	/* reset all settings */
22 #define		CMDSEND		4	/* send the page */
23 #define		CMDQUIT		5	/* disconnect */
24 #define		CMDHELP		6	/* send help information */
25 
26 /*
27 ** Level 2 commands
28 */
29 #define		CMDDATA		7	/* prompt for message text */
30 #define		CMDLOGI		8	/* authenticate remote user */
31 #define		CMDLEVE		9	/* specify service level */
32 #define		CMDALER		10	/* alert (not implemented) */
33 #define		CMDCOVE		11	/* specify alternate coverage */
34 #define		CMDHOLD		12	/* hold page until some future time */
35 #define		CMDCALL		13	/* specify callerid */
36 #define		CMDSUBJ		14	/* subject (not implemented) */
37 
38 /*
39 ** Level 3 commands (not implemented)
40 */
41 #define		CMD2WAY		15	/* begin 2-way paging */
42 #define		CMDPING		16	/* ping a pager */
43 #define		CMDEXPT		17	/* change expiration time */
44 #define		CMDNOQU		18	/* don't queue message */
45 #define		CMDACKR		19	/* read acknowledgment */
46 #define		CMDRTYP		20	/* reply type */
47 #define		CMDMCRE		21	/* multiple choice responce codes */
48 #define		CMDMSTA		22	/* message status */
49 #define		CMDKTAG		23	/* kill message */
50 
51 /*
52 ** Other commands which are not part of the SNPP protocol
53 **
54 ** Note: These commands are not documented, not supported, and may very
55 **       well disappear in a future release.  They do not produce results
56 **       consistant with RFC-1861.  Use at your own risk.
57 */
58 #define		CMDXDEB		24	/* activate debug mode */
59 #define		CMDXCON		25	/* print configuration file */
60 #define		CMDXQUE		26	/* show the page queue contents */
61 #define		CMDXWHO		27	/* show the known pagers/groups */
62 
63 
64 /*
65 ** global variables
66 */
67 #ifndef lint
68 static char	sccsid[] = "@(#)srvrsnpp.c  1.46  10/24/98  tomiii@qpage.org";
69 #endif
70 
71 #ifdef TCP_WRAPPERS
72 int allow_severity = LOG_INFO;
73 int deny_severity = LOG_WARNING;
74 #endif
75 
76 static struct cmd {
77 	char		*cmdname;
78 	int		cmdcode;
79 } CmdTab[] = {
80 	{"PAGEr",	CMDPAGE},
81 	{"MESSage",	CMDMESS},
82 	{"RESEt",	CMDRESE},
83 	{"SEND",	CMDSEND},
84 	{"QUIT",	CMDQUIT},
85 	{"HELP",	CMDHELP},
86 	{"DATA",	CMDDATA},
87 	{"LOGIn",	CMDLOGI},
88 	{"LEVEl",	CMDLEVE},
89 	{"ALERt",	CMDALER},
90 	{"COVErage",	CMDCOVE},
91 	{"HOLDuntil",	CMDHOLD},
92 	{"CALLerid",	CMDCALL},
93 	{"SUBJect",	CMDSUBJ},
94 	{"2WAY",	CMD2WAY},
95 	{"PING",	CMDPING},
96 	{"EXPTag",	CMDEXPT},
97 	{"NOQUEUEing",	CMDNOQU},
98 	{"ACKRead",	CMDACKR},
99 	{"RTYPe",	CMDRTYP},
100 	{"MCREsponse",	CMDMCRE},
101 	{"MSTAtus",	CMDMSTA},
102 	{"KTAG",	CMDKTAG},
103 	{"XDEBug",	CMDXDEB},
104 	{"XCONfig",	CMDXCON},
105 	{"XQUEue",	CMDXQUE},
106 	{"XWHO",	CMDXWHO},
107 	{NULL,		CMDERROR},
108 };
109 
110 
111 /*
112 ** message()
113 **
114 ** This function sends a string followed by CRLF to the standard output.
115 **
116 **	Input:
117 **		text - the string to print
118 **
119 **	Returns:
120 **		nothing
121 */
122 void
message(char * text)123 message(char *text)
124 {
125 	if (Debug) {
126 		fprintf(stderr, ">>> %s\r\n", text);
127 		(void)fflush(stderr);
128 	}
129 
130 	printf("%s\r\n", text);
131 	(void)fflush(stdout);
132 }
133 
134 
135 /*
136 ** clear_page()
137 **
138 ** This function frees the memory allocated to a page during the
139 ** SNPP session.  Memory allocated before the session started (such
140 ** as the socket's file descriptor) may or may not be freed,
141 ** depending on the save parameter.
142 **
143 **	Input:
144 **		p - a pointer to the PAGE structure
145 **		save - whether to save certain fields
146 **
147 **	Returns:
148 **		nothing
149 */
150 void
clear_page(PAGE * p,int save)151 clear_page(PAGE *p, int save)
152 {
153 	FILE		*peer;
154 	rcpt_t		*tmp;
155 	char		*ident;
156 	char		*msgid;
157 	char		*hostname;
158 
159 
160 	/*
161 	** free all the recipients
162 	*/
163 	while (p->rcpts) {
164 		tmp = p->rcpts;
165 		p->rcpts = p->rcpts->next;
166 
167 		my_free(tmp->pager);
168 		my_free(tmp->coverage);
169 		free(tmp);
170 	}
171 
172 	if (save) {
173 		/*
174 		** save a few things
175 		*/
176 		peer = p->peer;
177 		ident = p->ident;
178 		msgid = p->messageid;
179 		hostname = p->hostname;
180 	}
181 
182 	/*
183 	** free the page
184 	*/
185 	my_free(p->filename);
186 	my_free(p->message);
187 	my_free(p->auth);
188 	my_free(p->from);
189 	my_free(p->status);
190 
191 	if (save) {
192 		(void)memset((char *)p, 0, sizeof(*p));
193 
194 		/*
195 		** restore the saved fields
196 		*/
197 		p->peer = peer;
198 		p->ident = ident;
199 		p->messageid = msgid;
200 		p->hostname = hostname;
201 	}
202 	else
203 		free(p);
204 }
205 
206 
207 /*
208 ** newmsgid()
209 **
210 ** This function generates a unique message id.  Note that the client
211 ** is not limited to one page per connection, so this message id will
212 ** have to be updated later on after the SEND command is received.
213 **
214 **	Input:
215 **		buf - where to store the new id (must hold >7 characters)
216 **
217 **	Returns:
218 **		nothing
219 **
220 **	Note:
221 **		This assumes we'll never have more than 1000 incoming
222 **		SNPP connections per minute.  Probably a fair assumption,
223 **		but if this ever happens we'll end up with duplicate
224 **		message IDs.
225 */
226 void
newmsgid(char * buf)227 newmsgid(char *buf)
228 {
229 	static char		idchars[] =
230 					"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
231 					"abcdefghijklmnopqrstuvwxyz"
232 					"0123456789";
233 
234 	static int		count;
235 	struct tm		*tm;
236 	time_t			now;
237 
238 
239 	now = time(NULL);
240 
241 	/*
242 	** use gmtime() so time never goes backwards
243 	*/
244 	tm = gmtime(&now);
245 
246 	buf[0] = idchars[tm->tm_mon];
247 	buf[1] = idchars[tm->tm_mday-1];
248 	buf[2] = idchars[tm->tm_hour];
249 	buf[3] = idchars[tm->tm_min];
250 
251 	/*
252 	** make it unique
253 	*/
254 	(void)sprintf(&buf[4], "%03d", count++);
255 	count %= 1000;
256 }
257 
258 
259 /*
260 ** dohelp()
261 **
262 ** This function prints the list of SNPP commands supported by this program.
263 */
264 void
dohelp(void)265 dohelp(void)
266 {
267 	message("214 ");
268 	message("214 Level 1 commands accepted:");
269 	message("214 ");
270 	message("214     PAGEr <pager ID>");
271 	message("214     MESSage <alpha or numeric message>");
272 	message("214     RESEt");
273 	message("214     SEND");
274 	message("214     QUIT");
275 	message("214     HELP");
276 	message("214 ");
277 	message("214 Level 2 commands accepted:");
278 	message("214 ");
279 	message("214     DATA");
280 	message("214     LOGIn <loginid> [password]");
281 	message("214     LEVEl <ServiceLevel>");
282 	message("214     COVErage <AlternateArea>");
283 	message("214     HOLDuntil <YYMMDDHHMMSS> [+/-GMTdifference]");
284 	message("214     CALLerid <CallerID>");
285 	message("214 ");
286 	message("214 Level 3 commands accepted:");
287 	message("214 ");
288 	message("214     none");
289 	message("214 ");
290 	message("250 OK");
291 }
292 
293 
294 /*
295 ** dump_pagers()
296 **
297 ** This function prints the list of pagers/groups known by this server.
298 ** Only those with text descriptions are printed.
299 */
300 void
dump_pagers(void)301 dump_pagers(void)
302 {
303 	pager_t		*pager;
304 	pgroup_t	*group;
305 	char		buff[1024];
306 
307 
308 	for (pager=Pagers; pager; pager=pager->next) {
309 		if (pager->text == NULL)
310 			continue;
311 
312 		(void)sprintf(buff, "214 %s %s", pager->name, pager->text);
313 		message(buff);
314 	}
315 
316 	for (group=Groups; group; group=group->next) {
317 		if (group->text == NULL)
318 			continue;
319 
320 		(void)sprintf(buff, "214 %s %s", group->name, group->text);
321 		message(buff);
322 	}
323 }
324 
325 
326 /*
327 ** authorize()
328 **
329 ** This function verifies a userid/password supplied as arguments
330 ** to the SNPP LOGIN command.
331 **
332 **	Input:
333 **		str - the userid and password, separated by whitespace
334 **
335 **	Returns:
336 **		the userid if verification succeeds, NULL if it doesn't
337 */
338 char *
authorize(char * str)339 authorize(char *str)
340 {
341 	/*
342 	** add site-specific code here for authorization
343 	*/
344 
345 	return(strdup(str));
346 }
347 
348 
349 /*
350 ** find_recipients()
351 **
352 ** This function adds a pager to the page's recipient list.  If the pager
353 ** specifies a page group, the group is expanded and each member is added
354 ** to the recipient list.
355 **
356 **	Input:
357 **		p - the page structure
358 **		str - the pager to be added
359 **		service - the default paging service
360 **		holduntil - the default hold time
361 **		level - the default service level
362 **
363 **	Returns:
364 **		an integer status code (0=success, 1=no one on duty, -1=error)
365 */
366 static int
find_recipients(PAGE * p,char * str,service_t * service,time_t holduntil,int level)367 find_recipients(PAGE *p, char *str, service_t *service, time_t holduntil, int level)
368 {
369 	pgroup_t	*group;
370 	member_t	*member;
371 	rcpt_t		*tmp;
372 	char		*ptr;
373 	int		flags;
374 
375 
376 	tmp = NULL;
377 	flags = 0;
378 
379 	/*
380 	** interpret the service level
381 	*/
382 	switch (level) {
383 		case LEVEL_SENDMAIL:
384 			flags |= F_SENDMAIL;
385 			break;
386 	}
387 
388 	/*
389 	** see if they specified a group name
390 	*/
391 	if ((group = lookup(Groups, str)) != NULL) {
392 		for (member=group->members; member; member=member->next) {
393 			/*
394 			** Check the time range for this member to make
395 			** sure he/she is "on-duty" when the page goes out.
396 			*/
397 			if (!on_duty(member->schedule, holduntil)) {
398 				if (Debug)
399 					qpage_log(LOG_DEBUG,
400 						"skipping %s (off-duty)",
401 						member->pager->name);
402 
403 				continue;
404 			}
405 
406 			/*
407 			** Members can be listed in a group more than once
408 			** if they are on-duty during different times of
409 			** the week.  Check to make sure that this recipient
410 			** isn't already on the list (i.e. time ranges
411 			** overlap).
412 			*/
413 			for (tmp=p->rcpts; tmp; tmp=tmp->next) {
414 				if (!strcmp(member->pager->name, tmp->pager)) {
415 					member = NULL;
416 					break;
417 				}
418 			}
419 
420 			if (member == NULL)
421 				continue;
422 
423 			tmp = (void *)malloc(sizeof(*tmp));
424 			(void)memset((char *)tmp, 0, sizeof(*tmp));
425 			tmp->pager = strdup(member->pager->name);
426 			tmp->holduntil = holduntil;
427 
428 			if (service)
429 				tmp->coverage = strdup(service->name);
430 
431 			tmp->level = level;
432 			tmp->next = p->rcpts;
433 			tmp->flags = flags;
434 			p->rcpts = tmp;
435 		}
436 
437 		/*
438 		** Return success if we found one or more valid recipients.
439 		*/
440 		if (tmp)
441 			return(0);
442 		else
443 			return(1);
444 	}
445 
446 	/*
447 	** it wasn't a group name, try an individual pager
448 	*/
449 	if (lookup(Pagers, str) == NULL) {
450 		/*
451 		** The pager doesn't exist.  Let's
452 		** see if they gave us a pagerid
453 		** rather than a username.
454 		*/
455 		for (ptr=str; *ptr; ptr++)
456 			if (!isdigit(*ptr))
457 				return(-1);
458 
459 		if (*ptr)
460 			return(-1);
461 
462 		if (service == NULL) {
463 			service = lookup(Services,
464 				"default");
465 
466 			if (service == NULL)
467 				return(-1);
468 		}
469 
470 		if (service->allowpid == FALSE)
471 			return(-1);
472 
473 		flags |= F_RAWPID;
474 	}
475 
476 	tmp = (void *)malloc(sizeof(*tmp));
477 	(void)memset((char *)tmp, 0, sizeof(*tmp));
478 	tmp->pager = strdup(str);
479 	tmp->holduntil = holduntil;
480 
481 	if (service)
482 		tmp->coverage = strdup(service->name);
483 
484 	tmp->level = level;
485 	tmp->next = p->rcpts;
486 	tmp->flags = flags;
487 	p->rcpts = tmp;
488 
489 
490 	return(0);
491 }
492 
493 
494 /*
495 ** snpp()
496 **
497 ** This function does most all the communication between
498 ** the client and the server.
499 **
500 **	Input:
501 **		p - an empty PAGE structure
502 **
503 **	Returns:
504 **		0 on success, -1 on error
505 **
506 **	Note:
507 **		Calls to qpage_log() from within this function should
508 **		be treated as though XDEBug never existed.
509 */
510 int
snpp(PAGE * p)511 snpp(PAGE *p)
512 {
513 	struct cmd	*c;
514 	service_t	*service;
515 	time_t		holduntil;
516 	time_t		now;
517 	job_t		*joblist;
518 #ifdef DEBUG
519 	FILE		*fp;
520 #endif
521 	char		buff[1024];
522 	char		*cmdbuf;
523 	char		*errmsg;
524 	char		*a;
525 	char		*b;
526 	char		*m;
527 	int		i;
528 	int		badarg;
529 	int		gotpager;
530 	int		gotmessage;
531 	int		badcommands;
532 	int		level;
533 	int		pagecount;
534 
535 
536 	service = NULL;
537 	gotpager = 0;
538 	holduntil = 0;
539 	gotmessage = 0;
540 	badcommands = 0;
541 	pagecount = 0;
542 	level = DEFAULT_LEVEL;
543 
544 	now = time(NULL);
545 	(void)sprintf(buff, "220 QuickPage v%s SNPP server ready at %s",
546 		VERSION, my_ctime(&now));
547 
548 	message(buff);
549 
550 	for (;;) {
551 		while ((cmdbuf = getinput(p->peer, TRUE)) == NULL) {
552 			if (++badcommands > MAXBADCOMMANDS) {
553 				message("421 Too many errors, goodbye");
554 				return(-1);
555 			}
556 
557 			message("500 Command unrecognized");
558 		}
559 
560 		/*
561 		** check for a timeout condition
562 		*/
563 		if (*cmdbuf == '\0') {
564 			message("421 Timeout, goodbye");
565 			return(-1);
566 		}
567 
568 		if (Debug) {
569 			fprintf(stderr, "--> %s\n", cmdbuf);
570 			(void)fflush(stderr);
571 		}
572 
573 		/*
574 		** figure out which command they gave us
575 		*/
576 		for (c=CmdTab; c->cmdname != NULL; c++) {
577 			if (strncasecmp(c->cmdname, cmdbuf, 4) == 0)
578 				break;
579 		}
580 
581 		/*
582 		** find the first argument (if any)
583 		*/
584 		a = cmdbuf;
585 		while (*a && !isspace(*a))
586 			a++;
587 
588 		/*
589 		** nuke leading whitespace from the argument list
590 		*/
591 		while (*a && isspace(*a))
592 			a++;
593 
594 		/*
595 		** process the command
596 		*/
597 		switch (c->cmdcode) {
598 			/*
599 			** Level 1 commands
600 			*/
601 			case CMDPAGE:
602 				errmsg = "550 Error, invalid pager ID";
603 
604 				if (*a == '\0') {
605 					message(errmsg);
606 					break;
607 				}
608 
609 				/*
610 				** find the end of the argument
611 				*/
612 				for (b=a; *b && !isspace(*b); b++)
613 					continue;
614 
615 				*b = '\0';
616 				while (*b && isspace(*b))
617 					b++;
618 
619 				/*
620 				** We don't support the level 2 syntax yet
621 				*/
622 				if (*b) {
623 					message(errmsg);
624 					break;
625 				}
626 
627 				i = find_recipients(p, a, service, holduntil,
628 					level);
629 
630 				if (i == 1)
631 					errmsg = "550 Error, no group members on duty";
632 
633 				if (i) {
634 					message(errmsg);
635 					break;
636 				}
637 
638 				gotpager++;
639 
640 				if (holduntil)
641 					message("250 Pager ID accepted, message will be delayed");
642 				else
643 					message("250 Pager ID accepted, message will not be delayed");
644 
645 				/*
646 				** set the per-pager options to their defaults
647 				*/
648 				service = NULL;
649 				holduntil = 0;
650 				level = DEFAULT_LEVEL;
651 				break;
652 
653 			case CMDMESS:
654 				if (gotmessage) {
655 					message("503 Error, message already entered");
656 					break;
657 				}
658 
659 				if (*a == '\0') {
660 					message("550 Empty message not allowed");
661 					break;
662 				}
663 
664 				/*
665 				** trim trailing whitespace
666 				*/
667 				b = &a[strlen(a)-1];
668 				while (b > a && isspace(*b))
669 					*b-- = '\0';
670 
671 				p->message = strdup(a);
672 				strip(&p->message);
673 				gotmessage++;
674 
675 				message("250 Message ok");
676 				break;
677 
678 			case CMDRESE:
679 				clear_page(p, TRUE);
680 				service = NULL;
681 				gotpager = 0;
682 				holduntil = 0;
683 				gotmessage = 0;
684 				badcommands = 0;
685 				level = DEFAULT_LEVEL;
686 
687 				message("250 Reset ok");
688 				break;
689 
690 			case CMDSEND:
691 				if (!gotpager) {
692 					message("503 Error, no pager ID");
693 					clear_page(p, TRUE);
694 					break;
695 				}
696 
697 				if (!gotmessage) {
698 					message("503 Error, no message");
699 					clear_page(p, TRUE);
700 					break;
701 				}
702 
703 				p->created = time(NULL);
704 				(void)sprintf(buff, "%d", pagecount++);
705 				m = (void *)malloc(sizeof(*m) * (strlen(p->messageid) + strlen(buff) + 1));
706 				if ( m == NULL ) {
707 					message("554 Message failed (out of memory)");
708 					qpage_log(LOG_ERR, "snpp(): cannot allocate memory for p->messageid");
709 					clear_page(p, TRUE);
710 					break;
711 				}
712 				(void)sprintf(m, "%s%s", p->messageid, buff);
713 				my_free(p->messageid);
714 				p->messageid = m;
715 
716 				qpage_log(LOG_ALERT, "page submitted, id=%s, from=%s",
717 					p->messageid,
718 					p->from ? p->from : "[anonymous]");
719 
720 				/*
721 				** If the XDEBug command was issued, send
722 				** the page out now rather than queueing it.
723 				** Set the interactive flag so the remote
724 				** user can see what is going on.
725 				**
726 				** KLUDGE ALERT--we're sucking down memory
727 				** here without ever giving it back.  Good
728 				** thing this is a separate process that
729 				** will exit soon.
730 				*/
731 				if (Interactive) {
732 					message("214 Sending message");
733 					joblist = NULL;
734 					(void)insert_jobs(&joblist, p);
735 					send_pages(joblist);
736 					message("250 Done sending message");
737 					clear_page(p, TRUE);
738 					break;
739 				}
740 
741 				if (write_page(p, TRUE) < 0) {
742 					message("554 Message failed (error writing queue file)");
743 					qpage_log(LOG_ALERT, "write_page() failed for id=%s", p->messageid);
744 					clear_page(p, TRUE);
745 					break;
746 				}
747 
748 				/*
749 				** Tell the parent there's work to do.
750 				*/
751 				if (Synchronous)
752 					(void)kill(getppid(), SIGUSR1);
753 
754 				clear_page(p, TRUE);
755 				service = NULL;
756 				gotpager = 0;
757 				holduntil = 0;
758 				gotmessage = 0;
759 				badcommands = 0;
760 				level = DEFAULT_LEVEL;
761 
762 				(void)sprintf(buff,
763 					"250 Message %s queued for processing",
764 					p->messageid);
765 
766 				message(buff);
767 				break;
768 
769 			case CMDQUIT:
770 				message("221 OK, goodbye");
771 				return(0);
772 
773 			case CMDHELP:
774 				dohelp();
775 				break;
776 
777 			/*
778 			** Level 2 commands
779 			*/
780 			case CMDDATA:
781 				if (gotmessage) {
782 					message("503 Error, message already entered");
783 					break;
784 				}
785 
786 				message("354 Begin input; end with <CRLF>'.'<CRLF>");
787 
788 				p->message = getinput(p->peer, FALSE);
789 
790 				if (p->message == NULL) {
791 					message("550 Empty message not allowed");
792 					break;
793 				}
794 
795 				/*
796 				** check for a timeout condition
797 				*/
798 				if (p->message[0] == '\0') {
799 					message("421 Timeout, goodbye");
800 					return(-1);
801 				}
802 
803 				strip(&p->message);
804 				gotmessage++;
805 
806 				message("250 Message ok");
807 				break;
808 
809 			case CMDLOGI:
810 				errmsg = "550 Error, invalid login or password";
811 
812 				if ((p->auth = authorize(a)) == NULL) {
813 					message(errmsg);
814 					break;
815 				}
816 
817 				message("250 Login accepted");
818 				break;
819 
820 			case CMDLEVE:
821 				errmsg = "550 Error, invalid service level";
822 
823 				if (*a == '\0') {
824 					message(errmsg);
825 					break;
826 				}
827 
828 				badarg = 0;
829 				for (b=a; *b && !isspace(*b); b++) {
830 					if (!isdigit(*b)) {
831 						badarg++;
832 						break;
833 					}
834 				}
835 
836 				*b = '\0';
837 				while (*b && isspace(*b))
838 					b++;
839 
840 				if (*b)
841 					badarg++;
842 
843 				i = atoi(a);
844 
845 				if ((i < 0) || (i > 11))
846 					badarg++;
847 
848 				if (badarg) {
849 					message(errmsg);
850 					break;
851 				}
852 
853 				level = i;
854 				message("250 OK, alternate service level accepted");
855 				break;
856 
857 			case CMDALER:
858 				message("500 Command not implemented");
859 				break;
860 
861 			case CMDCOVE:
862 				errmsg = "550 Error, invalid alternate region";
863 
864 				if (*a == '\0') {
865 					message(errmsg);
866 					break;
867 				}
868 
869 				/*
870 				** find the end of the argument
871 				*/
872 				for (b=a; *b && !isspace(*b); b++)
873 					continue;
874 
875 				*b = '\0';
876 				while (*b && isspace(*b))
877 					b++;
878 
879 				if (*b) {
880 					message(errmsg);
881 					break;
882 				}
883 
884 				if ((service = lookup(Services, a)) == NULL) {
885 					message(errmsg);
886 					break;
887 				}
888 
889 				message("250 Alternate coverage selected");
890 				break;
891 
892 			case CMDHOLD:
893 				if ((holduntil = snpptime(a)) == INVALID_TIME) {
894 					message("550 Error, invalid delivery date/time");
895 					holduntil = 0;
896 					break;
897 				}
898 
899 				if ((b = my_ctime(&holduntil)) == NULL) {
900 					message("554 ctime() failed");
901 					break;
902 				}
903 
904 				(void)sprintf(buff, "250 Message for next PAGEr will be delayed until %s", b);
905 				message(buff);
906 				break;
907 
908 			case CMDCALL:
909 				if (*a == '\0') {
910 					message("550 Error, invalid caller ID");
911 					break;
912 				}
913 
914 				/*
915 				** trim trailing whitespace
916 				*/
917 				b = &a[strlen(a)-1];
918 				while (b > a && isspace(*b))
919 					*b-- = '\0';
920 
921 				my_free(p->from);
922 				p->from = strdup(a);
923 
924 #ifndef NOIDENT
925 				if (p->ident && strcasecmp(p->ident, p->from))
926 					message("250 You're a liar, but I'll trust you this time");
927 				else
928 #endif
929 					message("250 Caller ID accepted");
930 				break;
931 
932 			case CMDSUBJ:
933 				message("500 Command not implemented");
934 				break;
935 
936 			/*
937 			** Level 3 commands
938 			*/
939 			case CMD2WAY:
940 			case CMDPING:
941 			case CMDEXPT:
942 			case CMDNOQU:
943 			case CMDACKR:
944 			case CMDRTYP:
945 			case CMDMCRE:
946 			case CMDMSTA:
947 			case CMDKTAG:
948 				message("500 Command not implemented");
949 				break;
950 
951 #ifdef DEBUG
952 			/*
953 			** Other commands not part of SNPP protocol
954 			*/
955 			case CMDXDEB:
956 				qpage_log(LOG_ALERT, "debug mode entered");
957 				Debug = TRUE;
958 				Interactive = TRUE;
959 				setbuf(stdout, NULL);
960 				message("250 Debug mode entered");
961 				break;
962 
963 			case CMDXCON:
964 				qpage_log(LOG_ALERT, "configuration file requested");
965 
966 				dump_qpage_config(ConfigFile);
967 
968 				(void)fflush(stdout);
969 				(void)fclose(fp);
970 
971 				message("250 Command complete");
972 				break;
973 
974 			case CMDXQUE:
975 				qpage_log(LOG_ALERT, "page queue requested");
976 
977 				printf("---------- start queue ----------\n");
978 				i = showqueue();
979 				printf("---------- end queue ----------\n");
980 				(void)fflush(stdout);
981 
982 				message("250 Command complete");
983 				break;
984 #endif /* DEBUG */
985 
986 			case CMDXWHO:
987 				qpage_log(LOG_ALERT, "pagerid list requested");
988 				dump_pagers();
989 				message("250 Command complete");
990 				break;
991 
992 			case CMDERROR:
993 			default:
994 				if (++badcommands > MAXBADCOMMANDS) {
995 					message("421 Too many errors, goodbye");
996 					return(-1);
997 				}
998 
999 				message("500 Command unrecognized");
1000 				break;
1001 		}
1002 	}
1003 }
1004 
1005 
1006 void
accept_connection(int sock)1007 accept_connection(int sock)
1008 {
1009 #ifdef TCP_WRAPPERS
1010 	struct request_info	request;
1011 	char			*ptr;
1012 #endif
1013 	struct sockaddr_in	addr;
1014 	struct hostent		*hp;
1015 	pid_t			pid;
1016 	FILE			*in;
1017 	FILE			*out;
1018 	PAGE			*p;
1019 	char			msgid[100];
1020 	int			len;
1021 	int			s;
1022 
1023 
1024 	len = sizeof(addr);
1025 	if ((s = accept(sock, (struct sockaddr *)&addr, &len)) < 0) {
1026 #ifdef ERESTART
1027 		if (errno != EINTR && errno != ERESTART)
1028 #else
1029 		if (errno != EINTR)
1030 #endif
1031 			qpage_log(LOG_ERR, "accept() failed: %s",
1032 				strerror(errno));
1033 
1034 		return;
1035 	}
1036 
1037 	/*
1038 	** Generate a new message ID before the fork() to ensure
1039 	** that it will be somewhat unique.
1040 	*/
1041 	newmsgid(msgid);
1042 
1043 	pid = fork();
1044 
1045 	if (pid != 0) {
1046 		if (pid < 0)
1047 			qpage_log(LOG_ERR, "fork() failed: %s",
1048 				strerror(errno));
1049 
1050 		(void)close(s);
1051 		return;
1052 	}
1053 
1054 	/* CHILD */
1055 
1056 	/*
1057 	** create a new page structure
1058 	*/
1059 	p = (void *)malloc(sizeof(*p));
1060 	(void)memset((char *)p, 0, sizeof(*p));
1061 	p->messageid = strdup(msgid);
1062 
1063 #ifdef TCP_WRAPPERS
1064 	if (request_init(&request, RQ_DAEMON, PROGRAM_NAME, RQ_FILE,
1065 		s, NULL) != NULL) {
1066 
1067 		fromhost(&request);
1068 
1069 		ptr = eval_user(&request);
1070 
1071 		if (ptr && strcmp(ptr, STRING_UNKNOWN) != 0)
1072 			p->ident = strdup(ptr);
1073 
1074 		ptr = eval_hostinfo(&request.client);
1075 
1076 		if (ptr && strcmp(ptr, STRING_UNKNOWN) != 0)
1077 			p->hostname = strdup(ptr);
1078 	}
1079 
1080 	if (!hosts_access(&request)) {
1081 		ptr = "421 Permission Denied by Administrator\r\n";
1082 		(void)write(s, ptr, strlen(ptr));
1083 		(void)close(s);
1084 
1085 		qpage_log(LOG_INFO, "connection refused from %s@%s",
1086 			p->ident ? p->ident : "[anonymous]", p->hostname);
1087 		_exit(2);
1088 	}
1089 #endif
1090 
1091 	if (p->hostname == NULL) {
1092 		/*
1093 		** figure out where this connection came from
1094 		*/
1095 		hp = gethostbyaddr((char *)&addr.sin_addr.s_addr,
1096 			sizeof(addr.sin_addr.s_addr), AF_INET);
1097 
1098 		if (hp == NULL) {
1099 			/*
1100 			** allocate enough room for [nnn.nnn.nnn.nnn]
1101 			*/
1102 			p->hostname = (void *)malloc(17+1);
1103 			(void)sprintf(p->hostname, "[%s]",
1104 				inet_ntoa(addr.sin_addr));
1105 		}
1106 		else
1107 			p->hostname = strdup(hp->h_name);
1108 	}
1109 
1110 	if (IdentTimeout && p->ident == NULL)
1111 		p->ident = ident(s);
1112 
1113 	qpage_log(LOG_INFO, "connection from %s@%s",
1114 		p->ident ? p->ident : "[anonymous]", p->hostname);
1115 
1116 
1117 	if ((in = fdopen(s, "r")) == NULL) {
1118 		qpage_log(LOG_ERR, "cannot reopen socket");
1119 		_exit(-1);
1120 	}
1121 
1122 	if ((out = fdopen(dup(s), "w")) == NULL) {
1123 		qpage_log(LOG_ERR, "cannot reopen socket");
1124 		_exit(-1);
1125 	}
1126 
1127 	/*
1128 	** stdout goes to the socket
1129 	*/
1130 	if (fileno(out) != fileno(stdout))
1131 		(void)dup2(fileno(out), fileno(stdout));
1132 
1133 	p->peer = in;
1134 	(void)snpp(p);
1135 
1136 	qpage_log(LOG_INFO, "disconnect from %s@%s",
1137 		p->ident ? p->ident : "[anonymous]", p->hostname);
1138 
1139 	(void)fclose(stdout);
1140 	(void)fclose(out);
1141 	(void)fclose(in);
1142 	(void)close(s);
1143 	_exit(0);
1144 }
1145 
1146 
1147 /*
1148 ** become_daemon()
1149 **
1150 ** This function opens a socket on the SNPP port and waits for
1151 ** incoming connections.  When a connection is established, this
1152 ** function forks.  The parent continues to listen for incoming
1153 ** connections while the child is handed off to snpp().
1154 **
1155 ** A background process is also started which continually processes
1156 ** the page queue.  If there are jobs remaining in the queue after
1157 ** processing (such as jobs scheduled to run in the future), the
1158 ** background process waits for a specified number of seconds and
1159 ** starts over again.  Otherwise, the background process goes to
1160 ** sleep until a new job is submitted to the queue.
1161 **
1162 **	Input:
1163 **		sleeptime - the time interval to sleep between iterations
1164 **
1165 **	Returns:
1166 **		-1 on error, otherwise never
1167 */
1168 int
become_daemon(int sleeptime,short port)1169 become_daemon(int sleeptime, short port)
1170 {
1171 	struct sockaddr_in	addr;
1172 	struct servent		*svc;
1173 	struct timeval		timeout;
1174 #ifdef HAVE_POLL
1175 	struct pollfd		fds;
1176 #else
1177 	fd_set			readfds;
1178 #endif
1179 	time_t			lastrun;
1180 	time_t			now;
1181 	pid_t			childpid;
1182 	char			pid[30];
1183 	int			dontsend;
1184 	int			sock;
1185 	int			len;
1186 	int			on;
1187 	int			fd;
1188 	int			i;
1189 
1190 
1191 	if (sleeptime < 0) {
1192 		dontsend = TRUE;
1193 		sleeptime = 0;
1194 	}
1195 	else
1196 		dontsend = FALSE;
1197 
1198 	lastrun = 0;
1199 	childpid = 0;
1200 
1201 	if (port == 0) {
1202 		/*
1203 		** Get the SNPP port number from the /etc/services map.
1204 		** Note that the port number is returned in network byte
1205 		** order so no call to htons() is required.
1206 		*/
1207 		if ((svc = getservbyname("snpp", "tcp")) != NULL)
1208 			port = svc->s_port;
1209 		else
1210 
1211 			port = htons(SNPP_SVC_PORT);
1212 	}
1213 	else
1214 		port = htons(port);
1215 
1216 	/*
1217 	** Make sure we have permission to bind to this port.
1218 	*/
1219 	if (ntohs(port) < 1024 && geteuid() != 0)
1220 		fprintf(stderr, "Warning: daemon must be started as root\n");
1221 
1222 	if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
1223 		fprintf(stderr, "socket() failed: %s\n", strerror(errno));
1224 		return(-1);
1225 	}
1226 
1227 	/*
1228 	** Attempt to set REUSEADDR but it's no big deal if this fails.
1229 	*/
1230 	on = 1;
1231 	len = sizeof(on);
1232 	(void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, len);
1233 
1234 	addr.sin_addr.s_addr = INADDR_ANY;
1235 	addr.sin_family = AF_INET;
1236 	addr.sin_port = port;
1237 
1238 	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1239 		fprintf(stderr, "bind() failed: %s\n", strerror(errno));
1240 		(void)close(sock);
1241 		return(-1);
1242 	}
1243 
1244 	if (listen(sock, 5) < 0) {
1245 		fprintf(stderr, "listen() failed: %s\n", strerror(errno));
1246 		(void)close(sock);
1247 		return(-1);
1248 	}
1249 
1250 	/*
1251 	** Give up all root permissions now that we're bound to the SNPP port
1252 	*/
1253 	drop_root_privileges();
1254 
1255 	if (get_qpage_config(ConfigFile) != 0) {
1256 		fprintf(stderr, "Error reading configuration file\n");
1257 		return(-1);
1258 	}
1259 
1260 	if (!Debug) {
1261 		/*
1262 		** Detatch ourselves from the controling tty.
1263 		*/
1264 		switch (fork()) {
1265 			case (pid_t)-1:
1266 				qpage_log(LOG_ERR, "fork() failed: %s",
1267 					strerror(errno));
1268 				return(-1);
1269 
1270 			case 0:
1271 				/*
1272 				** Ensure that we will never have a
1273 				** controlling terminal.
1274 				*/
1275 				(void)close(0);
1276 				(void)close(1);
1277 				(void)close(2);
1278 				(void)setsid();
1279 				if (fork())
1280 					_exit(-1);
1281 				break;
1282 
1283 			default:
1284 				_exit(0);
1285 		}
1286 	}
1287 
1288 	/*
1289 	** Attempt to write our PID to a file specified by the
1290 	** administrator.  Note that we do not know the filename
1291 	** until after we've read the configuration file and we
1292 	** can't read the configuration file until after we've
1293 	** dropped our root permissions (because otherwise the
1294 	** access() calls in config.c will be using the wrong
1295 	** permissions).  Therefore, it is safe to use O_CREAT
1296 	** and O_TRUNC because we know it's not possible for
1297 	** someone to trick us into doing the wrong thing by
1298 	** feeding us a symbolic link.
1299 	**
1300 	** The obvious downside here is that the file will most
1301 	** likely want to be in some system directory such as /etc,
1302 	** which means if the file doesn't already exist then the
1303 	** O_CREAT flag probably won't do us any good.  Such is
1304 	** life, I guess.
1305 	*/
1306 	if (PIDfile) {
1307 		/*
1308 		** let the current umask determine the default permissions
1309 		*/
1310 		fd = open(PIDfile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1311 
1312 		if (fd >= 0) {
1313 			(void)sprintf(pid, "%d\n", (int)getpid());
1314 			(void)write(fd, pid, strlen(pid));
1315 			(void)close(fd);
1316 		}
1317 	}
1318 
1319 	if (Debug)
1320 		qpage_log(LOG_DEBUG, "waiting for incoming connections");
1321 
1322 	/*
1323 	** spin forever, waiting for connections and processing the queue
1324 	*/
1325 	for (;;) {
1326 		timeout.tv_sec = sleeptime;
1327 		timeout.tv_usec = 0;
1328 
1329 		if (JobsPending)
1330 			timeout.tv_sec = 0;
1331 
1332 #ifdef HAVE_POLL
1333 		fds.fd = sock;
1334 		fds.events = POLLIN;
1335 		fds.revents = 0;
1336 
1337 		i = poll(&fds, 1, timeout.tv_sec * 1000);
1338 #else
1339 		FD_ZERO_LINTED(&readfds);
1340 		FD_SET(sock, &readfds);
1341 
1342 		i = select(FD_SETSIZE, &readfds, 0, 0,
1343 			sleeptime ? &timeout : NULL);
1344 #endif
1345 
1346 		if (i < 0) {
1347 #ifdef ERESTART
1348 			if (errno != EINTR && errno != ERESTART)
1349 #else
1350 			if (errno != EINTR)
1351 #endif
1352 #ifdef HAVE_POLL
1353 				qpage_log(LOG_ERR, "poll() failed: %s",
1354 					strerror(errno));
1355 #else
1356 				qpage_log(LOG_ERR, "select() failed: %s",
1357 					strerror(errno));
1358 #endif
1359 		}
1360 
1361 		if (ReReadConfig) {
1362 			ReReadConfig = FALSE;
1363 			qpage_log(LOG_NOTICE, "rereading configuration");
1364 
1365 			if (get_qpage_config(ConfigFile)) {
1366 				qpage_log(LOG_NOTICE,
1367 					"new configuration has errors");
1368 			}
1369 		}
1370 
1371 #ifdef HAVE_POLL
1372 		if (fds.revents & POLLIN)
1373 			accept_connection(sock);
1374 #else
1375 		if (i > 0 && FD_ISSET(sock, &readfds))
1376 			accept_connection(sock);
1377 #endif
1378 
1379 		now = time(NULL);
1380 
1381 		/*
1382 		** If there's a living child processing the page queue,
1383 		** we should just go back to waiting for more incoming
1384 		** network requests.
1385 		*/
1386 		if (childpid > 0 && kill(childpid, 0) == 0) {
1387 #ifdef ENABLE_DEADMAN_TIMER
1388 			/*
1389 			** Make sure the child hasn't wedged itself.
1390 			** It shouldn't take more than 5 minutes to
1391 			** do a queue run.
1392 			*/
1393 			if (now - lastrun > 300) {
1394 				qpage_log(LOG_WARNING, "killing stuck child");
1395 				(void)kill(childpid, SIGKILL);
1396 			}
1397 			else
1398 #endif
1399 				continue;
1400 		}
1401 
1402 		/*
1403 		** hack to process new jobs without waiting for sleeptime
1404 		*/
1405 		if (JobsPending) {
1406 			JobsPending = FALSE;
1407 			lastrun = 0;
1408 		}
1409 
1410 		if (now - lastrun >= sleeptime && dontsend == FALSE) {
1411 			lastrun = now;
1412 
1413 			qpage_log(LOG_DEBUG, "processing the page queue");
1414 
1415 			childpid = fork();
1416 
1417 			switch (childpid) {
1418 				case (pid_t)-1:
1419 					qpage_log(LOG_ERR,
1420 						"fork() failed: %s",
1421 						strerror(errno));
1422 					break;
1423 
1424 				case 0:
1425 					i = runqueue();
1426 					_exit(i);
1427 			}
1428 		}
1429 	}
1430 }
1431