Commit | Line | Data |
---|---|---|
0c4520bd | 1 | static char sccsid[] = "@(#)sub.c 4.4 (Berkeley) %G%"; |
2a56de55 KM |
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" | |
2a56de55 | 23 | # include <varargs.h> |
2a56de55 KM |
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 | */ | |
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 | */ | |
87 | promptlogin(mchto) | |
88 | char mchto; | |
89 | { | |
90 | char buf[BUFSIZ], mch; | |
91 | FILE *wf; | |
92 | int c; | |
93 | if(status.mpasswd[0] == 0 || status.login[0] == 0 || status.force){ | |
94 | wf = fopen("/dev/tty","r"); | |
95 | if(wf != NULL){ | |
96 | if(status.login[0]==0 || status.force){ | |
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 | if(buf[0] == 0)strcpy(buf,status.localname); | |
114 | mch = MchSFromAddr(status.login,buf); | |
115 | if(mch != local && mch != mchto){ | |
116 | err( | |
117 | "Must specify login name on %s machine\n", | |
118 | longname(mchto)); | |
119 | exit(EX_USAGE); | |
120 | } | |
121 | } | |
122 | if(strcmp(status.login,"network") != 0 | |
123 | && (status.mpasswd[0]== 0 || status.force)){ | |
124 | sprintf(buf,"Password (%s:%s):", | |
125 | longname(mchto), status.login); | |
126 | strcpy(status.mpasswd,getpass(buf)); | |
127 | } | |
128 | fclose(wf); | |
129 | } | |
130 | } | |
131 | if(status.login[0] == 0) strcpy(status.login,status.localname); | |
132 | if(status.mpasswd[0] == 0)strcpy(status.mpasswd,"\"\""); | |
133 | status.force = 0; | |
134 | } | |
135 | ||
136 | #define tst(a,b) (*mode == 'r'? (b) : (a)) | |
137 | #define RDR 0 | |
138 | #define WTR 1 | |
139 | static int popen_pid[20]; | |
140 | ||
141 | /* return a file descriptor suitable for writing, send to | |
142 | user toaddress from fromaddress, | |
143 | if cautious != 0 then don't do any forwarding | |
144 | hopcnt is passed thru the mail program. | |
145 | normal value is 0 | |
146 | */ | |
147 | FILE * | |
148 | mailopen(toaddress, fromaddress, cautious, hopcnt) | |
149 | char *toaddress, *fromaddress; | |
150 | int cautious, hopcnt; | |
151 | { | |
152 | char cmd[100]; | |
153 | char *mode = "w"; | |
154 | int p[2]; | |
155 | register myside, hisside, pid; | |
156 | char shopcnt[20]; | |
157 | ||
158 | if(pipe(p) < 0) | |
159 | return NULL; | |
160 | myside = tst(p[WTR], p[RDR]); | |
161 | hisside = tst(p[RDR], p[WTR]); | |
162 | while((pid = fork()) == -1)sleep(2); | |
163 | if(pid == 0) { | |
164 | /* myside and hisside reverse roles in child */ | |
165 | close(myside); | |
166 | /* | |
167 | dup2(hisside, tst(0, 1)); | |
168 | */ | |
169 | close(0); | |
170 | dup(hisside); | |
171 | close(hisside); | |
172 | sprintf(shopcnt,"%d",hopcnt); | |
173 | if(fromaddress != NULL){ | |
174 | /* by convention, MAILFWD1 may forward this mail | |
175 | and response messages shouldn't be forwarded */ | |
176 | if(!cautious && !FMemberSCh(toaddress,'/')){ | |
177 | # ifdef DELIVERM | |
178 | mexecl("/etc/delivermail", | |
179 | "delivermail", "-ee", "-r", fromaddress, | |
180 | "-h",shopcnt, toaddress, 0); | |
181 | # endif | |
182 | mexecl(MAILFWD1, "mail","-r",fromaddress, | |
183 | "-h",shopcnt,toaddress,0); | |
184 | } | |
185 | mexecl(SYSMAIL2, "mail","-d","-r",fromaddress, | |
186 | "-h", shopcnt,toaddress,0); | |
187 | } else { | |
188 | if(!cautious && !FMemberSCh(toaddress,'/')){ | |
189 | # ifdef DELIVERM | |
190 | mexecl("/etc/delivermail", | |
191 | "delivermail", "-ee", "-h", shopcnt, | |
192 | toaddress, 0); | |
193 | # endif | |
194 | mexecl(MAILFWD1, "mail","-h", shopcnt, | |
195 | toaddress,0); | |
196 | } | |
197 | mexecl(SYSMAIL2, "mail","-d","-h", shopcnt,toaddress,0); | |
198 | } | |
199 | perror(SYSMAIL2); | |
200 | exit(EX_UNAVAILABLE); | |
201 | } | |
202 | if(pid == -1) | |
203 | return NULL; | |
204 | popen_pid[myside] = pid; | |
205 | close(hisside); | |
206 | return(fdopen(myside, mode)); | |
207 | } | |
208 | ||
209 | mailclose(ptr) | |
210 | FILE *ptr; | |
211 | { | |
212 | register f, r, (*hstat)(), (*istat)(), (*qstat)(); | |
213 | int status; | |
214 | ||
215 | f = fileno(ptr); | |
216 | fclose(ptr); | |
217 | istat = signal(SIGINT, SIG_IGN); | |
218 | qstat = signal(SIGQUIT, SIG_IGN); | |
219 | hstat = signal(SIGHUP, SIG_IGN); | |
220 | while((r = wait(&status)) != popen_pid[f] && r != -1) | |
221 | ; | |
222 | if(r == -1) | |
223 | status = -1; | |
224 | signal(SIGINT, istat); | |
225 | signal(SIGQUIT, qstat); | |
226 | signal(SIGHUP, hstat); | |
227 | return(status); | |
228 | } | |
229 | ||
230 | /* | |
231 | ch means 'a'-'z', inx in 0..25 | |
232 | ch means '0'-'9', inx in 26..35 | |
233 | */ | |
234 | chtoinx(ch) { | |
235 | if('a' <= ch && ch <= 'z') | |
236 | return(ch - 'a'); | |
237 | if('0' <= ch && ch <= '9') | |
238 | return((ch - '0') + 26); | |
239 | err("bad ch"); | |
240 | } | |
241 | ||
242 | /* | |
243 | inx is 0..25 means 'a'-'z' | |
244 | inx is 26..35 means '0'-'9' | |
245 | */ | |
246 | inxtoch(inx) { | |
247 | if(0 <= inx && inx <= 25) | |
248 | return(inx + 'a'); | |
249 | if(26 <= inx && inx <= 35) | |
250 | return('0' + (inx - 26)); | |
251 | err("bad ch"); | |
252 | } | |
253 | ||
254 | /* determine through machine */ | |
255 | gothru(from,to){ | |
256 | register int i; | |
257 | switch(from){ | |
258 | # ifdef RAND | |
259 | case 'a': i = configA[chtoinx(to)]; break; | |
260 | case 'b': i = configB[chtoinx(to)]; break; | |
261 | case 'c': i = configC[chtoinx(to)]; break; | |
262 | # endif | |
263 | # ifdef NOSC | |
264 | case 'a': i = configA[chtoinx(to)]; break; | |
265 | case 'c': i = configC[chtoinx(to)]; break; | |
266 | case 'm': i = configM[chtoinx(to)]; break; | |
267 | # endif | |
268 | # ifdef BERKELEY | |
269 | /* for Berkeley */ | |
270 | case 'a': i = configA[chtoinx(to)]; break; | |
271 | case 'b': i = configB[chtoinx(to)]; break; | |
272 | case 'c': i = configC[chtoinx(to)]; break; | |
273 | case 'd': i = configD[chtoinx(to)]; break; | |
274 | case 'e': i = configE[chtoinx(to)]; break; | |
275 | case 'f': i = configF[chtoinx(to)]; break; | |
276 | case 'g': i = configG[chtoinx(to)]; break; | |
0b4e7efb | 277 | case 'h': i = configH[chtoinx(to)]; break; |
2a56de55 KM |
278 | case 'i': i = configI[chtoinx(to)]; break; |
279 | case 'j': i = configJ[chtoinx(to)]; break; | |
280 | case 'k': i = configK[chtoinx(to)]; break; | |
281 | case 'l': i = configL[chtoinx(to)]; break; | |
282 | case 'm': i = configM[chtoinx(to)]; break; | |
283 | case 'n': i = configN[chtoinx(to)]; break; | |
284 | case 'o': i = configO[chtoinx(to)]; break; | |
285 | case 'p': i = configP[chtoinx(to)]; break; | |
2a56de55 KM |
286 | case 'r': i = configR[chtoinx(to)]; break; |
287 | case 's': i = configS[chtoinx(to)]; break; | |
288 | case 't': i = configT[chtoinx(to)]; break; | |
0b4e7efb | 289 | case 'u': i = configU[chtoinx(to)]; break; |
2a56de55 | 290 | case 'v': i = configV[chtoinx(to)]; break; |
0b4e7efb | 291 | case 'w': i = configW[chtoinx(to)]; break; |
2a56de55 KM |
292 | case 'x': i = configX[chtoinx(to)]; break; |
293 | case 'y': i = configY[chtoinx(to)]; break; | |
294 | case 'z': i = configZ[chtoinx(to)]; break; | |
295 | # endif | |
296 | default: i = 0; break; | |
297 | } | |
298 | return(i); | |
299 | } | |
300 | ||
301 | # define NPARMS 20 | |
302 | /* prints out commands before executing them */ | |
303 | /*VARARGS0*/ | |
304 | mexecl(va_alist) | |
305 | va_dcl | |
306 | { | |
307 | char *arr[NPARMS], *file, *f; | |
308 | va_list ap; | |
309 | register int i; | |
310 | va_start(ap); | |
311 | file = va_arg(ap, char *); | |
312 | i = 0; | |
313 | while(f = va_arg(ap, char *)){ | |
314 | if(i >= NPARMS){ | |
315 | err("too many args"); | |
316 | arr[NPARMS-1] = NULL; | |
317 | break; | |
318 | } | |
319 | if(debugflg) err("'%s' ",f); | |
320 | arr[i++] = f; | |
321 | } | |
322 | arr[i] = NULL; | |
323 | va_end(ap); | |
324 | if(debugflg) putc('\n',stderr); | |
325 | execv(file, arr); | |
326 | } | |
327 | ||
328 | /* prints out commands before executing them */ | |
329 | mexecv(s,p) | |
330 | register char *s, **p;{ | |
331 | register int i; | |
332 | if(debugflg){ | |
333 | err("'%s' ",s); | |
334 | for(i=0; p[i]; i++)err("'%s' ",p[i]); | |
335 | putc('\n',stderr); | |
336 | } | |
337 | execv(s,p); | |
338 | } | |
339 | ||
340 | /*VARARGS0*/ | |
341 | /* fills in -l - -p from commands like rcp */ | |
342 | /* must be called with at least two arguments */ | |
343 | kexecl(va_alist) | |
344 | va_dcl | |
345 | { | |
346 | char *a[NPARMS], i = 1, *file; | |
347 | va_list ap; | |
348 | va_start(ap); | |
349 | file = va_arg(ap, char *); | |
350 | a[0] = va_arg(ap, char *); | |
351 | if(status.login[0]){ | |
352 | a[i++] = "-l"; | |
353 | a[i++] = status.login; | |
354 | } | |
355 | if(status.mpasswd[0]){ | |
356 | a[i++] = "-p"; | |
357 | a[i++] = status.mpasswd; | |
358 | } | |
359 | if(status.nonotify)a[i++] = "-b"; | |
360 | if(status.force) a[i++] = "-f"; | |
361 | if(status.quiet) a[i++] = "-q"; | |
362 | if(status.nowrite) a[i++] = "-n"; | |
363 | while (a[i++] = va_arg(ap, char *)){ | |
364 | if(i >= NPARMS){ | |
365 | err("too many args"); | |
366 | a[NPARMS-1] = NULL; | |
367 | break; | |
368 | } | |
369 | }; | |
370 | mexecv(file, a); | |
371 | } | |
372 | ||
373 | /* | |
374 | MchSFromAddr(sn,addr) | |
375 | ||
376 | take an address of the form "mach:username" | |
377 | and return mch as the 1 char code of "mach" and | |
378 | in sn put "username". | |
379 | If addr has no colon in it, return mch==local, sn==addr. | |
380 | Return 0 for mch if host unknown. | |
381 | */ | |
382 | MchSFromAddr(sn,addr) | |
383 | char *sn, *addr; | |
384 | { | |
385 | char fcolon = 0, *s, mch, stemp[BUFSIZ]; | |
386 | ||
387 | /* assume addr is a local address */ | |
388 | ||
389 | strcpy(stemp,addr); | |
390 | s = stemp; | |
391 | while(*s){ | |
392 | if(*s == ':'){ | |
393 | fcolon = 1; | |
394 | *s++ = 0; | |
395 | break; | |
396 | } | |
397 | s++; | |
398 | } | |
399 | if(fcolon != 1){ | |
400 | /* sn better be the right size for addr */ | |
401 | mch = local; | |
402 | strcpy(sn,addr); | |
403 | return(mch); | |
404 | } | |
405 | ||
406 | /* addr has a colon in it, s pts to name */ | |
407 | mch = lookup(stemp); | |
408 | strcpy(sn,s); | |
409 | return(mch); | |
410 | } | |
411 | ||
412 | ||
413 | /* returns a single character for machine S */ | |
414 | /* returns 0 for unknown host */ | |
415 | lookup(s) | |
416 | register char *s; { | |
417 | register struct tt *t; | |
418 | if(strlen(s) == 1)return(isupper(*s) ? tolower(*s) : *s); | |
419 | for(t = table; t->bigname; t++) | |
420 | if(streql(s,t->bigname) == 0)return(t->lname); | |
421 | return(0); | |
422 | } | |
423 | ||
424 | /* returns a long name (string) for single character machine c */ | |
425 | char *longname(c) | |
426 | register char c; | |
427 | { | |
428 | register struct tt *t; | |
429 | if(c == 0)return("UNKNOWN"); | |
430 | for(t = table; t->bigname; t++) | |
431 | if(c == t->lname)return(t->bigname); | |
432 | return("UNKNOWN"); | |
433 | } | |
434 | /* | |
435 | FMemberSCh(s,ch) | |
436 | ||
437 | return 1 if ch is a character in string s. | |
438 | 0 otherwise. | |
439 | */ | |
440 | FMemberSCh(s,ch) | |
441 | register char *s, ch; | |
442 | { | |
443 | while(*s)if(*s++ == ch)return(1); | |
444 | return(0); | |
445 | } | |
446 | ||
447 | /* return a static string with the form "X hrs X mins X secs" */ | |
448 | /* t is # of secs */ | |
449 | char *comptime(t) | |
450 | long t; { | |
451 | static char str[30]; | |
452 | char buf[20]; | |
453 | long w; | |
454 | str[0] = 0; | |
455 | w = t/3600L; | |
456 | if(w > 0L){ | |
457 | sprintf(buf,"%ld hr ",w); | |
458 | strcat(str,buf); | |
459 | } | |
460 | t = t % 3600L; | |
461 | w = t/60L; | |
462 | if(w > 0L){ | |
463 | sprintf(buf,"%ld min ",w); | |
464 | strcat(str,buf); | |
465 | } | |
466 | t = t % 60L; | |
467 | sprintf(buf,"%ld sec",t); | |
468 | strcat(str,buf); | |
469 | return(str); | |
470 | } | |
471 | /* | |
472 | parseparmlist(string) | |
473 | ||
474 | parses variable parameter lists in string, | |
475 | as defined in genparmlist in net.c | |
476 | */ | |
477 | parseparmlist(parmlist) | |
478 | char *parmlist; | |
479 | { | |
480 | while(*parmlist && *parmlist != '(')parmlist++; | |
481 | } | |
482 | ||
483 | /* just like strcmp except upper- and lower-case are ignored */ | |
484 | streql(s1,s2) | |
485 | char *s1, *s2; { | |
486 | char a,b; | |
487 | while(*s1 && *s2){ | |
488 | a = isupper(*s1) ? tolower(*s1) : *s1; | |
489 | b = isupper(*s2) ? tolower(*s2) : *s2; | |
490 | if(a < b)return(-1); | |
491 | if(a > b)return(1); | |
492 | s1++, s2++; | |
493 | } | |
494 | if(*s2)return(-1); | |
495 | if(*s1)return(1); | |
496 | return(0); | |
497 | } | |
498 | /* VARARGS0 */ | |
499 | err(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) { | |
500 | fprintf(stderr,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r); | |
501 | } |