mods to ksh for YP using getpwnam() (LLLOOOONNNNGGGGG)

King Ables ables at hi3.aca.mcc.com.UUCP
Tue Jun 14 02:36:14 AEST 1988


Re: fixing ksh to understand ~username when running YP

Well, I got quite a few suggestions to fix my problem.
Unfortunately, no one of them actually fixed anything for me.
I think that is a function of the fact that we have a fairly
old version of ksh.  We are investigating getting the newest
one, but bad things happen when our Purchasing group gets
together with AT&T, so I decided I'd better pursue a solution
given the version we already have!

First, I'd like to thank everyone who contributed ideas.  I received
a number of suggestions as well as some pleas for me to send whatever
I learned along to others.  So I am doing just that.  Below I include
the ideas I received along with my experiences trying them out on my
problems.  This is going to be a LONG message!

I did finally manage to figure out the various problems involved and
using a couple of these fixes plus one of my own I now have a working
version of ksh.  This is the last time I decide to start a "20 minute
project" on a Friday afternoon!!! ;-)

> Date: Wed, 1 Jun 88 20:37:52 EDT
> From: Glenn Barry <glenn at emory.arpa>
> Subject: ksh yp tilde fix
> 
> Hi King,
> 
> I fixed the latest version of ksh (ksh-i) to handle the yp tilde stuff.
> I'm pretty sure the same fix will work for your older version of ksh.  
> A friend says that Dave Korn said it will really be fixed in the next
> release.  You will need SunOS 3.X source code (which I think you mentioned
> you had) for this to work.  BTW, this works on SunOS 3.4 but
> should work under 3.5, too.
> 
> The recipe is below.  Let me know if you have any problems.
> 
> Glenn T. Barry      |  {sun!sunatl,gatech}!emory!glenn		UUCP
> Emory University    |  glenn at emory                      	BITNET
> Dept of Math and CS |  glenn at emory.ARPA                      	ARPA,CSNET
> Atlanta, GA 30322   |  Phone: (404) 727-5637
> 
> --------------------------------------------------------------------------
> 
> 
> 1)  Replace passwdent() in ksh/shlib/tilde.c with the following code:
> 
> #include <pwd.h>
> static char buf_pwf[BUFSIZ];
> 
> /*
>  * This new version of passwdent() uses getpwnam(3) to read the passwd
>  * file rather than reading the file itself.  It is necessary
>  * inorder for yp passwd file id extensions (+,-,@) to work correctly.
>  *                              emory!glenn 3/18/88
>  */
> static int passwdent(user)
> char *user;
> 
> {
>         struct passwd *pw_ent;
> 
>         if((pw_ent=getpwnam(user))==NULL)
>                 return(-1);
>         else 
>         {
>                 strcpy(u_logdir, pw_ent->pw_dir);
>                 strcpy(u_name, user);
>                 return(0);
>         }
> }
>  
> 2)  Get the getpwent.c (contains getpwnam(3) stuff) file from SunOS 3.X source 
>     (I used 3.3).   Delete the '#include <stdio.h>' and '#include <pwd.h>' 
>     lines from the beginning of the file.  Add the following line to
>     setpwent() after the 'pwf = fopen(PASSWD, "r");' line:
> 
> 		setbuf(pwf, buf_pwf);
> 
>     This is the key.  The 'setbuf' makes 'buf_pwf' be used for the stdio buffer
>     for stream 'pwf', rather than the buffer coming via malloc (which
>     is trouble because ksh does its own memory management).
> 
> 3)  Now add the modified getpwent.c to the end of the tilde.c file and
>     remake and it should work.


This is very close to what I needed, but it didn't fix absolutely
everything.  After I made this fix, I began to have a problem where
it would work for a few "echo ~username" commands and THEN bomb.
But I began to understand the problem.  It is closely related to
the fact that ksh has it's own malloc() and free() among other
things!  This has been discussed on the net recently so I won't
venture an opinion on it (yes, I will, I think it SUCKS!).  Ahem.
Excuse me.  ;-)

The fixes for me were a little different since my version of ksh
had no passwdent() routine.  I've got a tilde.c which has tilde()
and logdir().  logdir() is where /etc/passwd was opened and read,
so I added the getpwnam() call there and stripped out much of that
routine that dealt with /etc/passwd.

Someone also suggested the following fix:

1) add a copy of fopen that calls fdopen.

2) fix io.h so that _N_STATIC_IOBS or whatever it is is set to 20
instead of 3.

which someone might want to try on the newer versions.  This did
me no good since my io.h didn't contain _N_STATIC_IOBS or anything
close to it.  I played around with fopen() and fdopen() for a bit
but couldn't make anything good come of it.  Since my basic problem
was buffers stepping on each other, I can see how this would fix
the problem since ksh has it's own fdopen(), too.

> Date: Fri, 3 Jun 88 13:07:39 EDT
> From: keenan at inmet (Keenan Ross )
> Subject: Ksh for the suns
> 
> I haven't actually done any of this, but here are a couple of mail
> messages from a co-worker which describe what he did to ksh to get
> it to work on the suns, addressing the '~' problem specifically.
> Hope this helps.
> --keenan ross		UUCP:     {bellcore,ima,ihnp4}!inmet!keenan
>  Intermetrics, Inc.	INTERNET: keenan at inmet.inmet.com
>  733 Concord Ave.
>  Cambridge, MA  02138	PHONE:    (617) 661-1840
> 
> >>>>>>erikl at pba.inmet.com Thu Apr 30 13:47:49 1987
> 
> I don't know if you care, but I fixed the tilde '~' problem in ksh
> on the suns.  Instead of opening the file /etc/passwd, I open a pipe
> with the command "ypcat passwd".  The following two lines (appropriately
> placed in src/shlib/tilde.c) will do the trick:
> 
> At line 114 replace:
>  	if((fd=fdopen(open("/etc/passwd",0),"r"))==NULL)
> with
>  	if((fd=popen("ypcat passwd","r"))==NULL)
> 
> At line 153 replace:
>  	fclose(fd);
> with
>  	pclose(fd);
> 
> To bring ksh up on the RCE Suns I had to make the following changes:
> 
> ================ File: sh/io.h =============
> 44a45,47
> > #ifndef _NFILE		/* true for bsd 4.3 */
> > #define _NFILE	20
> > #endif
> sh/makesh:
> 66c66
> < 	then	NOBUF=-DNOBUF DATA='data$$'
> ---
> > 	then	NOBUF=-DNOBUF DATA='data$$' D4_2=-DBSD_4_2 JOBLIB=
> ================ File: sh/io.c =============
> 33,35c33,35
> < # ifdef BSD4_2
> < # include	<fcntl.h>
> < # endif BSD4_2
> ---
> > # ifdef BSD_4_2
> > #include	<fcntl.h>
> > # endif BSD_4_2
> ================ File: sh/makefile =============
> 30c30
> < # D4_2 = -DBSD_4_2
> ---
> > D4_2 = -DBSD_4_2
> 84c84
> < 		$(C) -O -S -c ctype.c ;\
> ---
> > 		$(C) -O -S ctype.c ;\
> 95c95
> < 		$(C) -O -S -c msg.c ;\
> ---
> > 		$(C) -O -S msg.c ;\

I thought of this solution early and was keeping it my back
pocket if it was the only way.  But it sure slows things down
a lot!  It has the virtue of working in all cases, however.

This one was posted, but in the interest of completeness I will
include it...

> From: dupuy at douglass.columbia.edu (Alexander Dupuy)
> Newsgroups: comp.unix.wizards
> Subject: Re: Speaking of ksh
> Date: 4 Jun 88 11:35:28 GMT
> 
> In article <300 at hi3.aca.mcc.com.UUCP> King Ables writes: We recently converted
> >a sun server to run YP (like the rest of the ones in our department) and I was
> >asked to fix ksh so that ~username would work again (since there is no
> >significant passwd file on the clients of that server anymore).
> 
> >I thought to myself "no big deal... probably just a recompile so the
> >getpwnam() call works with YP."  WRONG.  Of course, ksh opens the passwd file
> >and reads it.  OK.  Big deal, I yank that code and I put in a call to
> >getpwnam() instead... seemed real simple.  But ever since then I've been
> >getting segmentation faults down in the bowels of the YP code.
> 
> >Has anybody "fixed" ksh anywhere to do this?  I can't believe it can be *THAT*
> >difficult... 
> 
> Here's the fix: (credit to Chris Maio for finally tracking this down - why he
> has to wait until we started running YP on his workstation I don't know :-)
> 
> First rip out the crap in shlib/tilde.c and make it use getpwnam() instead.
> (It sounds like you have already done this).
> 
> Then, patch sh/io.c (your line numbers will vary).
> 
> *** old/io.c	Wed Nov 18 11:17:03 1987
> --- io.c	Sat Dec  5 18:19:57 1987
> ***************
> *** 606,611 ****
> --- 610,622 ----
>   
>   	if ((iop->_flag&_IOREAD) == 0)
>   		return(EOF);
> + 
> + #if BUGFIX
> + 	/* will this let us call getpwnam? */
> + 	if (iop->_base == 0)
> + 		_findbuf(iop);
> + #endif BUGFIX
> + 
>   	if(fnobuff(iop))
>   	{
>   		/* unbuffered reads needed for pipes */
> 
> This patch is for ksh-i, but it ought to work for the older ksh as well.
> 
> @alex
> -- 
> inet: dupuy at columbia.edu
> uucp: ...!rutgers!columbia!dupuy

This was the key to my eventual success.  The fact that the iop
buffer doesn't seem to be allocated at this point is were my problems
began.  This fix combined with Glenn Barry's above (including code
from YP with a minor fix in it) fixed my interactive ksh.  I thought I was
all done at that point until I ran ksh on a file of commands (ksh script)
to test many many of these things.  It bombed then with the SAME OLD PROBLEM.
Obviously there was something different about running ksh interactively
and running it on a file.  I began to suspect that the above problem also
applied to the file descriptor being opened when reading from a file.
I then set about looking for the same type of operation as above on
a file descriptor planning to make the same fix.

In io.c, I found the ksh copy of fdopen() and found that they
create a buffer iop and assign iop->_base to NULL.  I took a shot
and added another _fillbuf(iop) call after that and then the script
worked!  SUCCESS!

This one was posted too, but is included (again) in the interest
of completeness.

> From: cliff at hcx1.SSD.HARRIS.COM
> Newsgroups: comp.unix.wizards
> Subject: Re: Speaking of ksh
> Date: 3 Jun 88 11:27:00 GMT
>
> ... summary of original message deleted ...
>
> We solved this problem (on our HCX series of machines running HCX/UX 3.0)
> by using getpwnam() just as you did. We found that the first call takes
> a long time since the _filbuf() used in ksh is incompatible with the standard
> one. All open()'s in ksh are immediately followed by a setbuf() call. The
> open() buried inside of getpwnam() is not. The _filbuf() built into
> ksh does not allocate a buffer for a buffered file if one is needed. We
> extracted the code from the standard _filbuf() which does this and
> don't have any performance, functionality, or realiability problems.
> -------------------------------------------------------------------------
> Cliff Van Dyke                   cliff at ssd.harris.com
> Harris Computer System           cliff%ssd.harris.com at eddie.mit.edu
> 2101 W. Cypress Creek Rd.        ...!{mit-eddie,uunet,novavax}!hcx1!cliff
> Ft. Lauderdale, FL 33309-1892        
> Tel: (305) 974-1700                  

This message helped me to understand what the basic problem 
throughout all the various versions of ksh was... there seem to
be a number of different ways to solve it, but the same common
thread seems to run through all the dialogue I received.  The
i/o buffers aren't allocated in a consistent manner (probably due
to the duplicated system calls) and we get in trouble.

Also posted:

> Date: Fri, 3 Jun 88 10:30:14 BST
> Subject: Re: Speaking of ksh
> Newsgroups: comp.unix.wizards
> From: mcvax!cs.bham.ac.uk!BattenIG at uunet.UU.NET
> 
> In article <300 at hi3.aca.mcc.com.UUCP> you write:
> > We recently converted a sun server to run YP (like the
> 
> There is a known bug in the YP code get getpwent-type operations if (1) the
> password required is NOT in the local /etc/passwd has "really" has to
> come across the net and (2) you have more than, I think, 128 entries in
> the YP table "passwd".  A (source) fix was posted to sunspots a while
> back ....
>
> ian

While we haven't noticed this problem at our site, I am planning to
investigate this one a little more.  However, it seems not to be
related to our ksh problems.

Thanks again to all who responded.  For those of you who simply asked
to be informed of what I found out, I hope this helps.  To take some
of the confusion out of the above multiple fixes, below are the diffs
*I* made to our version of ksh from the distribution to make it work
under BSD with YP.  I hope this helps someone somewhere.

---------------------------------sh/Makefile----------------------
20c20
< DBSD = -BSD 
---
> # DBSD = -BSD 
---------------------------------sh/io.c----------------------
84a85,87
> #ifdef BSD
> register char *s;
> #else
85a89
> #endif BSD
186d189
< 
193,201d195
< 
< /*
<  * --MCC--
<  *
<  * opening the fd has the same problem of assigning
<  * the buffer incorrectly... we know iop->_base is null, so...
<  */
< 	_findbuf(iop);
< 
604,612d597
< /*
<  * --MCC--
<  * added code to fix getpwnam() bomb 
<  */
< 	if (iop->_base == NULL)
< 		_findbuf(iop);
< /*
<  * END
<  */
---------------------------------sh/io.h----------------------
1c1
< /* @(#)io.h	1.3 */
---
> /* @(#)io.h	1.2 */
9,10d8
< 
< #include	<sys/param.h>
---------------------------------sh/makefile----------------------
27,28c27,28
< DBSD = -DBSD 
< LFLAGS = -z
---
> # DBSD = -DBSD 
> # LFLAGS = -z
30c30
< D4_2 = -DBSD_4_2
---
> # D4_2 = -DBSD_4_2
40c40
< NOBUF=-DNOBUF
---
> # NOBUF=-DNOBUF
85,87c85
< #		sed 's/^\([ 	]*\.*\)$(DATA)/\1$(FIXDATA)/g' ctype.s > temp.s ;\
< # don't do the above, just use the file as is ;\
< 		cp ctype.s temp.s ;\
---
> 		sed 's/^\([ 	]*\.*\)$(DATA)/\1$(FIXDATA)/g' ctype.s > temp.s ;\
98,100c96
< #		sed 's/^\([ 	]*\.*\)$(DATA)/\1$(FIXDATA)/g' msg.s > temp.s ;\
< # don't do the above, just use the file as is ;\
< 		cp msg.s temp.s ;\
---
> 		sed 's/^\([ 	]*\.*\)$(DATA)/\1$(FIXDATA)/g' msg.s > temp.s ;\
---------------------------------sh/makesh----------------------
65,71c65
< #
< # they were checking to see if the /usr/suntool directory existed
< # to see if we were a sun .. maybe it used to on suns, but it doesn't
< # now, so we'll check for existence of executable /usr/bin/suntools
< # instead... the old test was "test -d /usr/suntool"
< #
< 	if	test -x /usr/bin/suntools #sun workstations
---
> 	if	test -d /usr/suntool #sun workstations
---------------------------------shlib/tilde.c----------------------
12a13,16
>  *
>  * Additions by King Ables, June 1988. 
>  * Make it work for YP in ACA at MCC.
>  * (look for "--MCC--")
15d18
< 
86a90,98
>  *
>  * --MCC--
>  * They originally read the passwd file... and DIDN'T call getpwnam()!
>  * So of course, under YP it didn't work... call getpwnam() instead
>  * so that it works either way!
>  *
>  * Not trivial because some buffers step on each other since ksh
>  * has it's own malloc() and free() (among other things)!!  Must
>  * include some YP source code slightly modified to make it work.
88a101,107
> /*
>  * --MCC--
>  *
>  * add /usr/include/pwd.h for getpwnam()
>  */
> #include	<pwd.h>
> 
92,98c111,113
<  register FILE *fd;
<  register char *sp=user;
<  register int c;
<  char *rval = NULL;
<  char buff[BUFSIZ];
<  int ncol = 4;	/* number of colons before home directory entry */
<  if(strlen(sp)>=UNAME)
---
>  struct passwd *pw_ent;
> 
>  if(strlen(user)>=UNAME)
100c115,116
<  if(strcmp(sp,u_name)==0)
---
> 
>  if(strcmp(user,u_name)==0)
102,143d117
<  if((fd=fdopen(open("/etc/passwd",0),"r"))==NULL)
< 	 return(NULL);
<  setbuf(fd,buff);
<  /* one line at a time */
<  do
< 	{
< 	 /* read until eof or end-of-field  or name doesn't match */
< 	 while((c=getc(fd))!=EOF && c!=':' && *sp++==c);
< 	 if(c==':'&& *sp==0)
< 		{
< 		 /* match with user found, skip to logdir entry */
< 		 sp = u_logdir;
< 		 while((c=getc(fd))!=EOF && c!= '\n')
< 			{
< 			 if(c==':' && --ncol==0)
< 				{
< 				 /* now copy into u_logdir */
< 				 while((c=getc(fd))!=EOF && c!=':'&& c!='\n')
< 					{
< 					 *sp++ = c;
< 					 /* see if too big */
< 					 if(sp >= (u_logdir+LOGDIR))
< 						 goto leave;
< 					}
< 				 break;
< 				}
< 			}
< 		 *sp = 0;
< 		 strcpy(u_name,user);
< 		 rval = u_logdir;
< 		 goto leave;
< 		}
< 	 /* skip to end-of-line */
< 	 while((c=getc(fd))!=EOF && c != '\n');
< 	 sp = user;
< 	}
<  while(c != EOF);
< leave:
<  setbuf(fd,NULL);
<  fclose(fd);
<  return(rval);
< }
144a119,128
>  pw_ent = getpwnam(user);
>  if (pw_ent == NULL) {
> 	return (NULL);
>  }
>  else {
> 	strcpy(u_logdir, pw_ent->pw_dir);
> 	strcpy(u_name, user);
> 	return(u_logdir);
>  }
> }

---------------------------comments about tilde.c------------------

I didn't include the diffs for the rest since it would have included
the entire contents of getpwent.c since it wasn't there before.
I append the contents of getpwent.c to the end of tilde.c but make
the following changes:

	1) remove #includes for stdio.h and pwd.h (would redefine)
	2) remove definition "extern char *strcpy()" (would also redefine)
	3) add definition for a buffer after "static FILE *pwf = NULL;"
	   that says:

		static char buf_pwf[BUFSIZ];

	4) in the routine setpwent() I changed the following
	   statement:

		if (pwf == NULL)
			pwf = fopen(PASSWD, "r");
		else
			rewind(pwf);

	   to:

		if (pwf == NULL) {
			pwf = fopen(PASSWD, "r");
			setbuf(pwf, buf_pwf);
		}
		else
			rewind(pwf);

-----------------------------------------------------------------

King Ables
Microelectronics and Computer Technology Corporation (MCC)
3500 West Balcones Center Drive
Austin, TX  78759
(512) 338-3494 (office)
(512) 343-0978 (switchboard)

ARPA: ables at mcc.com
UUCP: {gatech,ihnp4,nbires,seismo,ucb-vax}!ut-sally!im4u!milano!ables



More information about the Comp.unix.wizards mailing list