imported 9.0.299 Beta.01
[ckermit.git] / ckufio.c
index 298c48e..d860757 100644 (file)
--- a/ckufio.c
+++ b/ckufio.c
@@ -3,21 +3,22 @@
 #define CK_NONBLOCK                     /* See zoutdump() */
 
 #ifdef aegis
-char *ckzv = "Aegis File support, 8.0.200, 4 Mar 2004";
+char *ckzv = "Aegis File support, 9.0.215, 13 Jun 2011";
 #else
 #ifdef Plan9
-char *ckzv = "Plan 9 File support, 8.0.200, 4 Mar 2004";
+char *ckzv = "Plan 9 File support, 9.0.215, 13 Jun 2011";
 #else
-char *ckzv = "UNIX File support, 8.0.200, 4 Mar 2004";
+char *ckzv = "UNIX File support, 9.0.215, 13 Jun 2011";
 #endif /* Plan9 */
 #endif /* aegis */
 /*
   Author: Frank da Cruz <fdc@columbia.edu>,
   Columbia University Academic Information Systems, New York City,
   and others noted in the comments below.  Note: CUCCA = Previous name of
-  Columbia University Academic Information Systems.
+  Columbia University Academic Information Systems.  Note: AcIS = Previous
+  of Columbia University Information Technology.
 
-  Copyright (C) 1985, 2004,
+  Copyright (C) 1985, 2011,
     Trustees of Columbia University in the City of New York.
     All rights reserved.  See the C-Kermit COPYING.TXT file or the
     copyright text in the ckcmai.c module for disclaimer and permissions.
@@ -45,6 +46,17 @@ char *ckzv = "UNIX File support, 8.0.200, 4 Mar 2004";
 #include "ckcxla.h"
 #endif /* NOCSETS */
 
+/* To avoid pulling in all of ckuusr.h so we copy the few needed prototypes */
+
+struct mtab {                          /* Macro table, like keyword table */
+    char *kwd;                         /* But with pointers for vals */
+    char *mval;                                /* instead of ints. */
+    short flgs;
+};
+_PROTOTYP( int mlook, (struct mtab [], char *, int) );
+_PROTOTYP( int dodo, (int, char *, int) );
+_PROTOTYP( int parser, ( int ) );
+
 #ifdef COMMENT
 /* This causes trouble in C-Kermit 8.0.  I don't remember the original */
 /* reason for this being here but it must have been needed at the time... */
@@ -237,6 +249,8 @@ extern long timezone;
 #include <sys/stat.h>
 #endif /* CIE */
 
+
+
 /* Macro to alleviate isdir() calls internal to this module */
 
 static struct stat STATBUF;
@@ -490,6 +504,9 @@ extern char * anonroot;
 static char guestpass[GUESTPASS] = { NUL, NUL }; /* Anonymous "password" */
 static int logged_in = 0;               /* Set when user is logged in */
 static int askpasswd = 0;               /* Have OK user, must ask for passwd */
+#ifdef CK_PAM
+extern int gotemptypasswd;
+#endif /* CK_PAM */
 #endif /* CK_LOGIN */
 
 #ifdef CKROOT
@@ -500,6 +517,9 @@ int ckrooterr = 0;
 
 _PROTOTYP( VOID ignorsigs, (void) );
 _PROTOTYP( VOID restorsigs, (void) );
+#ifdef SELECT
+_PROTOTYP( int ttwait, (int, int) );   /* ckutio.c */
+#endif /* SELECT */
 
 /*
   Change argument to "(const char *)" if this causes trouble.
@@ -555,7 +575,11 @@ _PROTOTYP( struct passwd * getpwent, (void) );
 #include <shadow.h>
 #endif /* CK_SHADOW */
 #ifdef CK_PAM                           /* PAM... */
+#ifdef MACOSX
+#include <pam/pam_appl.h>
+#else /* MACOSX */
 #include <security/pam_appl.h>
+#endif /* MACOSX */
 #ifndef PAM_SERVICE_TYPE                /* Defines which PAM service we are */
 #define PAM_SERVICE_TYPE "kermit"
 #endif /* PAM_SERVICE_TYPE */
@@ -861,11 +885,15 @@ static int maxnames = MAXWLD;
 #endif /* PROVX1 */
 static char sspace[SSPACE];             /* Buffer for generating filenames */
 #else /* is DYNAMIC */
+#ifdef CK_64BIT
+#define SSPACE 2000000000              /* Two billion bytes */
+#else
 #ifdef BIGBUFOK
-#define SSPACE 500000
+#define SSPACE 10000000                        /* Ten million */
 #else
-#define SSPACE 10000
+#define SSPACE 10000                   /* Ten thousand */
 #endif /* BIGBUFOK */
+#endif /* CK_64BIT */
 char *sspace = (char *)0;
 #endif /* DYNAMIC */
 static int ssplen = SSPACE;            /* Length of string space buffer */
@@ -1048,6 +1076,12 @@ logwtmp __P ((__const char *__ut_line, __const char *__ut_name,
 #endif /* HAVEUTMPX */
 #endif /* UTMPBUG */
 
+#ifdef HAVEUTMPX
+#define UTMPSTRUCT utmpx
+#else
+#define UTMPSTRUCT utmp
+#endif /* HAVEUTMPX */
+
 #ifndef WTMPFILE
 #ifdef QNX
 #define WTMPFILE "/usr/adm/wtmp.1"
@@ -1095,11 +1129,7 @@ logwtmp(const char * line, const char * name, const char * host)
 logwtmp(line, name, host) char *line, *name, *host;
 #endif /* CK_ANSIC */
 /* logwtmp */ {
-#ifdef HAVEUTMPX
-    struct utmpx ut;                    /* Needed for ut_host[] */
-#else
-    struct utmp ut;
-#endif /* HAVEUTMPX */
+    struct UTMPSTRUCT ut;
     struct stat buf;
     /* time_t time(); */
 
@@ -1143,11 +1173,20 @@ logwtmp(line, name, host) char *line, *name, *host;
             ut.ut_time = zz;
         }
 #else
+#ifdef CK_64BIT
+        {
+           /* Now (Jan 2006) we can do this for any 64-bit build */
+            time_t zz;
+            time(&zz);
+            ut.ut_time = zz;
+        }
+#else
         time(&ut.ut_time);
+#endif /* CK_64BIT */
 #endif /* LINUX */
 #endif /* HAVEUTMPX */
-        if (write(wtmpfd, (char *)&ut, sizeof(struct utmp)) !=
-            sizeof(struct utmp)) {
+        if (write(wtmpfd, (char *)&ut, sizeof(struct UTMPSTRUCT)) !=
+            sizeof(struct UTMPSTRUCT)) {
 #ifndef NOFTRUNCATE
 #ifndef COHERENT
             ftruncate(wtmpfd, buf.st_size); /* Error, undo any partial write */
@@ -1227,9 +1266,9 @@ extern char zinbuffer[], zoutbuffer[];
 #endif /* DYNAMIC */
 extern char *zinptr, *zoutptr;
 extern int zincnt, zoutcnt;
-extern int wildxpand;
+extern int wildxpand, wildena;         /* Wildcard handling */
 
-static long iflen = -1L;                /* Input file length */
+static CK_OFF_T iflen = (CK_OFF_T)-1;  /* Input file length */
 
 static PID_T pid = 0;                   /* pid of child fork */
 static int fcount = 0;                  /* Number of files in wild group */
@@ -1398,9 +1437,9 @@ zopeni(n,name) int n; char *name; {
     }
 #endif /* CKROOT */
     fp[n] = fopen(name,"r");            /* Real file, open it. */
-    debug(F111,"zopeni fopen", name, fp[n]);
+    /* debug(F111,"zopeni fopen", name, fp[n]); */
 #ifdef ZDEBUG
-    printf("ZOPENI fp[%d]=%ld\n",n,fp[n]);
+    /* printf("ZOPENI fp[%d]=%ld\n",n,fp[n]); */
 #endif /* ZDEBUG */
     ispipe[n] = 0;
 
@@ -1448,6 +1487,7 @@ zopeno(n,name,zz,fcb)
 
     char p[8];
     int append = 0;
+    int istty = 0, filefd = 0;
 
 /* As of Version 5A, the attribute structure and the file information */
 /* structure are included in the arglist. */
@@ -1474,10 +1514,12 @@ zopeno(n,name,zz,fcb)
        fp[n] = stdout;
         ispipe[n] = 0;
 #endif /* COMMENT */
+#ifdef COMMENT
 #ifdef DEBUG
         if (n != ZDFILE)
           debug(F101,"zopeno fp[n]=stdout","",fp[n]);
 #endif /* DEBUG */
+#endif /* COMMENT */
         zoutcnt = 0;
         zoutptr = zoutbuffer;
         return(1);
@@ -1501,7 +1543,6 @@ zopeno(n,name,zz,fcb)
             append = 1;
         }
     }
-
     if (xferlog
 #ifdef CKSYSLOG
         || ((ckxsyslog >= SYSLG_FC) && ckxlogging)
@@ -1510,8 +1551,37 @@ zopeno(n,name,zz,fcb)
         getfullname(name);
         debug(F110,"zopeno fullname",fullname,0);
     }
+    {
+    /* Allow tty devices to opened as output files 2009/10/20 */
+       int fd, mode = 0;
+       debug(F110,"zopeno attempting to open",name,0);
+#ifdef O_NONBLOCK
+       mode = O_NONBLOCK;
+#else
+#ifdef O_NDELAY
+       mode = O_NDELAY;
+#else
+#ifdef FNDELAY
+       mode = FNDELAY;
+#endif /* FNDELAY */
+#endif /* O_NDELAY */
+#endif /* O_NONBLOCK */
+       debug(F111,"zopeno open mode",name,mode);
+       fd = open(name,O_WRONLY,mode);
+       debug(F111,"zopeno open",name,fd); 
+       if (fd > -1) {
+           if (isatty(fd)) {
+               filefd = fd;
+               istty++;
+           }
+       }
+    }
+    debug(F111,"zopeno istty",name,istty);
     debug(F110,"zopeno fopen arg",p,0);
-    fp[n] = fopen(name,p);              /* Try to open the file */
+    if (istty)
+      fp[n] = fdopen(filefd,p);
+    else
+      fp[n] = fopen(name,p);           /* Try to open the file */
     ispipe[ZIFILE] = 0;
 
 #ifdef ZDEBUG
@@ -1520,6 +1590,7 @@ zopeno(n,name,zz,fcb)
 
     if (fp[n] == NULL) {                /* Failed */
         debug(F101,"zopeno failed errno","",errno);
+       if (istty) close(filefd);
 #ifdef CKSYSLOG
         if (ckxsyslog >= SYSLG_FC && ckxlogging)
           syslog(LOG_INFO, "file[%d] %s: %s failed (%m)",
@@ -1585,7 +1656,7 @@ zopeno(n,name,zz,fcb)
 int
 zclose(n) int n; {
     int x = 0, x2 = 0;
-    extern long ffc;
+    extern CK_OFF_T ffc;
 
     debug(F101,"zclose file number","",n);
     if (chkfn(n) < 1) return(0);        /* Check range of n */
@@ -1599,7 +1670,7 @@ zclose(n) int n; {
         x = EOF;
 #endif /* NOPUSH */
         debug(F101,"zclose zclosf","",x);
-        debug(F101,"zclose zclosf fp[n]","",fp[n]);
+        /* debug(F101,"zclose zclosf fp[n]","",fp[n]); */
     } else {
         if ((fp[n] != stdout) && (fp[n] != stdin))
           x = fclose(fp[n]);
@@ -1656,11 +1727,11 @@ zclose(n) int n; {
                         "%.24s [BUFFER WOULD OVERFLOW]\n",ctime(&timenow));
                else
                  sprintf(iksdmsg,      /* SAFE */
-                        "%.24s %d %s %ld %s %c %s %c %c %s %s %d %s\n",
+                        "%.24s %d %s %s %s %c %s %c %c %s %s %d %s\n",
                         ctime(&timenow),        /* date/time */
                         gtimer(),               /* elapsed secs */
                         s,                      /* peer name */
-                        ffc,                    /* byte count */
+                       ckfstoa(ffc),           /* byte count */
                         fnam,                  /* full pathname of file */
                         (binary ? 'b' : 'a'),   /* binary or ascii */
                         "_",                    /* options = none */
@@ -1886,7 +1957,7 @@ zinfill() {
         }
 #endif /* USE_MEMCPY */
        ckstrncpy(zinbuffer,"zinbuffer is a valid buffer",INBUFSIZE);
-       debug(F111,"ZINFILL about to call fread",zinbuffer,zinbuffer);
+       /* debug(F111,"ZINFILL about to call fread",zinbuffer,zinbuffer); */
     }
 #endif /* DEBUG */
 
@@ -1945,6 +2016,8 @@ zinfill() {
 
 /*  Z S O U T  --  Write a string out to the given file, buffered.  */
 
+/*  Returns 0 on success, -1 on failure */
+
 int
 zsout(n,s) int n; char *s; {
     int rc = 0;
@@ -1969,8 +2042,12 @@ zsout(n,s) int n; char *s; {
     }
 #endif /* IKSD */
 
-    if (n == ZSFILE)
-      return(write(fileno(fp[n]),s,(int)strlen(s)));
+    if (n == ZSFILE) {
+       int k;
+       k = strlen(s);
+       rc = write(fileno(fp[n]),s,k);
+       return((rc == k) ? 0 : -1);
+    }
     rc = fputs(s,fp[n]) == EOF ? -1 : 0;
     if (n == ZWFILE)
       fflush(fp[n]);
@@ -1979,6 +2056,8 @@ zsout(n,s) int n; char *s; {
 
 /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
 
+/*  Returns 0 on success, -1 on failure */
+
 int
 zsoutl(n,s) int n; char *s; {
     if (zsout(n,s) < 0)
@@ -1995,7 +2074,7 @@ zsoutl(n,s) int n; char *s; {
 #endif /* IKSD */
 
     if (n == ZSFILE)                    /* Session log is unbuffered */
-      return(write(fileno(fp[n]),"\n",1));
+      return(write(fileno(fp[n]),"\n",1) == 1 ? 0 : -1);
     else if (fputs("\n",fp[n]) == EOF)
       return(-1);
     if (n == ZDIFIL || n == ZWFILE)     /* Flush connection log records */
@@ -2005,8 +2084,14 @@ zsoutl(n,s) int n; char *s; {
 
 /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
 
+/*  Returns number of characters written on success, -1 on failure */
+
 int
 zsoutx(n,s,x) int n, x; char *s; {
+    int k;
+    if (!s) return(0);
+    if (!*s) return(0);
+
 #ifdef IKSD
     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
 #ifdef COMMENT
@@ -2017,6 +2102,7 @@ zsoutx(n,s,x) int n, x; char *s; {
     }
 #endif /* IKSD */
 
+    if ((k = (int)strlen(s)) > x) x = k; /* Nothing else would make sense */
 #ifdef COMMENT
     if (chkfn(n) < 1) return(-1);
     return(write(fp[n]->_file,s,x));
@@ -2166,11 +2252,11 @@ char linkname[CKMAXPATH+1];
 #endif /* _IFLNK */
 #endif /* CKSYMLINK */
 
-long
+CK_OFF_T
 zgetfs(name) char *name; {
     struct stat buf;
     char fnam[CKMAXPATH+4];
-    long size = -1L;
+    CK_OFF_T size = (CK_OFF_T)-1;
     int x;
     int needrlink = 0;
     char * s;
@@ -2312,7 +2398,7 @@ zgetfs(name) char *name; {
   For Berkeley Unix, a file must be of type "regular" to be readable.
   Directory files, special files, and symbolic links are not readable.
 */
-long
+CK_OFF_T
 zchki(name) char *name; {
     struct stat buf;
     char * s;
@@ -2408,7 +2494,7 @@ zchki(name) char *name; {
 int
 zchko(name) char *name; {
     int i, x, itsadir = 0;
-    char *s;
+    char *s = NULL;
     char * oname;
     extern int zchkod;                  /* Used by IF WRITEABLE */
 
@@ -2456,16 +2542,52 @@ zchko(name) char *name; {
   zchkod is a global flag meaning we're checking not to see if the directory
   file is writeable, but if it's OK to create files IN the directory.
 */
-    if (!zchkod && isdir(name))         /* Directories are not writeable */
-      return(-1);
-
+    if (!zchkod && isdir(name)) {      /* Directories are not writeable */
+       debug(F111,"zchko isdir",name,1);
+       return(-1);
+    }
     s = malloc(x+3);                    /* Must copy because we can't */
     if (!s) {                           /* write into our argument. */
         fprintf(stderr,"zchko: Malloc error 46\n");
         return(-1);
     }
     ckstrncpy(s,name,x+3);
-
+#ifdef UNIX
+#ifdef NOUUCP
+    {                                  /* 2009/10/20 */
+    /* Allow tty devices to opened as output files */
+       int fd, istty = 0, mode = 0;
+       debug(F110,"zchko attempting to open",name,0);
+       /* Don't block on lack of Carrier or other modem signals */
+#ifdef O_NONBLOCK
+       mode = O_NONBLOCK;
+#else
+#ifdef O_NDELAY
+       mode = O_NDELAY;
+#else
+#ifdef FNDELAY
+       mode = FNDELAY;
+#endif /* FNDELAY */
+#endif /* O_NDELAY */
+#endif /* O_NONBLOCK */
+       debug(F111,"zchko open mode",name,mode);
+       fd = open(name,O_WRONLY,mode);  /* Must attempt to open it */
+       debug(F111,"zchko open",name,fd); 
+       if (fd > -1) {                  /* to get a file descriptor */
+           if (isatty(fd))             /* for isatty() */
+             istty++;
+           debug(F111,"zchko isatty",name,istty);
+           fd = close(fd);
+           if (istty) {
+               goto doaccess;
+           }
+       } else {
+           debug(F101,"zchko open errno","",errno); 
+           x = -1;
+       }
+    }
+#endif /* NOUUCP */
+#endif /* UNIX */
     for (i = x; i > 0; i--) {           /* Strip filename from right. */
         if (ISDIRSEP(s[i-1])) {
             itsadir = 1;
@@ -2519,6 +2641,8 @@ zchko(name) char *name; {
     if (!s[0])
       ckstrncpy(s,".",x+3);
 
+  doaccess:
+
 #ifdef SW_ACC_ID
     debug(F100,"zchko swapping ids for access()","",0);
     priv_on();
@@ -2535,7 +2659,7 @@ zchko(name) char *name; {
       debug(F111,"zchko access failed:",s,errno);
     else
       debug(F111,"zchko access ok:",s,x);
-    free(s);                            /* Free temporary storage */
+    if (s) free(s);                    /* Free temporary storage */
 
     return((x < 0) ? -1 : 0);           /* and return. */
 }
@@ -3220,7 +3344,7 @@ zxcmd(filnum,comand) int filnum; char *comand; {
         shpath = getenv("SHELL");       /* What shell? */
         if (shpath == NULL) {
             p = getpwuid( real_uid() ); /* Get login data */
-            debug(F111,"zxcmd shpath","getpwuid()",p);
+            /* debug(F111,"zxcmd shpath","getpwuid()",p); */
             if (p == (struct passwd *)NULL || !*(p->pw_shell))
               shpath = defshell;
             else shpath = p->pw_shell;
@@ -3297,8 +3421,8 @@ zclosf(filnum) int filnum; {
         return((x != 0) ? -1 : 1);
     }
 #endif /* NOPOPEN */
-    debug(F101,"zclosf fp[filnum]","", fp[filnum]);
-    debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
+    /* debug(F101,"zclosf fp[filnum]","", fp[filnum]); */
+    /* debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]); */
 
     if (pid != (PID_T) 0) {
         debug(F101,"zclosf killing pid","",pid);
@@ -3327,7 +3451,7 @@ zclosf(filnum) int filnum; {
     fp[filnum] = fp[ZSYSFN] = NULL;
 
     ispipe[filnum] = 0;
-    debug(F101,"zclosf fp[filnum]","",fp[filnum]);
+    /* debug(F101,"zclosf fp[filnum]","",fp[filnum]); */
 #ifdef CK_CHILD
     return(pexitstat == 0 ? 1 : -1);
 #else
@@ -3358,6 +3482,9 @@ zclosf(filnum) int filnum; {
 
   Depends on external variable wildxpand: 0 means we expand wildcards
   internally, nonzero means we call the shell to do it.
+  
+  AND in C-Kermit 8.0.212 and later, on extern wildena: 1 means wildcards
+  are enabled, 0 means disabled, the characters are taken literally.
 */
 static int xdironly = 0;
 static int xfilonly = 0;
@@ -3537,34 +3664,28 @@ zxpand(fnarg) char *fnarg; {
             fn[x] = '\0';
         }
     }
-    debug(F111,"zxpand fn 3",fn,haveonedir);
+    debug(F111,"zxpand fn 3 haveonedir",fn,haveonedir);
 /*
   The following allows us to parse a single directory name without opening
   the directory and looking at its contents.  The diractive flag is a horrible
   hack (especially since DIR /NORECURSIVE turns it off), but otherwise we'd
   have to change the API.
 */
+    debug(F111,"zxpand fn 3 diractive",fn,diractive);
     if (!diractive && haveonedir) {
-#ifdef COMMENT
-       fcount = (mtchs == NULL &&
-                 (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
-         ? 0 : 1;
-#else
        fcount = 0;
        if (!mtchs) {
            mtchs = (char **)malloc(maxnames * sizeof(*mtchs));
-           if (mtchs)
-             fcount = 1;
-           if (!fcount)
+           if (!mtchs)
              return(nxpand = fcount);
        }
-#endif /* COMMENT */
+       fcount = 1;
        debug(F110,"zxpand haveonedir A1",fnarg,0);
        initspace(mtchs,ssplen);
        addresult(fnarg,1);
        if (numfnd < 0) return(-1);
        mtchptr = mtchs;                /* Save pointer for next. */
-       debug(F110,"zxpand haveonedir A2",*mtchptr,0);
+       debug(F111,"zxpand haveonedir A2",*mtchptr,numfnd);
        return(nxpand = fcount);
     }
 
@@ -3713,9 +3834,9 @@ znext(fn) char *fn; {
 /*ARGSUSED*/
 int
 #ifdef CK_ANSIC
-zchkspa(char *f, long n)
+zchkspa(char *f, CK_OFF_T n)
 #else
-zchkspa(f,n) char *f; long n;
+zchkspa(f,n) char *f; CK_OFF_T n;
 #endif /* CK_ANSIC */
 /* zchkspa() */ {
     /* In UNIX there is no good (and portable) way. */
@@ -4448,12 +4569,12 @@ ziperms(f) char *f; {
 
 int
 zsattr(xx) struct zattr *xx; {
-    long k; int x;
+    CK_OFF_T k; int x;
     struct stat buf;
 
-    k = iflen % 1024L;                  /* File length in K */
-    if (k != 0L) k = 1L;
-    xx->lengthk = (iflen / 1024L) + k;
+    k = iflen % 1024;                  /* File length in K */
+    if (k) k = 1L;
+    xx->lengthk = (iflen / 1024) + k;
     xx->type.len = 0;                   /* File type can't be filled in here */
     xx->type.val = "";
     if (*nambuf) {
@@ -4887,7 +5008,9 @@ zstrdt(date,len) char * date; int len; {
             }
 #else
 #ifndef BSD44
+#ifndef NOTIMEZONE
             tmx += timezone;
+#endif /* NOTIMEZONE */
 #endif /* BSD44 */
 #endif /* Plan9 */
 #endif /* ultrix */
@@ -5224,9 +5347,6 @@ zstime(f,yy,x)
     if (!*f) return(-1);
     if (!yy) return(-1);
 
-    debug(F110,"zstime",f,0);
-    debug(F111,"zstime date",yy->date.val,yy->date.len);
-
 #ifdef CKROOT
     debug(F111,"zstime setroot",ckroot,ckrootset);
     if (ckrootset) if (!zinroot(f)) {
@@ -5724,7 +5844,7 @@ splitpath(p) char *p; {
 
     while (*p) {
         cur = (struct path *) malloc(sizeof (struct path));
-        debug(F101,"splitpath malloc","",cur);
+        /* debug(F101,"splitpath malloc","",cur); */
         if (cur == NULL) {
             debug(F100,"splitpath malloc failure","",0);
             prv -> fwd = NULL;
@@ -6086,7 +6206,7 @@ traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
     debug(F111,"traverse sofar 2",sofar,0);
 
     segisdir = ((pl -> fwd) == NULL) ? 0 : 1;
-    itswild = iswild(pl -> npart);
+    itswild = wildena ? (iswild(pl -> npart)) : 0; /* 15 Jun 2005 */
 
     debug(F111,"traverse segisdir",sofar,segisdir);
     debug(F111,"traverse itswild ",pl -> npart,itswild);
@@ -6165,7 +6285,7 @@ traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
         debug(F101,"traverse directory open() failed","",errno);
         return;
     }
-    while (read(fd, (char *)dirbuf, sizeof dir_entry))
+    while (read(fd, (char *)dirbuf, sizeof dir_entry) > 0)
 #endif /* OPENDIR */
       {                         /* Read each entry in this directory */
           int exists;
@@ -6570,17 +6690,24 @@ whoami() {
     struct passwd *p;
     _PROTOTYP(extern char * getlogin, (void) );
 
+    debug(F111,"whoami ruid A",realname,ruid);
+
     if (ruid != -1)
       return(realname);
 
     ruid = real_uid();                  /* get our uid */
+    debug(F101,"whoami ruid B","",ruid);
+    if (ruid < 0) ruid = getuid();
+    debug(F101,"whoami ruid C","",ruid);
 
   /* how about $USER or $LOGNAME? */
     if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
         ckstrncpy(envname, c, 255);
+       debug(F110,"whoami envname",envname,0);
         if ((p = getpwnam(envname)) != NULL) {
             if (p->pw_uid == ruid) {    /* get passwd entry for envname */
                 ckstrncpy(realname, envname, UIDBUFLEN); /* uid's are same */
+               debug(F110,"whoami realname",realname,0);
                 return(realname);
             }
         }
@@ -6590,6 +6717,7 @@ whoami() {
 
     if ((c =  getlogin()) != NULL) {    /* name from utmp file */
         ckstrncpy (loginname, c, UIDBUFLEN);
+       debug(F110,"whoami loginname",loginname,0); 
         if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
           if (p->pw_uid == ruid)        /* for loginname */
             ckstrncpy(realname, envname, UIDBUFLEN); /* if uid's are same */
@@ -6598,11 +6726,13 @@ whoami() {
   /* Use first name we get for ruid */
 
     if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
+       debug(F101,"whoami no username for ruid","",ruid); 
         realname[0] = '\0';             /* no user name */
         ruid = -1;
         return(NULL);
     }
     ckstrncpy(realname, p->pw_name, UIDBUFLEN);
+    debug(F110,"whoami realname from getpwuid",realname,0);
     return(realname);
 #else
     return(NULL);
@@ -6627,17 +6757,22 @@ tilde_expand(dirname) char *dirname; {
 
     debug(F111,"tilde_expand",dirname,dirname[0]);
 
-    if (dirname[0] != '~')              /* Not a tilde...return param */
-      return(dirname);
+    if (dirname[0] != '~') {              /* Not a tilde...return param */
+       debug(F000,"tilde_expand NOT TILDE","",dirname[0]);
+       return(dirname);
+    }
     if (!strcmp(olddir,dirname)) {      /* Same as last time */
-      return(oldrealdir);               /* so return old answer. */
+       debug(F110,"tilde_expand same as previous",oldrealdir,0);
+       return(oldrealdir);               /* so return old answer. */
     } else {
+       debug(F110,"tilde_expand working...","",0);
         j = (int)strlen(dirname);
         for (i = 0; i < j; i++)         /* find username part of string */
           if (!ISDIRSEP(dirname[i]))
             temp[i] = dirname[i];
           else break;
         temp[i] = '\0';                 /* tie off with a NULL */
+       debug(F111,"tilde_expand first part",temp,i);
         if (i == 1) {                   /* if just a "~" */
 #ifdef IKSD
             if (inserver)
@@ -6646,14 +6781,20 @@ tilde_expand(dirname) char *dirname; {
 #endif /* IKSD */
             {
                 char * p = whoami();
-                if (p)
-                 user = getpwnam(p);
-                else
-                 user = NULL;
+               debug(F110,"tilde_expand p",p,0);
+                if (p) {
+                   user = getpwnam(p);
+                   debug(F110,"tilde_expand getpwpam ~",user,0);
+               } else {
+                   user = NULL;
+               }
             }
         } else {
+           debug(F110,"tilde_expand ~user",&temp[1],0);
             user = getpwnam(&temp[1]);  /* otherwise on the specified user */
+           debug(F110,"tilde_expand getpwpam user",user,0);
         }
+
     }
     if (user != NULL) {                 /* valid user? */
         ckstrncpy(olddir, dirname, BUFLEN); /* remember the directory */
@@ -6782,6 +6923,9 @@ zshcmd(s) char *s; {
     return(0);
 #else
     if (nopush) return(-1);
+    if (!s) return(-1);
+    while (*s == ' ') s++;
+
     debug(F110,"zshcmd command",s,0);
 
 #ifdef aegis
@@ -6817,12 +6961,23 @@ zshcmd(s) char *s; {
 /* This allows user to specify a different shell. */
         shpath = getenv("SHELL");       /* What shell? */
        debug(F110,"zshcmd SHELL",shpath,0);
-        if (shpath == NULL) {
-            p = getpwuid( real_uid() ); /* Get login data */
-            if (p == (struct passwd *)NULL || !*(p->pw_shell))
-              shpath = defshell;
-            else shpath = p->pw_shell;
-           debug(F110,"zshcmd shpath",shpath,0);
+       {
+           int x = 0;
+           if (!shpath) {
+               x++;
+           } else if (!*shpath) {
+               x++;
+           }
+           if (x) {
+               debug(F100,"zshcmd SHELL not defined","",0);
+               p = getpwuid( real_uid() ); /* Get login data */
+               if (p == (struct passwd *)NULL || !*(p->pw_shell)) {
+                   shpath = defshell;
+               } else {
+                   shpath = p->pw_shell;
+               }
+               debug(F110,"zshcmd shpath from getpwuid",shpath,0);
+           }
         }
 #endif /* COMMENT */
 #endif /* aegis */
@@ -6831,12 +6986,17 @@ zshcmd(s) char *s; {
           if (*shptr++ == DIRSEP)
             shname = shptr;
        restorsigs();                   /* Restore ignored signals */
-       debug(F110,"zshcmd shname",shname,0);
+       debug(F110,"zshcmd execl shpath",shpath,0);
+       debug(F110,"zshcmd execl shname",shname,0);
         if (s == NULL || *s == '\0') {  /* Interactive shell requested? */
+           debug(F100,"zshcmd execl interactive","",0);
             execl(shpath,shname,"-i",NULL); /* Yes, do that */
         } else {                        /* Otherwise, */
+           debug(F110,"zshcmd execl command",s,0);
             execl(shpath,shname,"-c",s,NULL); /* exec the given command */
         }                               /* If execl() failed, */
+        debug(F101,"zshcmd errno","",errno);
+       perror(shpath);                 /* print reason and */
         exit(BAD_EXIT);                 /* return bad return code. */
 
     } else {                            /* Parent */
@@ -6852,6 +7012,7 @@ zshcmd(s) char *s; {
         istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
         qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
 
+       debug(F110,"zshcmd parent waiting for child",s,0);
 #ifdef CK_CHILD
         while (((wstat = wait(&child)) != pid) && (wstat != -1))
 #else
@@ -6874,7 +7035,7 @@ zshcmd(s) char *s; {
 
 /*
   Returns:
-    0 if argument is empty or is the name of a single file;
+    0 wildcards disabled or argument is empty or is the name of a single file;
     1 if it contains wildcard characters.
   Note: must match the algorithm used by match(), hence no [a-z], etc.
 */
@@ -6882,7 +7043,9 @@ int
 iswild(filespec) char *filespec; {
     char c, *p, *f; int x;
     int quo = 0;
-    if (!filespec)
+    if (!filespec)                     /* Safety */
+      return(0);
+    if (!wildena)                      /* Wildcards disabled - 12 Jun 2005 */
       return(0);
     f = filespec;
     if (wildxpand) {                   /* Shell handles wildcarding */
@@ -6949,12 +7112,34 @@ clrdircache() {
 #endif /* ISDIRCACHE */
 
 int
+isalink(s) char *s; {
+#ifndef CKSYMLINK
+    return(0);
+#else
+    int r = 0;
+    char filbuf[CKMAXPATH+4];
+    if (readlink(s,filbuf,CKMAXPATH) > -1)
+      r = 1;
+    debug(F110,"isalink readlink",s,r);
+    return(r);
+#endif /* CKSYMLINK */
+}
+
+int
 isdir(s) char *s; {
     int x, needrlink = 0, islink = 0;
     struct stat statbuf;
     char fnam[CKMAXPATH+4];
 
     if (!s) return(0);
+    debug(F110,"isdir entry",s,0);
+#ifdef DTILDE                          /* 2005-08-13 */
+    if (*s == '~') {                   /* Starts with tilde? */
+        s = tilde_expand(s);           /* Attempt to expand tilde */
+        if (!s) s = "";
+       debug(F110,"isdir tilde_expand",s,0);
+    }
+#endif /* DTILDE */
     if (!*s) return(0);
 
 #ifdef ISDIRCACHE
@@ -7169,7 +7354,7 @@ zrmdir(path) char *path; {
 /* Z F S E E K  --  Position input file pointer */
 /*
    Call with:
-    Long int, 0-based, indicating desired position.
+    CK_OFF_T (32 or 64 bits), 0-based, indicating desired position.
    Returns:
     0 on success.
    -1 on failure.
@@ -7177,19 +7362,25 @@ zrmdir(path) char *path; {
 #ifndef NORESEND
 int
 #ifdef CK_ANSIC
-zfseek(long pos)
+zfseek(CK_OFF_T pos)
 #else
-zfseek(pos) long pos;
+zfseek(pos) CK_OFF_T pos;
 #endif /* CK_ANSIC */
 /* zfseek */ {
     zincnt = -1;                        /* Must empty the input buffer */
     debug(F101,"zfseek","",pos);
-    return(fseek(fp[ZIFILE], pos, 0)?-1:0);
+    return(CKFSEEK(fp[ZIFILE], pos, 0)?-1:0);
 }
 #endif /* NORESEND */
 
 /*  Z F N Q F P  --  Convert filename to fully qualified absolute pathname */
 
+/*
+  Given a possibly unqualified or relative file specification fn, zfnqfp()
+  returns the fully qualified filespec for the same file, returning a struct
+  that contains the length (len) of the result, a pointer (fpath) to the
+  whole result, and a pointer (fname) to where the filename starts.
+*/
 static struct zfnfp fnfp = { 0, NULL, NULL };
 
 struct zfnfp *
@@ -7586,9 +7777,10 @@ sgetpwnam(name) char *name; {
 
 #ifdef CK_SHADOW
     sp = getspnam(name);
-    debug(F111,"sgetpwnam","getspnam()",sp);
-    if (sp == NULL)
-      return (NULL);
+    if (sp == NULL) {
+        debug(F110,"sgetpwnam","getspnam() fails",0);
+       return (NULL);
+    }
 #endif /* CK_SHADOW */
 
 #ifdef HPUX10_TRUSTED
@@ -7597,7 +7789,7 @@ sgetpwnam(name) char *name; {
 #endif /* HPUX10_TRUSTED */
 
     p = getpwnam(name);
-    debug(F111,"sgetpwnam","getpwnam()",p);
+    /* debug(F111,"sgetpwnam","getpwnam()",p); */
     if (p == NULL)
       return(NULL);
     if (save.pw_name) {
@@ -7673,8 +7865,11 @@ zvuser(name) char *name; {
     int x;
     char *shell;
 #ifdef GETUSERSHELL
-    char *getusershell();
+_PROTOTYP(char * getusershell, (void) );
 #endif /* GETUSERSHELL */
+#ifndef NODCLENDUSERSHELL
+_PROTOTYP(VOID endusershell, (void) );
+#endif /* NODCLENDUSERSHELL */
 
 #ifdef CK_PAM
     int pam_status;
@@ -7768,11 +7963,15 @@ zvuser(name) char *name; {
 #ifdef GETUSERSHELL
         while ((cp = getusershell()) != NULL) {
             debug(F110,"zvuser getusershell",cp,0);
-            if (strcmp(cp, shell) == 0)
+            if ((int)strcmp(cp, shell) == 0)
               break;
         }
         debug(F100,"zvuser endusershell 1","",0);
+#ifndef NODCLENDUSERSHELL
+        (VOID) endusershell();
+#else
         endusershell();
+#endif /* NODCLENDUSERSHELL */
         debug(F100,"zvuser endusershell 2","",0);
 #else /* GETUSERSHELL */
         cp = "";                        /* Do not refuse if we cannot check */
@@ -7886,7 +8085,7 @@ checkuser(name) char *name; {
       return(1);
 
     fd = fopen(userfile ? userfile : _PATH_FTPUSERS, "r");
-    debug(F111,"checkuser userfile",userfile,fd);
+    /* debug(F111,"checkuser userfile",userfile,fd); */
     if (fd) {
         line[0] = '\0';
         while (fgets(line, sizeof(line), fd)) {
@@ -7996,8 +8195,18 @@ zsyslog() {
 #define AUTH_VALID 4
 #endif /* AUTH_VALID */
 
+#ifdef __FreeBSD__                     /* 299 This was necessary in */
+#ifndef NODCLINITGROUPS                        /* FreeBSD 4.4, don't know */
+#define NODCLINITGROUPS                        /* about other versions... */
+#endif /* NODCLINITGROUPS */            
+#endif /*  __FreeBSD__ */
+
 int
 zvpass(p) char *p; {
+#ifndef NODCLINITGROUPS
+_PROTOTYP(int initgroups, (const char *, gid_t) );
+#endif /* NODCLINITGROUPS */
+
     char *xpasswd, *salt;
     char * dir = NULL;
 #ifdef CK_PAM
@@ -8043,8 +8252,22 @@ zvpass(p) char *p; {
             }
         }
         debug(F110,"zvpass","calling pam_authenticate",0);
+#ifdef COMMENT
         if (*p)
          pam_pw = p;
+#else
+/*
+  Make IKSD authentication (using PAM) ask for a password when an
+  invalid username has been given, to avoid disclosing which account
+  names are valid. See #417247 (Debian).
+*/
+        if (*p
+#ifdef CK_LOGIN
+           || gotemptypasswd
+#endif /* CK_LOGIN */
+           )
+           pam_pw = p;
+#endif /* COMMENT */
         if ((pam_status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
             reply = pam_strerror(pamh, pam_status);
             debug(F110,"zvpass PAM failure",reply,0);