From budd@bu-cs.BU.EDU (Philip Budne) Tue Aug  9 23:09:34 1988
Path: aramis.rutgers.edu!njin!rutgers!mailrus!husc6!bu-cs!budd
From: budd@bu-cs.BU.EDU (Philip Budne)
Newsgroups: comp.protocols.appletalk
Subject: lwsrv accounting/access control for CAP 5.0
Keywords: cap lwsrv aufs printer accounting access control
Message-ID: <24353@bu-cs.BU.EDU>
Date: 10 Aug 88 03:09:34 GMT
Organization: Boston U. Comp. Sci.
Lines: 449

A while back someone asked if lwserv had been adapted to do
accounting.  Here is a solution I did a while back.

Our CS student machines has a pair of TI2115 OmniLoser printers, and I
wanted to make them available to Mac users ONLY IF they had accounts
on the Unix system.

I've modified aufs to write a small file based on net/node of origin
in a special directory when a user logs in via aufs and remove it when
they logout. (the files do get left when a mac crashes, but it usually
comes back with a different node number.

lwsrv checks if the incomming request comes from a node for which we
have data, then setuid()s to that user before running lpr so that
accounting is done properly.  If the user is not logged in the request
is rejected.

Both lwsrv and aufs now take "-X directory" arguments.

	Phil Budne, Boston University
	

Diffs:
================================================================
*** aufs.c.1	Thu May 19 15:20:19 1988
--- aufs.c	Tue Aug  9 20:34:54 1988
***************
*** 75,80 ****
--- 75,81 ----
  private char *passwdlookaside = NULL; /* local password file??? */
  private char *guestid = NULL;	/* any guest ids? */
  private char *coredir = NULL;	/* place to put coredumps */
+ export char *userlogindir = NULL;	/* budd -- name of userlogin file */
  export int mcs, qs;		/* maxcmdsize and quantum size */
  export int sqs = atpMaxNum;	/* maximum send quantum */
  export int n_rrpkts = atpMaxNum; /* maximum send quantum to allow remote */
***************
*** 151,157 ****
    char *DBLevelOpts();
  
    fprintf(stderr,"usage: %s [-d cap-flags] [-a afp-levels] ",name);
!   fprintf(stderr,"[-n name] [-t packets] [-s] [-V afpvols]\n");
    fprintf(stderr,"\t-d for CAP debugging flags:\n");
    fprintf(stderr,"\t   l = lap, d = ddp, a = atp, n = nbp, p = pap,");
    fprintf(stderr,"i = ini, s = asp\n");
--- 152,158 ----
    char *DBLevelOpts();
  
    fprintf(stderr,"usage: %s [-d cap-flags] [-a afp-levels] ",name);
!   fprintf(stderr,"[-n name] [-t packets] [-s] [-V afpvols] [-X usrfile]\n"); /* budd */
    fprintf(stderr,"\t-d for CAP debugging flags:\n");
    fprintf(stderr,"\t   l = lap, d = ddp, a = atp, n = nbp, p = pap,");
    fprintf(stderr,"i = ini, s = asp\n");
***************
*** 171,176 ****
--- 172,178 ----
    fprintf(stderr,"\t-l file to send logfile to other than <servername>.log\n");
    fprintf(stderr,"\t-S <n> limit responses to <n> packets\n");
    fprintf(stderr,"\t-R <n> limit remote to sending <n> packets\n");
+   fprintf(stderr,"\t-X datafile of logged in users\n"); /* budd */
    fprintf(stderr,"\nExample: %s -t 'bdelete irename' -a 'file fork dir' -s\n",
  	  name);
    exit(1);
***************
*** 202,208 ****
    extern char *optarg;
    extern int optind;
    
!   while ((c = getopt(argc,argv,"a:d:D:n:N:t:sV:U:G:P:c:l:z:S:R:")) != EOF) {
      switch (c) {
      case 'z':
        strncpy(zonetorun, optarg, 32);
--- 204,210 ----
    extern char *optarg;
    extern int optind;
    
!   while ((c = getopt(argc,argv,"a:d:D:n:N:t:sV:U:G:P:c:l:z:S:R:X:")) != EOF) {
      switch (c) {
      case 'z':
        strncpy(zonetorun, optarg, 32);
***************
*** 272,277 ****
--- 274,282 ----
  	n_rrpkts = atpMaxNum;
        }
        break;
+     case 'X':				/* budd... */
+       userlogindir = optarg;
+       break;				/* ...budd */
      default:
        usage(argv[0]);
        break;
***************
*** 280,285 ****
--- 285,292 ----
  }
  
  
+ export AddrBlock addr;			/* budd */
+ 
  main(argc,argv)
  int argc;
  char **argv;
***************
*** 289,295 ****
    int killnow(), killin5(), diein5();
  #endif
    int err,atpskt,slsref;
-   AddrBlock addr;
    int comp,comp2;
    byte *srvinfo;
    int srvinfolen;
--- 296,301 ----
***************
*** 382,387 ****
--- 389,398 ----
    if ((ctp_stack = (int *)malloc(sizeof(int)*maxsess)) == NULL) {
      log("couldn't malloc stack for pid recording, fatal!");
    }
+   if( userlogindir != NULL ) {		/* budd... */
+       log("Aufs: user login database in %s", userlogindir );
+   } /* ...budd */
+ 
    ctp_stack_cnt = 0;
    { int i;
      for (i = 0 ; i < maxsess; i++) {
***************
*** 579,584 ****
--- 590,596 ----
      while (comp > 0) { abSleep(sectotick(60),TRUE); }
      if (comp == SessClosed || comp == ParamErr) {
        log("Session (%d) closed",cno);
+       clearuserlogin();			/* budd */
        return;
      }
      if (comp < 0) {
***************
*** 995,997 ****
--- 1007,1035 ----
  }
  
  
+ /**************** budd... ****************/
+ clearuserlogin() {
+     if( userlogindir != NULL ) {
+ 	char fname[ 100 ];
+ 	int fd;
+ 
+ 	make_userlogin( fname, userlogindir, addr );
+ 	if( unlink( fname ) < 0 ) {
+ 	    if( (fd = open( fname, O_WRONLY|O_TRUNC )) != -1 )
+ 		close( fd );
+ 	} /* unlink failed */
+     } /* have userlogindir */
+ } /* clearuserlogin */
+ 
+ /* duplicated in aufs.c and lwsrv.c sigh */
+ make_userlogin( buf, dir, addrb )
+     char *buf, *dir;
+     AddrBlock addrb;
+ {
+     sprintf( buf, "%s/net%d.%dnode%d",
+ 	    dir,
+ 	    nkipnetnumber(addrb.net), nkipsubnetnumber(addrb.net),
+ 	    addrb.node
+ 	    );
+ } /* make_userlogin */
+ /**************** ...budd ****************/

=============================================

*** afpos.c.1	Thu May 19 15:19:51 1988
--- afpos.c	Tue Aug  9 21:53:37 1988
***************
*** 2427,2432 ****
--- 2439,2465 ----
      strcpy(usrnam,p->pw_name);
      usrdir = (char *) malloc(strlen(p->pw_dir)+1);
      strcpy(usrdir,p->pw_dir);
+ 
+     /* budd... */
+     if( userlogindir != NULL ) {	/* need to save user logins? */
+       extern AddrBlock addr;		/* is this valid now?? seems to be! */
+       char fname[ 100 ];
+       FILE *f;
+ 
+       /* create file before setuid call so we can write in directory. */
+       make_userlogin( fname, userlogindir, addr );
+       if( (f = fopen( fname, "w" )) != NULL ) {	/* sigh. leaves race. */
+ 	  fprintf( f, "%s\n", usrnam );	/* perhaps write temp */
+ 	  fclose( f );			/* and rename?  */
+ 	  /* sigh. fchown and fchmod are BSDisms */
+ 	  chmod( fname, 0644 );		/* make owned by user so they */
+ 	  chown( fname, usruid, -1 );	/* can truncate it on exit!! */
+       } /* fopen ok */
+       else
+ 	  log("Login: could not create %s: %s", fname, syserr() );
+     } /* userlogindir and not guest */
+     /* ...budd */
+ 
      break;
    }

================================================================

*** lwsrv.c.1	Thu May 19 15:19:01 1988
--- lwsrv.c	Mon Jul 25 14:45:41 1988
***************
*** 50,55 ****
--- 50,56 ----
  # include <fcntl.h>
  #endif
  #include "papstream.h"
+ #include <pwd.h>			/* budd */
  
  private char *tracefile = NULL;
  private char *fontfile = NULL;
***************
*** 64,71 ****
  export PAPStatusRec statbuff;			/* status buffer */
  
  private char username[80],jobname[80];
  
- 
  #ifndef TEMPFILE
  # define TEMPFILE "/tmp/lwsrvXXXXXX"	/* temporary file holds job */
  #endif
--- 65,73 ----
  export PAPStatusRec statbuff;			/* status buffer */
  
  private char username[80],jobname[80];
+ private char *aufsdb = NULL;		/* budd */
+ private int requid;
  
  #ifndef TEMPFILE
  # define TEMPFILE "/tmp/lwsrvXXXXXX"	/* temporary file holds job */
  #endif
***************
*** 82,88 ****
    fprintf(stderr,"usage: %s -n <PrinterName> -p <unix printer name>\n",s);
    fprintf(stderr,"usage:\t\t-a <DictionaryDirectory> -f <FontFile>\n");
    fprintf(stderr,"usage:\t\t[-l <LogFile>] [-t <TraceFile>] [-r] [-h]\n");
!   fprintf(stderr,"usage:\t\t[-T crtolf] [-T quote8bit]\n\n");
    fprintf(stderr,"\t-p*<unix printer name> is the unix printer to print to\n");
    fprintf(stderr,"\t-n*<PrinterName> specifies the name lwsrv registers.\n");
    fprintf(stderr,"\t-a*<DictionaryDirectory> is the ProcSet directory.\n");
--- 84,91 ----
    fprintf(stderr,"usage: %s -n <PrinterName> -p <unix printer name>\n",s);
    fprintf(stderr,"usage:\t\t-a <DictionaryDirectory> -f <FontFile>\n");
    fprintf(stderr,"usage:\t\t[-l <LogFile>] [-t <TraceFile>] [-r] [-h]\n");
!   fprintf(stderr,"usage:\t\t[-T crtolf] [-T quote8bit] [-X userlogindb]\n\n");
! 					/* budd.........^^*/
    fprintf(stderr,"\t-p*<unix printer name> is the unix printer to print to\n");
    fprintf(stderr,"\t-n*<PrinterName> specifies the name lwsrv registers.\n");
    fprintf(stderr,"\t-a*<DictionaryDirectory> is the ProcSet directory.\n");
***************
*** 106,111 ****
--- 109,115 ----
    fprintf(stderr,"\t-T quote8bit: quote 8 bit chars for Transcript\n");
    fprintf(stderr,"\t-T makenondscconformant: make non DSC conformant: use\n");
    fprintf(stderr,"\t   if psrv only works with DSC 1.0 conventions\n");
+   fprintf(stderr,"\t-X <database directory> use aufs for validation\n");/*budd*/
    fprintf(stderr,"\nexample: %s -n Laser -p ps -a/usr/lib/ADicts\n",s);
    fprintf(stderr,"\t\t-f /usr/lib/LW+Fonts\n");
    fprintf(stderr,"\t(note the starred items above are required)\n");
***************
*** 121,127 ****
    extern char *optarg;
    extern int optind;
    
!   while ((c = getopt(argc,argv,"a:f:l:p:P:t:d:n:rehT:A:S")) != EOF) {
      switch (c) {
      case 'a':
        if (index(optarg, '/') == NULL) {
--- 125,131 ----
    extern char *optarg;
    extern int optind;
    
!   while ((c = getopt(argc,argv,"a:f:l:p:P:t:d:n:rehT:A:SX:")) != EOF) {
      switch (c) {
      case 'a':
        if (index(optarg, '/') == NULL) {
***************
*** 171,176 ****
--- 175,185 ----
        singlefork = TRUE;
        fprintf(stderr, "lwsrv: single fork\n");
        break;
+     case 'X':				/* budd... */
+       aufsdb = optarg;
+       fprintf(stderr, "lwsrv: aufs db directory in %s\n", aufsdb );
+       break;				/* ...budd */
+ 
      case '?':				/* illegal character */
        usage(argv[0],NULL);		/* usage and exit */
        break;
***************
*** 212,217 ****
--- 221,227 ----
  
    doargs(argc,argv);			/* handle args */
    
+   requid = getuid();			/* budd */
  
    if (!dbug.db_flgs) {			/* disassociate */
      if (fork())
***************
*** 274,279 ****
--- 284,291 ----
    if (!singlefork)
      signal(SIGCHLD, childdone);
    while (TRUE) {
+     AddrBlock addr;			/* budd */
+ 
      NewStatus("idle");
      err = GetNextJob(srefnum, &cno, &rcomp);
      if (err != noErr) {
***************
*** 283,288 ****
--- 295,346 ----
      while (rcomp > 0)
        abSleep(20,TRUE);
      fprintf(stderr,"lwsrv: Starting print job for %s\n",prtname);
+ 
+     /*** budd.... */
+     if ((err = PAPGetNetworkInfo(cno, &addr)) != noErr)
+       fprintf(stderr, "Get Network info failed with error %d", err);
+     else
+       fprintf(stderr,"Connection %d from [Network %d.%d, node %d, socket %d]\n",
+ 	      cno,
+ 	      nkipnetnumber(addr.net), nkipsubnetnumber(addr.net),
+ 	      addr.node, addr.skt);
+ 
+     if( aufsdb != NULL ) {
+ 	char fname[ 256 ];
+ 	int f, cc, ok;
+ 	struct passwd *pw;
+ 	ok = 0;				/* false */
+ 	make_userlogin( fname, aufsdb, addr );
+ 	if( (f = open( fname, 0)) >= 0 &&
+ 	   (cc = read( f, fname, sizeof( fname )-1 )) > 0 ) {
+ 	    if( fname[cc-1] == '\n' )
+ 		fname[cc-1] = '\0';
+ 	    fprintf( stderr, "Found username in aufsdb (%s): %s\n",
+ 		    aufsdb, fname );
+ 	    if( (pw = getpwnam( fname )) != NULL ) {
+ 		requid = pw->pw_uid;
+ 		ok = 1;		/* true */
+ 	    } /* pwnam ok */
+ 	} /* open and read OK */
+ 	if( !ok ) {			/* dump connection with error message */
+ 	    char message[ 512 ];
+ 	    fprintf( stderr, "No username (or invalid) confirmation.\n");
+ 	    gethostname( fname, sizeof( fname )-1 ); /* ick */
+ 
+ 	    /* THIS DOES NOT WORK! */
+ 	    sprintf(message, "error: please login to host %s via appleshare",
+ 		    fname );
+ 	    NewStatus( message );
+ 	    sleep( 3 );			/* bleh!! */
+ /*	    PAPShutdown( cno );		/*  */
+ 	    PAPClose( cno, TRUE );	/* arg2 is ignored!! */
+ 					/* what does it mean? */
+ 
+ 	    continue;
+ 	} /* not ok */
+     } /* have aufsdb */
+     /* ....budd ***/
+ 
      if (!singlefork) {
        if (fork() != 0) {
  	PAPShutdown(cno);	/* kill off connection */
***************
*** 347,355 ****
        fprintf(stderr,"lwsrv: Preserving file in %s\n",tname);
      fprintf(stderr,"lwsrv: Printing job: %s; user %s; on %s\n",
  	    jobname,username,ctime(&t));
!     sprintf(buf,"/usr/ucb/lpr -P%s %s %s -J 'MacUser: %s' %s\n",
! 	    unixpname,rflag ? "" : "-r",hflag ? "" : "-h", username,tname);
!     system(buf);
    }
    p_cls(pf);				/* close out the pap connection */
  }
--- 405,449 ----
        fprintf(stderr,"lwsrv: Preserving file in %s\n",tname);
      fprintf(stderr,"lwsrv: Printing job: %s; user %s; on %s\n",
  	    jobname,username,ctime(&t));
!     if( aufsdb ) {
! 	char *av[20], **ap, printer[50];
! 	int pid2, pid, f;
! 
! 	sprintf( printer, "-P%s", unixpname );
! 	ap = av;
! 	*ap++ = "lpr";
! 	*ap++ = printer;
! 	if( !hflag )
! 	    *ap++ = "-h";
! 	*ap++ = "-J";
! 	*ap++ = "lwsrv output";
! 	*ap = NULL;
! 
! 	if( (pid = fork()) == 0 ) {
! 	    close( 0 );
! 	    open( tname, 0 );		/* open temp file */
! 
! 	    close( 1 );			/* remove any connection to any tty */
! 	    close( 2 );			/* so that lpr will use uid */
! 	    open( "/", 0 );		/* not getlogin(). */
! 	    dup( 1 );
! 
! 	    setuid( requid );
! 	    execv( "/usr/ucb/lpr", av );
! 	    exit( 1 );
! 	}
! 	else if( pid > 0 ) {
! 	    while( (pid2 = wait(0)) != -1 && pid2 != pid )
! 		;
! 	}
! 	if( !rflag )
! 	    unlink( tname );
!     }
!     else {
! 	sprintf(buf,"/usr/ucb/lpr -P%s %s %s -J 'MacUser: %s' %s\n",
! 		unixpname,rflag ? "" : "-r",hflag ? "" : "-h", username,tname);
! 	system(buf);
!     }
    }
    p_cls(pf);				/* close out the pap connection */
  }
***************
*** 380,383 ****
--- 474,490 ----
      sprintf(tmp,"status: %s",status);
    cpyc2pstr(statbuff.StatusStr, tmp);
    abSleep(0,TRUE);			/* make sure protocol runs */
+ }
+ 
+ /**************** budd... ****************/
+ /* duplicated in aufs.c and lwsrv.c sigh */
+ make_userlogin( buf, dir, addrb )
+     char *buf, *dir;
+     AddrBlock addrb;
+ {
+     sprintf( buf, "%s/net%d.%dnode%d",
+ 	    dir,
+ 	    nkipnetnumber(addrb.net), nkipsubnetnumber(addrb.net),
+ 	    addrb.node
+ 	    );
  }

