imapext-2007

annotate src/dmail/dmail.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
rev   line source
yuuji@0 1 /* ========================================================================
yuuji@0 2 * Copyright 1988-2007 University of Washington
yuuji@0 3 *
yuuji@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
yuuji@0 5 * you may not use this file except in compliance with the License.
yuuji@0 6 * You may obtain a copy of the License at
yuuji@0 7 *
yuuji@0 8 * http://www.apache.org/licenses/LICENSE-2.0
yuuji@0 9 *
yuuji@0 10 *
yuuji@0 11 * ========================================================================
yuuji@0 12 */
yuuji@0 13
yuuji@0 14 /*
yuuji@0 15 * Program: Procmail-Callable Mail Delivery Module
yuuji@0 16 *
yuuji@0 17 * Author: Mark Crispin
yuuji@0 18 * Networks and Distributed Computing
yuuji@0 19 * Computing & Communications
yuuji@0 20 * University of Washington
yuuji@0 21 * Administration Building, AG-44
yuuji@0 22 * Seattle, WA 98195
yuuji@0 23 * Internet: MRC@CAC.Washington.EDU
yuuji@0 24 *
yuuji@0 25 * Date: 5 April 1993
yuuji@0 26 * Last Edited: 30 October 2008
yuuji@0 27 */
yuuji@0 28
yuuji@0 29 #include <stdio.h>
yuuji@0 30 #include <pwd.h>
yuuji@0 31 #include <errno.h>
yuuji@0 32 extern int errno; /* just in case */
yuuji@0 33 #include <sysexits.h>
yuuji@0 34 #include <sys/file.h>
yuuji@0 35 #include <sys/stat.h>
yuuji@0 36 #include "c-client.h"
yuuji@0 37 #include "dquota.h"
yuuji@0 38
yuuji@0 39
yuuji@0 40 /* Globals */
yuuji@0 41
yuuji@0 42 char *version = "18"; /* dmail edit version */
yuuji@0 43 int debug = NIL; /* debugging (don't fork) */
yuuji@0 44 int flagseen = NIL; /* flag message as seen */
yuuji@0 45 int trycreate = NIL; /* flag saying gotta create before appending */
yuuji@0 46 int critical = NIL; /* flag saying in critical code */
yuuji@0 47 char *sender = NIL; /* message origin */
yuuji@0 48 char *keywords = NIL; /* keyword list */
yuuji@0 49 long precedence = 0; /* delivery precedence - used by quota hook */
yuuji@0 50
yuuji@0 51
yuuji@0 52 /* Function prototypes */
yuuji@0 53
yuuji@0 54 void file_string_init (STRING *s,void *data,unsigned long size);
yuuji@0 55 char file_string_next (STRING *s);
yuuji@0 56 void file_string_setpos (STRING *s,unsigned long i);
yuuji@0 57 int main (int argc,char *argv[]);
yuuji@0 58 int deliver (FILE *f,unsigned long msglen,char *user);
yuuji@0 59 long ibxpath (MAILSTREAM *ds,char **mailbox,char *path);
yuuji@0 60 int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
yuuji@0 61 char *tmp);
yuuji@0 62 int delivery_unsafe (char *path,struct stat *sbuf,char *tmp);
yuuji@0 63 int fail (char *string,int code);
yuuji@0 64
yuuji@0 65
yuuji@0 66 /* File string driver for file stringstructs */
yuuji@0 67
yuuji@0 68 STRINGDRIVER file_string = {
yuuji@0 69 file_string_init, /* initialize string structure */
yuuji@0 70 file_string_next, /* get next byte in string structure */
yuuji@0 71 file_string_setpos /* set position in string structure */
yuuji@0 72 };
yuuji@0 73
yuuji@0 74
yuuji@0 75 /* Cache buffer for file stringstructs */
yuuji@0 76
yuuji@0 77 #define CHUNKLEN 16384
yuuji@0 78 char chunk[CHUNKLEN];
yuuji@0 79
yuuji@0 80 /* Initialize file string structure for file stringstruct
yuuji@0 81 * Accepts: string structure
yuuji@0 82 * pointer to string
yuuji@0 83 * size of string
yuuji@0 84 */
yuuji@0 85
yuuji@0 86 void file_string_init (STRING *s,void *data,unsigned long size)
yuuji@0 87 {
yuuji@0 88 s->data = data; /* note fd */
yuuji@0 89 s->size = size; /* note size */
yuuji@0 90 s->chunk = chunk;
yuuji@0 91 s->chunksize = (unsigned long) CHUNKLEN;
yuuji@0 92 SETPOS (s,0); /* set initial position */
yuuji@0 93 }
yuuji@0 94
yuuji@0 95
yuuji@0 96 /* Get next character from file stringstruct
yuuji@0 97 * Accepts: string structure
yuuji@0 98 * Returns: character, string structure chunk refreshed
yuuji@0 99 */
yuuji@0 100
yuuji@0 101 char file_string_next (STRING *s)
yuuji@0 102 {
yuuji@0 103 char c = *s->curpos++; /* get next byte */
yuuji@0 104 SETPOS (s,GETPOS (s)); /* move to next chunk */
yuuji@0 105 return c; /* return the byte */
yuuji@0 106 }
yuuji@0 107
yuuji@0 108
yuuji@0 109 /* Set string pointer position for file stringstruct
yuuji@0 110 * Accepts: string structure
yuuji@0 111 * new position
yuuji@0 112 */
yuuji@0 113
yuuji@0 114 void file_string_setpos (STRING *s,unsigned long i)
yuuji@0 115 {
yuuji@0 116 if (i > s->size) i = s->size; /* don't permit setting beyond EOF */
yuuji@0 117 s->offset = i; /* set new offset */
yuuji@0 118 s->curpos = s->chunk; /* reset position */
yuuji@0 119 /* set size of data */
yuuji@0 120 if (s->cursize = min (s->chunksize,SIZE (s))) {
yuuji@0 121 /* move to that position in the file */
yuuji@0 122 fseek ((FILE *) s->data,s->offset,SEEK_SET);
yuuji@0 123 fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data);
yuuji@0 124 }
yuuji@0 125 }
yuuji@0 126
yuuji@0 127 /* Main program */
yuuji@0 128
yuuji@0 129 int main (int argc,char *argv[])
yuuji@0 130 {
yuuji@0 131 FILE *f = NIL;
yuuji@0 132 int c,ret = 0;
yuuji@0 133 unsigned long msglen;
yuuji@0 134 char *s,tmp[MAILTMPLEN];
yuuji@0 135 uid_t ruid = getuid ();
yuuji@0 136 struct passwd *pwd = ruid ? getpwnam ("daemon") : NIL;
yuuji@0 137 openlog ("dmail",LOG_PID,LOG_MAIL);
yuuji@0 138 /* must not be root or daemon! */
yuuji@0 139 if (!ruid || (pwd && (pwd->pw_uid == ruid)))
yuuji@0 140 _exit (fail ("dmail may not be invoked by root or daemon",EX_USAGE));
yuuji@0 141 #include "linkage.c"
yuuji@0 142 /* process all flags */
yuuji@0 143 for (--argc; argc && (*(s = *++argv)) == '-'; argc--) switch (s[1]) {
yuuji@0 144 case 'D': /* debug */
yuuji@0 145 debug = T; /* extra debugging */
yuuji@0 146 break;
yuuji@0 147 case 's': /* deliver as seen */
yuuji@0 148 flagseen = T;
yuuji@0 149 break;
yuuji@0 150 case 'f':
yuuji@0 151 case 'r': /* flag giving return path */
yuuji@0 152 if (sender) _exit (fail ("duplicate -r",EX_USAGE));
yuuji@0 153 if (argc--) sender = cpystr (*++argv);
yuuji@0 154 else _exit (fail ("missing argument to -r",EX_USAGE));
yuuji@0 155 break;
yuuji@0 156 case 'k':
yuuji@0 157 if (keywords) _exit (fail ("duplicate -k",EX_USAGE));
yuuji@0 158 if (argc--) keywords = cpystr (*++argv);
yuuji@0 159 else _exit (fail ("missing argument to -k",EX_USAGE));
yuuji@0 160 break;
yuuji@0 161 case 'p':
yuuji@0 162 if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
yuuji@0 163 else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
yuuji@0 164 precedence = atol (s);
yuuji@0 165 else _exit (fail ("missing argument to -p",EX_USAGE));
yuuji@0 166 break;
yuuji@0 167 default: /* anything else */
yuuji@0 168 _exit (fail ("unknown switch",EX_USAGE));
yuuji@0 169 }
yuuji@0 170
yuuji@0 171 if (argc > 1) _exit (fail ("too many recipients",EX_USAGE));
yuuji@0 172 else if (!(f = tmpfile ())) _exit(fail ("can't make temp file",EX_TEMPFAIL));
yuuji@0 173 /* build delivery headers */
yuuji@0 174 if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
yuuji@0 175 /* start Received line: */
yuuji@0 176 fprintf (f,"Received: via dmail-%s.%s for %s; ",CCLIENTVERSION,version,
yuuji@0 177 (argc == 1) ? *argv : myusername ());
yuuji@0 178 rfc822_date (tmp);
yuuji@0 179 fputs (tmp,f);
yuuji@0 180 fputs ("\015\012",f);
yuuji@0 181 /* copy text from standard input */
yuuji@0 182 if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
yuuji@0 183 (s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
yuuji@0 184 else if (s[-1] == '\015') { /* nuke leading "From " line */
yuuji@0 185 if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
yuuji@0 186 (tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
yuuji@0 187 while ((c = getchar ()) != EOF) putc (c,f);
yuuji@0 188 }
yuuji@0 189 else {
yuuji@0 190 if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
yuuji@0 191 (tmp[3] != 'm') || (tmp[4] != ' ')) {
yuuji@0 192 *s++ = '\015'; /* overwrite NL with CRLF */
yuuji@0 193 *s++ = '\012';
yuuji@0 194 *s = '\0'; /* tie off string */
yuuji@0 195 fputs (tmp,f); /* write line */
yuuji@0 196 }
yuuji@0 197 }
yuuji@0 198 /* copy text from standard input */
yuuji@0 199 while ((c = getchar ()) != EOF) {
yuuji@0 200 /* add CR if needed */
yuuji@0 201 if (c == '\012') putc ('\015',f);
yuuji@0 202 putc (c,f);
yuuji@0 203 }
yuuji@0 204 msglen = ftell (f); /* size of message */
yuuji@0 205 fflush (f); /* make sure all changes written out */
yuuji@0 206 if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
yuuji@0 207 else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
yuuji@0 208 /* single delivery */
yuuji@0 209 else ret = deliver (f,msglen,argc ? *argv : myusername ());
yuuji@0 210 fclose (f); /* all done with temporary file */
yuuji@0 211 _exit (ret); /* normal exit */
yuuji@0 212 return 0; /* stupid gcc */
yuuji@0 213 }
yuuji@0 214
yuuji@0 215 /* Deliver message to recipient list
yuuji@0 216 * Accepts: file description of message temporary file
yuuji@0 217 * size of message temporary file in bytes
yuuji@0 218 * recipient name
yuuji@0 219 * Returns: NIL if success, else error code
yuuji@0 220 */
yuuji@0 221
yuuji@0 222 int deliver (FILE *f,unsigned long msglen,char *user)
yuuji@0 223 {
yuuji@0 224 MAILSTREAM *ds = NIL;
yuuji@0 225 char *s,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN];
yuuji@0 226 STRING st;
yuuji@0 227 struct stat sbuf;
yuuji@0 228 /* have a mailbox specifier? */
yuuji@0 229 if (mailbox = strchr (user,'+')) {
yuuji@0 230 *mailbox++ = '\0'; /* yes, tie off user name */
yuuji@0 231 if (!*mailbox || !compare_cstring ((unsigned char *) mailbox,"INBOX"))
yuuji@0 232 mailbox = NIL; /* user+ and user+INBOX same as user */
yuuji@0 233 }
yuuji@0 234 if (!*user) user = myusername ();
yuuji@0 235 else if (strcmp (user,myusername ()))
yuuji@0 236 return fail ("can't deliver to other user",EX_CANTCREAT);
yuuji@0 237 sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX");
yuuji@0 238 mm_dlog (tmp);
yuuji@0 239 /* prepare stringstruct */
yuuji@0 240 INIT (&st,file_string,(void *) f,msglen);
yuuji@0 241 if (mailbox) { /* non-INBOX name */
yuuji@0 242 switch (mailbox[0]) { /* make sure a valid name */
yuuji@0 243 default: /* other names, try to deliver if not INBOX */
yuuji@0 244 if (!strstr (mailbox,"..") && !strstr (mailbox,"//") &&
yuuji@0 245 !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] &&
yuuji@0 246 !deliver_safely (NIL,&st,mailbox,path,tmp)) return NIL;
yuuji@0 247 case '%': case '*': /* wildcards not valid */
yuuji@0 248 case '/': /* absolute path names not valid */
yuuji@0 249 case '~': /* user names not valid */
yuuji@0 250 sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox);
yuuji@0 251 mm_log (tmp,WARN);
yuuji@0 252 break;
yuuji@0 253 }
yuuji@0 254 mm_dlog ("retrying delivery to INBOX");
yuuji@0 255 SETPOS (&st,0); /* rewind stringstruct just in case */
yuuji@0 256 }
yuuji@0 257
yuuji@0 258 /* no -I, resolve "INBOX" into path */
yuuji@0 259 if (mailboxfile (path,mailbox = "INBOX") && !path[0]) {
yuuji@0 260 /* clear box, get generic INBOX prototype */
yuuji@0 261 if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
yuuji@0 262 fatal ("no INBOX prototype");
yuuji@0 263 /* standard system driver? */
yuuji@0 264 if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) {
yuuji@0 265 strcpy (path,sysinbox ());/* use system INBOX */
yuuji@0 266 if (!lstat (path,&sbuf)) /* deliver to existing system INBOX */
yuuji@0 267 return deliver_safely (ds,&st,mailbox,path,tmp);
yuuji@0 268 }
yuuji@0 269 else { /* other driver, try ~/INBOX */
yuuji@0 270 if ((mailboxfile (path,"&&&&&") == path) &&
yuuji@0 271 (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") &&
yuuji@0 272 !lstat (path,&sbuf)){ /* deliver to existing ~/INBOX */
yuuji@0 273 sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
yuuji@0 274 return deliver_safely (ds,&st,cpystr (tmp),path,tmp);
yuuji@0 275 }
yuuji@0 276 }
yuuji@0 277 /* not dummy, deliver to driver imputed path */
yuuji@0 278 if (strcmp (ds->dtb->name,"dummy"))
yuuji@0 279 return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ?
yuuji@0 280 deliver_safely (ds,&st,mailbox,path,tmp) :
yuuji@0 281 fail ("unable to resolve INBOX path",EX_CANTCREAT);
yuuji@0 282 /* dummy, empty imputed append path exist? */
yuuji@0 283 if (ibxpath (ds = default_proto (T),&mailbox,path) &&
yuuji@0 284 !lstat (path,&sbuf) && !sbuf.st_size)
yuuji@0 285 return deliver_safely (ds,&st,mailbox,path,tmp);
yuuji@0 286 /* impute path that we will create */
yuuji@0 287 if (!ibxpath (ds = default_proto (NIL),&mailbox,path))
yuuji@0 288 return fail ("unable to resolve INBOX",EX_CANTCREAT);
yuuji@0 289 }
yuuji@0 290 /* black box, must create, get create proto */
yuuji@0 291 else if (lstat (path,&sbuf)) ds = default_proto (NIL);
yuuji@0 292 else { /* black box, existing file */
yuuji@0 293 /* empty file, get append prototype */
yuuji@0 294 if (!sbuf.st_size) ds = default_proto (T);
yuuji@0 295 /* non-empty, get prototype from its data */
yuuji@0 296 else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
yuuji@0 297 fatal ("no INBOX prototype");
yuuji@0 298 /* error if unknown format */
yuuji@0 299 if (!strcmp (ds->dtb->name,"phile"))
yuuji@0 300 return fail ("unknown format INBOX",EX_UNAVAILABLE);
yuuji@0 301 /* otherwise can deliver to it */
yuuji@0 302 return deliver_safely (ds,&st,mailbox,path,tmp);
yuuji@0 303 }
yuuji@0 304 sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path);
yuuji@0 305 mm_dlog (tmp);
yuuji@0 306 /* supplicate to the Evil One */
yuuji@0 307 if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT);
yuuji@0 308 sprintf (tmp,"created %.80s",path);
yuuji@0 309 mm_dlog (tmp);
yuuji@0 310 /* deliver the message */
yuuji@0 311 return deliver_safely (ds,&st,mailbox,path,tmp);
yuuji@0 312 }
yuuji@0 313
yuuji@0 314 /* Resolve INBOX from driver prototype into mailbox name and filesystem path
yuuji@0 315 * Accepts: driver prototype
yuuji@0 316 * pointer to mailbox name string pointer
yuuji@0 317 * buffer to return mailbox path
yuuji@0 318 * Returns: T if success, NIL if error
yuuji@0 319 */
yuuji@0 320
yuuji@0 321 long ibxpath (MAILSTREAM *ds,char **mailbox,char *path)
yuuji@0 322 {
yuuji@0 323 char *s,tmp[MAILTMPLEN];
yuuji@0 324 long ret = T;
yuuji@0 325 if (!ds) return NIL;
yuuji@0 326 else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf"))
yuuji@0 327 strcpy (path,sysinbox ()); /* use system INBOX for unix and MMDF */
yuuji@0 328 else if (!strcmp (ds->dtb->name,"tenex"))
yuuji@0 329 ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL;
yuuji@0 330 else if (!strcmp (ds->dtb->name,"mtx"))
yuuji@0 331 ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL;
yuuji@0 332 else if (!strcmp (ds->dtb->name,"mbox"))
yuuji@0 333 ret = (mailboxfile (path,"mbox") == path) ? T : NIL;
yuuji@0 334 /* better not be a namespace driver */
yuuji@0 335 else if (ds->dtb->flags & DR_NAMESPACE) return NIL;
yuuji@0 336 /* INBOX in home directory */
yuuji@0 337 else ret = ((mailboxfile (path,"&&&&&") == path) &&
yuuji@0 338 (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL;
yuuji@0 339 if (ret) { /* don't bother if lossage */
yuuji@0 340 sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
yuuji@0 341 *mailbox = cpystr (tmp); /* name of INBOX in this namespace */
yuuji@0 342 }
yuuji@0 343 return ret;
yuuji@0 344 }
yuuji@0 345
yuuji@0 346 /* Deliver safely
yuuji@0 347 * Accepts: prototype stream to force mailbox format
yuuji@0 348 * stringstruct of message temporary file or NIL for check only
yuuji@0 349 * mailbox name
yuuji@0 350 * filesystem path name
yuuji@0 351 * scratch buffer for messages
yuuji@0 352 * Returns: NIL if success, else error code
yuuji@0 353 */
yuuji@0 354
yuuji@0 355 int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
yuuji@0 356 char *tmp)
yuuji@0 357 {
yuuji@0 358 struct stat sbuf;
yuuji@0 359 char *flags = NIL;
yuuji@0 360 int i = delivery_unsafe (path,&sbuf,tmp);
yuuji@0 361 if (i) return i; /* give up now if delivery unsafe */
yuuji@0 362 /* directory, not file */
yuuji@0 363 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
yuuji@0 364 if (sbuf.st_mode & 0001) { /* listable directories may be worrisome */
yuuji@0 365 sprintf (tmp,"WARNING: directory %.80s is listable",path);
yuuji@0 366 mm_log (tmp,WARN);
yuuji@0 367 }
yuuji@0 368 }
yuuji@0 369 else { /* file, not directory */
yuuji@0 370 if (sbuf.st_nlink != 1) { /* multiple links may be worrisome */
yuuji@0 371 sprintf (tmp,"WARNING: multiple links to file %.80s",path);
yuuji@0 372 mm_log (tmp,WARN);
yuuji@0 373 }
yuuji@0 374 if (sbuf.st_mode & 0111) { /* executable files may be worrisome */
yuuji@0 375 sprintf (tmp,"WARNING: file %.80s is executable",path);
yuuji@0 376 mm_log (tmp,WARN);
yuuji@0 377 }
yuuji@0 378 }
yuuji@0 379 if (sbuf.st_mode & 0002) { /* public-write files may be worrisome */
yuuji@0 380 sprintf (tmp,"WARNING: file %.80s is publicly-writable",path);
yuuji@0 381 mm_log (tmp,WARN);
yuuji@0 382 }
yuuji@0 383 if (sbuf.st_mode & 0004) { /* public-write files may be worrisome */
yuuji@0 384 sprintf (tmp,"WARNING: file %.80s is publicly-readable",path);
yuuji@0 385 mm_log (tmp,WARN);
yuuji@0 386 }
yuuji@0 387 /* check site-written quota procedure */
yuuji@0 388 if (!dmail_quota (st,path,tmp,sender,precedence))
yuuji@0 389 return fail (tmp,EX_CANTCREAT);
yuuji@0 390 /* so far, so good */
yuuji@0 391 sprintf (tmp,"%s appending to %.80s (%s %.80s)",
yuuji@0 392 prt ? prt->dtb->name : "default",mailbox,
yuuji@0 393 ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path);
yuuji@0 394 mm_dlog (tmp);
yuuji@0 395 if (keywords) { /* any keywords requested? */
yuuji@0 396 if (flagseen) sprintf (flags = tmp,"\\Seen %.1000s",keywords);
yuuji@0 397 else flags = keywords;
yuuji@0 398 }
yuuji@0 399 else if (flagseen) flags = "\\Seen";
yuuji@0 400 /* do the append now! */
yuuji@0 401 if (!mail_append_full (prt,mailbox,flags,NIL,st)) {
yuuji@0 402 sprintf (tmp,"message delivery failed to %.80s",path);
yuuji@0 403 return fail (tmp,EX_CANTCREAT);
yuuji@0 404 }
yuuji@0 405 /* note success */
yuuji@0 406 sprintf (tmp,"delivered to %.80s",path);
yuuji@0 407 mm_log (tmp,NIL);
yuuji@0 408 /* make sure nothing evil this way comes */
yuuji@0 409 return delivery_unsafe (path,&sbuf,tmp);
yuuji@0 410 }
yuuji@0 411
yuuji@0 412 /* Verify that delivery is safe
yuuji@0 413 * Accepts: path name
yuuji@0 414 * stat buffer
yuuji@0 415 * scratch buffer for messages
yuuji@0 416 * Returns: NIL if delivery is safe, error code if unsafe
yuuji@0 417 */
yuuji@0 418
yuuji@0 419 int delivery_unsafe (char *path,struct stat *sbuf,char *tmp)
yuuji@0 420 {
yuuji@0 421 u_short type;
yuuji@0 422 sprintf (tmp,"Verifying safe delivery to %.80s",path);
yuuji@0 423 mm_dlog (tmp);
yuuji@0 424 /* prepare message just in case */
yuuji@0 425 sprintf (tmp,"delivery to %.80s unsafe: ",path);
yuuji@0 426 /* unsafe if can't get its status */
yuuji@0 427 if (lstat (path,sbuf)) strcat (tmp,strerror (errno));
yuuji@0 428 /* check file type */
yuuji@0 429 else switch (sbuf->st_mode & S_IFMT) {
yuuji@0 430 case S_IFDIR: /* directory is always OK */
yuuji@0 431 return NIL;
yuuji@0 432 case S_IFREG: /* file is unsafe if setuid */
yuuji@0 433 if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file");
yuuji@0 434 /* or setgid */
yuuji@0 435 else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file");
yuuji@0 436 else return NIL; /* otherwise safe */
yuuji@0 437 break;
yuuji@0 438 case S_IFCHR: strcat (tmp,"character special"); break;
yuuji@0 439 case S_IFBLK: strcat (tmp,"block special"); break;
yuuji@0 440 case S_IFLNK: strcat (tmp,"symbolic link"); break;
yuuji@0 441 case S_IFSOCK: strcat (tmp,"socket"); break;
yuuji@0 442 default:
yuuji@0 443 sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type);
yuuji@0 444 }
yuuji@0 445 return fail (tmp,EX_CANTCREAT);
yuuji@0 446 }
yuuji@0 447
yuuji@0 448 /* Report an error
yuuji@0 449 * Accepts: string to output
yuuji@0 450 */
yuuji@0 451
yuuji@0 452 int fail (char *string,int code)
yuuji@0 453 {
yuuji@0 454 mm_log (string,ERROR); /* pass up the string */
yuuji@0 455 switch (code) {
yuuji@0 456 #if T
yuuji@0 457 case EX_USAGE:
yuuji@0 458 case EX_OSERR:
yuuji@0 459 case EX_SOFTWARE:
yuuji@0 460 case EX_NOUSER:
yuuji@0 461 case EX_CANTCREAT:
yuuji@0 462 code = EX_TEMPFAIL; /* coerce these to TEMPFAIL */
yuuji@0 463 break;
yuuji@0 464 #endif
yuuji@0 465 case -1: /* quota failure... */
yuuji@0 466 code = EX_CANTCREAT; /* ...really returns this code */
yuuji@0 467 break;
yuuji@0 468 default:
yuuji@0 469 break;
yuuji@0 470 }
yuuji@0 471 return code; /* error code to return */
yuuji@0 472 }
yuuji@0 473
yuuji@0 474 /* Co-routines from MAIL library */
yuuji@0 475
yuuji@0 476
yuuji@0 477 /* Message matches a search
yuuji@0 478 * Accepts: MAIL stream
yuuji@0 479 * message number
yuuji@0 480 */
yuuji@0 481
yuuji@0 482 void mm_searched (MAILSTREAM *stream,unsigned long msgno)
yuuji@0 483 {
yuuji@0 484 fatal ("mm_searched() call");
yuuji@0 485 }
yuuji@0 486
yuuji@0 487
yuuji@0 488 /* Message exists (i.e. there are that many messages in the mailbox)
yuuji@0 489 * Accepts: MAIL stream
yuuji@0 490 * message number
yuuji@0 491 */
yuuji@0 492
yuuji@0 493 void mm_exists (MAILSTREAM *stream,unsigned long number)
yuuji@0 494 {
yuuji@0 495 fatal ("mm_exists() call");
yuuji@0 496 }
yuuji@0 497
yuuji@0 498
yuuji@0 499 /* Message expunged
yuuji@0 500 * Accepts: MAIL stream
yuuji@0 501 * message number
yuuji@0 502 */
yuuji@0 503
yuuji@0 504 void mm_expunged (MAILSTREAM *stream,unsigned long number)
yuuji@0 505 {
yuuji@0 506 fatal ("mm_expunged() call");
yuuji@0 507 }
yuuji@0 508
yuuji@0 509
yuuji@0 510 /* Message flags update seen
yuuji@0 511 * Accepts: MAIL stream
yuuji@0 512 * message number
yuuji@0 513 */
yuuji@0 514
yuuji@0 515 void mm_flags (MAILSTREAM *stream,unsigned long number)
yuuji@0 516 {
yuuji@0 517 }
yuuji@0 518
yuuji@0 519 /* Mailbox found
yuuji@0 520 * Accepts: MAIL stream
yuuji@0 521 * delimiter
yuuji@0 522 * mailbox name
yuuji@0 523 * mailbox attributes
yuuji@0 524 */
yuuji@0 525
yuuji@0 526 void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
yuuji@0 527 {
yuuji@0 528 fatal ("mm_list() call");
yuuji@0 529 }
yuuji@0 530
yuuji@0 531
yuuji@0 532 /* Subscribed mailbox found
yuuji@0 533 * Accepts: MAIL stream
yuuji@0 534 * delimiter
yuuji@0 535 * mailbox name
yuuji@0 536 * mailbox attributes
yuuji@0 537 */
yuuji@0 538
yuuji@0 539 void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
yuuji@0 540 {
yuuji@0 541 fatal ("mm_lsub() call");
yuuji@0 542 }
yuuji@0 543
yuuji@0 544
yuuji@0 545 /* Mailbox status
yuuji@0 546 * Accepts: MAIL stream
yuuji@0 547 * mailbox name
yuuji@0 548 * mailbox status
yuuji@0 549 */
yuuji@0 550
yuuji@0 551 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
yuuji@0 552 {
yuuji@0 553 fatal ("mm_status() call");
yuuji@0 554 }
yuuji@0 555
yuuji@0 556 /* Notification event
yuuji@0 557 * Accepts: MAIL stream
yuuji@0 558 * string to log
yuuji@0 559 * error flag
yuuji@0 560 */
yuuji@0 561
yuuji@0 562 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
yuuji@0 563 {
yuuji@0 564 char tmp[MAILTMPLEN];
yuuji@0 565 tmp[11] = '\0'; /* see if TRYCREATE */
yuuji@0 566 if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T;
yuuji@0 567 mm_log (string,errflg); /* just do mm_log action */
yuuji@0 568 }
yuuji@0 569
yuuji@0 570
yuuji@0 571 /* Log an event for the user to see
yuuji@0 572 * Accepts: string to log
yuuji@0 573 * error flag
yuuji@0 574 */
yuuji@0 575
yuuji@0 576 void mm_log (char *string,long errflg)
yuuji@0 577 {
yuuji@0 578 if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */
yuuji@0 579 else { /* ordinary logging */
yuuji@0 580 fprintf (stderr,"%s\n",string);
yuuji@0 581 switch (errflg) {
yuuji@0 582 case NIL: /* no error */
yuuji@0 583 syslog (LOG_INFO,"%s",string);
yuuji@0 584 break;
yuuji@0 585 case PARSE: /* parsing problem */
yuuji@0 586 case WARN: /* warning */
yuuji@0 587 syslog (LOG_WARNING,"%s",string);
yuuji@0 588 break;
yuuji@0 589 case ERROR: /* error */
yuuji@0 590 default:
yuuji@0 591 syslog (LOG_ERR,"%s",string);
yuuji@0 592 break;
yuuji@0 593 }
yuuji@0 594 }
yuuji@0 595 }
yuuji@0 596
yuuji@0 597
yuuji@0 598 /* Log an event to debugging telemetry
yuuji@0 599 * Accepts: string to log
yuuji@0 600 */
yuuji@0 601
yuuji@0 602 void mm_dlog (char *string)
yuuji@0 603 {
yuuji@0 604 if (debug) fprintf (stderr,"%s\n",string);
yuuji@0 605 syslog (LOG_DEBUG,"%s",string);
yuuji@0 606 }
yuuji@0 607
yuuji@0 608 /* Get user name and password for this host
yuuji@0 609 * Accepts: parse of network mailbox name
yuuji@0 610 * where to return user name
yuuji@0 611 * where to return password
yuuji@0 612 * trial count
yuuji@0 613 */
yuuji@0 614
yuuji@0 615 void mm_login (NETMBX *mb,char *username,char *password,long trial)
yuuji@0 616 {
yuuji@0 617 fatal ("mm_login() call");
yuuji@0 618 }
yuuji@0 619
yuuji@0 620
yuuji@0 621 /* About to enter critical code
yuuji@0 622 * Accepts: stream
yuuji@0 623 */
yuuji@0 624
yuuji@0 625 void mm_critical (MAILSTREAM *stream)
yuuji@0 626 {
yuuji@0 627 critical = T; /* note in critical code */
yuuji@0 628 }
yuuji@0 629
yuuji@0 630
yuuji@0 631 /* About to exit critical code
yuuji@0 632 * Accepts: stream
yuuji@0 633 */
yuuji@0 634
yuuji@0 635 void mm_nocritical (MAILSTREAM *stream)
yuuji@0 636 {
yuuji@0 637 critical = NIL; /* note not in critical code */
yuuji@0 638 }
yuuji@0 639
yuuji@0 640
yuuji@0 641 /* Disk error found
yuuji@0 642 * Accepts: stream
yuuji@0 643 * system error code
yuuji@0 644 * flag indicating that mailbox may be clobbered
yuuji@0 645 * Returns: T if user wants to abort
yuuji@0 646 */
yuuji@0 647
yuuji@0 648 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
yuuji@0 649 {
yuuji@0 650 return T;
yuuji@0 651 }
yuuji@0 652
yuuji@0 653
yuuji@0 654 /* Log a fatal error event
yuuji@0 655 * Accepts: string to log
yuuji@0 656 */
yuuji@0 657
yuuji@0 658 void mm_fatal (char *string)
yuuji@0 659 {
yuuji@0 660 printf ("?%s\n",string); /* shouldn't happen normally */
yuuji@0 661 }

UW-IMAP'd extensions by yuuji