xref: /original-bsd/old/berknet/sub.c (revision badf4faa)
1 static char sccsid[] = "@(#)sub.c	4.5	(Berkeley)	01/05/83";
2 
3 /*
4 	sub.c
5 
6 	support procedures
7 
8 	the following procedures end up reading the passwd file
9 	or the passwdf file and are to be avoided.
10 
11 	getpwuid(uid)
12 	getpwnam(sn)
13 	PwdCurrent()
14 	getenv("HOME")		maybe if hget, hgethome don't work
15 	SnFromUid(uid)		maybe if hashed passwd stuff doesn't work
16 	SnCurrent()		maybe if getlogin fails calls SnFromUid(uid)
17 	getpwf()
18 	passwdent(uid,sn)
19 */
20 
21 # include "defs.h"
22 # include "config.h"
23 # include <varargs.h>
24 
25 /* global variables */
26 int debugflg = DBV;	/* debug flag */
27 char local = LOCAL;	/* the machine we're on */
28 struct userinfo status;
29 
30 char netcmd[]  =	NETCMD;
31 char resfile[] = 	RESFILE;
32 char senddir[] =	SENDDIR;
33 char Bsh[] =		BINSH;
34 
35 char shomedir[100];
36 
37 /*
38 	passwdent()
39 
40 	Read the password file looking for current user's entry.
41 	Fill in the status structure.
42 	Has the (dangerous) side effect of giving a value to getenv("HOME").
43 */
passwdent()44 passwdent()
45 {
46 	register char *u;
47 	register struct passwd *pwd;
48 #ifdef CRN
49 	register struct gecos *gcos;
50 #endif
51 	pwd = PwdCurrent();
52 	if(pwd == NULL){
53 		err("Bad uid/username\n");
54 		return;
55 	}
56 	strcpy(status.localname,pwd->pw_name);
57 	status.muid = guid(pwd->pw_uid,pwd->pw_gid);
58 	status.mgid = pwd->pw_gid;
59 #ifdef CRN
60 	if( (gcos=pwgecos( pwd->pw_gecos) ) == NULL )
61 		strcpy( status.jobno, MAGICCRN );
62 	else {
63 		if( debugflg )
64 			debug( "crn found = %s\n", gcos->gc_crn );
65 		if( isalpha( gcos->gc_crn[0] ) ||
66 			isdigit( gcos->gc_crn[0] ) )
67 			strcpy( status.jobno, gcos->gc_crn );
68 		else
69 			strcpy( status.jobno, MAGICCRN );
70 	}
71 #else
72 	strcpy( status.jobno, "XYZZ" );
73 #endif
74 	strcpy(status.dir,pwd->pw_dir);
75 	strcpy(shomedir,pwd->pw_dir);		/* side effect */
76 	u = pwd->pw_shell;
77 	if(u[0] == 0 || strcmp(u,"/bin/sbash") == 0)u= Bsh;
78 	strcpy(status.loginshell,u);
79 	}
80 /*
81 	promptlogin(mchto)
82 
83 	ask user for login and passwd on mchto.
84 	make sure status.localname has a value before calling
85 	this.  One way is to call passwdent().
86 */
promptlogin(mchto)87 promptlogin(mchto)
88 	char mchto;
89 {
90 	char buf[BUFSIZ], mch;
91 	FILE *wf;
92 	int c;
93 	if(status.login[0]==0 || status.force){
94 		buf[0] = 0;
95 		wf = fopen("/dev/tty","r");
96 		if(wf != NULL){
97 			fprintf(stderr,"Name (%s:%s): ",longname(mchto),
98 				status.localname);
99 			if(fgets(buf, BUFSIZ, wf) != buf){
100 				perror("fgets");
101 				exit(EX_OSERR);
102 				}
103 			c = strlen(buf);
104 			buf[c > 0 ? c-1 : 0] = 0;
105 			if(c > 10){
106 				err("Login name too long.\n");
107 				exit(EX_USAGE);
108 				}
109 			if(FMemberSCh(buf,' ')){
110 				err("Login names don't have blanks in them.\n");
111 				exit(EX_USAGE);
112 				}
113 			fclose(wf);
114 			}
115 		if(buf[0] == 0)strcpy(buf,status.localname);
116 		mch = MchSFromAddr(status.login,buf);
117 		if(mch != local && mch != mchto){
118 			err("Must specify login name on %s machine\n",
119 				longname(mchto));
120 			exit(EX_USAGE);
121 			}
122 		}
123 	if(strcmp(status.login,"network") != 0
124 		&& (status.mpasswd[0]== 0 || status.force)){
125 		sprintf(buf,"Password (%s:%s):",
126 			longname(mchto), status.login);
127 		strcpy(status.mpasswd,getpass(buf));
128 		}
129 	if(status.login[0] == 0) strcpy(status.login,status.localname);
130 	if(status.mpasswd[0] == 0)strcpy(status.mpasswd,"\"\"");
131 	status.force = 0;
132 	}
133 
134 #define	tst(a,b)	(*mode == 'r'? (b) : (a))
135 #define	RDR	0
136 #define	WTR	1
137 static	int	popen_pid[20];
138 
139 /* return a file descriptor suitable for writing, send to
140   user toaddress from fromaddress,
141   if cautious != 0 then don't do any forwarding
142   hopcnt is passed thru the mail program.
143 	  normal value is 0
144   */
145 FILE *
mailopen(toaddress,fromaddress,cautious,hopcnt)146 mailopen(toaddress, fromaddress, cautious, hopcnt)
147 char *toaddress, *fromaddress;
148 int cautious, hopcnt;
149 {
150 	char	cmd[100];
151 	char	*mode = "w";
152 	int p[2];
153 	register myside, hisside, pid;
154 	char shopcnt[20];
155 
156 	if(pipe(p) < 0)
157 		return NULL;
158 	myside = tst(p[WTR], p[RDR]);
159 	hisside = tst(p[RDR], p[WTR]);
160 	while((pid = fork()) == -1)sleep(2);
161 	if(pid == 0) {
162 		/* myside and hisside reverse roles in child */
163 		close(myside);
164 		/*
165 		dup2(hisside, tst(0, 1));
166 		*/
167 		close(0);
168 		dup(hisside);
169 		close(hisside);
170 		sprintf(shopcnt,"%d",hopcnt);
171 		if(fromaddress != NULL){
172 			/* by convention, MAILFWD1 may forward this mail
173 			   and response messages shouldn't be forwarded */
174 			if(!cautious && !FMemberSCh(toaddress,'/')){
175 # ifdef SENDMAIL
176 				mexecl("/usr/lib/sendmail",
177 					"sendmail", "-oee", "-r", fromaddress,
178 					"-h",shopcnt, toaddress, 0);
179 # endif SENDMAIL
180 				mexecl(MAILFWD1, "mail","-r",fromaddress,
181 					"-h",shopcnt,toaddress,0);
182 			}
183 			mexecl(SYSMAIL2, "mail","-d","-r",fromaddress,
184 				"-h", shopcnt,toaddress,0);
185 		} else {
186 			if(!cautious && !FMemberSCh(toaddress,'/')){
187 # ifdef SENDMAIL
188 				mexecl("/usr/lib/sendmail",
189 					"sendmail", "-ee", "-h", shopcnt,
190 					toaddress, 0);
191 # endif
192 				mexecl(MAILFWD1, "mail","-h", shopcnt,
193 					toaddress,0);
194 			}
195 			mexecl(SYSMAIL2, "mail","-d","-h", shopcnt,toaddress,0);
196 		}
197 		perror(SYSMAIL2);
198 		exit(EX_UNAVAILABLE);
199 	}
200 	if(pid == -1)
201 		return NULL;
202 	popen_pid[myside] = pid;
203 	close(hisside);
204 	return(fdopen(myside, mode));
205 }
206 
mailclose(ptr)207 mailclose(ptr)
208 FILE *ptr;
209 {
210 	register f, r, (*hstat)(), (*istat)(), (*qstat)();
211 	int status;
212 
213 	f = fileno(ptr);
214 	fclose(ptr);
215 	istat = signal(SIGINT, SIG_IGN);
216 	qstat = signal(SIGQUIT, SIG_IGN);
217 	hstat = signal(SIGHUP, SIG_IGN);
218 	while((r = wait(&status)) != popen_pid[f] && r != -1)
219 		;
220 	if(r == -1)
221 		status = -1;
222 	signal(SIGINT, istat);
223 	signal(SIGQUIT, qstat);
224 	signal(SIGHUP, hstat);
225 	return(status);
226 }
227 
228 /*
229 	ch means 'a'-'z', inx in 0..25
230 	ch means '0'-'9', inx in 26..35
231 */
chtoinx(ch)232 chtoinx(ch) {
233 	if('a' <= ch && ch <= 'z')
234 		return(ch - 'a');
235 	if('0' <= ch && ch <= '9')
236 		return((ch - '0') + 26);
237 	err("bad ch");
238 }
239 
240 /*
241 	inx is 0..25 means 'a'-'z'
242 	inx is 26..35 means '0'-'9'
243 */
inxtoch(inx)244 inxtoch(inx) {
245 	if(0 <= inx && inx <= 25)
246 		return(inx + 'a');
247 	if(26 <= inx && inx <= 35)
248 		return('0' + (inx - 26));
249 	err("bad ch");
250 }
251 
252 /* determine through machine */
gothru(from,to)253 gothru(from,to){
254 	register int i;
255 	switch(from){
256 # ifdef RAND
257 	case 'a':	i = configA[chtoinx(to)]; break;
258 	case 'b':	i = configB[chtoinx(to)]; break;
259 	case 'c':	i = configC[chtoinx(to)]; break;
260 # endif
261 # ifdef NOSC
262 	case 'a':	i = configA[chtoinx(to)]; break;
263 	case 'c':	i = configC[chtoinx(to)]; break;
264 	case 'm':	i = configM[chtoinx(to)]; break;
265 # endif
266 # ifdef BERKELEY
267 	/* for Berkeley */
268 	case 'a':	i = configA[chtoinx(to)]; break;
269 	case 'b':	i = configB[chtoinx(to)]; break;
270 	case 'c':	i = configC[chtoinx(to)]; break;
271 	case 'd':	i = configD[chtoinx(to)]; break;
272 	case 'e':	i = configE[chtoinx(to)]; break;
273 	case 'f':	i = configF[chtoinx(to)]; break;
274 	case 'g':	i = configG[chtoinx(to)]; break;
275 	case 'h':	i = configH[chtoinx(to)]; break;
276 	case 'i':	i = configI[chtoinx(to)]; break;
277 	case 'j':	i = configJ[chtoinx(to)]; break;
278 	case 'k':	i = configK[chtoinx(to)]; break;
279 	case 'l':	i = configL[chtoinx(to)]; break;
280 	case 'm':	i = configM[chtoinx(to)]; break;
281 	case 'n':	i = configN[chtoinx(to)]; break;
282 	case 'o':	i = configO[chtoinx(to)]; break;
283 	case 'p':	i = configP[chtoinx(to)]; break;
284 	case 'r':	i = configR[chtoinx(to)]; break;
285 	case 's':	i = configS[chtoinx(to)]; break;
286 	case 't':	i = configT[chtoinx(to)]; break;
287 	case 'u':	i = configU[chtoinx(to)]; break;
288 	case 'v':	i = configV[chtoinx(to)]; break;
289 	case 'w':	i = configW[chtoinx(to)]; break;
290 	case 'x':	i = configX[chtoinx(to)]; break;
291 	case 'y':	i = configY[chtoinx(to)]; break;
292 	case 'z':	i = configZ[chtoinx(to)]; break;
293 # endif
294 	default:	i = 0; break;
295 	}
296 	return(i);
297 	}
298 
299 # define NPARMS 20
300 /* prints out commands before executing them */
301 /*VARARGS0*/
mexecl(va_alist)302 mexecl(va_alist)
303   	va_dcl
304 {
305 	char *arr[NPARMS], *file, *f;
306 	va_list ap;
307 	register int i;
308 	va_start(ap);
309 	file = va_arg(ap, char *);
310 	i = 0;
311 	while(f = va_arg(ap, char *)){
312 		if(i >= NPARMS){
313 			err("too many args");
314 			arr[NPARMS-1] = NULL;
315 			break;
316 			}
317 		if(debugflg) err("'%s' ",f);
318 		arr[i++] = f;
319 		}
320 	arr[i] = NULL;
321 	va_end(ap);
322 	if(debugflg) putc('\n',stderr);
323 	execv(file, arr);
324 	}
325 
326 /* prints out commands before executing them */
mexecv(s,p)327 mexecv(s,p)
328   register char *s, **p;{
329 	register int i;
330 	if(debugflg){
331 		err("'%s' ",s);
332 		for(i=0; p[i]; i++)err("'%s' ",p[i]);
333 		putc('\n',stderr);
334 		}
335 	execv(s,p);
336 	}
337 
338 /*VARARGS0*/
339 /* fills in -l - -p from commands like rcp */
340 /* must be called with at least two arguments */
kexecl(va_alist)341 kexecl(va_alist)
342   va_dcl
343 {
344 	char *a[NPARMS], i = 1, *file;
345 	va_list ap;
346 	va_start(ap);
347 	file = va_arg(ap, char *);
348 	a[0] = va_arg(ap, char *);
349 	if(status.login[0]){
350 		a[i++] = "-l";
351 		a[i++] = status.login;
352 		}
353 	if(status.mpasswd[0]){
354 		a[i++] = "-p";
355 		a[i++] = status.mpasswd;
356 		}
357 	if(status.nonotify)a[i++] = "-b";
358 	if(status.force)   a[i++] = "-f";
359 	if(status.quiet)   a[i++] = "-q";
360 	if(status.nowrite) a[i++] = "-n";
361 	while (a[i++] = va_arg(ap, char *)){
362 		if(i >= NPARMS){
363 			err("too many args");
364 			a[NPARMS-1] = NULL;
365 			break;
366 			}
367 		};
368 	mexecv(file, a);
369 	}
370 
371 /*
372 	MchSFromAddr(sn,addr)
373 
374 	take an address of the form "mach:username"
375 	and return mch as the 1 char code of "mach" and
376 	in sn put "username".
377 	If addr has no colon in it, return mch==local, sn==addr.
378 	Return 0 for mch if host unknown.
379 */
MchSFromAddr(sn,addr)380 MchSFromAddr(sn,addr)
381 	char *sn, *addr;
382 {
383 	char fcolon = 0, *s, mch, stemp[BUFSIZ];
384 
385 	/* assume addr is a local address */
386 
387 	strcpy(stemp,addr);
388 	s = stemp;
389 	while(*s){
390 		if(*s == ':'){
391 			fcolon = 1;
392 			*s++ = 0;
393 			break;
394 		}
395 		s++;
396 	}
397 	if(fcolon != 1){
398 		/* sn better be the right size for addr */
399 		mch = local;
400 		strcpy(sn,addr);
401 		return(mch);
402 	}
403 
404 	/* addr has a colon in it, s pts to name */
405 	mch = lookup(stemp);
406 	strcpy(sn,s);
407 	return(mch);
408 }
409 
410 
411 /* returns a single character for machine S */
412 /* returns 0 for unknown host */
lookup(s)413 lookup(s)
414   register char *s; {
415 	register struct tt *t;
416 	if(strlen(s) == 1)return(isupper(*s) ? tolower(*s) : *s);
417 	for(t = table; t->bigname; t++)
418 		if(streql(s,t->bigname) == 0)return(t->lname);
419 	return(0);
420 	}
421 
422 /* returns a long name (string) for single character machine c */
longname(c)423 char *longname(c)
424   register char c;
425 	{
426 	register struct tt *t;
427 	if(c == 0)return("UNKNOWN");
428 	for(t = table; t->bigname; t++)
429 		if(c == t->lname)return(t->bigname);
430 	return("UNKNOWN");
431 	}
432 /*
433 	FMemberSCh(s,ch)
434 
435 	return 1 if ch is a character in string s.
436 	0 otherwise.
437 */
FMemberSCh(s,ch)438 FMemberSCh(s,ch)
439 	register char *s, ch;
440 {
441 	while(*s)if(*s++ == ch)return(1);
442 	return(0);
443 }
444 
445 /* return a static string with the form "X hrs X mins X secs" */
446 /* t is # of secs */
comptime(t)447 char *comptime(t)
448   long t; {
449 	static char str[30];
450 	char buf[20];
451 	long w;
452 	str[0] = 0;
453 	w = t/3600L;
454 	if(w > 0L){
455 		sprintf(buf,"%ld hr ",w);
456 		strcat(str,buf);
457 		}
458 	t = t % 3600L;
459 	w = t/60L;
460 	if(w > 0L){
461 		sprintf(buf,"%ld min ",w);
462 		strcat(str,buf);
463 		}
464 	t = t % 60L;
465 	sprintf(buf,"%ld sec",t);
466 	strcat(str,buf);
467 	return(str);
468 	}
469 /*
470 	parseparmlist(string)
471 
472 	parses variable parameter lists in string,
473 	as defined in genparmlist in net.c
474 */
parseparmlist(parmlist)475 parseparmlist(parmlist)
476 	char *parmlist;
477 {
478 	while(*parmlist && *parmlist != '(')parmlist++;
479 }
480 
481 /* just like strcmp except upper- and lower-case are ignored */
streql(s1,s2)482 streql(s1,s2)
483   char *s1, *s2; {
484 	char a,b;
485 	while(*s1 && *s2){
486 		a = isupper(*s1) ? tolower(*s1) : *s1;
487 		b = isupper(*s2) ? tolower(*s2) : *s2;
488 		if(a < b)return(-1);
489 		if(a > b)return(1);
490 		s1++, s2++;
491 		}
492 	if(*s2)return(-1);
493 	if(*s1)return(1);
494 	return(0);
495 	}
496 /* VARARGS0 */
err(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r)497 err(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) {
498 	fprintf(stderr,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r);
499 	}
500