summaryrefslogtreecommitdiff
path: root/src/tet3/tccd/tccd.c
blob: 35c4179cb3925afa31ba0666c40d82d14fc4621c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
/*
 *      SCCS:  @(#)tccd.c	1.18 (98/09/01) 
 *
 *	UniSoft Ltd., London, England
 *
 * (C) Copyright 1992, 1996 X/Open Company Limited
 *
 * All rights reserved.  No part of this source code may be reproduced,
 * stored in a retrieval system, or transmitted, in any form or by any
 * means, electronic, mechanical, photocopying, recording or otherwise,
 * except as stated in the end-user licence agreement, without the prior
 * permission of the copyright owners.
 *
 * X/Open and the 'X' symbol are trademarks of X/Open Company Limited in
 * the UK and other countries.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/************************************************************************

SCCS:   	@(#)tccd.c	1.18 98/09/01 TETware release 3.3
NAME:		tccd.c
PRODUCT:	TETware
AUTHOR:		Andrew Dingwall, UniSoft Ltd.
DATE CREATED:	April 1992

DESCRIPTION:
	server-specific functions for tccd server

MODIFICATIONS:
	Denis McConalogue, UniSoft Limited, August 1993
	added support for OP_RCOPY request message

	Denis McConalogue, UniSoft Limited, September 1993
	added ss_disconnect() function

	Andrew Dingwall, UniSoft Ltd., December 1993
	removed disconnect stuff
	moved tet_sdptab and tet_xdptab to here

	Andrew Dingwall, UniSoft Ltd., February 1994
	added -e command-line option

	Andrew Dingwall, UniSoft Ltd., February 1995
	provide default PATH if one is not present in the environment
	(mainly for the INETD version)

	Andrew Dingwall, UniSoft Ltd., August 1996
	added OP_SETCONF, OP_MKALLDIRS and OP_TIME
	changed for tetware-style configuration

	Geoff Clare, UniSoft Ltd., August-Sept 1996
	Missing <unistd.h> and <sys/stat.h>.
	Define and initialise tet_blockable_sigs.

	Andrew Dingwall, UniSoft Ltd., September 1996
	added OP_RMALLDIRS

	Andrew Dingwall, UniSoft Ltd., July 1997
	added support the MT DLL version of the C runtime support library
	on Win32 systems

	Andrew Dingwall, UniSoft Ltd., July 1998
	Added support for shared API libraries.

	Aaron Plattner, April 2010
	Fixed warnings when compiled with GCC's -Wall option.

************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#  include <pwd.h>
#  include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "dtmac.h"
#include "dtmsg.h"
#include "ptab.h"
#include "sptab.h"
#include "ltoa.h"
#include "error.h"
#include "globals.h"
#include "avmsg.h"
#include "valmsg.h"
#include "server.h"
#include "servlib.h"
#include "dtetlib.h"
#include "sigsafe.h"
#include "tslib.h"
#include "tccd.h"


/* global variables */
struct ptab *tet_sdptab;		/* ptr to SYNCD ptab element */
struct ptab *tet_xdptab;		/* ptr to XRESD ptab element */

char *Myusername = "tet";		/* user name to run as */
char *Logfile = "/tmp/tccdlog";		/* file name for stdout and stderr */
sigset_t tet_blockable_sigs;		/* for tet_sigsafe_start() */


/* pointers to error handlers - used in the generic code and libraries */
void (*tet_liberror)() = logerror;
void (*tet_libfatal)() = tet_genfatal;


/* static function declarations */
static void op_sysid PROTOLIST((struct ptab *));
static void op_sysname PROTOLIST((struct ptab *));
static SIG_FUNC_T terminate PROTOLIST((int));


/************************************************************************
**									*
**	MAIN ROUTINES							*
**									*
************************************************************************/

int main(argc, argv)
int argc;
char **argv;
{
	/* ignore certain signals */
	(void) signal(SIGHUP, SIG_IGN);
	(void) signal(SIGINT, SIG_IGN);
	(void) signal(SIGQUIT, SIG_IGN);

	/* initialise the global variables for the library code */
	tet_init_globals("tccd", PT_STCC, -1, logerror, tet_genfatal);
	tet_root[0] = '\0';

	/* initialise signal set to be blocked by tet_sigsafe_start() */
	tet_init_blockable_sigs();

	/* open the error log file */
	(void) umask((mode_t) 022);
	loginit();

	/* catch SIGTERM */
	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
		(void) signal(SIGTERM, terminate);

	/* call the generic server */
	return(tet_si_main(argc, argv, 0));
}

/*
**	tet_ss_argproc() - tccd command-line argument processing
**
**	return 0 if only firstarg was used or 1 if both args were used
*/

int tet_ss_argproc(firstarg, nextarg)
char *firstarg, *nextarg;
{
	register int rc = 0;
	register int mask;
	register char *p;

	switch (*(firstarg + 1)) {
	case 'u':
		if (*(firstarg + 2))
			Myusername = firstarg + 2;
		else {
			Myusername = nextarg;
			rc = 1;
		}
		break;
	case 'm':
		if (*(firstarg + 2))
			p = firstarg + 2;
		else {
			p = nextarg;
			rc = 1;
		}
		mask = 0;
		while (*p >= '0' && *p <= '7')
			mask = (mask << 3) | (*p++ & 07);
		(void) umask((mode_t)(mask & 077));
		break;
	case 'l':
		if (*(firstarg + 2))
			Logfile = firstarg + 2;
		else {
			Logfile = nextarg;
			rc = 1;
		}
		loginit();
		break;
	case 'e':
		if (*(firstarg + 2))
			p = firstarg + 2;
		else {
			p = nextarg;
			rc = 1;
		}
		if (!tet_equindex(p))
			error(0, "bad format environment variable:", p);
		else if (tet_putenv(p) < 0)
			error(0, "can't add variable to environment:", p);
		break;
	default:
		return(ss_tsargproc(firstarg, nextarg));
	}

	return(rc);
}

/*
**	tet_ss_initdaemon() - tccd daemon initialisation
*/

void tet_ss_initdaemon()
{
	static char defpath[] = "/bin:/usr/bin";
	static char null[] = "/dev/null";
	static char msg[] = "can't find passwd entry for";
	register struct passwd *pw;
	uid_t euid;
	gid_t egid;
	register char *p;
	static char home[] = "HOME";
	static char path[] = "PATH";
	char buf[sizeof home + MAXPATH + 1];


	/* get effecive ids */
	euid = geteuid();
	egid = getegid();

	/* get password file entry for the specified user name */
	errno = 0;
	if ((pw = getpwnam(Myusername)) == (struct passwd *) 0) {
		error(errno != ENOTTY ? errno : 0, msg, Myusername);
		if (euid < 100)
			exit(1);
		errno = 0;
		if ((pw = getpwuid(euid)) == (struct passwd *) 0)
			fatal(errno, msg, tet_i2a(euid));
	}
#  ifndef _POSIX_SOURCE
	endpwent();
#  endif

	/* change uid and gid if necessary */
	if (getgid() != pw->pw_gid || egid != pw->pw_gid)
		if (setgid(pw->pw_gid) < 0) {
			error(errno, "can't set gid to", tet_i2a(pw->pw_gid));
			if (egid < 100)
				exit(1);
		}
	if (getuid() != pw->pw_uid || euid != pw->pw_uid)
		if (setuid(pw->pw_uid) < 0) {
			error(errno, "can't set uid to", tet_i2a(pw->pw_uid));
			if (euid < 100)
				exit(1);
		}

	/* fix up HOME environment variable if necessary */
	if ((p = getenv(home)) == (char *) 0 || strcmp(p, pw->pw_dir)) {
		(void) sprintf(buf, "%s=%.*s", home,
			(int) sizeof buf - (int) sizeof home - 2, pw->pw_dir);
		if ((p = tet_strstore(buf)) == (char *) 0 || tet_putenv(p) < 0)
			exit(1);
	}

	/* provide a default PATH variable if necessary */
	if ((p = getenv(path)) == (char *) 0) {
		(void) sprintf(buf, "%s=%.*s", path,
			(int) sizeof buf - (int) sizeof path - 2, defpath);
		TRACE2(tet_Ttccd, 4, "no PATH env var, using default: \"%s\"",
			buf);
		if ((p = tet_strstore(buf)) == (char *) 0 || tet_putenv(p) < 0)
			exit(1);
	}

	/* remember home directory for later and chdir to there */
	p = getenv(home);
	ASSERT(p && *p);
	if (tetrootset(p) < 0)
		exit(1);
	TRACE3(tet_Ttccd, 4, "chdir to %s HOME: \"%s\"", pw->pw_name, tet_root);
	if (CHDIR(tet_root) < 0)
		fatal(errno, "can't chdir to", tet_root);

	/* perform syncd transport-specific initialisation */
	ss_tsinitb4fork();

	/* attach stdin to /dev/null and stdout to stderr (which goes
		to the log file */
	(void) CLOSE(0);
	errno = 0;
	if (OPEN(null, O_RDONLY, 0) != 0)
		fatal(errno, "can't open", null);
	(void) CLOSE(1);
	errno = 0;
	if (FCNTL_F_DUPFD(FILENO(stderr), 1) != 1)
		fatal(errno, "can't attach stdout to stderr", (char *) 0);

#ifndef INITTAB
	/* start the daemon */
	ts_forkdaemon();
#endif

	/* detach from the control terminal (if any) */
	tet_tiocnotty();

	/* make a log file entry */
	ts_logstart();

}

/*
**	tet_ss_serverloop() - tccd daemon main processing loop
**
**	always return 1 because we always want to come back
*/

int tet_ss_serverloop()
{
	tet_si_serverloop();
	return(1);
}

/************************************************************************
**									*
**	SERVER-SPECIFIC PARTS OF GENERIC SERVICE ROUTINES		*
**									*
************************************************************************/

/*
**	tet_ss_dead() - server-specific routine to handle a dead process
*/

void tet_ss_dead(pp)
register struct ptab *pp;
{
	static char fmt[] = "%s connection closed";
	static char cl[] = "client";
	static char se[] = "server";
	char msg[sizeof fmt + sizeof cl];
	extern struct ptab *tet_ptab;

	/* emit a diagnostic message if this is unexpected */
	if ((pp->pt_flags & PF_LOGGEDOFF) == 0) {
		(void) sprintf(msg, fmt, (pp->pt_flags & PF_SERVER) ? se : cl);
		error(0, msg, tet_r2a(&pp->pt_rid));
	}

	pp->pt_flags = (pp->pt_flags & ~PF_LOGGEDON) | PF_LOGGEDOFF;

	/*
	** for clients:
	**	remove any related file and exec table elements
	**	remove ptab entry
	**	exit if it was the last one
	*/
	if ((pp->pt_flags & PF_SERVER) == 0) {
		tet_fiodead(pp);
		etdead(pp);
		tet_ptrm(pp);
		tet_ptfree(pp);
		if (!tet_ptab)
			tet_ss_cleanup();
	}
}

/*
**	tet_ss_connect() - connect to remote process
*/

void tet_ss_connect(pp)
struct ptab *pp;
{
	tet_ts_connect(pp);
}

/************************************************************************
**									*
**	FULL REQUEST PROCESSING ROUTINES				*
**									*
************************************************************************/

/*
**	tet_ss_process() - request processing routine
*/

void tet_ss_process(pp)
struct ptab *pp;
{
	/* a server ptab might get here via tet_si_servwait() */
	if ((pp->pt_flags & PF_SERVER) == 0)
		tet_si_serverproc(pp);
}

/*
**	tet_ss_serverproc() - request processing as a server
*/

void tet_ss_serverproc(pp)
register struct ptab *pp;
{
	switch (pp->ptm_req) {
	case OP_SYSID:
		op_sysid(pp);
		break;
	case OP_TSINFO:
		op_tsinfo(pp);
		break;
	case OP_SYSNAME:
		op_sysname(pp);
		break;
	case OP_EXEC:
		op_exec(pp);
		break;
	case OP_WAIT:
		op_wait(pp);
		break;
	case OP_KILL:
		op_kill(pp);
		break;
	case OP_CFNAME:
		op_cfname(pp);
		break;
	case OP_SNDCONF:
		op_sndconf(pp);
		break;
	case OP_RCVCONF:
		op_rcvconf(pp);
		break;
	case OP_PUTENV:
		op_putenv(pp);
		break;
	case OP_ACCESS:
		op_access(pp);
		break;
	case OP_MKDIR:
		op_mkdir(pp);
		break;
	case OP_RMDIR:
		op_rmdir(pp);
		break;
	case OP_CHDIR:
		op_chdir(pp);
		break;
	case OP_FOPEN:
		tet_op_fopen(pp);
		break;
	case OP_FCLOSE:
		tet_op_fclose(pp);
		break;
	case OP_PUTS:
		tet_op_puts(pp);
		break;
	case OP_LOCKFILE:
		op_lockfile(pp);
		break;
	case OP_SHARELOCK:
		op_sharelock(pp);
		break;
	case OP_MKTMPDIR:
		op_mktmpdir(pp);
		break;
	case OP_UNLINK:
		op_unlink(pp);
		break;
	case OP_CONFIG:
		op_config(pp);
		break;
	case OP_RXFILE:
		op_rxfile(pp);
		break;
	case OP_RCOPY:
		op_rcopy(pp);
		break;
	case OP_MKSDIR:
		op_mksdir(pp);
		break;
	case OP_TSFILES:
		op_tsfiles(pp);
		break;
	case OP_SETCONF:
		op_setconf(pp);
		break;
	case OP_MKALLDIRS:
		op_mkalldirs(pp);
		break;
	case OP_RMALLDIRS:
		op_rmalldirs(pp);
		break;
	case OP_TIME:
		op_time(pp);
		break;
	default:
		pp->ptm_rc = ER_REQ;
		pp->ptm_mtype = MT_NODATA;
		pp->ptm_len = 0;
		break;
	}

	/* here to send a reply message */
	pp->pt_state = PS_SNDMSG;
	pp->pt_flags |= PF_ATTENTION;
}

/*
**	op_sysid() - assign system id
*/

static void op_sysid(pp)
register struct ptab *pp;
{
	register struct valmsg *mp = (struct valmsg *) pp->ptm_data;

	/* all reply messages have no data */
	pp->ptm_mtype = MT_NODATA;
	pp->ptm_len = 0;

	/* do a sanity check on the request message */
	if ((int) mp->vm_nvalue != OP_SYSID_NVALUE) {
		pp->ptm_rc = ER_INVAL;
		return;
	}

	if (tet_mysysid >= 0) {
		error(0, "sysid already assigned:", tet_i2a(tet_mysysid));
		pp->ptm_rc = ER_ERR;
		return;
	}

	tet_mysysid = (int) VM_SYSID(mp);
	logent("my sysid =", tet_i2a(tet_mysysid));
	pp->ptm_rc = ER_OK;
}

/*
**	op_sysname() - receive a system name list
**
**	in the request message:
**		VM_SYSNAME(0) .. VM_SYSNAME(op_sysname_nsname() - 1) =
**			list of system names
**
*/

static void op_sysname(pp)
register struct ptab *pp;
{
	register struct valmsg *mp = (struct valmsg *) pp->ptm_data;
	register struct sptab *sp = (struct sptab *) pp->pt_sdata;
	register int *snp;
	register int i, j, needlen;

	/* all reply messages have no data */
	pp->ptm_mtype = MT_NODATA;
	pp->ptm_len = 0;

	/* do a sanity check on the request message -
		make sure that there are no duplicates in the system
		name list */
	if (OP_SYSNAME_NSNAME(mp) < 1) {
		pp->ptm_rc = ER_INVAL;
		return;
	}
	for (i = 0; i < OP_SYSNAME_NSNAME(mp); i++) {
		if (VM_SYSNAME(mp, i) < 0) {
			pp->ptm_rc = ER_INVAL;
			return;
		}
		for (j = 0; j < i; j++)
			if (VM_SYSNAME(mp, j) == VM_SYSNAME(mp, i)) {
				pp->ptm_rc = ER_DUPS;
				return;
			}
	}

	/* allocate storage for the system name list */
	needlen = OP_SYSNAME_NSNAME(mp) * sizeof *sp->sp_snames;
	if (BUFCHK((char **) &sp->sp_snames, &sp->sp_snlen, needlen) < 0) {
		pp->ptm_rc = ER_ERR;
		return;
	}

	/* copy over the system name list */
	sp->sp_nsname = OP_SYSNAME_NSNAME(mp);
	for (i = 0, snp = sp->sp_snames; i < OP_SYSNAME_NSNAME(mp); i++, snp++)
		*snp = (int) VM_SYSNAME(mp, i);

	pp->ptm_rc = ER_OK;
}

/************************************************************************
**									*
**	SERVER-SPECIFIC PARTS OF GENERIC REQUEST PROCESSING		*
**									*
************************************************************************/

/*
**	tet_ss_logon() - server-specific logon processing routine
**
**	return ER_OK if successful or other ER_* error code on error
*/

int tet_ss_logon(pp)
struct ptab *pp;
{
	switch (pp->ptr_ptype) {
	case PT_MTCC:
	case PT_MTCM:
	case PT_STCM:
		return(ss_tslogon());
	default:
		error(0, "unexpected connected process type",
			tet_r2a(&pp->pt_rid));
		return(ER_ERR);
	}
}

/*
**	tet_ss_logoff() - server-specific logoff processing routine
*/

void tet_ss_logoff(pp)
struct ptab *pp;
{
	etdead(pp);
}

/*
**	tet_ss_cleanup() - clean up and exit
*/

void tet_ss_cleanup()
{
	config_cleanup();
	(void) tet_xdlogoff();
	tet_ts_cleanup();
	exit(0);
}

/************************************************************************
**									*
**	PUBLIC SUBROUTINES						*
**									*
************************************************************************/

/*
**	tet_ss_newptab() - server-specific new ptab entry handler
*/

void tet_ss_newptab(pp)
struct ptab *pp;
{
	/* add the entry to the process table */
	tet_ptadd(pp);
}

/************************************************************************
**									*
**	PRIVATE SUBROUTINES						*
**									*
************************************************************************/

/*
**	terminate() - SIGTERM signal handler
*/

static SIG_FUNC_T terminate(sig)
int sig;
{
	logent("going down on signal", tet_i2a(sig));
	tet_ss_cleanup();
	/* NOTREACHED */
}

/*
**	tetrootset() - assign a new value to tet_root
**
**	return 0 if successful or -1 on error
*/

int tetrootset(s)
char *s;
{
	(void) sprintf(tet_root, "%.*s", (int) sizeof tet_root - 1, s);
	return(0);
}