📄 env_ami.c
字号:
} return dst; /* return final name */}/* 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,mask,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 */ if ((j = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) lock_protection)) >= 0) { close (i); /* make the file, now close it */ chmod (base->lock,(int) lock_protection); return LONGT; } if (errno == EEXIST) { /* already locked? */ retry = -1; /* can try again */ 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 */ } else retry = i = 0; /* hard failure, no more retries */ } 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); } mask = umask (0); unlink (base->lock); /* try to remove the old file */ /* 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); umask (mask) /* restore old umask */ return LONGT; } umask (mask) /* restore old umask */ } if (fd >= 0) switch (errno) { case EACCES: /* protection failure? */ /* make command pipes */ if (!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]); } /* find directory/file delimiter */ if (s = strrchr (base->lock,'/')) { *s = '\0'; /* tie off at directory */ sprintf(tmp, /* generate default message */ "Mailbox vulnerable - directory %.80s must have 1777 protection", base->lock); /* definitely not 1777 if can't stat */ mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777); *s = '/'; /* restore lock name */ if (mask != 1777) { /* default warning if not 1777 */ 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; int mask = umask (0); if (pid) *pid = 0; /* initialize return PID */ /* make temporary lock file name */ sprintf (lock,"%s/.%lx.%lx","/tmp", (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) */ umask (mask); /* restore old mask */ 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)); if (stat ("/tmp",&lsb)) syslog (LOG_CRIT,"SYSTEM ERROR: no /tmp: %s",strerror (errno)); else if ((lsb.st_mode & 01777) != 01777) mm_log ("Can't lock for write: /tmp must have 1777 protection",WARN); umask (mask); /* restore old mask */ 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 */ if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) && (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0)) *pid = i; close (fd); /* failed, give up on lock */ umask (mask); /* restore old mask */ return -1; /* fail: can't lock */ } /* make sure this lock is good for us */ if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) && !fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) && (lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break; close (fd); /* lock not right, drop fd and try again */ } /* make sure mode OK (don't use fchmod()) */ chmod (lock,(int) lock_protection); umask (mask); /* restore old mask */ return fd; /* success */}/* Check to make sure not a symlink * Accepts: file name * stat buffer * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links */long chk_notsymlink (char *name,void *sb){ struct stat *sbuf = (struct stat *) sb; /* name exists? */ if (lstat (name,sbuf)) return -1; /* forbid symbolic link */ if ((sbuf->st_mode & S_IFMT) == S_IFLNK) { mm_log ("symbolic link on lock name",ERROR); syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s", name); return NIL; } return (long) sbuf->st_nlink; /* return number of hard links */}/* Unlock file descriptor * Accepts: file descriptor * lock file name from lockfd() */void unlockfd (int fd,char *lock){ /* delete the file if no sharers */ if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock); flock (fd,LOCK_UN); /* unlock it */ close (fd); /* close it */}/* Set proper file protection for mailbox * Accepts: mailbox name * actual file path name * Returns: T, always */long set_mbx_protections (char *mailbox,char *path){ struct stat sbuf; int mode = (int) mbx_protection; if (*mailbox == '#') { /* possible namespace? */ if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) && ((mailbox[2] == 't') || (mailbox[2] == 'T')) && ((mailbox[3] == 'p') || (mailbox[3] == 'P')) && (mailbox[4] == '/')) mode = (int) ftp_protection; else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) && ((mailbox[2] == 'u') || (mailbox[2] == 'U')) && ((mailbox[3] == 'b') || (mailbox[3] == 'B')) && ((mailbox[4] == 'l') || (mailbox[4] == 'L')) && ((mailbox[5] == 'i') || (mailbox[5] == 'I')) && ((mailbox[6] == 'c') || (mailbox[6] == 'C')) && (mailbox[7] == '/')) mode = (int) public_protection; else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) && ((mailbox[2] == 'h') || (mailbox[2] == 'H')) && ((mailbox[3] == 'a') || (mailbox[3] == 'A')) && ((mailbox[4] == 'r') || (mailbox[4] == 'R')) && ((mailbox[5] == 'e') || (mailbox[5] == 'E')) && ((mailbox[6] == 'd') || (mailbox[6] == 'D')) && (mailbox[7] == '/')) mode = (int) shared_protection; } /* if a directory */ if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) { /* set owner search if allow read or write */ if (mode & 0600) mode |= 0100; if (mode & 060) mode |= 010;/* set group search if allow read or write */ if (mode & 06) mode |= 01; /* set world search if allow read or write */ /* preserve directory SGID bit */ if (sbuf.st_mode & S_ISGID) mode |= S_ISGID; } chmod (path,mode); /* set the new protection, ignore failure */ return LONGT;}/* Get proper directory protection * Accepts: mailbox name * Returns: directory mode, always */long get_dir_protection (char *mailbox){ if (*mailbox == '#') { /* possible namespace? */ if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) && ((mailbox[2] == 't') || (mailbox[2] == 'T')) && ((mailbox[3] == 'p') || (mailbox[3] == 'P')) && (mailbox[4] == '/')) return ftp_dir_protection; else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) && ((mailbox[2] == 'u') || (mailbox[2] == 'U')) && ((mailbox[3] == 'b') || (mailbox[3] == 'B')) && ((mailbox[4] == 'l') || (mailbox[4] == 'L')) && ((mailbox[5] == 'i') || (mailbox[5] == 'I')) && ((mailbox[6] == 'c') || (mailbox[6] == 'C')) && (mailbox[7] == '/')) return public_dir_protection; else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) && ((mailbox[2] == 'h') || (mailbox[2] == 'H')) && ((mailbox[3] == 'a') || (mailbox[3] == 'A')) && ((mailbox[4] == 'r') || (mailbox[4] == 'R')) && ((mailbox[5] == 'e') || (mailbox[5] == 'E')) && ((mailbox[6] == 'd') || (mailbox[6] == 'D')) && (mailbox[7] == '/')) return shared_dir_protection; } return dir_protection;}/* Determine default prototype stream to user * Accepts: type (NIL for create, T for append) * Returns: default prototype stream */MAILSTREAM *default_proto (long type){ myusername (); /* make sure initialized */ /* return default driver's prototype */ return type ? appendProto : createProto;}/* Set up user flags for stream * Accepts: MAIL stream * Returns: MAIL stream with user flags set up */MAILSTREAM *user_flags (MAILSTREAM *stream){ int i; myusername (); /* make sure initialized */ for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i) if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]); return stream;}/* Return nth user flag * Accepts: user flag number * Returns: flag */char *default_user_flag (unsigned long i){ myusername (); /* make sure initialized */ return userFlags[i];}/* Default block notify routine * Accepts: reason for calling * data * Returns: data */void *mm_blocknotify (int reason,void *data){ void *ret = data; switch (reason) { case BLOCK_SENSITIVE: /* entering sensitive code */ ret = (void *) alarm (0); break; case BLOCK_NONSENSITIVE: /* exiting sensitive code */ if ((unsigned int) data) alarm ((unsigned int) data); break; default: /* ignore all other reasons */ break; } return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -