📄 env_unix.c
字号:
{ if (!myHomeDir) myusername ();/* initialize if first time */ return myHomeDir ? myHomeDir : "";}/* Return my home mailbox name * Returns: my home directory name */static char *mymailboxdir (){ /* initialize if first time */#ifdef MAILSUBDIR if (!myMailboxDir) { char tmp[MAILTMPLEN]; sprintf (tmp,"%s/%s",myhomedir (),MAILSUBDIR); myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */ }#else if (!myMailboxDir && myHomeDir) myMailboxDir = cpystr (myhomedir ());#endif return myMailboxDir ? myMailboxDir : "";}/* Return system standard INBOX * Accepts: buffer string */char *sysinbox (){ char tmp[MAILTMPLEN]; if (!sysInbox) { /* initialize if first time */ sprintf (tmp,"%s/%s",MAILSPOOL,myusername ()); sysInbox = cpystr (tmp); /* system inbox is from mail spool */ } return sysInbox;}/* Return mailbox directory name * Accepts: destination buffer * directory prefix * name in directory * Returns: file name or NIL if error */char *mailboxdir (char *dst,char *dir,char *name){ char tmp[MAILTMPLEN]; if (dir || name) { /* if either argument provided */ if (dir) { if (strlen (dir) > NETMAXMBX) return NIL; strcpy (tmp,dir); /* write directory prefix */ } else tmp[0] = '\0'; /* otherwise null string */ if (name) { if (strlen (name) > NETMAXMBX) return NIL; strcat (tmp,name); /* write name in directory */ } /* validate name, return its name */ if (!mailboxfile (dst,tmp)) return NIL; } /* no arguments, wants mailbox directory */ else strcpy (dst,mymailboxdir ()); return dst; /* return the name */}/* Return mailbox file name * Accepts: destination buffer * mailbox name * Returns: file name or empty string for driver-selected INBOX or NIL if error */char *mailboxfile (char *dst,char *name){ struct passwd *pw; char *dir = mymailboxdir (); *dst = '\0'; /* default to empty string */ /* check invalid name */ if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX)) return NIL; /* check for INBOX */ if (((name[0] == 'I') || (name[0] == 'i')) && ((name[1] == 'N') || (name[1] == 'n')) && ((name[2] == 'B') || (name[2] == 'b')) && ((name[3] == 'O') || (name[3] == 'o')) && ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) { /* if restricted, canonicalize name of INBOX */ if (anonymous || blackBox || closedBox) name = "INBOX"; else return dst; /* else driver selects the INBOX name */ } /* restricted name? */ else if ((*name == '#') || anonymous || blackBox) { if (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~")) return NIL; /* none of these allowed when restricted */ switch (*name) { /* what kind of restricted name? */ case '#': /* namespace name */ if (((name[1] == 'f') || (name[1] == 'F')) && ((name[2] == 't') || (name[2] == 'T')) && ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/') && (dir = ftpHome)) name += 5; else if (((name[1] == 'p') || (name[1] == 'P')) && ((name[2] == 'u') || (name[2] == 'U')) && ((name[3] == 'b') || (name[3] == 'B')) && ((name[4] == 'l') || (name[4] == 'L')) && ((name[5] == 'i') || (name[5] == 'I')) && ((name[6] == 'c') || (name[6] == 'C')) && (name[7] == '/') && (dir = publicHome)) name += 8; else if (!anonymous && ((name[1] == 's') || (name[1] == 'S')) && ((name[2] == 'h') || (name[2] == 'H')) && ((name[3] == 'a') || (name[3] == 'A')) && ((name[4] == 'r') || (name[4] == 'R')) && ((name[5] == 'e') || (name[5] == 'E')) && ((name[6] == 'd') || (name[6] == 'D')) && (name[7] == '/') && (dir = sharedHome)) name += 8; else return NIL; /* unknown namespace name */ break; case '/': /* rooted restricted name */ if (anonymous) return NIL;/* anonymous can't do this */ dir = blackBoxDir; /* base is black box directory */ name++; /* skip past delimiter */ break; } } /* absolute path name? */ else if (*name == '/') return strcpy (dst,name); /* some home directory? */ else if (!closedBox && (*name == '~') && *++name) { if (*name == '/') name++; /* yes, my home directory? */ else { /* no, copy user name */ for (dir = dst; *name && (*name != '/'); *dir++ = *name++); *dir++ = '\0'; /* tie off user name, look up in passwd file */ if (!((pw = getpwnam (dst)) && (dir = pw->pw_dir))) return NIL; if (*name) name++; /* skip past the slash */#ifdef MAILSUBDIR sprintf (dst,"%s/%s/%s",dir,MAILSUBDIR,name); return dst;#endif } } /* build resulting name */ sprintf (dst,"%s/%s",dir,name); return dst; /* return it */}/* Dot-lock file locker * Accepts: file name to lock * destination buffer for lock file name * open file description on file name to lock * Returns: T if success, NIL if failure */long dotlock_lock (char *file,DOTLOCK *base,int fd){ int i = locktimeout * 60; int j,retry,pi[2],po[2]; char *s,tmp[MAILTMPLEN]; struct stat sb; /* flush absurd file name */ if (strlen (file) > 512) return NIL; /* build lock filename */ sprintf (base->lock,"%s.lock",file); /* assume no pipe */ base->pipei = base->pipeo = -1; do { /* make sure not symlink */ if (!(j = chk_notsymlink (base->lock,&sb))) return NIL; /* time out if file older than 5 minutes */ if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0; /* try to create the lock */ switch (retry = crexcl (base->lock)) { case -1: /* OK to retry */ if (!(i%15)) { /* time to notify? */ sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...", file,i); mm_log (tmp,WARN); } sleep (1); /* wait 1 second before next try */ break; case NIL: /* failure, can't retry */ i = 0; break; case T: /* success, make sure others can break lock */ chmod (base->lock,(int) lock_protection); return LONGT; } } while (i--); /* until out of retries */ if (retry < 0) { /* still returning retry after locktimeout? */ if (!(j = chk_notsymlink (base->lock,&sb))) return NIL; if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) { sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock", (long) (time (0) - sb.st_ctime)); mm_log (tmp,WARN); } /* seize the lock */ if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) lock_protection)) >= 0) { close (i); /* don't need descriptor any more */ sprintf (tmp,"Mailbox %.80s lock overridden",file); mm_log (tmp,NIL); chmod (base->lock,(int) lock_protection); return LONGT; } } if (fd >= 0) switch (errno) { case EACCES: /* protection failure? */ /* make command pipes */ if (!closedBox && !stat (LOCKPGM,&sb) && (pipe (pi) >= 0)) { if (pipe (po) >= 0) { if (!(j = fork ())) { /* make inferior process */ if (!fork ()) { /* make grandchild so it's inherited by init */ char *argv[4]; /* prepare argument vector */ sprintf (tmp,"%d",fd); argv[0] = LOCKPGM; argv[1] = tmp; argv[2] = file; argv[3] = NIL; /* set parent's I/O to my O/I */ dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0); /* close all unnecessary descriptors */ for (j = max (20,max (max (pi[0],pi[1]),max(po[0],po[1]))); j >= 3; --j) if (j != fd) close (j); /* be our own process group */ setpgrp (0,getpid ()); /* now run it */ execv (argv[0],argv); } _exit (1); /* child is done */ } else if (j > 0) { /* reap child; grandchild now owned by init */ grim_pid_reap (j,NIL); /* read response from locking program */ if ((read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) { /* success, record pipes */ base->pipei = pi[0]; base->pipeo = po[1]; /* close child's side of the pipes */ close (pi[1]); close (po[0]); return LONGT; } } close (po[0]); close (po[1]); } close (pi[0]); close (pi[1]); } if (lockEaccesError) { /* punt silently if paranoid site */ sprintf (tmp,"Mailbox vulnerable - directory %.80s",base->lock); if (s = strrchr (tmp,'/')) *s = '\0'; strcat (tmp," must have 1777 protection"); mm_log (tmp,WARN); } break; default: sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s", base->lock,strerror (errno)); mm_log (tmp,WARN); /* this is probably not good */ break; } base->lock[0] = '\0'; /* don't use lock files */ return NIL;}/* Dot-lock file unlocker * Accepts: lock file name * Returns: T if success, NIL if failure */long dotlock_unlock (DOTLOCK *base){ long ret = LONGT; if (base && base->lock[0]) { if (base->pipei >= 0) { /* if running through a pipe unlocker */ ret = (write (base->pipeo,"+",1) == 1); /* nuke the pipes */ close (base->pipei); close (base->pipeo); } else ret = !unlink (base->lock); } return ret;}/* Lock file name * Accepts: scratch buffer * file name * type of locking operation (LOCK_SH or LOCK_EX) * pointer to return PID of locker * Returns: file descriptor of lock or negative if error */int lockname (char *lock,char *fname,int op,long *pid){ struct stat sbuf; *pid = 0; /* no locker PID */ return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);}/* Lock file descriptor * Accepts: file descriptor * lock file name buffer * type of locking operation (LOCK_SH or LOCK_EX) * Returns: file descriptor of lock or negative if error */int lockfd (int fd,char *lock,int op){ struct stat sbuf; return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);}/* Lock file name worker * Accepts: lock file name * pointer to stat() buffer * type of locking operation (LOCK_SH or LOCK_EX) * pointer to return PID of locker * Returns: file descriptor of lock or negative if error */int lock_work (char *lock,void *sb,int op,long *pid){ struct stat lsb,fsb; struct stat *sbuf = (struct stat *) sb; char tmp[MAILTMPLEN]; long i; int fd; if (pid) *pid = 0; /* initialize return PID */ /* make temporary lock file name */ sprintf (lock,"%s/.%lx.%lx",#ifdef CHROOT_SERVER "",#else "/tmp",#endif (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino); while (T) { /* until get a good lock */ do switch ((int) chk_notsymlink (lock,&lsb)) { case 1: /* exists just once */ if (((fd = open (lock,O_RDWR,lock_protection)) >= 0) || (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break; case -1: /* name doesn't exist */ fd = open (lock,O_RDWR|O_CREAT|O_EXCL,lock_protection); break; default: /* multiple hard links */ mm_log ("hard link to lock name",ERROR); syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock); case 0: /* symlink (already did syslog) */ return -1; /* fail: no lock file */ } while ((fd < 0) && (errno == EEXIST)); if (fd < 0) { /* failed to get file descriptor */ syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock, strerror (errno)); return -1; /* fail: can't open lock file */ } /* non-blocking form */ if (op & LOCK_NB) i = flock (fd,op); else { /* blocking form */ (*mailblocknotify) (BLOCK_FILELOCK,NIL); i = flock (fd,op); (*mailblocknotify) (BLOCK_NONE,NIL); } if (i) { /* failed, get other process' PID */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -