| /* C K U F I O -- Kermit file system support for UNIX, Aegis, and Plan 9 */ |
| |
| #define CK_NONBLOCK /* See zoutdump() */ |
| |
| #ifdef aegis |
| char *ckzv = "Aegis File support, 8.0.200, 4 Mar 2004"; |
| #else |
| #ifdef Plan9 |
| char *ckzv = "Plan 9 File support, 8.0.200, 4 Mar 2004"; |
| #else |
| char *ckzv = "UNIX File support, 8.0.200, 4 Mar 2004"; |
| #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. |
| |
| Copyright (C) 1985, 2004, |
| 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. |
| */ |
| |
| /* |
| NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be |
| compatible with C preprocessors that support only #ifdef, #else, #endif, |
| #define, and #undef. Please do not use #if, logical operators, or other |
| preprocessor features in any of the portable C-Kermit modules. You can, |
| of course, use these constructions in platform-specific modules where you |
| know they are supported. |
| */ |
| /* Include Files */ |
| |
| #ifdef MINIX2 |
| #define _MINIX |
| #endif /* MINIX2 */ |
| |
| #include "ckcsym.h" |
| #include "ckcdeb.h" |
| #include "ckcasc.h" |
| |
| #ifndef NOCSETS |
| #include "ckcxla.h" |
| #endif /* NOCSETS */ |
| |
| #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... */ |
| #ifdef OSF13 |
| #ifdef CK_ANSIC |
| #ifdef _NO_PROTO |
| #undef _NO_PROTO |
| #endif /* _NO_PROTO */ |
| #endif /* CK_ANSIC */ |
| #endif /* OSF13 */ |
| #endif /* COMMENT */ |
| |
| #include <errno.h> |
| #include <signal.h> |
| |
| #ifdef MINIX2 |
| #undef MINIX |
| #undef CKSYSLOG |
| #include <limits.h> |
| #include <time.h> |
| #define NOFILEH |
| #endif /* MINIX2 */ |
| |
| #ifdef MINIX |
| #include <limits.h> |
| #include <sys/types.h> |
| #include <time.h> |
| #else |
| #ifdef POSIX |
| #include <limits.h> |
| #else |
| #ifdef SVR3 |
| #include <limits.h> |
| #endif /* SVR3 */ |
| #endif /* POSIX */ |
| #endif /* MINIX */ |
| /* |
| Directory Separator macros, to allow this module to work with both UNIX and |
| OS/2: Because of ambiguity with the command line editor escape \ character, |
| the directory separator is currently left as / for OS/2 too, because the |
| OS/2 kernel also accepts / as directory separator. But this is subject to |
| change in future versions to conform to the normal OS/2 style. |
| */ |
| #ifndef DIRSEP |
| #define DIRSEP '/' |
| #endif /* DIRSEP */ |
| #ifndef ISDIRSEP |
| #define ISDIRSEP(c) ((c)=='/') |
| #endif /* ISDIRSEP */ |
| |
| #ifdef SDIRENT |
| #define DIRENT |
| #endif /* SDIRENT */ |
| |
| #ifdef XNDIR |
| #include <sys/ndir.h> |
| #else /* !XNDIR */ |
| #ifdef NDIR |
| #include <ndir.h> |
| #else /* !NDIR, !XNDIR */ |
| #ifdef RTU |
| #include "/usr/lib/ndir.h" |
| #else /* !RTU, !NDIR, !XNDIR */ |
| #ifdef DIRENT |
| #ifdef SDIRENT |
| #include <sys/dirent.h> |
| #else |
| #include <dirent.h> |
| #endif /* SDIRENT */ |
| #else |
| #include <sys/dir.h> |
| #endif /* DIRENT */ |
| #endif /* RTU */ |
| #endif /* NDIR */ |
| #endif /* XNDIR */ |
| |
| #ifdef UNIX /* Pointer arg to wait() allowed */ |
| #define CK_CHILD /* Assume this is safe in all UNIX */ |
| #endif /* UNIX */ |
| |
| extern int binary, recursive, stathack; |
| #ifdef CK_CTRLZ |
| extern int eofmethod; |
| #endif /* CK_CTRLZ */ |
| |
| #include <pwd.h> /* Password file for shell name */ |
| #ifdef CK_SRP |
| #include <t_pwd.h> /* SRP Password file */ |
| #endif /* CK_SRP */ |
| |
| #ifdef HPUX10_TRUSTED |
| #include <hpsecurity.h> |
| #include <prot.h> |
| #endif /* HPUX10_TRUSTED */ |
| |
| #ifdef COMMENT |
| /* Moved to ckcdeb.h */ |
| #ifdef POSIX |
| #define UTIMEH |
| #else |
| #ifdef HPUX9 |
| #define UTIMEH |
| #endif /* HPUX9 */ |
| #endif /* POSIX */ |
| #endif /* COMMENT */ |
| |
| #ifdef SYSUTIMEH /* <sys/utime.h> if requested, */ |
| #include <sys/utime.h> /* for extra fields required by */ |
| #else /* 88Open spec. */ |
| #ifdef UTIMEH /* or <utime.h> if requested */ |
| #include <utime.h> /* (SVR4, POSIX) */ |
| #ifndef BSD44 |
| #ifndef V7 |
| /* Not sure why this is here. What it implies is that the code bracketed |
| by SYSUTIMEH is valid on all platforms on which we support time |
| functionality. But we know that is not true because the BSD44 and V7 |
| platforms do not support sys/utime.h and the data structures which |
| are defined in them. Now this worked before because prior to today's |
| changes the UTIMEH definition for BSD44 and V7 did not take place |
| until after SYSUTIMEH was defined. It also would not have been a |
| problem if the ordering of all the time blocks was consistent. All but |
| one of the blocks were BSD44, V7, SYSUTIMEH, <OTHER>. That one case |
| is where this problem was triggered. |
| */ |
| #define SYSUTIMEH /* Use this for both cases. */ |
| #endif /* V7 */ |
| #endif /* BSD44 */ |
| #endif /* UTIMEH */ |
| #endif /* SYSUTIMEH */ |
| |
| #ifndef NOTIMESTAMP |
| #ifdef POSIX |
| #ifndef AS400 |
| #define TIMESTAMP |
| #endif /* AS400 */ |
| #endif /* POSIX */ |
| |
| #ifdef BSD44 /* BSD 4.4 */ |
| #ifndef TIMESTAMP |
| #define TIMESTAMP /* Can do file dates */ |
| #endif /* TIMESTAMP */ |
| #include <sys/time.h> |
| #include <sys/timeb.h> |
| |
| #else /* Not BSD44 */ |
| |
| #ifdef BSD4 /* BSD 4.3 and below */ |
| #define TIMESTAMP /* Can do file dates */ |
| #include <time.h> /* Need this */ |
| #include <sys/timeb.h> /* Need this if really BSD */ |
| |
| #else /* Not BSD 4.3 and below */ |
| |
| #ifdef SVORPOSIX /* System V or POSIX */ |
| #ifndef TIMESTAMP |
| #define TIMESTAMP |
| #endif /* TIMESTAMP */ |
| #include <time.h> |
| |
| /* void tzset(); (the "void" type upsets some compilers) */ |
| #ifndef IRIX60 |
| #ifndef ultrix |
| #ifndef CONVEX9 |
| /* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */ |
| #ifndef Plan9 |
| extern long timezone; |
| #endif /* Plan9 */ |
| #endif /* CONVEX9 */ |
| #endif /* ultrix */ |
| #endif /* IRIX60 */ |
| #endif /* SVORPOSIX */ |
| #endif /* BSD4 */ |
| #endif /* BSD44 */ |
| |
| #ifdef COHERENT |
| #include <time.h> |
| #endif /* COHERENT */ |
| |
| /* Is `y' a leap year? */ |
| #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) |
| |
| /* Number of leap years from 1970 to `y' (not including `y' itself). */ |
| #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400) |
| |
| #endif /* NOTIMESTAMP */ |
| |
| #ifdef CIE |
| #include <stat.h> /* File status */ |
| #else |
| #include <sys/stat.h> |
| #endif /* CIE */ |
| |
| /* Macro to alleviate isdir() calls internal to this module */ |
| |
| static struct stat STATBUF; |
| #define xisdir(a) ((stat(a,&STATBUF)==-1)?0:(S_ISDIR(STATBUF.st_mode)?1:0)) |
| |
| extern char uidbuf[]; |
| extern int xferlog; |
| extern char * xferfile; |
| int iklogopen = 0; |
| static time_t timenow; |
| |
| #define IKSDMSGLEN CKMAXPATH+512 |
| |
| static char iksdmsg[IKSDMSGLEN]; |
| |
| extern int local; |
| |
| extern int server, en_mkd, en_cwd, en_del; |
| |
| /* |
| Functions (n is one of the predefined file numbers from ckcker.h): |
| |
| zopeni(n,name) -- Opens an existing file for input. |
| zopeno(n,name,attr,fcb) -- Opens a new file for output. |
| zclose(n) -- Closes a file. |
| zchin(n,&c) -- Gets the next character from an input file. |
| zsinl(n,&s,x) -- Read a line from file n, max len x, into address s. |
| zsout(n,s) -- Write a null-terminated string to output file, buffered. |
| zsoutl(n,s) -- Like zsout, but appends a line terminator. |
| zsoutx(n,s,x) -- Write x characters to output file, unbuffered. |
| zchout(n,c) -- Add a character to an output file, unbuffered. |
| zchki(name) -- Check if named file exists and is readable, return size. |
| zchko(name) -- Check if named file can be created. |
| zchkspa(name,n) -- Check if n bytes available to create new file, name. |
| znewn(name,s) -- Make a new unique file name based on the given name. |
| zdelet(name) -- Delete the named file. |
| zxpand(string) -- Expands the given wildcard string into a list of files. |
| znext(string) -- Returns the next file from the list in "string". |
| zxrewind() -- Rewind zxpand list. |
| zxcmd(n,cmd) -- Execute the command in a lower fork on file number n. |
| zclosf() -- Close input file associated with zxcmd()'s lower fork. |
| zrtol(n1,n2) -- Convert remote filename into local form. |
| zltor(n1,n2) -- Convert local filename into remote form. |
| zchdir(dirnam) -- Change working directory. |
| zhome() -- Return pointer to home directory name string. |
| zkself() -- Kill self, log out own job. |
| zsattr(struct zattr *) -- Return attributes for file which is being sent. |
| zstime(f, struct zattr *, x) - Set file creation date from attribute packet. |
| zrename(old, new) -- Rename a file. |
| zcopy(source,destination) -- Copy a file. |
| zmkdir(path) -- Create the directory path if possible |
| zfnqfp(fname,len,fullpath) - Determine full path for file name. |
| zgetfs(name) -- return file size regardless of accessibility |
| zchkpid(pid) -- tell if PID is valid and active |
| */ |
| |
| /* Kermit-specific includes */ |
| /* |
| Definitions here supersede those from system include files. |
| ckcdeb.h is included above. |
| */ |
| #include "ckcker.h" /* Kermit definitions */ |
| #include "ckucmd.h" /* For keyword tables */ |
| #include "ckuver.h" /* Version herald */ |
| |
| char *ckzsys = HERALD; |
| |
| /* |
| File access checking ... There are two calls to access() in this module. |
| If this program is installed setuid or setgid on a Berkeley-based UNIX |
| system that does NOT incorporate the saved-original-effective-uid/gid |
| feature, then, when we have swapped the effective and original uid/gid, |
| access() fails because it uses what it thinks are the REAL ids, but we have |
| swapped them. This occurs on systems where ANYBSD is defined, NOSETREU |
| is NOT defined, and SAVEDUID is NOT defined. So, in theory, we should take |
| care of this situation like so: |
| |
| ifdef ANYBSD |
| ifndef NOSETREU |
| ifndef SAVEDUID |
| define SW_ACC_ID |
| endif |
| endif |
| endif |
| |
| But we can't test such a general scheme everywhere, so let's only do this |
| when we know we have to... |
| */ |
| #ifdef NEXT /* NeXTSTEP 1.0-3.0 */ |
| #define SW_ACC_ID |
| #endif /* NEXT */ |
| |
| /* Support for tilde-expansion in file and directory names */ |
| |
| #ifdef POSIX |
| #define NAMEENV "LOGNAME" |
| #else |
| #ifdef BSD4 |
| #define NAMEENV "USER" |
| #else |
| #ifdef ATTSV |
| #define NAMEENV "LOGNAME" |
| #endif /* ATTSV */ |
| #endif /* BSD4 */ |
| #endif /* POSIX */ |
| |
| /* Berkeley Unix Version 4.x */ |
| /* 4.1bsd support from Charles E Brooks, EDN-VAX */ |
| |
| #ifdef BSD4 |
| #ifdef MAXNAMLEN |
| #define BSD42 |
| #endif /* MAXNAMLEN */ |
| #endif /* BSD4 */ |
| |
| /* Definitions of some system commands */ |
| |
| char *DELCMD = "rm -f "; /* For file deletion */ |
| char *CPYCMD = "cp "; /* For file copy */ |
| char *RENCMD = "mv "; /* For file rename */ |
| char *PWDCMD = "pwd "; /* For saying where I am */ |
| |
| #ifdef COMMENT |
| #ifdef HPUX10 |
| char *DIRCMD = "/usr/bin/ls -l "; /* For directory listing */ |
| char *DIRCM2 = "/usr/bin/ls -l "; /* For directory listing, no args */ |
| #else |
| char *DIRCMD = "/bin/ls -l "; /* For directory listing */ |
| char *DIRCM2 = "/bin/ls -l "; /* For directory listing, no args */ |
| #endif /* HPUX10 */ |
| #else |
| char *DIRCMD = "ls -l "; /* For directory listing */ |
| char *DIRCM2 = "ls -l "; /* For directory listing, no args */ |
| #endif /* COMMENT */ |
| |
| char *TYPCMD = "cat "; /* For typing a file */ |
| |
| #ifdef HPUX |
| char *MAILCMD = "mailx"; /* For sending mail */ |
| #else |
| #ifdef DGUX540 |
| char *MAILCMD = "mailx"; |
| #else |
| #ifdef UNIX |
| #ifdef CK_MAILCMD |
| char *MAILCMD = CK_MAILCMD; /* CFLAGS override */ |
| #else |
| char *MAILCMD = "Mail"; /* Default */ |
| #endif /* CK_MAILCMD */ |
| #else |
| char *MAILCMD = ""; |
| #endif /* UNIX */ |
| #endif /* HPUX */ |
| #endif /* DGUX40 */ |
| |
| #ifdef UNIX |
| #ifdef ANYBSD /* BSD uses lpr to spool */ |
| #ifdef DGUX540 /* And DG/UX */ |
| char * PRINTCMD = "lp"; |
| #else |
| char * PRINTCMD = "lpr"; |
| #endif /* DGUX540 */ |
| #else /* Sys V uses lp */ |
| #ifdef TRS16 /* except for Tandy-16/6000... */ |
| char * PRINTCMD = "lpr"; |
| #else |
| char * PRINTCMD = "lp"; |
| #endif /* TRS16 */ |
| #endif /* ANYBSD */ |
| #else /* Not UNIX */ |
| #define PRINTCMD "" |
| #endif /* UNIX */ |
| |
| #ifdef FT18 /* Fortune For:Pro 1.8 */ |
| #undef BSD4 |
| #endif /* FT18 */ |
| |
| #ifdef BSD4 |
| char *SPACMD = "pwd ; df ."; /* Space in current directory */ |
| #else |
| #ifdef FT18 |
| char *SPACMD = "pwd ; du ; df ."; |
| #else |
| char *SPACMD = "df "; |
| #endif /* FT18 */ |
| #endif /* BSD4 */ |
| |
| char *SPACM2 = "df "; /* For space in specified directory */ |
| |
| #ifdef FT18 |
| #define BSD4 |
| #endif /* FT18 */ |
| |
| #ifdef BSD4 |
| char *WHOCMD = "finger "; |
| #else |
| char *WHOCMD = "who "; |
| #endif /* BSD4 */ |
| |
| /* More system-dependent includes, which depend on symbols defined */ |
| /* in the Kermit-specific includes. Oh what a tangled web we weave... */ |
| |
| #ifdef COHERENT /* <sys/file.h> */ |
| #define NOFILEH |
| #endif /* COHERENT */ |
| |
| #ifdef MINIX |
| #define NOFILEH |
| #endif /* MINIX */ |
| |
| #ifdef aegis |
| #define NOFILEH |
| #endif /* aegis */ |
| |
| #ifdef unos |
| #define NOFILEH |
| #endif /* unos */ |
| |
| #ifndef NOFILEH |
| #include <sys/file.h> |
| #endif /* NOFILEH */ |
| |
| #ifndef is68k /* Whether to include <fcntl.h> */ |
| #ifndef BSD41 /* All but a couple UNIXes have it. */ |
| #ifndef FT18 |
| #ifndef COHERENT |
| #include <fcntl.h> |
| #endif /* COHERENT */ |
| #endif /* FT18 */ |
| #endif /* BSD41 */ |
| #endif /* is68k */ |
| |
| #ifdef COHERENT |
| #ifdef _I386 |
| #include <fcntl.h> |
| #else |
| #include <sys/fcntl.h> |
| #endif /* _I386 */ |
| #endif /* COHERENT */ |
| |
| extern int inserver; /* I am IKSD */ |
| int guest = 0; /* Anonymous user */ |
| |
| #ifdef IKSD |
| extern int isguest; |
| extern char * anonroot; |
| #endif /* IKSD */ |
| |
| #ifdef CK_LOGIN |
| #define GUESTPASS 256 |
| 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 */ |
| #endif /* CK_LOGIN */ |
| |
| #ifdef CKROOT |
| static char ckroot[CKMAXPATH+1] = { NUL, NUL }; |
| static int ckrootset = 0; |
| int ckrooterr = 0; |
| #endif /* CKROOT */ |
| |
| _PROTOTYP( VOID ignorsigs, (void) ); |
| _PROTOTYP( VOID restorsigs, (void) ); |
| |
| /* |
| Change argument to "(const char *)" if this causes trouble. |
| Or... if it causes trouble, then maybe it was already declared |
| in a header file after all, so you can remove this prototype. |
| */ |
| #ifndef NDGPWNAM /* If not defined No Declare getpwnam... */ |
| #ifndef _POSIX_SOURCE |
| #ifndef NEXT |
| #ifndef SVR4 |
| /* POSIX <pwd.h> already gave prototypes for these. */ |
| #ifdef IRIX40 |
| _PROTOTYP( struct passwd * getpwnam, (const char *) ); |
| #else |
| #ifdef IRIX51 |
| _PROTOTYP( struct passwd * getpwnam, (const char *) ); |
| #else |
| #ifdef M_UNIX |
| _PROTOTYP( struct passwd * getpwnam, (const char *) ); |
| #else |
| #ifdef HPUX9 |
| _PROTOTYP( struct passwd * getpwnam, (const char *) ); |
| #else |
| #ifdef HPUX10 |
| _PROTOTYP( struct passwd * getpwnam, (const char *) ); |
| #else |
| #ifdef DCGPWNAM |
| _PROTOTYP( struct passwd * getpwnam, (const char *) ); |
| #else |
| _PROTOTYP( struct passwd * getpwnam, (char *) ); |
| #endif /* DCGPWNAM */ |
| #endif /* HPUX10 */ |
| #endif /* HPUX9 */ |
| #endif /* M_UNIX */ |
| #endif /* IRIX51 */ |
| #endif /* IRIX40 */ |
| #ifndef SUNOS4 |
| #ifndef HPUX9 |
| #ifndef HPUX10 |
| #ifndef _SCO_DS |
| _PROTOTYP( struct passwd * getpwuid, (PWID_T) ); |
| #endif /* _SCO_DS */ |
| #endif /* HPUX10 */ |
| #endif /* HPUX9 */ |
| #endif /* SUNOS4 */ |
| _PROTOTYP( struct passwd * getpwent, (void) ); |
| #endif /* SVR4 */ |
| #endif /* NEXT */ |
| #endif /* _POSIX_SOURCE */ |
| #endif /* NDGPWNAM */ |
| |
| #ifdef CK_SHADOW /* Shadow Passwords... */ |
| #include <shadow.h> |
| #endif /* CK_SHADOW */ |
| #ifdef CK_PAM /* PAM... */ |
| #include <security/pam_appl.h> |
| #ifndef PAM_SERVICE_TYPE /* Defines which PAM service we are */ |
| #define PAM_SERVICE_TYPE "kermit" |
| #endif /* PAM_SERVICE_TYPE */ |
| |
| #ifdef SOLARIS |
| #define PAM_CONST |
| #else /* SOLARIS */ |
| #define PAM_CONST CONST |
| #endif |
| |
| static char * pam_pw = NULL; |
| |
| int |
| #ifdef CK_ANSIC |
| pam_cb(int num_msg, |
| PAM_CONST struct pam_message **msg, |
| struct pam_response **resp, |
| void *appdata_ptr |
| ) |
| #else /* CK_ANSIC */ |
| pam_cb(num_msg, msg, resp, appdata_ptr) |
| int num_msg; |
| PAM_CONST struct pam_message **msg; |
| struct pam_response **resp; |
| void *appdata_ptr; |
| #endif /* CK_ANSIC */ |
| { |
| int i; |
| |
| debug(F111,"pam_cb","num_msg",num_msg); |
| |
| for (i = 0; i < num_msg; i++) { |
| char message[PAM_MAX_MSG_SIZE]; |
| |
| /* Issue prompt and get response */ |
| debug(F111,"pam_cb","Message",i); |
| debug(F111,"pam_cb",msg[i]->msg,msg[i]->msg_style); |
| if (msg[i]->msg_style == PAM_ERROR_MSG) { |
| debug(F111,"pam_cb","PAM ERROR",0); |
| fprintf(stdout,"%s\n", msg[i]->msg); |
| return(0); |
| } else if (msg[i]->msg_style == PAM_TEXT_INFO) { |
| debug(F111,"pam_cb","PAM TEXT INFO",0); |
| fprintf(stdout,"%s\n", msg[i]->msg); |
| return(0); |
| } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) { |
| debug(F111,"pam_cb","Reading response, no echo",0); |
| /* Ugly hack. We check to see if a password has been pushed */ |
| /* into zvpasswd(). This would be true if the password was */ |
| /* received by REMOTE LOGIN. */ |
| if (pam_pw) { |
| ckstrncpy(message,pam_pw,PAM_MAX_MSG_SIZE); |
| } else |
| readpass((char *)msg[i]->msg,message,PAM_MAX_MSG_SIZE); |
| } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON) { |
| debug(F111,"pam_cb","Reading response, with echo",0); |
| readtext((char *)msg[i]->msg,message,PAM_MAX_MSG_SIZE); |
| } else { |
| debug(F111,"pam_cb","unknown style",0); |
| return(0); |
| } |
| |
| /* Allocate space for this message's response structure */ |
| resp[i] = (struct pam_response *) malloc(sizeof (struct pam_response)); |
| if (!resp[i]) { |
| int j; |
| debug(F110,"pam_cb","malloc failure",0); |
| for (j = 0; j < i; j++) { |
| free(resp[j]->resp); |
| free(resp[j]); |
| } |
| return(0); |
| } |
| |
| /* Allocate a buffer for the response */ |
| resp[i]->resp = (char *) malloc((int)strlen(message) + 1); |
| if (!resp[i]->resp) { |
| int j; |
| debug(F110,"pam_cb","malloc failure",0); |
| for (j = 0; j < i; j++) { |
| free(resp[j]->resp); |
| free(resp[j]); |
| } |
| free(resp[i]); |
| return(0); |
| } |
| /* Return the results back to PAM */ |
| strcpy(resp[i]->resp, message); /* safe (prechecked) */ |
| resp[i]->resp_retcode = 0; |
| } |
| debug(F110,"pam_cb","Exiting",0); |
| return(0); |
| } |
| #endif /* CK_PAM */ |
| |
| /* Define macros for getting file type */ |
| |
| #ifdef OXOS |
| /* |
| Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined |
| incorrectly, so we force their redefinition. |
| */ |
| #undef S_ISREG |
| #undef S_ISDIR |
| #endif /* OXOS */ |
| |
| #ifdef UTSV /* Same deal for Amdahl UTSV */ |
| #undef S_ISREG |
| #undef S_ISDIR |
| #endif /* UTSV */ |
| |
| #ifdef UNISYS52 /* And for UNISYS UTS V 5.2 */ |
| #undef S_ISREG |
| #undef S_ISDIR |
| #endif /* UNISYS52 */ |
| |
| #ifdef ICLSVR3 /* And for old ICL versions */ |
| #undef S_ISREG |
| #undef S_ISDIR |
| #endif /* ICLSVR3 */ |
| |
| #ifdef ISDIRBUG /* Also allow this from command line */ |
| #ifdef S_ISREG |
| #undef S_ISREG |
| #endif /* S_ISREG */ |
| #ifdef S_ISDIR |
| #undef S_ISDIR |
| #endif /* S_ISDIR */ |
| #endif /* ISDIRBUG */ |
| |
| #ifndef _IFMT |
| #ifdef S_IFMT |
| #define _IFMT S_IFMT |
| #else |
| #define _IFMT 0170000 |
| #endif /* S_IFMT */ |
| #endif /* _IFMT */ |
| |
| #ifndef S_ISREG |
| #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) |
| #endif /* S_ISREG */ |
| #ifndef S_ISDIR |
| #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
| #endif /* S_ISDIR */ |
| |
| /* The following mainly for NeXTSTEP... */ |
| |
| #ifndef S_IWUSR |
| #define S_IWUSR 0000200 |
| #endif /* S_IWUSR */ |
| |
| #ifndef S_IRGRP |
| #define S_IRGRP 0000040 |
| #endif /* S_IRGRP */ |
| |
| #ifndef S_IWGRP |
| #define S_IWGRP 0000020 |
| #endif /* S_IWGRP */ |
| |
| #ifndef S_IXGRP |
| #define S_IXGRP 0000010 |
| #endif /* S_IXGRP */ |
| |
| #ifndef S_IROTH |
| #define S_IROTH 0000004 |
| #endif /* S_IROTH */ |
| |
| #ifndef S_IWOTH |
| #define S_IWOTH 0000002 |
| #endif /* S_IWOTH */ |
| |
| #ifndef S_IXOTH |
| #define S_IXOTH 0000001 |
| #endif /* S_IXOTH */ |
| /* |
| Define maximum length for a file name if not already defined. |
| NOTE: This applies to a path segment (directory or file name), |
| not the entire path string, which can be CKMAXPATH bytes long. |
| */ |
| #ifdef QNX |
| #ifdef _MAX_FNAME |
| #define MAXNAMLEN _MAX_FNAME |
| #else |
| #define MAXNAMLEN 48 |
| #endif /* _MAX_FNAME */ |
| #else |
| #ifndef MAXNAMLEN |
| #ifdef sun |
| #define MAXNAMLEN 255 |
| #else |
| #ifdef FILENAME_MAX |
| #define MAXNAMLEN FILENAME_MAX |
| #else |
| #ifdef NAME_MAX |
| #define MAXNAMLEN NAME_MAX |
| #else |
| #ifdef _POSIX_NAME_MAX |
| #define MAXNAMLEN _POSIX_NAME_MAX |
| #else |
| #ifdef _D_NAME_MAX |
| #define MAXNAMLEN _D_NAME_MAX |
| #else |
| #ifdef DIRSIZ |
| #define MAXNAMLEN DIRSIZ |
| #else |
| #define MAXNAMLEN 14 |
| #endif /* DIRSIZ */ |
| #endif /* _D_NAME_MAX */ |
| #endif /* _POSIX_NAME_MAX */ |
| #endif /* NAME_MAX */ |
| #endif /* FILENAME_MAX */ |
| #endif /* sun */ |
| #endif /* MAXNAMLEN */ |
| #endif /* QNX */ |
| |
| #ifdef COMMENT |
| /* As of 2001-11-03 this is handled in ckcdeb.h */ |
| /* Longest pathname ... */ |
| /* |
| Beware: MAXPATHLEN is one of UNIX's dirty little secrets. Where is it |
| defined? Who knows... <param.h>, <mod.h>, <unistd.h>, <limits.h>, ... |
| There is not necessarily even a definition for it anywhere, or it might have |
| another name. If you get it wrong, bad things happen with getcwd() and/or |
| getwd(). If you allocate a buffer that is too short, getwd() might write |
| over memory and getcwd() will fail with ERANGE. The definitions of these |
| functions (e.g. in SVID or POSIX.1) do not tell you how to determine the |
| maximum path length in order to allocate a buffer that is the right size. |
| */ |
| #ifdef BSD44 |
| #include <sys/param.h> /* For MAXPATHLEN */ |
| #endif /* BSD44 */ |
| #ifdef COHERENT |
| #include <sys/param.h> /* for MAXPATHLEN, needed for -DDIRENT */ |
| #endif /* COHERENT */ |
| #endif /* COMMENT */ |
| |
| #ifdef MAXPATHLEN |
| #ifdef MAXPATH |
| #undef MAXPATH |
| #endif /* MAXPATH */ |
| #define MAXPATH MAXPATHLEN |
| #else |
| #ifdef PATH_MAX |
| #define MAXPATH PATH_MAX |
| #else |
| #ifdef _POSIX_PATH_MAX |
| #define MAXPATH _POSIX_PATH_MAX |
| #else |
| #ifdef BSD42 |
| #define MAXPATH 1024 |
| #else |
| #ifdef SVR4 |
| #define MAXPATH 1024 |
| #else |
| #define MAXPATH 255 |
| #endif /* SVR4 */ |
| #endif /* BSD42 */ |
| #endif /* _POSIX_PATH_MAX */ |
| #endif /* PATH_MAX */ |
| #endif /* MAXPATHLEN */ |
| |
| /* Maximum number of filenames for wildcard expansion */ |
| |
| #ifndef MAXWLD |
| /* Already defined in ckcdeb.h so the following is superfluous. */ |
| /* Don't expect changing them to have any effect. */ |
| #ifdef CK_SMALL |
| #define MAXWLD 50 |
| #else |
| #ifdef BIGBUFOK |
| #define MAXWLD 102400 |
| #else |
| #define MAXWLD 8192 |
| #endif /* BIGBUFOK */ |
| #endif /* CK_SMALL */ |
| #endif /* MAXWLD */ |
| |
| static int maxnames = MAXWLD; |
| |
| /* Define the size of the string space for filename expansion. */ |
| |
| #ifndef DYNAMIC |
| #ifdef PROVX1 |
| #define SSPACE 500 |
| #else |
| #ifdef BSD29 |
| #define SSPACE 500 |
| #else |
| #ifdef pdp11 |
| #define SSPACE 500 |
| #else |
| #ifdef aegis |
| #define SSPACE 10000 /* Size of string-generating buffer */ |
| #else /* Default static buffer size */ |
| #ifdef BIGBUFOK |
| #define SSPACE 65000 /* Size of string-generating buffer */ |
| #else |
| #define SSPACE 2000 /* size of string-generating buffer */ |
| #endif /* BIGBUFOK */ |
| #endif /* aegis */ |
| #endif /* pdp11 */ |
| #endif /* BSD29 */ |
| #endif /* PROVX1 */ |
| static char sspace[SSPACE]; /* Buffer for generating filenames */ |
| #else /* is DYNAMIC */ |
| #ifdef BIGBUFOK |
| #define SSPACE 500000 |
| #else |
| #define SSPACE 10000 |
| #endif /* BIGBUFOK */ |
| char *sspace = (char *)0; |
| #endif /* DYNAMIC */ |
| static int ssplen = SSPACE; /* Length of string space buffer */ |
| |
| #ifdef DCLFDOPEN |
| /* fdopen() needs declaring because it's not declared in <stdio.h> */ |
| _PROTOTYP( FILE * fdopen, (int, char *) ); |
| #endif /* DCLFDOPEN */ |
| |
| #ifdef DCLPOPEN |
| /* popen() needs declaring because it's not declared in <stdio.h> */ |
| _PROTOTYP( FILE * popen, (char *, char *) ); |
| #endif /* DCLPOPEN */ |
| |
| extern int nopush; |
| |
| /* More internal function prototypes */ |
| /* |
| * The path structure is used to represent the name to match. |
| * Each slash-separated segment of the name is kept in one |
| * such structure, and they are linked together, to make |
| * traversing the name easier. |
| */ |
| struct path { |
| char npart[MAXNAMLEN+4]; /* name part of path segment */ |
| struct path *fwd; /* forward ptr */ |
| }; |
| #ifndef NOPUSH |
| _PROTOTYP( int shxpand, (char *, char *[], int ) ); |
| #endif /* NOPUSH */ |
| _PROTOTYP( static int fgen, (char *, char *[], int ) ); |
| _PROTOTYP( static VOID traverse, (struct path *, char *, char *) ); |
| _PROTOTYP( static VOID addresult, (char *, int) ); |
| #ifdef COMMENT |
| /* Replaced by ckmatch() */ |
| _PROTOTYP( static int match, (char *, char *) ); |
| #endif /* COMMENT */ |
| _PROTOTYP( char * whoami, (void) ); |
| _PROTOTYP( UID_T real_uid, (void) ); |
| _PROTOTYP( static struct path *splitpath, (char *p) ); |
| _PROTOTYP( char * zdtstr, (time_t) ); |
| _PROTOTYP( time_t zstrdt, (char *, int) ); |
| |
| /* Some systems define these symbols in include files, others don't... */ |
| |
| #ifndef R_OK |
| #define R_OK 4 /* For access */ |
| #endif /* R_OK */ |
| |
| #ifndef W_OK |
| #define W_OK 2 |
| #endif /* W_OK */ |
| |
| #ifndef X_OK |
| #define X_OK 1 |
| #endif /* X_OK */ |
| |
| #ifndef O_RDONLY |
| #define O_RDONLY 000 |
| #endif /* O_RDONLY */ |
| |
| /* syslog and wtmp items for Internet Kermit Service */ |
| |
| extern char * clienthost; /* From ckcmai.c. */ |
| |
| static char fullname[CKMAXPATH+1]; |
| static char tmp2[CKMAXPATH+1]; |
| |
| extern int ckxlogging; |
| |
| #ifdef CKXPRINTF /* Our printf macro conflicts with */ |
| #undef printf /* use of "printf" in syslog.h */ |
| #endif /* CKXPRINTF */ |
| #ifdef CKSYSLOG |
| #ifdef RTAIX |
| #include <sys/syslog.h> |
| #else /* RTAIX */ |
| #include <syslog.h> |
| #endif /* RTAIX */ |
| #endif /* CKSYSLOG */ |
| #ifdef CKXPRINTF |
| #define printf ckxprintf |
| #endif /* CKXPRINTF */ |
| |
| int ckxanon = 1; /* Anonymous login ok */ |
| int ckxperms = 0040; /* Anonymous file permissions */ |
| int ckxpriv = 1; /* Priv'd login ok */ |
| |
| #ifndef XFERFILE |
| #define XFERFILE "/var/log/iksd.log" |
| #endif /* XFERFILE */ |
| |
| /* wtmp logging for IKSD... */ |
| |
| #ifndef CKWTMP /* wtmp logging not selected */ |
| int ckxwtmp = 0; /* Know this at runtime */ |
| #else /* wtmp file details */ |
| int ckxwtmp = 1; |
| #ifdef UTMPBUG /* Unfortunately... */ |
| /* |
| Some versions of Linux have a <utmp.h> file that contains |
| "enum utlogin { local, telnet, rlogin, screen, ... };" This clobbers |
| any program that uses any of these words as variable names, function |
| names, macro names, etc. (Other versions of Linux have this declaration |
| within #if 0 ... #endif.) There is nothing we can do about this other |
| than to not include the stupid file. But we need stuff from it, so... |
| */ |
| #include <features.h> |
| #include <sys/types.h> |
| #define UT_LINESIZE 32 |
| #define UT_NAMESIZE 32 |
| #define UT_HOSTSIZE 256 |
| |
| struct timeval { |
| time_t tv_sec; |
| time_t tv_usec; |
| }; |
| |
| struct exit_status { |
| short int e_termination; /* Process termination status. */ |
| short int e_exit; /* Process exit status. */ |
| }; |
| |
| struct utmp { |
| short int ut_type; /* Type of login */ |
| pid_t ut_pid; /* Pid of login process */ |
| char ut_line[UT_LINESIZE]; /* NUL-terminated devicename of tty */ |
| char ut_id[4]; /* Inittab id */ |
| char ut_user[UT_NAMESIZE]; /* Username (not NUL terminated) */ |
| |
| char ut_host[UT_HOSTSIZE]; /* Hostname for remote login */ |
| struct exit_status ut_exit; /* Exit status */ |
| long ut_session; /* Session ID, used for windowing */ |
| struct timeval ut_tv; /* Time entry was made */ |
| int32_t ut_addr_v6[4]; /* Internet address of remote host */ |
| char pad[20]; /* Reserved */ |
| }; |
| |
| #define ut_time ut_tv.tv_sec /* Why should Linux be like anything else? */ |
| #define ut_name ut_user /* ... */ |
| |
| extern void |
| logwtmp __P ((__const char *__ut_line, __const char *__ut_name, |
| __const char *__ut_host)); |
| |
| #else /* Not UTMPBUG */ |
| |
| #ifndef HAVEUTMPX /* Who has <utmpx.h> */ |
| #ifdef SOLARIS |
| #define HAVEUTMPX |
| #else |
| #ifdef IRIX60 |
| #define HAVEUTMPX |
| #else |
| #ifdef CK_SCOV5 |
| #define HAVEUTMPX |
| #else |
| #ifdef HPUX100 |
| #define HAVEUTMPX |
| #else |
| #ifdef UNIXWARE |
| #define HAVEUTMPX |
| #endif /* UNIXWARE */ |
| #endif /* HPUX100 */ |
| #endif /* CK_SCOV5 */ |
| #endif /* IRIX60 */ |
| #endif /* SOLARIS */ |
| #endif /* HAVEUTMPX */ |
| #ifdef HAVEUTMPX |
| #include <utmpx.h> |
| #else |
| #ifdef OSF50 |
| /* Because the time_t in the utmp struct is 64 bits but time() wants 32 */ |
| #define __V40_OBJ_COMPAT 1 |
| #endif /* OSF50 */ |
| #include <utmp.h> |
| #ifdef OSF50 |
| #undef __V40_OBJ_COMPAT |
| #endif /* OSF50 */ |
| #endif /* HAVEUTMPX */ |
| #endif /* UTMPBUG */ |
| |
| #ifndef WTMPFILE |
| #ifdef QNX |
| #define WTMPFILE "/usr/adm/wtmp.1" |
| #else |
| #ifdef LINUX |
| #define WTMPFILE "/var/log/wtmp" |
| #else |
| #define WTMPFILE "/usr/adm/wtmp" |
| #endif /* QNX */ |
| #endif /* LINUX */ |
| #endif /* WTMPFILE */ |
| char * wtmpfile = NULL; |
| |
| static int wtmpfd = 0; |
| static char cksysline[32] = { NUL, NUL }; |
| |
| #ifndef HAVEUTHOST /* Does utmp include ut_host[]? */ |
| #ifdef HAVEUTMPX /* utmpx always does */ |
| #define HAVEUTHOST |
| #else |
| #ifdef LINUX /* Linux does */ |
| #define HAVEUTHOST |
| #else |
| #ifdef SUNOS4 /* SunOS does */ |
| #define HAVEUTHOST |
| #else |
| #ifdef AIX41 /* AIX 4.1 and later do */ |
| #define HAVEUTHOST |
| #endif /* AIX41 */ |
| #endif /* SUNOS4 */ |
| #endif /* LINUX */ |
| #endif /* HAVEUTMPX */ |
| #endif /* HAVEUTHOST */ |
| |
| #ifdef UW200 |
| PID_T _vfork() { /* To satisfy a library foulup */ |
| return(fork()); /* in Unixware 2.0.x */ |
| } |
| #endif /* UW200 */ |
| |
| VOID |
| #ifdef CK_ANSIC |
| logwtmp(const char * line, const char * name, const char * host) |
| #else |
| 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 stat buf; |
| /* time_t time(); */ |
| |
| if (!ckxwtmp) |
| return; |
| |
| if (!wtmpfile) |
| makestr(&wtmpfile,WTMPFILE); |
| |
| if (!line) line = ""; |
| if (!name) name = ""; |
| if (!host) host = ""; |
| |
| if (!wtmpfd && (wtmpfd = open(wtmpfile, O_WRONLY|O_APPEND, 0)) < 0) { |
| ckxwtmp = 0; |
| debug(F110,"WTMP open failed",line,0); |
| return; |
| } |
| if (!fstat(wtmpfd, &buf)) { |
| ckstrncpy(ut.ut_line, line, sizeof(ut.ut_line)); |
| ckstrncpy(ut.ut_name, name, sizeof(ut.ut_name)); |
| #ifdef HAVEUTHOST |
| /* Not portable */ |
| ckstrncpy(ut.ut_host, host, sizeof(ut.ut_host)); |
| #endif /* HAVEUTHOST */ |
| #ifdef HAVEUTMPX |
| time(&ut.ut_tv.tv_sec); |
| #else |
| #ifdef LINUX |
| /* In light of the following comment perhaps the previous line should */ |
| /* be "#ifndef COMMENT". */ |
| { |
| /* |
| * On 64-bit platforms sizeof(time_t) and sizeof(ut.ut_time) |
| * are not the same and attempt to use an address of |
| * ut.ut_time as an argument to time() call may cause |
| * "unaligned access" trap. |
| */ |
| time_t zz; |
| time(&zz); |
| ut.ut_time = zz; |
| } |
| #else |
| time(&ut.ut_time); |
| #endif /* LINUX */ |
| #endif /* HAVEUTMPX */ |
| if (write(wtmpfd, (char *)&ut, sizeof(struct utmp)) != |
| sizeof(struct utmp)) { |
| #ifndef NOFTRUNCATE |
| #ifndef COHERENT |
| ftruncate(wtmpfd, buf.st_size); /* Error, undo any partial write */ |
| #else |
| chsize(wtmpfd, buf.st_size); /* Error, undo any partial write */ |
| #endif /* COHERENT */ |
| #endif /* NOFTRUNCATE */ |
| debug(F110,"WTMP write error",line,0); |
| } else { |
| debug(F110,"WTMP record OK",line,0); |
| return; |
| } |
| } |
| } |
| #endif /* CKWTMP */ |
| |
| #ifdef CKSYSLOG |
| /* |
| C K S Y S L O G -- C-Kermit system logging function, |
| |
| For use by other modules. |
| This module can, but doesn't have to, use it. |
| Call with: |
| n = SYSLG_xx values defined in ckcdeb.h |
| s1, s2, s3: strings. |
| */ |
| VOID |
| cksyslog(n, m, s1, s2, s3) int n, m; char * s1, * s2, * s3; { |
| int level; |
| |
| if (!ckxlogging) /* syslogging */ |
| return; |
| if (!s1) s1 = ""; /* Fix null args */ |
| if (!s2) s2 = ""; |
| if (!s3) s3 = ""; |
| switch (n) { /* Translate Kermit level */ |
| case SYSLG_DB: /* to syslog level */ |
| level = LOG_DEBUG; |
| break; |
| default: |
| level = m ? LOG_INFO : LOG_ERR; |
| } |
| debug(F110,"cksyslog s1",s1,0); |
| debug(F110,"cksyslog s2",s2,0); |
| debug(F110,"cksyslog s3",s3,0); |
| errno = 0; |
| syslog(level, "%s: %s %s", s1, s2, s3); /* Write syslog record */ |
| debug(F101,"cksyslog errno","",errno); |
| } |
| #endif /* CKSYSLOG */ |
| |
| |
| /* Declarations */ |
| |
| int maxnam = MAXNAMLEN; /* Available to the outside */ |
| int maxpath = MAXPATH; |
| int ck_znewn = -1; |
| |
| #ifdef UNIX |
| char startupdir[MAXPATH+1]; |
| #endif /* UNIX */ |
| |
| int pexitstat = -2; /* Process exit status */ |
| |
| FILE *fp[ZNFILS] = { /* File pointers */ |
| NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL |
| }; |
| |
| /* Flags for each file indicating whether it was opened with popen() */ |
| int ispipe[ZNFILS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
| |
| /* Buffers and pointers used in buffered file input and output. */ |
| #ifdef DYNAMIC |
| extern char *zinbuffer, *zoutbuffer; |
| #else |
| extern char zinbuffer[], zoutbuffer[]; |
| #endif /* DYNAMIC */ |
| extern char *zinptr, *zoutptr; |
| extern int zincnt, zoutcnt; |
| extern int wildxpand; |
| |
| static long iflen = -1L; /* Input file length */ |
| |
| static PID_T pid = 0; /* pid of child fork */ |
| static int fcount = 0; /* Number of files in wild group */ |
| static int nxpand = 0; /* Copy of fcount */ |
| static char nambuf[CKMAXPATH+4]; /* Buffer for a pathname */ |
| |
| #ifndef NOFRILLS |
| #define ZMBUFLEN 200 |
| static char zmbuf[ZMBUFLEN]; /* For mail, remote print strings */ |
| #endif /* NOFRILLS */ |
| |
| char **mtchs = NULL; /* Matches found for filename */ |
| char **mtchptr = NULL; /* Pointer to current match */ |
| |
| /* Z K S E L F -- Kill Self: log out own job, if possible. */ |
| |
| /* Note, should get current pid, but if your system doesn't have */ |
| /* getppid(), then just kill(0,9)... */ |
| |
| #ifndef SVR3 |
| #ifndef POSIX |
| #ifndef OSFPC |
| /* Already declared in unistd.h for SVR3 and POSIX */ |
| #ifdef CK_ANSIC |
| extern PID_T getppid(void); |
| #else |
| #ifndef PS2AIX10 |
| #ifndef COHERENT |
| extern PID_T getppid(); |
| #endif /* COHERENT */ |
| #endif /* PS2AIX10 */ |
| #endif /* CK_ANSIC */ |
| #endif /* OSFPC */ |
| #endif /* POSIX */ |
| #endif /* SVR3 */ |
| |
| int |
| zkself() { /* For "bye", but no guarantee! */ |
| #ifdef PROVX1 |
| return(kill(0,9)); |
| #else |
| #ifdef V7 |
| return(kill(0,9)); |
| #else |
| #ifdef TOWER1 |
| return(kill(0,9)); |
| #else |
| #ifdef FT18 |
| return(kill(0,9)); |
| #else |
| #ifdef aegis |
| return(kill(0,9)); |
| #else |
| #ifdef COHERENT |
| return(kill((PID_T)getpid(),1)); |
| #else |
| #ifdef PID_T |
| exit(kill((PID_T)getppid(),1)); |
| return(0); |
| #else |
| exit(kill(getppid(),1)); |
| return(0); |
| #endif |
| #endif |
| #endif |
| #endif |
| #endif |
| #endif |
| #endif |
| } |
| |
| static VOID |
| getfullname(name) char * name; { |
| char *p = (char *)fullname; |
| int len = 0; |
| fullname[0] = '\0'; |
| /* If necessary we could also chase down symlinks here... */ |
| #ifdef COMMENT |
| /* This works but is incompatible with wuftpd */ |
| if (isguest && anonroot) { |
| ckstrncpy(fullname,anonroot,CKMAXPATH); |
| len = strlen(fullname); |
| if (len > 0) |
| if (fullname[len-1] == '/') |
| len--; |
| } |
| p += len; |
| #endif /* COMMENT */ |
| zfnqfp(name, CKMAXPATH - len, p); |
| while (*p) { |
| if (*p < '!') *p = '_'; |
| p++; |
| } |
| } |
| |
| /* D O I K L O G -- Open Kermit-specific ftp-like transfer log. */ |
| |
| VOID /* Called in ckcmai.c */ |
| doiklog() { |
| if (iklogopen) /* Already open? */ |
| return; |
| if (xferlog) { /* Open iksd log if requested */ |
| if (!xferfile) /* If no pathname given */ |
| makestr(&xferfile,XFERFILE); /* use this default */ |
| if (*xferfile) { |
| xferlog = open(xferfile, O_WRONLY | O_APPEND | O_CREAT, 0660); |
| debug(F101,"doiklog open","",xferlog); |
| if (xferlog < 0) { |
| #ifdef CKSYSLOG |
| syslog(LOG_ERR, "xferlog open failure %s: %m", xferfile); |
| #endif /* CKSYSLOG */ |
| debug(F101,"doiklog open errno","",errno); |
| xferlog = 0; |
| } else |
| iklogopen = 1; |
| } else |
| xferlog = 0; |
| #ifdef CKSYSLOG |
| if (xferlog && ckxlogging) |
| syslog(LOG_INFO, "xferlog: %s open ok", xferfile); |
| #endif /* CKSYSLOG */ |
| } |
| } |
| |
| /* Z O P E N I -- Open an existing file for input. */ |
| |
| /* Returns 1 on success, 0 on failure */ |
| |
| int |
| zopeni(n,name) int n; char *name; { |
| int x; |
| |
| debug(F111,"zopeni",name,n); |
| if ((x = chkfn(n)) != 0) { |
| debug(F111,"zopeni chkfn",ckitoa(n),x); |
| return(0); |
| } |
| zincnt = 0; /* Reset input buffer */ |
| if (n == ZSYSFN) { /* Input from a system function? */ |
| #ifdef COMMENT |
| /*** Note, this function should not be called with ZSYSFN ***/ |
| /*** Always call zxcmd() directly, and give it the real file number ***/ |
| /*** you want to use. ***/ |
| return(zxcmd(n,name)); /* Try to fork the command */ |
| #else |
| debug(F110,"zopeni called with ZSYSFN, failing!",name,0); |
| *nambuf = '\0'; /* No filename. */ |
| return(0); /* fail. */ |
| #endif /* COMMENT */ |
| } |
| if (n == ZSTDIO) { /* Standard input? */ |
| if (is_a_tty(0)) { |
| fprintf(stderr,"Terminal input not allowed"); |
| debug(F110,"zopeni: attempts input from unredirected stdin","",0); |
| return(0); |
| } |
| fp[ZIFILE] = stdin; |
| ispipe[ZIFILE] = 0; |
| return(1); |
| } |
| #ifdef CKROOT |
| debug(F111,"zopeni setroot",ckroot,ckrootset); |
| if (ckrootset) if (!zinroot(name)) { |
| debug(F110,"zopeni setroot violation",name,0); |
| return(0); |
| } |
| #endif /* CKROOT */ |
| fp[n] = fopen(name,"r"); /* Real file, open it. */ |
| debug(F111,"zopeni fopen", name, fp[n]); |
| #ifdef ZDEBUG |
| printf("ZOPENI fp[%d]=%ld\n",n,fp[n]); |
| #endif /* ZDEBUG */ |
| ispipe[n] = 0; |
| |
| if (xferlog |
| #ifdef CKSYSLOG |
| || ((ckxsyslog >= SYSLG_FA) && ckxlogging) |
| #endif /* CKSYSLOG */ |
| ) { |
| getfullname(name); |
| debug(F110,"zopeni fullname",fullname,0); |
| } |
| if (fp[n] == NULL) { |
| #ifdef CKSYSLOG |
| if (ckxsyslog >= SYSLG_FA && ckxlogging) { |
| syslog(LOG_INFO, "file[%d] %s: open failed (%m)", n, fullname); |
| perror(fullname); |
| } else |
| #endif /* CKSYSLOG */ |
| perror(name); |
| return(0); |
| } else { |
| #ifdef CKSYSLOG |
| if (ckxsyslog >= SYSLG_FA && ckxlogging) |
| syslog(LOG_INFO, "file[%d] %s: open read ok", n, fullname); |
| #endif /* CKSYSLOG */ |
| clearerr(fp[n]); |
| return(1); |
| } |
| } |
| |
| #ifdef QNX |
| #define DONDELAY |
| #else |
| #ifdef O_NDELAY |
| #define DONDELAY |
| #endif /* O_NDELAY */ |
| #endif /* QNX */ |
| |
| /* Z O P E N O -- Open a new file for output. */ |
| |
| /*ARGSUSED*/ /* zz not used */ |
| int |
| zopeno(n,name,zz,fcb) |
| /* zopeno */ int n; char *name; struct zattr *zz; struct filinfo *fcb; { |
| |
| char p[8]; |
| int append = 0; |
| |
| /* As of Version 5A, the attribute structure and the file information */ |
| /* structure are included in the arglist. */ |
| |
| #ifdef DEBUG |
| debug(F111,"zopeno",name,n); |
| if (fcb) { |
| debug(F101,"zopeno fcb disp","",fcb->dsp); |
| debug(F101,"zopeno fcb type","",fcb->typ); |
| debug(F101,"zopeno fcb char","",fcb->cs); |
| } else { |
| debug(F100,"zopeno fcb is NULL","",0); |
| } |
| #endif /* DEBUG */ |
| |
| if (chkfn(n) != 0) /* Already open? */ |
| return(0); /* Nothing to do. */ |
| |
| if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */ |
| fp[ZOFILE] = stdout; |
| ispipe[ZOFILE] = 0; |
| #ifdef COMMENT |
| /* This seems right but it breaks client server ops */ |
| fp[n] = stdout; |
| ispipe[n] = 0; |
| #endif /* COMMENT */ |
| #ifdef DEBUG |
| if (n != ZDFILE) |
| debug(F101,"zopeno fp[n]=stdout","",fp[n]); |
| #endif /* DEBUG */ |
| zoutcnt = 0; |
| zoutptr = zoutbuffer; |
| return(1); |
| } |
| |
| /* A real file. Open it in desired mode (create or append). */ |
| |
| #ifdef CKROOT |
| debug(F111,"zopeno setroot",ckroot,ckrootset); |
| if (ckrootset) if (!zinroot(name)) { |
| debug(F110,"zopeno setroot violation",name,0); |
| return(0); |
| } |
| #endif /* CKROOT */ |
| |
| ckstrncpy(p,"w",8); /* Assume write/create mode */ |
| if (fcb) { /* If called with an FCB... */ |
| if (fcb->dsp == XYFZ_A) { /* Does it say Append? */ |
| ckstrncpy(p,"a",8); /* Yes. */ |
| debug(F100,"zopeno append","",0); |
| append = 1; |
| } |
| } |
| |
| if (xferlog |
| #ifdef CKSYSLOG |
| || ((ckxsyslog >= SYSLG_FC) && ckxlogging) |
| #endif /* CKSYSLOG */ |
| ) { |
| getfullname(name); |
| debug(F110,"zopeno fullname",fullname,0); |
| } |
| debug(F110,"zopeno fopen arg",p,0); |
| fp[n] = fopen(name,p); /* Try to open the file */ |
| ispipe[ZIFILE] = 0; |
| |
| #ifdef ZDEBUG |
| printf("ZOPENO fp[%d]=%ld\n",n,fp[n]); |
| #endif /* ZDEBUG */ |
| |
| if (fp[n] == NULL) { /* Failed */ |
| debug(F101,"zopeno failed errno","",errno); |
| #ifdef CKSYSLOG |
| if (ckxsyslog >= SYSLG_FC && ckxlogging) |
| syslog(LOG_INFO, "file[%d] %s: %s failed (%m)", |
| n, |
| fullname, |
| append ? "append" : "create" |
| ); |
| #endif /* CKSYSLOG */ |
| #ifdef COMMENT /* Let upper levels print message. */ |
| perror("Can't open output file"); |
| #endif /* COMMENT */ |
| } else { /* Succeeded */ |
| extern int zofbuffer, zofblock, zobufsize; |
| debug(F101, "zopeno zobufsize", "", zobufsize); |
| if (n == ZDFILE || n == ZTFILE) { /* If debug or transaction log */ |
| setbuf(fp[n],NULL); /* make it unbuffered. */ |
| #ifdef DONDELAY |
| } else if (n == ZOFILE && !zofblock) { /* blocking or nonblocking */ |
| int flags; |
| if ((flags = fcntl(fileno(fp[n]),F_GETFL,0)) > -1) |
| fcntl(fileno(fp[n]),F_SETFL, flags | |
| #ifdef QNX |
| O_NONBLOCK |
| #else |
| O_NDELAY |
| #endif /* QNX */ |
| ); |
| debug(F100,"zopeno ZOFILE nonblocking","",0); |
| #endif /* DONDELAY */ |
| } else if (n == ZOFILE && !zofbuffer) { /* buffered or unbuffered */ |
| setbuf(fp[n],NULL); |
| debug(F100,"zopeno ZOFILE unbuffered","",0); |
| } |
| |
| #ifdef CK_LOGIN |
| /* Enforce anonymous file-creation permission */ |
| if (isguest) |
| if (n == ZWFILE || n == ZMFILE || |
| n == ZOFILE || n == ZDFILE || |
| n == ZTFILE || n == ZPFILE || |
| n == ZSFILE) |
| chmod(name,ckxperms); |
| #endif /* CK_LOGIN */ |
| #ifdef CKSYSLOG |
| if (ckxsyslog >= SYSLG_FC && ckxlogging) |
| syslog(LOG_INFO, "file[%d] %s: %s ok", |
| n, |
| fullname, |
| append ? "append" : "create" |
| ); |
| #endif /* CKSYSLOG */ |
| debug(F100, "zopeno ok", "", 0); |
| } |
| zoutcnt = 0; /* (PWP) reset output buffer */ |
| zoutptr = zoutbuffer; |
| return((fp[n] != NULL) ? 1 : 0); |
| } |
| |
| /* Z C L O S E -- Close the given file. */ |
| |
| /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */ |
| |
| int |
| zclose(n) int n; { |
| int x = 0, x2 = 0; |
| extern long ffc; |
| |
| debug(F101,"zclose file number","",n); |
| if (chkfn(n) < 1) return(0); /* Check range of n */ |
| if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */ |
| x2 = zoutdump(); |
| |
| if (fp[ZSYSFN] || ispipe[n]) { /* If file is really pipe */ |
| #ifndef NOPUSH |
| x = zclosf(n); /* do it specially */ |
| #else |
| x = EOF; |
| #endif /* NOPUSH */ |
| debug(F101,"zclose zclosf","",x); |
| debug(F101,"zclose zclosf fp[n]","",fp[n]); |
| } else { |
| if ((fp[n] != stdout) && (fp[n] != stdin)) |
| x = fclose(fp[n]); |
| fp[n] = NULL; |
| #ifdef COMMENT |
| if (n == ZCTERM || n == ZSTDIO) /* See zopeno() */ |
| if (fp[ZOFILE] == stdout) |
| fp[ZOFILE] = NULL; |
| #endif /* COMMENT */ |
| } |
| iflen = -1L; /* Invalidate file length */ |
| if (x == EOF) { /* if we got a close error */ |
| debug(F101,"zclose fclose fails","",x); |
| return(-1); |
| } else if (x2 < 0) { /* or error flushing last buffer */ |
| debug(F101,"zclose error flushing last buffer","",x2); |
| return(-1); /* then return an error */ |
| } else { |
| /* Print log record compatible with wu-ftpd */ |
| if (xferlog && (n == ZIFILE || n == ZOFILE)) { |
| char * s, *p; |
| extern char ttname[]; |
| if (!iklogopen) (VOID) doiklog(); /* Open log if necessary */ |
| debug(F101,"zclose iklogopen","",iklogopen); |
| if (iklogopen) { |
| int len; |
| char * fnam; |
| |
| timenow = time(NULL); |
| #ifdef CK_LOGIN |
| if (logged_in) |
| s = clienthost; |
| else |
| #endif /* CK_LOGIN */ |
| s = (char *)ttname; |
| if (!s) s = ""; |
| if (!*s) s = "*"; |
| #ifdef CK_LOGIN |
| if (logged_in) { |
| p = guestpass; |
| if (!*p) p = "*"; |
| } else |
| #endif /* CK_LOGIN */ |
| p = whoami(); |
| |
| len = 24 + 12 + (int)strlen(s) + 16 |
| + (int)strlen(fullname) + 1 + 1 + 1 + 1 |
| + (int)strlen(p) + 6 + 2 + 12; |
| fnam = fullname; |
| if (!*fnam) fnam = "(pipe)"; |
| |
| if (len > IKSDMSGLEN) |
| sprintf(iksdmsg, /* SAFE */ |
| "%.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", |
| ctime(&timenow), /* date/time */ |
| gtimer(), /* elapsed secs */ |
| s, /* peer name */ |
| ffc, /* byte count */ |
| fnam, /* full pathname of file */ |
| (binary ? 'b' : 'a'), /* binary or ascii */ |
| "_", /* options = none */ |
| n == ZIFILE ? 'o' : 'i', /* in/out */ |
| #ifdef CK_LOGIN |
| (isguest ? 'a' : 'r'), /* User type */ |
| #else |
| 'r', |
| #endif /* CK_LOGIN */ |
| p, /* Username or guest passwd */ |
| #ifdef CK_LOGIN |
| logged_in ? "iks" : "kermit", /* Record ID */ |
| #else |
| "kermit", |
| #endif /* CK_LOGIN */ |
| 0, /* User ID on client system unknown */ |
| "*" /* Ditto */ |
| ); |
| debug(F110,"zclose iksdmsg",iksdmsg,0); |
| write(xferlog, iksdmsg, (int)strlen(iksdmsg)); |
| } |
| } |
| debug(F101,"zclose returns","",1); |
| return(1); |
| } |
| } |
| |
| /* Z C H I N -- Get a character from the input file. */ |
| |
| /* Returns -1 if EOF, 0 otherwise with character returned in argument */ |
| |
| int |
| zchin(n,c) int n; int *c; { |
| int a; |
| |
| #ifdef IKSD |
| if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { |
| a = coninc(0); |
| if (*c < 0) |
| return(-1); |
| } else |
| #endif /* IKSD */ |
| /* (PWP) Just in case this gets called when it shouldn't. */ |
| if (n == ZIFILE) { |
| a = zminchar(); /* Note: this catches Ctrl-Z */ |
| if (a < 0) /* (See zinfill()...) */ |
| return(-1); |
| } else { |
| a = getc(fp[n]); |
| if (a == EOF) return(-1); |
| #ifdef CK_CTRLZ |
| /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */ |
| if (!binary && a == 0x1A && eofmethod == XYEOF_Z) |
| return(-1); |
| #endif /* CK_CTRLZ */ |
| } |
| *c = (CHAR) a & 0377; |
| return(0); |
| } |
| |
| /* Z S I N L -- Read a line from a file */ |
| |
| /* |
| Writes the line into the address provided by the caller. |
| n is the Kermit "channel number". |
| Writing terminates when newline is encountered, newline is not copied. |
| Writing also terminates upon EOF or if length x is exhausted. |
| Returns 0 on success, -1 on EOF or error. |
| */ |
| int |
| zsinl(n,s,x) int n, x; char *s; { |
| int a, z = 0; /* z is return code. */ |
| int count = 0; |
| int len = 0; |
| char *buf; |
| extern CHAR feol; /* Line terminator */ |
| |
| if (!s || chkfn(n) < 1) /* Make sure file is open, etc */ |
| return(-1); |
| buf = s; |
| s[0] = '\0'; /* Don't return junk */ |
| |
| a = -1; /* Current character, none yet. */ |
| while (x--) { /* Up to given length */ |
| int old = 0; |
| if (feol) /* Previous character */ |
| old = a; |
| if (zchin(n,&a) < 0) { /* Read a character from the file */ |
| debug(F101,"zsinl zchin fail","",count); |
| if (count == 0) |
| z = -1; /* EOF or other error */ |
| break; |
| } else |
| count++; |
| if (feol) { /* Single-character line terminator */ |
| if (a == feol) |
| break; |
| } else { /* CRLF line terminator */ |
| if (a == '\015') /* CR, get next character */ |
| continue; |
| if (old == '\015') { /* Previous character was CR */ |
| if (a == '\012') { /* This one is LF, so we have a line */ |
| break; |
| } else { /* Not LF, deposit CR */ |
| *s++ = '\015'; |
| x--; |
| len++; |
| } |
| } |
| } |
| *s = a; /* Deposit character */ |
| s++; |
| len++; |
| } |
| *s = '\0'; /* Terminate the string */ |
| debug(F011,"zsinl",buf,len); |
| return(z); |
| } |
| |
| /* Z X I N -- Read x bytes from a file */ |
| |
| /* |
| Reads x bytes (or less) from channel n and writes them |
| to the address provided by the caller. |
| Returns number of bytes read on success, 0 on EOF or error. |
| */ |
| int |
| zxin(n,s,x) int n, x; char *s; { |
| #ifdef IKSD |
| if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { |
| int a, i; |
| a = ttchk(); |
| if (a < 1) return(0); |
| for (i = 0; i < a && i < x; i++) |
| s[i] = coninc(0); |
| return(i); |
| } |
| #endif /* IKSD */ |
| |
| return(fread(s, sizeof (char), x, fp[n])); |
| } |
| |
| /* |
| Z I N F I L L -- Buffered file input. |
| |
| (re)fill the file input buffer with data. All file input |
| should go through this routine, usually by calling the zminchar() |
| macro defined in ckcker.h. Returns: |
| |
| Value 0..255 on success, the character that was read. |
| -1 on end of file. |
| -2 on any kind of error other than end of file. |
| -3 timeout when reading from pipe (Kermit packet mode only). |
| */ |
| int |
| zinfill() { |
| extern int kactive, srvping; |
| errno = 0; |
| |
| #ifdef ZDEBUG |
| printf("ZINFILL fp[%d]=%ld\n",ZIFILE,fp[ZIFILE]); |
| #endif /* ZDEBUG */ |
| |
| #ifdef IKSD |
| if (inserver && !local && fp[ZIFILE] == stdin) { |
| int a, i; |
| a = ttchk(); |
| if (a < 0) return(-2); |
| for (i = 0; i < a && i < INBUFSIZE; i++) { |
| zinbuffer[i] = coninc(0); |
| } |
| zincnt = i; |
| /* set pointer to beginning, (== &zinbuffer[0]) */ |
| zinptr = zinbuffer; |
| if (zincnt == 0) return(-1); |
| zincnt--; /* One less char in buffer */ |
| return((int)(*zinptr++) & 0377); /* because we return the first */ |
| } |
| #endif /* IKSD */ |
| |
| debug(F101,"zinfill kactive","",kactive); |
| |
| if (!(kactive && ispipe[ZIFILE])) { |
| if (feof(fp[ZIFILE])) { |
| debug(F100,"ZINFILL feof","",0); |
| #ifdef ZDEBUG |
| printf("ZINFILL EOF\n"); |
| #endif /* ZDEBUG */ |
| return(-1); |
| } |
| } |
| clearerr(fp[ZIFILE]); |
| |
| #ifdef SELECT |
| /* Here we can call select() to get a timeout... */ |
| if (kactive && ispipe[ZIFILE]) { |
| int secs, z = 0; |
| #ifndef NOXFER |
| if (srvping) { |
| secs = 1; |
| debug(F101,"zinfill calling ttwait","",secs); |
| z = ttwait(fileno(fp[ZIFILE]),secs); |
| debug(F101,"zinfill ttwait","",z); |
| } |
| #endif /* NOXFER */ |
| if (z == 0) |
| return(-3); |
| } |
| #endif /* SELECT */ |
| |
| #ifdef DEBUG |
| if (deblog) { |
| int i; |
| debug(F101,"ZINFILL INBUFSIZE","",INBUFSIZE); |
| #ifdef USE_MEMCPY |
| memset(zinbuffer, 0xFF, INBUFSIZE); |
| #else |
| for (i = 0; i < INBUFSIZE; i++) { |
| zinbuffer[i] = 0xFF; |
| #ifdef COMMENT /* Too much! */ |
| debug(F101,"ZINFILL zinbuffer[i]","",i); |
| #endif /* COMMENT */ |
| } |
| #endif /* USE_MEMCPY */ |
| ckstrncpy(zinbuffer,"zinbuffer is a valid buffer",INBUFSIZE); |
| debug(F111,"ZINFILL about to call fread",zinbuffer,zinbuffer); |
| } |
| #endif /* DEBUG */ |
| |
| /* |
| Note: The following read MUST be nonblocking when reading from a pipe |
| and we want timeouts to work. See zxcmd(). |
| */ |
| zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]); |
| debug(F101,"ZINFILL fread","",zincnt); /* Just the size */ |
| #ifdef ZDEBUG |
| printf("FREAD=%d\n",zincnt); |
| #endif /* ZDEBUG */ |
| #ifdef CK_CTRLZ |
| /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */ |
| if (zincnt > 0 && !binary && eofmethod == XYEOF_Z) { |
| register int i; |
| for (i = 0; i < zincnt; i++) { |
| if (zinbuffer[i] == SUB) { |
| zincnt = i; /* Stop at first Ctrl-Z */ |
| if (i == 0) |
| return(-1); |
| break; |
| } |
| } |
| } |
| #endif /* CK_CTRLZ */ |
| |
| if (zincnt == 0) { /* Got nothing? */ |
| if (ferror(fp[ZIFILE])) { |
| debug(F100,"ZINFILL ferror","",0); |
| debug(F101,"ZINFILL errno","",errno); |
| #ifdef ZDEBUG |
| printf("ZINFILL errno=%d\n",errno); |
| #endif /* ZDEBUG */ |
| #ifdef EWOULDBLOCK |
| return((errno == EWOULDBLOCK) ? -3 : -2); |
| #else |
| return(-2); |
| #endif /* EWOULDBLOCK */ |
| } |
| |
| /* In case feof() didn't work just above -- sometimes it doesn't... */ |
| |
| if (feof(fp[ZIFILE]) ) { |
| debug(F100,"ZINFILL count 0 EOF return -1","",0); |
| return (-1); |
| } else { |
| debug(F100,"ZINFILL count 0 not EOF return -2","",0); |
| return(-2); |
| } |
| } |
| zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */ |
| zincnt--; /* One less char in buffer */ |
| return((int)(*zinptr++) & 0377); /* because we return the first */ |
| } |
| |
| /* Z S O U T -- Write a string out to the given file, buffered. */ |
| |
| int |
| zsout(n,s) int n; char *s; { |
| int rc = 0; |
| rc = chkfn(n); |
| if (rc < 1) return(-1); /* Keep this, prevents memory faults */ |
| if (!s) return(0); /* Null pointer, do nothing, succeed */ |
| if (!*s) return(0); /* empty string, ditto */ |
| |
| #ifdef IKSD |
| /* |
| This happens with client-side Kermit server when a REMOTE command |
| was sent from the server to the client and the server is supposed to |
| display the text, but of course there is no place to display it |
| since it is in remote mode executing Kermit protocol. |
| */ |
| if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { |
| #ifdef COMMENT |
| return(ttol(s,((int)strlen(s)) < 0) ? -1 : 0); |
| #else |
| return(0); |
| #endif /* COMMENT */ |
| } |
| #endif /* IKSD */ |
| |
| if (n == ZSFILE) |
| return(write(fileno(fp[n]),s,(int)strlen(s))); |
| rc = fputs(s,fp[n]) == EOF ? -1 : 0; |
| if (n == ZWFILE) |
| fflush(fp[n]); |
| return(rc); |
| } |
| |
| /* Z S O U T L -- Write string to file, with line terminator, buffered */ |
| |
| int |
| zsoutl(n,s) int n; char *s; { |
| if (zsout(n,s) < 0) |
| return(-1); |
| |
| #ifdef IKSD |
| if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { |
| #ifdef COMMENT |
| return(ttoc(LF)); |
| #else |
| return(0); /* See comments in zsout() */ |
| #endif /* COMMENT */ |
| } |
| #endif /* IKSD */ |
| |
| if (n == ZSFILE) /* Session log is unbuffered */ |
| return(write(fileno(fp[n]),"\n",1)); |
| else if (fputs("\n",fp[n]) == EOF) |
| return(-1); |
| if (n == ZDIFIL || n == ZWFILE) /* Flush connection log records */ |
| fflush(fp[n]); |
| return(0); |
| } |
| |
| /* Z S O U T X -- Write x characters to file, unbuffered. */ |
| |
| int |
| zsoutx(n,s,x) int n, x; char *s; { |
| #ifdef IKSD |
| if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { |
| #ifdef COMMENT |
| return(ttol(s,x)); /* See comments in zsout() */ |
| #else |
| return(x); |
| #endif /* COMMENT */ |
| } |
| #endif /* IKSD */ |
| |
| #ifdef COMMENT |
| if (chkfn(n) < 1) return(-1); |
| return(write(fp[n]->_file,s,x)); |
| #endif /* COMMENT */ |
| return(write(fileno(fp[n]),s,x) == x ? x : -1); |
| } |
| |
| /* Z C H O U T -- Add a character to the given file. */ |
| |
| /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */ |
| |
| int |
| #ifdef CK_ANSIC |
| zchout(register int n, char c) |
| #else |
| zchout(n,c) register int n; char c; |
| #endif /* CK_ANSIC */ |
| /* zchout() */ { |
| /* if (chkfn(n) < 1) return(-1); */ |
| |
| #ifdef IKSD |
| if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { |
| #ifdef COMMENT |
| return(ttoc(c)); |
| #else |
| return(0); /* See comments in zsout() */ |
| #endif /* COMMENT */ |
| } |
| #endif /* IKSD */ |
| |
| if (n == ZSFILE) /* Use unbuffered for session log */ |
| return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1); |
| /* Buffered for everything else */ |
| if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */ |
| return(ferror(fp[n])?-1:0); /* Check to make sure */ |
| else /* Otherwise... */ |
| return(0); /* There was no error. */ |
| } |
| |
| /* (PWP) buffered character output routine to speed up file IO */ |
| |
| int |
| zoutdump() { |
| int x; |
| char * zp; |
| zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */ |
| #ifdef DEBUG |
| if (deblog) |
| debug(F101,"zoutdump zoutcnt","",zoutcnt); |
| #endif /* DEBUG */ |
| if (zoutcnt == 0) { /* Nothing to output */ |
| return(0); |
| } else if (zoutcnt < 0) { /* Unexpected negative argument */ |
| zoutcnt = 0; /* Reset output buffer count */ |
| return(-1); /* and fail. */ |
| } |
| |
| #ifdef IKSD |
| if (inserver && !local && fp[ZOFILE] == stdout) { |
| #ifdef COMMENT |
| x = ttol(zoutbuffer,zoutcnt); |
| #else |
| x = 1; /* See comments in zsout() */ |
| #endif /* COMMENT */ |
| zoutcnt = 0; |
| return(x > 0 ? 0 : -1); |
| } |
| #endif /* IKSD */ |
| |
| /* |
| Frank Prindle suggested that replacing this fwrite() by an fflush() |
| followed by a write() would improve the efficiency, especially when |
| writing to stdout. Subsequent tests showed a 5-fold improvement. |
| */ |
| #ifdef COMMENT |
| if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) ... |
| #endif /* COMMENT */ |
| |
| #ifndef CK_NONBLOCK |
| fflush(fp[ZOFILE]); |
| #endif /* CK_NONBLOCK */ |
| zp = zoutbuffer; |
| while (zoutcnt > 0) { |
| if ((x = write(fileno(fp[ZOFILE]),zp,zoutcnt)) > -1) { |
| #ifdef DEBUG |
| if (deblog) /* Save a function call... */ |
| debug(F101,"zoutdump wrote","",x); |
| #endif /* DEBUG */ |
| zoutcnt -= x; /* Adjust output buffer count */ |
| zp += x; /* and pointer */ |
| } else { |
| #ifdef DEBUG |
| if (deblog) { |
| debug(F101,"zoutdump write error","",errno); |
| debug(F101,"zoutdump write returns","",x); |
| } |
| #endif /* DEBUG */ |
| zoutcnt = 0; /* Reset output buffer count */ |
| return(-1); /* write() failed */ |
| } |
| } |
| return(0); |
| } |
| |
| /* C H K F N -- Internal function to verify file number is ok */ |
| |
| /* |
| Returns: |
| -1: File number n is out of range |
| 0: n is in range, but file is not open |
| 1: n in range and file is open |
| */ |
| int |
| chkfn(n) int n; { |
| /* if (n != ZDFILE) debug(F101,"chkfn","",n); */ |
| if (n < 0 || n >= ZNFILS) { |
| if (n != ZDFILE) debug(F101,"chkfn out of range","",n); |
| return(-1); |
| } else { |
| /* if (n != ZDFILE) debug(F101,"chkfn fp[n]","",fp[n]); */ |
| return((fp[n] == NULL) ? 0 : 1); |
| } |
| } |
| |
| /* Z G E T F S -- Return file size regardless of accessibility */ |
| /* |
| Used for directory listings, etc. |
| Returns: |
| The size of the file in bytes, 0 or greater, if the size can be learned. |
| -1 if the file size can not be obtained. |
| Also (and this is a hack just for UNIX): |
| If the argument is the name of a symbolic link, |
| the global variable issymlink is set to 1, |
| and the global buffer linkname[] gets the link value. |
| And it sets zgfs_dir to 1 if it's a directory, otherwise 0. |
| This lets us avoid numerous redundant calls to stat(). |
| */ |
| int zgfs_link = 0; |
| int zgfs_dir = 0; |
| time_t zgfs_mtime = 0; |
| unsigned int zgfs_mode = 0; |
| |
| #ifdef CKSYMLINK |
| char linkname[CKMAXPATH+1]; |
| #ifndef _IFLNK |
| #define _IFLNK 0120000 |
| #endif /* _IFLNK */ |
| #endif /* CKSYMLINK */ |
| |
| long |
| zgetfs(name) char *name; { |
| struct stat buf; |
| char fnam[CKMAXPATH+4]; |
| long size = -1L; |
| int x; |
| int needrlink = 0; |
| char * s; |
| |
| if (!name) name = ""; |
| if (!*name) return(-1); |
| |
| #ifdef UNIX |
| x = strlen(name); |
| if (x == 9 && !strcmp(name,"/dev/null")) |
| return(0); |
| #endif /* UNIX */ |
| |
| s = name; |
| #ifdef DTILDE |
| if (*s == '~') { |
| s = tilde_expand(s); |
| if (!s) s = ""; |
| if (!*s) s = name; |
| } |
| #endif /* DTILDE */ |
| x = ckstrncpy(fnam,s,CKMAXPATH); |
| s = fnam; |
| debug(F111,"zgetfs fnam",s,x); |
| if (x > 0 && s[x-1] == '/') |
| s[x-1] = '\0'; |
| |
| zgfs_dir = 0; /* Assume it's not a directory */ |
| zgfs_link = 0; /* Assume it's not a symlink */ |
| zgfs_mtime = 0; /* No time yet */ |
| zgfs_mode = 0; /* No permission bits yet */ |
| |
| #ifdef CKSYMLINK /* We're doing symlinks? */ |
| #ifdef USE_LSTAT /* OK to use lstat()? */ |
| x = lstat(s,&buf); |
| debug(F101,"STAT","",1); |
| if (x < 0) /* stat() failed */ |
| return(-1); |
| if ( /* Now see if it's a symlink */ |
| #ifdef S_ISLNK |
| S_ISLNK(buf.st_mode) |
| #else |
| #ifdef _IFLNK |
| ((_IFMT & buf.st_mode) == _IFLNK) |
| #endif /* _IFLNK */ |
| #endif /* S_ISLNK */ |
| ) { |
| zgfs_link = 1; /* It's a symlink */ |
| linkname[0] = '\0'; /* Get the name */ |
| x = readlink(s,linkname,CKMAXPATH); |
| debug(F101,"zgetfs readlink",s,x); |
| if (x > -1 && x < CKMAXPATH) { /* It's a link */ |
| linkname[x] = '\0'; |
| size = buf.st_size; /* Remember size of link */ |
| x = stat(s,&buf); /* Now stat the linked-to file */ |
| debug(F101,"STAT","",2); |
| if (x < 0) /* so we can see if it's a directory */ |
| return(-1); |
| } else { |
| ckstrncpy(linkname,"(lookup failed)",CKMAXPATH); |
| } |
| } |
| #else /* !USE_LSTAT */ |
| x = stat(s,&buf); /* No lstat(), use stat() instead */ |
| debug(F101,"STAT","",3); |
| if (x < 0) |
| return(-1); |
| #endif /* USE_LSTAT */ |
| |
| /* Do we need to call readlink()? */ |
| |
| #ifdef NOLINKBITS |
| /* |
| lstat() does not work in SCO operating systems. From "man NS lstat": |
| |
| lstat obtains information about the file named by path. In the case of a |
| symbolic link, lstat returns information about the link, and not the file |
| named by the link. It is only used by the NFS automount daemon and should |
| not be utilized by users. |
| */ |
| needrlink = 1; |
| debug(F101,"zgetfs forced needrlink","",needrlink); |
| #else |
| #ifdef S_ISLNK |
| needrlink = S_ISLNK(buf.st_mode); |
| debug(F101,"zgetfs S_ISLNK needrlink","",needrlink); |
| #else |
| #ifdef _IFLNK |
| needrlink = (_IFMT & buf.st_mode) == _IFLNK; |
| debug(F101,"zgetfs _IFLNK needrlink","",needrlink); |
| #else |
| needrlink = 1; |
| debug(F101,"zgetfs default needrlink","",needrlink); |
| #endif /* _IFLNK */ |
| #endif /* S_ISLNK */ |
| #endif /* NOLINKBITS */ |
| |
| if (needrlink) { |
| linkname[0] = '\0'; |
| errno = 0; |
| x = readlink(s,linkname,CKMAXPATH); |
| #ifdef DEBUG |
| debug(F111,"zgetfs readlink",s,x); |
| if (x < 0) |
| debug(F101,"zgetfs readlink errno","",errno); |
| else |
| debug(F110,"zgetfs readlink result",linkname,0); |
| #endif /* DEBUG */ |
| if (x > -1 && x < CKMAXPATH) { |
| zgfs_link = 1; |
| linkname[x] = '\0'; |
| } |
| } |
| #else /* !CKSYMLINK */ |
| x = stat(s,&buf); /* Just stat the file */ |
| debug(F111,"zgetfs stat",s,x); |
| if (x < 0) /* and get the size */ |
| return(-1); |
| #endif /* CKSYMLINK */ |
| |
| zgfs_mtime = buf.st_mtime; |
| zgfs_mode = buf.st_mode; |
| zgfs_dir = (S_ISDIR(buf.st_mode)) ? 1 : 0; /* Set "is directory" flag */ |
| debug(F111,"zgetfs size",s,size); |
| debug(F111,"zgetfs st_size",s,buf.st_size); |
| return((size < 0L) ? buf.st_size : size); /* Return the size */ |
| } |
| |
| |
| /* Z C H K I -- Check if input file exists and is readable */ |
| |
| /* |
| Returns: |
| >= 0 if the file can be read (returns the size). |
| -1 if file doesn't exist or can't be accessed, |
| -2 if file exists but is not readable (e.g. a directory file). |
| -3 if file exists but protected against read access. |
| |
| For Berkeley Unix, a file must be of type "regular" to be readable. |
| Directory files, special files, and symbolic links are not readable. |
| */ |
| long |
| zchki(name) char *name; { |
| struct stat buf; |
| char * s; |
| int x, itsadir = 0; |
| extern int zchkid, diractive, matchfifo; |
| |
| if (!name) |
| return(-1); |
| x = strlen(name); |
| if (x < 1) |
| return(-1); |
| s = name; |
| |
| #ifdef UNIX |
| if (x == 9 && !strcmp(s,"/dev/null")) |
| return(0); |
| if (x == 8 && !strcmp(s,"/dev/tty")) |
| return(0); |
| #endif /* UNIX */ |
| |
| #ifdef DTILDE |
| if (*s == '~') { |
| s = tilde_expand(s); |
| if (!s) s = ""; |
| if (!*s) s = name; |
| } |
| #endif /* DTILDE */ |
| |
| #ifdef CKROOT |
| debug(F111,"zchki setroot",ckroot,ckrootset); |
| if (ckrootset) if (!zinroot(name)) { |
| debug(F110,"zchki setroot violation",name,0); |
| return(-1); |
| } |
| #endif /* CKROOT */ |
| |
| x = stat(s,&buf); |
| debug(F101,"STAT","",5); |
| if (x < 0) { |
| debug(F111,"zchki stat fails",s,errno); |
| return(-1); |
| } |
| if (S_ISDIR (buf.st_mode)) |
| itsadir = 1; |
| |
| if (!(itsadir && zchkid)) { /* Unless this... */ |
| if (!S_ISREG (buf.st_mode) /* Must be regular file */ |
| #ifdef S_ISFIFO |
| && (!matchfifo || !S_ISFIFO (buf.st_mode)) /* or FIFO */ |
| #endif /* S_ISFIFO */ |
| ) { |
| debug(F111,"zchki not regular file (or fifo)",s,matchfifo); |
| return(-2); |
| } |
| } |
| debug(F111,"zchki stat ok:",s,x); |
| |
| if (diractive) { /* If listing don't check access */ |
| x = 1; |
| } else { |
| #ifdef SW_ACC_ID |
| debug(F100,"zchki swapping ids for access()","",0); |
| priv_on(); |
| #endif /* SW_ACC_ID */ |
| if ((x = access(s,R_OK)) < 0) |
| x = access(s,X_OK); /* For RUN-class commands */ |
| #ifdef SW_ACC_ID |
| priv_off(); |
| debug(F100,"zchki swapped ids restored","",0); |
| #endif /* SW_ACC_ID */ |
| } |
| if (x < 0) { /* Is the file accessible? */ |
| debug(F111,"zchki access failed:",s,x); /* No */ |
| return(-3); |
| } else { |
| iflen = buf.st_size; /* Yes, remember size */ |
| ckstrncpy(nambuf,s,CKMAXPATH); /* and name globally. */ |
| debug(F111,"zchki access ok:",s,iflen); |
| return((iflen > -1L) ? iflen : 0L); |
| } |
| } |
| |
| /* Z C H K O -- Check if output file can be created */ |
| |
| /* |
| Returns -1 if write permission for the file would be denied, 0 otherwise. |
| |
| NOTE: The design is flawed. There is no distinction among: |
| . Can I overwrite an existing file? |
| . Can I create a file (or directory) in an existing directory? |
| . Can I create a file (or directory) and its parent(s)? |
| */ |
| int |
| zchko(name) char *name; { |
| int i, x, itsadir = 0; |
| char *s; |
| char * oname; |
| extern int zchkod; /* Used by IF WRITEABLE */ |
| |
| debug(F110,"zchko entry",name,0); |
| |
| if (!name) return(-1); /* Watch out for null pointer. */ |
| |
| oname = name; |
| |
| #ifdef CKROOT |
| debug(F111,"zchko setroot",ckroot,ckrootset); |
| if (ckrootset) if (!zinroot(name)) { |
| debug(F110,"zchko setroot violation",name,0); |
| errno = EACCES; |
| return(-1); |
| } |
| #endif /* CKROOT */ |
| |
| x = (int)strlen(name); /* Get length of filename */ |
| debug(F111,"zchko len",name,x); |
| debug(F111,"zchko zchkod",name,zchkod); |
| |
| #ifdef UNIX |
| /* |
| Writing to null device is OK. |
| */ |
| if (x == 9 && !strcmp(name,"/dev/null")) |
| return(0); |
| if (x == 8 && !strcmp(name,"/dev/tty")) |
| return(0); |
| #endif /* UNIX */ |
| |
| s = name; |
| #ifdef DTILDE |
| if (*s == '~') { |
| s = tilde_expand(s); |
| if (!s) s = ""; |
| if (!*s) s = name; |
| x = strlen(s); |
| } |
| #endif /* DTILDE */ |
| name = s; |
| s = NULL; |
| /* |
| 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); |
| |
| 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); |
| |
| for (i = x; i > 0; i--) { /* Strip filename from right. */ |
| if (ISDIRSEP(s[i-1])) { |
| itsadir = 1; |
| break; |
| } |
| } |
| debug(F101,"zchko i","",i); |
| debug(F101,"zchko itsadir","",itsadir); |
| |
| #ifdef COMMENT |
| /* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */ |
| if (i == 0) /* If no path, use current directory */ |
| strcpy(s,"./"); |
| else /* Otherwise, use given one. */ |
| s[i] = '\0'; |
| #else |
| #ifdef COMMENT |
| /* |
| The following does not work for "foo/bar" where the foo directory does |
| not exist even though we could create it: access("foo/.") fails, but |
| access("foo") works OK. |
| */ |
| /* So now we use "path/." if path given, or "." if no path given. */ |
| s[i++] = '.'; /* Append "." to path. */ |
| s[i] = '\0'; |
| #else |
| /* So NOW we strip path segments from the right as long as they don't */ |
| /* exist -- we only call access() for path segments that *do* exist.. */ |
| /* (But this isn't quite right either since now zchko(/foo/bar/baz/xxx) */ |
| /* succeeds when I have write access to foo and bar but baz doesn't exit.) */ |
| |
| if (itsadir && i > 0) { |
| s[i-1] = '\0'; |
| while (s[0] && !isdir(s)) { |
| for (i = (int)strlen(s); i > 0; i--) { |
| if (ISDIRSEP(s[i-1])) { |
| s[i-1] = '\0'; |
| break; |
| } |
| } |
| if (i == 0) |
| s[0] = '\0'; |
| } |
| } else { |
| s[i++] = '.'; /* Append "." to path. */ |
| s[i] = '\0'; |
| } |
| #endif /* COMMENT */ |
| #endif /* COMMENT */ |
| |
| if (!s[0]) |
| ckstrncpy(s,".",x+3); |
| |
| #ifdef SW_ACC_ID |
| debug(F100,"zchko swapping ids for access()","",0); |
| priv_on(); |
| #endif /* SW_ACC_ID */ |
| |
| x = access(s,W_OK); /* Check access of path. */ |
| |
| #ifdef SW_ACC_ID |
| priv_off(); |
| debug(F100,"zchko swapped ids restored","",0); |
| #endif /* SW_ACC_ID */ |
| |
| if (x < 0) |
| debug(F111,"zchko access failed:",s,errno); |
| else |
| debug(F111,"zchko access ok:",s,x); |
| free(s); /* Free temporary storage */ |
| |
| return((x < 0) ? -1 : 0); /* and return. */ |
| } |
| |
| /* Z D E L E T -- Delete the named file. */ |
| |
| /* Returns: -1 on error, 0 on success */ |
| |
| int |
| zdelet(name) char *name; { |
| int x; |
| #ifdef CK_LOGIN |
| if (isguest) |
| return(-1); |
| #endif /* CK_LOGIN */ |
| |
| #ifdef CKROOT |
| debug(F111,"zdelet setroot",ckroot,ckrootset); |
| if (ckrootset) if (!zinroot(name)) { |
| debug(F110,"zdelet setroot violation",name,0); |
| return(-1); |
| } |
| #endif /* CKROOT */ |
| |
| x = unlink(name); |
| debug(F111,"zdelet",name,x); |
| #ifdef CKSYSLOG |
| if (ckxsyslog >= SYSLG_FC && ckxlogging) { |
| fullname[0] = '\0'; |
| zfnqfp(name,CKMAXPATH,fullname); |
| debug(F110,"zdelet fullname",fullname,0); |
| if (x < 0) |
| syslog(LOG_INFO, "file[] %s: delete failed (%m)", fullname); |
| else |
| syslog(LOG_INFO, "file[] %s: delete ok", fullname); |
| } |
| #endif /* CKSYSLOG */ |
| return(x); |
| } |
| |
| /* Z R T O L -- Convert remote filename into local form */ |
| |
| VOID |
| zrtol(name,name2) char *name, *name2; { |
| nzrtol(name,name2,1,0,CKMAXPATH); |
| } |
| |
| VOID |
| nzrtol(name,name2,fncnv,fnrpath,max) |
| char *name, *name2; int fncnv, fnrpath, max; |
| { /* nzrtol */ |
| char *s, *p; |
| int flag = 0, n = 0; |
| char fullname[CKMAXPATH+1]; |
| int devnull = 0; |
| int acase = 0; |
| if (!name2) return; |
| if (!name) name = ""; |
| |
| debug(F111,"nzrtol name",name,fncnv); |
| |
| #ifdef DTILDE |
| s = name; |
| if (*s == '~') { |
| s = tilde_expand(s); |
| if (!s) s = ""; |
| if (*s) name = s; |
| } |
| #endif /* DTILDE */ |
| |
| /* Handle the path -- we don't have to convert its format, since */ |
| /* the standard path format and our (UNIX) format are the same. */ |
| |
| fullname[0] = NUL; |
| devnull = !strcmp(name,"/dev/null"); |
| |
| if (!devnull && fnrpath == PATH_OFF) { /* RECEIVE PATHNAMES OFF */ |
| zstrip(name,&p); |
| strncpy(fullname,p,CKMAXPATH); |
| } else if (!devnull && fnrpath == PATH_ABS) { /* REC PATHNAMES ABSOLUTE */ |
| strncpy(fullname,name,CKMAXPATH); |
| } else if (!devnull && isabsolute(name)) { /* RECEIVE PATHNAMES RELATIVE */ |
| ckmakmsg(fullname,CKMAXPATH,".",name,NULL,NULL); |
| } else { /* Ditto */ |
| ckstrncpy(fullname,name,CKMAXPATH); |
| } |
| fullname[CKMAXPATH] = NUL; |
| debug(F110,"nzrtol fullname",fullname,0); |
| |
| #ifndef NOTRUNCATE |
| /* |
| The maximum length for any segment of a filename is MAXNAMLEN, defined |
| above. On some platforms (at least QNX) if a segment exceeds this limit, |
| the open fails with ENAMETOOLONG, so we must prevent it by truncating each |
| overlong name segment to the maximum segment length before passing the |
| name to open(). This must be done even when file names are literal, so as |
| not to halt a file transfer unnecessarily. |
| */ |
| { |
| char buf[CKMAXPATH+1]; /* New temporary buffer on stack */ |
| char *p = fullname; /* Source and */ |
| char *s = buf; /* destination pointers */ |
| int i = 0, n = 0; |
| debug(F101,"nzrtol sizing MAXNAMLEN","",MAXNAMLEN); |
| while (*p && n < CKMAXPATH) { /* Copy name to new buffer */ |
| if (++i > MAXNAMLEN) { /* If this segment too long */ |
| while (*p && *p != '/') /* skip past the rest... */ |
| p++; |
| i = 0; /* and reset counter. */ |
| } else if (*p == '/') { /* End of this segment. */ |
| i = 0; /* Reset counter. */ |
| } |
| *s++ = *p++; /* Copy this character. */ |
| n++; |
| } |
| *s = NUL; |
| ckstrncpy(fullname,buf,CKMAXPATH); /* Copy back to original buffer. */ |
| debug(F111,"nzrtol sizing",fullname,n); |
| } |
| #endif /* NOTRUNCATE */ |
| |
| if (!fncnv || devnull) { /* Not converting */ |
| ckstrncpy(name2,fullname,max); /* We're done. */ |
| return; |
| } |
| name = fullname; /* Converting */ |
| |
| p = name2; |
| for (; *name != '\0' && n < maxnam; name++) { |
| if (*name > SP) flag = 1; /* Strip leading blanks and controls */ |
| if (flag == 0 && *name < '!') |
| continue; |
| if (fncnv > 0) { |
| if (*name == SP) { |
| *p++ = '_'; |
| n++; |
| continue; |
| } |
| if (isupper(*name)) /* Check for mixed case */ |
| acase |= 1; |
| else if (islower(*name)) |
| acase |= 2; |
| } |
| *p++ = *name; |
| n++; |
| } |
| *p-- = '\0'; /* Terminate */ |
| while (*p < '!' && p > name2) /* Strip trailing blanks & controls */ |
| *p-- = '\0'; |
| |
| if (*name2 == '\0') { /* Nothing left? */ |
| ckstrncpy(name2,"NONAME",max); /* do this... */ |
| } else if (acase == 1) { /* All uppercase? */ |
| p = name2; /* So convert all letters to lower */ |
| while (*p) { |
| if (isupper(*p)) |
| *p = tolower(*p); |
| p++; |
| } |
| } |
| debug(F110,"nzrtol new name",name2,0); |
| } |
| |
| |
| /* Z S T R I P -- Strip device & directory name from file specification */ |
| |
| /* Strip pathname from filename "name", return pointer to result in name2 */ |
| |
| static char work[CKMAXPATH+1]; |
| |
| VOID |
| zstrip(name,name2) char *name, **name2; { |
| char *cp, *pp; |
| int n = 0; |
| |
| debug(F110,"zstrip before",name,0); |
| if (!name) { *name2 = ""; return; } |
| pp = work; |
| #ifdef DTILDE |
| /* Strip leading tilde */ |
| if (*name == '~') name++; |
| debug(F110,"zstrip after tilde-stripping",name,0); |
| #endif /* DTILDE */ |
| for (cp = name; *cp; cp++) { |
| if (ISDIRSEP(*cp)) { |
| pp = work; |
| n = 0; |
| } else { |
| *pp++ = *cp; |
| if (n++ >= CKMAXPATH) |
| break; |
| } |
| } |
| *pp = '\0'; /* Terminate the string */ |
| *name2 = work; |
| debug(F110,"zstrip after",*name2,0); |
| } |
| |
| /* Z L T O R -- Local TO Remote */ |
| |
| VOID |
| zltor(name,name2) char *name, *name2; { |
| nzltor(name,name2,1,0,CKMAXPATH); |
| } |
| |
| /* N Z L T O R -- New Local TO Remote */ |
| |
| /* |
| fncnv = 0 for no conversion, > 0 for regular conversion, < 0 for minimal. |
| */ |
| VOID |
| nzltor(name,name2,fncnv,fnspath,max) |
| char *name, *name2; int fncnv, fnspath, max; |
| { /* nzltor */ |
| char *cp, *pp; |
| #ifdef COMMENT |
| int dc = 0; |
| #endif /* COMMENT */ |
| int n = 0; |
| char *dotp = NULL; |
| char *dirp = NULL; |
| char fullname[CKMAXPATH+1]; |
| char *p; |
| CHAR c; |
| |
| #ifndef NOCSETS |
| extern int fcharset, /* tcharset, */ language; |
| int langsv; |
| _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */ |
| #ifdef CK_ANSIC |
| extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); |
| #else |
| extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); |
| #endif /* CK_ANSIC */ |
| langsv = language; |
| language = L_USASCII; |
| #ifdef COMMENT |
| /* Proper translation of filenames must be done elsewhere */ |
| n = tcharset ? tcharset : TC_USASCII; |
| sxo = xls[n][fcharset]; |
| #else |
| sxo = xls[TC_USASCII][fcharset]; |
| #endif /* COMMENT */ |
| #endif /* NOCSETS */ |
| |
| debug(F110,"nzltor name",name,0); |
| |
| /* Handle pathname */ |
| |
| fullname[0] = NUL; |
| if (fnspath == PATH_OFF) { /* PATHNAMES OFF */ |
| zstrip(name,&p); |
| ckstrncpy(fullname,p,CKMAXPATH); |
| } else { /* PATHNAMES RELATIVE or ABSOLUTE */ |
| char * p = name; |
| while (1) { |
| if (!strncmp(p,"../",3)) |
| p += 3; |
| else if (!strncmp(p,"./",2)) |
| p += 2; |
| else |
| break; |
| } |
| if (fnspath == PATH_ABS) { /* ABSOLUTE */ |
| zfnqfp(p,CKMAXPATH,fullname); |
| } else { /* RELATIVE */ |
| ckstrncpy(fullname,p,CKMAXPATH); |
| } |
| } |
| debug(F110,"nzltor fullname",fullname,0); |
| |
| if (!fncnv) { /* Not converting */ |
| ckstrncpy(name2,fullname,max); /* We're done. */ |
| #ifndef NOCSETS |
| langsv = language; |
| #endif /* NOCSETS */ |
| return; |
| } |
| name = fullname; /* Converting */ |
| |
| #ifdef aegis |
| char *namechars; |
| int tilde = 0, bslash = 0; |
| |
| if ((namechars = getenv("NAMECHARS")) != NULL) { |
| if (ckstrchr(namechars, '~' ) != NULL) tilde = '~'; |
| if (ckstrchr(namechars, '\\') != NULL) bslash = '\\'; |
| } else { |
| tilde = '~'; |
| bslash = '\\'; |
| } |
| #endif /* aegis */ |
| |
| pp = work; /* Output buffer */ |
| for (cp = name, n = 0; *cp && n < max; cp++,n++) { /* Convert name chars */ |
| c = *cp; |
| #ifndef NOCSETS |
| if (sxo) c = (*sxo)(c); /* Convert to ASCII */ |
| #endif /* NOCSETS */ |
| if (fncnv > 0 && islower(c)) /* Uppercase letters */ |
| *pp++ = toupper(c); /* Change tilde to hyphen */ |
| else if (c == '~') |
| *pp++ = '-'; |
| else if (fncnv > 0 && c == '#') /* Change number sign to 'X' */ |
| *pp++ = 'X'; |
| else if (c == '*' || c == '?') /* Change wildcard chars to 'X' */ |
| *pp++ = 'X'; |
| else if (c == ' ') /* Change space to underscore */ |
| *pp++ = '_'; |
| else if (c < ' ') /* Change controls to 'X' */ |
| *pp++ = 'X'; |
| else if (fncnv > 0 && c == '.') { /* Change dot to underscore */ |
| dotp = pp; /* Remember where we last did this */ |
| *pp++ = '_'; |
| } else { |
| if (c == '/') |
| dirp = pp; |
| *pp++ = c; |
| } |
| } |
| *pp = NUL; /* Tie it off. */ |
| #ifdef COMMENT |
| if (dotp) *dotp = '.'; /* Restore last dot (if any) */ |
| #else |
| if (dotp > dirp) *dotp = '.'; /* Restore last dot in file name */ |
| #endif /* COMMENT */ |
| cp = name2; /* If nothing before dot, */ |
| if (*work == '.') *cp++ = 'X'; /* insert 'X' */ |
| ckstrncpy(cp,work,max); |
| #ifndef NOCSETS |
| language = langsv; |
| #endif /* NOCSETS */ |
| debug(F110,"nzltor name2",name2,0); |
| } |
| |
| |
| /* Z C H D I R -- Change directory */ |
| /* |
| Call with: |
| dirnam = pointer to name of directory to change to, |
| which may be "" or NULL to indicate user's home directory. |
| Returns: |
| 0 on failure |
| 1 on success |
| */ |
| int |
| zchdir(dirnam) char *dirnam; { |
| char *hd, *sp; |
| #ifdef IKSDB |
| _PROTOTYP (int slotdir,(char *,char *)); |
| #endif /* IKSDB */ |
| #ifndef NOSPL |
| extern struct mtab *mactab; /* Main macro table */ |
| extern int nmac; /* Number of macros */ |
| #endif /* NOSPL */ |
| |
| debug(F110,"zchdir",dirnam,0); |
| if (!dirnam) dirnam = ""; |
| if (!*dirnam) /* If argument is null or empty, */ |
| dirnam = zhome(); /* use user's home directory. */ |
| sp = dirnam; |
| debug(F110,"zchdir 2",dirnam,0); |
| |
| #ifdef DTILDE |
| hd = tilde_expand(dirnam); /* Attempt to expand tilde */ |
| if (!hd) hd = ""; |
| if (*hd == '\0') hd = dirnam; /* in directory name. */ |
| #else |
| hd = dirnam; |
| #endif /* DTILDE */ |
| debug(F110,"zchdir 3",hd,0); |
| |
| #ifdef CKROOT |
| debug(F111,"zchdir setroot",ckroot,ckrootset); |
| if (ckrootset) if (!zinroot(hd)) { |
| debug(F110,"zchdir setroot violation",hd,0); |
| return(0); |
| } |
| #endif /* CKROOT */ |
| |
| #ifdef pdp11 |
| /* Just to save some space */ |
| return((chdir(hd) == 0) ? 1 : 0); |
| #else |
| if (chdir(hd) == 0) { /* Try to cd */ |
| #ifdef IKSDB |
| #ifdef CK_LOGIN |
| if (inserver && ikdbopen) |
| slotdir(isguest ? anonroot : "", zgtdir()); |
| #endif /* CK_LOGIN */ |
| #endif /* IKSDB */ |
| |
| #ifndef NOSPL |
| if (nmac) { /* Any macros defined? */ |
| int k; /* Yes */ |
| static int on_cd = 0; |
| if (!on_cd) { |
| on_cd = 1; |
| k = mlook(mactab,"on_cd",nmac); /* Look this up */ |
| if (k >= 0) { /* If found, */ |
| if (dodo(k,zgtdir(),0) > -1) /* set it up, */ |
| parser(1); /* and execute it */ |
| } |
| on_cd = 0; |
| } |
| } |
| #endif /* NOSPL */ |
| return(1); |
| } |
| return(0); |
| #endif /* pdp11 */ |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| zchkpid(unsigned long xpid) |
| #else |
| zchkpid(xpid) unsigned long xpid; |
| #endif /* CK_ANSIC */ |
| { |
| return((kill((PID_T)xpid,0) < 0) ? 0 : 1); |
| } |
| |
| |
| /* Z H O M E -- Return pointer to user's home directory */ |
| |
| static char * zhomdir = NULL; |
| |
| char * |
| zhome() { |
| char * home; |
| |
| #ifdef CKROOT |
| if (ckrootset) |
| return((char *)ckroot); |
| #endif /* CKROOT */ |
| |
| #ifdef Plan9 |
| home = getenv("home"); |
| #else |
| home = getenv("HOME"); |
| #endif /* Plan9 */ |
| makestr(&zhomdir,home); |
| return(home ? zhomdir : "."); |
| } |
| |
| /* Z G T D I R -- Returns a pointer to the current directory */ |
| |
| /* |
| The "preferred" interface for getting the current directory in modern UNIX |
| is getcwd() [POSIX 1003.1 5.2.2]. However, on certain platforms (such as |
| SunOS), it is implemented by forking a shell, feeding it the pwd command, |
| and returning the result, which is not only inefficient but also can result |
| in stray messages to the terminal. In such cases -- as well as when |
| getcwd() is not available at all -- getwd() can be used instead by defining |
| USE_GETWD. However, note that getwd() provides no buffer-length argument |
| and therefore no safeguard against memory leaks. |
| */ |
| #ifndef USE_GETWD |
| #ifdef BSD42 |
| #define USE_GETWD |
| #else |
| #ifdef SUNOS4 |
| #define USE_GETWD |
| #endif /* SUNOS4 */ |
| #endif /* BSD42 */ |
| #endif /* USE_GETWD */ |
| |
| #ifdef pdp11 |
| #define CWDBL 80 /* Save every byte we can... */ |
| #else |
| #define CWDBL CKMAXPATH |
| #endif /* pdp11 */ |
| static char cwdbuf[CWDBL+2]; |
| /* |
| NOTE: The getcwd() prototypes are commented out on purpose. If you get |
| compile-time warnings, search through your system's header files to see |
| which one has the needed prototype, and #include it. Usually it is |
| <unistd.h>. See the section for including <unistd.h> in ckcdeb.h and |
| make any needed adjustments there (and report them). |
| */ |
| char * |
| zgtdir() { |
| char * buf = cwdbuf; |
| char * s; |
| |
| #ifdef USE_GETWD |
| extern char *getwd(); |
| s = getwd(buf); |
| debug(F110,"zgtdir BSD4 getwd()",s,0); |
| if (!s) s = "./"; |
| return(s); |
| #else |
| #ifdef BSD44 |
| #ifdef DCLGETCWD |
| _PROTOTYP( char * getcwd, (char *, SIZE_T) ); |
| #endif /* DCLGETCWD */ |
| debug(F101,"zgtdir BSD44 CWDBL","",CWDBL); |
| s = getcwd(buf,CWDBL); |
| if (!s) s = "./"; |
| return(s); |
| #else |
| #ifdef MINIX2 |
| #ifdef DCLGETCWD |
| _PROTOTYP( char * getcwd, (char *, SIZE_T) ); |
| #endif /* DCLGETCWD */ |
| debug(F101,"zgtdir MINIX2 CWDBL","",CWDBL); |
| s = getcwd(buf,CWDBL); |
| if (!s) s = "./"; |
| return(s); |
| #else |
| #ifdef SVORPOSIX |
| #ifdef COMMENT |
| /* This non-ANSI prototype can be fatal at runtime! (e.g. in SCO3.2v5.0.5). */ |
| /* Anyway it's already prototyped in some header file that we have included. */ |
| extern char *getcwd(); |
| #else |
| #ifdef DCLGETCWD |
| _PROTOTYP( char * getcwd, (char *, SIZE_T) ); |
| #endif /* DCLGETCWD */ |
| #endif /* COMMENT */ |
| debug(F101,"zgtdir SVORPOSIX CWDBL","",CWDBL); |
| s = getcwd(buf,CWDBL); |
| if (!s) s = "./"; |
| return(s); |
| #else |
| #ifdef COHERENT |
| #ifdef _I386 |
| #ifdef DCLGETCWD |
| extern char *getcwd(); |
| #endif /* DCLGETCWD */ |
| debug(F101,"zgtdir COHERENT _I386 CWDBL","",CWDBL); |
| s = getcwd(buf,CWDBL); |
| if (!s) s = "./"; |
| return(s); |
| #else |
| extern char *getwd(); |
| debug(F101,"zgtdir COHERENT CWDBL","",CWDBL); |
| s = getwd(buf); |
| if (!s) s = "./"; |
| return(s); |
| #endif /* _I386 */ |
| #else |
| #ifdef SUNOS4 |
| debug(F101,"zgtdir SUNOS CWDBL","",CWDBL); |
| s = getcwd(buf,CWDBL); |
| if (!s) s = "./"; |
| return(s); |
| #else |
| return("./"); |
| #endif /* SUNOS4 */ |
| #endif /* COHERENT */ |
| #endif /* SYSVORPOSIX */ |
| #endif /* MINIX2 */ |
| #endif /* BSD44 */ |
| #endif /* USE_GETWD */ |
| } |
| |
| /* Z X C M D -- Run a system command so its output can be read like a file */ |
| |
| #ifndef NOPUSH |
| int |
| zxcmd(filnum,comand) int filnum; char *comand; { |
| int out; |
| int pipes[2]; |
| extern int kactive; /* From ckcpro.w and ckcmai.c */ |
| |
| if (nopush) { |
| |