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 'y': i = configY[to-'a']; break; 245: case 'z': i = configZ[to-'a']; break; 246: # endif 247: default: i = 0; break; 248: } 249: return(i); 250: } 251: /* 252: harg(string,pargc,pargv) 253: 254: A curious procedure which takes a pointer to an argc, and a 255: pointer to an argv, and parses them so that the 256: argument following the flag is copied into string. 257: pargv[0] must be the flag argument. 258: handles both 259: -my 260: and 261: -m y 262: for the net command. 263: */ 264: harg(ans,pargc,pargv) 265: char *ans,*pargc,***pargv;{ 266: if((*pargv)[0][2]) /* no space */ 267: strcpy(ans,(*pargv)[0] + 2); 268: else { /* space, get next arg */ 269: strcpy(ans,(*pargv)[1]); 270: (*pargc)--; 271: (*pargv)++; 272: } 273: } 274: 275: /* prints out commands before executing them */ 276: /*VARARGS0*/ 277: mexecl(s) 278: char *s;{ 279: int *p = (int *)&s; 280: register int i; 281: if(debugflg){ 282: for(i=0; p[i]; i++)err("%s ",p[i]); 283: putc('\n',stderr); 284: } 285: 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], 286: p[12],p[13],p[14],p[15],0); 287: } 288: /* prints out commands before executing them */ 289: mexecv(s,p) 290: register char *s, **p;{ 291: register int i; 292: if(debugflg){ 293: err("%s ",s); 294: for(i=0; p[i]; i++)err("%s ",p[i]); 295: putc('\n',stderr); 296: } 297: execv(s,p); 298: } 299: 300: /*VARARGS0*/ 301: /* fills in -l - -p from commands like rcp */ 302: /* must be called with at least two arguments */ 303: kexecl(s) 304: char *s; { 305: char *a[20], i = 2, j = 2; 306: char **p = (char **)&s; 307: a[0] = p[0]; 308: a[1] = p[1]; 309: if(status.login[0]){ 310: a[i++] = "-l"; 311: a[i++] = status.login; 312: } 313: if(status.mpasswd[0]){ 314: a[i++] = "-p"; 315: a[i++] = status.mpasswd; 316: } 317: if(status.nonotify)a[i++] = "-b"; 318: if(status.force) a[i++] = "-f"; 319: if(status.quiet) a[i++] = "-q"; 320: if(status.nowrite) a[i++] = "-n"; 321: while(p[j])a[i++] = p[j++]; 322: a[i] = 0; 323: 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], 324: a[12],a[13],a[14],a[15],0); 325: } 326: 327: /* 328: MchSFromAddr(sn,addr) 329: 330: take an address of the form "mach:username" 331: and return mch as the 1 char code of "mach" and 332: in sn put "username". 333: If addr has no colon in it, return mch==local, sn==addr. 334: Return 0 for mch if host unknown. 335: */ 336: MchSFromAddr(sn,addr) 337: char *sn, *addr; 338: { 339: char fcolon = 0, *s, mch, stemp[BUFSIZ]; 340: 341: /* assume addr is a local address */ 342: 343: strcpy(stemp,addr); 344: s = stemp; 345: while(*s){ 346: if(*s == ':'){ 347: fcolon = 1; 348: *s++ = 0; 349: break; 350: } 351: s++; 352: } 353: if(fcolon != 1){ 354: /* sn better be the right size for addr */ 355: mch = local; 356: strcpy(sn,addr); 357: return(mch); 358: } 359: 360: /* addr has a colon in it, s pts to name */ 361: mch = lookup(stemp); 362: strcpy(sn,s); 363: return(mch); 364: } 365: 366: 367: /* returns a single character for machine S */ 368: /* returns 0 for unknown host */ 369: lookup(s) 370: register char *s; { 371: register struct tt *t; 372: if(strlen(s) == 1)return(isupper(*s) ? tolower(*s) : *s); 373: for(t = table; t->bigname; t++) 374: if(streql(s,t->bigname) == 0)return(t->lname); 375: return(0); 376: } 377: 378: /* returns a long name (string) for single character machine c */ 379: char *longname(c) 380: register char c; 381: { 382: register struct tt *t; 383: if(c == 0)return("UNKNOWN"); 384: for(t = table; t->bigname; t++) 385: if(c == t->lname)return(t->bigname); 386: return("UNKNOWN"); 387: } 388: /* 389: FMemberSCh(s,ch) 390: 391: return 1 if ch is a character in string s. 392: 0 otherwise. 393: */ 394: FMemberSCh(s,ch) 395: register char *s, ch; 396: { 397: while(*s)if(*s++ == ch)return(1); 398: return(0); 399: } 400: 401: /* return a static string with the form "X hrs X mins X secs" */ 402: /* t is # of secs */ 403: char *comptime(t) 404: long t; { 405: static char str[30]; 406: char buf[20]; 407: long w; 408: str[0] = 0; 409: w = t/3600L; 410: if(w > 0L){ 411: sprintf(buf,"%ld hr ",w); 412: strcat(str,buf); 413: } 414: t = t % 3600L; 415: w = t/60L; 416: if(w > 0L){ 417: sprintf(buf,"%ld min ",w); 418: strcat(str,buf); 419: } 420: t = t % 60L; 421: sprintf(buf,"%ld sec",t); 422: strcat(str,buf); 423: return(str); 424: } 425: /* 426: parseparmlist(string) 427: 428: parses variable parameter lists in string, 429: as defined in genparmlist in net.c 430: */ 431: parseparmlist(parmlist) 432: char *parmlist; 433: { 434: while(*parmlist && *parmlist != '(')parmlist++; 435: } 436: 437: /* just like strcmp except upper- and lower-case are ignored */ 438: streql(s1,s2) 439: char *s1, *s2; { 440: char a,b; 441: while(*s1 && *s2){ 442: a = isupper(*s1) ? tolower(*s1) : *s1; 443: b = isupper(*s2) ? tolower(*s2) : *s2; 444: if(a < b)return(-1); 445: if(a > b)return(1); 446: s1++, s2++; 447: } 448: if(*s2)return(-1); 449: if(*s1)return(1); 450: return(0); 451: } 452: /* VARARGS0 */ 453: err(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) { 454: fprintf(stderr,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r); 455: }