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