1 static char sccsid[] = "@(#)sub.c 4.3 (Berkeley) 10/03/82"; 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 */ 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; 277 case 'h': i = configH[chtoinx(to)]; break; 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; 286 case 'r': i = configR[chtoinx(to)]; break; 287 case 's': i = configS[chtoinx(to)]; break; 288 case 't': i = configT[chtoinx(to)]; break; 289 case 'u': i = configU[chtoinx(to)]; break; 290 case 'v': i = configV[chtoinx(to)]; break; 291 case 'w': i = configW[chtoinx(to)]; break; 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 } 502