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