Commit | Line | Data |
---|---|---|
e804469b | 1 | static char sccsid[] = "@(#)sub.c 4.5 (Berkeley) 1/5/83"; |
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; | |
7319947c EA |
93 | if(status.login[0]==0 || status.force){ |
94 | buf[0] = 0; | |
2a56de55 KM |
95 | wf = fopen("/dev/tty","r"); |
96 | if(wf != NULL){ | |
7319947c EA |
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); | |
2a56de55 | 102 | } |
7319947c EA |
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); | |
2a56de55 KM |
112 | } |
113 | fclose(wf); | |
114 | } | |
7319947c EA |
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)); | |
2a56de55 KM |
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 * | |
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,'/')){ | |
407f19f7 EA |
175 | # ifdef SENDMAIL |
176 | mexecl("/usr/lib/sendmail", | |
177 | "sendmail", "-oee", "-r", fromaddress, | |
2a56de55 | 178 | "-h",shopcnt, toaddress, 0); |
407f19f7 | 179 | # endif SENDMAIL |
2a56de55 KM |
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,'/')){ | |
407f19f7 EA |
187 | # ifdef SENDMAIL |
188 | mexecl("/usr/lib/sendmail", | |
189 | "sendmail", "-ee", "-h", shopcnt, | |
2a56de55 KM |
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 | ||
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 | */ | |
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 | */ | |
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 */ | |
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; | |
0b4e7efb | 275 | case 'h': i = configH[chtoinx(to)]; break; |
2a56de55 KM |
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; | |
2a56de55 KM |
284 | case 'r': i = configR[chtoinx(to)]; break; |
285 | case 's': i = configS[chtoinx(to)]; break; | |
286 | case 't': i = configT[chtoinx(to)]; break; | |
0b4e7efb | 287 | case 'u': i = configU[chtoinx(to)]; break; |
2a56de55 | 288 | case 'v': i = configV[chtoinx(to)]; break; |
0b4e7efb | 289 | case 'w': i = configW[chtoinx(to)]; break; |
2a56de55 KM |
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*/ | |
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 */ | |
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 */ | |
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 | */ | |
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 */ | |
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 */ | |
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 | */ | |
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 */ | |
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 | */ | |
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 */ | |
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 */ | |
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 | } |