Annotation of 3BSD/cmd/net/net.c, revision 1.1.1.1

1.1       root        1: # include "defs.h"
                      2: /* must be setuid root */
                      3: /*
                      4:        net - -b -c cmd -f -i file -l name -mmach -n -o file -p passwd
                      5:                -r file -s file -u uid -w -x -y -z command
                      6:                
                      7:        -       take from standard input
                      8:        -b      never send anything back
                      9:        -c cmd  think of this as a "cmd" *
                     10:        -f      force prompting of user name and password
                     11:        -i file remote stdin *
                     12:        -l name remote login name
                     13:        -m Mach remote machine
                     14:        -n      do not write back anything, always mail them back
                     15:        -o file remote stdout & stderr *
                     16:        -p pass remote password
                     17:        -q      quiet option, send back only if rcode !=0 or if there is stdout
                     18:        -r file local response file
                     19:        -s file local stdin file *
                     20:        
                     21:        (super users only, always skip login/passwd check:)
                     22:        -u uid  net queue files should be owned by uid (16 bits)
                     23:        -w      this is a write/mail response cmd *
                     24:        -x      this is being forwarded through us to another machine *
                     25:        -y      skip login/password check *
                     26:        -z      this is a response file being returned *
                     27: 
                     28:        * = not documented in net(NEW)
                     29:        
                     30: */
                     31: /*
                     32:        code    option  reason
                     33:        q               normal request
                     34:        w       -w      message to be written back
                     35:                -x      being forwarded through us
                     36:        y       -y      simply skips login check (used by netlpr)
                     37:        s       -z      normal response
                     38: */
                     39: static char dfname[]=          DFNAME;
                     40: 
                     41: main(argc, argv)
                     42:   char **argv; {
                     43:        register int i;
                     44:        int outerror(),uid;
                     45:        char *genparmlist();
                     46:        char resp[FNS], infile[FNS], outfile[FNS], localin[FNS];
                     47:        char buf[BUFSIZ], suid[10];
                     48:        char sin =0, code, zopt = 0, wopt = 0, yopt = 0, xopt = 0;
                     49:        char *s,*sn;
                     50:        char sTtyname[20], sCmdAct[BUFSIZ], sCmdVirt[BUFSIZ];
                     51:        long cnt = 0L, maxfile = MAXFILE, lTtytime;
                     52:        char cflag = 'a';
                     53:        FILE *file, *temp, *rfile;
                     54:        struct utmp utmpstr;
                     55:        struct stat statbuf;
                     56: 
                     57:        debugflg = DBV;
                     58:        argv[argc] = 0;
                     59:        sCmdAct[0] = resp[0] = outfile[0] = infile[0] = 0;
                     60:        sCmdVirt[0] = localin[0] = 0;
                     61:        sTtyname[0] = 0;
                     62:        suid[0] = 0;
                     63: 
                     64:        if(isatty(0)) strcat(sTtyname,ttyname(0));
                     65:        else if(isatty(2)) strcat(sTtyname,ttyname(2));
                     66:        remote = 0;
                     67:        signal(SIGHUP,outerror);
                     68:        signal(SIGQUIT,outerror);
                     69:        signal(SIGINT,outerror);
                     70:        signal(SIGTRM,outerror);
                     71: 
                     72:        while(argc > 1 && argv[1][0] == '-'){
                     73:                argc--; argv++;
                     74:                switch(argv[0][1]){
                     75:                case 0:   sin++; break;
                     76:                case 'b': status.nonotify++; break;
                     77:                case 'c': harg(sCmdVirt,&argc,&argv); break;
                     78:                case 'f': status.force++; break;
                     79:                case 'i': harg(infile,&argc,&argv); break;
                     80:                case 'l': harg(status.login,&argc,&argv); break;
                     81:                case 'm': harg(buf,&argc,&argv); remote = lookup(buf); break;
                     82:                case 'n': status.nowrite++; break;
                     83:                case 'o': harg(outfile,&argc,&argv); break;
                     84:                case 'p':
                     85:                          harg(status.mpasswd,&argc,&argv);
                     86:                          if(status.mpasswd[0] == 0)
                     87:                                strcpy(status.mpasswd,"\n\n");
                     88:                          break;
                     89:                case 'q': status.quiet++; break;
                     90:                case 'r': harg(buf,&argc,&argv); addir(resp,buf); break;
                     91:                case 's': harg(localin,&argc,&argv); break;
                     92:                case 'u': harg(suid,&argc,&argv); break;
                     93:                case 'w': wopt++; break;
                     94:                case 'x': xopt++; break;
                     95:                case 'y': yopt++; break;
                     96:                case 'z': zopt++; break;
                     97:                default:
                     98:                        fprintf(stderr,"Unknown option %s\n",argv[0]);
                     99:                        break;
                    100:                }
                    101:                }
                    102:        while(argc > 1){
                    103:                argc--; argv++;
                    104:                strcat(sCmdAct,argv[0]);
                    105:                strcat(sCmdAct," ");
                    106:                }
                    107:        uid = getuid();
                    108:        code = 'q';
                    109:        if(zopt || wopt || yopt || xopt || suid[0] != 0){
                    110:                /* check z or w or y or x option permission */
                    111: # ifndef TESTING
                    112:                if(uid != SUPERUSER){
                    113:                        fprintf(stderr,"Error: Not super-user");
                    114:                        outerror();
                    115:                        }
                    116: # endif
                    117:                code = zopt ? 's' : 'w';
                    118:                code = yopt ? 'y' : code;
                    119:                if(status.mpasswd[0] == 0)      /* no passwd required */
                    120:                        strcpy(status.mpasswd,"\n");
                    121:                }
                    122: 
                    123:        status.jobno = 32767;           /* default (invalid) job number */
                    124:        if(code == 'q' && !xopt){
                    125:                if((sn = SnCurrent()) == NULL
                    126:                /* || machtype[local-'a'] == M_CC */)
                    127:                        /* turns out we never use jobno, except in netlpr */
                    128:                        /* read passwd file, get status.localname & jobno */
                    129:                        passwdent();
                    130:                else
                    131:                        /* don't bother reading passwd file, don't need jobno */
                    132:                        strcpy(status.localname,sn);
                    133:        }
                    134: 
                    135:        /* sets remote,status.login,status.force,status.mpasswd,
                    136:                status.nonotify, status.nowrite */
                    137:        /* may read passwd file if getenv(HOME) reads it */
                    138:        commandfile();
                    139: 
                    140:        if(remote == 0)remote = getremote(local);
                    141: # ifndef TESTING
                    142:        if(remote == local){
                    143:                fprintf(stderr,"Request sent to local machine - doesn't make sense\n");
                    144:                /* outerror(); */
                    145:                }
                    146: # endif
                    147:        strcat(status.defcmd," ");
                    148:        if(strlen(sCmdAct) == 0)strcpy(sCmdAct,status.defcmd);
                    149:        sCmdAct[strlen(sCmdAct)-1] = 0;
                    150:        mktemp(dfname);
                    151:        /* determine through machine */
                    152:        i = gothru(local,remote);
                    153:        if(i == 0){
                    154:                s = longname(remote);
                    155:                if(s != 0)fprintf(stderr,"No path to %s machine.\n",s);
                    156:                else fprintf(stderr,"Unknown machine\n");
                    157:                outerror();
                    158:                }
                    159:        dfname[strlen(dfname)-11] = i;          /* set directory */
                    160:        dfname[strlen(dfname)-7] = i;           /* set file (unused) */
                    161:        /* check to see if data files are directories */
                    162:        if(isdirectory(resp) || isdirectory(infile) || isdirectory(outfile)){
                    163:                fprintf(stderr,"%s is a directory, must be a file\n",
                    164:                        isdirectory(resp)    ? resp :
                    165:                        isdirectory(infile)  ? infile :
                    166:                        outfile);
                    167:                outerror();
                    168:        }
                    169:        if(suid[0] != 0)uid = atoi(suid);
                    170:        if(resp[0]){
                    171:                if(strcmp(resp,"/dev/tty") == 0){
                    172:                fprintf(stderr,"Can't have /dev/tty as response file.\n");
                    173:                        outerror();
                    174:                        }
                    175:                if(stat(resp,&statbuf) == -1){
                    176:                        strcpy(buf,resp);
                    177:                        s = &buf[0];
                    178:                        s = s + strlen(buf) - 1;
                    179:                        while(*s != '/' && s > &(buf[0]))s--;
                    180:                        *s = 0;
                    181:                        debug("chkdir %s",buf);
                    182:                        if(strlen(buf) == 0)strcpy(buf,".");
                    183:                        if(access(buf,2) == -1){
                    184:                                perror(buf);
                    185:                                outerror();
                    186:                                }
                    187:                        if((rfile=fopen(resp,"w")) == NULL){
                    188:                                perror(resp);
                    189:                                outerror();
                    190:                                }
                    191:                        chmod(resp,0600);
                    192:                        fclose(rfile);
                    193:                        mchown(resp,uid,getgid());
                    194:                        }
                    195:                else if(access(resp,2) == -1){
                    196:                        perror(resp);
                    197:                        outerror();
                    198:                        }
                    199:                }
                    200:        /* go ahead and prompt for login name and passwd, if neccessary,
                    201:           as long as the X option has not been specified */
                    202:        if(code == 'q' && !xopt)promptlogin(remote);
                    203: 
                    204:        /* at this point, we create the dfa... file */
                    205:        file = fopen(dfname,"w");
                    206:        if(file == NULL){
                    207:                perror(dfname);
                    208:                outerror();
                    209:                }
                    210:        chmod(dfname,0600);
                    211:        mchown(dfname,uid,getgid());
                    212:        if(xopt)goto stickit;
                    213:        if(status.mpasswd[0] == '\n')
                    214:                status.mpasswd[0] = 0;
                    215: # ifndef NEWPROT
                    216:        if(machtype[local-'a'] == M_CC && machtype[remote-'a'] == M_CC
                    217:                && status.mpasswd[0] != 0){
                    218:                s = crypt(status.mpasswd);
                    219:                strcpy(status.mpasswd,s);
                    220:                }
                    221: # endif
                    222:        if(status.mpasswd[0] == 0 && code == 'q' &&
                    223:                strcmp(status.login,"network") != 0){
                    224:                fprintf(stderr,"Zero-length password not allowed\n");
                    225:                outerror();
                    226:                }
                    227:        if(code == 'q' && (streql(status.login,"root") == 0 ||
                    228:                streql(status.login,"ruut") == 0)){
                    229:                fprintf(stderr,"Can't login as root through the network\n");
                    230:                outerror();
                    231:                }
                    232: # ifdef SPACCT
                    233:        /* handle special accounts */
                    234:        /* give a value for mgid and muid */
                    235:        strcpy(status.mpasswd,handlesp(status.login,status.mpasswd,
                    236:                status.localname,status.muid,status.mgid));
                    237: # endif
                    238:        enmask(status.mpasswd);
                    239:        lTtytime = 0;
                    240:        if(sTtyname[0] && status.nowrite == 0){
                    241:                temp = fopen("/etc/utmp","r");
                    242:                if(temp == NULL){
                    243:                        perror("/etc/utmp");
                    244:                        outerror();
                    245:                        }
                    246:                while(fread(&utmpstr,1,sizeof utmpstr,temp) == sizeof utmpstr)
                    247: # ifdef OLDTTY
                    248:                        if(utmpstr.ut_tty == sTtyname[8]){
                    249: # else
                    250:                        if(strcmp(utmpstr.ut_line,sTtyname+5) == 0){
                    251: # endif
                    252:                                lTtytime = utmpstr.ut_time;
                    253:                                break;
                    254:                                }
                    255:                }
                    256: /*
                    257:        debug("p:%s:\n",status.mpasswd);
                    258: */
                    259:        /* cflag is initially 'a'. Add the flags as needed. */
                    260:        if(status.nonotify)cflag += F_NONOTIFY;
                    261:        if(status.quiet)cflag += F_QUIET;
                    262: /*
                    263:        protocol:
                    264:        code, remote mach, local mach, version stamp (2), remote login name,
                    265:        password, -i, -o, -r files,
                    266:        local login name, terminal, flag, utmp tty login time,
                    267:        cc jobno(variable parameter list), current time,
                    268:        command '\n' real command '\n'
                    269:        any data
                    270:        
                    271:        changes:
                    272:        1) remove header
                    273:        3) use ascii length instead of 4 bytes
                    274:        4) encrypt the login name, command, and part of data as well
                    275: */
                    276: 
                    277:        fprintf(file,
                    278:        "%c :%c :%c :%c :%c :%s :%s :%s :%s :%s :%s :%s :%c :%lo :%d%s :%ld :",
                    279:                code,remote,local,VMAJOR+'a',VMINOR+'a',status.login,
                    280:                status.mpasswd,infile,outfile,resp,
                    281:                status.localname,sTtyname,cflag,lTtytime,
                    282:                status.jobno,genparmlist(),gettime()-TIMEBASE);
                    283:        fputs(sCmdAct,file);
                    284:        putc('\n',file);
                    285:        fputs(sCmdVirt,file);
                    286:        putc('\n',file);
                    287: stickit:
                    288:        /* between ingres machines, allow long files */
                    289:        /* this should be parametrized on a per machine pair basis */
                    290:        if(machtype[local  - 'a'] == M_INGRES &&
                    291:           machtype[remote - 'a'] == M_INGRES)
                    292:                maxfile = MAXFILELARGE;
                    293:        if(sin)
                    294:                while((i = fread(buf,1,BUFSIZ,stdin)) > 0){
                    295:                        if(fwrite(buf,1,i,file) != i){
                    296:                                perror("net queue file");
                    297:                                outerror();
                    298:                                }
                    299:                        if((cnt += i) > maxfile)goto toobig;
                    300:                        if(feof(stdin))break;
                    301:                        }
                    302:        else if(localin[0]){
                    303:                if(access(localin,4) == -1){
                    304:                        perror(localin);
                    305:                        outerror();
                    306:                        }
                    307:                temp = fopen(localin,"r");
                    308:                if(temp == NULL){
                    309:                        perror(localin);
                    310:                        outerror();
                    311:                        }
                    312:                while((i = fread(buf,1,BUFSIZ,temp)) > 0){
                    313:                        if((cnt += i) > maxfile)goto toobig;
                    314:                        if(fwrite(buf,1,i,file) != i){
                    315:                                perror("net queue file");
                    316:                                outerror();
                    317:                                }
                    318:                        }
                    319:                fclose(temp);
                    320:                }
                    321:        fclose(file);
                    322:        chmod(dfname,0400);
                    323:        dfname[strlen(dfname)-9] = 'c';
                    324:        file = fopen(dfname,"w");
                    325:        chmod(dfname,0400);
                    326:        fclose(file);
                    327:        mchown(dfname,uid,getgid());
                    328:        exit(0);
                    329: toobig:
                    330:        fprintf(stderr,"No more than %ld bytes can be sent\n",maxfile);
                    331:        outerror();             /* no return */
                    332:        }
                    333: /* 
                    334:    called if there is an error, makes sure that the files created
                    335:    are deleted and the terminal is reset to echo
                    336: */
                    337: outerror(){
                    338:        register int i;
                    339:        struct sgttyb stt;
                    340:        signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN);
                    341:        signal(SIGQUIT,SIG_IGN); signal(SIGTRM,SIG_IGN);
                    342:        unlink(dfname);
                    343:        i = strlen(dfname) - 9;
                    344:        dfname[i] = (dfname[i] == 'c' ? 'd' : 'c');
                    345:        unlink(dfname);
                    346:        if(gtty(0,&stt) >= 0){
                    347:                stt.sg_flags |= ECHO;
                    348:                stty(0,&stt);
                    349:                }
                    350:        exit(1);
                    351:        }
                    352: enmask(s)
                    353:   register char *s; {
                    354: # ifdef NEWPROT
                    355:        static char buf[20];
                    356:        strcpy(s,nbsencrypt(s,THEKEY,buf));
                    357: # else
                    358:        while(*s){
                    359:                *s &= 0177;             /* strip quote bites */
                    360:                *s++ ^= 040;            /* invert upper-lower */
                    361:                }
                    362: # endif
                    363:        }
                    364: addir(s,t)
                    365:   register char *s, *t; {
                    366:        if(t[0] == '/')strcpy(s,t);
                    367:        else {
                    368:                gwd(s);
                    369:                strcat(s,t);
                    370:                }
                    371:        }
                    372: /* returns pass if not special, otherwise returns funny passwd */
                    373: /* list of special accounts must be consistent - with netdaemon.c */
                    374: char *handlesp(log,pass,localname,luid,lgid)
                    375: char *log,*pass,*localname;{
                    376:        /* experimental */
                    377: # ifdef SPACCT
                    378:        long lt;
                    379:        char str[20];
                    380:        if(strcmp(log,localname) == 0 && luid != 0 && lgid == 0 && (
                    381:        strcmp(log,"source") == 0
                    382:        || strcmp(log,"daemon") == 0
                    383:        )) {
                    384:                lt = lgid;
                    385:                lt = (lt << 16) | luid;
                    386:                sprintf(str,"%ld",lt);
                    387:                return(str);
                    388:                }
                    389: # endif
                    390:        return(pass);
                    391:        }
                    392: 
                    393: 
                    394: 
                    395: static struct stat x;
                    396: static struct direct y;
                    397: static FILE *file;
                    398: static int off = -1;
                    399: 
                    400: 
                    401: /* these three routines gwd, cat, ckroot and 
                    402:    data structures x, y, off, do a pwd to string name */
                    403: gwd(name)
                    404:   register char *name; {
                    405:        *name = 0;
                    406:        for(;;){
                    407:                stat(".",&x);
                    408:                if((file = fopen("..","r")) == NULL)break;
                    409:                do {
                    410:                        if(fread(&y,1,sizeof y,file) != sizeof y)break;
                    411:                        } while(y.d_ino != x.st_ino);
                    412:                fclose(file);
                    413:                if(y.d_ino == ROOTINO){
                    414:                        ckroot(name);
                    415:                        break;
                    416:                        }
                    417:                if(cat(name))break;
                    418:                chdir("..");
                    419:                }
                    420:        chdir(name);
                    421:        }
                    422: 
                    423: cat(name)
                    424:   register char *name; {               /* return 1 to exit */
                    425:        register int i,j;
                    426:        i = -1;
                    427:        while(y.d_name[++i] != 0);
                    428:        if((off+i+2) > 511)return(1);
                    429:        for(j = off +1; j >= 0; --j)name[j+i+1] = name[j];
                    430:        off = i + off + 1;
                    431:        name[i] = '/';
                    432:        for(--i; i>= 0; --i)name[i] = y.d_name[i];
                    433:        return(0);
                    434:        }
                    435: 
                    436: ckroot(name)
                    437:   char *name; {
                    438:        register int i;
                    439:        if(stat(y.d_name,&x) < 0)return;
                    440:        i = x.st_dev;
                    441:        if(chdir("/") < 0)return;
                    442:        if((file = fopen("/","r")) == NULL)return;
                    443:        do {
                    444:                if(fread(&y,1,sizeof y,file) != sizeof y)return;
                    445:                if(y.d_ino == 0)continue;
                    446:                if(stat(y.d_name,&x) < 0)return;
                    447:                } while(x.st_dev!=i || (x.st_mode&S_IFMT)!=S_IFDIR);
                    448:        if(strcmp(y.d_name,".") != 0 && strcmp(y.d_name,"..") != 0)
                    449:                if(cat(name))return;
                    450:        i = strlen(name);
                    451:        name[i+1] = 0;
                    452:        while(--i >= 0)name[i + 1] = name[i];
                    453:        name[0] = '/';
                    454:        return;
                    455:        }
                    456: /*
                    457:        this function takes a file name and tells whether it is a 
                    458:        directory or on. Returns 1 if so, 0 otherwise.
                    459:        null strings etc. return 0.
                    460: */
                    461: isdirectory(fn)
                    462:        char *fn;
                    463: {
                    464:        int i,ret=0;
                    465:        if(fn == NULL || *fn == 0)return(0);
                    466:        i = strlen(fn);
                    467:        if(i == 1){
                    468:                if(strcmp(fn,".")       == 0)ret = 1;
                    469:                if(strcmp(fn,"/")       == 0)ret = 1;
                    470:        }
                    471:        else if(i == 2){
                    472:                if(strcmp(fn,"..")      == 0)ret = 1;
                    473:                if(strcmp(fn,"/.")      == 0)ret = 1;
                    474:        }
                    475:        else {
                    476:                if(strcmp(fn+i-2,"/.")  == 0)ret = 1;
                    477:                if(strcmp(fn+i-3,"/..") == 0)ret = 1;
                    478:        }
                    479:        return(ret);
                    480: }
                    481: /*
                    482:        generate a variable parameter list
                    483:        the format is:
                    484:                (name value, name value, ..., name value)
                    485:        where names are unquoted single words and values
                    486:        are unquoted if a single alphanumeric word, and are
                    487:        surrounded by {} otherwise. \ quotes { and }.
                    488:        the values are escape-processed, e.g. \n becomes 012.
                    489:        this function returns such a list.
                    490:        Returns the null parm list if nothing to give, i.e. "()" 
                    491: 
                    492:        Should also default so single keywords can have on/off
                    493:        states, and so do not require a value.
                    494: 
                    495:        Things this variable protocol should specify:
                    496:                EPASSWD         encrypted passwd
                    497:                FILEMODE        file mode
                    498:                FROMUID         from users' uid
                    499:                FROMGID         from users' gid
                    500:                COMPRESS        use colin's compression
                    501:                SPACCT          handle special accounts.
                    502:                MESSAGEID       unique number identifying this request.
                    503:                VTOUSERNAME     name netq should display as being "To:"
                    504:                FILENAME        when omitted by netcp, will use FILENAME ext.
                    505:                MACHINE2        a second machine (e.g. 3way netcp)
                    506:                LOGIN2          a second login name
                    507:                PASSWD2         a second passwd
                    508:                REPLYTO         the person the response should be sent to
                    509: 
                    510: */
                    511: char *genparmlist(){
                    512:        static char returnstr[PARMLIST];
                    513:        strcpy(returnstr,"()");
                    514:        return(returnstr);
                    515: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.